<> <> <> <> DIRECTORY Vector2, Imager, Real, Rope, ImagerPath, Interpress, ImagerInterpress, RealFns; Nov13Impl: CEDAR PROGRAM IMPORTS Imager, ImagerPath, ImagerInterpress, Real, RealFns, Vector2 ~ BEGIN Context: TYPE ~ Imager.Context; VEC: TYPE ~ Vector2.VEC; ROPE: TYPE ~ Rope.ROPE; PathProc: TYPE ~ Imager.PathProc; constructionWidth: REAL _ 1.0; dotWidth: REAL _ 6.0; dashSize: REAL _ 6.0; curveWidth: REAL _ 3.0; MeasurePath: PROC [path: PathProc] RETURNS [sum: REAL _ 0.0] ~ { Bezier: TYPE ~ ARRAY [0..4) OF VEC; RealPlusOrMinus: TYPE ~ RECORD [value: REAL, error: REAL]; nPts: NAT _ 6; AverageSpeed: PROC [p: Bezier] RETURNS [RealPlusOrMinus] ~ { <> nReal: REAL ~ nPts; min: REAL _ Real.LargestNumber; max: REAL _ 0; delta: ARRAY [0..3) OF VEC ~ [Vector2.Sub[p[1], p[0]], Vector2.Sub[p[2], p[1]], Vector2.Sub[p[3], p[2]]]; <> FOR i: NAT IN [0..nPts] DO t: REAL ~ i/nReal; s: REAL ~ 1.0-t; d01: VEC _ Vector2.Add[Vector2.Mul[delta[0], t], Vector2.Mul[delta[1], s]]; d12: VEC _ Vector2.Add[Vector2.Mul[delta[1], t], Vector2.Mul[delta[2], s]]; d012: VEC _ Vector2.Add[Vector2.Mul[d01, t], Vector2.Mul[d12, s]]; sqr: REAL ~ Vector2.Square[d012]; IF sqr > max THEN max _ sqr; IF sqr < min THEN min _ sqr; ENDLOOP; max _ RealFns.SqRt[max]; min _ RealFns.SqRt[min]; RETURN [[(max+min)*1.5, (max-min)*1.5]] }; sigBits: NAT _ 5; DivideUntilSmooth: PROC [p: Bezier, piece: PROC [p: Bezier, speed: REAL], fullScale: REAL] ~ { a: RealPlusOrMinus _ AverageSpeed[p]; UNTIL Real.FScale[a.error, sigBits] <= fullScale DO Mid: PROC [a,b: VEC] RETURNS [VEC] ~ INLINE {RETURN [[Real.FScale[a.x+b.x, -1], Real.FScale[a.y+b.y, -1]]]}; p01: VEC ~ Mid[p[0],p[1]]; p12: VEC ~ Mid[p[1],p[2]]; p23: VEC ~ Mid[p[2],p[3]]; p012: VEC ~ Mid[p01,p12]; p123: VEC ~ Mid[p12,p23]; p0123: VEC ~ Mid[p012,p123]; DivideUntilSmooth[[p[0], p01, p012, p0123], piece, fullScale]; p _ [p0123, p123, p23, p[3]]; a _ AverageSpeed[p]; ENDLOOP; piece[p, a.value]; }; SubDivide: PROC [b: Bezier, t: REAL, hi: BOOL] RETURNS [Bezier] ~ { s: REAL ~ 1-t; Interpolate: PROC [a, b: VEC] RETURNS [VEC] ~ INLINE { RETURN [[a.x*s+b.x*t, a.y*s+b.y*t]] }; q1 : VEC ~ Interpolate[b[0], b[1]]; q2: VEC ~ Interpolate[b[1], b[2]]; q3: VEC ~ Interpolate[b[2], b[3]]; qp1: VEC ~ Interpolate[q1, q2]; qp2: VEC ~ Interpolate[q2, q3]; q: VEC ~ Interpolate[qp1, qp2]; RETURN [IF hi THEN [q, qp2, q3, b[3]] ELSE [b[0], q1, qp1, q]] }; SubPiece: PROC [b: Bezier, t0, t1: REAL] RETURNS [Bezier] ~ { IF t1 # 1.0 THEN { b _ SubDivide[b, t1, FALSE]; t0 _ t0/t1; t1 _ 1; }; IF t0 # 0.0 THEN b _ SubDivide[b, t0, TRUE]; RETURN [b]; }; lp: VEC _ [0,0]; move: PROC [p0: VEC] ~ { lp _ p0; }; line: PROC [p1: VEC] ~ { sum _ sum + Vector2.Length[Vector2.Sub[p1, lp]]; lp _ p1; }; piece: PROC [p: Bezier, speed: REAL] ~ { sum _ sum + speed; }; curve: PROC [p1, p2, p3: VEC] ~ TRUSTED { p: Bezier ~ [lp, p1, p2, p3]; fullScale: REAL ~ AverageSpeed[p].value; IF fullScale > 0.0 THEN DivideUntilSmooth[p, piece, fullScale]; lp _ p3; }; conic: PROC [p1, p2: VEC, r: REAL] ~ { ImagerPath.ConicToCurves[lp, p1, p2, r, curve] }; arc: PROC [p1, p2: VEC] ~ {ImagerPath.ArcToConics[lp, p1, p2, conic]}; path[moveTo: move, lineTo: line, curveTo: curve, conicTo: conic, arcTo: arc]; }; Bisect: PROC [context: Context, a, b: VEC, t: REAL, wScale: REAL _ 1.0] RETURNS [c: VEC] ~ { path: PathProc ~ {moveTo[a]; lineTo[b]}; pattern: PROC [i: NAT] RETURNS [REAL] ~ {RETURN [dashSize]}; len: REAL ~ MeasurePath[path]; nDashes: NAT _ Real.Round[len/(2*dashSize)+1]; IF nDashes MOD 2 = 1 THEN nDashes _ nDashes + 1; Imager.SetStrokeWidth[context, constructionWidth*wScale]; Imager.SetStrokeEnd[context, round]; IF wScale # 0 THEN Imager.MaskDashedStroke[context, path, 1, pattern, dashSize/2, nDashes*2*dashSize]; Imager.SetStrokeWidth[context, dotWidth]; Imager.MaskVector[context, a, a]; Imager.MaskVector[context, b, b]; c _ b.Sub[a].Mul[t].Add[a]; Imager.MaskVector[context, c, c]; }; BezierSkeleton: PROC [context: Imager.Context, p: ARRAY [0..4) OF VEC, t: REAL] ~ { p01: VEC ~ Bisect[context, p[0], p[1], t, 2]; p12: VEC ~ Bisect[context, p[1], p[2], t, 2]; p23: VEC ~ Bisect[context, p[2], p[3], t, 2]; p012: VEC ~ Bisect[context, p01, p12, t]; p123: VEC ~ Bisect[context, p12, p23, t]; p0123: VEC ~ Bisect[context, p012, p123, t]; }; BezierCurve: PROC [context: Imager.Context, p: ARRAY [0..4) OF VEC] ~ { path: PathProc ~ {moveTo[p[0]]; curveTo[p[1], p[2], p[3]]}; Imager.SetStrokeEnd[context, round]; Imager.MaskStroke[context, path]; }; bezierExample: ARRAY [0..4) OF VEC _ [[155.0,345.0], [159.0,501.0], [394.0,510.0], [453.0,313.0]]; splitRatio: REAL _ 0.5; BezierExample: PROC [context: Imager.Context] ~ { Imager.SetGray[context, 1]; Imager.SetStrokeWidth[context, curveWidth]; BezierCurve[context, bezierExample]; <> <> <> <> BezierSkeleton[context, bezierExample, splitRatio]; }; ConicCurve: PROC [context: Imager.Context, p: ARRAY [0..3) OF VEC, r: REAL] ~ { path: PathProc ~ {moveTo[p[0]]; conicTo[p[1], p[2], r]}; Imager.SetStrokeEnd[context, round]; Imager.MaskStroke[context, path]; }; ConicSkeleton: PROC [context: Imager.Context, p: ARRAY [0..3) OF VEC, r: REAL, w: REAL _ 1] ~ { p0: VEC ~ Bisect[context, p[0], p[1], 0, 2*w]; p2: VEC ~ Bisect[context, p[1], p[2], 1, 2*w]; p02: VEC ~ Bisect[context, p[0], p[2], 0.5, w]; m: VEC ~ Bisect[context, p02, p[1], r, w]; }; conicExample: ARRAY [0..3) OF VEC _ [[155.0,345.0], [225.0,505.0], [453.0,313.0]]; conicRatio: REAL _ 0.75; ConicInstance: PROC [context: Imager.Context, conicRatio: REAL, w: REAL] ~ { Imager.SetGray[context, 1]; Imager.SetStrokeWidth[context, curveWidth]; ConicCurve[context, conicExample, conicRatio]; <> <> <> <> ConicSkeleton[context, conicExample, conicRatio, w]; }; ConicExample: PROC [context: Imager.Context] ~ { ConicInstance[context, 0.25, 0]; ConicInstance[context, 0.5, 0]; ConicInstance[context, 0.75, 1]; }; ArcCurve: PROC [context: Imager.Context, p: ARRAY [0..3) OF VEC] ~ { path: PathProc ~ {moveTo[p[0]]; arcTo[p[1], p[2]]}; Imager.SetStrokeEnd[context, round]; Imager.SetGray[context, 1]; Imager.SetStrokeWidth[context, curveWidth]; Imager.MaskStroke[context, path]; <> <> <> <> [] _ Bisect[context, p[0], p[1], 0]; [] _ Bisect[context, p[1], p[2], 0]; }; ArcExample: PROC [context: Imager.Context] ~ { Imager.TranslateT[context, [0, 72]]; ArcCurve[context, conicExample]; ArcCurve[context, [[155.0,345.0-160], [453.0,313.0-160], [155.0,345.0-160]]]; Imager.TranslateT[context, [0, -72]]; }; pat: ARRAY [0..4) OF REAL _ [18,9,0,9]; FillInstance: PROC [context: Imager.Context, parity: BOOL] ~ { pattern: PROC [i: NAT] RETURNS [REAL] ~ {RETURN [pat[i]]}; path: PathProc ~ {moveTo[[93.0,127.0]]; lineTo[[175.0,331.0]]; lineTo[[247.0,123.0]]; lineTo[[62.0,270.0]]; lineTo[[302.0,288.0]]; lineTo[[93.0,127.0]];}; len: REAL ~ MeasurePath[path]; nDashes: NAT _ Real.Round[len/(2*pat[0])+1]; Imager.SetGray[context, 0.3]; Imager.MaskFill[context, path, parity]; Imager.SetGray[context, 1]; Imager.SetStrokeWidth[context, 3]; Imager.SetStrokeEnd[context, round]; Imager.MaskDashedStroke[context, path, 4, pattern, 0, nDashes*2*pat[0]]; }; FillExample: PROC [context: Imager.Context] ~ { FillInstance[context, FALSE]; Imager.TranslateT[context, [210.0,300.0]]; FillInstance[context, TRUE]; Imager.TranslateT[context, [-210.0,-300.0]]; }; tightPat: ARRAY [0..2) OF REAL _ [0.5, 2.5]; tightWidth: REAL _ 72+36; TightExample: PROC [context: Imager.Context] ~ { pattern: PROC [i: NAT] RETURNS [REAL] ~ {RETURN [tightPat[i]]}; path: PathProc ~ {moveTo[[0,0]]; curveTo[[10, 10], [100, 10], [100, -300]]}; Imager.TranslateT[context, [300, 500]]; Imager.SetStrokeWidth[context, 2]; Imager.SetStrokeEnd[context, round]; Imager.MaskStroke[context, path]; Imager.SetStrokeWidth[context, tightWidth]; Imager.SetStrokeEnd[context, butt]; Imager.MaskDashedStroke[context, path, 2, pattern, 0, 0]; Imager.TranslateT[context, [-300, -500]]; }; MakeIP: PROC ~ { points: REAL _ 0.0254/72; interpress: ImagerInterpress.Ref _ ImagerInterpress.Create["Nov13.interpress"]; <> ImagerInterpress.DoPage[interpress, BezierExample, points]; ImagerInterpress.DoPage[interpress, ConicExample, points]; ImagerInterpress.DoPage[interpress, ArcExample, points]; ImagerInterpress.DoPage[interpress, FillExample, points]; ImagerInterpress.DoPage[interpress, TightExample, points]; ImagerInterpress.Close[interpress]; }; END.