<> <> <> DIRECTORY CedarProcess, Commander, Contours, Controls, Controls3d, Draw2d, Draw3d, Icons, Menus, Real, Render3d, Rope, ThreeDBasics, ThreeDMisc, TubeDefs, TubeIO, TubeContour, TubeDisplay, TubeGeometry, TubeMisc, TubePick, TubeRender, Vector3d, ViewerOps; TubeDesignImpl: CEDAR PROGRAM IMPORTS CedarProcess, Commander, Contours, Controls, Controls3d, Draw2d, Draw3d, Icons, Real, Render3d, Rope, TubeContour, TubeDisplay, TubeGeometry, TubeIO, TubePick, TubeMisc, TubeRender, Vector3d, ViewerOps ~ BEGIN OPEN TubeDefs; <> UserData: TYPE ~ RECORD [o: OuterData, p: ProgramData]; ActionType: TYPE ~ {none, select, camera, spline, shape, button}; ProgramData: TYPE ~ REF ProgramDataRep; ProgramDataRep: TYPE ~ RECORD [ <> controls: ControlList _ NIL, -- list of the following controls: scale: Control _ NIL, -- scale 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 cam: Camera _ NIL, -- camera hold: Hold _ NIL, -- handle on a point and its tangent lim: Control _ NIL, -- vector limit <> buttons: ButtonList _ NIL, <> outer: Viewer _ NIL, outerData: OuterData _ NIL, graphics: Viewer _ NIL, graphicsData: GraphicsData _ NIL, view: Matrix _ NIL, <> context3d: Context3d _ NIL, renderProcess: CedarProcess.Process _ NIL, vectors: BOOL _ TRUE, render: BOOL _ FALSE, renderStyle: RenderStyle _ smooth, backFaces: BOOL _ FALSE, noDraw: BOOL _ FALSE, <> details: Details _ NIL, pendings: Pendings _ NIL, 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 <> tube: Tube _ NIL -- all the tube splines ]; <> TubeDesign: Commander.CommandProc ~ { p: ProgramData ~ NEW[ProgramDataRep]; InitProgramData[p]; InitViewer[p]; ReplaceTube[p, ResetTube[]]; }; InitProgramData: PROC [p: ProgramData] ~ { p.view _ NEW[MatrixRep]; p.details _ NEW[DetailsRep]; p.pendings _ NEW[PendingsRep]; p.cam _ Controls3d.InitCamera[scale: 3.0, data: p, proc: CameraControl]; p.hold _ Controls3d.InitHold[TubeControl, p]; p.tw0 _ Controls.NewControl["tw0", vSlider, p, -1000., 1000., 0.0, TubeControl]; p.tw1 _ Controls.NewControl["tw1", vSlider, p, -1000., 1000., 0.0, TubeControl]; p.tens0 _ Controls.NewControl["tens0", vSlider, p, -3.0, 3.0, 0.0, TubeControl]; p.tens1 _ Controls.NewControl["tens1", vSlider, p, -3.0, 3.0, 0.0, TubeControl]; p.r0 _ Controls.NewControl["r0", vSlider, p, 0.0, 0.5, 0.0, TubeControl]; p.r1 _ Controls.NewControl["r1", vSlider, p, 0.0, 0.5, 0.0, TubeControl]; p.scale _ Controls.NewControl["scale", vSlider, p, 0.0, 4.0, 1.0, TubeControl]; p.epsilon _ Controls.NewControl["eps", vSlider, p, 0.0, 0.2, 0.03, TubeControl,,,,,,,,,,,, exp]; p.cres _ Controls.NewControl["cres", vSlider, p, 3.0, 25.0, 6.0, TubeControl, , TRUE]; p.lim _ Controls.NewControl["lim", vSlider, p, 0.0, 1000.0, 500.0, TubeControl, , TRUE]; p.controls _ LIST[ p.hold.x, p.hold.y, p.hold.z, p.hold.lng, p.hold.lat, p.hold.mag, p.tw0, p.tw1, p.r0, p.r1, p.scale, p.tens0, p.tens1, p.cam.xGlobal, p.cam.yGlobal, p.cam.zGlobal, p.cam.scale, p.cam.hScreen, p.cam.vScreen, p.cam.fieldOfView, p.lim, p.epsilon, p.cres]; p.buttons _ LIST[ <> [name: "Tube Ops:", proc: NIL, row: 3], [name: "New", proc: NewTube, guarded: TRUE, row: 3, x: 75], ["Branch", Branch, 3], ["Delete", Delete, 3], ["Wt Rad", WeightRadii, 3], ["Linear", CycleRadiusMode, 3], ["Round-Off", TogRound, 3], ["Read", ReadFile, 3], ["Get", GetTube, 3], ["Get Contour", GetContour, 3], ["Write", WriteFile, 3], <> [name: "Misc Ops:", proc: NIL, row: 2], [name: "Rend-Off", proc: TogRender, row: 2, x: 75], ["Smooth", TogRenderStyle, 2], ["BFaces-Off", TogBackFaces, 2], ["Abort Rend", AbortRender, 2], ["Norm IO", TogXformIO, 2], ["PP-Out", WriteFile, 2], ["IP-Out", WriteFile, 2], <> [name: "Draw Ops:", proc: NIL, row: 1], [name: "Vectors-On", proc: TogVectors, row: 1, x: 75], ["Skel-Off", TogSkel, 1], ["Splines-On", TogSpline, 1], ["Ends-On", TogEnds, 1], ["Pick-On", TogPick, 1], ["Label-On", TogLabel, 1], ["Auto-Off", TogAuto, 1], [name: "Contours-Off", proc: TogContours, row: 0, x: 75], ["Lines-Off", TogLines, 0], ["Frames-Off", TogFrames, 0], ["Normals-Off", TogNormals, 0], ["Curv-Off", TogCurv, 0], ["Vel-Off", TogVel, 0], ["Acc-Off", TogAcc, 0]]; }; InitViewer: PROC [p: ProgramData] ~ { Controls.ControlRow[p.cam.xGlobal, 1]; p.outer _ Controls.OuterViewer[ name: "Tube Design", buttons: p.buttons, controls: p.controls, controlSizes: [20, 200, 60, 20, 60, 150, 150], typeScriptHeight: 18, graphicsHeight: 300, graphicsProc: ScreenPick, graphicsShow: GraphicsShow, data: p, destroyProc: DestroyProc, noOpen: TRUE]; p.outerData _ NARROW[p.outer.data]; p.buttons _ p.outerData.buttons; p.graphics _ p.outerData.graphics; p.graphicsData _ NARROW[p.graphics.data]; p.outer.icon _ Icons.NewIconFromFile["///Commands/Tube.icon", 0]; ViewerOps.OpenIcon[p.outer]; }; GraphicsShow: Controls.GraphicsShow ~ { p: ProgramData ~ NARROW[data]; Action: PROC ~ { p.view _ Controls3d.InitContext[context, p.cam, p.view]; IF p.details.spline AND p.details.ends THEN TubeDisplay.DrawSplineEnds[p.tube, context, p.view]; IF p.details.enabled THEN TubeDisplay.DrawTube[p.tube, context, p.details, p.view] ELSE IF p.details.spline THEN TubeDisplay.DrawSplines[p.tube, context, p.view]; IF p.details.pick AND p.pick # NIL AND p.pick.tube # NIL THEN Draw3d.Vector[context, p.pick.pos, p.pick.tan, p.view, , , IF p.pick.t IN (0.0..1.0) THEN cross ELSE none]; }; IF whatChanged # NIL AND p.noDraw THEN RETURN; IF TubeDisplay.NVectors[p.tube, p.details] < p.lim.value THEN Draw2d.DoWithBuffer[context, Action] ELSE Action[]; }; <> Moused: PROC [p: ProgramData, mouse: Mouse, whatChanged: REF ANY, msg: ROPE _ NIL] ~ { p.mousePrev _ p.mouse; p.mouse _ mouse; p.action _ SELECT whatChanged FROM p.buttons => button, p.graphicsData => select, p.cam => camera, p.hold.lat, p.hold.lng, p.hold.mag, p.hold.x, p.hold.y, p.hold.z, p.epsilon => spline, p.scale, p.r0, p.r1, p.tw0, p.tw1, p.cres => shape, ENDCASE => none; p.details.enabled _ NOT p.details.autoSimplify OR p.action = shape OR p.mouse.state = up; p.noDraw _ p.mouse.state = up AND p.action # button AND NOT p.details.autoSimplify; IF NOT p.noDraw THEN SELECT whatChanged FROM p.scale => p.pendings.scale _ TRUE; p.r0, p.r1 => p.pendings.r _ TRUE; p.tw0 => p.pendings.tw0 _ TRUE; p.tw1 => p.pendings.tw1 _ TRUE; p.tens0, p.tens1 => p.pendings.tens _ TRUE; p.cres => p.pendings.cres _ TRUE; p.epsilon => p.pendings.epsilon _ TRUE; p.hold.x, p.hold.y, p.hold.z => p.pendings.holdPosition _ TRUE; p.hold.lng, p.hold.lat, p.hold.mag => p.pendings.holdTangent _ TRUE; ENDCASE; IF p.action = spline AND p.pick.dividePending THEN DivideSpline[p]; IF msg = NIL THEN Controls.TypeScriptClear[p.outerData] ELSE Controls.TypeScriptWrite[p.outerData, msg]; }; DivideSpline: PROC [p: ProgramData] ~ { TubePick.DivideSpline[p.pick]; Controls.SetSliderDialValue[p.hold.mag, Vector3d.Length[p.pick.tube.v1]]; }; CheckPendingAndRePaint: PROC [p: ProgramData, forceReDraw: BOOL _ FALSE] ~ { p.pendings.shape _ p.pendings.shape OR p.pendings.holdPosition OR p.pendings.holdTangent; p.pendings.skin _ p.pendings.skin OR p.pendings.shape OR p.pendings.r OR p.pendings.tens OR p.pendings.tw0 OR p.pendings.tw1 OR p.pendings.epsilon; IF p.pendings.holdPosition THEN TubePick.ChangePosition[p.pick, [p.hold.x.value, p.hold.y.value, p.hold.z.value]]; IF p.pendings.holdTangent THEN TubePick.ChangeTangent[p.pick, Vector3d.CartesianFromPolar[[p.hold.lng.value, p.hold.lat.value, p.hold.mag.value]]]; IF p.pendings.scale THEN TubeGeometry.ReScale[p.tube, p.scale.value, 0.0]; IF p.pendings.cres THEN TubeContour.PropagateCircleRes[p.tube, Real.RoundI[p.cres.value]]; IF p.pendings.tens THEN TubePick.ChangeTension[p.pick, p.tens0.value, p.tens1.value]; IF p.details.skin OR p.details.shape THEN { IF p.pendings.r THEN TubePick.ChangeRadii[p.pick, p.r0.value, p.r1.value, p.scale.value, p.epsilon.value]; IF p.pendings.tw0 THEN { TubePick.ChangeTw0[p.pick, p.tw0.value, p.tw0.valuePrev]; IF p.pick.selected1 # NIL THEN Controls.SetSliderDialValue[p.tw1, p.pick.selected1.tw1]; }; IF p.pendings.tw1 THEN TubePick.ChangeTw1[p.pick, p.tw1.value, p.tw1.valuePrev]; IF p.pendings.shape OR p.pendings.skin THEN MakeDetails[p]; }; IF forceReDraw THEN p.noDraw _ FALSE; IF p.vectors THEN ViewerOps.PaintViewer[p.graphics, client, FALSE, p]; IF p.render THEN { IF p.renderProcess = NIL OR CedarProcess.GetStatus[p.renderProcess] # busy THEN { IF p.pendings.skin OR p.pendings.cres OR p.pendings.scale OR p.pendings.r OR p.pendings.tens THEN TubeRender.AddTube[p.tube, p.context3d, p.renderStyle]; p.renderProcess _ CedarProcess.Fork[ForkRender, p]; }; }; TubeMisc.ClearPendings[p.pendings]; }; CameraControl: Controls3d.CameraProc ~ { p: ProgramData ~ NARROW[data]; Moused[p, control.mouse, control]; IF p.noDraw THEN RETURN; IF control.mouse.button = right THEN CheckPendingAndRePaint[p]; }; TubeControl: Controls.ControlProc ~ { p: ProgramData ~ NARROW[control.data]; Moused[p, control.mouse, control]; IF p.noDraw THEN RETURN; IF control.mouse.button = right THEN CheckPendingAndRePaint[p]; }; MakePick: PROC [p: ProgramData] ~ { p.pick _ NEW[PickRep _ [tube: p.tube]]; p.pendings.holdPosition _ p.pendings.holdTangent _ FALSE; TubePick.SetPickPoint[p.pick]; IF p.hold.x.viewer # NIL THEN Controls3d.FocusHold[p.pick.tan, p.hold]; }; ScreenPick: Controls.GraphicsProc ~ { <> p: ProgramData ~ NARROW[graphics.data]; Moused[p, graphics.mouse, graphics]; IF p.mouse.state = up THEN RETURN; TubePick.ScreenPick[p.tube, p.mouse, p.view, p.pick]; IF p.mouse.button = left THEN Controls3d.FocusHold[p.pick.tan, p.hold]; FocusPick[p]; ViewerOps.PaintViewer[graphics.viewer, client, FALSE, graphics]; }; FocusPick: PROC [p: ProgramData] ~ { <> IF p.pick.selected0 # NIL THEN { Controls.SetSliderDialValue[p.r0, p.pick.selected0.r0]; Controls.SetSliderDialValue[p.tw0, p.pick.selected0.tw0]; Controls.SetSliderDialValue[p.tens0, p.pick.selected0.tens0]; }; IF p.pick.selected1 # NIL THEN { Controls.SetSliderDialValue[p.r1, p.pick.selected1.r1]; Controls.SetSliderDialValue[p.tw1, p.pick.selected1.tw1]; Controls.SetSliderDialValue[p.tens1, p.pick.selected1.tens1]; }; }; <> NewTube: ClickProc ~ {ReplaceTube[UserDataFromClientData[clientData].p, ResetTube[]]}; MakeDetails: PROC [p: ProgramData] ~ { TubeGeometry.MakeFrames[p.tube, p.epsilon.value, p.scale.value, 0, p.details.skin, p.round]; <<, p.view];>> }; ResetTube: PROC RETURNS [tube: Tube] ~ { tube _ NEW[TubeRep _ [p0: [-0.5,0.,0.], p1: [0.5,0.,0.], v0: [1.,1.,0.], v1: [1.,1.,0.]]]; TubeGeometry.SetCoeffs[tube]; tube.name _ "Tube"; }; ReplaceTube: PROC [p: ProgramData, tube: Tube] ~ { p.tube _ tube; IF tube.name = NIL THEN tube.name _ "Tube"; p.pendings _ NEW[PendingsRep _ [shape: TRUE]]; MakePick[p]; FocusPick[p]; Moused[p, [0, 0, up, left], p.buttons]; CheckPendingAndRePaint[p, TRUE]; }; Branch: ClickProc ~ { p: ProgramData ~ UserDataFromClientData[clientData].p; IF p.pick.t = 0.0 AND p.pick.tube.prev = NIL THEN RETURN; IF p.pick.dividePending THEN DivideSpline[p]; TubeMisc.AddBranch[p.pick.tube, TubeMisc.NewBranch[p.pick.tube]]; CheckPendingAndRePaint[p, TRUE]; }; Delete: ClickProc ~ { p: ProgramData ~ UserDataFromClientData[clientData].p; TubeMisc.Delete[p.pick.selected0]; p.pick.selected0 _ p.pick.selected1 _ NIL; TubeMisc.UnSelectAll[p.tube]; IF NOT TubeMisc.Find[p.pick.tube, p.tube] THEN p.pick.tube _ NIL; CheckPendingAndRePaint[p, TRUE]; }; WeightRadii: ClickProc ~ { p: ProgramData ~ UserDataFromClientData[clientData].p; TubeMisc.SetDescendantRadii[p.tube, p.radiusMode]; p.pendings.skin _ TRUE; CheckPendingAndRePaint[p, TRUE]; }; GetContour: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; c: Control ~ Controls.LastControlMoused[]; IF c # NIL AND c.type = contour AND NOT c.viewer.destroyed THEN { TubeContour.AddContour[u.p.tube, Contours.Orient[Contours.FromControl[c, u.p.pick.t]]]; Moused[u.p, [0, 0, up, left], u.p.buttons, "Contour received\n"]; u.p.pendings.skin _ TRUE; CheckPendingAndRePaint[u.p, TRUE]; } ELSE { Controls.TypeScriptWrite[u.o, "First middle-click a contour viewer\n"]; RETURN; }; }; GetTube: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; tube: Tube ~ TubePick.LastTubePicked[]; IF tube # NIL THEN ReplaceTube[u.p, tube] ELSE Controls.TypeScriptWrite[u.o, "First click a tube viewer\n"]; }; <> DestroyProc: Controls.DestroyProc ~ { p: ProgramData ~ NARROW[NARROW[outerData, OuterData].data]; Render3d.NullifyThreeDContext[p.context3d]; }; ForkRender: CedarProcess.ForkableProc ~ { p: ProgramData ~ NARROW[data]; Render3d.Render[p.context3d, p.tube.name, p.cam]; }; AbortRender: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; u.p.context3d.stopMe _ TRUE; u.p.render _ FALSE; Controls.ButtonReLabel[u.o, "Render-On", "Render-Off"]; }; <> WriteFile: ClickProc ~ { Equal: PROC [r: ROPE] RETURNS [BOOL] ~ {RETURN[Rope.Equal[button, r, FALSE]]}; button: ROPE ~ NARROW[parent, Viewer].name; u: UserData ~ UserDataFromClientData[clientData]; m: Matrix ~ IF u.p.xformIO THEN u.p.cam.matrix ELSE NIL; SELECT TRUE FROM Equal["Write"] => TubeIO.QueryAndWriteTube[u.p.tube, u.o, m]; Equal["IP-Out"] => TubeIO.QueryAndWriteIP[u.p.tube, u.o, u.p.details, u.p.view]; Equal["PP-Out"] => TubeIO.QueryAndWritePointsPoly[u.p.tube, u.o, m]; ENDCASE; }; ReadFile: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; tube: Tube ~ TubeIO.QueryAndReadTube[u.o]; IF tube # NIL THEN ReplaceTube[u.p, tube]; }; <> TogDetail: PROC [r: REF ANY, button: Menus.MouseButton, type: DetailType, name: ROPE] ~ { u: UserData ~ UserDataFromClientData[r]; m: Mouse ~ [0, 0, up, SELECT button FROM red => left, yellow => middle, ENDCASE => right]; wasShape: BOOL ~ u.p.details.shape; wasSkin: BOOL ~ u.p.details.skin; TubeMisc.ToggleDetail[u.p.details, type, Rope.Cat[name, "-On"], Rope.Cat[name, "-Off"], u.o]; Moused[u.p, m, u.p.buttons]; IF wasShape # u.p.details.shape THEN u.p.pendings.shape _ u.p.details.shape; IF wasSkin # u.p.details.skin THEN u.p.pendings.skin _ u.p.details.skin; IF type # autoSimplify AND button = blue THEN CheckPendingAndRePaint[u.p, TRUE]; }; TogLabel: ClickProc ~ {TogDetail[clientData, mouseButton, label, "Label"]}; TogAuto: ClickProc ~ {TogDetail[clientData, mouseButton, autoSimplify, "Auto"]}; TogSkel: ClickProc ~ {TogDetail[clientData, mouseButton, skeleton, "Skel"]}; TogPick: ClickProc ~ {TogDetail[clientData, mouseButton, pick, "Pick"]}; TogSpline: ClickProc ~ {TogDetail[clientData, mouseButton, spline, "Splines"]}; TogEnds: ClickProc ~ {TogDetail[clientData, mouseButton, ends, "Ends"]}; TogContours: ClickProc ~ {TogDetail[clientData, mouseButton, contours, "Contours"]}; TogLines: ClickProc ~ {TogDetail[clientData, mouseButton, lines, "Lines"]}; TogFrames: ClickProc ~ {TogDetail[clientData, mouseButton, frames, "Frames"]}; TogNormals: ClickProc ~ {TogDetail[clientData, mouseButton, normals, "Normals"]}; TogCurv: ClickProc ~ {TogDetail[clientData, mouseButton, curvature, "Curv"]}; TogVel: ClickProc ~ {TogDetail[clientData, mouseButton, velocity, "Vel"]}; TogAcc: ClickProc ~ {TogDetail[clientData, mouseButton, acceleration, "Acc"]}; TogXformIO: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; Controls.ButtonToggle[u.o, u.p.xformIO _ NOT u.p.xformIO, "Xfrm IO", "Norm IO"]; }; TogRender: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; Controls.ButtonToggle[u.o, u.p.render _ NOT u.p.render, "Rend-On", "Rend-Off"]; IF u.p.render THEN { IF u.p.context3d = NIL THEN u.p.context3d _ Render3d.InitContext3d[]; TubeRender.AddTube[u.p.tube, u.p.context3d, u.p.renderStyle]; }; IF mouseButton = blue THEN CheckPendingAndRePaint[u.p]; }; TogVectors: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; Controls.ButtonToggle[u.o, u.p.vectors _ NOT u.p.vectors, "Vectors-On", "Vectors-Off"]; IF mouseButton = blue THEN CheckPendingAndRePaint[u.p, TRUE]; }; TogRenderStyle: ClickProc ~ { RopeFromType: PROC [type: RenderStyle] RETURNS [rope: ROPE] ~ { rope _ SELECT type FROM smooth => "Smooth", shiny => "Shiny", ENDCASE => "Faceted"; }; u: UserData ~ UserDataFromClientData[clientData]; old: RenderStyle ~ u.p.renderStyle; u.p.renderStyle _ IF old = RenderStyle.LAST THEN RenderStyle.FIRST ELSE SUCC[old]; IF mouseButton = blue THEN CheckPendingAndRePaint[u.p]; Controls.ButtonReLabel[u.o, RopeFromType[old], RopeFromType[u.p.renderStyle]]; Render3d.SetRenderStyle[u.p.context3d, u.p.tube.name, u.p.renderStyle]; }; TogBackFaces: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; u.p.backFaces _ NOT u.p.backFaces; Controls.ButtonToggle[u.o, u.p.backFaces, "BFaces-On", "BFaces-Off"]; Render3d.SetInsideVisible[u.p.context3d, u.p.tube.name, u.p.backFaces]; IF mouseButton = blue THEN CheckPendingAndRePaint[u.p]; }; TogRound: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; u.p.round _ NOT u.p.round; u.p.pendings.shape _ TRUE; Controls.ButtonToggle[u.o, u.p.round, "Round-On", "Round-Off"]; IF mouseButton = blue THEN CheckPendingAndRePaint[u.p]; }; CycleRadiusMode: ClickProc ~ { u: UserData ~ UserDataFromClientData[clientData]; Roper: PROC [mode: RadiusMode] RETURNS [ROPE] ~ { RETURN[SELECT mode FROM linear => "Linear", ENDCASE => "Square"]; }; old: RadiusMode ~ u.p.radiusMode; u.p.radiusMode _ IF old = RadiusMode.LAST THEN RadiusMode.FIRST ELSE SUCC[old]; IF u.o # NIL THEN Controls.ButtonReLabel[u.o, Roper[old], Roper[u.p.radiusMode]]; }; <> UserDataFromClientData: PROC [clientData: REF ANY] RETURNS [u: UserData] ~ { u.p _ NARROW[(u.o _ NARROW[clientData]).data]; }; <> Commander.Register["///Commands/Tube", TubeDesign, "\nModel tubular structures."]; END.