<> <> <> DIRECTORY IPErrors USING [Bug, MasterError], IPGeometry USING [], IPImagerBasic USING [Outline, OutlineRep, Pair, Segment, SegmentRep, Trajectory, Transformation], IPTransform USING [Tp]; IPGeometryImpl: CEDAR PROGRAM IMPORTS IPErrors, IPTransform EXPORTS IPGeometry = BEGIN OPEN IPImagerBasic; MoveTo: PUBLIC PROC[p: Pair] RETURNS[Trajectory] = { RETURN[NEW[SegmentRep[moveto] _ [ prev: NIL, lp: p, simple: TRUE, variant: moveto[]]]]; }; LineTo: PUBLIC PROC[t: Trajectory, p: Pair] RETURNS[Trajectory] = { RETURN[NEW[SegmentRep[lineto] _ [ prev: t, lp: p, simple: t.simple AND (p.x=t.lp.x OR p.y=t.lp.y), variant: lineto[]]]]; }; LineToX: PUBLIC PROC[t: Trajectory, x: REAL] RETURNS[Trajectory] = { RETURN[NEW[SegmentRep[lineto] _ [ prev: t, lp: [x, t.lp.y], simple: t.simple, variant: lineto[]]]]; }; LineToY: PUBLIC PROC[t: Trajectory, y: REAL] RETURNS[Trajectory] = { RETURN[NEW[SegmentRep[lineto] _ [ prev: t, lp: [t.lp.x, y], simple: t.simple, variant: lineto[]]]]; }; CurveTo: PUBLIC PROC[t: Trajectory, p1, p2, p3: Pair] RETURNS[Trajectory] = { RETURN[NEW[SegmentRep[curveto] _ [ prev: t, lp: p3, simple: FALSE, variant: curveto[p1, p2]]]]; }; MakeOutline: PUBLIC PROC[n: INT, p: PROC RETURNS[Trajectory]] RETURNS[Outline] = { IF n<0 THEN ERROR IPErrors.MasterError[InvalidArgs] ELSE IF n>LAST[NAT] THEN ERROR IPErrors.MasterError[LimitExceeded] ELSE { size: NAT = n; outline: Outline = NEW[OutlineRep[size]]; FOR i: NAT IN[0..size) DO outline[i] _ p[] ENDLOOP; RETURN[outline]; }; }; MSegment: TYPE = REF SegmentRep[moveto]; LSegment: TYPE = REF SegmentRep[lineto]; CSegment: TYPE = REF SegmentRep[curveto]; MapTrajectory: PUBLIC PROC[t: Trajectory, m: Transformation _ NIL, move: PROC[Pair], line: PROC[Pair], curve: PROC[Pair, Pair, Pair]] = { Map: PROC[p: Pair] RETURNS[Pair] = INLINE { RETURN[IF m=NIL THEN p ELSE IPTransform.Tp[m, p]] }; Eq: PROC[a, b: Pair] RETURNS[BOOL] = INLINE { RETURN[a.x=b.x AND a.y=b.y] }; fp, lp: Pair; move[lp _ fp _ Map[t.lp]]; FOR s: Segment _ t, s.prev UNTIL s=NIL DO WITH s SELECT FROM s: MSegment => EXIT; s: LSegment => { p: Pair = Map[s.prev.lp]; IF NOT Eq[p, lp] THEN line[lp _ p]; }; s: CSegment => { p1: Pair = Map[s.p2]; p2: Pair = Map[s.p1]; p3: Pair = Map[s.prev.lp]; matches: NAT _ 0; IF Eq[lp, p1] THEN matches _ matches+1; IF Eq[p1, p2] THEN matches _ matches+1; IF Eq[p2, p3] THEN matches _ matches+1; IF matches<2 THEN curve[p1, p2, lp _ p3] ELSE IF matches<3 THEN line[lp _ p3]; }; ENDCASE => ERROR IPErrors.Bug; -- invalid segment type REPEAT FINISHED => ERROR IPErrors.Bug; -- should have seen MSegment ENDLOOP; }; MapOutline: PUBLIC PROC[o: Outline, m: Transformation _ NIL, move: PROC[Pair], line: PROC[Pair], curve: PROC[Pair, Pair, Pair]] = { FOR i: NAT IN[0..o.length) DO MapTrajectory[o[i], m, move, line, curve]; ENDLOOP; }; END.