-- SplineImpl.mesa
-- Last changed by Doug Wyatt, September 1, 1982 12:07 pm

DIRECTORY
Graphics USING [Path, MoveTo, CurveTo],
CGCubic USING [Bezier, Coeffs, CoeffsToBezier],
CGSpline USING [Coeffs, Coords, KnotsRep, MakeSpline, New, Ref],
Spline USING [],
CGStorage USING [pZone, qZone];

SplineImpl: CEDAR PROGRAM
IMPORTS Graphics, CGCubic, CGSpline, CGStorage
EXPORTS Spline = {

knotZone: ZONE = CGStorage.pZone;
repZone: ZONE = CGStorage.qZone;

Knots: TYPE = REF KnotsRep;
KnotsRep: TYPE = CGSpline.KnotsRep;

Ref: TYPE = REF Rep;
Rep: PUBLIC TYPE = RECORD[knots: Knots, spline: CGSpline.Ref];

New: PUBLIC PROC RETURNS[Ref] = {
knots: Knots ← knotZone.NEW[KnotsRep[20] ← [length: 0, array: ]];
spline: CGSpline.Ref ← CGSpline.New[];
RETURN[repZone.NEW[Rep ← [knots,spline]]];
};

Reset: PUBLIC PROC[self: Ref] = {
self.knots.length ← 0;
};

Knot: PUBLIC PROC[self: Ref, x,y: REAL] = {
knots: Knots ← self.knots;
i: NAT ← knots.length;
size: NAT ← i + 1;
space: NAT ← knots.space;
IF size>space THEN {
new: Knots ← knotZone.NEW[KnotsRep[space+space/2] ← [length: 0, array: ]];
FOR j: NAT IN[0..i) DO new[j] ← knots[j] ENDLOOP;
knots ← self.knots ← new;
};
knots[i] ← [x,y];
knots.length ← size;
};

Enter: PUBLIC PROC[self: Ref, path: Graphics.Path, cyclic: BOOLEAN, flush: BOOLEAN] = {
first: BOOLEANTRUE;
Proc: PROC[coeffs: CGSpline.Coeffs] = { OPEN coeffs;
c: CGCubic.Coeffs ← [c0: [t0[X],t0[Y]], c1: [t1[X],t1[Y]],
c2: [t2[X],t2[Y]], c3: [t3[X],t3[Y]]];
b: CGCubic.Bezier ← CGCubic.CoeffsToBezier[c];
IF first THEN { Graphics.MoveTo[path,b.b0.x,b.b0.y,flush]; first ← FALSE };
Graphics.CurveTo[path, b.b1.x,b.b1.y,b.b2.x,b.b2.y,b.b3.x,b.b3.y];
};
IF self.knots.length=0 THEN RETURN;
IF cyclic THEN { k: CGSpline.Coords ← self.knots[0]; Knot[self,k[X],k[Y]] };
CGSpline.MakeSpline[self.spline,self.knots,(IF cyclic THEN cyclicAL ELSE naturalAL),Proc];
self.knots.length ← 0;
};

}.