-- Compiler PressObjs/n
-- Stone October 15, 1981  7:06 PM

DIRECTORY
	SplineDefs: FROM "SplineDefs",
	PressDefs: FROM "PressDefs",
	GriffinMemoryDefs: FROM "GriffinMemoryDefs",
	PointDefs: FROM "PointDefs",
	StyleDefs: FROM "StyleDefs",
	GriffinFontDefs: FROM "GriffinFontDefs",
	Real: FROM "Real",
	RealConvert: FROM "RealConvert",
	ControllerDefs: FROM "ControllerDefs",
	PressLineDefs: FROM "PressLineDefs",
	ScreenDefs: FROM "ScreenDefs",
	ObjectDefs: FROM "ObjectDefs";

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

RABS: PROCEDURE [r: REAL] RETURNS[REAL] = INLINE BEGIN
	IF r<0 THEN RETURN[-r] ELSE RETURN[r]; END;

pressXscale: REAL ←1;
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: BOOLEAN ← FALSE;

--makes a press file of all objects linked to obj
PressAllObjects: PUBLIC PROCEDURE [s: STRING]=
BEGIN
IF NOT PressDefs.BeginPress[s,TRUE,1] 
	THEN ERROR;	--no good on begin press
PressDefs.BeginPage[];
ObjectDefs.ForAllObjects[PressObject];
PressDefs.EndPage[];
IF NOT PressDefs.EndPress[] THEN ERROR;
END;

--calls the correct type of formatting routine
PressObject:  ObjectDefs.ObjectProc =
BEGIN
pcolor: PressDefs.ColorDescriptor;
thisScreen: ScreenDefs.ScreenPtr ← ScreenDefs.GetCurrentScreen[];
IF obj=NIL THEN RETURN;
IF ~Visible[obj] THEN RETURN;	--outside, other view, or deleted
--partials also get tossed
IF  (obj.br[X] > thisScreen.rx OR obj.tl[X] <thisScreen.lx
	OR obj.br[Y] > thisScreen.by OR obj.tl[Y] <thisScreen.ty ) 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: Trajectory,style: POINTER TO StyleDefs.Style,closed: BOOLEAN] =
BEGIN
currentColor ← [hue: style.color.hue,
	saturation: style.color.saturation,
	brightness: style.color.brightness];
WITH shape: traj SELECT FROM
	linked => BEGIN
		lshape: POINTER TO linked Trajectory ← FillGaps[@shape,closed];
		linkPtr: POINTER TO 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;
	cyclic => PlotCurve[shape.knots,style,traj.splineType,TRUE];

	ENDCASE;
END;


PressCurve: PROCEDURE [coeffs: POINTER TO 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: DESCRIPTOR FOR ARRAY OF PointDefs.ObjPt] =
BEGIN
END;

--Contours and Press's lines.  Ignores the junction specification for now. 
PlotLines: PROCEDURE [knots: DESCRIPTOR FOR ARRAY OF PointDefs.ObjPt,style: POINTER TO StyleDefs.Style] =
BEGIN
i: INTEGER;
p0,p1: ObjPt;
end0,end1: PressLineDefs.End;
lastknot: INTEGER ← LENGTH[knots]-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: DESCRIPTOR FOR ARRAY OF PointDefs.ObjPt,style: POINTER TO StyleDefs.Style,type: SplineDefs.SplineType,cyclic: BOOLEAN] =
BEGIN
coeffs: DESCRIPTOR FOR ARRAY OF SplineDefs.Coeffs;
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 SplineDefs.MakeSpline[knots,type ];
lastseg ← LENGTH[coeffs]-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;
SplineDefs.FreeCoeffs[coeffs];
END;

MakeCyclicSpline: PROCEDURE[knots: DESCRIPTOR FOR ARRAY OF ObjPt, type: SplineDefs.SplineType] RETURNS[coeffs: DESCRIPTOR FOR ARRAY OF SplineDefs.Coeffs]=
BEGIN
i: INTEGER;
cycknots: DESCRIPTOR FOR ARRAY OF ObjPt;
numknots: INTEGER ← LENGTH[knots];
newLength: INTEGER;
IF numknots <= 0 THEN RETURN[DESCRIPTOR[NIL,0]];
SELECT type FROM
	naturalUM, naturalAL,bezier=> newLength ← numknots+1;
	bspline, crspline=> newLength ← numknots+3;
	ENDCASE;
cycknots ← DESCRIPTOR[Allocate[newLength*SIZE[ObjPt]],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];
Free[BASE[cycknots]];
RETURN;
END;

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

--Fills an area
FillArea: PROCEDURE [area: shape Object] =
BEGIN
i: INTEGER;
first: BOOLEAN ← TRUE;
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: POINTER TO 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..LENGTH[type.knots]) DO
				PressDefs.DrawTo [ObjToPress[type.knots[i]]];
				ENDLOOP;
			END;
		D2 => NULL;
		D3 =>
			BEGIN
			allCoeffs: DESCRIPTOR FOR ARRAY OF SplineDefs.Coeffs;
			SplineDefs.InitSplines[Allocate,Free];
			allCoeffs ← SplineDefs.MakeSpline[type.knots,shape.splineType];
			IF first THEN PressDefs.MoveTo[ObjToPress[allCoeffs[0].t0]];
			FOR i IN [0..LENGTH[allCoeffs]) DO
				p ← CoeffsToPressSpline[allCoeffs[i]];
				PressDefs.DrawCurve[p];
				ENDLOOP;
			SplineDefs.FreeCoeffs[allCoeffs];
			END;
		ENDCASE;
		type ← type.link;
		first ← FALSE;
		ENDLOOP;
--do something here about releasing the object made by FillGaps
	END;
cyclic =>
	BEGIN
	allCoeffs: DESCRIPTOR FOR ARRAY OF SplineDefs.Coeffs;
	SplineDefs.InitSplines[Allocate,Free];
	allCoeffs ← MakeCyclicSpline[shape.knots,shape.splineType];
	PressDefs.MoveTo[ObjToPress[allCoeffs[0].t0]];
	FOR i IN [0..LENGTH[allCoeffs]) DO
		p ← CoeffsToPressSpline[allCoeffs[i]];
		PressDefs.DrawCurve[p];
		ENDLOOP;
	SplineDefs.FreeCoeffs[allCoeffs];
	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.Ax ← FloatToPressFloat[pressXscale*coeffs.t3[X]];
p.Bx ← FloatToPressFloat[pressXscale*coeffs.t2[X]];
p.Cx ← FloatToPressFloat[pressXscale*coeffs.t1[X]];
p.Ay ← FloatToPressFloat[pressYscale*coeffs.t3[Y]];
p.By ← FloatToPressFloat[pressYscale*coeffs.t2[Y]];
p.Cy ← FloatToPressFloat[pressYscale*coeffs.t1[Y]];
END;

FloatToPressFloat: PUBLIC PROCEDURE [r: REAL] RETURNS [p: PressDefs.PressFloat] =
BEGIN 
--hack for press.  Will be ok since r is already scaled to press coords
IF RABS[r] < (0.1) THEN RETURN[0];
--on to the conversion
RETURN[RealConvert.IeeeToBcpl[r]];
END;
END.