ImplicitWingCmdImpl.mesa
Copyright Ó 1991 by Xerox Corporation. All rights reserved.
Bloomenthal, a.k.a. Batman, July 14, 1991 11:59 pm PDT
DIRECTORY Commander, Draw2d, G3dBasic, G3dControl, G3dCurve, G3dDraw, G3dMatrix, G3dSpline, G3dVector, G3dView, Imager, ImplicitConvolve, ImplicitDefs, ImplicitDesign, IO, Rope;
ImplicitWingCmdImpl: CEDAR PROGRAM
IMPORTS G3dBasic, G3dControl, G3dCurve, G3dSpline, G3dVector, ImplicitConvolve, ImplicitDesign, IO
~ BEGIN
Imported Types
RealSequence:      TYPE ~ G3dBasic.RealSequence;
Triple:        TYPE ~ G3dBasic.Triple;
TripleSequence:      TYPE ~ G3dBasic.TripleSequence;
TripleSequenceRep:     TYPE ~ G3dBasic.TripleSequenceRep;
Curve:        TYPE ~ G3dCurve.Curve;
Spline:        TYPE ~ G3dSpline.Spline;
SplineSequence:      TYPE ~ G3dSpline.SplineSequence;
Primitive:        TYPE ~ ImplicitConvolve.Primitive;
PrimitiveList:      TYPE ~ ImplicitConvolve.PrimitiveList;
TripleList:       TYPE ~ ImplicitConvolve.TripleList;
ROPE:         TYPE ~ Rope.ROPE;
The ~WING~ of a BAT
Segment:        TYPE ~ RECORD [p1, p2: Triple, primitives: PrimitiveList];
SegmentList:       TYPE ~ LIST OF Segment;
WingData:       TYPE ~ REF WingDataRep;
WingDataRep:      TYPE ~ RECORD [
cmd:           Commander.Handle ← NIL,
tool:           ImplicitDesign.Tool ← NIL,
kHeight:          REAL ← 0.1,
kWidth:          REAL ← 0.25,
thumb:          SegmentList ← NIL,
finger1, finger2, finger3, finger4:   SegmentList ← NIL,
upperArm, lowerArm, elbow:    SegmentList ← NIL,
loft1, loft2, loft3, loft4, loft5, loft6, loft7: SplineSequence ← NIL,
primitives:         PrimitiveList ← NIL
];
out:     IO.STREAM;
fingerExtent:   REAL ← 0.2;
fingerTipIntensity: REAL ← 3.5;
fingerIntensity:  REAL ← 4.5;
muscleExtent:  REAL ← 0.5;
muscleIntensity:  REAL ← 5.0;
muscleTipIntensity: REAL ← 4.0;
webExtent:   REAL ← 0.1;
webIntensity:  REAL ← 1.75;
gRes:     ImplicitConvolve.IntegerPair ← [60, 60];
WingCmd: Commander.CommandProc ~ {
w: WingData ← NEW[WingDataRep ← [cmd: cmd]];
out ← cmd.out;
MakeWing[w];
IO.PutF[out, "%g primitives\n", IO.int[NPrimitives[w.primitives]]];
w.tool ← ImplicitConvolve.MakeTool[
cmd: cmd,
name: "WING IT!",
primitives: w.primitives,
clientData: w,
toolSettings: [trackSize: .09, threshold: 0.5]
];
G3dControl.UpdateControl[w.tool.renderTool.camera, w.tool.renderTool.camera.scale, 0.2];
};
NPrimitives: PROC [p: PrimitiveList] RETURNS [n: NAT ← 0] ~ {
FOR l: PrimitiveList ← p, l.rest WHILE l # NIL DO n ← n+1; ENDLOOP;
};
MakeWing: PROC [w: WingData, repaint: BOOLFALSE] ~ {
w.primitives ← NIL;
w.thumb ← MakeThumb[[-.2, 0, 1.2], [-.3, 0, 1.8]];
w.finger1 ← MakeFinger[[-.2, 0, 1.2], [-1.9, .1, 1.2], [-2.2, .25, 1], [-2.5, .4, .7]];
w.finger2 ← MakeFinger[[-.2, 0, 1.2], [-1.7, .05, .8], [-2.8, .15, -.1], [-3.1, .25, -1.0]];
w.finger3 ← MakeFinger[[-.2, 0, 1.2], [-1.8, 0, .3], [-2.6, .1, -.7], [-2.7, .15, -1.4]];
w.finger4 ← MakeFinger[[-.2, 0, 1.2], [-1.2, 0, -.3], [-1.5, 0, -1.4], [-1.5, 0, -2.]];
w.upperArm ← MakeUpperArm[[3.6, 0, 1.7], [2.3, 0, -.2]];
w.lowerArm ← MakeLowerArm[[2.3, 0, -.2], [-.2, 0, 1.2]];
w.elbow ← MakeElbow[[2.3, 0, -.2], [2.2, 0, -2.2]];
w.loft1 ← MakeLofts[
w, CombineSegments[w.lowerArm, w.thumb], ReverseSegments[w.upperArm], 8, 0.35];
w.loft2 ← MakeLofts[w, w.thumb, w.finger1, 4, .5];
w.loft3 ← MakeLofts[w, w.finger1, w.finger2, 6, .5];
w.loft4 ← MakeLofts[w, w.finger2, w.finger3, 6, .5];
w.loft5 ← MakeLofts[w, w.finger3, w.finger4, 6, .5];
w.loft6 ← MakeLofts[
w, w.finger4, CombineSegments[ReverseSegments[w.lowerArm], w.elbow], 8, 0.75];
w.loft7 ← MakeLofts[w, w.elbow, ReverseSegments[w.upperArm], 4, 0.25];
FOR l: LIST OF SegmentList ← LIST[
w.thumb, w.finger1, w.finger2, w.finger3, w.finger4, w.upperArm, w.lowerArm],
l.rest WHILE l # NIL DO
FOR s: SegmentList ← l.first, s.rest WHILE s # NIL DO
FOR p: PrimitiveList ← s.first.primitives, p.rest WHILE p # NIL DO
IF p.first # NIL THEN w.primitives ← CONS[p.first, w.primitives];
ENDLOOP;
ENDLOOP;
ENDLOOP;
MakeRectangles[w, w.loft1, 7];
MakeRectangles[w, w.loft2, 4];
MakeRectangles[w, w.loft3, 3];
MakeRectangles[w, w.loft4, 3];
MakeRectangles[w, w.loft5, 4];
MakeRectangles[w, w.loft6, 6];
MakeRectangles[w, w.loft7, 4];
IF repaint THEN ImplicitDesign.Repaint[w.tool];
};
MakeRectangles: PROC [w: WingData, splines: SplineSequence, res: NAT] ~ {
Add: PROC [list: TripleList] ~ {
pts: TripleSequence ← TripleSequenceFromList[list];
p: Primitive ← ImplicitConvolve.MakePrimitive[pts, webExtent,, webIntensity,,, gRes];
w.primitives ← CONS[p, w.primitives];
};
FillUp: PROC [pts: TripleSequence, s: Spline] ~ {
FOR i: NAT IN [0..res] DO pts[i] ← G3dSpline.Position[s, REAL[i]/REAL[res]]; ENDLOOP;
};
pts1: TripleSequence ← NEW[TripleSequenceRep[res+1]];
pts2: TripleSequence ← NEW[TripleSequenceRep[res+1]];
FillUp[pts1, splines[0]];
FOR n: NAT IN [1..splines.length) DO
FillUp[pts2, splines[n]];
FOR i: NAT IN [0..res) DO Add[LIST[pts1[i], pts1[i+1], pts2[i+1], pts2[i]]]; ENDLOOP;
{temp: TripleSequence ← pts1; pts1 ← pts2; pts2 ← temp};
ENDLOOP;
};
MakeSegment: PROC [p1, p2: Triple, extent, intensity0, intensity1: REAL]
RETURNS [s: Segment]
~ {
pts: TripleSequence ← TripleSequenceFromList[LIST[p1, p2]];
intensities: RealSequence ← RealSequenceFromList[LIST[intensity0, intensity1]];
primitive: Primitive ← ImplicitConvolve.MakePrimitive[pts, extent, 0, 1, intensities,, gRes];
s ← [p1, p2, LIST[primitive]];
};
MakeThumb: PROC [p1, p2: Triple] RETURNS [list: SegmentList] ~ {
list ← LIST[MakeSegment[p1, p2, 0.2, fingerIntensity, fingerTipIntensity]];
};
MakeFinger: PROC [p1, p2, p3, p4: Triple] RETURNS [list: SegmentList] ~ {
list ← LIST[
MakeSegment[p1, p2, fingerExtent, fingerIntensity, fingerTipIntensity],
MakeSegment[p2, p3, fingerExtent, fingerIntensity, fingerTipIntensity],
MakeSegment[p3, p4, fingerExtent, fingerIntensity, fingerTipIntensity]];
};
MakeUpperArm: PROC [p1, p2: Triple] RETURNS [list: SegmentList] ~ {
s: Segment ← [p1, p2, NIL];
bicep: PrimitiveList ← MakeMuscle[p1, [1.9, 0, .15], .2, .7, muscleTipIntensity, muscleTipIntensity, muscleIntensity, muscleExtent];
tricep: PrimitiveList ← MakeMuscle[p1, [2.3, 0, -.15], .1, .6, muscleTipIntensity, muscleTipIntensity, muscleIntensity, muscleExtent];
s.primitives ← CombinePrimitives[LIST[bicep, tricep]];
list ← LIST[s];
};
MakeLowerArm: PROC [p1, p2: Triple] RETURNS [list: SegmentList] ~ {
s1: Segment ← [p1, p2, MakeMuscle[p1, p2, .2, .7, muscleTipIntensity, muscleTipIntensity, muscleIntensity, muscleExtent]];
list ← LIST[s1];
};
MakeElbow: PROC [p1, p2: Triple] RETURNS [list: SegmentList] ~ {list ← LIST[[p1, p2, NIL]]};
Muscles
MakeMuscle: PROC [
p1, p2: Triple,         -- endpoints of the muscle
tendon1, tendon2: REAL,      -- start/stop of the muscle
intensity1, intensity2, maxIntensity: REAL, -- start/stop and max height of muscle
extent: REAL]         -- blending extent
RETURNS [list: PrimitiveList ← NIL]
~ {
IntensityAta: PROC [a: REAL] RETURNS [intensity: REAL] ~ {
intensity ← intensity1+a*(intensity2-intensity1);
IF a IN (tendon1..tendon2) THEN {
SlowInOut: PROC [x: REAL] RETURNS [REAL] ~ {RETURN[(3.0-2.0*x)*x*x]};
xx: REAL ← (a-tendon1)/(tendon2-tendon1);
b: REAL ← SlowInOut[1.0-ABS[1.0-2.0*xx]];
intensity ← intensity+b*(maxIntensity-intensity);
};
};
pp: Triple ← p1;
pIntensity: REAL ← intensity1;
FOR i: NAT IN [1..8] DO
a: REALREAL[i]/REAL[8];
p: Triple ← G3dVector.Interp[a, p1, p2];
intensity: REAL ← IntensityAta[a];
pts: TripleSequence ← TripleSequenceFromList[LIST[pp, p]];
intensities: RealSequence ← RealSequenceFromList[LIST[pIntensity, intensity]];
list CONS[ImplicitConvolve.MakePrimitive[pts, extent, 0, 1.0, intensities,, gRes], list];
pp ← p;
pIntensity ← intensity;
ENDLOOP;
};
Lofts
CurveFromSegmentList: PROC [s: SegmentList] RETURNS [c: Curve] ~ {
pts: TripleList ← LIST[s.first.p1];
FOR l: SegmentList ← s, l.rest WHILE l # NIL DO pts ← CONS[l.first.p2, pts]; ENDLOOP;
c ← G3dCurve.CurveFromSplines[G3dSpline.Interpolate[TripleSequenceFromList[pts]]];
};
PositionA: PROC [s: SegmentList, t: REAL] RETURNS [p: Triple] ~ {
length, totalLength, desiredLength: REAL ← 0.0;
FOR l: SegmentList ← s, l.rest WHILE l # NIL DO
totalLength ← totalLength+G3dVector.Distance[l.first.p1, l.first.p2];
ENDLOOP;
desiredLength ← t*totalLength;
FOR l: SegmentList ← s, l.rest WHILE l # NIL DO
segLength: REAL ← G3dVector.Distance[l.first.p1, l.first.p2];
dif: REAL ← (length ← length+segLength)-desiredLength;
IF dif < 0.0 THEN LOOP;
RETURN[G3dVector.Interp[(segLength-dif)/segLength, l.first.p1, l.first.p2]];
ENDLOOP;
};
globalCross: Triple ← [0.0, 1.0, 0.0];
MakeLofts: PROC [w: WingData, s0, s1: SegmentList, nLofts: NAT, sag: REAL]
RETURNS [splines: SplineSequence]
~ {
Loft: PROC [t, kWide, kHeight, kSag: REAL] RETURNS [s: Spline] ~ {
p0: Triple ← PositionA[s0, t];
p1: Triple ← PositionA[s1, t];
p0p1: Triple ← G3dVector.Sub[p1, p0];
lenp0p1: REAL ← G3dVector.Length[p0p1];
beam: Triple ← G3dVector.Mul[p0p1, kWide];
pMid: Triple ← G3dVector.Midpoint[p0, p1];
pp0: Triple ← G3dVector.Sub[pMid, beam];
pp1: Triple ← G3dVector.Add[pMid, beam];
cross: Triple ← G3dVector.SetVectorLength[G3dVector.Cross[v0, v1], kHeight*lenp0p1];
cross: Triple ← G3dVector.SetVectorLength[globalCross, kHeight*lenp0p1];
sag: Triple ← G3dVector.SetVectorLength[vSum, -t*t*kSag];
v: Triple ← G3dVector.Add[cross, sag];
pp0 ← G3dVector.Add[pp0, v];
pp1 ← G3dVector.Add[pp1, v];
s ← G3dSpline.SplineFromBezier[[p0, pp0, pp1, p1]];
};
c0: Curve ← CurveFromSegmentList[s0];
c1: Curve ← CurveFromSegmentList[s1];
v0: Triple ← G3dVector.Sub[PositionA[s0, 1.0], s0.first.p1];
v1: Triple ← G3dVector.Sub[PositionA[s1, 1.0], s1.first.p1];
vSum: Triple ← G3dVector.Add[G3dVector.Unit[v0], G3dVector.Unit[v1]];
splines ← NEW[G3dSpline.SplineSequenceRep[nLofts]];
splines.length ← nLofts;
FOR n: NAT IN [0..nLofts) DO
splines[n] ← Loft[REAL[n]/REAL[nLofts-1], w.kWidth, w.kHeight, sag];
ENDLOOP;
};
Display
Draw: Draw2d.DrawProc ~ {
Action: PROC ~ {
FOR l: LIST OF SplineSequence ←
LIST[w.loft1, w.loft2, w.loft3, w.loft4, w.loft5, w.loft6, w.loft7], l.rest WHILE l # NIL DO
G3dDraw.DrawCurves[context, l.first, view];
ENDLOOP;
};
w: WingData ← NARROW[data];
view: G3dMatrix.Matrix ← ImplicitDesign.GetViewTransform[viewer, w.tool];
WrapInCG6[context, Action];
};
Support
ReverseSegments: PROC [list: SegmentList] RETURNS [ret: SegmentList] ~ {
Reverse the list of segments and reverse the points within each segment
FOR s: SegmentList ← list, s.rest WHILE s # NIL DO
ret ← CONS[[s.first.p2, s.first.p1, s.first.primitives], ret];
ENDLOOP;
};
CombineSegments: PROC [s1, s2: SegmentList] RETURNS [ret: SegmentList] ~ {
tmp: SegmentList ← NIL;
FOR l: SegmentList ← s1, l.rest WHILE l # NIL DO tmp ← CONS[l.first, tmp]; ENDLOOP;
FOR l: SegmentList ← s2, l.rest WHILE l # NIL DO tmp ← CONS[l.first, tmp]; ENDLOOP;
FOR l: SegmentList ← tmp, l.rest WHILE l # NIL DO ret ← CONS[l.first, ret]; ENDLOOP;
};
CombinePrimitives: PROC [list: LIST OF PrimitiveList] RETURNS [ret: PrimitiveList] ~ {
FOR l: LIST OF PrimitiveList ← list, l.rest WHILE l # NIL DO
FOR p: PrimitiveList ← l.first, p.rest WHILE p # NIL DO
IF p.first # NIL THEN ret ← CONS[p.first, ret]
ENDLOOP;
ENDLOOP;
};
TripleSequenceFromList: PROC [points: LIST OF Triple] RETURNS [TripleSequence] ~ {
RETURN[G3dBasic.TripleSequenceFromList[points]];
};
RealSequenceFromList: PROC [reals: LIST OF REAL] RETURNS [s: RealSequence] ~ {
len: NAT ← 0;
FOR l: LIST OF REAL ← reals, l.rest WHILE l # NIL DO len ← len+1; ENDLOOP;
s ← NEW[G3dBasic.RealSequenceRep[len]];
s.length ← len;
FOR n: NAT IN [0..s.length ← len) DO {s[n] ← reals.first; reals ← reals.rest}; ENDLOOP;
};
Start Code
ImplicitDesign.Register["Wing", WingCmd, "\ta wing?", "ImplicitConvolve"];
END.