PEFileOpsImpl.mesa
Written by Darlene Plebon on August 24, 1983 9:42 am
Routines for reading/writing paths from/to files.
Last Edited by: Beach, February 13, 1984 3:45:21 pm PST
DIRECTORY
FS USING [Error, StreamOpen],
IO USING [Close, EndOf, GetRefAny, PutF, real, rope, SkipWhitespace, STREAM],
MessageWindow USING [Append, Blink, Clear],
PEBezier USING [Bezier, BezierToSegment, SegmentToBezier],
PEFileOps,
PETrajectoryOps USING [ForAllSegments, ForAllTrajectories, InsertSegment, InsertTrajectory, InsertVertex, SegmentProc, TrajectoryProc, VertexListLength],
PETypes USING [Segment, SegmentList, SegmentNode, SegmentRec, SegmentType, Trajectory, TrajectoryList, TrajectoryNode, TrajectoryRec, Vertex, VertexRec],
Rope USING [Concat, ROPE];
PEFileOpsImpl: CEDAR PROGRAM
IMPORTS FS, IO, MessageWindow, PEBezier, PETrajectoryOps, Rope
EXPORTS PEFileOps =
BEGIN OPEN PEBezier, PEFileOps, PETrajectoryOps, PETypes;
CubicType: TYPE = {coeffs, bezier};
ReadTrajectoryFile: PUBLIC PROCEDURE [fileName: Rope.ROPE] RETURNS [trajectoryList: TrajectoryList] = {
This routine reads the specified trajectory file and constructs the corresponding path editor data structure. A trajectory file may contain more than one trajectory.
in: IO.STREAM;
token: REF ANY;
stack: LIST OF REF ANYNIL;
lastTrajectoryNode: TrajectoryNode ← NIL;
lastSegmentNode: SegmentNode ← NIL;
Push: PROCEDURE [value: REF ANY] = {
stack ← CONS[value, stack];
};
Pop: PROCEDURE [] RETURNS [value: REF ANY] = {
IF stack # NIL THEN {
value ← stack.first;
stack ← stack.rest;
}
ELSE {
value ← NIL;
};
};
NewTrajectory: PROCEDURE [closed: BOOLEAN] = {
newTrajectory: Trajectory ← NEW[TrajectoryRec];
[trajectoryList, lastTrajectoryNode] ← InsertTrajectory[trajectoryList, newTrajectory, lastTrajectoryNode];
lastSegmentNode ← NIL;
IF ~closed THEN EnterPoint[moveTo]
ELSE {
[] ← Pop[];
[] ← Pop[];
};
};
EnterPoint: PROCEDURE [segmentType: SegmentType] = {
x, y: REF REAL;
newKnot: Vertex;
newSegment: Segment;
y ← NARROW[Pop[]];
x ← NARROW[Pop[]];
IF x # NIL THEN {
newKnot ← NEW[VertexRec ← [point: [x^, y^]]];
newSegment ← NEW[SegmentRec ← [type: segmentType]];
[newSegment.vertices,] ← InsertVertex[newSegment.vertices, newKnot, NIL];
[lastTrajectoryNode.first.segments, lastSegmentNode] ← InsertSegment[lastTrajectoryNode.first.segments, newSegment, lastSegmentNode];
};
};
EnterCubic: PROCEDURE [] = {
x1, y1, x2, y2, x3, y3: REF REAL;
b: Bezier;
newSegment: Segment;
y3 ← NARROW[Pop[], REF REAL];
x3 ← NARROW[Pop[], REF REAL];
y2 ← NARROW[Pop[], REF REAL];
x2 ← NARROW[Pop[], REF REAL];
y1 ← NARROW[Pop[], REF REAL];
x1 ← NARROW[Pop[], REF REAL];
IF x1 # NIL THEN {
Note that b0 is not used by BezierToSegment.
b ← [b0: [0.0, 0.0], b1: [x1^, y1^], b2: [x2^, y2^], b3: [x3^, y3^]];
newSegment ← BezierToSegment[b];
[lastTrajectoryNode.first.segments, lastSegmentNode] ← InsertSegment[lastTrajectoryNode.first.segments, newSegment, lastSegmentNode];
};
};
in ← FS.StreamOpen[fileName: fileName ! FS.Error => {
MessageWindow.Clear[];
MessageWindow.Append["PathTool file error: "];
MessageWindow.Append[error.explanation];
MessageWindow.Blink[];
GOTO fileNotOpened;
}];
trajectoryList ← NIL;
[] ← IO.SkipWhitespace[in];
WHILE ~IO.EndOf[in] DO
token ← IO.GetRefAny[in];
WITH token SELECT FROM
operator: ATOM => SELECT operator FROM
$PEMoveTo, $PEMoveToNext => NewTrajectory[FALSE];
$PEMoveToClosed, $PEMoveToNextClosed => NewTrajectory[TRUE];
$PELineTo => EnterPoint[curveTo];
$PECurveTo => EnterCubic[];
ENDCASE;
number: REF REAL => Push[number];
ENDCASE;
[] ← IO.SkipWhitespace[in];
ENDLOOP;
IO.Close[in];
EXITS
fileNotOpened => NULL;
};
WriteTrajectoryFile: PUBLIC PROCEDURE [fileName: Rope.ROPE, trajectoryList: TrajectoryList] = {
This routine writes a text representation of the specified trajectories to a file.
b: Bezier;
out: IO.STREAM;
firstTrajectory: BOOLEANTRUE;
WriteTrajectory: TrajectoryProc = {
WriteSegment: SegmentProc = {
numberVertices: CARDINAL ← VertexListLength[s.first.vertices];
IF firstSegment THEN {
firstSegment ← FALSE;
IF s.first.type = moveTo THEN
IO.PutF[out, "\n%f %f %g\n", IO.real[s.first.vertices.first.point.x], IO.real[s.first.vertices.first.point.y], IF firstTrajectory THEN IO.rope["PEMoveTo"] ELSE IO.rope["PEMoveToNext"]]
ELSE
IO.PutF[out, "\n%f %f %g\n", IO.real[s.first.fp.point.x], IO.real[s.first.fp.point.y], IF firstTrajectory THEN IO.rope["PEMoveToClosed"] ELSE IO.rope["PEMoveToNextClosed"]];
};
SELECT TRUE FROM
s.first.type = moveTo => NULL;
numberVertices = 1 => {
IO.PutF[out, "%f %f PELineTo\n", IO.real[s.first.vertices.first.point.x], IO.real[s.first.vertices.first.point.y]];
};
ENDCASE => {
b ← SegmentToBezier[s.first];
IO.PutF[out, "%f %f ", IO.real[b.b1.x], IO.real[b.b1.y]];
IO.PutF[out, "%f %f %f %f PECurveTo\n", IO.real[b.b2.x], IO.real[b.b2.y], IO.real[b.b3.x], IO.real[b.b3.y]];
};
};
firstSegment: BOOLEANTRUE;
ForAllSegments[t.first.segments, WriteSegment];
firstTrajectory ← FALSE;
};
out ← FS.StreamOpen[fileName: fileName, accessOptions: $create ! FS.Error => {
MessageWindow.Clear[];
MessageWindow.Append["PathTool file error: "];
MessageWindow.Append[error.explanation];
MessageWindow.Blink[];
GOTO fileNotOpened;
}];
MessageWindow.Clear[];
MessageWindow.Append[Rope.Concat["Writing Trajectory to file ", fileName]];
ForAllTrajectories[trajectoryList, WriteTrajectory];
IO.Close[out];
EXITS
fileNotOpened => NULL;
};
END.