DIRECTORY Cubic2, CubicPaths, CubicPathsExtras, CubicSplines, GGBoundBox, GGLines, GGModelTypes, GGSegment, GGTransform, Imager, ImagerPath, ImagerTransformation; GGSegmentImpl: CEDAR PROGRAM IMPORTS CubicSplines, CubicPaths, CubicPathsExtras, GGBoundBox, GGLines, GGTransform, Imager, ImagerPath, ImagerTransformation EXPORTS GGSegment = BEGIN VEC: TYPE = Imager.VEC; X: NAT = CubicSplines.X; Y: NAT = CubicSplines.Y; BoundBox: TYPE = GGModelTypes.BoundBox; Edge: TYPE = GGModelTypes.Edge; Point: TYPE = GGModelTypes.Point; Segment: TYPE = GGModelTypes.Segment; SegmentObj: TYPE = GGModelTypes.SegmentObj; SegmentClass: TYPE = REF SegmentClassObj; SegmentClassObj: TYPE = GGModelTypes.SegmentClassObj; Vector: TYPE = GGModelTypes.Vector; CopyDataProc: TYPE = GGModelTypes.CopyDataProc; TransformProc: TYPE = GGModelTypes.TransformProc; MaskStrokeProc: TYPE = GGModelTypes.MaskStrokeProc; MaskStrokeTransformProc: TYPE = GGModelTypes.MaskStrokeTransformProc; BuildPathProc: TYPE = GGModelTypes.BuildPathProc; BuildPathTransformProc: TYPE = GGModelTypes.BuildPathTransformProc; ClosestPointProc: TYPE = GGModelTypes.ClosestPointProc; segmentClasses: LIST OF ClassDef; ClassDef: TYPE = REF ClassDefRec; ClassDefRec: TYPE = RECORD[type: ATOM, class: SegmentClass]; globalEdgePool: ARRAY [0..MaxEdges-1] OF Edge; globalEdgePoolIndex: NAT; MaxEdges: NAT = 3; NoOpClosestPointAndTangent: PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, tangent: Vector, success: BOOL] = { success _ FALSE; }; Init: PROC [] = { classDef: ClassDef _ NEW[ClassDefRec _ [type: $Line, class: BuildLineClass[]]]; segmentClasses _ CONS[classDef, segmentClasses]; classDef _ NEW[ClassDefRec _ [type: $Arc, class: BuildArcClass[]]]; segmentClasses _ CONS[classDef, segmentClasses]; classDef _ NEW[ClassDefRec _ [type: $Conic, class: BuildConicClass[]]]; segmentClasses _ CONS[classDef, segmentClasses]; classDef _ NEW[ClassDefRec _ [type: $Bezier, class: BuildBezierClass[]]]; segmentClasses _ CONS[classDef, segmentClasses]; classDef _ NEW[ClassDefRec _ [type: $CubicSpline, class: BuildCubicSplineClass[]]]; segmentClasses _ CONS[classDef, segmentClasses]; FOR i: NAT IN [0..MaxEdges) DO globalEdgePool[i] _ GGLines.CreateEmptyEdge[]; ENDLOOP; globalEdgePoolIndex _ 0; }; NotFound: PUBLIC SIGNAL = CODE; FetchSegmentClass: PUBLIC PROC [type: ATOM] RETURNS [class: SegmentClass] = { FOR l: LIST OF ClassDef _ segmentClasses, l.rest UNTIL l=NIL DO IF l.first.type=type THEN RETURN[l.first.class]; ENDLOOP; SIGNAL NotFound; RETURN[NIL]; }; MakeLine: PUBLIC PROC [p0, p1: Point] RETURNS [seg: Segment] = { lineSegment: LineData _ NEW[LineDataRec]; seg _ NEW[SegmentObj _ [ class: FetchSegmentClass[$Line], looks: NIL, strokeWidth: 1.0, color: Imager.black, lo: p0, hi: p1, boundBox: GGBoundBox.CreateBoundBox[0,0,0,0], -- gets et one line down. data: lineSegment]]; seg.class.boundBox[seg]; }; MakeBezier: PUBLIC PROC [p0, p1, p2, p3: Point] RETURNS [seg: Segment] = { data: BezierData _ NEW[BezierDataRec _ [ b1: [p1[1], p1[2]], b2: [p2[1], p2[2]], path: NEW[CubicPaths.PathRec] ]]; data.path.cubics _ NEW[CubicPaths.PathSequence[1]]; data.path.cubics[0] _ [b0: [p0[1], p0[2]], b1: [p1[1], p1[2]], b2: [p2[1], p2[2]], b3: [p3[1], p3[2]]]; CubicPathsExtras.UpdateBounds[data.path]; seg _ NEW[SegmentObj _ [ class: FetchSegmentClass[$Bezier], looks: NIL, strokeWidth: 1.0, color: Imager.black, lo: p0, hi: p3, boundBox: GGBoundBox.CreateBoundBox[0,0,0,0], -- gets updated one line down. data: data]]; seg.class.boundBox[seg]; }; MakeCubicSpline: PUBLIC PROC [cps: CubicSplines.KnotSequence, type: CubicSplines.SplineType] RETURNS[seg: Segment] = { coeffs: CubicSplines.CoeffsSequence _ CubicSplines.MakeSpline[cps, type]; data: CubicSplineData _ NEW[CubicSplineDataRec _ [ cps: cps, type: type, path: CubicPaths.PathFromCubic[coeffs] ]]; last: NAT _ data.path.cubics.length-1; seg _ NEW[SegmentObj _ [ class: FetchSegmentClass[$CubicSpline], looks: NIL, strokeWidth: 1.0, color: Imager.black, lo: [data.path.cubics[0].b0.x, data.path.cubics[0].b0.y], hi: [data.path.cubics[last].b3.x,data.path.cubics[last].b3.y], boundBox: GGBoundBox.CreateBoundBox[0,0,0,0], -- gets updated one line down. data: data]]; seg.class.boundBox[seg]; }; MakeConic: PUBLIC PROC [p0, p1, p2: Point, r: REAL] RETURNS [seg: Segment] = { data: ConicData _ NEW[ConicDataRec _ [ p1: [p1[1],p1[2]], s: r, path: PathFromConic[p0, p1, p2, r] ]]; seg _ NEW[SegmentObj _ [ class: FetchSegmentClass[$Conic], looks: NIL, strokeWidth: 1.0, color: Imager.black, lo: p0, hi: p2, boundBox: GGBoundBox.CreateBoundBox[0,0,0,0], -- gets updated one line down. data: data]]; seg.class.boundBox[seg]; }; MakeArc: PUBLIC PROC [p0, p1, p2: Point] RETURNS [seg: Segment] = { data: ArcData _ NEW[ArcDataRec _ [ p1: [p1[1],p1[2]], path: PathFromArc[p0, p1, p2] ]]; seg _ NEW[SegmentObj _ [ class: FetchSegmentClass[$Arc], looks: NIL, strokeWidth: 1.0, color: Imager.black, lo: p0, hi: p2, boundBox: GGBoundBox.CreateBoundBox[0,0,0,0], -- gets updated one line down. data: data]]; seg.class.boundBox[seg]; }; CopySegment: PUBLIC PROC [seg: Segment] RETURNS [copy: Segment] = { copyData: REF ANY; copyData _ seg.class.copyData[seg]; copy _ NEW[SegmentObj _ [ class: seg.class, looks: seg.looks, strokeWidth: seg.strokeWidth, color: seg.color, lo: seg.lo, hi: seg.hi, boundBox: GGBoundBox.CopyBoundBox[seg.boundBox], data: copyData]]; }; ReverseSegment: PUBLIC PROC [seg: Segment] = { temp: Point; temp _ seg.lo; seg.lo _ seg.hi; seg.hi _ temp; seg.class.reverse[seg]; }; BuildArcClass: PROC [] RETURNS [class: SegmentClass] = { class _ NEW[SegmentClassObj _ [ type: $Arc, copyData: ArcCopyData, reverse: ArcReverse, transform: ArcTransform, endpointMoved: ArcEndPointMoved, maskStroke: CurveMaskStroke, maskStrokeTransform: ArcMaskStrokeTransform, buildPath: CurveBuildPath, buildPathTransform: ArcBuildPathTransform, closestPoint: CurveClosestPoint, closestPointAndTangent: NoOpClosestPointAndTangent, boundBox: CurveBoundBox ]]; }; ArcData: TYPE = REF ArcDataRec; ArcDataRec: TYPE = RECORD [ p1: VEC, path: CubicPaths.Path]; ArcCopyData: PROC [seg: Segment] RETURNS [REF ANY] = { data: ArcData _ NARROW[seg.data]; new: ArcData _ NEW[ArcDataRec]; new.p1 _ data.p1; new.path _ CubicPathsExtras.CopyPath[data.path]; RETURN[new]; }; ArcReverse: PROC [seg: Segment] = { data: ArcData _ NARROW[seg.data]; CubicPathsExtras.ReversePath[data.path]; }; ArcTransform: PROC [transform: ImagerTransformation.Transformation, seg: Segment] = { data: ArcData _ NARROW[seg.data]; data.p1 _ ImagerTransformation.Transform[transform, data.p1]; CubicPaths.TransformPath[data.path, transform]; CubicPathsExtras.UpdateBounds[data.path]; UpdateBoundBox[data.path.bounds, seg.boundBox]; }; ArcEndPointMoved: PROC [seg: Segment, lo: BOOL, newPoint: Point] = { data: ArcData _ NARROW[seg.data]; p0: Point _ IF lo THEN newPoint ELSE seg.lo; p1: Point _ [data.p1.x, data.p1.y]; p2: Point _ IF lo THEN seg.hi ELSE newPoint; data.path _ PathFromArc[p0, p1, p2]; }; ArcMaskStrokeTransform: PROC [dc: Imager.Context, seg: Segment, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL] = { data: ArcData _ NARROW[seg.data]; p0,p1,p2: VEC; pathProc: ImagerPath.PathProc = {moveTo[p0]; arcTo[p1,p2]}; IF entire THEN { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, TRUE, TRUE, transform]; p1 _ ImagerTransformation.Transform[transform, data.p1]; } ELSE { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, lo, hi, transform]; p1 _ data.p1; }; Imager.MaskStroke[dc, pathProc]; }; ArcBuildPathTransform: PROC [seg: Segment, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL] = { data: ArcData _ NARROW[seg.data]; p0,p1,p2: VEC; IF entire THEN { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, TRUE, TRUE, transform]; p1 _ ImagerTransformation.Transform[transform, data.p1]; } ELSE { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, lo, hi, transform]; p1 _ data.p1; }; arcTo[p1,p2]; }; BuildConicClass: PROC [] RETURNS [class: SegmentClass] = { class _ NEW[SegmentClassObj _ [ type: $Conic, copyData: ConicCopyData, reverse: ConicReverse, transform: ConicTransform, endpointMoved: ConicEndPointMoved, maskStroke: CurveMaskStroke, maskStrokeTransform: ConicMaskStrokeTransform, buildPath: CurveBuildPath, buildPathTransform: ConicBuildPathTransform, closestPoint: CurveClosestPoint, closestPointAndTangent: NoOpClosestPointAndTangent, boundBox: CurveBoundBox ]]; }; ConicData: TYPE = REF ConicDataRec; ConicDataRec: TYPE = RECORD [ p1: VEC, s: REAL, path: CubicPaths.Path]; ConicCopyData: PROC [seg: Segment] RETURNS [REF ANY] = { data: ConicData _ NARROW[seg.data]; new: ConicData _ NEW[ConicDataRec]; new.p1 _ data.p1; new.path _ CubicPathsExtras.CopyPath[data.path]; RETURN[new]; }; ConicReverse: PROC [seg: Segment] = { data: ConicData _ NARROW[seg.data]; CubicPathsExtras.ReversePath[data.path]; }; ConicTransform: PROC [transform: ImagerTransformation.Transformation, seg: Segment] = { data: ConicData _ NARROW[seg.data]; data.p1 _ ImagerTransformation.Transform[transform, data.p1]; CubicPaths.TransformPath[data.path, transform]; CubicPathsExtras.UpdateBounds[data.path]; UpdateBoundBox[data.path.bounds, seg.boundBox]; }; ConicEndPointMoved: PROC [seg: Segment, lo: BOOL, newPoint: Point] = { data: ConicData _ NARROW[seg.data]; p0: Point _ IF lo THEN newPoint ELSE seg.lo; p1: Point _ [data.p1.x, data.p1.y]; p2: Point _ IF lo THEN seg.hi ELSE newPoint; data.path _ PathFromConic[p0, p1, p2, data.s]; }; ConicMaskStrokeTransform: PROC [dc: Imager.Context, seg: Segment, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL] = { data: ConicData _ NARROW[seg.data]; p0,p1,p2: VEC; pathProc: ImagerPath.PathProc = {moveTo[p0]; conicTo[p1,p2,data.s]}; IF entire THEN { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, TRUE, TRUE, transform]; p1 _ ImagerTransformation.Transform[transform, data.p1]; } ELSE { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, lo, hi, transform]; p1 _ data.p1; }; Imager.MaskStroke[dc, pathProc]; }; ConicBuildPathTransform: PROC [seg: Segment, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL] = { data: ConicData _ NARROW[seg.data]; p0,p1,p2: VEC; IF entire THEN { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, TRUE, TRUE, transform]; p1 _ ImagerTransformation.Transform[transform, data.p1]; } ELSE { [p0,p2] _ TransformEndPoints[seg.lo, seg.hi, lo, hi, transform]; p1 _ data.p1; }; conicTo[p1,p2,data.s]; }; TransformEndPoints: PROC [loPt, hiPt: Point, lo, hi: BOOL, transform: ImagerTransformation.Transformation] RETURNS [newLo, newHi: VEC] ~ { IF lo THEN newLo _ ImagerTransformation.Transform[transform, [loPt[1],loPt[2]]] ELSE newLo _ [loPt[1],loPt[2]]; IF hi THEN newHi _ ImagerTransformation.Transform[transform, [hiPt[1],hiPt[2]]] ELSE newHi _ [hiPt[1],hiPt[2]]; }; BuildBezierClass: PROC [] RETURNS [class: SegmentClass] = { class _ NEW[SegmentClassObj _ [ type: $Bezier, copyData: BZCopyData, reverse: BZReverse, transform: BZTransform, endpointMoved: BZEndPointMoved, maskStroke: CurveMaskStroke, maskStrokeTransform: CubicMaskStrokeTransform, buildPath: CurveBuildPath, buildPathTransform: CubicBuildPathTransform, closestPoint: CurveClosestPoint, closestPointAndTangent: NoOpClosestPointAndTangent, boundBox: CurveBoundBox ]]; }; BezierData: TYPE = REF BezierDataRec; BezierDataRec: TYPE = RECORD [ b1, b2: VEC, path: CubicPaths.Path]; BZCopyData: PROC [seg: Segment] RETURNS [REF ANY] = { data: BezierData _ NARROW[seg.data]; new: BezierData _ NEW[BezierDataRec]; new.b1 _ data.b1; new.b2 _ data.b2; new.path _ CubicPathsExtras.CopyPath[data.path]; RETURN[new]; }; BZReverse: PROC [seg: Segment] = { data: BezierData _ NARROW[seg.data]; temp: VEC _ data.b1; data.b1 _ data.b2; data.b2 _ temp; CubicPathsExtras.ReversePath[data.path]; }; BZTransform: PROC [transform: ImagerTransformation.Transformation, seg: Segment] = { data: BezierData _ NARROW[seg.data]; data.b1 _ ImagerTransformation.Transform[transform, data.b1]; data.b2 _ ImagerTransformation.Transform[transform, data.b2]; CubicPaths.TransformPath[data.path, transform]; CubicPathsExtras.UpdateBounds[data.path]; UpdateBoundBox[data.path.bounds, seg.boundBox]; }; BZEndPointMoved: PROC [seg: Segment, lo: BOOL, newPoint: Point] = { data: BezierData _ NARROW[seg.data]; IF lo THEN data.path.cubics[0].b0 _ [newPoint[1], newPoint[2]] ELSE data.path.cubics[0].b3 _ [newPoint[1], newPoint[2]]; CubicPathsExtras.UpdateBounds[data.path]; UpdateBoundBox[data.path.bounds, seg.boundBox]; }; BuildCubicSplineClass: PROC [] RETURNS [class: SegmentClass] = { class _ NEW[SegmentClassObj _ [ type: $CubicSpline, copyData: CSCopyData, reverse: CSReverse, transform: CSTransform, endpointMoved: CSEndPointMoved, maskStroke: CurveMaskStroke, maskStrokeTransform: CubicMaskStrokeTransform, buildPath: CurveBuildPath, buildPathTransform: CubicBuildPathTransform, closestPoint: CurveClosestPoint, closestPointAndTangent: NoOpClosestPointAndTangent, boundBox: CurveBoundBox ]]; }; CubicSplineData: TYPE = REF CubicSplineDataRec; CubicSplineDataRec: TYPE = RECORD [ cps: CubicSplines.KnotSequence, type: CubicSplines.SplineType, path: CubicPaths.Path]; CSCopyData: PROC [seg: Segment] RETURNS [REF ANY] = { data: CubicSplineData _ NARROW[seg.data]; new: CubicSplineData _ NEW[CubicSplineDataRec]; new.cps _ NEW[CubicSplines.KnotSequenceRec[data.cps.length]]; FOR i: NAT IN [0..new.cps.length) DO new.cps[i] _ data.cps[i]; ENDLOOP; new.type _ data.type; new.path _ CubicPathsExtras.CopyPath[data.path]; RETURN[new]; }; CSReverse: PROC [seg: Segment] = { data: CubicSplineData _ NARROW[seg.data]; temp: CubicSplines.FPCoords; last: NAT _ data.cps.length-1; FOR i: NAT IN [0..data.cps.length/2) DO temp _ data.cps[i]; data.cps[i] _ data.cps[last-i]; data.cps[last-i] _ temp; ENDLOOP; CubicPathsExtras.ReversePath[data.path]; }; CSTransform: PROC [transform: ImagerTransformation.Transformation, seg: Segment] = { data: CubicSplineData _ NARROW[seg.data]; FOR i: NAT IN [0..data.cps.length) DO vec: VEC _ [data.cps[i][X], data.cps[i][Y]]; vec _ ImagerTransformation.Transform[transform, vec]; data.cps[i][X] _ vec.x; data.cps[i][Y] _ vec.y; ENDLOOP; CubicPaths.TransformPath[data.path, transform]; CubicPathsExtras.UpdateBounds[data.path]; UpdateBoundBox[data.path.bounds, seg.boundBox]; }; CSEndPointMoved: PROC [seg: Segment, lo: BOOL, newPoint: Point] = { data: CubicSplineData _ NARROW[seg.data]; IF lo THEN { data.cps[0] _ newPoint; data.path.cubics[0].b0.x _ newPoint[1]; data.path.cubics[0].b0.y _ newPoint[2]; } ELSE { data.cps[data.cps.length-1] _ newPoint; data.path.cubics[data.path.cubics.length-1].b3 _ [newPoint[1], newPoint[2]]; }; CubicPathsExtras.UpdateBounds[data.path]; UpdateBoundBox[data.path.bounds, seg.boundBox]; }; CurveMaskStroke: PROC [dc: Imager.Context, seg: Segment] = { path: CubicPaths.Path _ PathFromSeg[seg]; pathProc: ImagerPath.PathProc = {CubicPaths.EnumeratePath[path, moveTo, curveTo]}; Imager.MaskStroke[dc, pathProc]; }; CurveBuildPath: PROC [seg: Segment, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc] = { path: CubicPaths.Path _ PathFromSeg[seg]; moveTo: ImagerPath.MoveToProc _ {}; CubicPaths.EnumeratePath[path, moveTo, curveTo]; }; CubicMaskStrokeTransform: PROC [dc: Imager.Context, seg: Segment, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL] = { path: CubicPaths.Path _ PathFromSeg[seg]; pathProc: ImagerPath.PathProc = {CubicPaths.EnumeratePath[path, moveTo, curveTo]}; IF entire THEN { CubicPaths.TransformPath[path, transform]; Imager.MaskStroke[dc, pathProc]; CubicPaths.TransformPath[path, ImagerTransformation.Invert[transform]]; } ELSE { oldLo, oldHi: VEC; [oldLo, oldHi] _ TransformPathEnds[path, transform, lo, hi]; Imager.MaskStroke[dc, pathProc]; RestorePathEnds[path, oldLo, oldHi]; }; }; CubicBuildPathTransform: PROC [seg: Segment, lineTo: ImagerPath.LineToProc, curveTo: ImagerPath.CurveToProc, conicTo: ImagerPath.ConicToProc, arcTo: ImagerPath.ArcToProc, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL] = { path: CubicPaths.Path _ PathFromSeg[seg]; moveTo: ImagerPath.MoveToProc _ {}; IF entire THEN { CubicPaths.TransformPath[path, transform]; CubicPaths.EnumeratePath[path, moveTo, curveTo]; CubicPaths.TransformPath[path, ImagerTransformation.Invert[transform]]; } ELSE { oldLo, oldHi: VEC; [oldLo, oldHi] _ TransformPathEnds[path, transform, lo, hi]; CubicPaths.EnumeratePath[path, moveTo, curveTo]; RestorePathEnds[path, oldLo, oldHi]; }; }; TransformPathEnds: PROC [path: CubicPaths.Path, transform: ImagerTransformation.Transformation, lo, hi: BOOL] RETURNS [oldLo, oldHi: VEC] ~ { last: NAT _ path.cubics.length-1; oldLo _ path.cubics[0].b0; oldHi _ path.cubics[last].b3; IF lo THEN path.cubics[0].b0 _ ImagerTransformation.Transform[transform, oldLo]; IF hi THEN path.cubics[last].b3 _ ImagerTransformation.Transform[transform, oldHi]; }; RestorePathEnds: PROC [path: CubicPaths.Path, oldLo, oldHi: VEC] ~ { path.cubics[0].b0 _ oldLo; path.cubics[path.cubics.length-1].b3 _ oldHi; }; CurveClosestPoint: PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, success: BOOL] = { path: CubicPaths.Path _ PathFromSeg[seg]; pt: VEC _ CubicPathsExtras.ClosestPoint[[testPoint[1],testPoint[2]], path]; RETURN[[pt.x, pt.y], TRUE]; }; CurveBoundBox: PROC [seg: Segment] = { path: CubicPaths.Path _ PathFromSeg[seg]; UpdateBoundBox[path.bounds, seg.boundBox]; }; UpdateBoundBox: PROC[r: Imager.Rectangle, box: BoundBox] = { box^ _ [loX: r.x, loY: r.y, hiX: r.x+r.w, hiY: r.y+r.h]; }; PathFromSeg: PROC [seg: Segment] RETURNS [path: CubicPaths.Path] ~ { WITH seg.data SELECT FROM type: BezierData => path _ type.path; type: ConicData => path _ type.path; type: ArcData => path _ type.path; type: CubicSplineData => path _ type.path; ENDCASE => ERROR; RETURN[path]; }; BezierRef: TYPE = REF Cubic2.Bezier; PathFromConic: PROC [p0, p1, p2: Point, r: REAL] RETURNS [path: CubicPaths.Path] ~ { bList: LIST OF BezierRef; joint: VEC _ [p0[1],p0[2]]; bproc: ImagerPath.CurveToProc = { new: BezierRef _ NEW[Cubic2.Bezier _ [joint, p1, p2, p3]]; bList _ CONS[new, bList]; joint _ p3; }; ImagerPath.ConicToCurves[[p0[1],p0[2]], [p1[1],p1[2]], [p2[1],p2[2]], r, bproc]; path _ PathFromList[bList]; RETURN[path]; }; PathFromArc: PROC [p0, p1, p2: Point] RETURNS [path: CubicPaths.Path] ~ { Conic: TYPE = REF ConicRec; ConicRec: TYPE = RECORD[p1, p2: VEC, r: REAL]; joint: VEC _ [p0[1],p0[2]]; rList, list: LIST OF Conic; bList: LIST OF BezierRef; proc: ImagerPath.ConicToProc = { new: Conic _ NEW[ConicRec _ [p1, p2, r]]; rList _ CONS[new,rList]; }; bproc: ImagerPath.CurveToProc = { new: BezierRef _ NEW[Cubic2.Bezier _ [joint, p1, p2, p3]]; bList _ CONS[new, bList]; joint _ p3; }; ImagerPath.ArcToConics[[p0[1],p0[2]], [p1[1],p1[2]], [p2[1],p2[2]], proc]; FOR l: LIST OF Conic _ rList, l.rest UNTIL l=NIL DO list _ CONS[l.first, list]; ENDLOOP; FOR l: LIST OF Conic _ list, l.rest UNTIL l=NIL DO ImagerPath.ConicToCurves[joint, l.first.p1, l.first.p2, l.first.r, bproc]; joint _ l.first.p2; ENDLOOP; path _ PathFromList[bList]; RETURN[path]; }; PathFromList: PROC [list: LIST OF BezierRef] RETURNS [CubicPaths.Path] ~ { count: NAT _ 0; path: CubicPaths.Path _ NEW[CubicPaths.PathRec]; FOR l: LIST OF BezierRef _ list, l.rest UNTIL l=NIL DO count _ count+1; ENDLOOP; path.cubics _ NEW[CubicPaths.PathSequence[count]]; FOR l: LIST OF BezierRef _ list, l.rest UNTIL l=NIL DO count _ count-1; --count starts at number of entries, not last entry path.cubics[count] _ l.first^; ENDLOOP; CubicPathsExtras.UpdateBounds[path]; RETURN[path]; }; LineData: TYPE = REF LineDataRec; LineDataRec: TYPE = RECORD []; --doesn't need any data BuildLineClass: PROC [] RETURNS [lineClass: SegmentClass] = { lineClass _ NEW[SegmentClassObj _ [ type: $Line, copyData: LineCopyData, reverse: LineReverse, transform: LineTransform, endpointMoved: LineEndPointMoved, maskStroke: LineMaskStroke, maskStrokeTransform: LineMaskStrokeTransform, buildPath: LineBuildPath, buildPathTransform: LineBuildPathTransform, closestPoint: LineClosestPoint, closestPointAndTangent: LineClosestPointAndTangent, boundBox: LineBoundBox ]]; }; LineCopyData: PROC [seg: Segment] RETURNS [data: REF ANY] = { lineSegment: LineData _ NARROW[seg.data]; data _ NEW[LineDataRec]; }; LineReverse: PROC [seg: Segment] = { }; LineTransform: PROC [transform: ImagerTransformation.Transformation, seg: Segment] = { }; LineEndPointMoved: PROC [seg: Segment, lo: BOOL, newPoint: Point] = { }; LineMaskStroke: PROC [dc: Imager.Context, seg: Segment] = { Imager.MaskVector[dc, [seg.lo[1], seg.lo[2]], [seg.hi[1], seg.hi[2]]]; }; LineMaskStrokeTransform: PROC [dc: Imager.Context, seg: Segment, transform: ImagerTransformation.Transformation, entire, lo, hi: BOOL] = { loPoint, hiPoint: Point; loPoint _ IF lo OR entire THEN GGTransform.Transform[transform, seg.lo] ELSE [seg.lo[1], seg.lo[2]]; hiPoint _ IF hi OR entire THEN GGTransform.Transform[transform, seg.hi] ELSE [seg.hi[1], seg.hi[2]]; Imager.MaskVector[dc, [loPoint[1], loPoint[2]], [hiPoint[1], hiPoint[2]]]; }; LineBuildPath: BuildPathProc = { lineTo[ [seg.hi[1], seg.hi[2]] ]; }; LineBuildPathTransform: BuildPathTransformProc = { hiPoint: Point; hiPoint _ IF hi OR entire THEN GGTransform.Transform[transform, seg.hi] ELSE [seg.hi[1], seg.hi[2]]; lineTo[ [hiPoint[1], hiPoint[2]] ]; }; LineClosestPoint: PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, success: BOOL] = { edge: Edge; edge _ GetEdgeFromPool[]; GGLines.FillEdge[seg.lo, seg.hi, edge]; point _ GGLines.NearestPointOnEdge[testPoint, edge]; ReturnEdgeToPool[edge]; success _ TRUE; }; LineClosestPointAndTangent: PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, tangent: Vector, success: BOOL] = { edge: Edge; edge _ GetEdgeFromPool[]; GGLines.FillEdge[seg.lo, seg.hi, edge]; point _ GGLines.NearestPointOnEdge[testPoint, edge]; ReturnEdgeToPool[edge]; tangent _ GGLines.DirectionOfLine[edge.line]; success _ TRUE; }; LineBoundBox: PROC [seg: Segment] = { loX, loY, hiX, hiY: REAL; loX _ MIN[seg.lo[1], seg.hi[1]]; hiX _ MAX[seg.lo[1], seg.hi[1]]; loY _ MIN[seg.lo[2], seg.hi[2]]; hiY _ MAX[seg.lo[2], seg.hi[2]]; seg.boundBox^ _ [loX, loY, hiX, hiY]; }; GetEdgeFromPool: PROC [] RETURNS [edge: Edge] = { IF globalEdgePoolIndex = MaxEdges THEN ERROR; edge _ globalEdgePool[globalEdgePoolIndex]; globalEdgePoolIndex _ globalEdgePoolIndex + 1; }; ReturnEdgeToPool: PROC [edge: Edge] = { IF globalEdgePoolIndex = 0 THEN ERROR; globalEdgePoolIndex _ globalEdgePoolIndex - 1; globalEdgePool[globalEdgePoolIndex] _ edge; }; Init[]; END. @GGSegmentImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by Bier on September 19, 1985 10:35:53 pm PDT Contents: Procedures which implement the Gargoyle segment classes. Stone, August 9, 1985 2:42:18 pm PDT The segment data assumes that the endpoints are in the segment record (lo and hi). Making Segments (much like the Imager interface) Create a Bezier segment which passed thru p0 and p3, guided by p1 and p2. Makes a segment of any of the types defined in CubicSplines. Expected to be used principally for interpolating splines and sequences of Bezier cubics Let m be the midpoint of [p0, p2]. Let p be the point on [m, p1] such that Length[m, p]/Length[m, p1] = r. The curve starts at p0, passes through p, and ends at p2. It is a line if r=0; an ellipse if 0˜>Jšœ,žœ ˜LJšœ ˜ —J˜J˜—šŸ œž œžœžœ˜NLšœ"™"LšœG™GLšœ9™9LšœX™XLšœ2™2šœžœ˜&J˜Jšœ"˜"J˜—šœžœ˜J˜!Jšœžœ˜ Jšœ˜J˜Jšœ˜Jšœ. ˜LJšœ ˜ —J˜J˜—šŸœž œžœ˜CJ™%šœžœ˜"J˜Jšœ˜J˜—šœžœ˜J˜Jšœžœ˜ Jšœ˜J˜Jšœ˜Jšœ. ˜LJšœ ˜ —J˜J˜J˜—J™šŸ œž œžœ˜DJšœ žœžœ˜Jšœ#˜#šœžœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜0Jšœ˜J™—J˜J˜—šŸœžœžœ˜/J˜ J˜J˜J˜J˜J˜J˜—J™ J˜šŸ œžœžœ˜8šœžœ˜J˜ J˜J˜J˜J˜ Jšœ˜Jšœ,˜,Jšœ˜Jšœ*˜*J˜ J˜3J˜J˜—˜J˜——Jšœ žœžœ ˜šœ žœžœ˜Jšœžœ˜Jšœ˜—J˜š Ÿ œžœžœžœžœ˜6J™JJšœžœ ˜!Jšœžœ ˜J˜J˜0Jšžœ˜ J˜—šŸ œžœ˜#J™TJšœžœ ˜!J˜(J˜J˜—šŸ œžœC˜UJ™ƒJšœžœ ˜!Jšœ=˜=Jšœ/˜/Jšœ)˜)Jšœ/˜/J˜J˜—šŸœžœžœ˜DJšœžœ ˜!Jšœ žœžœ žœ˜,Jšœ#˜#Jšœ žœžœžœ ˜,Jšœ$˜$Jšœ˜—J˜šŸœžœdžœ˜‰Jšœ³™³Jšœžœ ˜!Jšœ žœ˜L˜;šžœžœ˜Jšœ-žœžœ ˜DJšœ8˜8J˜—šžœ˜Jšœ@˜@Jšœ ˜ J˜—J˜ J˜J™—šŸœžœΞžœ˜ςJšœ»™»Jšœžœ ˜!Jšœ žœ˜šžœžœ˜Jšœ-žœžœ ˜DJšœ8˜8J˜—šžœ˜Jšœ@˜@Jšœ ˜ L˜—L˜ J˜J™—šŸœžœžœ˜:šœžœ˜J˜ J˜J˜J˜J˜"Jšœ˜Jšœ.˜.Jšœ˜Jšœ,˜,J˜ J˜3J˜J˜—˜J˜——Jšœ žœžœ˜#šœžœžœ˜Jšœžœ˜Jšœž˜Jšœ˜—J˜š Ÿ œžœžœžœžœ˜8J™JJšœžœ ˜#Jšœžœ˜#J˜J˜0Jšžœ˜ J˜—šŸ œžœ˜%J™TJšœžœ ˜#J˜(J˜J˜—šŸœžœC˜WJ™ƒJšœžœ ˜#Jšœ=˜=Jšœ/˜/Jšœ)˜)Jšœ/˜/J˜J˜—šŸœžœžœ˜FJšœžœ ˜#Jšœ žœžœ žœ˜,Jšœ#˜#Jšœ žœžœžœ ˜,Jšœ.˜.Jšœ˜—J˜šŸœžœdžœ˜‹Jšœ³™³Jšœžœ ˜#Jšœ žœ˜L˜Dšžœžœ˜Jšœ-žœžœ ˜DJšœ8˜8J˜—šžœ˜Jšœ@˜@J˜ J˜—L˜ J˜J™—šŸœžœΞžœ˜τJšœ»™»Jšœžœ ˜#Jšœ žœ˜šžœžœ˜Jšœ-žœžœ ˜DJšœ8˜8J˜—šžœ˜Jšœ@˜@J˜ L˜—L˜J˜J™—š Ÿœžœžœ2žœžœ˜ŠLšžœžœE˜OLšžœ˜LšžœžœE˜OLšžœ˜L˜L˜—šŸœžœžœ˜;šœžœ˜J˜J˜J˜J˜J˜Jšœ˜Jšœ.˜.Jšœ˜Jšœ,˜,J˜ J˜3J˜J˜—˜J˜——Jšœ žœžœ˜%šœžœžœ˜Jšœžœ˜ Jšœ˜J˜—š Ÿ œžœžœžœžœ˜5J™JJšœžœ ˜$Jšœžœ˜%J˜$J˜0Jšžœ˜ J˜—šŸ œžœ˜"J™TJšœžœ ˜$Lšœžœ ˜L˜L˜J˜(J˜J™—šŸ œžœC˜TJ™ƒJšœžœ ˜$Jšœ=˜=Jšœ=˜=Jšœ/˜/Jšœ)˜)Jšœ/˜/J˜J˜—šŸœžœžœ˜CJšœžœ ˜$Jšžœžœ4˜>Jšžœ5˜9Jšœ)˜)Jšœ/˜/J˜—J˜J˜šŸœžœžœ˜@šœžœ˜J˜J˜J˜J˜J˜Jšœ˜Jšœ.˜.Jšœ˜Jšœ,˜,J˜ J˜3J˜J˜—˜J˜——J˜Jšœžœžœ˜/šœžœžœ˜#Jšœ˜Jšœ˜Jšœ˜J˜—š Ÿ œžœžœžœžœ˜5J™JJšœžœ ˜)Jšœžœ˜/Jšœ žœ0˜=šžœžœžœž˜$J˜Jšžœ˜—J˜J˜0Jšžœ˜ J˜—šŸ œžœ˜"J™TJšœžœ ˜)J˜Jšœžœ˜šžœžœžœž˜'J˜J˜J˜Jšžœ˜—J˜(J˜J™—šŸ œžœC˜TJ™ƒJšœžœ ˜)šžœžœžœž˜%Jšœžœ$˜,Jšœ5˜5Jšœ˜Jšœ˜Jšžœ˜—Jšœ/˜/Jšœ)˜)Jšœ/˜/J˜J˜—šŸœžœžœ˜CJšœžœ ˜)šžœžœ˜ Jšœ˜J˜'J˜'J˜—šžœ˜Jšœ'˜'JšœL˜LJ˜—Jšœ)˜)Jšœ/˜/J˜—J˜šŸœžœ'˜Jšœžœ ˜)Jšœžœ˜J˜J˜—šŸ œžœ˜%J™!J˜J˜—šŸ œžœD˜WJ™!J˜J˜—šŸœžœžœ˜FJ™!J˜J˜—šŸœžœ(˜