<> <> <> <> <> <<>> DIRECTORY CDInstances, CDCurves, CDTexts, CD, CDBasics, CDLayers, CDIO, CDOps, Imager, ImagerPath, Rope, TokenIO, Vector2; CDCurvesImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDLayers, CDIO, CDOps, Imager, ImagerPath, Rope, TokenIO EXPORTS CDCurves = BEGIN CurveSpecific: TYPE = CDCurves.CurveSpecific; CurveRec: TYPE = CDCurves.CurveRec; LoP: TYPE = LIST OF CD.Position; splineClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$Spline0, [ drawMe: DrawCurve, quickDrawMe: DrawCurve, hitInside: HitInsideCurve, describe: Describe, internalRead: ReadCurve, internalWrite: WriteCurve, newLayer: ChangeLayer, description: "spline" ]]; lineClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$Line0, [ drawMe: DrawCurve, quickDrawMe: DrawCurve, hitInside: HitInsideCurve, describe: Describe, internalRead: ReadCurve, internalWrite: WriteCurve, newLayer: ChangeLayer, description: "line" ]]; polygonClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$Polygon0, [ drawMe: DrawCurve, quickDrawMe: DrawCurve, hitInside: HitInsideCurve, describe: Describe, internalRead: ReadCurve, internalWrite: WriteCurve, newLayer: ChangeLayer, description: "polygon" ]]; filledCurveClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$FilledCurve0, [ drawMe: DrawCurve, quickDrawMe: DrawCurve, hitInside: HitInsideCurve, describe: Describe, internalRead: ReadCurve, internalWrite: WriteCurve, newLayer: ChangeLayer, description: "filled curve" ]]; oldPolygonClass: CD.ObjectClass _ CD.RegisterObjectClass[$Polygon, [ internalRead: ReadOldPolygon, description: "old kind of polygon" ]]; ToImagerRectangle: PROC [r: CD.Rect] RETURNS [Imager.Rectangle] = { RETURN [[x: r.x1, y: r.y1, w: r.x2-r.x1, h: r.y2-r.y1]] }; CopyList: PROC [points: LoP, w: CD.Number_0] RETURNS [copy: LoP_NIL, r: CD.Rect, leng: INT_0] = { min: CD.Position _ CDBasics.highposition; max: CD.Position _ CDBasics.minposition; FOR class: LoP _ points, class.rest WHILE class#NIL DO leng _ leng+1; min _ CDBasics.MinPoint[min, class.first]; max _ CDBasics.MaxPoint[max, class.first]; ENDLOOP; min _ [min.x-w, min.y-w]; max _ [max.x+w, max.y+w]; FOR class: LoP _ points, class.rest WHILE class#NIL DO copy _ CONS[CDBasics.SubPoints[class.first, min], copy]; ENDLOOP; r _ CDBasics.ToRect[min, max]; IF (r.x2-r.x1)>LAST[NAT] OR (r.y2-r.y1)>LAST[NAT] THEN CD.Error[calling, "size out of range"]; }; CreatePolygon: PUBLIC PROC [points: LIST OF CD.Position, layer: CD.Layer] RETURNS [ob: CD.Object_NIL, offset: CD.Position_[0, 0]] = { r: CD.Rect; leng: INT; cp: CurveSpecific = NEW[CurveRec]; [cp.points, r, leng] _ CopyList[points, 0]; IF leng<3 THEN RETURN; cp.path _ ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]]; FOR class: LoP _ cp.points.rest, class.rest WHILE class#NIL DO cp.path _ ImagerPath.LineTo[cp.path, [class.first.x, class.first.y]]; ENDLOOP; ob _ NEW[CD.ObjectRep_[ bbox: [0, 0, r.x2-r.x1, r.y2-r.y1], layer: CDLayers.AbstractToPaint[layer], class: polygonClass, immutable: TRUE, specific: cp ]]; cp.imagerObject _ NEW[Imager.ObjectRep _ [draw: MaskFillProc, clip: ToImagerRectangle[ob.bbox], data: cp]]; offset _ CDBasics.BaseOfRect[r]; }; CreateFilledCurve: PUBLIC PROC [points: LIST OF CD.Position, layer: CD.Layer] RETURNS [ob: CD.Object_NIL, offset: CD.Position_[0, 0]] = { r: CD.Rect; leng: INT; pl: LoP; cp: CurveSpecific = NEW[CurveRec]; [cp.points, r, leng] _ CopyList[points, 0]; IF leng<4 THEN RETURN; cp.path _ ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]]; pl _ cp.points.rest; WHILE pl # NIL DO p1, p2, p3: Vector2.VEC; p1 _ [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl _ pl.rest; p2 _ [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl _ pl.rest; p3 _ [pl.first.x, pl.first.y]; pl _ pl.rest; cp.path _ ImagerPath.CurveTo[cp.path, p1, p2, p3]; ENDLOOP; ob _ NEW[CD.ObjectRep_[ bbox: [0, 0, r.x2-r.x1, r.y2-r.y1], layer: CDLayers.AbstractToPaint[layer], class: filledCurveClass, immutable: TRUE, specific: cp ]]; cp.imagerObject _ NEW[Imager.ObjectRep _ [draw: MaskFillProc, clip: ToImagerRectangle[ob.bbox], data: cp]]; offset _ CDBasics.BaseOfRect[r]; }; CreateSpline: PUBLIC PROC [points: LIST OF CD.Position, w: CD.Number, layer: CD.Layer] RETURNS [ob: CD.Object_NIL, offset: CD.Position_[0, 0]] = { r: CD.Rect; leng: INT; pl: LoP; cp: CurveSpecific = NEW[CurveRec]; w2: INT _ MAX[1, (w+1)/2]; [cp.points, r, leng] _ CopyList[points, w2]; IF leng<1 THEN RETURN; cp.w _ w2*2; cp.path _ ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]]; pl _ cp.points.rest; WHILE pl # NIL DO p1, p2, p3: Vector2.VEC; p1 _ [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl _ pl.rest; p2 _ [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl _ pl.rest; p3 _ [pl.first.x, pl.first.y]; pl _ pl.rest; cp.path _ ImagerPath.CurveTo[cp.path, p1, p2, p3]; ENDLOOP; ob _ NEW[CD.ObjectRep_[ bbox: [0, 0, MAX[cp.w, r.x2-r.x1], MAX[cp.w, r.y2-r.y1]], layer: CDLayers.AbstractToPaint[layer], class: splineClass, immutable: TRUE, specific: cp ]]; cp.imagerObject _ NEW[Imager.ObjectRep _ [draw: MaskStrokeProc, clip: ToImagerRectangle[ob.bbox], data: cp]]; offset _ CDBasics.BaseOfRect[r]; }; CreateLine: PUBLIC PROC [points: LIST OF CD.Position, w: CD.Number, layer: CD.Layer] RETURNS [ob: CD.Object_NIL, offset: CD.Position_[0, 0]] = { r: CD.Rect; leng: INT; pl: LoP; cp: CurveSpecific = NEW[CurveRec]; w2: INT _ MAX[1, (w+1)/2]; [cp.points, r, leng] _ CopyList[points, w2]; IF leng<1 THEN RETURN; cp.w _ w2*2; cp.path _ ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]]; pl _ cp.points.rest; WHILE pl # NIL DO p1: Vector2.VEC _ [pl.first.x, pl.first.y]; pl _ pl.rest; cp.path _ ImagerPath.LineTo[cp.path, p1]; ENDLOOP; ob _ NEW[CD.ObjectRep_[ bbox: [0, 0, MAX[cp.w, r.x2-r.x1], MAX[cp.w, r.y2-r.y1]], layer: CDLayers.AbstractToPaint[layer], class: lineClass, immutable: TRUE, specific: cp ]]; cp.imagerObject _ NEW[Imager.ObjectRep _ [draw: MaskStrokeProc, clip: ToImagerRectangle[ob.bbox], data: cp]]; offset _ CDBasics.BaseOfRect[r]; }; HitInsideCurve: PROC [ob: CD.Object, hitRect: CD.Rect] RETURNS [yes: BOOL] = { RETURN [ CDBasics.Intersect[ob.class.interestRect[ob], hitRect] ]; }; MaskFillProc: PROC [self: Imager.Object, context: Imager.Context] ~ { cp: CurveSpecific = NARROW[self.data]; Imager.MaskFillTrajectory[context, cp.path, TRUE]; }; MaskStrokeProc: PROC [self: Imager.Object, context: Imager.Context] ~ { cp: CurveSpecific = NARROW[self.data]; Imager.SetStrokeWidth[context: context, strokeWidth: cp.w]; Imager.SetStrokeEnd[context: context, strokeEnd: square]; Imager.SetStrokeJoint[context: context, strokeJoint: round]; Imager.MaskStrokeTrajectory[context, cp.path, FALSE]; }; enableObjectCache: BOOL _ TRUE; DrawCurve: CD.DrawProc = { CurveInContext: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = { Imager.DrawObject[context: context, object: NARROW[ob.specific, CurveSpecific].imagerObject, interactive: enableObjectCache]; }; pr.drawContext[pr, CurveInContext, ob, trans, ob.layer] }; <> <> <> <> <<};>> <> <<}; >> <> <> <> <> <> <> <<};>> <> <<}; >> Describe: CD.DescribeProc = { RETURN [Rope.Cat[ob.class.description, " ", CDOps.LayerRope[ob.layer]]] }; WriteCurve: CD.InternalWriteProc = { Length: PROC [points: LIST OF CD.Position] RETURNS [n: NAT _ 0] = { FOR l: LIST OF CD.Position _ points, l.rest WHILE l#NIL DO n _ n+1 ENDLOOP }; cp: CurveSpecific = NARROW[ob.specific]; l: NAT _ Length[cp.points]; CDIO.WriteLayer[h, ob.layer]; SELECT ob.class FROM lineClass => {TokenIO.WriteInt[h, 0]; TokenIO.WriteInt[h, cp.w]}; polygonClass => TokenIO.WriteInt[h, 1]; splineClass => {TokenIO.WriteInt[h, 2]; TokenIO.WriteInt[h, cp.w]}; filledCurveClass => TokenIO.WriteInt[h, 3]; ENDCASE => ERROR; TokenIO.WriteInt[h, l]; FOR pl: LoP _ cp.points, pl.rest WHILE pl#NIL DO CDIO.WritePos[h, pl.first]; ENDLOOP; }; ReadCurve: CD.InternalReadProc = { ob: CD.Object _ NIL; kind, w, leng: INT; layer: CD.Layer; points: LoP _ NIL; layer _ CDIO.ReadLayer[h]; SELECT kind _ TokenIO.ReadInt[h] FROM 0, 2 => w _ TokenIO.ReadInt[h]; ENDCASE => NULL; leng _ TokenIO.ReadInt[h]; FOR i: INT IN [1..leng] DO points _ CONS[CDIO.ReadPos[h], points]; ENDLOOP; SELECT kind FROM 0 => ob _ CreateLine[points, w, layer].ob; 1 => ob _ CreatePolygon[points, layer].ob; 2 => ob _ CreateSpline[points, w, layer].ob; 3 => ob _ CreateFilledCurve[points, layer].ob; ENDCASE; RETURN [ob] }; ReadOldPolygon: CD.InternalReadProc = { ob: CD.Object; layer: CD.Layer = CDIO.ReadLayer[h]; leng: INT = TokenIO.ReadInt[h]; points: LIST OF CD.Position _ NIL; FOR i: INT IN [1..leng] DO points _ CONS[CDIO.ReadPos[h], points]; ENDLOOP; ob _ CreatePolygon[points, layer].ob; RETURN [ob] }; ChangeLayer: CD.ChangeLayerProc = { <<--at this point we have to now the class implementation>> <<--to know that the specific field is treated readonly...>> newLayer: CD.Layer _ CDLayers.AbstractToPaint[layer]; IF newLayer#inst.ob.layer AND newLayer#CD.undefLayer THEN { new: CD.Object _ NEW[CD.ObjectRep_inst.ob^]; new.layer _ newLayer; new.properties _ NIL; inst.ob _ new; RETURN [TRUE] }; RETURN [FALSE] }; END.