<> <> <> DIRECTORY Matrix3d, Spline3d, Vector3d, TubeContour, TubeDefs, TubeMisc, TubePick, TubeGeometry; TubePickImpl: CEDAR PROGRAM IMPORTS Matrix3d, Spline3d, TubeContour, TubeGeometry, TubeMisc, Vector3d EXPORTS TubePick ~ BEGIN OPEN TubeDefs; lastTubePicked: Tube _ NIL; NearestTube: TYPE ~ RECORD [tube: Tube, t: REAL]; LastTubePicked: PUBLIC PROC RETURNS [Tube] ~ { RETURN[lastTubePicked]; }; ScreenPick: PUBLIC PROC [tube: Tube, mouse: Mouse, view: Matrix, pick: Pick] ~ { lastTubePicked _ tube; IF pick # NIL THEN IF mouse.button = left THEN { [[pick.tube, pick.t]] _ ClosestTube[tube, mouse, view]; SetPickPoint[pick] } ELSE { pick.selected1 _ ClosestTube[tube, mouse, view].tube; IF mouse.button = middle OR pick.selected0 = NIL THEN pick.selected0 _ pick.selected1; SetPickSelected[pick]; }; }; ClosestTube: PROC [tube: Tube, mouse: Mouse, view: Matrix] RETURNS [near: NearestTube] ~ { t, dist, minDist: REAL _ 1000.0; hasPersp: BOOL _ Matrix3d.HasPerspective[view]; tubeProc: TubeProc ~ { near2d: Near2d _ Spline3d.NearestPair[[mouse.x, mouse.y], tube.xCoeffs, hasPersp]; IF near2d.distance < minDist THEN { minDist _ near2d.distance; near.t _ SELECT near2d.t FROM < 0.05 => 0.0, > 0.95 => 1.0, ENDCASE => near2d.t; near.tube _ tube; }; }; IF mouse.state = down THEN { tubeProc: TubeProc ~ {tube.xCoeffs _ Matrix3d.Mul[tube.coeffs, view, tube.xCoeffs]}; TubeMisc.ApplyToTube[tube, tubeProc]; }; TubeMisc.ApplyToTube[tube, tubeProc]; }; SetPickPoint: PUBLIC PROC [pick: Pick] ~ { IF pick.t = 0.0 AND pick.tube.prev # NIL THEN { pick.t _ 1.0; pick.tube _ pick.tube.prev; }; IF pick.selected0 # NIL THEN pick.selected0.selected _ FALSE; IF pick.selected1 # NIL THEN pick.selected1.selected _ FALSE; pick.selected0 _ pick.selected1 _ NIL; pick.dividePending _ pick.t IN (0.0..1.0); pick.tan _ Spline3d.Tangent[pick.tube.coeffs, pick.t]; pick.pos _ pick.origPos _ Spline3d.Position[pick.tube.coeffs, pick.t]; }; SetPickSelected: PUBLIC PROC [pick: Pick] ~ { 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; TubeMisc.UnSelectAll[TubeMisc.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; }; DivideSpline: PUBLIC PROC [pick: Pick] ~ { IF pick.dividePending AND pick.t IN (0.0..1.0) THEN { tubeProc: TubeProc ~ {tube.prev _ newTube}; newTube: Tube _ NEW[TubeRep _ [ coeffs: NEW[CoeffsRep], xCoeffs: NEW[CoeffsRep], 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]]; TubeContour.DivideContours[pick.tube, pick.tube, newTube, pick.t]; pick.tube.next _ newTube; pick.tube.branches _ NIL; TubeMisc.ApplyToBranches[newTube, tubeProc, FALSE]; pick.tube.p1 _ newTube.p0 _ 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); [] _ Spline3d.Reparameterize[pick.tube.coeffs, pick.t, 1.0, newTube.coeffs]; [] _ Spline3d.Reparameterize[pick.tube.coeffs, 0.0, pick.t, pick.tube.coeffs]; pick.tube.v0 _ Spline3d.Tangent[pick.tube.coeffs, 0.0]; pick.tube.v1 _ Spline3d.Tangent[pick.tube.coeffs, 1.0]; newTube.v0 _ Spline3d.Tangent[newTube.coeffs, 0.0]; newTube.v1 _ Spline3d.Tangent[newTube.coeffs, 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; <> }; NewSplits: PUBLIC PROC [pick: Pick] ~ { tubeProc: TubeProc ~ {IF tube # NIL THEN TubeGeometry.SetCoeffs[tube]}; [] _ tubeProc[pick.tube]; TubeMisc.ApplyToBranches[pick.tube, tubeProc]; }; ChangeTangent: PUBLIC PROC [pick: Pick, tangent: Triple] ~ { pick.tan _ tangent; IF pick.tube = NIL THEN RETURN; IF pick.t = 0.0 THEN pick.tube.v0 _ tangent ELSE { <> <> <> <> tubeProc: TubeProc ~ { IF tube # NIL THEN tube.v0 _ Vector3d.Mul[tangent, Vector3d.Length[tube.v0]*iV1]; }; iV1: REAL ~ IF pick.tube.v1 = origin THEN 0.0 ELSE 1.0/Vector3d.Length[pick.tube.v1]; pick.tube.v1 _ tangent; IF iV1 # 0.0 THEN TubeMisc.ApplyToBranches[pick.tube, tubeProc]; }; NewSplits[pick]; }; ChangePosition: PUBLIC PROC [pick: Pick, change: Triple] ~ { pick.pos _ Vector3d.Add[pick.origPos, change]; 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..TubeMisc.NBranches[pick.tube]) DO pick.tube.branches[n].p0 _ pick.pos; ENDLOOP; IF pick.tube.next # NIL THEN pick.tube.next.p0 _ pick.pos; }; NewSplits[pick]; }; ChangeRadii: PUBLIC 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: PUBLIC 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; TubeGeometry.SetCoeffs[t]; ENDLOOP; }; }; ChangeTw0: PUBLIC 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 _ TubeMisc.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: PUBLIC 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: PUBLIC 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: PUBLIC 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: PUBLIC 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: PUBLIC 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 TubeGeometry.MakeSectionFrames[t, epsilon, scale, scale]; ENDLOOP; }; END.