G3dTubeMiscImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, August 26, 1992 5:31 pm PDT
DIRECTORY Draw2d, FileNames, FS, G2dContour, G3dDraw, G3dBasic, G3dIO, G3dMatrix, G3dQuaternion, G3dShape, G3dSpline, G3dVector, G3dTube, Imager, ImagerColor, ImagerFont, ImagerInterpress, IO, Real, Rope;
G3dTubeMiscImpl:
CEDAR
PROGRAM
IMPORTS Draw2d, FileNames, FS, G2dContour, G3dDraw, G3dIO, G3dMatrix, G3dQuaternion, G3dSpline, G3dVector, G3dTube, Imager, ImagerColor, ImagerFont, ImagerInterpress, IO, Real, Rope
EXPORTS G3dTube
Types
DrawType: TYPE ~ Draw2d.DrawType;
MarkType: TYPE ~ Draw2d.MarkType;
Hull: TYPE ~ G3dBasic.Hull;
Pair: TYPE ~ G3dBasic.Pair;
PairSequence: TYPE ~ G3dBasic.PairSequence;
Triple: TYPE ~ G3dBasic.Triple;
Matrix: TYPE ~ G3dMatrix.Matrix;
Viewport: TYPE ~ G3dMatrix.Viewport;
Quaternion: TYPE ~ G3dQuaternion.Quaternion;
Shape: TYPE ~ G3dShape.Shape;
Bezier: TYPE ~ G3dSpline.Bezier;
Details: TYPE ~ G3dTube.Details;
DetailsRep: TYPE ~ G3dTube.DetailsRep;
XSection: TYPE ~ G3dTube.XSection;
XSectionSequence: TYPE ~ G3dTube.XSectionSequence;
PointProc: TYPE ~ G3dTube.PointProc;
PolyProc: TYPE ~ G3dTube.PolyProc;
Tube: TYPE ~ G3dTube.Tube;
TubeProc: TYPE ~ G3dTube.TubeProc;
TubeRep: TYPE ~ G3dTube.TubeRep;
TubeSequence: TYPE ~ G3dTube.TubeSequence;
TubeSequenceRep: TYPE ~ G3dTube.TubeSequenceRep;
Context: TYPE ~ Imager.Context;
STREAM: TYPE ~ IO.STREAM;
PI: REAL ~ G3dBasic.PI;
origin: Triple ~ G3dBasic.origin;
IO
ReadTube:
PUBLIC
PROC [stream:
STREAM]
RETURNS [tube: Tube]
~ {
IF stream =
NIL
THEN RETURN[NIL]
ELSE {
InnerReadTube:
PROC [prev: Tube]
RETURNS [tube: Tube] ~ {
TubeLineOK:
PROC
RETURNS [ok:
BOOL ¬
TRUE] ~ {
DO
line ¬ G3dIO.GetLine[stream, line ! IO.EndOfStream => GOTO eof];
IF Rope.Equal[G3dIO.GetWord[line], "tube:", FALSE] THEN RETURN;
REPEAT
eof => RETURN[FALSE];
ENDLOOP;
};
IF TubeLineOK[]
THEN {
next: BOOL;
tube ¬ NEW[TubeRep];
tube.prev ¬ prev;
tube.p0 ¬ G3dIO.GetTriple[line];
tube.p1 ¬ G3dIO.GetTriple[line];
tube.v0 ¬ G3dIO.GetTriple[line];
tube.v1 ¬ G3dIO.GetTriple[line];
tube.r0 ¬ G3dIO.GetReal[line];
tube.r1 ¬ G3dIO.GetReal[line];
tube.tw0 ¬ G3dIO.GetReal[line];
tube.tw1 ¬ G3dIO.GetReal[line];
tube.scale ¬ G3dIO.GetReal[line];
tube.taper ¬ G3dIO.GetReal[line];
tube.epsilon ¬ G3dIO.GetReal[line];
tube.circleRes ¬ G3dIO.GetInteger[line];
next ¬ Rope.Equal[G3dIO.GetWord[line], "next", FALSE];
tube.branches ¬ NEW[TubeSequenceRep[G3dIO.GetInteger[line]]];
tube.branches.length ¬ tube.branches.maxLength;
G3dTube.SetSpline[tube];
IF next THEN tube.next ¬ InnerReadTube[tube];
IF tube.branches #
NIL
THEN
FOR n:
NAT
IN [0..tube.branches.length)
DO
tube.branches[n] ¬ InnerReadTube[tube];
ENDLOOP;
};
};
line: Line ¬ G3dIO.ObtainLine[];
tube ¬ InnerReadTube[NIL];
G3dIO.ReleaseLine[line];
};
};
WriteTube:
PUBLIC
PROC [stream:
STREAM, tube: Tube, m: Matrix ¬
NIL] ~ {
Write: TubeProc ~ {
IO.PutRope[stream, "Tube: "];
G3dIO.WriteTriple[stream, IF m = NIL THEN tube.p0 ELSE G3dMatrix.Transform[tube.p0, m]];
G3dIO.WriteTriple[stream, IF m = NIL THEN tube.p1 ELSE G3dMatrix.Transform[tube.p1, m]];
G3dIO.WriteTriple[stream,
IF m = NIL THEN tube.v0 ELSE G3dMatrix.TransformVec[tube.v0, m]];
G3dIO.WriteTriple[stream,
IF m = NIL THEN tube.v1 ELSE G3dMatrix.TransformVec[tube.v1, m]];
IO.PutF[stream, "%5.4f %5.4f\t", IO.real[tube.r0], IO.real[tube.r1]];
IO.PutF[stream, "%5.4f %5.4f\t", IO.real[tube.tw0], IO.real[tube.tw1]];
IO.PutF[stream, "%5.4f %5.4f\t", IO.real[tube.scale], IO.real[tube.taper]];
IO.PutF[stream, "%5.4f %g ", IO.real[tube.epsilon], IO.int[tube.circleRes]];
IO.PutRope[stream, IF tube.next # NIL THEN "next " ELSE "no "];
IO.PutF1[stream, "%g", IO.int[NBranches[tube]]];
IO.PutRope[stream, "\n"];
};
ApplyToTube[tube, Write];
};
WritePointsPolys:
PUBLIC
PROC [tube: Tube, fileName:
ROPE, m: Matrix ¬
NIL]
RETURNS [nPoints, nPolys: INT] ~ {
Point: PointProc ~ {
IO.PutF1[out, "%g\t", IO.int[id]];
G3dIO.WriteTriple[out, position];
G3dIO.WriteTriple[out, normal];
IO.PutF[out, "%6.5f %6.5f\n", IO.real[texture.x], IO.real[texture.y]];
};
Poly: PolyProc ~ {
IO.PutFL[out,"%g\t%4g %4g %4g\n", LIST[IO.int[id], IO.int[p0], IO.int[p1], IO.int[p2]]];
};
out: STREAM ¬ FS.StreamOpen[fileName, $create];
nPoints ¬ NPoints[tube];
nPolys ¬ NPolys[tube];
IO.PutF1[out, "-- %g\n\n", IO.rope[tube.name]];
IO.PutF[out, "DataSize~ vertices: %g, surfaces: %g\n\n", IO.int[nPoints], IO.int[nPolys]];
IO.PutRope[out,
"Vertices~ index: integer xyzCoords: triple normalVec: triple textureCoords: pair\n\n"];
[] ¬ Points[tube, Point, m];
IO.PutRope[out, "\nSurfaces~ index: integer vertices: nats\n\n"];
[] ¬ Polys[tube, Poly];
IO.Close[out];
};
WriteIP:
PUBLIC
PROC [ref: ImagerInterpress.Ref, tube: Tube, details: Details, m: Matrix] ~ {
font: ImagerFont.Font ¬ ImagerFont.Scale[ImagerFont.Find["xerox/pressfonts/helvetica-mrr"], 12.0];
ContextProc:
PROC [context: Context] ~ {
metersPerPoint: REAL ~ .0254/72.0;
Imager.ScaleT[context, metersPerPoint];
Imager.SetStrokeWidth[context, 1.0];
Imager.SetStrokeEnd[context, round];
Imager.SetFont[context, font];
Imager.TranslateT[context, [0.0, 0.5*11.0*72.0]];
G3dTube.DrawTube[context, tube, details, m];
};
ImagerInterpress.DoPage[ref, ContextProc];
};
TubeFromFile:
PUBLIC
PROC [fileName:
ROPE]
RETURNS [tube: Tube] ~ {
name: ROPE ¬ FileNames.ResolveRelativePath[fileName];
IF name #
NIL
THEN {
stream: STREAM ¬ FS.StreamOpen[name ! FS.Error => GOTO noOpen];
IF (tube ¬ ReadTube[stream]) = NIL THEN RETURN;
IO.Close[stream];
name ¬ FileNames.GetShortName[name];
tube.name ¬ Rope.Substr[name, 0, Rope.Index[name, 0, "."]];
EXITS noOpen => NULL;
};
RETURN[tube];
};
TubeToFile:
PUBLIC
PROC [tube: Tube, fileName:
ROPE, matrix: Matrix ¬
NIL] ~ {
IF fileName #
NIL
THEN {
s: STREAM ¬ FS.StreamOpen[FileNames.ResolveRelativePath[fileName], $create];
IO.PutF1[s, "\n-- %g, format for each line:\n", IO.rope[fileName]];
IO.PutRope[s,
"--Tube: p0 p1 v0 v1 r0 r1 tw0 tw1 scale taper eps cres <next|no> nBranches\n\n"];
WriteTube[s, tube, matrix];
IO.Close[s];
};
};
Points and Polygons
Points:
PUBLIC
PROC [tube: Tube, pointProc: PointProc, view: Matrix ¬
NIL]
RETURNS [nPoints: INT]
~ {
pointId: INT ¬ 0;
uRangeStart: REAL ¬ 2.0*PI*tube.r0;
OneSpline:
PROC [tube: Tube, iStart:
NAT, uRange0, v:
REAL] ~ {
IF tube #
NIL
AND tube.xSections #
NIL
THEN {
uRange1: REAL ¬ uRange0*(0.5+0.5*(tube.r1/tube.r0)); -- a compromise
duRange: REAL ¬ (uRange1-uRange0)/(tube.xSections.length-1.0);
circle: PairSequence ¬ G2dContour.CirclePairs[tube.circleRes];
tapered: BOOL ¬ tube.r1 # tube.r0;
vFactor:
REAL ¬
IF tapered
THEN (tube.r0-tube.r1)/G3dVector.Distance[tube.p0, tube.p1]
ELSE 1.0;
pNow, pPrev: Triple ¬ tube.p0;
odd: BOOL ¬ tube.circleRes MOD 2 = 1;
FOR i:
NAT
IN[iStart..NXSections[tube])
DO
uRange: REAL ¬ uRange0+i*duRange;
u: REAL ¬ 0.0;
du: REAL ¬ 0.5*uRange/tube.circleRes;
m: Matrix ¬ tube.xSections[i].matrix;
mm: Matrix ¬ IF view # NIL THEN G3dMatrix.Mul[m, view] ELSE m;
pPrev ¬ pNow;
pNow ¬ [m[3][0], m[3][1], m[3][2]];
IF i # 0 THEN v ¬ v+G3dVector.Distance[pNow, pPrev];
FOR j:
NAT
IN[0..tube.circleRes)
DO
p: Triple ¬ G3dMatrix.TransformPair[circle[j], mm];
n: Triple ¬ G3dMatrix.TransformVec[[circle[j].x, circle[j].y, 0.0], mm];
IF tapered
THEN {
vv: Triple ¬ G3dSpline.Velocity[tube.spline, tube.xSections[i].t];
len: REAL ¬ G3dVector.Length[n];
n ¬ G3dVector.Add[n, G3dVector.Mul[vv, len*vFactor/G3dVector.Length[vv]]];
};
n ¬ G3dVector.Unit[n];
[] ¬ pointProc[pointId, p, n, [u, v]];
pointId ¬ pointId+1;
u ¬ IF j < tube.circleRes/2 OR odd THEN u+du ELSE u-du; -- u radial symmetry
ENDLOOP;
ENDLOOP;
IF tube.next #
NIL
AND tube.next.circleRes = tube.circleRes
AND tube.next.r0 = tube.r1
THEN OneSpline[tube.next, 1, uRange1, v] -- skip first xSection
ELSE OneSpline[tube.next, 0, uRange1, v]; -- do first xSection
FOR n:
NAT
IN [0..NBranches[tube])
DO
OneSpline[tube.branches[n], 0, uRangeStart, v]; -- use 1st xSection of 1st branch tube
ENDLOOP;
};
};
OneSpline[tube, 0, uRangeStart, 0.0]; -- start with first xSection of first tube
RETURN[pointId];
};
Polys:
PUBLIC
PROC [tube: Tube, polyProc: PolyProc]
RETURNS [nPolys:
INT] ~ {
polyId, pointId: INTEGER ¬ 0;
OneSpline:
PROC [tube: Tube] ~ {
IF tube #
NIL
THEN {
cRes: INTEGER ¬ tube.circleRes;
connect ith xSection to (i+1)th xSection:
FOR i:
NAT
IN [0..NXSections[tube]-1)
DO
n: NAT ¬ pointId;
FOR ii:
NAT
IN[0..cRes)
DO
nn: NAT ¬ IF ii = cRes-1 THEN pointId ELSE n+1;
r: NAT ¬ n+cRes;
rr: NAT ¬ nn+cRes;
[] ¬ polyProc[polyId, n, nn, r]; -- reversed r and n, per Crow, 10/7/86
polyId ¬ polyId+1;
[] ¬ polyProc[polyId, r, nn, rr]; -- reversed r and rr, per Crow, 10/7/86
n ¬ n+1;
polyId ¬ polyId+1;
ENDLOOP;
pointId ¬ pointId+cRes;
ENDLOOP;
IF tube.next =
NIL
OR tube.next.circleRes # tube.circleRes
OR tube.next.r0 # tube.r1
THEN pointId ¬ pointId+cRes; -- end of branch or discontinuity from t to t.next
OneSpline[tube.next];
FOR n:
NAT
IN [0..NBranches[tube])
DO
OneSpline[tube.branches[n]];
ENDLOOP;
};
};
OneSpline[tube];
RETURN[polyId];
};
ShapeFromTube:
PUBLIC
PROC [tube: Tube]
RETURNS [shape: Shape] ~ {
Point: PointProc ~ {
v: G3dShape.Vertex ¬ shape.vertices[id] ¬ NEW[G3dShape.VertexRep];
v ¬ [point: position, normal: normal, texture: texture];
};
Poly: PolyProc ~ {
p: G3dBasic.NatSequence ¬ NEW[G3dBasic.NatSequenceRep[3]];
p.length ¬ 3;
p[0] ¬ p0;
p[1] ¬ p1;
p[2] ¬ p2;
};
shape ¬ NEW[G3dShape.ShapeRep ¬ [name: tube.name]];
shape.vertices ¬ NEW[G3dShape.VertexSequenceRep[NPoints[tube]]];
shape.vertices.length ¬ shape.vertices.maxLength;
[] ¬ Points[tube, Point];
shape.surfaces ¬ NEW[G3dBasic.SurfaceSequenceRep[NPolys[tube]]];
shape.surfaces.length ¬ shape.surfaces.maxLength;
[] ¬ Polys[tube, Poly];
};
Miscellany
Find:
PUBLIC
PROC [searchee, search: Tube]
RETURNS [found:
BOOL] ~ {
tubeProc: TubeProc ~ {IF tube = searchee THEN found ¬ TRUE; RETURN[NOT found]};
found ¬ FALSE;
ApplyToTube[search, tubeProc];
};
Where:
PUBLIC
PROC [searchee, search: Tube]
RETURNS [rope:
ROPE] ~ {
whereError: ERROR = CODE;
Inner:
PROC [tube: Tube] ~ {
IF tube.prev = NIL THEN ERROR whereError;
IF tube.prev.next = tube
THEN rope ¬ Rope.Concat[".next", rope]
ELSE
FOR n:
NAT
IN [0..NBranches[tube.prev])
DO
IF tube.prev.branches[n] = tube
THEN {
rope ¬ IO.PutFR[".branches[%g]%g", IO.int[n], IO.rope[rope]];
EXIT;
};
REPEAT
FINISHED => ERROR whereError;
ENDLOOP;
IF tube.prev # search THEN Inner[tube.prev];
};
IF NOT Find[searchee, search] THEN RETURN[".not found"];
IF searchee = search THEN RETURN[".same"];
Inner[searchee ! whereError => {rope ¬ ".error findng tube"; CONTINUE}];
};
lastTubePicked: Tube ¬
NIL;
SetLastTubePicked:
PUBLIC
PROC [tube: Tube] ~ {
lastTubePicked ¬ tube;
};
LastTubePicked:
PUBLIC
PROC [copy:
BOOL ¬
TRUE]
RETURNS [Tube] ~ {
RETURN[IF copy THEN CopyEntireTube[lastTubePicked] ELSE lastTubePicked];
};
First:
PUBLIC
PROC [tube: Tube]
RETURNS [t: Tube] ~ {
IF (t ¬ tube) = NIL THEN RETURN;
WHILE t.prev # NIL DO t ¬ t.prev; ENDLOOP;
};
Last:
PUBLIC
PROC [tube: Tube]
RETURNS [t: Tube] ~ {
IF (t ¬ tube) = NIL THEN RETURN;
WHILE t.next # NIL DO t ¬ t.next; ENDLOOP;
};
Divide:
PUBLIC PROC [tube: Tube, t:
REAL] ~ {
new: Tube ¬ CopyEntireTube[tube];
new ¬ G3dTube.ExtractPartTube[new, 0.0, t];
tube ¬ G3dTube.ExtractPartTube[tube, t, 1.0, tube];
IF tube.prev #
NIL
THEN {
IF tube.prev.next = tube
THEN tube.prev.next ¬ new
ELSE
FOR n:
NAT
IN [0..tube.prev.branches.length)
DO
IF tube.prev.branches[n] # tube THEN LOOP;
tube.prev.branches[n] ¬ new;
EXIT;
ENDLOOP;
};
new.prev ¬ tube.prev;
new.next ¬ tube;
tube.prev ¬ new;
};
Delete:
PUBLIC
PROC [tube: Tube] ~ {
IF tube #
NIL
AND tube.prev #
NIL
THEN {
IF tube.prev.next = tube
THEN tube.prev.next ¬ NIL
ELSE
FOR n:
NAT
IN [0..NBranches[tube.prev])
DO
IF tube.prev.branches[n] # tube THEN LOOP;
tube.prev.branches[n] ¬ tube.prev.branches[NBranches[tube.prev]-1];
tube.prev.branches.length ¬ tube.prev.branches.length-1;
EXIT;
ENDLOOP;
};
};
SelectAll:
PUBLIC
PROC [tube: Tube] ~ {
tubeProc: TubeProc ~ {tube.selected ¬ TRUE};
ApplyToTube[tube, tubeProc];
};
UnSelectAll:
PUBLIC
PROC [tube: Tube] ~ {
tubeProc: TubeProc ~ {tube.selected ¬ FALSE};
ApplyToTube[tube, tubeProc];
};
ExtractTubeName:
PUBLIC PROC [fileName:
ROPE]
RETURNS [name:
ROPE] ~ {
rope: ROPE ¬ FileNames.ResolveRelativePath[fileName];
rope ¬ FileNames.GetShortName[rope];
name ¬ Rope.Substr[rope, 0, Rope.Index[rope, 0, "."]];
};
SetTubeColors:
PUBLIC
PROC [tube: Tube] ~ {
SetColor: G3dTube.TubeProc ~ {
hue: REAL ¬ 0.15*Depth[tube];
hue ¬ hue-Real.Floor[hue];
tube.color ¬ ImagerColor.ColorFromHSV[hue, 1.0, 1.0];
};
ApplyToTube[tube, SetColor];
};
Interpolation
Average:
PUBLIC
PROC [tube0, tube1: Tube]
RETURNS [tube: Tube] ~ {
tube ¬ NEW[TubeRep];
tube.v0 ¬ G3dVector.Midpoint[tube0.v0, tube1.v0];
tube.v1 ¬ G3dVector.Midpoint[tube0.v1, tube1.v1];
tube.p0 ¬ G3dVector.Midpoint[tube0.p0, tube1.p0];
tube.p1 ¬ G3dVector.Midpoint[tube0.p1, tube1.p1];
tube.circleRes ¬ (tube0.circleRes+tube1.circleRes)/2;
tube.epsilon ¬ 0.5*(tube0.epsilon+tube1.epsilon);
tube.tw0 ¬ 0.5*(tube0.tw0+tube1.tw0);
tube.tw1 ¬ 0.5*(tube0.tw1+tube1.tw1);
tube.tens0 ¬ 0.5*(tube0.tens0+tube1.tens0);
tube.tens1 ¬ 0.5*(tube0.tens1+tube1.tens1);
tube.r0 ¬ 0.5*(tube0.r0+tube1.r0);
tube.r1 ¬ 0.5*(tube0.r1+tube1.r1);
tube.scale ¬ 0.5*(tube0.scale+tube1.scale);
tube.taper ¬ 0.5*(tube0.taper+tube1.taper);
tube.refVec ¬ G3dVector.Unit[G3dVector.Midpoint[tube0.refVec, tube1.refVec]];
G3dTube.SetSpline[tube];
};
InterpTubes:
PUBLIC PROC [tube1, tube2, interp: Tube, alpha:
REAL] ~ {
GetQuaternion:
PROC [t: Tube]
RETURNS [Quaternion] ~ {
z: Triple ¬ G3dVector.Unit[G3dVector.Sub[t.p1, t.p0]];
x: Triple ¬ G3dVector.Unit[G3dVector.V90[z, t.refVec]];
y: Triple ¬ G3dVector.Unit[G3dVector.Cross[z, x]];
m ¬ G3dMatrix.MakeFromTriad[x, y, z,, FALSE, m];
RETURN[G3dQuaternion.FromMatrix[m]];
};
Set:
PROC [t, t1, t2: Tube] ~ {
q1: Quaternion ¬ GetQuaternion[t1];
q2: Quaternion ¬ GetQuaternion[t2];
q: Quaternion ¬ G3dQuaternion.Slerp[q1, q2, alpha];
len1: REAL ¬ G3dVector.Distance[t1.p0, t1.p1];
len2: REAL ¬ G3dVector.Distance[t2.p0, t2.p1];
len: REAL ¬ len1+alpha*(len2-len1);
temp: Matrix ¬ m ¬ G3dQuaternion.ToMatrix[q, m];
z: Triple ¬ G3dMatrix.TransformVec[[0.0, 0.0, 1.0], m];
IF t.prev # NIL THEN t.p0 ¬ t.prev.p1;
t.p1 ¬ G3dVector.Add[t.p0, G3dVector.SetVectorLength[z, len]];
};
DoTube:
PROC [t, t1, t2: Tube] ~ {
Set[t, t1, t2];
IF t.next # NIL THEN DoTube[t.next, t1.next, t2.next];
IF t.branches #
NIL
THEN
FOR n:
NAT
IN [0..t.branches.length)
DO
DoTube[t.branches[n], t1.branches[n], t2.branches[n]];
ENDLOOP;
};
m: Matrix;
DoTube[interp, tube1, tube2];
};
Branching
NewBranch:
PUBLIC
PROC [tube: Tube]
RETURNS [Tube] ~ {
branch: Tube ~ NEW[TubeRep ¬ [p0: tube.p1, v0: tube.v1]];
IF tube.next #
NIL
THEN {
vDif: Triple ~ G3dVector.Sub[tube.next.p1, tube.next.p0];
v: Triple ~ G3dVector.SameLength[vDif, tube.v1];
branch.p1 ¬ G3dVector.Add[branch.p0, G3dVector.Combine[v, 1.5, vDif, -0.5]];
}
ELSE branch.p1 ¬ G3dVector.Add[branch.p0, G3dVector.Sub[branch.p0, tube.p0]];
branch.v1 ¬ G3dVector.SameLength[branch.v0, G3dVector.Sub[branch.p1, branch.p0]];
G3dTube.SetSpline[branch];
RETURN[branch];
};
AddBranch:
PUBLIC
PROC [tube, branch: Tube] ~ {
IF tube.branches = NIL THEN tube.branches ¬ NEW[TubeSequenceRep[1]];
IF tube.branches.length = tube.branches.maxLength
THEN {
old: TubeSequence ~ tube.branches;
tube.branches ¬ NEW[TubeSequenceRep[old.length+1]];
tube.branches.length ¬ old.length;
FOR i: NAT IN [0..old.length) DO tube.branches[i] ¬ old[i]; ENDLOOP;
};
tube.branches[tube.branches.length] ¬ branch;
tube.branches.length ¬ tube.branches.length+1;
branch.prev ¬ tube;
};
GetBranch:
PUBLIC
PROC [tube: Tube, n:
NAT]
RETURNS [branch: Tube ¬
NIL] ~ {
IF tube.next =
NIL
THEN {
IF tube.branches #
NIL
AND n < tube.branches.length
THEN RETURN[tube.branches[n]];
}
ELSE {
IF n = 0 THEN RETURN[tube.next];
IF tube.branches #
NIL
AND n-1 < tube.branches.length
THEN RETURN[tube.branches[n-1]];
};
};
Information
NTubes:
PUBLIC PROC [tube: Tube]
RETURNS [
INTEGER] ~ {
nTubes: INTEGER ¬ 0;
tubeProc: TubeProc ~ {nTubes ¬ nTubes+1};
ApplyToTube[tube, tubeProc];
RETURN[nTubes];
};
NBranches:
PUBLIC
PROC [tube: Tube, nextAlso:
BOOL ¬
FALSE]
RETURNS [n:
INTEGER ¬0] ~ {
IF tube = NIL THEN RETURN;
IF tube.branches # NIL THEN n ¬ tube.branches.length;
IF nextAlso AND tube.next # NIL THEN n ¬ n+1;
};
NSiblings:
PUBLIC
PROC [tube: Tube, tubeAlso:
BOOL ¬
TRUE]
RETURNS [n:
INTEGER] ~ {
tubeProc: TubeProc ~ {n ¬ n+1};
n ¬ 0;
ApplyToSiblings[tube, tubeProc, tubeAlso];
};
NXSections:
PUBLIC PROC [tube: Tube]
RETURNS [
INTEGER] ~ {
RETURN[IF tube.xSections # NIL THEN tube.xSections.length ELSE 0];
};
NPoints:
PUBLIC
PROC [tube: Tube]
RETURNS [
INT] ~ {
OneSpline:
PROC [tube: Tube, iStart:
NAT] ~ {
IF tube #
NIL
AND tube.xSections #
NIL
THEN {
nPoints ¬ nPoints+(tube.xSections.length-iStart)*tube.circleRes;
IF tube.next #
NIL
AND tube.next.circleRes = tube.circleRes
AND tube.next.r0 = tube.r1
THEN OneSpline[tube.next, 1] -- skip first xSection
ELSE OneSpline[tube.next, 0]; -- do first xSection
FOR n:
NAT
IN [0..NBranches[tube])
DO
OneSpline[tube.branches[n], 0]; -- use 1st xSection of 1st branch tube
ENDLOOP;
};
};
nPoints: INT ¬ 0;
OneSpline[tube, 0]; -- start with first xSection of first tube
RETURN[nPoints];
};
NPolys:
PUBLIC PROC [tube: Tube]
RETURNS [
INT] ~ {
n: INT ¬ 0;
FOR t: Tube ¬ tube, t.next
WHILE t #
NIL
DO
IF t.xSections # NIL THEN n ¬ n+2*(t.xSections.length-1)*t.circleRes;
ENDLOOP;
RETURN[MAX[0, n]];
};
NSplinesInBranch:
PUBLIC PROC [tube: Tube]
RETURNS [
INT] ~ {
n: INT ¬ 0;
FOR t: Tube ¬ tube, t.next WHILE t # NIL DO n ¬ n+1; ENDLOOP;
RETURN[n];
};
Depth:
PUBLIC
PROC [tube: Tube]
RETURNS [n:
NAT ¬ 0] ~ {
IF tube = NIL THEN RETURN;
WHILE tube.prev # NIL DO tube ¬ tube.prev; n ¬ n+1; ENDLOOP;
};
Info:
PUBLIC
PROC [tube: Tube]
RETURNS [nPoints, nPolys, minCres, maxCres:
INT] ~ {
InnerResInfo: TubeProc ~ {
IF tube.circleRes > maxCres THEN maxCres ¬ tube.circleRes;
IF tube.circleRes < minCres THEN minCres ¬ tube.circleRes;
};
minCres ¬ 10000;
maxCres ¬ nPolys ¬ nPoints ¬ 0;
ApplyToTube[tube, InnerResInfo];
nPoints ¬ NPoints[tube];
nPolys ¬ NPolys[tube];
};
Copying
CopyTubeSection:
PUBLIC
PROC [tube: Tube, copy: Tube ¬
NIL]
RETURNS [Tube] ~ {
IF tube = NIL THEN RETURN[NIL];
IF copy = NIL THEN copy ¬ NEW[TubeRep];
copy ¬ tube;
copy.xSections ¬ G3dTube.CopyXSections[tube.xSections];
copy.spline ¬ G3dSpline.CopySpline[tube.spline];
copy.xSpline ¬ G3dSpline.CopySpline[tube.xSpline];
IF tube.branches #
NIL
THEN {
copy.branches ¬ NEW[TubeSequenceRep[tube.branches.length]];
copy.branches.length ¬ tube.branches.length;
FOR n:
NAT
IN [0..copy.branches.length)
DO
copy.branches[n] ¬ tube.branches[n];
ENDLOOP;
};
RETURN[copy];
};
CopyEntireTube:
PUBLIC
PROC [tube: Tube]
RETURNS [copy: Tube] ~ {
InnerCopy:
PROC [tube, prev: Tube]
RETURNS [copy: Tube] ~ {
IF tube = NIL THEN RETURN[NIL];
copy ¬ NEW[TubeRep ¬ tube];
copy.xSections ¬ G3dTube.CopyXSections[tube.xSections];
copy.spline ¬ G3dSpline.CopySpline[tube.spline];
copy.xSpline ¬ G3dSpline.CopySpline[tube.xSpline];
copy.prev ¬ prev;
IF tube.branches #
NIL
THEN {
copy.branches ¬ NEW[TubeSequenceRep[tube.branches.length]];
copy.branches.length ¬ tube.branches.length;
FOR n:
NAT
IN [0..copy.branches.length)
DO
copy.branches[n] ¬ InnerCopy[tube.branches[n], copy];
ENDLOOP;
};
copy.next ¬ InnerCopy[tube.next, copy];
};
copy ¬ InnerCopy[tube, NIL];
};
Call Backs
ApplyToTube:
PUBLIC
PROC [tube: Tube, tubeProc: TubeProc] ~ {
Inner:
PROC [tube: Tube] ~ {
IF tube = NIL OR NOT tubeProc[tube] THEN RETURN;
Inner[tube.next];
FOR n: NAT IN [0..NBranches[tube]) DO Inner[tube.branches[n]]; ENDLOOP;
};
Inner[tube];
};
ApplyToBranches:
PUBLIC
PROC [tube: Tube, tubeProc: TubeProc, nextAlso:
BOOL ¬
TRUE] ~{
IF tube = NIL THEN RETURN;
IF nextAlso AND tube.next # NIL AND NOT tubeProc[tube.next] THEN RETURN;
FOR n:
NAT
IN [0..NBranches[tube])
DO
IF tube.branches[n] # NIL AND NOT tubeProc[tube.branches[n]] THEN RETURN;
ENDLOOP;
};
ApplyToSiblings:
PUBLIC
PROC [tube: Tube, tubeProc: TubeProc, tubeAlso:
BOOL ¬
TRUE] ~ {
IF tube #
NIL
THEN {
prev: Tube ~ tube.prev;
IF prev =
NIL
THEN {
IF tubeAlso THEN [] ¬ tubeProc[tube];
RETURN;
};
IF (tubeAlso
OR prev.next # tube)
AND prev.next #
NIL
AND
NOT tubeProc[prev.next]
THEN RETURN;
FOR n:
NAT
IN [0..NBranches[prev])
DO
IF (tubeAlso
OR prev.branches[n] # tube)
AND
prev.branches[n] # NIL AND NOT tubeProc[prev.branches[n]] THEN RETURN;
ENDLOOP;
};
};
Drawing
SetColor:
PROC [context: Context, tube: Tube] ~
INLINE {
Imager.SetColor[context, IF tube.color = NIL THEN Imager.black ELSE tube.color];
};
DrawTube:
PUBLIC
PROC [
context: Context,
tube: Tube,
details: Details,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ solid]
~ {
IF details = NIL THEN RETURN;
IF details[skeleton]
THEN DrawSkeleton[context, tube, view, viewport, drawType];
IF details[spline]
THEN DrawSplines[context, tube, view, viewport, drawType];
IF details[lines]
THEN DrawLines[context, tube, view, viewport, drawType];
IF details[contours]
THEN DrawContours[context, tube, view, viewport, drawType];
IF details[xSections]
THEN DrawXSections[context, tube, view, viewport, details[label], drawType];
IF details[curvature]
THEN DrawCurvature[context, tube, view, viewport, details[label], drawType];
IF details[velocity]
THEN DrawVelocity[context, tube, view, viewport, details[label], drawType];
IF details[acceleration]
THEN DrawAcceleration[context, tube, view, viewport, details[label], drawType];
IF details[normals]
THEN DrawNormals[context, tube, view, viewport, details[label], drawType];
IF details[points]
THEN DrawPoints[context, tube, view, viewport, dot];
};
DrawSkeleton:
PUBLIC PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
SetColor[context, tube];
G3dDraw.Segment[context, tube.p0, tube.p1, view, viewport, IF tube.selected THEN drawType ELSE dotted];
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawSplines:
PUBLIC PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
SetColor[context, tube];
tube.selected ← TRUE; -- for filming day
IF tube.selected
THEN G3dDraw.Curve[context, tube.spline, view, viewport]
ELSE G3dDraw.DotCurve[context, tube.spline, view, viewport];
};
Imager.SetStrokeWidth[context, 2.0]; -- for film day
G3dTube.ApplyToTube[tube, ApplyDraw];
Imager.SetStrokeWidth[context, 1.0]; -- for film day
};
DrawSplineEnds:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
mark: MarkType ¬ dot]
~ {
ApplyDraw: TubeProc ~ {
SetColor[context, tube];
G3dDraw.Mark[context, tube.p0, view, viewport,, mark];
G3dDraw.Mark[context, tube.p1, view, viewport,, mark];
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
AxialDrawRes:
PROC [tube: Tube]
RETURNS [
INTEGER] ~ {
nXSections: NAT ¬ G3dTube.NXSections[tube];
RETURN[IF tube.next = NIL THEN nXSections ELSE nXSections-1];
};
DrawPoints:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
markType: MarkType ¬ dot]
~ {
ApplyDraw: TubeProc ~ {
SetColor[context, tube];
FOR i:
NAT
IN [0..AxialDrawRes[tube])
DO
f: XSection ¬ tube.xSections[i];
IF f.contour #
NIL
AND f.contour.pairs #
NIL
THEN {
pairs: PairSequence ¬ f.contour.pairs;
FOR j:
NAT
IN [0..pairs.length)
DO
G3dDraw.Mark[
context, G3dMatrix.TransformPair[pairs[j], f.matrix], view, viewport,, markType];
ENDLOOP;
};
ENDLOOP;
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawContours:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
VP:
PROC [p: Pair]
RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
SetColor[context, tube];
FOR i:
NAT
IN [0..AxialDrawRes[tube])
DO
f: XSection ¬ tube.xSections[i];
IF f.contour #
NIL
AND f.contour.pairs #
NIL
THEN {
pairs: PairSequence ¬ f.contour.pairs;
p0, psave: Pair ¬
VP[G3dMatrix.TransformD[G3dMatrix.TransformPair[pairs[0], f.matrix], view]];
FOR j:
NAT
IN [1..pairs.length)
DO
p1: Pair ¬
VP[G3dMatrix.TransformD[G3dMatrix.TransformPair[pairs[j], f.matrix], view]];
Draw2d.Line[context, p0, p1, drawType];
p0 ¬ p1;
ENDLOOP;
Draw2d.Line[context, p0, psave];
};
ENDLOOP;
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawLines:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
VP:
PROC [p: Pair]
RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
Xform:
PROC [p: Pair, m: Matrix]
RETURNS [Pair] ~ {
RETURN[VP[G3dMatrix.TransformD[G3dMatrix.TransformPair[p, m], view]]];
};
allCircles: BOOL ¬ TRUE;
xSections: XSectionSequence ¬ tube.xSections;
nXSections: NAT ¬ G3dTube.NXSections[tube];
SetColor[context, tube];
FOR i:
NAT
IN [0..nXSections)
DO
IF xSections[i].contour #
NIL
AND
NOT xSections[i].contour.circle
THEN {allCircles ¬ FALSE; EXIT};
ENDLOOP;
IF allCircles
THEN {
circle: PairSequence ¬ G2dContour.CirclePairs[tube.circleRes];
FOR i:
NAT
IN [0..tube.circleRes)
DO
p0: Pair ¬ Xform[circle[i], xSections[0].matrix];
FOR j:
NAT
IN [1..nXSections)
DO
p1: Pair ¬ Xform[circle[i], xSections[j].matrix];
Draw2d.Line[context, p0, p1, drawType];
p0 ¬ p1;
ENDLOOP;
ENDLOOP;
}
ELSE {
pc: REAL ¬ 0.0;
dpc: REAL ¬ 1.0/MAX[1, tube.circleRes];
FOR i:
NAT
IN [0..tube.circleRes)
DO
p0: Pair ¬
Xform[G2dContour.PercentPair[xSections[0].contour, pc], xSections[0].matrix];
FOR j:
NAT
IN [1..nXSections)
DO
p1: Pair ¬ Xform[G2dContour.PercentPair[xSections[j].contour, pc], xSections[j].matrix];
Draw2d.Line[context, p0, p1, drawType];
p0 ¬ p1;
ENDLOOP;
pc ¬ pc+dpc;
ENDLOOP;
};
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawXSections:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
label: BOOL,
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
VP:
PROC [p: Pair]
RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
DrawMatrix:
PROC [m: Matrix] ~ {
o: Pair ¬ VP[G3dMatrix.TransformD[[m[3][0], m[3][1], m[3][2]], view]];
FOR i:
NAT
IN [0..2]
DO
p: Pair ¬ VP[G3dMatrix.TransformD[
[m[3][0]+scale*m[i][0], m[3][1]+scale*m[i][1], m[3][2]+scale*m[i][2]], view]];
Draw2d.Line[context, o, p, drawType];
IF label THEN Draw2d.Label[context, p, names[i]];
ENDLOOP;
};
SetColor[context, tube];
FOR i:
NAT
IN [0..AxialDrawRes[tube])
DO
IF tube.xSections[i].matrix # NIL THEN DrawMatrix[tube.xSections[i].matrix];
ENDLOOP;
};
scale: REAL ~ 0.8;
names: ARRAY[0..2] OF Rope.ROPE ¬ ["x", "y", "z"];
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawNormals:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
label: BOOL,
drawType: DrawType ¬ solid]
~ {
See TubeIO.Points
tapered: BOOL;
vFactor: REAL;
ApplyDraw: TubeProc ~ {
DrawN:
PROC [f: XSection] ~ {
FOR j:
NAT
IN [0..f.contour.pairs.length)
DO
p: Triple ¬ G3dMatrix.TransformPair[f.contour.pairs[j], f.matrix];
n: Triple ¬ G3dMatrix.TransformVec[[f.normals[j].x, f.normals[j].y, 0], f.matrix];
IF tapered
THEN {
v: Triple ¬ G3dSpline.Velocity[tube.spline, f.t];
len: REAL ¬ G3dVector.Length[n];
n ¬ G3dVector.Add[n, G3dVector.Mul[v, len*vFactor/G3dVector.Length[v]]];
};
n ¬ G3dVector.Unit[n];
G3dDraw.Vector[context, p, n, view, viewport, IF label THEN "n" ELSE NIL, 0.1];
ENDLOOP;
};
tapered ¬ tube.r1 # tube.r0;
IF tapered THEN vFactor ¬ (tube.r0-tube.r1)/G3dVector.Distance[tube.p0, tube.p1];
SetColor[context, tube];
FOR i:
NAT
IN [0..AxialDrawRes[tube])
DO
IF tube.xSections[i].matrix # NIL THEN DrawN[tube.xSections[i]];
ENDLOOP;
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawCurvature:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
label: BOOL,
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
DrawK:
PROC [f: XSection] ~ {
p: Triple ¬ [f.matrix[3][0], f.matrix[3][1], f.matrix[3][2]];
k: Triple ¬ G3dSpline.Curvature[tube.spline, f.t];
G3dDraw.Vector[context, p, k, view, viewport, IF label THEN "k" ELSE NIL];
};
SetColor[context, tube];
FOR i:
NAT
IN [0..AxialDrawRes[tube])
DO
IF tube.xSections[i].matrix # NIL THEN DrawK[tube.xSections[i]];
ENDLOOP;
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawVelocity:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
label: BOOL,
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
DrawV:
PROC [f: XSection] ~ {
p: Triple ¬ [f.matrix[3][0], f.matrix[3][1], f.matrix[3][2]];
v: Triple ¬ G3dSpline.Velocity[tube.spline, f.t];
G3dDraw.Vector[context, p, v, view, viewport, IF label THEN "v" ELSE NIL];
};
SetColor[context, tube];
FOR i:
NAT
IN [0..AxialDrawRes[tube])
DO
IF tube.xSections[i].matrix # NIL THEN DrawV[tube.xSections[i]];
ENDLOOP;
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
DrawAcceleration:
PUBLIC
PROC [
context: Context,
tube: Tube,
view: Matrix,
viewport: Viewport ¬ [],
label: BOOL,
drawType: DrawType ¬ solid]
~ {
ApplyDraw: TubeProc ~ {
DrawA:
PROC [f: XSection] ~ {
p: Triple ¬ [f.matrix[3][0], f.matrix[3][1], f.matrix[3][2]];
a: Triple ¬ G3dSpline.Acceleration[tube.spline, f.t];
G3dDraw.Vector[context, p, a, view, viewport, IF label THEN "a" ELSE NIL];
};
SetColor[context, tube];
FOR i:
NAT
IN [0..AxialDrawRes[tube])
DO
IF tube.xSections[i].matrix # NIL THEN DrawA[tube.xSections[i]];
ENDLOOP;
};
G3dTube.ApplyToTube[tube, ApplyDraw];
};
NVectors:
PUBLIC
PROC [tube: Tube, details: Details]
RETURNS [
INTEGER] ~ {
sum: INTEGER ¬ 0;
IF details[enabled]
THEN
FOR t: Tube ¬ tube, t.next
WHILE t #
NIL
DO
nXSections: INTEGER ¬ G3dTube.NXSections[t];
sum ¬ sum
+(IF details[lines] THEN t.circleRes*nXSections ELSE 0)
+(IF details[xSections] THEN 3*nXSections ELSE 0);
FOR n:
NAT
IN [0..nXSections)
DO
f: XSection ¬ t.xSections[n];
sum ¬ sum+(IF f.contour # NIL THEN f.contour.pairs.length ELSE t.circleRes);
ENDLOOP;
ENDLOOP;
RETURN[sum];
};