-- TACalligImpl.mesa, for drawing thick lines for TiogaArtwork. -- liberally borrowed from Callig.mesa -- Rick Beach, June 30, 1982 10:25 pm -- Maureen Stone April 24, 1983 5:37 pm DIRECTORY Complex, Cubic, Graphics, GraphicsBasic, JaMFnsDefs, TJaMGraphics, PolygonPen, Real, RealFns, Rope, SirPress, Vector, CGPath, TACallig; TACalligImpl: PROGRAM IMPORTS Complex, Cubic, Graphics, JaMFnsDefs, TJaMGraphics, PolygonPen, Real, RealFns, Rope, SirPress, CGPath, Vector EXPORTS TACallig= { ROPE: TYPE = Rope.ROPE; Vec: TYPE = GraphicsBasic.Vec; pi: REAL = 3.14159625; RoundPenCacheRef: TYPE = REF RoundPenCacheRec; RoundPenCacheRec: TYPE = RECORD [ next: RoundPenCacheRef, numCorners: CARDINAL, multiplier: Vec, record: PolygonPen.Pen]; pens: RoundPenCacheRef _ NIL; curLoc: Vec; pen: PolygonPen.Pen; rectangularPen: BOOLEAN _ FALSE; shadowLoc: Vec; shadowPen: PolygonPen.Pen; p: SirPress.PressHandle _ NIL; press: BOOLEAN _ FALSE; path: Graphics.Path _ Graphics.NewPath[]; penPath: Graphics.Path _ Graphics.NewPath[]; PaintPath: PROC [context: Graphics.Context] = {Graphics.DrawArea[context,path]}; PaintPenPath: PROC [context: Graphics.Context] = {Graphics.DrawArea[context,penPath]}; Mica: PROCEDURE[pt:REAL] RETURNS [LONG INTEGER] = INLINE { RETURN[Real.RoundLI[pt*2540.0/72.0]]}; Transform: PROCEDURE[u: Vec] RETURNS[v: Vec] = { paint: PROC[context: Graphics.Context] = { [v.x, v.y] _ Graphics.UserToWorld[context, u.x, u.y]}; TJaMGraphics.Painter[paint]; }; JBeginObject: PROC = { IF press THEN SirPress.StartOutline[p] ELSE Graphics.FlushPath[path]; }; JEndObject: PROC = { IF press THEN SirPress.EndOutline[p] ELSE {TJaMGraphics.Painter[PaintPath]; Graphics.FlushPath[path]}; }; JMoveTo: PROC = {t: Vec _ PopVec[]; Graphics.MoveTo[path, t.x, t.y]}; JLineTo: PROC = {t: Vec _ PopVec[]; Graphics.LineTo[path, t.x, t.y]}; JCurveTo: PROC = { b3:Vec _ PopVec[]; b2:Vec _ PopVec[]; b1: Vec _ PopVec[]; Graphics.CurveTo[path,b1.x,b1.y, b2.x,b2.y, b3.x,b3.y]}; JDrawPath: PROC = { width: REAL _ JaMFnsDefs.PopReal[]; IF width <= 0 AND ~press THEN SimplePath[] ELSE { pen _ RoundPen[width]; JOutlinePath[]}; }; SimplePath: PROC = {TJaMGraphics.Painter[PaintPath]}; JOutlinePath: PROC = { moveTo: SAFE PROC[z0: Vec] = CHECKED {curLoc _ z0}; lineTo: SAFE PROC[z1: Vec] = TRUSTED { IF rectangularPen THEN {OPEN Vector; dv: Vec _ Unit[Sub[z1,curLoc]]; dh: Vec _ [-pen[0].y*dv.y,pen[0].y*dv.x]; --normal * height dw: Vec _ [pen[0].x*dv.x,pen[0].x*dv.y]; --direction * width v: Vec _ curLoc; IF dv=[0,0] THEN PolygonPen.Dot[pen, z1, PenMoveTo, PenLineTo, PenCurveTo] ELSE { PenMoveTo[ Add[Sub[v,dw],dh] ]; PenLineTo[ Sub[Sub[v,dw],dh] ]; PenLineTo[ Sub[Add[z1,dw],dh] ]; PenLineTo[ Add[Add[z1,dw],dh] ]; PenLineTo[ Add[Sub[v,dw],dh] ]; }; } ELSE PolygonPen.Line[pen, curLoc, z1, PenMoveTo, PenLineTo, PenCurveTo]; curLoc _ z1}; curveTo: SAFE PROC[b1,b2,b3: Vec] = TRUSTED { PolygonPen.Stroke[pen, [curLoc, b1, b2, b3], PenMoveTo, PenLineTo, PenCurveTo]; curLoc _ b3}; IF press THEN SirPress.StartOutline[p]; CGPath.Generate[path,moveTo,lineTo,curveTo]; IF press THEN SirPress.EndOutline[p] ELSE TJaMGraphics.Painter[PaintPenPath]; Graphics.FlushPath[path]; Graphics.FlushPath[penPath]; }; PenMoveTo: PolygonPen.MoveToProc = { IF press THEN { tz0: Vec = Transform[z0]; SirPress.EndOutline[p]; SirPress.StartOutline[p]; SirPress.PutMoveTo[p,Mica[tz0.x],Mica[tz0.y]]} ELSE { TJaMGraphics.Painter[PaintPenPath]; Graphics.MoveTo[penPath,z0.x,z0.y]}; curLoc _ z0; }; PenLineTo: PolygonPen.LineToProc = { IF press THEN {tz1: Vec = Transform[z1]; SirPress.PutDrawTo[p,Mica[tz1.x],Mica[tz1.y]]} ELSE Graphics.LineTo[penPath,z1.x,z1.y]; curLoc _ z1; }; PenCurveTo: PolygonPen.CurveToProc = { IF press THEN { tcurLoc: Vec = Transform[curLoc]; tz1: Vec = Transform[z1]; tz2: Vec = Transform[z2]; tz3: Vec = Transform[z3]; c: Cubic.Coeffs _ Cubic.BezierToCoeffs[[tcurLoc,tz1,tz2,tz3]]; SirPress.PutCubic[p, Mica[c.c1.x], Mica[c.c1.y], Mica[c.c2.x], Mica[c.c2.y], Mica[c.c3.x],Mica[c.c3.y]]} ELSE Graphics.CurveTo[penPath,z1.x,z1.y,z2.x,z2.y,z3.x,z3.y]; curLoc _ z3; }; JShadowPen: PROC = { shadowPen _ pen}; JShadowPath: PROC = { moveTo: SAFE PROC[z0: Vec] = CHECKED {curLoc _ z0}; lineTo: SAFE PROC[z1: Vec] = TRUSTED { PolygonPen.Line[pen, curLoc, z1, ShadowMoveTo, ShadowLineTo, ShadowCurveTo]; curLoc _ z1}; curveTo: SAFE PROC[b1,b2,b3: Vec] = TRUSTED { PolygonPen.Stroke[pen, [curLoc, b1, b2, b3], ShadowMoveTo, ShadowLineTo, ShadowCurveTo]; curLoc _ b3}; IF press THEN SirPress.StartOutline[p]; CGPath.Generate[path,moveTo,lineTo,curveTo]; IF press THEN SirPress.EndOutline[p] ELSE TJaMGraphics.Painter[PaintPenPath]; Graphics.FlushPath[path]; Graphics.FlushPath[penPath]; }; ShadowMoveTo: PolygonPen.MoveToProc = { shadowLoc _ z0}; ShadowLineTo: PolygonPen.LineToProc = { PolygonPen.Line[shadowPen, shadowLoc, z1, PenMoveTo, PenLineTo, PenCurveTo]; shadowLoc _ z1}; ShadowCurveTo: PolygonPen.CurveToProc = { PolygonPen.Stroke[shadowPen, [shadowLoc, z1, z2, z3], PenMoveTo, PenLineTo, PenCurveTo]; shadowLoc _ z3}; JDrawArea: PROC = { IF press THEN { moveTo: SAFE PROC[z0: Vec] = TRUSTED { tz0: Vec = Transform[z0]; SirPress.PutMoveTo[p, Mica[tz0.x], Mica[tz0.y]]; curLoc _ z0}; lineTo: SAFE PROC[z1: Vec] = TRUSTED { tz1: Vec = Transform[z1]; SirPress.PutDrawTo[p, Mica[tz1.x], Mica[tz1.y]]; curLoc _ z1}; curveTo: SAFE PROC[b1,b2,b3: Vec] = TRUSTED { tcurLoc: Vec = Transform[curLoc]; tb1: Vec = Transform[b1]; tb2: Vec = Transform[b2]; tb3: Vec = Transform[b3]; c: Cubic.Coeffs _ Cubic.BezierToCoeffs[[tcurLoc, tb1, tb2, tb3]]; SirPress.PutCubic[p, Mica[c.c1.x], Mica[c.c1.y], Mica[c.c2.x], Mica[c.c2.y], Mica[c.c3.x], Mica[c.c3.y]]; curLoc _ b3}; SirPress.StartOutline[p]; CGPath.Generate[path,moveTo,lineTo,curveTo]; SirPress.EndOutline[p]; } ELSE { TJaMGraphics.Painter[PaintPath]; Graphics.FlushPath[path]; }; }; PopVec: PROCEDURE RETURNS [v:Vec] = { v.y _ JaMFnsDefs.GetReal[]; v.x _ JaMFnsDefs.GetReal[]}; PopText: PROCEDURE RETURNS [t: REF TEXT] = { t_NEW[TEXT[128]]; JaMFnsDefs.PopString[LOOPHOLE[t]]; }; UseThisPressHandle: PUBLIC PROCEDURE[pressHandle: SirPress.PressHandle] = { p _ pressHandle; press _ p#NIL}; ForgetThePressHandle: PUBLIC PROCEDURE = { p _ NIL; press _ FALSE}; JOpenPress: PROC = { name: ROPE _ Rope.FromRefText[PopText[]]; p _ SirPress.NewPressHandle[FixFileName[name, ".Press"]]; press _ p#NIL}; FixFileName: PROC [oldname, extension: ROPE] RETURNS [newname:ROPE] = { dotPosition: INTEGER _ Rope.Find[oldname, "."]; IF dotPosition < 0 THEN newname _ Rope.Cat[oldname, extension] ELSE newname _ Rope.Cat[Rope.Substr[oldname, 0, dotPosition], extension]; }; JClosePress: PROC = { IF press THEN SirPress.ClosePress[p]; p _ NIL; press _ FALSE}; JNewPage: PROC = { IF press THEN SirPress.WritePage[p]}; JPen: PROC = { n: NAT _ JaMFnsDefs.PopInteger[]; pen _ NEW[PolygonPen.PenRec[n]]; FOR i:NAT DECREASING IN [0..n) DO pen[i] _ PopVec[]; ENDLOOP; rectangularPen _ FALSE; }; JRoundPen: PROC = { pen _ RoundPen[JaMFnsDefs.PopReal[]]}; -- create a regular polygon of n sides, with n > pi*sqrt(w/2) RoundPen: PROC[width: REAL] RETURNS[PolygonPen.Pen] = { halfWidth: REAL = MAX[.5, width/2]; nCorners: CARDINAL _ Real.RoundC[0.5+(pi*RealFns.SqRt[halfWidth])]; r: RoundPenCacheRef _ pens; i: CARDINAL; rectangularPen _ FALSE; WHILE r#NIL DO IF r.numCorners=nCorners THEN RETURN[r.record]; r _ r.next; ENDLOOP; pens _ NEW[RoundPenCacheRec _ [pens, nCorners, Complex.Exp[[0,2*pi/nCorners]], NEW[PolygonPen.PenRec[nCorners]]] ]; pens.record[0] _ [halfWidth, 0]; FOR i IN [1 .. nCorners) DO pens.record[i] _ Complex.Mul[pens.record[i-1], pens.multiplier]; ENDLOOP; RETURN[pens.record]; }; JRectangularPen: PROC = { slant: REAL _ JaMFnsDefs.PopReal[]; height: REAL _ JaMFnsDefs.PopReal[]; width: REAL _ JaMFnsDefs.PopReal[]; pen _ RectangularPen[width, height, slant]}; RectangularPen: PROC[width, height, slant: REAL] RETURNS[pen: PolygonPen.Pen] = { halfWidth: REAL _ MAX[0.5, width/2]; halfHeight: REAL _ MAX[0.5, height/2]; rotate: Vec = Complex.Exp[[0,-(slant*pi/180)]]; pen _ NEW[PolygonPen.PenRec[4]]; pen[0] _ Complex.Mul[[halfWidth, halfHeight], rotate]; pen[1] _ Complex.Mul[[halfWidth, -halfHeight], rotate]; pen[2] _ Complex.Mul[[-halfWidth, -halfHeight], rotate]; pen[3] _ Complex.Mul[[-halfWidth, halfHeight], rotate]; rectangularPen _ slant=0; RETURN[pen]; }; JItalicPen: PROC = { slant: REAL _ JaMFnsDefs.PopReal[]; length: REAL _ JaMFnsDefs.PopReal[]; pen _ ItalicPen[length, slant]; }; ItalicPen: PROC[length, slant: REAL] RETURNS[pen: PolygonPen.Pen] = { pen _ NEW[PolygonPen.PenRec[2]]; pen[0] _ [0,0]; pen[1] _ Complex.Mul[[0, -MAX[1.0,length]], Complex.Exp[[0,-(slant*pi/180)]]]; rectangularPen _ FALSE; RETURN[pen]; }; JEllipticalPen: PROC = { slant: REAL _ JaMFnsDefs.PopReal[]; height: REAL _ JaMFnsDefs.PopReal[]; width: REAL _ JaMFnsDefs.PopReal[]; pen _ EllipticalPen[width, height, slant]}; EllipticalPen: PROC[width, height, slant: REAL] RETURNS[pen: PolygonPen.Pen] = { a: REAL = MAX[0.5, width/2]; b: REAL = MAX[0.5, height/2]; nCorners: CARDINAL = Real.RoundC[0.5+(pi*RealFns.SqRt[2*MIN[a,b]])]; theta: REAL = 2*pi/nCorners; cosTheta: REAL = RealFns.Cos[theta]; sinTheta: REAL = RealFns.Sin[theta]; cosSlant: REAL = RealFns.CosDeg[slant]; sinSlant: REAL = RealFns.SinDeg[slant]; cosAccum: REAL _ 1; sinAccum: REAL _ 0; x,y,t: REAL; pen _ NEW[PolygonPen.PenRec[nCorners]]; FOR i: CARDINAL IN [0 .. nCorners) DO x _ a*cosAccum; y _ b*sinAccum; pen[i] _ [x*cosSlant-y*sinSlant, x*sinSlant+y*cosSlant]; t _ cosAccum*cosTheta-sinAccum*sinTheta; sinAccum _ sinAccum*cosTheta+cosAccum*sinTheta; cosAccum _ t; ENDLOOP; rectangularPen _ FALSE; RETURN[pen]; }; JDrawDot: PROC = { point: Vec _ PopVec[]; IF press THEN SirPress.StartOutline[p]; PolygonPen.Dot[pen,point,PenMoveTo,PenLineTo,PenCurveTo]; IF press THEN SirPress.EndOutline[p] ELSE {TJaMGraphics.Painter[PaintPath]; Graphics.FlushPath[path]}; }; JDrawLine: PROC = { point: Vec _ PopVec[]; t: Vec _ PopVec[]; s: Vec _ PopVec[]; IF press THEN SirPress.StartOutline[p]; PolygonPen.Line[pen,s,t,PenMoveTo,PenLineTo,PenCurveTo]; IF press THEN SirPress.EndOutline[p] ELSE {TJaMGraphics.Painter[PaintPath]; Graphics.FlushPath[path]}; }; JDrawBezier: PROC = { b3: Vec _ PopVec[]; b2: Vec _ PopVec[]; b1: Vec _ PopVec[]; b0: Vec _ PopVec[]; IF press THEN SirPress.StartOutline[p]; PolygonPen.Stroke[pen,[b0,b1,b2,b3],PenMoveTo,PenLineTo,PenCurveTo]; IF press THEN SirPress.EndOutline[p] ELSE {TJaMGraphics.Painter[PaintPath]; Graphics.FlushPath[path]}; }; JDrawText: PROC = { paint: PROC [context: Graphics.Context] = { Graphics.SetCP[context,loc.x,loc.y]; Graphics.DrawRope[self: context, rope: LOOPHOLE[s], font: font]; }; s: REF TEXT _ PopText[]; loc: Vec _ PopVec[]; IF press THEN { tloc: Vec = Transform[loc]; SirPress.PutText[p,LOOPHOLE[s],Mica[tloc.x],Mica[tloc.y]]} ELSE TJaMGraphics.Painter[paint]; }; font: Graphics.FontRef _ NIL; JSetFont: PROC = { fontName: ROPE _ Rope.FromRefText[PopText[]]; IF press THEN { len: INTEGER _ Rope.Length[fontName]-1; family: ROPE; face, size: INTEGER _ 0; units: INTEGER _ 1; DO SELECT Rope.Fetch[fontName, len] FROM 'B => {face _ face + 1; len _ len - 1}; 'I => {face _ face + 2; len _ len - 1}; ENDCASE => EXIT; ENDLOOP; WHILE Rope.Digit[Rope.Fetch[fontName, len]] DO size _ size+(Rope.Fetch[fontName, len]-'0)*units; len _ len-1; units _ units*10; ENDLOOP; family _ Rope.Substr[fontName, 0, len+1]; SirPress.SetFont[p,LOOPHOLE[family],size,face]} ELSE font _ Graphics.MakeFont[fontName]; }; JPressHue: PROC = { IF press THEN SirPress.SetHue[p,JaMFnsDefs.PopInteger[]]}; JPressSaturation: PROC = { IF press THEN SirPress.SetSaturation[p,JaMFnsDefs.PopInteger[]]}; JPressBrightness: PROC = { IF press THEN SirPress.SetBrightness[p,JaMFnsDefs.PopInteger[]]}; JPressHSB: PROC = { IF press THEN { v: REAL _ JaMFnsDefs.PopReal[]; s: REAL _ JaMFnsDefs.PopReal[]; h: REAL _ JaMFnsDefs.PopReal[]; SirPress.SetColor[p,Real.RoundI[h*240],Real.RoundI[s*255],Real.RoundI[v*255]]; }; }; JaMFnsDefs.Register[".openpress"L,JOpenPress]; -- filename .openpress JaMFnsDefs.Register[".closepress"L,JClosePress]; -- .closepress JaMFnsDefs.Register[".pressnewpage"L,JNewPage]; -- .pressnewpage JaMFnsDefs.Register[".beginpressobject"L,JBeginObject]; -- .beginpressobject JaMFnsDefs.Register[".endpressobject"L,JEndObject]; -- .endpressobject JaMFnsDefs.Register[".calligmoveto"L,JMoveTo]; -- x y .calligmoveto JaMFnsDefs.Register[".calliglineto"L,JLineTo]; -- x y .calliglineto JaMFnsDefs.Register[".calligcurveto"L,JCurveTo]; -- b1.x b1.y b2.x b2.y b3.x b3.y .calligcurveto JaMFnsDefs.Register[".calligdrawdot"L,JDrawDot]; -- x y .calligdrawdot JaMFnsDefs.Register[".calligdrawline"L,JDrawLine]; -- sx sy tx ty .calligdrawline JaMFnsDefs.Register[".calligdrawbezier"L,JDrawBezier]; -- b0.x b0.y b1.x b1.y b2.x b2.y b3.x b3.y .calligdrawbezier JaMFnsDefs.Register[".calligdrawpath"L,JDrawPath]; -- width .calligdrawpath JaMFnsDefs.Register[".calligoutlinepath"L,JOutlinePath]; -- .calligdrawpath, assumes pen JaMFnsDefs.Register[".calligdrawarea"L,JDrawArea]; -- .calligdrawarea JaMFnsDefs.Register[".calligpen"L,JPen]; -- x1 y1 . . . xn yn n .calligpen JaMFnsDefs.Register[".calligroundpen"L,JRoundPen]; -- diameter .calligroundpen JaMFnsDefs.Register[".calligrectangularpen"L,JRectangularPen]; -- width height slant .calligrectangularpen JaMFnsDefs.Register[".calligitalicpen"L,JItalicPen]; -- length slant .calligitalicpen JaMFnsDefs.Register[".calligellipticalpen"L,JEllipticalPen]; -- width height slant .calligellipticalpen JaMFnsDefs.Register[".presshue"L,JPressHue]; -- hue[0-255] .presshue JaMFnsDefs.Register[".presssaturation"L,JPressSaturation]; -- saturation[0-255] .presssaturation JaMFnsDefs.Register[".pressbrightness"L,JPressBrightness]; -- brightness[0-255] .pressbrightness JaMFnsDefs.Register[".presshsb"L,JPressHSB]; -- hue[0-1) saturation[0-1) brightness[0-1) .presshsb JaMFnsDefs.Register[".calligtext"L,JDrawText]; -- string .calligtext JaMFnsDefs.Register[".presssetfont"L,JSetFont]; -- fontname .presssetfont JaMFnsDefs.Register[".calligshadowpen"L,JShadowPen]; -- some-pen-definition .calligshadowpen JaMFnsDefs.Register[".calligshadowpath"L,JShadowPath]; -- .calligshadowpath, assumes shadow pen pen _ NEW[PolygonPen.PenRec[2]]; pen[0] _ [-2,-2]; pen[1] _ [2,2]; }. ĘΘJšĪĪcĩœĪk œ™žœžœ†žœžœžœžœžœ!žœžœ%žœžœ)žœGžœ5žœžœIžœ žœžœ[Īn œžœBŸ œžœFŸœž œžœžœžœžœžœžœ"Ÿ œž œ žœžœ|Ÿ œžœžœžœžœ Ÿ œžœžœžœžœCŸœžœ:Ÿœžœ:Ÿœžœ}Ÿ œžœ žœžœ žœžœžœ4Ÿ œžœ'Ÿ œžœžœžœ žœžœžœ žœžœžœžœYœ,œ#žœ?žœĮžœ_žœžœžœfžœžœJžœžœžœ‰žœžœ‡žœ‰žœžœLžœ`žœžœąžœMŸ œžœŸ œžœžœžœ žœžœžœ žœlžœžœžœožœžœJžœžœžœžŸ œžœžœžœ žœžœ žœnžœžœ žœožœžœžœąžœLŸœž œžœJŸœž œžœžœžœ žœžœžœ Ÿœžœž œEžœŸœžœž œ žœ žœŸ œžœ žœfžœŸ œžœžœžœ žœžœžœžœ+žœMŸ œžœžœžœžœ žœŸœžœžœžœŸœžœ žœ#žœžœžœž œžœžœžœžœŸ œžœ/>Ÿœžœžœžœ!žœžœžœSžœžœžœžœžœžœžœžœžœ žœEžœEžœžœžœFžœžœŸœžœ žœ"žœ!žœIŸœžœžœžœ&žœžœžœžœIžœ˜žœ Ÿ œžœ žœ"žœ@Ÿ œžœžœžœ!žœDžœDžœžœ Ÿœžœ žœ"žœ!žœHŸ œžœžœžœžœžœžœžœžœ&žœžœžœ#žœ"žœ%žœ%žœžœžœ žœ žœžœžœžœĪžœžœžœ ŸœžœžœžœWžœžœžœCŸ œžœFžœžœVžœžœžœCŸ œžœZžœžœbžœžœžœCŸ œžœ žœqžœžœžœ%žœžœ4žœ!žœ<žœŸœžœžœ!žœžœ žœ&žœžœžœžœžœžœZžœžœžœžœ'žœ^žœCžœžœ*Ÿ œžœžœžœ/Ÿœžœžœžœ6Ÿœžœžœžœ6Ÿ œžœžœžœķœ1œ0œ8œ4œ/œ/œ10œ1œ3œ7=œ3œ9 œ3œ)"œ3œ?,œ5!œ=+œ-œ;&œ;'œ-7œ/œ0œ6(œ7)œžœ=˜īr—…—9r?F