-- Compiler PressObjs/n
-- Stone October 15, 1981 7:06 PM
-- Last Edited by: Stone, December 28, 1983 2:41 pm

DIRECTORY
 SplineDefs: FROM "SplineDefs",
 PressDefs: FROM "PressDefs",
 GriffinMemoryDefs USING [CZone],
 PointDefs: FROM "PointDefs",
 StyleDefs: FROM "StyleDefs",
 Real: FROM "Real",
 ControllerDefs: FROM "ControllerDefs",
 PressLineDefs: FROM "PressLineDefs",
 ScreenDefs: FROM "ScreenDefs",
 Rope USING [ROPE],
 ObjectDefs: FROM "ObjectDefs";

PressObjs: PROGRAM IMPORTS ObjectDefs, PressDefs, SplineDefs, GriffinMemoryDefs,Real,ControllerDefs,PressLineDefs, ScreenDefs EXPORTS ObjectDefs =
BEGIN OPEN ObjectDefs,PointDefs,GriffinMemoryDefs;

ROPE: TYPE = Rope.ROPE;
pressXscale: REAL 𡤁
pressYscale: REAL ← 1;
--magic centering numbers to center display on press page
--the distance (in micas) is the difference between 32 micas/pixel and
--2540 micas/inch for a full page.
--Y is also shifted about 1/4 inch empirically
--X is also shifted about 1/8 inch empirically
xOffset: REAL ← 1067+327;
yOffset: REAL ← 1042-635;
currentColor: PressDefs.ColorDescriptor ← [0,0,0];
inObject: BOOLEANFALSE;

--makes a press file of all objects linked to obj
PressAllObjects: PUBLIC PROCEDURE [s: ROPE]=
BEGIN
PressDefs.BeginPress[s];
ObjectDefs.ForAllObjects[PressObject];
PressDefs.EndPress[];
END;

--calls the correct type of formatting routine
PressObject: ObjectDefs.ObjectProc =
BEGIN
pcolor: PressDefs.ColorDescriptor;
newTL,newBR: ScrPt;
IF obj=NIL THEN RETURN;
IF ~Visible[obj] THEN RETURN; --outside, other view, or deleted
--partials also get tossed
[newTL,newBR] ← ScreenDefs.ClipToScreen[obj.tl,obj.br];
IF (newTL#obj.tl OR newBR#obj.br) THEN RETURN;
WITH object: obj SELECT FROM
shape => IF ~object.closed THEN PlotTrajectory[object.trajectory,object.style,FALSE]
ELSE BEGIN
--areas have trajectories too. TRUE = closed
  IF object.style.filled THEN FillArea[object];
  IF object.style.outlined THEN PlotTrajectory[object.trajectory,object.style,TRUE];
  END;
caption => BEGIN
 pcolor ← [hue: object.style.color.hue, saturation: object.style.color.saturation,
  brightness: object.style.color.brightness];
 PressDefs.ShowText [pcolor, object.text, ObjToPress[object.p0], object.style.orientation,object.style.anchor, ControllerDefs.FontWithNumber [object.style.fontid]];
END;
token => NULL;
ENDCASE;
END;

--first set in second set
BoxInsideBox: PROCEDURE[tl0,br0,tl1,br1: ScrPt] RETURNS [BOOLEAN]=
BEGIN
IF (tl0[X] IN [tl1[X]..br1[X]] AND br0[X] IN [tl1[X]..br1[X]]
AND tl0[Y] IN [tl1[Y]..br1[Y]] AND br0[Y] IN [tl1[Y]..br1[Y]])
THEN RETURN[TRUE]
ELSE RETURN[FALSE];
END;

--Draws a trajectory
PlotTrajectory: PROCEDURE [traj: REF Trajectory,style: REF StyleDefs.Style,closed: BOOLEAN] =
BEGIN
currentColor ← [hue: style.color.hue,
 saturation: style.color.saturation,
 brightness: style.color.brightness];
WITH traj SELECT FROM
 shape: REF Trajectory[linked] => BEGIN
  lshape: REF linked Trajectory ← FillGaps[shape,closed];
  linkPtr: REF Link ← lshape.links;
  UNTIL linkPtr = NIL DO
   SELECT linkPtr.degree FROM
   D0 => PlotDots[linkPtr.knots];
   D1 => PlotLines[linkPtr.knots,style];
   D2 => NULL;
   D3 => PlotCurve[linkPtr.knots,style,lshape.splineType,FALSE];
   ENDCASE;

   linkPtr ← linkPtr.link;
   ENDLOOP;
--do something here about releasing the object made by FillGaps
  END;
 shape: REF Trajectory[cyclic] => PlotCurve[shape.knots,style,traj.splineType,TRUE];

ENDCASE;
END;


PressCurve: PROCEDURE [coeffs: SplineDefs.Coeffs,newObject: BOOLEAN] =
BEGIN
zeropt: ObjPt ← [0,0];
IF newObject THEN BEGIN
IF inObject THEN PressDefs.EndObject[];
 PressDefs.BeginObject[currentColor];
 inObject ← TRUE;
 PressDefs.MoveTo[ObjToPress[coeffs.t0]];
END;
IF coeffs.t3=coeffs.t2 AND coeffs.t2=zeropt THEN BEGIN
 pt: ObjPt ← [coeffs.t1[X]+coeffs.t0[X],coeffs.t1[Y]+coeffs.t0[Y]];
 PressDefs.DrawTo[ObjToPress[pt]];
END
ELSE BEGIN
 p: PressDefs.PressSpline ← CoeffsToPressSpline[coeffs];
 PressDefs.DrawCurve[p];
END;
END;

--Plots Dots
PlotDots: PROCEDURE [knots: PointDefs.ObjPtSequence] =
BEGIN
END;

--Contours and Press's lines. Ignores the junction specification for now.
PlotLines: PROCEDURE [knots: PointDefs.ObjPtSequence,style: REF StyleDefs.Style] =
BEGIN
i: INTEGER;
p0,p1: ObjPt;
end0,end1: PressLineDefs.End;
lastknot: INTEGER ← knots.length-1;
end0 ← (SELECT style.firstend.type FROM flat => flat, angled => square, ENDCASE => round);
end1 ← round;

p0 ← knots[0];
IF lastknot=0 THEN PressLineDefs.ContourLine[p0,p0,style.width/2,end0,end1,PressCurve];
FOR i IN [1..lastknot] DO
 p1 ← knots[i];
IF i=lastknot THEN end1 ←
  (SELECT style.lastend.type FROM flat => flat, angled => square, ENDCASE => round);
 PressLineDefs.ContourLine[p0,p1,style.width/2,end0,end1,PressCurve];
IF i = 0 THEN end0 ← round;  
 p0 ← p1;
ENDLOOP;
PressDefs.EndObject[];
inObject ← FALSE;
END;

--Plots a curve. description is in the knots and the splinetype
PlotCurve: PROCEDURE [knots: PointDefs.ObjPtSequence,style: REF StyleDefs.Style,type: SplineDefs.SplineType,cyclic: BOOLEAN] =
BEGIN
coeffs: SplineDefs.CoeffsSequence;
end0,end1: PressLineDefs.End;
lastseg: INTEGER;
i: INTEGER ← 0;
end0 ← (SELECT style.firstend.type FROM flat => square, angled => square, ENDCASE => round);
end1 ← round;
IF cyclic THEN end0 ← end1 ← round;

coeffs ← IF cyclic THEN MakeCyclicSpline[knots,type] ELSE MakeSpline[knots,type ];
lastseg ← coeffs.length-1;
FOR i IN [0..lastseg] DO
IF i=lastseg THEN end1 ←
  (SELECT style.lastend.type FROM flat => square, angled => square, ENDCASE => round);
 PressLineDefs.ContourCubic[coeffs[i],style.width/2,end0,end1,PressCurve];
IF i = 0 THEN end0 ← round;  
ENDLOOP;
PressDefs.EndObject[];
inObject ← FALSE;
END;

MakeCyclicSpline: PROCEDURE[knots: PointDefs.ObjPtSequence, type: SplineDefs.SplineType] RETURNS[coeffs: SplineDefs.CoeffsSequence]=
BEGIN
i: INTEGER;
cycknots: SplineDefs.KnotSequence;
numknots: INTEGER ← (IF knots=NIL THEN 0 ELSE knots.length);
newLength: INTEGER;
IF numknots <= 0 THEN RETURN[NIL];
SELECT type FROM
 naturalUM, naturalAL,bezier=> newLength ← numknots+1;
 bspline, crspline=> newLength ← numknots+3;
ENDCASE;
cycknots ← CZone.NEW[SplineDefs.KnotSequenceRec[newLength]];
FOR i IN [0..numknots) DO
 cycknots[i] ← knots[i];
ENDLOOP;
cycknots[numknots] ← cycknots[0];
SELECT type FROM
 naturalUM=> type ← cyclicUM;
 naturalAL=> type ← cyclicAL;
 bspline=> BEGIN
  cycknots[numknots +1] ← cycknots[1];
  cycknots[numknots+2] ← cycknots[2];
  END;
 crspline=> BEGIN
  cycknots[numknots +1] ← cycknots[1];
  cycknots[numknots+2] ← cycknots[2];
  END;
ENDCASE;
coeffs ← SplineDefs.MakeSpline[cycknots,type];
RETURN;
END;

--type conversion routine
MakeSpline: PROCEDURE[knots: PointDefs.ObjPtSequence, type: SplineDefs.SplineType] RETURNS[coeffs: SplineDefs.CoeffsSequence]=
BEGIN
splineknots: SplineDefs.KnotSequence;
numknots: INTEGER ← (IF knots=NIL THEN 0 ELSE knots.length);
IF numknots <= 0 THEN RETURN[NIL];
splineknots ← CZone.NEW[SplineDefs.KnotSequenceRec[numknots]];
FOR i: NAT IN [0..numknots) DO
 splineknots[i] ← knots[i];
ENDLOOP;
coeffs ← SplineDefs.MakeSpline[splineknots,type];
RETURN;
END;


--makes a new linked trajectory with knuth splines in gaps
FillGaps: PROCEDURE[traj: REF linked Trajectory,closed: BOOLEAN] RETURNS[REF linked Trajectory] =
BEGIN
RETURN[traj];
END;

--Fills an area
FillArea: PROCEDURE [area: shape Object] =
BEGIN
i: INTEGER;
first: BOOLEANTRUE;
p: PressDefs.PressSpline;
color: PressDefs.ColorDescriptor←
 [hue: area.style.fillcolor.hue,
 saturation: area.style.fillcolor.saturation,
 brightness: area.style.fillcolor.brightness];

PressDefs.BeginObject[color];

WITH shape: area.trajectory SELECT FROM
linked =>
BEGIN
 i: INTEGER;
 type: REF Link ← shape.links;
UNTIL type = NIL DO
  SELECT type.degree FROM
  D0 => NULL;
  D1 => BEGIN
   IF first THEN PressDefs.MoveTo[ObjToPress[type.knots[0]]];
   FOR i IN [1..type.knots.length) DO
    PressDefs.DrawTo [ObjToPress[type.knots[i]]];
    ENDLOOP;
   END;
  D2 => NULL;
  D3 =>
   BEGIN
   allCoeffs: SplineDefs.CoeffsSequence ← MakeSpline[type.knots,shape.splineType];
   IF first THEN PressDefs.MoveTo[ObjToPress[allCoeffs[0].t0]];
   FOR i IN [0..allCoeffs.length) DO
    p ← CoeffsToPressSpline[allCoeffs[i]];
    PressDefs.DrawCurve[p];
    ENDLOOP;
   END;
  ENDCASE;
  type ← type.link;
  first ← FALSE;
  ENDLOOP;
--do something here about releasing the object made by FillGaps
END;
cyclic =>
BEGIN
 allCoeffs: SplineDefs.CoeffsSequence ← MakeCyclicSpline[shape.knots,shape.splineType];
 PressDefs.MoveTo[ObjToPress[allCoeffs[0].t0]];
FOR i IN [0..allCoeffs.length) DO
  p ← CoeffsToPressSpline[allCoeffs[i]];
  PressDefs.DrawCurve[p];
  ENDLOOP;
END;
ENDCASE;
PressDefs.EndObject[];
END;

ObjToPress: PROCEDURE[pt: ObjPt] RETURNS[pc: PressDefs.PressCoords]=
BEGIN
pt[X] ← pt[X]+xOffset;
pt[Y] ← pt[Y]+yOffset;
pc[PressDefs.X] ← Real.RoundC[pt[X]];
pc[PressDefs.Y] ← Real.RoundC[pt[Y]];
END;

CoeffsToPressSpline: PROCEDURE[coeffs: SplineDefs.Coeffs] RETURNS[p: PressDefs.PressSpline]=
BEGIN
p.x3 ← FloatToPressFloat[pressXscale*coeffs.t3[X]];
p.x2 ← FloatToPressFloat[pressXscale*coeffs.t2[X]];
p.x1 ← FloatToPressFloat[pressXscale*coeffs.t1[X]];
p.y3 ← FloatToPressFloat[pressYscale*coeffs.t3[Y]];
p.y2 ← FloatToPressFloat[pressYscale*coeffs.t2[Y]];
p.y1 ← FloatToPressFloat[pressYscale*coeffs.t1[Y]];
END;

FloatToPressFloat: PUBLIC PROCEDURE [r: REAL] RETURNS [p: PressDefs.PressFloat] = INLINE
BEGIN
--hack for press. Will be ok since r is already scaled to press coords
IF ABS[r] < (0.1) THEN RETURN[0];
--conversion done in SirPress
RETURN[r];
END;
END.