TubeStructureImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, May 23, 1986 12:57:02 pm PDT
DIRECTORY Cubic2, Matrix3d, Real, RealFns, Spline3d, Vector2, Vector3d, TubeDefs, TubeStructure;
TubeStructureImpl: CEDAR PROGRAM
IMPORTS Cubic2, Matrix3d, Real, RealFns, Spline3d, Vector2, Vector3d
EXPORTS TubeStructure
~ BEGIN
OPEN TubeDefs;
nCircles: NAT ~ 40;
circles: ARRAY [1..nCircles] OF PairSequence ← ALL[NIL];
PropagateCircleRes: PUBLIC PROC [tube: Tube, circleRes: NAT] ~ {
IF tube = NIL THEN RETURN;
tube.circleRes ← circleRes;
FOR n: NAT IN [0..tube.nBranches) DO
PropagateCircleRes[tube.branches[n], circleRes];
ENDLOOP;
PropagateCircleRes[tube.next, circleRes];
};
PropagateFrames: PUBLIC PROC [
tube: Tube, scale, epsilon: REAL ← 1.0, taper: REAL ← 0.0, view: Matrix ← NIL]
~ {
Inner: PROC [t: Tube, length, scale0: REAL] ~ {
scale1: REAL ← scale0;
IF t = NIL THEN RETURN;
IF taper # 0.0 THEN {
length ← length+Spline3d.Length[t.c];
scale1 ← scale*(1.0-taper*length);
};
MakeFrames[t, scale0, scale1, epsilon, view];
FOR n: NAT IN [0..t.nBranches) DO
Inner[t.branches[n], length, scale1];
ENDLOOP;
Inner[t.next, length, scale1];
};
Inner[tube, 0.0, scale];
};
MakeFrames: PUBLIC PROC [
tube: Tube, scale0, scale1, epsilon: REAL ← 1.0, view: Matrix ← NIL]
~ {
bez: Spline3d.Bezier ← Spline3d.BezierFromCoeffs[tube.c];
maxLen: REALIF view = NIL THEN 0.01*Spline3d.ConvexHullLength[bez] ELSE 0.0;
vv: Triple ← Vector3d.Sub[bez.b1, bez.b0];
tw0: REAL ← tube.twist0;
tw1: REAL ← tube.twist1;
sc0: REAL ← tube.r0*scale0;
sc1: REAL ← tube.r1*scale1;
ScreenCircleRes: PROC [tube: Tube, view: Matrix] RETURNS [res: NAT] ~ {
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/MAX[0.01, epsilon]]];
};
res ← MAX[CircleRes[tube.p0, scale0*tube.r0], CircleRes[tube.p1, scale1*tube.r1]];
IF res MOD 2 = 1 THEN res ← res+1;
};
LengthenFrameSeq: PROC [f: FrameSeq] RETURNS [FrameSeq] ~ {
temp: FrameSeq ← NEW[FrameSeqRep[MAX[5, Real.RoundI[1.3*f.maxLength]]]];
FOR i: NAT IN[0..f.maxLength) DO temp[i] ← f[i]; ENDLOOP;
RETURN[temp];
};
SmallEnough: PROC [bez: Spline3d.Bezier] RETURNS[BOOL] ~ {
RETURN[IF view = NIL
THEN Spline3d.ConvexHullLength[bez] < maxLen OR Spline3d.FlatBezier[bez, epsilon]
ELSE Cubic2.Flat[
[Matrix3d.TransformD[bez.b0, view], Matrix3d.TransformD[bez.b1, view],
Matrix3d.TransformD[bez.b2, view], Matrix3d.TransformD[bez.b3, view]],
epsilon]];
};
Walker: PROC [bez: Spline3d.Bezier, t0, t1: REAL] ~ {
IF SmallEnough[bez]
THEN MakeFrame[bez.b0, Vector3d.Sub[bez.b1, bez.b0], t0]
ELSE {
left, rite: Spline3d.Bezier;
t: REAL ← 0.5*(t0+t1);
[left, rite] ← Spline3d.SplitBezier[bez];
Walker[left, t0, t];
Walker[rite, t, t1];
};
};
MakeFrame: PROC [p, v: Triple, t: REAL] ~ {
n, b: Triple;
i: NAT ← tube.axialRes;
tt: REAL ← 1.0-t;
tube.axialRes ← i+1;
IF tube.axialRes >= tube.frames.maxLength
THEN tube.frames ← LengthenFrameSeq[tube.frames];
tube.frames[i].t ← t;
[n, b] ← Basis[v, vv, tube.refVec];
Keep scale non-zero (avoid subsequent surface normal computation problems):
tube.frames[i].m ←
RefMatrix[p, n, b, v, MAX[0.000001, tt*sc0+t*sc1], tt*tw0+t*tw1, tube.frames[i].m];
vv ← v;
tube.refVec ← n;
};
IF tube.frames = NIL THEN tube.frames ← NEW[FrameSeqRep];
tube.axialRes ← 0;
tube.refVec ← IF tube.prev # NIL THEN tube.prev.refVec ELSE Spline3d.RefVec[tube.c, 0.0];
Walker[bez, 0.0, 1.0];
MakeFrame[
bez.b3,
IF Vector3d.Equal[bez.b3, bez.b2, 0.0001] -- check for degenerate end tangent
THEN Vector3d.Sub[bez.b2, bez.b1]
ELSE Vector3d.Sub[bez.b3, bez.b2],
1.0];
IF view # NIL THEN tube.circleRes ScreenCircleRes[tube, view];
};
TubeResInfo: PUBLIC PROC [tube: Tube]
RETURNS [nPoints, nPolys, minCres, maxCres: INTEGER] ~ {
Inner: PROC [t: Tube] ~ {
IF t = NIL THEN RETURN;
IF t.circleRes > maxCres THEN maxCres ← t.circleRes;
IF t.circleRes < minCres THEN minCres ← t.circleRes;
nPoints ← nPoints+t.circleRes*(IF t.next # NIL THEN t.axialRes ELSE t.axialRes-1);
nPolys ← nPolys+2*t.circleRes*(t.axialRes-1);
Inner[t.next];
FOR n: NAT IN [0..t.nBranches) DO Inner[t.branches[n]] ENDLOOP;
};
minCres ← 10000;
maxCres ← nPolys ← nPoints ← 0;
Inner[tube];
};
GetCircle: PUBLIC PROC [res: NAT] RETURNS [PairSequence] ~ {
IF res <= 0 THEN RETURN[NIL];
IF res > nCircles THEN RETURN[NewCircle[res]];
IF circles[res] = NIL THEN circles[res] ← NewCircle[res];
RETURN[circles[res]];
};
NewCircle: PROC [res: NAT] RETURNS [PairSequence] ~ {
rad: REAL ← 0.0;
drad: REAL ← 2.0*3.1415926535/REAL[res];
circle: PairSequence ← NEW[PairSequenceRec[res]];
FOR i: NAT IN[0..res) DO
circle[i] ← [RealFns.Cos[rad], RealFns.Sin[rad]];
rad ← rad+drad;
ENDLOOP;
RETURN[circle];
};
Basis: PUBLIC PROC [v, vv, rv: Triple] RETURNS [n, b: Triple] ~ {
dot: REAL;
vv ← Vector3d.Normalize[vv];
v ← Vector3d.Normalize[v];
rv ← Vector3d.Normalize[rv];
dot ← Vector3d.Dot[v, vv];
IF ABS[dot] > 0.9999 THEN {        -- tangents v, vv colinear
n ← IF dot > 0.0 THEN rv ELSE [-rv.x, -rv.y, -rv.z];
n ← Vector3d.V90[v, n];       -- ensure orthogonality
}
ELSE {
a: REAL ← RealFns.ArcTanDeg[RealFns.SqRt[1.0-dot*dot], dot]; -- == Acos[]
axis: Triple ← Vector3d.Cross[v, vv];
n ← Vector3d.Normalize[Vector3d.RotateAbout[rv, axis, a]]; -- incremental kludge
};
b ← Vector3d.Normalize[Vector3d.Cross[v, n]];
};
RefMatrix: PUBLIC PROC [p, x, y, z: Triple, s, t: REAL, out: Matrix←NIL] RETURNS [Matrix] ~ {
IF ABS[t] > 0.001 THEN {
out ← Matrix3d.MakePureRotate[z, t, , out];
x ← Matrix3d.TransformVec[x, out];
y ← Matrix3d.TransformVec[y, out];
};
RETURN[Matrix3d.LocalScale[Matrix3d.MakeFromTriad[x, y, z, p], s, out]];
};
NSegments: PUBLIC PROC [tube: Tube] RETURNS [n: NAT ← 0] ~ {
Return number of splines in limb:
FOR t: Tube ← tube, t.next WHILE t # NIL DO n ← n+1; ENDLOOP;
};
END.
..
MakeMatrices: PUBLIC PROC [s: SplineData, scale: REAL] ~ {
sc0: REAL ← s.rad0*scale;
sc1: REAL ← s.rad1*scale;
tw0: REAL ← s.twist0;
tw1: REAL ← s.twist1;
vv: Triple ← s.v0;
mats: MatrixSeq ← s.mats;
s.refVec ← IF s.prev # NIL THEN s.prev.refVec ELSE Spline3d.RefVec[s.c, 0.0];
mats[0] ←Misc3d.RefMatrix[s.p0, s.refVec, Vector3d.Cross[vv, s.refVec], vv, sc0, tw0, mats[0]];
FOR i: NAT IN[1..s.axialRes) DO
n, b: Triple;
t: REAL ← i/REAL[s.axialRes-1.0];
p: Triple ← Spline3d.Position[s.c, t];
v: Triple ← Spline3d.Tangent[s.c, t];
[n, b] ← Misc3d.Basis[v, vv, s.refVec];
mats[i] ← Misc3d.RefMatrix[p, n, b, v, (1.0-t)*sc0+t*sc1, (1.0-t)*tw0+t*tw1, mats[i]];
vv ← v;
s.refVec ← n;
ENDLOOP;
};