Make:
PUBLIC
PROC [
tube: Tube,
epsilon: REAL ← 0.03,
scale: REAL ← 1.0,
taper: REAL ← 0.0,
skin: BOOL ← FALSE,
roundTip: BOOL ← FALSE,
view: Matrix ← NIL,
frameProc: FrameProc ← NIL]
~ {
SetCoeffs[tube];
SetLengths[tube];
MakeFrames[tube, epsilon, scale, taper, skin, roundTip, view, frameProc];
};
MakeFrames:
PUBLIC PROC [
tube: Tube,
epsilon: REAL ← 0.03,
scale: REAL ← 1.0,
taper: REAL ← 0.0,
skin: BOOL ← FALSE,
roundTip: BOOL ← FALSE,
view: Matrix ← NIL,
frameProc: FrameProc ← NIL]
~ {
tubeProc: TubeProc ~ {
scale0, scale1: REAL ← scale;
IF tube = NIL THEN RETURN;
IF taper # 0.0
THEN {
scale0 ← scale*(1.0-taper*tube.length0);
scale1 ← scale*(1.0-taper*tube.length1);
};
MakeSectionFrames[tube, epsilon, scale0, scale1, skin, roundTip, view, frameProc];
};
TubeMisc.ApplyToTube[tube, tubeProc];
};
MakeSectionFrames:
PUBLIC PROC [
tube: Tube,
epsilon: REAL ← 0.03,
scale0, scale1: REAL ← 1.0,
skin: BOOL ← FALSE,
roundTip: BOOL ← FALSE,
view: Matrix ← NIL,
frameProc: FrameProc ← NIL]
~ {
bez: Bezier ← Spline3d.BezierFromCoeffs[tube.coeffs];
maxLen: REAL ← IF view = NIL THEN 0.01*Spline3d.ConvexHullLength[bez] ELSE 0.0;
vv: Triple ←
IF Vector3d.Equal[bez.b1, bez.b0, 0.0001]
THEN Vector3d.Sub[bez.b2, bez.b1]
ELSE Vector3d.Sub[bez.b1, bez.b0];
circle: Contour ← Contours.Circle[tube.circleRes];
c0: Contour ← TubeContour.TContour[tube.contours, circle, 0.0];
c1: Contour ← TubeContour.TContour[tube.contours, circle, 1.0];
MakeFrame:
PROC [position, velocity: Triple, t:
REAL, c: Contour] ~ {
tube.frames ← TestFrameSequence[tube.frames];
IF frameProc #
NIL
THEN tube.frames[tube.frames.length] ← frameProc[position, velocity, t]
ELSE {
f: Frame ← tube.frames[tube.frames.length];
f.t ← t;
f.position ← position;
f.triad ← Basis[velocity, vv, tube.refVec];
Keep scale non-zero (to avoid subsequent surface normal computation problems):
f.scale ← MAX[.000001, (scale0+t*(scale1-scale0))*TubeMisc.Radius[tube, t, roundTip]];
f.twist ← tube.tw0+t*(tube.tw1-tube.tw0);
f.matrix ← RefMatrix[f.position, f.triad, f.scale, f.twist, f.matrix];
IF skin
THEN {
f.contour ← c;
f.normals ←
SELECT
TRUE
FROM
c.circle => c.pairs,
c.normals # NIL => c.normals,
ENDCASE => Contours.Normals[c];
};
};
tube.frames.length ← tube.frames.length+1;
vv ← velocity;
tube.refVec ← tube.frames[tube.frames.length-1].triad.n;
};
Walker:
PROC [bez: Bezier, t0, t1:
REAL, c0, c1: Contour] ~ {
IF DividedEnough[bez, t0, t1, c0, c1]
THEN MakeFrame[
bez.b0,
IF Vector3d.Equal[bez.b1, bez.b0, 0.0001]
-- degenerate end tangent check
THEN Vector3d.Sub[bez.b2, bez.b1]
ELSE Vector3d.Sub[bez.b1, bez.b0],
t0,
c0]
ELSE {
left, rite: Bezier;
t: REAL ← 0.5*(t0+t1);
c: Contour ← IF skin THEN TubeContour.TContour[tube.contours, circle, t] ELSE NIL;
[left, rite] ← Spline3d.SplitBezier[bez];
Walker[left, t0, t, c0, c];
Walker[rite, t, t1, c, c1];
};
};
DividedEnough:
PROC [bez: Bezier, t0, t1:
REAL, c0, c1: Contour]
RETURNS [
BOOL] ~ {
BezSmallEnough:
PROC [bez: 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]],
100.0*epsilon]];
};
TwistSmallEnough:
PROC [t0, t1:
REAL]
RETURNS[
BOOL] ~ {
RETURN[ABS[(t1-t0)*(tube.tw1-tube.tw0)] < 20.0];
};
ContoursCloseEnough:
PROC [c0, c1: Contour]
RETURNS [ret:
BOOL] ~ {
AllCircles:
PROC [contours: ContourSequence]
RETURNS [
BOOL] ~ {
IF contours #
NIL
THEN
FOR n:
NAT
IN [0..contours.length)
DO
IF NOT contours[n].circle THEN RETURN [FALSE];
ENDLOOP;
RETURN[TRUE];
};
IF AllCircles[tube.contours]
THEN {
IF roundTip
THEN {
r0: REAL ~ TubeMisc.Radius[tube, t0, TRUE];
r1: REAL ~ TubeMisc.Radius[tube, t1, TRUE];
IF r0 = 0.0 OR r1 = 0.0 THEN RETURN[FALSE];
RETURN[1.0-MIN[r0, r1]/MAX[r0, r1] < 100.0*epsilon];
}
ELSE RETURN[TRUE];
};
RETURN[Contours.Similar[c0, c1] > 1.0-10.0*epsilon];
};
IF t1-t0 < 0.005 THEN RETURN[TRUE];
RETURN[
BezSmallEnough[bez] AND
TwistSmallEnough[t0, t1] AND
ContoursCloseEnough[c0, c1]
];
};
IF tube # NIL AND tube.frames # NIL THEN tube.frames.length ← 0;
tube.refVec ←
IF tube.prev #
NIL
THEN tube.prev.refVec
ELSE Spline3d.RefVec[tube.coeffs, 0.0];
Walker[bez, 0.0, 1.0, c0, c1];
MakeFrame[
bez.b3,
IF Vector3d.Equal[bez.b3, bez.b2, 0.0001]
-- test for degenerate end tangent
THEN Vector3d.Sub[bez.b2, bez.b1]
ELSE Vector3d.Sub[bez.b3, bez.b2],
1.0,
c1];
IF view #
NIL THEN tube.circleRes ←
Real.RoundI[TubeContour.ScreenCircleRes[tube, view]/MAX[0.01, 100*epsilon]];
};