ImplicitSliceCmdsImpl.mesa
Copyright Ó 1985, 1990 by Xerox Corporation. All rights reserved.
Bloomenthal, August 11, 1992 4:06 pm PDT
DIRECTORY Commander, Controls, Draw2d, FileNames, G3dDraw, G3dMatrix, G3dTool, G3dTube, ImplicitDefs, ImplicitSlice, ImplicitTube, IO, Menus, Rope;
ImplicitSliceCmdsImpl:
CEDAR
PROGRAM
IMPORTS Controls, FileNames, ImplicitSlice, ImplicitTube, IO, G3dDraw, G3dTool, G3dTube, Rope
Types
Button: TYPE ~ Controls.Button;
DrawProc: TYPE ~ Draw2d.DrawProc;
ClickProc: TYPE ~ Menus.ClickProc;
DiagramProc: TYPE ~ ImplicitDefs.DiagramProc;
ValueProc: TYPE ~ ImplicitDefs.ValueProc;
Tool: TYPE ~ ImplicitSlice.Tool;
Function: TYPE ~ ImplicitSlice.Function;
Tube: TYPE ~ G3dTube.Tube;
ROPE: TYPE ~ Rope.ROPE;
Tube Testing
TubeData: TYPE ~ REF TubeDataRep;
TubeDataRep:
TYPE ~
RECORD [
tool: Tool ¬ NIL,
tube: Tube ¬ NIL,
drawLines: BOOL ¬ FALSE
];
TubeSlice: Commander.CommandProc ~ {
t: TubeData ¬ NEW[TubeDataRep];
f: LIST OF Function ¬ LIST[["segment", ValueSegment, DrawSegment]];
b:
LIST
OF Button ¬
LIST[
Controls.ClickButton["GetTube", GetTube, t],
Controls.ClickButton["Lines: Off", ToggleDrawLines, t]];
t.tool ¬ ImplicitSlice.MakeTool["ImplicitSlice Tube", f, DrawTube, t,, b];
};
DrawTube: DrawProc ~ {
t: TubeData ¬ NARROW[data];
v: G3dMTool.View ¬ G3dTool.GetView[viewer, t.tool.renderTool];
G3dTube.DrawSplines[context, t.tube, xform];
IF t.drawLines
THEN {
G3dTube.DrawContours[context, t.tube, v.camera.matrix, v.viewport];
G3dTube.DrawLines[context, t.tube, v.camera.matrix, v.viewport];
};
};
DrawSegment: DiagramProc ~ {
t: TubeData ¬ NARROW[clientData];
xform: Matrix ¬ G3dTool.GetView[viewer, t.tool.renderTool].camera.matrix;
vp: G3dMatrix.Viewport ¬ G3dView.GetViewport[viewer];
ImplicitTube.DiagramTube[context, xform, vp, point, t.tube, $Segment, inverseSqrd, 0.0, 0.75];
G3dDraw.Mark[context, t.tool.point, xform, vp, IO.PutFR[" %6.3f", IO.real[t.tool.value]]];
};
ValueSegment: ValueProc ~ {
t: TubeData ¬ NARROW[clientData];
value ¬ ImplicitTube.SampleTube[point, t.tube, $Segment, inverseSqrd, 0.0, 0.75].value;
};
ToggleDrawLines: ClickProc ~ {
t: TubeData ¬ NARROW[clientData];
t.drawLines ¬ NOT t.drawLines;
Controls.ButtonToggle[t.tool.renderTool.outerData, t.drawLines, "Lines: On", "Lines: Off"];
ImplicitSlice.Repaint[t.tool];
};
GetTube: ClickProc ~ {
t: TubeData ¬ NARROW[clientData];
t.tube ¬ G3dTube.LastTubePicked[TRUE];
IF t.tube =
NIL
THEN {
r: ROPE ¬FileNames.ResolveRelativePath[Controls.TypescriptReadFileName[t.tool.typescript]];
IF (t.tube ¬ G3dTube.TubeFromFile[r]) =
NIL
THEN {
Controls.TypescriptWrite[t.tool.typescript, Rope.Cat["Bad file: ", r, "\n"]];
RETURN;
};
};
G3dTube.SelectAll[t.tube];
IF t.tube.xSections = NIL THEN G3dTube.MakeXSections[t.tube, TRUE, TRUE];
ImplicitSlice.Repaint[t.tool];
};
Fancy Tube Display
DrawTube: PROC [context: Context, tube: Tube] ~ {
tubeProc: G3dTube.TubeProc ~ {
i: G3dSpline.SplinePlaneIntersect ¬
G3dSpline.IntersectSplineAndPlane[tube.coeffs, t.slice.plane];
FOR n: NAT IN [0..i.nRoots) DO
Draw3d.Mark[context, G3dSpline.Position[s.tube.coeffs, i.roots[n]], t.view, , x];
ENDLOOP;
DrawSpline[context, tube.coeffs];
};
Imager.SetColor[context, Imager.black];
Imager.SetStrokeWidth[context, 2.0];
G3dTube.ApplyToTube[tube, tubeProc];
Imager.SetStrokeWidth[context, 4.0];
};
DrawSpline: PROC [context: Context, coeffs: Coeffs] ~ {
PatternProc: PROC [i: NAT] RETURNS [REAL] ~ {RETURN[2]};
behind: BOOL ¬ Plane3d.DistanceToPt[Spline3d.Position[coeffs, 0.0], s.slice.plane] < 0;
was: BOOL ¬ NOT behind;
solid, dash: Imager.Trajectory ¬ NIL;
FOR t: REAL ¬ 0.0, t+0.005 WHILE t <= 1.004 DO
q: Triple ¬ G3dSpline.Position[coeffs, t];
v: Pair ¬ G3dMatrix.TransformD[q, s.view];
behind ¬ G3dPlane.DistanceToPoint[q, s.slice.plane] < 0;
SELECT TRUE FROM
was AND NOT behind => solid ¬ ImagerPath.MoveTo[v];
NOT was AND behind => dash ¬ ImagerPath.MoveTo[v];
behind => dash ¬ ImagerPath.LineTo[dash, v];
ENDCASE => solid ¬ ImagerPath.LineTo[solid, v];
was ¬ behind;
ENDLOOP;
IF dash # NIL THEN
Imager.MaskDashedStrokeTrajectory[context, dash, 2, PatternProc, 0, 20];
IF solid # NIL THEN Imager.MaskStrokeTrajectory[context, solid];
};
Discarded Value Procs
Line: InfoProc ~ {
FOR n: NAT IN [0..info.length) DO
i: Info ¬ info[n];
FOR nn: NAT IN (n..info.length) DO
ii: Info ¬ info[nn];
IF i.point # ii.point THEN {
near: NearSegment3d ¬ G3dVector.NearestTo3dSegment[i.point, ii.point, point];
distance: REAL ¬ SELECT near.w0 FROM
0.0 => ii.distance,
1.0 => i.distance,
ENDCASE => G3dVector.Distance[near.point, point];
aveRadius: REAL ¬ 0.5*(i.radius+ii.radius);
value ¬ value+Strength[Ratio[distance, aveRadius, spread]];
}
ELSE value ¬ value+i.strength;
ENDLOOP;
ENDLOOP;
IF info.length > 2 THEN value ¬ 2.0*value/(info.length*(info.length-1));
};
MaxInfo: PROC [info: REF Infos] RETURNS [max: NAT ¬ 0] ~ {
strength: REAL ¬ 0.0;
FOR n: NAT IN [0..info.length) DO
IF info[n].strength > strength THEN {strength ¬ info[n].strength; max ¬ n};
ENDLOOP;
};
TotalValue: PROC [info: REF Infos, proc: PROC [i, ii: Info] RETURNS [REAL]] RETURNS [REAL]
~ {
max: NAT ¬ MaxInfo[info];
i: Info ¬ info[max];
value: REAL ¬ i.strength;
FOR n: NAT IN [0..info.length) DO
IF n # max THEN value ¬ value+proc[i, info[n]];
ENDLOOP;
RETURN[value];
};
CosineAndSynergy: InfoProc ~ {
Proc: PROC [i, ii: Info] RETURNS [REAL] ~ {
tot: REAL ¬ i.strength+ii.strength;
acos: REAL ¬ G3dVector.Dot[i.vector, ii.vector];
RETURN[(1.0-acos)* (IF tot > 1.0 THEN tot*tot*ii.strength ELSE ii.strength)];
};
RETURN[TotalValue[info, Proc]];
};
CosineAndClose: InfoProc ~ {
Proc: PROC [i, ii: Info] RETURNS [REAL] ~ {
totalStrength: REAL ¬ i.strength+ii.strength;
IF totalStrength # 0.0 THEN {
acos: REAL ¬ G3dVector.Dot[i.vector, ii.vector];
closeness: REAL ¬ 1.0-ABS[i.strength-ii.strength]/totalStrength;
RETURN[closeness*(1.0-acos)*ii.strength];
};
RETURN[0.0];
};
RETURN[TotalValue[info, Proc]];
};
Summation: InfoProc ~ {
FOR n: NAT IN [0..info.length) DO value ¬ value+info[n].strength; ENDLOOP;
};
Strength: PROC [distance, radius, spread: REAL] RETURNS [REAL] ~ {
Attempt 2:
dOverR: REAL ¬ distance/radius;
IF dOverR > 4.0
THEN RETURN[0.0]
ELSE {
dif: REAL ¬ dOverR-4.0;
RETURN[4.0-Real.SqRt[16.0-dif*dif]];
};
Strength: PROC [distance, radius, spread: REAL] RETURNS [REAL] ~ {
Attempt 1:
dOverR: REAL ¬ distance/radius;
RETURN[SELECT dOverR FROM
IN[0.00..0.25) => 4.0-4.00*dOverR,
IN[0.25..0.50) => 4.0-4.00*dOverR,
IN[0.50..0.75) => 3.0-2.00*dOverR,
IN[0.75..1.00) => 3.0-2.00*dOverR,
IN[1.00..1.50) => 1.5-0.50*dOverR,
IN[1.50..2.00) => 1.5-0.50*dOverR,
IN[2.00..3.00) => 1.0-0.25*dOverR,
IN[3.00..4.00) => 1.0-0.25*dOverR,
ENDCASE => 0.0];
};
ValueOfTube: PROC [tube: Tube, point: Triple, spread: REAL] RETURNS [value: REAL ¬ 0.]~ {
max, nBranches: NAT ¬ G3dTube.NBranches[tube]+1;
FOR n: NAT IN [0..nBranches) DO
branch: Tube ¬ IF n = 0 THEN tube.next ELSE tube.branches[n-1];
nearest: NearSpline3d ¬ G3dSpline.PreciseNearestPoint[point, branch.xCoeffs];
vector: Triple ¬ G3dVector.Normalize[G3dVector.Sub[nearest.point, point]];
radius: REAL ¬ G3dTube.Radius[branch, nearest.t];
strength: REAL ¬ Strength[nearest.distance, radius, spread];
IF strength > value THEN {value ¬ strength; max ¬ n};
info[n] ¬ [nearest.point, vector, nearest.distance, radius, strength];
ENDLOOP;
FOR n: NAT IN [0..nBranches) DO
IF n # max THEN {
acos: REAL ¬ G3dVector.Dot[info[max].vec, info[n].vec];
value ¬ value+0.5*(1.0-acos)*info[n].strength;
};
ENDLOOP;
value ¬ (4.0/3.0)*value;
};
SqDistToSegment:
PROC [a, b, q: Pair]
RETURNS [
REAL] ~ {
n: Pair ~ [b.x-a.x, b.y-a.y];
nSq: REAL ~ n.x*n.x+n.y*n.y;
qSq: REAL ~ SqDist[q, a];
IF nSq < 0.1*qSq
THEN RETURN[qSq]
ELSE {
ua: Pair ~ [q.x-a.x, q.y-a.y];
alpha: REAL ~ (ua.x*n.x+ua.y*n.y)/nSq;
RETURN[SqDist[q,
SELECT alpha
FROM
<= 0.0 => a,
>= 1.0 => b,
ENDCASE => [a.x+alpha*n.x, a.y+alpha*n.y]]];
};
};
SqDist:
PROC [p0, p1: Pair]
RETURNS [
REAL] ~ {
d: Pair ¬ [p1.x-p0.x, p1.y-p0.y];
RETURN[d.x*d.x+d.y*d.y];
};
SqDistToContour:
PROC [contour: Contour, q: Pair]
RETURNS [min:
REAL ¬ 10000.0] ~ {
pairs: PairSequence ~ contour.pairs;
n, n0, n1: NAT;
FOR i:
NAT
IN [0..pairs.length)
DO
d: REAL ~ SqDist[q, pairs[i]];
IF d < min THEN {min ¬ d; n ¬ i};
ENDLOOP;
n0 ¬ IF n > 0 THEN n-1 ELSE IF contour.closed THEN pairs.length-1 ELSE n;
n1 ¬ IF n < pairs.length-1 THEN n+1 ELSE IF contour.closed THEN 0 ELSE n;
RETURN[
MIN[
SqDistToSegment[pairs[n0], pairs[n], q],
SqDistToSegment[pairs[n], pairs[n1], q]]];
SqDistToArc:
PROC [q: Pair, arc:
REAL]
RETURNS [
REAL] ~ {
IF q.y > arc
THEN
RETURN[
MIN[SqDist[q, [arc, arc]], SqDist[q, [-arc, arc]]]]
ELSE {
yDif: REAL ~ q.y-arc;
d: REAL ~ arc-RealFns.SqRt[q.x*q.x+yDif*yDif];
RETURN[d*d];
};
};
FOR s:
NAT
IN [pm.sMin..pm.sMin+pm.sSize)
DO
IF p.abort THEN RETURN;
FOR f:
NAT
IN [pm.fMin..pm.fMin+pm.fSize)
DO
q: Pair ~ PairCoords[[f, s]];
potential: REAL ¬ 0.0;
IF p.options[radius]
AND p.rad.value # 0.0
THEN {
d: REAL ~ q.x*q.x+q.y*q.y;
potential ¬ IF d # 0.0 THEN 10.0*p.rad.value/d ELSE 255.0;
};
IF p.options[arc]
THEN {
d: REAL ~ SqDistToArc[q, p.arc.value];
potential ¬ IF d # 0.0 THEN potential+1.0/d ELSE 255.0;
};
IF p.options[line]
AND
ABS[q.x] < p.line.value
THEN {
potential ¬
IF q.y = 0.0
THEN 255.0
ELSE potential+10.0*(p.line.value-ABS[q.x])*(p.line.value-ABS[q.x])/ABS[q.y];
ELSE potential+(p.line.value-ABS[q.x])/(q.y*q.y);
d: REAL ~ SELECT q.x FROM
< -p.line.value => SqDist[q, [-p.line.value, 0.0]],
> p.line.value => SqDist[q, [p.line.value, 0.0]],
ENDCASE => q.y*q.y;
potential ¬ IF d # 0.0 THEN potential+1.0/d ELSE 255.0;
};
IF p.options[contour]
THEN {
d: REAL ~ SqDistToContour[c, q];
potential ¬ IF d # 0.0 THEN potential+1.0/d ELSE 255.0;
};
CtBasic.PutPixel[pm, f, s, Real.RoundI[MIN[255.0, MAX[0.0, potential]]]];
ENDLOOP;
ENDLOOP;