TubePickImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, February 24, 1987 6:14:46 pm PST
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];
pick.tube.v1 ← newTube.v0 ← [
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[pick];
};
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 {
If T = new vector, V0 = beginning vector of outgoing tube, and V1 = end vector of
incoming tube, then T|V0|/|T| is a vector in direction T with length of V0.
We would like V0 length to increase, however, by |T|/|V1|.
So, V0 should be assigned T|V0||T|/|T||V1| = T|V0|/|V1|.
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.