TubeContourImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, February 24, 1987 6:14:39 pm PST
DIRECTORY Contours, Matrix3d, Real, TubeDefs, TubeContour, TubeGeometry, TubeMisc, Vector2;
TubeContourImpl: CEDAR PROGRAM
IMPORTS Contours, Matrix3d, Real, TubeGeometry, TubeMisc, Vector2
EXPORTS TubeContour
~ BEGIN
OPEN TubeDefs;
ContourRep:    TYPE ~ Contours.ContourRep;
ContourSequenceRep: TYPE ~ Contours.ContourSequenceRep;
NContours: PUBLIC PROC [tube: Tube] RETURNS [INTEGER] ~ {
RETURN[IF tube.contours # NIL THEN tube.contours.length ELSE 0];
};
TestContourSequence: PROC [contours: ContourSequence] RETURNS [ContourSequence] ~ {
IF contours = NIL OR contours.length >= contours.maxLength
THEN contours ← LengthenContourSequence[contours];
RETURN[contours];
};
LengthenContourSequence: PROC [contours: ContourSequence] RETURNS [ContourSequence]
~ {
nContours: INTEGERIF contours = NIL THEN 0 ELSE contours.length;
new: ContourSequence ← NEW[ContourSequenceRep[MAX[5, Real.RoundI[1.3*nContours]]]];
FOR i: NAT IN[0..nContours) DO new[i] ← contours[i]; ENDLOOP;
FOR i: NAT IN[nContours..new.maxLength) DO new[i] ← NEW[ContourRep]; ENDLOOP;
new.length ← nContours;
RETURN[new];
};
AddContour: PUBLIC PROC [tube: Tube, contour: Contour] ~ {
InsertContour: PROC [contour: Contour, contours: ContourSequence, n: NAT] ~ {
FOR i: INT DECREASING IN [n..contours.length) DO contours[n+1] ← contours[n]; ENDLOOP;
contours[n] ← contour;
};
new: Contour ← NEW[ContourRep ← contour^];
tube.contours ← TestContourSequence[tube.contours];
SELECT TRUE FROM
tube.contours.length = 0 =>
tube.contours[0] ← new;
new.t < tube.contours[0].t =>
InsertContour[new, tube.contours, 0];
new.t > tube.contours[tube.contours.length-1].t =>
tube.contours[tube.contours.length] ← new;
ENDCASE => {
n: NAT ← 0;
WHILE tube.contours[n].t < new.t DO n ← n+1; ENDLOOP;
IF tube.contours[n].t = new.t THEN {
tube.contours[n] ← new;
RETURN;
};
InsertContour[new, tube.contours, n];
};
tube.contours.length ← tube.contours.length+1;
};
DivideContours: PUBLIC PROC [tube, tube0, tube1: Tube, t: REAL] ~ {
circle: Contour ← Contours.Circle[tube.circleRes];
NewTs: PROC [tube: Tube, t0, t1: REAL] ~ {
div: REALIF t0 = t1 THEN 1.0 ELSE 1.0/(t1-t0);
FOR n: NAT IN [0..tube.contours.length) DO
tube.contours[n].t ← (tube.contours[n].t-t0)*div;
ENDLOOP;
};
IF tube.contours # NIL THEN {
contours: ContourSequence ← tube.contours;    -- tube may = tube0 or tube1
divideContour: Contour ← TContour[contours, circle, t];
tube0.contours ← tube1.contours ← NIL;
AddContour[tube1, divideContour];
FOR n: NAT IN [0..contours.length) DO
SELECT contours[n].t FROM
<= t => AddContour[tube0, contours[n]];
>= t => AddContour[tube1, contours[n]];
ENDCASE;
ENDLOOP;
AddContour[tube0, divideContour];
NewTs[tube0, 0.0, t];
NewTs[tube1, t, 1.0];
};
};
Alpha: PROC [t, t0, t1: REAL] RETURNS [REAL] ~ {
RETURN[IF t0 = t1 THEN t0 ELSE (t-t0)/(t1-t0)];
};
TContour: PUBLIC PROC [contours: ContourSequence, circle: Contour, t: REAL]
RETURNS [Contour] ~ {
IF contours = NIL
THEN RETURN[circle]
ELSE {
c0, c1: Contour ← NIL;
FOR n: NAT IN [0..contours.length) WHILE contours[n].t <= t DO
c0 ← contours[n];
ENDLOOP;
FOR n: NAT DECREASING IN [0..contours.length) WHILE contours[n].t >= t DO
c1 ← contours[n];
ENDLOOP;
RETURN[SELECT TRUE FROM
c0 = NIL AND c1 = NIL => circle,
c0 = NIL => Contours.Interpolate[circle, c1, Alpha[t, 0.0, c1.t]],
c1 = NIL => Contours.Interpolate[c0, circle, Alpha[t, c0.t, 1.0]],
ENDCASE => Contours.Interpolate[c0, c1, Alpha[t, c0.t, c1.t]]];
};
};
Skin: PUBLIC PROC [tube: Tube] ~ {
InnerSkin: TubeProc ~ {
circle: Contour ← Contours.Circle[tube.circleRes];
FOR n: INTEGER IN [0..TubeGeometry.NFrames[tube]) DO
f: Frame ← tube.frames[n];
f.contour ← TContour[tube.contours, circle, f.t];
f.normals ← SELECT TRUE FROM
f.contour = circle => f.contour.pairs,
ENDCASE => Contours.Normals[f.contour];
ENDLOOP;
};
TubeMisc.ApplyToTube[tube, InnerSkin];
};
PropagateCircleRes: PUBLIC PROC [tube: Tube, circleRes: INTEGER] ~ {
tubeProc: TubeProc ~ {
IF tube = NIL THEN RETURN;
tube.circleRes ← circleRes;
FOR n: NAT IN [0..TubeGeometry.NFrames[tube]) DO
f: Frame ← tube.frames[n];
IF f.contour # NIL AND f.contour.circle THEN f.contour ← circle;
ENDLOOP;
};
circle: Contour ← Contours.Circle[circleRes];
TubeMisc.ApplyToTube[tube, tubeProc];
};
ScreenCircleRes: PUBLIC PROC [tube: Tube, view: Matrix] RETURNS [INTEGER] ~ {
CircleRes: PROC [p: Triple, r: REAL] RETURNS [NAT] ~ {
q: Vector2.VEC ← Matrix3d.TransformD[p, view];
q1: Vector2.VEC ← Matrix3d.TransformD[[p.x+r, p.y, p.z], view];
q2: Vector2.VEC ← Matrix3d.TransformD[[p.x, p.y+r, p.z], view];
l: REALMAX[Vector2.Length[Vector2.Sub[q, q1]], Vector2.Length[Vector2.Sub[q, q2]]];
RETURN[3+Real.RoundI[0.4*l]];
};
res: INTEGERIF tube.frames = NIL
THEN 0
ELSE MAX[
CircleRes[tube.p0, tube.frames[0].scale],
CircleRes[tube.p1, tube.frames[tube.frames.length-1].scale]];
IF res MOD 2 = 1 THEN res ← res+1;
RETURN[res];
};
END.