<<>> <> <> <> DIRECTORY Args, Commander, Controls, Draw2d, FileNames, FS, G2dBasic, G2dContour, G3dBasic, G3dControl, G3dCurve, G3dDraw, G3dMatrix, G3dPlane, G3dSpline, G3dTool, G3dTube, G3dVector, G3dView, Icons, IO, ImagerInterpress, Menus, MessageWindow, Real, Rope, ViewerOps; G3dTubeCmdImpl: CEDAR PROGRAM IMPORTS Args, Controls, Draw2d, FileNames, FS, G2dContour, G3dControl, G3dCurve, G3dDraw, G3dMatrix, G3dPlane, G3dSpline, G3dTool, G3dTube, G3dVector, G3dView, Icons, IO, ImagerInterpress, MessageWindow, Real, Rope, ViewerOps ~ BEGIN <> ClickProc: TYPE ~ Controls.ClickProc; Control: TYPE ~ Controls.Control; ControlList: TYPE ~ Controls.ControlList; Mouse: TYPE ~ Controls.Mouse; OuterData: TYPE ~ Controls.OuterData; Zip: TYPE ~ Draw2d.Zip; Contour: TYPE ~ G2dContour.Contour; Pair: TYPE ~ G3dBasic.Pair; Triple: TYPE ~ G3dBasic.Triple; Quad: TYPE ~ G3dBasic.Quad; Hold: TYPE ~ G3dControl.Hold; Matrix: TYPE ~ G3dMatrix.Matrix; Plane: TYPE ~ G3dPlane.Plane; RenderTool: TYPE ~ G3dTool.Tool; SplineRep: TYPE ~ G3dSpline.SplineRep; STREAM: TYPE ~ IO.STREAM; ROPE: TYPE ~ Rope.ROPE; Details: TYPE ~ G3dTube.Details; DetailType: TYPE ~ G3dTube.DetailType; RadiusMode: TYPE ~ G3dTube.RadiusMode; Tube: TYPE ~ G3dTube.Tube; TubeProc: TYPE ~ G3dTube.TubeProc; TubeRep: TYPE ~ G3dTube.TubeRep; Pendings: TYPE ~ REF PendingsRep; PendingsRep: TYPE ~ RECORD [ epsilon: BOOL ¬ FALSE, size: BOOL ¬ FALSE, r: BOOL ¬ FALSE, taper: BOOL ¬ FALSE, tens: BOOL ¬ FALSE, tw0: BOOL ¬ FALSE, tw1: BOOL ¬ FALSE, cres: BOOL ¬ FALSE, holdPosition: BOOL ¬ FALSE, holdTangent: BOOL ¬ FALSE, holdRoll: BOOL ¬ FALSE, shape: BOOL ¬ FALSE, skin: BOOL ¬ FALSE ]; Pick: TYPE ~ REF PickRep; PickRep: TYPE ~ RECORD [ type: {point, segment, subTree} ¬ point, pos, tan: Triple ¬ G3dBasic.origin, tube: Tube ¬ NIL, t: REAL ¬ 1.0, selected0, selected1: Tube ¬ NIL, dividePending: BOOL ¬ FALSE, plane: Plane ¬ [0.0, 0.0, 0.0, 0.0], mouse: Mouse ]; ActionType: TYPE ~ {none, select, camera, spline, shape, button}; Tool: TYPE ~ REF ToolRep; ToolRep: TYPE ~ RECORD [ <> controls: ControlList ¬ NIL, -- list of the following controls: size: Control ¬ NIL, -- size of tube r0: Control ¬ NIL, -- radius 0 r1: Control ¬ NIL, -- radius 1 tw0: Control ¬ NIL, -- twist 0 tw1: Control ¬ NIL, -- twist 1 tens0: Control ¬ NIL, -- tension 0 tens1: Control ¬ NIL, -- tension 1 cres: Control ¬ NIL, -- circ. resolution epsilon: Control ¬ NIL, -- spline flatness value taper: Control ¬ NIL, -- tube taper hold: Hold ¬ NIL, -- handle on a point and its tangent lim: Control ¬ NIL, -- vector limit <> renderTool: RenderTool ¬ NIL, <> details: Details ¬ NIL, pendings: Pendings ¬ NIL, noDraw: BOOL ¬ FALSE, vectors: BOOL ¬ TRUE, neverMoused: BOOL ¬ TRUE, mouse: Mouse ¬ [[0, 0], none, left], mousePrev: Mouse ¬ [[0, 0], none, left], pick: Pick ¬ NIL, action: ActionType ¬ none, radiusMode: RadiusMode ¬ linear, round: BOOL ¬ FALSE, xformIO: BOOL ¬ FALSE, -- view-xform points when writing file <> ground: Plane ¬ [], -- something new frill: Tube ¬ NIL, -- the frilled tube tube: Tube ¬ NIL -- all the tube splines ]; <> TubeDesignCmd: Commander.CommandProc ~ { NewControl: PROC [name: ROPE, min, max, init: REAL, lin: BOOL ¬ TRUE, precision: NAT ¬ 3] RETURNS [c: Control] ~ { c ¬ Controls.NewControl[ name, vSlider, t, min, max, init, TubeControl,, precision,,,,,,,,, IF lin THEN lin ELSE exp]; }; err: ROPE; t: Tool ~ NEW[ToolRep]; SELECT Args.NArgs[cmd] FROM 0 => t.tube ¬ ResetTube[]; 1 => IF (err ¬ TubeFromFile[t, Args.GetRope[cmd]]) # NIL THEN RETURN[$Failure, err]; ENDCASE => RETURN[$Failure, designUsage]; t.details ¬ NEW[G3dTube.DetailsRep]; t.pendings ¬ NEW[PendingsRep]; t.hold ¬ G3dControl.InitHold[TubeControl, t]; t.tw0 ¬ NewControl["tw0", -1000., 1000., 0.0]; t.tw1 ¬ NewControl["tw1", -1000., 1000., 0.0]; t.tens0 ¬ NewControl["tens0", -3.0, 3.0, 0.0]; t.tens1 ¬ NewControl["tens1", -3.0, 3.0, 0.0]; t.r0 ¬ NewControl["r0", 0.0, 0.5, 0.0]; t.r1 ¬ NewControl["r1", 0.0, 0.5, 0.0]; t.size ¬ NewControl["size", 0.0, 4.0, 1.0]; t.epsilon ¬ NewControl["eps", 0.0, 0.2, 0.03, FALSE]; t.taper ¬ NewControl["taper", -3.0, 3.0, 0.0, FALSE]; t.cres ¬ NewControl["cres", 2.0, 25.0, 6.0, TRUE, 0]; t.lim ¬ NewControl["lim", 0.0, 1000.0, 500.0, TRUE, 0]; t.pendings ¬ NEW[PendingsRep ¬ [shape: TRUE]]; MakePick[t]; SetPick[t]; Moused[t, [[0, 0], up, left], $Buttons]; t.renderTool ¬ G3dTool.MakeTool[ name: Rope.Concat["3dTube ", IF t.tube # NIL THEN t.tube.name ELSE NIL], extraButtons: LIST[ Controls.ClickButton["Tube Ops", TubeOps, t], Controls.ClickButton["IO Ops", IOOps, t], Controls.ClickButton["Draw Ops", DrawOps, t]], extraControls: LIST[ t.hold.x, t.hold.y, t.hold.z, t.hold.pitch, t.hold.yaw, -- t.hold.roll, -- t.hold.mag, t.tw0, t.tw1, t.r0, t.r1, t.tens0, t.tens1, t.lim, t.epsilon, t.taper, t.size, t.cres], controlSizes: [20, 200, 55, 20, 55, 150, 150], client: [data: t, mouse: MouseProc, draw: DrawProc, destroy: DestroyProc], ops: [FALSE, FALSE, FALSE, FALSE, FALSE, FALSE], useArcBalls: FALSE, arcBallSize: 80, icon: icon]; }; ClearPendings: PROC [pendings: Pendings] ~ { pendings.epsilon ¬ pendings.size ¬ pendings.r ¬ pendings.tw0 ¬ pendings.tw1 ¬ pendings.cres ¬ pendings.holdPosition ¬ pendings.holdTangent ¬ pendings.shape ¬ pendings.skin ¬ FALSE; }; <> TubeOps: ClickProc ~ { t: Tool ¬ NARROW[clientData]; SELECT Controls.PopUpRequest[["Tube Ops"], LIST[ -- 1 -- ["New Tube", "reset the current tube to the default tube"], -- 2 -- ["Select All", "select the entire tube"], -- 3 -- ["Branch", "add a branch to the current tube at the selected point"], -- 4 -- ["Delete", "delete the current selected branch"], -- 5 -- Controls.BoolRequest[t.round, "Round ends"], -- 6 -- ["Wt Rad", "select different radius weighting scheme"], -- 7 -- ["Radius Mode", "cycle through radius mode"], -- 8 -- Controls.BoolRequest[t.xformIO, "Xform points"]]] FROM 1 => ReplaceTube[t, ResetTube[]]; 2 => G3dTube.SelectAll[t.tube]; 3 => Branch[t]; 4 => Delete[t]; 5 => { t.round ¬ NOT t.round; t.pendings.shape ¬ TRUE; }; 6 => WeightRadii[t]; 7 => { t.radiusMode ¬ SELECT Controls.MultiRequest["Radius mode is ", LIST[ ["Linear", t.radiusMode = linear], ["Square", t.radiusMode = square]]] FROM 1 => linear, 2 => square, ENDCASE => linear; }; 8 => t.xformIO ¬ NOT t.xformIO; ENDCASE; IF Controls.GetPopUpButton[] = right THEN CheckPendingAndRePaint[t]; }; <> DrawProc: G3dTool.DrawProc ~ { t: Tool ~ NARROW[clientData]; IF NOT t.noDraw THEN { IF whatChanged # $Camera THEN Draw2d.Clear[context]; IF t.details[spline] AND t.details[ends] THEN G3dTube.DrawSplineEnds[context, t.tube, view]; IF t.details[enabled] THEN G3dTube.DrawTube[context, t.tube, t.details, view, vp] ELSE IF t.details[spline] THEN G3dTube.DrawSplines[context, t.tube, view, vp]; IF t.details[pick] AND t.pick # NIL AND t.pick.tube # NIL THEN { IF NOT t.neverMoused THEN { pairClip: G3dView.PairClip ~ G3dView.TransformAndClipInZ[t.pick.pos, view]; Imager.SetStrokeWidth[context, 1.0]; G3dDraw.Vector[context, t.pick.pos, t.pick.tan, view, vp]; IF NOT pairClip.clipped THEN { Draw2d.Circle[context, pairClip.pair, 3.0, TRUE]; IF NOT t.pick.t IN (0.0..1.0) THEN Draw2d.Mark[context, pairClip.pair, asterisk]; }; }; }; }; }; DrawOps: ClickProc ~ { t: Tool ¬ NARROW[clientData]; SELECT Controls.PopUpRequest[["LF Ops"], LIST[ -- 1 -- Controls.BoolRequest[t.vectors, "Vectors"], -- 2 -- Controls.BoolRequest[t.details[skeleton], "Skeleton"], -- 3 -- Controls.BoolRequest[t.details[spline], "Splines"], -- 4 -- Controls.BoolRequest[t.details[ends], "Ends"], -- 5 -- Controls.BoolRequest[t.details[pick], "Pick"], -- 6 -- Controls.BoolRequest[t.details[label], "Label"], -- 7 -- Controls.BoolRequest[t.details[autoSimplify], "Auto"], -- 8 -- Controls.BoolRequest[t.details[contours], "Contours"], -- 9 -- Controls.BoolRequest[t.details[lines], "Lines"], -- 10 -- Controls.BoolRequest[t.details[xSections], "XSections"], -- 11 -- Controls.BoolRequest[t.details[points], "Points"], -- 12 -- Controls.BoolRequest[t.details[normals], "Normals"], -- 13 -- Controls.BoolRequest[t.details[curvature], "Curvature"], -- 14 -- Controls.BoolRequest[t.details[velocity], "Velocity"], -- 15 -- Controls.BoolRequest[t.details[acceleration], "Acceleration"]]] FROM 1 => t.vectors ¬ NOT t.vectors; 2 => TogDetail[t, skeleton]; 3 => TogDetail[t, spline]; 4 => TogDetail[t, ends]; 5 => TogDetail[t, pick]; 6 => TogDetail[t, label]; 7 => TogDetail[t, autoSimplify]; 8 => TogDetail[t, contours]; 9 => TogDetail[t, lines]; 10 => TogDetail[t, xSections]; 11 => TogDetail[t, points]; 12 => TogDetail[t, normals]; 13 => TogDetail[t, curvature]; 14 => TogDetail[t, velocity]; 15 => TogDetail[t, acceleration]; ENDCASE; IF Controls.GetPopUpButton[] = right THEN CheckPendingAndRePaint[t, TRUE]; }; TogDetail: PROC [t: Tool, detailType: DetailType] ~ { button: Controls.MouseButton ¬ Controls.GetPopUpButton[]; m: Mouse ~ [[0, 0], up, button]; wasShape: BOOL ~ t.details[shape]; wasSkin: BOOL ~ t.details[skin]; t.details[detailType] ¬ NOT t.details[detailType]; t.details[shape] ¬ t.details[xSections] OR t.details[curvature] OR t.details[velocity] OR t.details[acceleration]; t.details[skin] ¬ t.details[contours] OR t.details[lines] OR t.details[normals]; Moused[t, m, $Buttons]; IF wasShape # t.details[shape] THEN t.pendings.shape ¬ t.details[shape]; IF wasSkin # t.details[skin] THEN t.pendings.skin ¬ t.details[skin]; IF detailType # autoSimplify AND button = right THEN CheckPendingAndRePaint[t, TRUE]; }; <> Moused: PROC [ t: Tool, mouse: Mouse, whatChanged: REF ANY, msg: ROPE ¬ NIL] ~ { c: Control ¬ SELECT whatChanged FROM t.hold.pitch, t.hold.yaw, t.hold.roll, t.hold.mag, t.hold.x, t.hold.y, t.hold.z, t.epsilon, t.taper, t.size, t.r0, t.r1, t.tw0, t.tw1, t.cres => NARROW[whatChanged], ENDCASE => NIL; t.mousePrev ¬ t.mouse; t.mouse ¬ mouse; t.action ¬ SELECT whatChanged FROM $Buttons => button, $Select => select, t.hold.pitch, t.hold.yaw, t.hold.roll, t.hold.mag, t.hold.x, t.hold.y, t.hold.z => spline, t.epsilon, t.taper => spline, $Pull, t.size, t.r0, t.r1, t.tw0, t.tw1, t.cres => shape, ENDCASE => none; t.details[enabled] ¬ NOT t.details[autoSimplify] OR t.action = shape OR t.mouse.state = up; <> <> IF NOT t.noDraw THEN SELECT whatChanged FROM t.size => t.pendings.size ¬ TRUE; t.r0, t.r1 => t.pendings.r ¬ TRUE; t.tw0 => t.pendings.tw0 ¬ TRUE; t.tw1 => t.pendings.tw1 ¬ TRUE; t.tens0, t.tens1 => t.pendings.tens ¬ TRUE; t.cres => t.pendings.cres ¬ TRUE; t.epsilon => t.pendings.epsilon ¬ TRUE; t.taper => t.pendings.taper ¬ TRUE; $Pull, t.hold.x, t.hold.y, t.hold.z => t.pendings.holdPosition ¬ TRUE; t.hold.pitch, t.hold.yaw, t.hold.mag => t.pendings.holdTangent ¬ TRUE; t.hold.roll => t.pendings.holdRoll ¬ TRUE; ENDCASE; IF t.action = spline AND t.pick.dividePending THEN DivideSpline[t]; IF t.renderTool # NIL THEN { IF msg = NIL THEN Controls.TypescriptClear[t.renderTool.typescript] ELSE Controls.TypescriptWrite[t.renderTool.typescript, msg]; }; }; DivideSpline: PROC [t: Tool] ~ { DividePick[t.pick]; Controls.SetSliderDialValue[t.hold.mag, G3dVector.Length[t.pick.tube.v1]]; }; CheckPendingAndRePaint: PROC [t: Tool, forceReDraw: BOOL ¬ FALSE] ~ { IF t.pick.tube = NIL THEN t.pendings.holdPosition ¬ t.pendings.holdTangent ¬ t.pendings.holdRoll ¬ FALSE; t.pendings.shape ¬ t.pendings.shape OR t.pendings.holdPosition OR t.pendings.holdTangent OR t.pendings.holdRoll; t.pendings.skin ¬ t.pendings.skin OR t.pendings.shape OR t.pendings.r OR t.pendings.tens OR t.pendings.tw0 OR t.pendings.tw1 OR t.pendings.taper OR t.pendings.epsilon OR t.pendings.cres; IF t.pendings.holdPosition THEN ChangePosition[t.pick, [t.hold.x.value, t.hold.y.value, t.hold.z.value]]; IF t.pendings.holdTangent THEN ChangeTangent[t.pick, t.hold]; IF t.pendings.holdRoll THEN RollSubTree[t.pick, Controls.GetSliderDialDeltaValue[t.hold.roll]]; IF t.pendings.size OR t.pendings.taper THEN G3dTube.ReScale[t.tube, t.size.value, t.taper.value]; IF t.pendings.epsilon THEN G3dTube.PropagateEpsilon[t.tube, t.epsilon.value]; IF t.pendings.cres THEN G3dTube.PropagateCircleRes[t.tube, Real.Round[t.cres.value]]; IF t.pendings.tens THEN ChangeTension[t.pick, t.tens0.value, t.tens1.value]; IF t.pendings.shape OR t.pendings.skin THEN G3dTube.InvalidateTubeAttributes[t.tube]; IF t.details[skin] OR t.details[shape] THEN { IF t.pendings.r THEN ChangeRadii[t.pick, t.r0.value, t.r1.value, t.size.value, t.epsilon.value]; IF t.pendings.tw0 THEN { ChangeTw0[t.pick, t.tw0.value, t.tw0.valuePrev]; IF t.pick.selected1 # NIL THEN Controls.SetSliderDialValue[t.tw1, t.pick.selected1.tw1]; }; IF t.pendings.tw1 THEN ChangeTw1[t.pick, t.tw1.value, t.tw1.valuePrev]; IF t.pendings.shape OR t.pendings.skin THEN MakeDetails[t]; }; IF forceReDraw THEN t.noDraw ¬ FALSE; IF t.vectors THEN G3dTool.Repaint[t.renderTool, t]; ClearPendings[t.pendings]; }; TubeControl: Controls.ControlProc ~ { t: Tool ~ NARROW[control.clientData]; Moused[t, control.mouse, control]; IF NOT t.noDraw AND (control.mouse.button = right OR control.whatChanged = $TypedIn) THEN CheckPendingAndRePaint[t]; }; MouseProc: Controls.MouseProc ~ { t: Tool ~ NARROW[clientData]; whatChanged: REF ANY ¬ $Select; view: Matrix ¬ GetView[viewer, t]; Moused[t, mouse, whatChanged]; t.neverMoused ¬ FALSE; IF mouse.state = up THEN RETURN; IF -- mouse.state = down OR -- NOT mouse.controlKey THEN { ScreenPick[t, mouse, view, t.pick]; G3dControl.SetHold[t.hold, t.pick.pos, t.pick.tan]; SetPick[t]; }; IF mouse.controlKey THEN { p: Pair ¬ [mouse.pos.x, mouse.pos.y]; plane: Quad ¬ [t.pick.plane.x, t.pick.plane.y, t.pick.plane.z, t.pick.plane.w]; q: Triple ¬ G3dMatrix.TripleFromScreenAndPlane[p, plane, view]; Controls.SetSliderDialValue[t.hold.x, q.x]; Controls.SetSliderDialValue[t.hold.y, q.y]; Controls.SetSliderDialValue[t.hold.z, q.z]; whatChanged ¬ t.hold.x -- $Pull -- ; } ELSE IF t.mouse.button = left THEN { point: Triple ¬ G3dSpline.Position[t.pick.tube.spline, t.pick.t]; message: ROPE ¬ IO.PutFLR["%g%g (%6.3f, %6.3f, %6.3f)", LIST[ IO.rope[IF t.tube.name # NIL THEN t.tube.name ELSE "Tube"], IO.rope[G3dTube.Where[t.pick.tube, t.tube]], IO.real[point.x], IO.real[point.y], IO.real[point.z]]]; MessageWindow.Append[message, TRUE]; }; <> CheckPendingAndRePaint[t]; }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <<};>> <> <> <<};>> <<>> SetPick: PROC [t: Tool] ~ { <> IF t.pick.selected0 # NIL THEN { Controls.SetSliderDialValue[t.r0, t.pick.selected0.r0]; Controls.SetSliderDialValue[t.tw0, t.pick.selected0.tw0]; Controls.SetSliderDialValue[t.tens0, t.pick.selected0.tens0]; }; IF t.pick.selected1 # NIL THEN { Controls.SetSliderDialValue[t.r1, t.pick.selected1.r1]; Controls.SetSliderDialValue[t.tw1, t.pick.selected1.tw1]; Controls.SetSliderDialValue[t.tens1, t.pick.selected1.tens1]; }; }; <> MakeDetails: PROC [t: Tool] ~ { G3dTube.Make[t.tube, t.details[skin], t.round, NIL, t.epsilon.value]; }; ResetTube: PROC RETURNS [tube: Tube] ~ { tube ¬ NEW[TubeRep ¬ [p0: [-0.5,0.,0.], p1: [0.5,0.,0.], v0: [1.,0.,1.], v1: [1.,0.,1.]]]; G3dTube.SetSpline[tube]; tube.name ¬ "Tube"; }; RenameViewer: PROC [t: Tool] ~ { IF Rope.Equal[t.tube.name, "Tube", FALSE] THEN RETURN; t.renderTool.outer.name ¬ Rope.Concat["3dTube ", t.tube.name]; t.renderTool.outer.label ¬ t.tube.name; ViewerOps.PaintViewer[t.renderTool.outer, caption]; }; ReplaceTube: PROC [t: Tool, tube: Tube] ~ { t.tube ¬ tube; IF tube.name = NIL THEN tube.name ¬ "Tube"; RenameViewer[t]; t.pendings ¬ NEW[PendingsRep ¬ [shape: TRUE]]; MakePick[t]; SetPick[t]; Moused[t, [[0, 0], up, left], $Buttons]; CheckPendingAndRePaint[t, TRUE]; }; Branch: PROC [t: Tool] ~ { IF t.pick.t = 0.0 AND t.pick.tube.prev = NIL THEN RETURN; IF t.pick.dividePending THEN DivideSpline[t]; G3dTube.AddBranch[t.pick.tube, G3dTube.NewBranch[t.pick.tube]]; CheckPendingAndRePaint[t, TRUE]; }; Delete: PROC [t: Tool] ~ { G3dTube.Delete[t.pick.selected0]; t.pick.selected0 ¬ t.pick.selected1 ¬ NIL; G3dTube.UnSelectAll[t.tube]; IF NOT G3dTube.Find[t.pick.tube, t.tube] THEN t.pick.tube ¬ NIL; CheckPendingAndRePaint[t, TRUE]; }; WeightRadii: PROC [t: Tool] ~ { G3dTube.SetDescendantRadii[t.tube, t.radiusMode]; t.pendings.skin ¬ TRUE; CheckPendingAndRePaint[t, TRUE]; }; FromControl: PROC [control: Control, t: REAL ¬ 0.0] RETURNS [contour: Contour] ~ { ips: G2dBasic.IntegerPairSequence ¬ Controls.GetContour[control]; IF ips # NIL THEN { offset: Pair ¬ [0.5*(control.w-1), 0.5*(control.h-1)]; scale: Pair ¬ [IF offset.x>0 THEN 1./offset.x ELSE 1., IF offset.y>0 THEN 1./offset.y ELSE 1.]; contour ¬ G2dContour.FromIntegerPairs[ips, Controls.IsContourClosed[control], t]; RETURN[G2dContour.Thin[G2dContour.Scale[G2dContour.Offset[contour, offset], scale]]]; }; }; GetContour: PROC [t: Tool] ~ { c: Control ~ Controls.LastControlMoused[]; IF c # NIL AND c.type = contour AND NOT c.viewer.destroyed THEN { G3dTube.AddContour[t.tube, G2dContour.Orient[FromControl[c, t.pick.t]]]; Moused[t, [[0, 0], up, left], $Buttons, "Contour received\n"]; t.pendings.skin ¬ TRUE; CheckPendingAndRePaint[t, TRUE]; } ELSE Controls.TypescriptWrite[t.renderTool.typescript, "1st middle-click a contour viewer\n"]; }; GetTube: PROC [t: Tool] ~ { tube: Tube ~ G3dTube.LastTubePicked[FALSE]; IF tube # NIL THEN ReplaceTube[t, tube] ELSE Controls.TypescriptWrite[t.renderTool.typescript, "1st click tube viewer\n"]; }; DestroyProc: Controls.DestroyProc ~ { t: Tool ~ NARROW[clientData]; MessageWindow.Clear[]; IF G3dTube.LastTubePicked[FALSE] = t.tube THEN G3dTube.SetLastTubePicked[NIL]; }; <> IOOps: ClickProc ~ { t: Tool ¬ NARROW[clientData]; SELECT Controls.PopUpRequest[["Misc Ops"], LIST[ -- 1 -- ["Read Tube", "read a tube from a file"], -- 2 -- ["Get Tube", "get a tube from another viewer"], -- 3 -- ["Get Contour", "get a contour from a viewer"], -- 4 -- ["Write Tube", "write a tube to a file"], -- 5 -- ["Write Curve", "write a curve to a file"], -- 6 -- ["Write Interpress", "write an Interpress file of the current image"], -- 7 -- ["Shape-Out", "write a shape file consisting of points and polygons"]]] FROM 1 => ReadTube[t]; 2 => GetTube[t]; 3 => GetContour[t]; 4 => WriteTube[t]; 5 => WriteCurve[t]; 6 => WriteInterpress[t]; 7 => WritePointsPolys[t]; ENDCASE; }; GetView: PROC [v: Controls.Viewer ¬ NIL, t: Tool] RETURNS [m: Matrix] ~ { m ¬ G3dTool.GetViewTransform[v, t.renderTool]; }; WriteTube: PROC [t: Tool] ~ { fileName: ROPE ¬ Controls.TypescriptReadFileName[t.renderTool.typescript]; IF fileName # NIL THEN { m: Matrix ~ IF t.xformIO THEN GetView[, t] ELSE NIL; t.tube.name ¬ G3dTube.ExtractTubeName[fileName]; G3dTube.TubeToFile[t.tube, fileName, m]; RenameViewer[t]; }; }; WritePointsPolys: PROC [t: Tool] ~ { nPoints, nPolys: INT; m: Matrix ~ IF t.xformIO THEN GetView[, t] ELSE NIL; fileName: ROPE ¬ Controls.TypescriptReadFileName[t.renderTool.typescript]; IF fileName = NIL THEN RETURN; [nPoints, nPolys] ¬ G3dTube.WritePointsPolys[t.tube, fileName, m]; Controls.TypescriptWrite[t.renderTool.typescript, IO.PutFR["%g points and %g polys written\n", IO.int[nPoints], IO.int[nPolys]]]; }; WriteInterpress: PROC [t: Tool] ~ { fileName: ROPE ¬ Controls.TypescriptReadFileName[t.renderTool.typescript]; IF fileName # NIL THEN { ref: ImagerInterpress.Ref ¬ ImagerInterpress.Create[fileName]; G3dTube.WriteIP[ref, t.tube, t.details, G3dTool.GetViewTransform[, t.renderTool]]; ImagerInterpress.Close[ref]; }; }; WriteCurve: PROC [t: Tool] ~ { fileName: ROPE ¬ Controls.TypescriptReadFileName[t.renderTool.typescript]; IF fileName # NIL THEN { out: STREAM ¬ FS.StreamOpen[fileName, $create]; c: G3dCurve.Curve ¬ G3dTube.CurveFromTube[t.tube]; name: ROPE ¬ IF t.tube.name # NIL THEN Rope.Concat["from ", t.tube.name] ELSE NIL; IF t.xformIO THEN G3dCurve.Transform[c, GetView[, t]]; G3dCurve.Write[out, c, name]; }; }; ReadTube: PROC [tool: Tool] ~ { name: ROPE ¬ Controls.TypescriptReadFileName[tool.renderTool.typescript]; tool.tube ¬ G3dTube.TubeFromFile[name]; IF tool.tube # NIL THEN ReplaceTube[tool, tool.tube] ELSE Blink["Couldn't read tube"]; }; TubeFromFile: PROC [t: Tool, name: ROPE] RETURNS [error: ROPE] ~ { r: ROPE ¬ FileNames.ResolveRelativePath[name]; stream: STREAM ¬ FS.StreamOpen[FS.ExpandName[r].fullFName ! FS.Error => GOTO noOpen]; t.tube ¬ G3dTube.ReadTube[stream]; IO.Close[stream]; IF t.tube = NIL THEN RETURN["No tube in file."]; t.tube.name ¬ G3dTube.ExtractTubeName[r]; EXITS noOpen => error ¬ IO.PutFR1["Couldn't open %g.\n", IO.rope[name]]; }; WriteTubeInfo: PROC [tube: Tube, o: OuterData] ~ { nPoints, nPolys, minCres, maxCres: INTEGER; [nPoints, nPolys, minCres, maxCres] ¬ G3dTube.Info[tube]; Controls.TypescriptWrite[o.typescript, IO.PutFLR["%g points, %g polygons, cres: %g-%g\n", LIST[IO.int[nPoints], IO.int[nPolys], IO.int[minCres], IO.int[maxCres]]]]; }; <> MakePick: PROC [t: Tool] ~ { t.pick ¬ NEW[PickRep ¬ [tube: t.tube]]; t.pendings.holdPosition ¬ t.pendings.holdTangent ¬ t.pendings.holdRoll ¬ FALSE; SetPoint[t]; IF t.hold.x.viewer # NIL THEN G3dControl.SetHold[t.hold, t.pick.pos, t.pick.tan]; }; ScreenPick: PROC [tool: Tool, mouse: Mouse, view: Matrix, pick: Pick] ~ { IF pick = NIL THEN RETURN; pick.mouse ¬ mouse; [[pick.tube, pick.t]] ¬ G3dTube.NearestTube2d[tool.tube, [mouse.pos.x, mouse.pos.y], mouse. state= down, view]; SELECT TRUE FROM mouse.button = right => { pick.type ¬ subTree; SetSubTree[tool]; }; mouse.shiftKey => { pick.type ¬ segment; SetSelection[tool]; }; ENDCASE => { pick.type ¬ point; SetPoint[tool]; }; }; UpdatePick: PROC [t: Tool] ~ { pick: Pick ¬ t.pick; IF pick.tube = NIL THEN RETURN; G3dTube.SetLastTubePicked[pick.tube]; pick.dividePending ¬ pick.t IN (0.0..1.0); pick.tan ¬ G3dSpline.Tangent[pick.tube.spline, pick.t]; pick.pos ¬ --pick.origPos ¬-- G3dSpline.Position[pick.tube.spline, pick.t]; IF t.renderTool # NIL THEN { <> <> <> <> <> nrm: Quad ¬ G3dMatrix.TransformH[[0,0,1], GetView[, t]]; pick.plane ¬ G3dPlane.FromPointAndNormal[t.pick.pos, [nrm.x, nrm.y, nrm.z], TRUE]; }; }; SetPoint: PROC [tool: Tool] ~ { IF tool.pick.tube = NIL THEN RETURN; IF tool.pick.t = 0.0 AND tool.pick.tube.prev # NIL THEN { tool.pick.t ¬ 1.0; tool.pick.tube ¬ tool.pick.tube.prev; }; IF tool.pick.selected0 # NIL THEN tool.pick.selected0.selected ¬ FALSE; IF tool.pick.selected1 # NIL THEN tool.pick.selected1.selected ¬ FALSE; tool.pick.selected0 ¬ tool.pick.selected1 ¬ NIL; UpdatePick[tool]; }; SetSelection: PROC [tool: Tool] ~ { pick: Pick ¬ tool.pick; pick.selected1 ¬ pick.tube; IF pick.mouse.button = middle OR pick.selected0 = NIL THEN pick.selected0 ¬ pick.selected1; pick.t ¬ IF pick.t > 0.5 THEN 1.0 ELSE 0.0; FOR t: Tube ¬ pick.selected0, t.next WHILE t # NIL DO -- ensure selected0 before selected1 IF t = pick.selected1 THEN EXIT; REPEAT FINISHED => { temp: Tube ¬ pick.selected0; pick.selected0 ¬ pick.selected1; pick.selected1 ¬ temp; }; ENDLOOP; G3dTube.UnSelectAll[G3dTube.First[pick.tube]]; -- set selected splines FOR t: Tube ¬ pick.selected0, t.next WHILE t # NIL AND t # pick.selected1.next DO t.selected ¬ TRUE; ENDLOOP; UpdatePick[tool]; }; SetSubTree: PROC [tool: Tool] ~ { tool.pick.selected0 ¬ tool.pick.selected1 ¬ tool.pick.tube; tool.pick.t ¬ IF tool.pick.t > 0.5 THEN 1.0 ELSE 0.0; G3dTube.UnSelectAll[G3dTube.First[tool.pick.tube]]; G3dTube.SelectAll[tool.pick.tube]; UpdatePick[tool]; }; DividePick: PROC [pick: Pick] ~ { IF pick.tube # NIL AND pick.dividePending AND pick.t IN (0.0..1.0) THEN { tubeProc: TubeProc ~ {tube.prev ¬ newTube}; newTube: Tube ¬ NEW[TubeRep ¬ [ spline: NEW[SplineRep], xSpline: NEW[SplineRep], prev: pick.tube, selected: pick.tube.selected, next: pick.tube.next, branches: pick.tube.branches, p1: pick.tube.p1, r1: pick.tube.r1, tw1: pick.tube.tw1]]; G3dTube.DivideContours[pick.tube, pick.tube, newTube, pick.t]; pick.tube.next ¬ newTube; pick.tube.branches ¬ NIL; G3dTube.ApplyToBranches[newTube, tubeProc, FALSE]; pick.tube.p1 ¬ newTube.p0 ¬ pick.pos --pick.origPos--; pick.tube.r1 ¬ newTube.r0 ¬ 0.5*(pick.tube.r0+newTube.r1); pick.tube.tw1 ¬ newTube.tw0 ¬ 0.5*(pick.tube.tw0+newTube.tw1); [] ¬ G3dSpline.Reparameterize[pick.tube.spline, pick.t, 1.0, newTube.spline]; [] ¬ G3dSpline.Reparameterize[pick.tube.spline, 0.0, pick.t, pick.tube.spline]; pick.tube.v0 ¬ G3dSpline.Tangent[pick.tube.spline, 0.0]; pick.tube.v1 ¬ G3dSpline.Tangent[pick.tube.spline, 1.0]; newTube.v0 ¬ G3dSpline.Tangent[newTube.spline, 0.0]; newTube.v1 ¬ G3dSpline.Tangent[newTube.spline, 1.0]; <> <<0.25*(3.0*(newTube.p1.x-pick.tube.p0.x)-pick.tube.v0.x-newTube.v1.x),>> <<0.25*(3.0*(newTube.p1.y-pick.tube.p0.y)-pick.tube.v0.y-newTube.v1.y),>> <<0.25*(3.0*(newTube.p1.z-pick.tube.p0.z)-pick.tube.v0.z-newTube.v1.z)];>> pick.t ¬ 1.0; pick.tan ¬ pick.tube.v1; }; pick.dividePending ¬ FALSE; }; NewSpline: PROC [pick: Pick] ~ { tubeProc: TubeProc ~ {G3dTube.SetSpline[tube]}; [] ¬ tubeProc[pick.tube]; G3dTube.ApplyToBranches[pick.tube, tubeProc]; }; RollSubTree: PROC [pick: Pick, rollAngle: REAL] ~ { IF G3dTube.NBranches[pick.tube] = 0 THEN RETURN; IF pick.t = 0.0 THEN G3dTube.Rotate[pick.tube, [pick.tube.p0, pick.tube.v0], rollAngle, TRUE, TRUE] ELSE { v: Triple ¬ IF pick.tube.next#NIL THEN pick.tube.next.v0 ELSE pick.tube.branches[0].v0; G3dTube.Rotate[pick.tube, [pick.tube.p1, v], rollAngle, TRUE, FALSE]; }; NewSpline[pick]; }; ChangeTangent: PROC [pick: Pick, hold: Hold] ~ { IF pick.tube # NIL THEN { tangent: Triple ¬ G3dControl.VectorFromHold[hold]; SELECT pick.type FROM point, segment => { IF pick.t = 0.0 THEN pick.tube.v0 ¬ tangent ELSE { <> <> <> <> tubeProc: TubeProc ~ { IF tube # NIL THEN tube.v0 ¬ G3dVector.Mul[tangent, G3dVector.Length[tube.v0]*iV1]; }; iV1: REAL ~ IF G3dVector.Null[pick.tube.v1] THEN 0.0 ELSE 1.0/G3dVector.Length[pick.tube.v1]; pick.tube.v1 ¬ tangent; IF iV1 # 0.0 THEN G3dTube.ApplyToBranches[pick.tube, tubeProc]; }; }; subTree => { axis: Triple ¬ G3dVector.Cross[tangent, pick.tan]; base: Triple ¬ IF pick.t = 0.0 THEN pick.tube.p0 ELSE pick.tube.p1; angle: REAL ¬ G3dVector.AngleBetween[tangent, pick.tan, , TRUE]; G3dTube.Rotate[pick.tube, [base, axis], angle, TRUE, pick.t = 0.0]; }; ENDCASE; pick.tan ¬ tangent; NewSpline[pick]; }; }; ChangePosition: PROC [pick: Pick, --change-- position: Triple] ~ { pick.pos ¬ position; <> IF pick.tube = NIL THEN RETURN; IF pick.t = 0.0 THEN pick.tube.p0 ¬ pick.pos ELSE { pick.tube.p1 ¬ pick.pos; FOR n: NAT IN [0..G3dTube.NBranches[pick.tube]) DO pick.tube.branches[n].p0 ¬ pick.pos; ENDLOOP; IF pick.tube.next # NIL THEN pick.tube.next.p0 ¬ pick.pos; }; NewSpline[pick]; }; ChangeRadii: PROC [pick: Pick, r0, r1, scale, epsilon: REAL] ~ { numberSelected: INTEGER ~ NumberSelected[pick]; IF numberSelected > 0 THEN { r: REAL ¬ r0; dr: REAL ~ (r1-r)/REAL[numberSelected]; IF pick.selected0.prev # NIL THEN pick.selected0.prev.r1 ¬ r; FOR t: Tube ¬ pick.selected0, t.next WHILE t # NIL AND t # pick.selected1.next DO t.r0 ¬ r; r ¬ r+dr; t.r1 ¬ r; ENDLOOP; IF pick.selected1.next # NIL THEN pick.selected1.next.r0 ¬ r; RemakeSelected[pick, scale, epsilon]; }; }; ChangeTension: PROC [pick: Pick, tens0, tens1: REAL] ~ { numberSelected: INTEGER ~ NumberSelected[pick]; IF numberSelected > 0 THEN { tens: REAL ¬ tens0; dtens: REAL ~ (tens1-tens0)/REAL[numberSelected]; FOR t: Tube ¬ pick.selected0, t.next WHILE t # NIL AND t # pick.selected1.next DO t.tens0 ¬ tens; tens ¬ tens+dtens; t.tens1 ¬ tens; G3dTube.SetSpline[t]; ENDLOOP; }; }; ChangeTw0: PROC [pick: Pick, tw0, tw0Prev: REAL] ~ { nBefore: INTEGER ~ BeforeSelected[pick]; change: REAL ~ tw0-tw0Prev; IF nBefore > 0 THEN { dchange: REAL ¬ 0.0; ddchange: REAL ¬ change/REAL[nBefore]; FOR t: Tube ¬ G3dTube.First[t], t.next WHILE t # pick.selected0 DO t.tw0 ¬ t.tw0+dchange; dchange ¬ dchange+ddchange; t.tw1 ¬ t.tw1+dchange; ENDLOOP; }; FOR t: Tube ¬ pick.selected0, t.next WHILE t # NIL DO t.tw0 ¬ t.tw0+change; t.tw1 ¬ t.tw1+change; ENDLOOP; }; ChangeTw1: PROC [pick: Pick, tw1, tw1Prev: REAL] ~ { nSelected: INTEGER ~ NumberSelected[pick]; change: REAL ~ tw1-tw1Prev; IF nSelected > 0 THEN { dchange: REAL ¬ 0.0; ddchange: REAL ¬ change/REAL[nSelected]; FOR t: Tube ¬ pick.selected0, t.next WHILE t # pick.selected1.next DO t.tw0 ¬ t.tw0+dchange; dchange ¬ dchange+ddchange; t.tw1 ¬ t.tw1+dchange; ENDLOOP; }; IF pick.selected1 # NIL THEN FOR t: Tube ¬ pick.selected1.next, t.next WHILE t # NIL DO t.tw0 ¬ t.tw0+change; t.tw1 ¬ t.tw1+change; ENDLOOP; }; NumberSelected: PROC [pick: Pick] RETURNS [INTEGER] ~ { n: INTEGER ¬ 0; IF pick.selected0 = NIL OR pick.selected1 = NIL THEN RETURN[0]; FOR t: Tube ¬ pick.selected0, t.next WHILE t # NIL AND t # pick.selected1.next DO n ¬ n+1; ENDLOOP; RETURN[n]; }; BeforeSelected: PROC [pick: Pick] RETURNS [INTEGER] ~ { n: INTEGER ¬ 0; FOR t: Tube ¬ pick.selected0.prev, t.prev WHILE t # NIL DO n ¬ n+1; ENDLOOP; RETURN[n]; }; AfterSelected: PROC [pick: Pick] RETURNS [INTEGER] ~ { n: INTEGER ¬ 0; FOR t: Tube ¬ pick.selected1.next, t.next WHILE t # NIL DO n ¬ n+1; ENDLOOP; RETURN[n]; }; RemakeSelected: PROC [pick: Pick, scale, epsilon: REAL] ~ { t0: Tube ¬ IF pick.selected0.prev # NIL THEN pick.selected0.prev ELSE pick.selected0; t1: Tube ¬ IF pick.selected1.next # NIL THEN pick.selected1.next ELSE pick.selected1; FOR t: Tube ¬ t0, t.next WHILE t # t1.next AND t # NIL DO t.epsilon ¬ epsilon; t.scale ¬ scale; G3dTube.MakeSectionXSections[t]; ENDLOOP; }; <> Blink: PROC [rope: ROPE] ~ { MessageWindow.Append[rope, TRUE]; MessageWindow.Blink[]; }; <> icon: Icons.IconFlavor ¬ Icons.NewIconFromFile["G3dUser.icons", 5]; designUsage: ROPE ~ "tube : Model tubular structures."; G3dTool.Register["Tube", TubeDesignCmd, designUsage]; END.