/*ScianVisTraces.c Eric Pepke September 9, 1991 Trace visualization object in SciAn */ #include "Scian.h" #include "ScianTypes.h" #include "ScianArrays.h" #include "ScianWindows.h" #include "ScianTextBoxes.h" #include "ScianObjWindows.h" #include "ScianIcons.h" #include "ScianColors.h" #include "ScianControls.h" #include "ScianLists.h" #include "ScianSpaces.h" #include "ScianButtons.h" #include "ScianSliders.h" #include "ScianIDs.h" #include "ScianDatasets.h" #include "ScianErrors.h" #include "ScianVisObjects.h" #include "ScianVisWindows.h" #include "ScianStyle.h" #include "ScianPictures.h" #include "ScianTimers.h" #ifndef RELEASE #define NSEGMENTS 10 /*Number of segments in a trace to show*/ ObjPtr traceClass; /*Class for trace*/ static ObjPtr MakeTraceBounds(object) ObjPtr object; /*Makes bounds for a trace*/ { ObjPtr objBounds; real bounds[6]; ObjPtr dataObj; ObjPtr var; int component; long index, *dims; real sample; /*Go through all data expanding bounds*/ bounds[0] = 1E12; bounds[1] = -1E12; bounds[2] = 1E12; bounds[3] = -1E12; bounds[4] = 1E12; bounds[5] = -1E12; /*X bounds*/ dataObj = GetObjectVar("TraceBounds", object, XFIELD); var = GetIntVar("TraceBounds", object, XTOPDIM); if (!dataObj || !var) { return ObjFalse; } component = GetInt(var); SetCurField(FIELD1, dataObj); if (GetNComponents(FIELD1) < component) { component = GetNComponents(FIELD1); } if (CountComponentDims(FIELD1, component) != 1) { ReportError("TraceBounds", "Only one-dimensional components are valid in a trace"); return ObjFalse; } dims = GetComponentDims(FIELD1, component); index = 0; sample = SelectFieldComponent(FIELD1, component, &index); bounds[0] = sample; bounds[1] = sample; for (index = 1; index < dims[0]; ++index) { sample = SelectFieldComponent(FIELD1, component, &index); if (sample < bounds[0]) bounds[0] = sample; if (sample > bounds[1]) bounds[1] = sample; } /*Y bounds*/ dataObj = GetObjectVar("TraceBounds", object, YFIELD); var = GetIntVar("TraceBounds", object, YTOPDIM); if (!dataObj || !var) { return ObjFalse; } component = GetInt(var); SetCurField(FIELD1, dataObj); if (GetNComponents(FIELD1) < component) { component = GetNComponents(FIELD1); printf("Bumping component down to %d", component); } if (CountComponentDims(FIELD1, component) != 1) { ReportError("TraceBounds", "Only one-dimensional components are valid in a trace"); return ObjFalse; } dims = GetComponentDims(FIELD1, component); index = 0; sample = SelectFieldComponent(FIELD1, component, &index); bounds[2] = sample; bounds[3] = sample; for (index = 1; index < dims[0]; ++index) { sample = SelectFieldComponent(FIELD1, component, &index); if (sample < bounds[2]) bounds[2] = sample; if (sample > bounds[3]) bounds[3] = sample; } /*Z bounds*/ dataObj = GetObjectVar("TraceBounds", object, ZFIELD); var = GetIntVar("TraceBounds", object, ZTOPDIM); if (!dataObj || !var) { return ObjFalse; } component = GetInt(var); SetCurField(FIELD1, dataObj); if (GetNComponents(FIELD1) < component) { component = GetNComponents(FIELD1); } if (CountComponentDims(FIELD1, component) != 1) { ReportError("TraceBounds", "Only one-dimensional components are valid in a trace"); return ObjFalse; } dims = GetComponentDims(FIELD1, component); index = 0; sample = SelectFieldComponent(FIELD1, component, &index); bounds[4] = sample; bounds[5] = sample; for (index = 0; index < dims[0]; ++index) { sample = SelectFieldComponent(FIELD1, component, &index); if (sample < bounds[4]) bounds[4] = sample; if (sample > bounds[5]) bounds[5] = sample; } objBounds = NewRealArray(1, (long) 6); CArray2Array(objBounds, bounds); SetVar(object, BOUNDS, objBounds); return ObjTrue; } static ObjPtr ChangeMovingTrace(object) ObjPtr object; /*Changed value for a moving trace*/ { int movingTrace; ObjPtr val; ObjPtr repObj; repObj = GetObjectVar("ChangeMovingTrace", object, REPOBJ); if (!repObj) { return ObjFalse; } val = GetVar(object, VALUE); if (val) { movingTrace = GetInt(val); } else { movingTrace = false; } DoNotDisturb(repObj, WAKEUP); if (movingTrace) { SetVar(repObj, HILITESEGMENT, NewInt(1)); WakeMe(repObj, WAKEUP, Clock()); } else { SetVar(repObj, HILITESEGMENT, NULLOBJ); } ImInvalid(repObj); return ObjTrue; } static ObjPtr AddTraceControls(object, panelContents) ObjPtr object, panelContents; /*Adds controls for a trace object*/ { int width; int left, top; ObjPtr checkBox; int smooth; width = CWINWIDTH - 2 * CORRALBORDER - CWINCORRALWIDTH; left = MAJORBORDER; top = CWINHEIGHT - MAJORBORDER; /****UPDATE*** moving trace is not the best idea*/ /*Create the check box for moving trace*/ checkBox = NewCheckBox(left, left + width, top - CHECKBOXHEIGHT, top, "Moving Trace", GetVar(object, HILITESEGMENT) ? 1 : 0); if (!checkBox) { return ObjFalse; } PrefixList(panelContents, checkBox); SetVar(checkBox, HELPSTRING, NewString("If this box is checked, a moving red trace will follow \ the trace through time.\n")); SetVar(checkBox, PARENT, panelContents); SetVar(checkBox, REPOBJ, object); SetMethod(checkBox, CHANGEDVALUE, ChangeMovingTrace); top -= CHECKBOXHEIGHT + CHECKBOXSPACING; /*Create the check box for smooth trace*/ smooth = GetPredicate(object, SMOOTH); checkBox = NewCheckBox(left, left + width, top - CHECKBOXHEIGHT, top, "Smooth Trace", smooth); if (!GetVar(object, SMOOTH)) { SetVar(object, SMOOTH, NewInt(0)); } if (!checkBox) { return ObjFalse; } PrefixList(panelContents, checkBox); SetVar(checkBox, HELPSTRING, NewString("If this box is checked, the trace will be drawn smoothly \ using a Cardinal spline. If not, the trace will be drawn with a series of \ line segments.")); SetVar(checkBox, PARENT, panelContents); AssocDirectControlWithVar(checkBox, object, SMOOTH); top -= CHECKBOXHEIGHT + CHECKBOXSPACING; return ObjTrue; } static ObjPtr WakeTrace(object) ObjPtr object; /*Wakes up a trace*/ { ObjPtr space; WinInfoPtr window; ObjPtr hiliteObj; ObjPtr dataField; long nSamples; int xComponent; ObjPtr var; long *dims; int hiliteSegment; /*Set up X coordinate*/ dataField = GetObjectVar("WakeTrace", object, XFIELD); var = GetIntVar("WakeTrace", object, XTOPDIM); if (!dataField || !var) { return ObjFalse; } xComponent = GetInt(var); SetCurField(FIELD1, dataField); if (GetNComponents(FIELD1) < xComponent) { xComponent = GetNComponents(FIELD1); } if (CountComponentDims(FIELD1, xComponent) != 1) { ReportError("WakeTrace", "Only one-dimensional components are valid in a trace"); } dims = GetComponentDims(FIELD1, xComponent); nSamples = *dims; /*Next highlighted segment*/ hiliteObj = GetVar(object, HILITESEGMENT); if (hiliteObj) { hiliteSegment = GetInt(hiliteObj); hiliteSegment += 1; if (hiliteSegment > nSamples) { SetVar(object, HILITESEGMENT, NewInt(0)); } else { SetVar(object, HILITESEGMENT, NewInt(hiliteSegment)); } WakeMe(object, WAKEUP, Clock() + 1.0 / 30.0); } ImInvalid(object); return ObjTrue; } static ObjPtr SetTraceMainDataset(visObj, dataSet) ObjPtr visObj, dataSet; /*Sets the main data set of visObj to dataSet*/ { SetVar(visObj, XFIELD, dataSet); SetVar(visObj, YFIELD, dataSet); SetVar(visObj, ZFIELD, dataSet); SetVar(visObj, MAINDATASET, dataSet); return ObjTrue; } static ObjPtr InitTrace(visObj) ObjPtr visObj; /*Initializes a trace*/ { SetVar(visObj, XTOPDIM, NewInt(0)); SetVar(visObj, YTOPDIM, NewInt(1)); SetVar(visObj, ZTOPDIM, NewInt(2)); return ObjTrue; } static ObjPtr DrawTrace(object) ObjPtr object; /*Draw a trace*/ { #ifdef GRAPHICS long k; int xComponent, yComponent, zComponent; int x, y, z; real xScale, yScale, zScale; ObjPtr dataField, var; Bool smooth; long *dims; int hiliteSegment; Coord curveSeg[4][3]; long nSamples; /*The number of samples*/ /*Get x, y, z, scale*/ var = GetRealVar("DrawTrace", object, XSCALE); if (var) { xScale = GetReal(var); } else { xScale = 1.0; } var = GetRealVar("DrawTrace", object, YSCALE); if (var) { yScale = GetReal(var); } else { yScale = 1.0; } var = GetRealVar("DrawTrace", object, ZSCALE); if (var) { zScale = GetReal(var); } else { zScale = 1.0; } /*Set up X coordinate*/ dataField = GetObjectVar("DrawTrace", object, XFIELD); var = GetIntVar("DrawTrace", object, XTOPDIM); if (!dataField || !var) { return ObjFalse; } xComponent = GetInt(var); SetCurField(FIELD1, dataField); if (GetNComponents(FIELD1) < xComponent) { xComponent = GetNComponents(FIELD1); } if (CountComponentDims(FIELD1, xComponent) != 1) { ReportError("DrawTrace", "Only one-dimensional components are valid in a trace"); } dims = GetComponentDims(FIELD1, xComponent); nSamples = *dims; /*Set up Y coordinate*/ dataField = GetObjectVar("DrawTrace", object, YFIELD); var = GetIntVar("DrawTrace", object, YTOPDIM); if (!dataField || !var) { return ObjFalse; } yComponent = GetInt(var); SetCurField(FIELD2, dataField); if (GetNComponents(FIELD2) < yComponent) { yComponent = GetNComponents(FIELD2); } if (CountComponentDims(FIELD2, yComponent) != 1) { ReportError("DrawTrace", "Only one-dimensional components are valid in a trace"); } dims = GetComponentDims(FIELD2, yComponent); if (*dims != nSamples) { /****UPDATE*** do something else*/ nSamples = MIN(*dims, nSamples); } /*Set up Z coordinate*/ dataField = GetObjectVar("DrawTrace", object, ZFIELD); var = GetIntVar("DrawTrace", object, ZTOPDIM); if (!dataField || !var) { return ObjFalse; } zComponent = GetInt(var); SetCurField(FIELD3, dataField); if (GetNComponents(FIELD3) < zComponent) { zComponent = GetNComponents(FIELD3); } if (CountComponentDims(FIELD3, zComponent) != 1) { ReportError("DrawTrace", "Only one-dimensional components are valid in a trace"); } dims = GetComponentDims(FIELD3, zComponent); if (*dims != nSamples) { /****UPDATE*** do something else*/ nSamples = MIN(*dims, nSamples); } /*Get smooth predicate*/ smooth = GetPredicate(object, SMOOTH); /*Determine which segment to hilite, if any*/ var = GetVar(object, HILITESEGMENT); if (var && IsInt(var)) { hiliteSegment = GetInt(var); } else { hiliteSegment = -50; } SetLineWidth(1); /*Make z-buffer read-only*/ BeginMask(true, true, true, false); if (smooth) { int b, e; curvebasis(CARDBASIS); SetUIColor(WHITE); /*Draw the unhilited segments*/ k = 0; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[0][0] = x; curveSeg[0][1] = y; curveSeg[0][2] = z; curveSeg[1][0] = x; curveSeg[1][1] = y; curveSeg[1][2] = z; k = 1; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[2][0] = x; curveSeg[2][1] = y; curveSeg[2][2] = z; k = 2; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[3][0] = x; curveSeg[3][1] = y; curveSeg[3][2] = z; for (k = 1; k < nSamples; ++k) { crv(curveSeg); /*Shift everything down and add new point*/ curveSeg[0][0] = curveSeg[1][0]; curveSeg[0][1] = curveSeg[1][1]; curveSeg[0][2] = curveSeg[1][2]; curveSeg[1][0] = curveSeg[2][0]; curveSeg[1][1] = curveSeg[2][1]; curveSeg[1][2] = curveSeg[2][2]; curveSeg[2][0] = curveSeg[3][0]; curveSeg[2][1] = curveSeg[3][1]; curveSeg[2][2] = curveSeg[3][2]; if (k < nSamples - 1) { curveSeg[3][0] = xScale * SelectFieldComponent(FIELD1, xComponent, &k); curveSeg[3][1] = yScale * SelectFieldComponent(FIELD2, yComponent, &k); curveSeg[3][2] = zScale * SelectFieldComponent(FIELD3, zComponent, &k); } } /*Draw the hilited segments*/ SetUIColor(UIRED); SetLineWidth(3); b = hiliteSegment - NSEGMENTS; e = hiliteSegment; if (b < 0) b = 0; if (e >= nSamples) e = nSamples - 1; if (b > 0) { k = b - 1; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[0][0] = x; curveSeg[0][1] = y; curveSeg[0][2] = z; ++k; } else { k = b; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[0][0] = x; curveSeg[0][1] = y; curveSeg[0][2] = z; } x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[1][0] = x; curveSeg[1][1] = y; curveSeg[1][2] = z; ++k; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[2][0] = x; curveSeg[2][1] = y; curveSeg[2][2] = z; ++k; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[3][0] = x; curveSeg[3][1] = y; curveSeg[3][2] = z; for (k = b + 1; k < e; ++k) { crv(curveSeg); /*Shift everything down and add new point*/ curveSeg[0][0] = curveSeg[1][0]; curveSeg[0][1] = curveSeg[1][1]; curveSeg[0][2] = curveSeg[1][2]; curveSeg[1][0] = curveSeg[2][0]; curveSeg[1][1] = curveSeg[2][1]; curveSeg[1][2] = curveSeg[2][2]; curveSeg[2][0] = curveSeg[3][0]; curveSeg[2][1] = curveSeg[3][1]; curveSeg[2][2] = curveSeg[3][2]; if (k < nSamples - 1) { x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); curveSeg[3][0] = x; curveSeg[3][1] = y; curveSeg[3][2] = z; } } } else { /*Draw the unhilited segments*/ long b, e; SetUIColor(WHITE); SetLineWidth(1); k = 0; x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD2, yComponent, &k); z = zScale * SelectFieldComponent(FIELD3, zComponent, &k); move(x, y, z); for (k = 1; k < nSamples; ++k) { x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD1, yComponent, &k); z = zScale * SelectFieldComponent(FIELD1, zComponent, &k); draw(x, y, z); } SetUIColor(UIRED); SetLineWidth(3); /*Draw the hilited segments*/ b = hiliteSegment - NSEGMENTS; e = hiliteSegment; if (b < 0) b = 0; if (e >= nSamples) e = nSamples - 1; x = xScale * SelectFieldComponent(FIELD1, xComponent, &b); y = yScale * SelectFieldComponent(FIELD2, yComponent, &b); z = zScale * SelectFieldComponent(FIELD3, zComponent, &b); move(x, y, z); for (k = b + 1; k <= e; ++k) { x = xScale * SelectFieldComponent(FIELD1, xComponent, &k); y = yScale * SelectFieldComponent(FIELD1, yComponent, &k); z = zScale * SelectFieldComponent(FIELD1, zComponent, &k); draw(x, y, z); } } SetLineWidth(1); SetUIColor(UIGRAY50); EndMask(); #endif return ObjTrue; } #endif void InitTraces() /*Initializes the traces*/ { #ifndef RELEASE ObjPtr icon; /*Class for a trace displayer*/ traceClass = NewObject(visColored, 0); AddToReferenceList(traceClass); SetVar(traceClass, NAME, NewString("Trace")); SetMethod(traceClass, BOUNDS, MakeTraceBounds); SetMethod(traceClass, ADDCONTROLS, AddTraceControls); SetMethod(traceClass, SETMAINDATASET, SetTraceMainDataset); SetMethod(traceClass, INITIALIZE, InitTrace); icon = NewIcon(0, 0, ICONTRACE , "Trace"); SetVar(icon, HELPSTRING, NewString("Select this icon to show controls for a trace, such \ as whether to smooth the trace and show a moving trace.")); SetVar(traceClass, CONTROLICON, icon); icon = NewObject(visIcon, 0); SetVar(icon, WHICHICON, NewInt(ICONTRACE)); SetVar(icon, NAME, NewString("Trace")); SetVar(icon, HELPSTRING, NewString("This icon represents a trace object. A trace object shows \ a 1-D vector field as a trace in 3-space, taking the x, y, and z positions \ from components of the vector.")); SetVar(traceClass, DEFAULTICON, icon); SetMethod(traceClass, DRAW, DrawTrace); SetMethod(traceClass, WAKEUP, WakeTrace); /* DefineVisMapping(DS_HASFORM | DS_HASFIELD, 1, -1, -1, traceClass); DefineVisMapping(DS_HASFIELD, 1, -1, -1, traceClass); */ DefineVisMapping(DS_HASFORM | DS_HASFIELD | DS_VECTOR, 1, -1, -1, traceClass); DefineVisMapping(DS_HASFIELD | DS_VECTOR, 1, -1, -1, traceClass); #endif } void KillTraces() /*Kills the traces*/ { #ifndef RELEASE DeleteThing(traceClass); #endif }