FitIOImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Maureen Stone March 14, 1985 6:25:19 pm PST
Doug Wyatt, September 5, 1985 2:24:33 pm PDT
DIRECTORY
Complex USING [Mul, VEC],
Cubic USING [Bezier],
FitBasic USING [Handle, LinkHandle, SampleHandle, SListHandle, TrajHandle],
FitIO USING [Context, Feedback],
FitState USING [GetClosed, Handle],
FitStateUtils USING [ForAllLinks, ForAllOtherSLists, ForAllOtherTrajs, ForAllSamples, LinkProc, SampleProc, SListProc, TrajProc],
Imager USING [Context, DoSave, MaskFill, MaskStroke, MaskStrokeTrajectory, MaskVector, SetColor, SetStrokeEnd, SetStrokeWidth, SetXY, Trans, white],
ImagerPath USING [CurveTo, LineTo, MapTrajectoryList, MoveTo, PathProc, Trajectory],
IO USING [char, Close, CR, int, Put, PutRope, real, rope, SP, STREAM],
RealFns USING [],
Rope USING [ROPE],
Vector USING [Unit];
FitIOImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerPath, IO, Complex, Vector, FitStateUtils, FitState
EXPORTS FitIO = { OPEN FitIO;
Trajectory: TYPE ~ ImagerPath.Trajectory;
Handle: TYPE = FitState.Handle;
SetFeedback: PUBLIC PROC[ctx: Context, feedback: Feedback] = {
ctx.feedback ¬ feedback;
IF ctx.logActions THEN { --print feedback
SELECT feedback.color FROM
Imager.white => PrintRope[ctx, "white "];
ENDCASE=> PrintRope[ctx, "black"];
PrintLine[ctx, "FB.color"];
PrintReal[ctx, feedback.sampleSize]; PrintLine[ctx, "Fit.sampleSize"];
PrintReal[ctx, feedback.jointSize]; PrintLine[ctx, "Fit.jointSize"];
PrintReal[ctx, feedback.nodeLength]; PrintLine[ctx, "Fit.nodeLength"];
PrintReal[ctx, feedback.nodeLineWidth]; PrintLine[ctx, "Fit.nodeLineWidth"];
PrintReal[ctx, feedback.lineWidth]; PrintLine[ctx, "Fit.lineWidth"];
};
};
DrawSamples: PUBLIC PROC [ctx: Context, handle: Handle, all: BOOLEAN ¬ FALSE, fill: BOOLEAN ¬ FALSE] = {
treat samples as vertices of a polygon or a broken line
list: LIST OF Trajectory;
traj: Trajectory ¬ PathFromSList[ctx, handle.slist];
IF traj=NIL THEN RETURN ELSE list ¬ CONS[traj,list];
Imager.SetColor[ctx.imager, ctx.feedback.color];
IF all THEN {
makeList: FitStateUtils.SListProc = {list ¬ CONS[PathFromSList[ctx, slist],list]};
FitStateUtils.ForAllOtherSLists[handle,makeList];
};
IF fill THEN MaskFill[ctx,list]
ELSE
IF FitState.GetClosed[handle] THEN MaskStrokeClosed[ctx,list]
ELSE MaskStroke[ctx,list];
IF ctx.logActions THEN PrintLine[ctx, "\n"];
};
DrawContour: PUBLIC PROC [ctx: Context, handle: Handle, all: BOOLEAN ¬ FALSE, fill: BOOLEAN ¬ FALSE] = {
traj: Trajectory ¬ PathFromTraj[ctx, handle.traj];
list: LIST OF Trajectory;
IF traj=NIL THEN RETURN ELSE list ¬ CONS[traj,list];
Imager.SetColor[ctx.imager, ctx.feedback.color];
IF all THEN {
makeList: FitStateUtils.TrajProc = {list ¬ CONS[PathFromTraj[ctx, traj, fill],list]};
FitStateUtils.ForAllOtherTrajs[handle,makeList];
};
IF fill THEN MaskFill[ctx, list]
ELSE
IF FitState.GetClosed[handle] OR all THEN MaskStrokeClosed[ctx, list]
ELSE MaskStroke[ctx, list];
IF ctx.logActions THEN PrintLine[ctx, "\n"];
};
DrawCubic: PUBLIC PROC[ctx: Context, cubic: Cubic.Bezier] = {
list: LIST OF Trajectory;
traj: Trajectory ¬ MoveTo[ctx, cubic.b0];
traj ¬ CurveTo[ctx, traj,cubic.b1,cubic.b2,cubic.b3];
MaskStroke[ctx, CONS[traj,list]];
};
PathFromSList: PROC [ctx: Context, slist: FitBasic.SListHandle] RETURNS [path: Trajectory] = {
treat samples as vertices of a polygon or a broken line
first: BOOLEAN ¬ TRUE;
do: FitStateUtils.SampleProc = {
IF first THEN {path ¬ MoveTo[ctx, s.xy]; first ¬ FALSE}
ELSE path¬ LineTo[ctx, path,s.xy];
};
FitStateUtils.ForAllSamples[slist, do];
IF ctx.logActions AND path#NIL THEN PrintLine[ctx, "\n"];
RETURN[path];
};
PathFromTraj: PROC [ctx: Context, traj: FitBasic.TrajHandle, moveToNext: BOOLEAN ¬ FALSE] RETURNS [path: Trajectory] = {
convert my trajectory to an imager.trajectory
first: BOOLEAN ¬ TRUE;
do: FitStateUtils.LinkProc = {
IF first THEN {path ¬ MoveTo[ctx, l.cubic.b0, moveToNext]; first ¬ FALSE};
path ¬ CurveTo[ctx, path,l.cubic.b1,l.cubic.b2,l.cubic.b3];
};
FitStateUtils.ForAllLinks[traj, do];
IF ctx.logActions AND path#NIL THEN PrintLine[ctx, "\n"];
};
MarkSamples: PUBLIC PROC [ctx: Context, handle: Handle, all: BOOLEAN ¬ FALSE] = {
markSample: FitStateUtils.SampleProc = {MarkSample[ctx, s]};
markSamples: FitStateUtils.SListProc = {FitStateUtils.ForAllSamples[slist, markSample]};
[] ¬ markSamples[handle.slist];
IF all THEN FitStateUtils.ForAllOtherSLists[handle, markSamples];
IF ctx.logActions THEN PrintLine[ctx, "\n"];
};
MarkNodes: PUBLIC PROC [ctx: Context, handle: Handle, all: BOOLEAN ¬ FALSE] = {
markNode: FitStateUtils.SampleProc = {MarkNode[ctx, s]};
markNodes: FitStateUtils.SListProc = {FitStateUtils.ForAllSamples[slist, markNode]};
[] ¬ markNodes[handle.slist];
IF all THEN FitStateUtils.ForAllOtherSLists[handle, markNodes];
IF ctx.logActions THEN PrintLine[ctx, "\n"];
};
MarkJoints: PUBLIC PROC [ctx: Context, handle: Handle, all: BOOLEAN ¬ FALSE] ={
--joints between the cubic pieces
do: FitStateUtils.TrajProc = {MarkTrajJoints[ctx, traj]};
[] ¬ MarkTrajJoints[ctx, handle.traj];
IF all THEN FitStateUtils.ForAllOtherTrajs[handle, do];
IF ctx.logActions THEN PrintLine[ctx, "\n"];
};
MarkTrajJoints: PROC[ctx: Context, traj: FitBasic.TrajHandle] = {
first: BOOLEAN ¬ TRUE;
do: FitStateUtils.LinkProc = {
IF first THEN {MarkJoint[ctx, l.cubic.b0]; first ¬ FALSE};
MarkJoint[ctx, l.cubic.b3];
};
FitStateUtils.ForAllLinks[traj, do];
IF ctx.logActions THEN PrintLine[ctx, "\n"];
};
FeedbackRec: TYPE=RECORD [
color: Imager.Color ← black,
sampleSize: REAL ← 1,
jointSize: REAL ← 2,
nodeLength: REAL ← 2,
nodeLineWidth: REAL ← 0,
lineWidth: REAL ← 0--for DrawSamples and DrawContour
];
MarkNode: PUBLIC PROC [ctx: Context, s: FitBasic.SampleHandle] = {
pt: Complex.VEC ¬ MagnifyPoint[ctx, s.xy];
drawProc: PROC = {
drawTan: PROC[t: Complex.VEC, d: REAL] = {
t ¬ Complex.Mul[Vector.Unit[t],[0,d]];
IF t = [0,0] THEN { --draw a box
w: REAL ¬ d/2.0;
path: ImagerPath.PathProc ~ {
moveTo[[-w,-w]]; lineTo[[-w,+w]]; lineTo[[+w,+w]]; lineTo[[+w,-w]];
};
Imager.MaskStroke[context: ctx.imager, path: path, closed: TRUE];
}
ELSE { --draw a line
Imager.MaskVector[ctx.imager, [-t.x,-t.y], [t.x,t.y]];
};
};
Imager.SetXY[ctx.imager, pt];
Imager.Trans[ctx.imager];
Imager.SetStrokeWidth[ctx.imager, ctx.feedback.nodeLineWidth];
drawTan[t: s.tanIn, d: ctx.feedback.nodeLength];
drawTan[t: s.tanOut, d: ctx.feedback.nodeLength*1.5];
IF s.jointType=forced THEN { --draw diamond dot
w: REAL ¬ ctx.feedback.nodeLength/2.0;
path: ImagerPath.PathProc ~ {
moveTo[[-w, 0]]; lineTo[[0,w]]; lineTo[[w,0]]; lineTo[[0,-w]];
};
Imager.MaskStroke[context: ctx.imager, path: path, closed: TRUE];
Imager.MaskFill[context: ctx.imager, path: path];
};
};
IF s.jointType=none THEN RETURN;
Imager.DoSave[ctx.imager, drawProc];
IF ctx.logActions THEN {
PrintPoint[ctx, pt];
PrintPoint[ctx, s.tanIn];
PrintPoint[ctx, s.tanOut];
IF s.jointType=forced THEN PrintRope[ctx, "Fit.forcedJoint "] ELSE PrintRope[ctx, "Fit.joint "];
};
};
MarkSample: PUBLIC PROC [ctx: Context, s: FitBasic.SampleHandle] = {
size: REAL ¬ ctx.feedback.sampleSize;
pt: Complex.VEC ¬ MagnifyPoint[ctx, s.xy];
draw: PROC = {
dot: ImagerPath.PathProc ~ { moveTo[[0, 0]] };
Imager.SetXY[ctx.imager, pt];
Imager.Trans[ctx.imager];
Imager.SetStrokeWidth[ctx.imager, size];
Imager.SetStrokeEnd[ctx.imager, round];
Imager.MaskStroke[ctx.imager, dot];
Imager.MaskRectangle[ctx.imager,pt.x-size/2,pt.y-size/2,size,size];
};
Imager.DoSave[ctx.imager, draw];
IF ctx.logActions THEN {PrintPoint[ctx, pt]; PrintRope[ctx, "Fit.mark "]};
};
MarkJoint: PUBLIC PROC[ctx: Context, pt: Complex.VEC] = {
size: REAL ¬ ctx.feedback.jointSize;
dot: ImagerPath.PathProc ~ { moveTo[pt] };
pt ¬ MagnifyPoint[ctx, pt];
Imager.SetStrokeWidth[ctx.imager, size];
Imager.SetStrokeEnd[ctx.imager, round];
Imager.MaskStroke[ctx.imager, dot];
Imager.MaskRectangle[ctx.imager,pt.x,pt.y,size,size];
IF ctx.logActions THEN {PrintPoint[ctx, pt]; PrintRope[ctx, "Fit.joint "]};
};
MoveTo: PROC[ctx: Context, p: Complex.VEC, moveToNext: BOOLEAN ¬ FALSE] RETURNS [path: Trajectory]= {
p ¬ MagnifyPoint[ctx, p];
path ¬ ImagerPath.MoveTo[[p.x,p.y]];
IF ctx.logActions THEN {
PrintPoint[ctx, p];
IF moveToNext THEN PrintRope[ctx, "Fit.movetonext "]
ELSE PrintRope[ctx, "Fit.moveto "]};
RETURN[path];
};
LineTo: PROC[ctx: Context, path: Trajectory, p: Complex.VEC] RETURNS [Trajectory]= {
p ¬ MagnifyPoint[ctx, p];
path ¬ ImagerPath.LineTo[path, [p.x,p.y]];
IF ctx.logActions THEN {PrintPoint[ctx, p]; PrintRope[ctx, "Fit.lineto "]};
RETURN[path];
};
CurveTo: PROC[ctx: Context, path: Trajectory, p1,p2,p3: Complex.VEC] RETURNS [Trajectory] = {
p1 ¬ MagnifyPoint[ctx, p1];
p2 ¬ MagnifyPoint[ctx, p2];
p3 ¬ MagnifyPoint[ctx, p3];
path ¬ ImagerPath.CurveTo[path,[p1.x,p1.y],[p2.x,p2.y],[p3.x,p3.y]];
IF ctx.logActions THEN {
PrintPoint[ctx, p1];
PrintPoint[ctx, p2];
PrintPoint[ctx, p3];
PrintLine[ctx, "Fit.curveto "];
};
RETURN[path];
};
MaskStroke: PROC[ctx: Context, list: LIST OF Trajectory] = {
width: REAL ¬ ctx.feedback.lineWidth;
count: INT ¬ 0;
Imager.SetStrokeWidth[ctx.imager, width];
FOR l: LIST OF Trajectory ¬ list, l.rest UNTIL l=NIL DO
Imager.MaskStrokeTrajectory[ctx.imager,l.first];
count ¬ count+1;
ENDLOOP;
IF ctx.logActions THEN {PrintInt[ctx, count]; PrintLine[ctx, "Fit.maskstroke"]};
};
MaskStrokeClosed: PROC[ctx: Context, list: LIST OF Trajectory] = {
width: REAL ¬ ctx.feedback.lineWidth;
count: INT ¬ 0;
Imager.SetStrokeWidth[ctx.imager, width];
FOR l: LIST OF Trajectory ¬ list, l.rest UNTIL l=NIL DO
Imager.MaskStrokeTrajectory[ctx.imager,l.first, TRUE];
count ¬ count+1;
ENDLOOP;
IF ctx.logActions THEN {PrintInt[ctx, count]; PrintLine[ctx, "Fit.maskstrokeclosed"]};
};
MaskFill: PROC[ctx: Context, list: LIST OF Trajectory] = {
path: ImagerPath.PathProc ~ {
ImagerPath.MapTrajectoryList[list, moveTo, lineTo, curveTo, conicTo, arcTo];
};
Imager.MaskFill[ctx.imager, path];
IF ctx.logActions THEN {
count: INT ¬ 0;
FOR l: LIST OF Trajectory ¬ list, l.rest UNTIL l=NIL DO
count ¬ count+1;
ENDLOOP;
PrintInt[ctx, count];
PrintLine[ctx, "Fit.maskfill"];
};
};
NoLog: PUBLIC SIGNAL = CODE;
StartLog: PUBLIC PROC [ctx: Context, stream: IO.STREAM ¬ NIL] = {
IF stream=NIL uses previous stream. Otherwise, closes previous stream (if any) and sets current output stream to stream.
IF ctx.log#NIL THEN IO.Close[ctx.log];
ctx.log ¬ stream;
ctx.logActions ¬ TRUE;
};
StopLog: PUBLIC PROC[ctx: Context, close: BOOLEAN ¬ TRUE] = {
IF close=FALSE just disables logging.
IF close THEN IO.Close[ctx.log];
ctx.logActions ¬ FALSE;
};
PrintReal: PROC[ctx: Context, r: REAL] = {OPEN IO; Put[ctx.log,real[r],char[SP]]};
PrintRope: PROC[ctx: Context, s: Rope.ROPE] = {IO.PutRope[ctx.log,s]};
PrintLine: PROC[ctx: Context, s: Rope.ROPE] = {OPEN IO; Put[ctx.log,rope[s],char[CR]]};
PrintInt: PROC[ctx: Context, i: INT] = {OPEN IO; Put[ctx.log,int[i],char[SP]]};
PrintPoint: PROC[ctx: Context, pt: Complex.VEC] = {PrintReal[ctx, pt.x]; PrintReal[ctx, pt.y]};
MagnifyPoint: PUBLIC PROC [ctx: Context, p: Complex.VEC] RETURNS[Complex.VEC] = {
--magnify and position
vt: Complex.VEC;
vt.x ¬ p.x*ctx.magnify+ctx.position.x;
vt.y ¬ p.y*ctx.magnify+ctx.position.y;
RETURN[vt]
};
UnMagnifyPoint: PUBLIC PROC [ctx: Context, p: Complex.VEC] RETURNS[Complex.VEC] = {
--undo magnify and position
vt: Complex.VEC;
vt.x ¬ (p.x-ctx.position.x)/ctx.magnify;
vt.y ¬ (p.y-ctx.position.y)/ctx.magnify;
RETURN[vt]
};
}.