-- CGPrivateImpl.mesa -- Last edited by Doug Wyatt, September 20, 1982 4:21 pm DIRECTORY CGArea USING [Insert, InsertBox, Ref], CGClipper USING [Bounds, Empty, GenerateBox, GenerateLine, IsBox, Load, Ref, SetArea, TestBox, TestPoint], CGCubic USING [Bezier, Flat, Split], CGContext USING [Ref, TouchClipper, TouchCP, TouchFill, TouchMatrix], CGDevice USING [Fill, Generator, Ref, Rep], CGDummyDevice USING [Get], CGMatrix USING [Concat, Inv, InvRel, Map, MapRel, Ref, SetTrans], CGPath USING [Bounds, Empty, MapAndFilter], CGPrivate USING [], CGReducer USING [Close, Generate, Ref, Vertex], CGVector USING [Add], Graphics USING [Context, Warning], GraphicsBasic USING [Box, Color, PaintMode, Path, Trap, Vec, YMode], SpecialReal USING [Round]; CGPrivateImpl: CEDAR PROGRAM IMPORTS CGArea, CGClipper, CGContext, CGCubic, CGDummyDevice, CGMatrix, CGPath, CGReducer, CGVector, Graphics, SpecialReal EXPORTS CGContext, CGPrivate, GraphicsBasic = { OPEN GraphicsBasic; Context: TYPE = Graphics.Context; Data: TYPE = CGContext.Ref; Path: TYPE = GraphicsBasic.Path; DeviceObject: PUBLIC TYPE = CGDevice.Rep; -- export to GraphicsBasic -- Procedures dependent on data representation -- GetCP: PUBLIC PROC[self: Context, rounded: BOOLEAN] RETURNS[x,y: REAL] = { d: Data _ NARROW[self.data]; m: CGMatrix.Ref _ d.matrix; cp: Vec _ d.cp; p: Vec; IF rounded THEN { cp.x _ SpecialReal.Round[cp.x]; cp.y _ SpecialReal.Round[cp.y] }; p _ CGMatrix.Inv[m,cp]; RETURN[p.x,p.y]; }; SetCP: PUBLIC PROC[self: Context, x,y: REAL, rel: BOOLEAN] = { d: Data _ NARROW[self.data]; m: CGMatrix.Ref _ d.matrix; p: Vec _ [x,y]; CGContext.TouchCP[d]; IF rel THEN d.cp _ CGVector.Add[d.cp,CGMatrix.MapRel[m,p]] ELSE d.cp _ CGMatrix.Map[m,p]; }; DrawTo: PUBLIC PROC[self: Context, x,y: REAL, rel: BOOLEAN] = { d: Data _ NARROW[self.data]; m: CGMatrix.Ref _ d.matrix; clipper: CGClipper.Ref _ d.clipper; device: CGDevice.Ref _ d.device; fill: CGDevice.Fill _ d.fill; p, q: Vec; Gen: CGDevice.Generator = { CGClipper.GenerateLine[clipper, p, q, showTrap]; }; p _ d.cp; CGContext.TouchCP[d]; IF rel THEN q _ CGVector.Add[p,CGMatrix.MapRel[m,[x,y]]] ELSE q _ CGMatrix.Map[m,[x,y]]; fill.fat _ TRUE; device.ShowConst[device, Gen, fill]; d.cp _ q; }; DrawArea: PUBLIC PROC[self: Context, path: Path, parityFill: BOOLEAN] = { d: Data _ NARROW[self.data]; device: CGDevice.Ref _ d.device; Gen: CGDevice.Generator = { GenPath[d: d, trap: showTrap, path: path, parityFill: parityFill, exclude: FALSE]; }; device.ShowConst[device, Gen, d.fill]; }; DrawBox: PUBLIC PROC[self: Context, box: Box] = { d: Data _ NARROW[self.data]; m: CGMatrix.Ref _ d.matrix; device: CGDevice.Ref _ d.device; Gen: CGDevice.Generator = { GenBox[d, showTrap, showBox, box, m] }; device.ShowConst[device, Gen, d.fill]; }; Translate: PUBLIC PROC[self: Context, tx,ty: REAL, round: BOOLEAN] = { d: Data _ NARROW[self.data]; m: CGMatrix.Ref _ d.matrix; t: Vec _ CGMatrix.Map[m,[tx,ty]]; CGContext.TouchMatrix[d]; IF round THEN { t.x _ SpecialReal.Round[t.x]; t.y _ SpecialReal.Round[t.y]; }; CGMatrix.SetTrans[m,t]; }; Concat: PUBLIC PROC[self: Context, m11,m12,m21,m22: REAL] = { d: Data _ NARROW[self.data]; CGContext.TouchMatrix[d]; CGMatrix.Concat[d.matrix,m11,m12,m21,m22]; }; WorldToUser: PUBLIC PROC[self: Context, wx,wy: REAL] RETURNS[x,y: REAL] = { d: Data _ NARROW[self.data]; device: CGDevice.Ref _ d.device; world: CGMatrix.Ref _ device.GetMatrix[device]; m: CGMatrix.Ref _ d.matrix; u: Vec _ CGMatrix.Inv[m,CGMatrix.Map[world,[wx,wy]]]; RETURN[u.x,u.y]; }; UserToWorld: PUBLIC PROC[self: Context, x,y: REAL] RETURNS[wx,wy: REAL] = { d: Data _ NARROW[self.data]; device: CGDevice.Ref _ d.device; world: CGMatrix.Ref _ device.GetMatrix[device]; m: CGMatrix.Ref _ d.matrix; w: Vec _ CGMatrix.Inv[world,CGMatrix.Map[m,[x,y]]]; RETURN[w.x,w.y]; }; SetColor: PUBLIC PROC[self: Context, color: Color] = { d: Data _ NARROW[self.data]; CGContext.TouchFill[d]; d.fill.color _ color; }; GetColor: PUBLIC PROC[self: Context] RETURNS[Color] = { d: Data _ NARROW[self.data]; RETURN[d.fill.color]; }; SetPaintMode: PUBLIC PROC[self: Context, mode: PaintMode] RETURNS[PaintMode] = { d: Data _ NARROW[self.data]; old: PaintMode _ d.fill.mode; CGContext.TouchFill[d]; d.fill.mode _ mode; RETURN[old]; }; SetFat: PUBLIC PROC[self: Context, fat: BOOLEAN] RETURNS[BOOLEAN] = { d: Data _ NARROW[self.data]; f: BOOLEAN _ d.fill.fat; CGContext.TouchFill[d]; d.fill.fat _ fat; RETURN[f]; }; ClipArea: PUBLIC PROC[self: Context, path: Path, parityFill: BOOLEAN, exclude: BOOLEAN] = { d: Data _ NARROW[self.data]; clipper: CGClipper.Ref _ d.clipper; area: CGArea.Ref _ d.area; Add: PROC[trap: Trap] = { CGArea.Insert[area, trap] }; CGContext.TouchClipper[d]; GenPath[d, Add, path, parityFill, exclude]; CGClipper.SetArea[self: clipper, area: area]; }; ClipBox: PUBLIC PROC[self: Context, box: Box, exclude: BOOLEAN] = { d: Data _ NARROW[self.data]; area: CGArea.Ref _ d.area; AddTrap: PROC[trap: Trap] = { CGArea.Insert[area, trap] }; AddBox: PROC[box: Box] = { CGArea.InsertBox[area, box] }; CGContext.TouchClipper[d]; GenBox[d,AddTrap,AddBox,box,d.matrix,exclude]; CGClipper.SetArea[d.clipper,area]; }; IsPointVisible: PUBLIC PROC[self: Context, x,y: REAL] RETURNS[BOOLEAN] = { d: Data _ NARROW[self.data]; clipper: CGClipper.Ref _ d.clipper; m: CGMatrix.Ref _ d.matrix; p: Vec _ CGMatrix.Map[m,[x,y]]; RETURN[CGClipper.TestPoint[clipper,p]]; }; IsRectangular: PUBLIC PROC[self: Context] RETURNS[BOOLEAN] = { d: Data _ NARROW[self.data]; clipper: CGClipper.Ref _ d.clipper; RETURN[CGClipper.IsBox[clipper]]; }; GetBounds: PUBLIC PROC[self: Context] RETURNS[Box] = { data: Data _ NARROW[self.data]; clipper: CGClipper.Ref _ data.clipper; m: CGMatrix.Ref _ data.matrix; box: Box _ CGClipper.Bounds[clipper]; result: Box; a,b,c,d: Vec; IF m.rectangular THEN { a _ CGMatrix.Inv[m,[box.xmin,box.ymin]]; c _ CGMatrix.Inv[m,[box.xmax,box.ymax]]; result.xmin _ MIN[a.x,c.x]; result.xmax _ MAX[a.x,c.x]; result.ymin _ MIN[a.y,c.y]; result.ymax _ MAX[a.y,c.y]; } ELSE { a _ CGMatrix.Inv[m,[box.xmin,box.ymin]]; b _ CGMatrix.Inv[m,[box.xmax,box.ymin]]; c _ CGMatrix.Inv[m,[box.xmax,box.ymax]]; d _ CGMatrix.Inv[m,[box.xmin,box.ymax]]; result.xmin _ MIN[a.x,b.x,c.x,d.x]; result.xmax _ MAX[a.x,b.x,c.x,d.x]; result.ymin _ MIN[a.y,b.y,c.y,d.y]; result.ymax _ MAX[a.y,b.y,c.y,d.y]; }; RETURN[result]; }; Visible: PUBLIC PROC[self: Context] RETURNS[BOOLEAN] = { d: Data _ NARROW[self.data]; RETURN[NOT CGClipper.Empty[d.clipper]]; }; UserToDevice: PUBLIC PROC[self: Context, x, y: REAL, rel: BOOLEAN] RETURNS[tx, ty: REAL] = { d: Data _ NARROW[self.data]; m: CGMatrix.Ref _ d.matrix; w: Vec; IF rel THEN w _ CGMatrix.MapRel[m,[x,y]] ELSE w _ CGMatrix.Map[m,[x,y]]; RETURN[w.x, w.y]; }; DeviceToUser: PUBLIC PROC[self: Context, tx, ty: REAL, rel: BOOLEAN] RETURNS[x, y: REAL] = { d: Data _ NARROW[self.data]; m: CGMatrix.Ref _ d.matrix; w: Vec; IF rel THEN w _ CGMatrix.InvRel[m,[tx,ty]] ELSE w _ CGMatrix.Inv[m,[tx,ty]]; RETURN[w.x, w.y]; }; GetYMode: PUBLIC PROC[self: Context] RETURNS[YMode] = { d: Data _ NARROW[self.data]; RETURN[IF d.yUp THEN bottomUp ELSE topDown]; }; SetYMode: PUBLIC PROC[self: Context, mode: YMode] = { d: Data _ NARROW[self.data]; yUp: BOOLEAN _ (mode=bottomUp); IF d.yUp#yUp THEN { CGContext.TouchMatrix[d]; CGMatrix.Concat[d.matrix,1,0,0,-1]; d.yUp _ yUp; }; }; Disable: PUBLIC PROC[self: Context] = { d: Data _ NARROW[self.data]; d.device _ CGDummyDevice.Get[]; d.dbase _ NIL; d.drast _ 0; d.haveRaster _ FALSE; }; MoveDeviceRectangle: PUBLIC PROC[self: Context, width, height, fromX, fromY, toX, toY: NAT] = { d: Data _ NARROW[self.data]; device: CGDevice.Ref _ d.device; IF device.MoveBlock#NIL THEN device.MoveBlock[self: device, width: width, height: height, fromX: fromX, fromY: fromY, toX: toX, toY: toY] ELSE SIGNAL Graphics.Warning[notImplemented]; }; -- Miscellaneous utility procedures -- GenPath: PROC[d: Data, trap: PROC[Trap], path: Path, parityFill, exclude: BOOLEAN] = { IF NOT CGPath.Empty[path] THEN { matrix: CGMatrix.Ref _ d.matrix; box: Box _ MapBox[matrix, CGPath.Bounds[path]]; clipper: CGClipper.Ref _ d.clipper; reducer: CGReducer.Ref _ d.reducer; IF CGClipper.TestBox[clipper, box, reducer] THEN { EnterPath[path, matrix, reducer]; CGReducer.Generate[self: reducer, proc: trap, exclude: exclude, oddwrap: parityFill]; }; }; }; EnterPath: PROC[path: Path, m: CGMatrix.Ref, reducer: CGReducer.Ref] = { lp: Vec; Map: PROC[v: Vec] RETURNS[Vec] = { RETURN[CGMatrix.Map[m, v]] }; Vertex: PROC[v: Vec] = { CGReducer.Vertex[reducer, lp _ v] }; Curve: PROC[v1, v2, v3: Vec] = { eps: REAL = 1.5; maxdepth: NAT = 10; Divide: PROC[b: CGCubic.Bezier, depth: NAT _ 0] = { IF depth>=maxdepth OR CGCubic.Flat[b, eps] THEN CGReducer.Vertex[reducer, b.b3] ELSE { b1, b2: CGCubic.Bezier; [b1, b2] _ CGCubic.Split[b]; Divide[b1, depth+1]; Divide[b2, depth+1] }; }; Divide[[lp, v1, v2, v3]]; lp _ v3; }; Close: PROC = { CGReducer.Close[reducer] }; CGPath.MapAndFilter[path, Map, Vertex, Vertex, Curve, Close]; }; MapBox: PUBLIC PROC[m: CGMatrix.Ref, box: Box] RETURNS[Box] = { mbox: Box; IF m.rectangular THEN { a: Vec _ CGMatrix.Map[m,[box.xmin,box.ymin]]; b: Vec _ CGMatrix.Map[m,[box.xmax,box.ymax]]; IF a.x<=b.x THEN { mbox.xmin _ a.x; mbox.xmax _ b.x } ELSE { mbox.xmin _ b.x; mbox.xmax _ a.x }; IF a.y<=b.y THEN { mbox.ymin _ a.y; mbox.ymax _ b.y } ELSE { mbox.ymin _ b.y; mbox.ymax _ a.y }; } ELSE { a: Vec _ CGMatrix.Map[m,[box.xmin,box.ymin]]; b: Vec _ CGMatrix.Map[m,[box.xmax,box.ymin]]; c: Vec _ CGMatrix.Map[m,[box.xmax,box.ymax]]; d: Vec _ CGMatrix.Map[m,[box.xmin,box.ymax]]; mbox _ [xmin: MIN[a.x, b.x, c.x, d.x], ymin: MIN[a.y, b.y, c.y, d.y], xmax: MAX[a.x, b.x, c.x, d.x], ymax: MAX[a.y, b.y, c.y, d.y]]; }; RETURN[mbox]; }; InvBox: PUBLIC PROC[m: CGMatrix.Ref, box: Box] RETURNS[Box] = { mbox: Box; IF m.rectangular THEN { a: Vec _ CGMatrix.Inv[m,[box.xmin,box.ymin]]; b: Vec _ CGMatrix.Inv[m,[box.xmax,box.ymax]]; IF a.x<=b.x THEN { mbox.xmin _ a.x; mbox.xmax _ b.x } ELSE { mbox.xmin _ b.x; mbox.xmax _ a.x }; IF a.y<=b.y THEN { mbox.ymin _ a.y; mbox.ymax _ b.y } ELSE { mbox.ymin _ b.y; mbox.ymax _ a.y }; } ELSE { a: Vec _ CGMatrix.Inv[m,[box.xmin,box.ymin]]; b: Vec _ CGMatrix.Inv[m,[box.xmax,box.ymin]]; c: Vec _ CGMatrix.Inv[m,[box.xmax,box.ymax]]; d: Vec _ CGMatrix.Inv[m,[box.xmin,box.ymax]]; mbox _ [xmin: MIN[a.x, b.x, c.x, d.x], ymin: MIN[a.y, b.y, c.y, d.y], xmax: MAX[a.x, b.x, c.x, d.x], ymax: MAX[a.y, b.y, c.y, d.y]]; }; RETURN[mbox]; }; GenBox: PUBLIC PROC[d: Data, emitTrap: PROC[Trap], emitBox: PROC[Box], box: Box, m: CGMatrix.Ref, exclude: BOOLEAN _ FALSE] = { clipper: CGClipper.Ref _ d.clipper; reducer: CGReducer.Ref _ d.reducer; IF m.rectangular AND NOT exclude THEN { mbox: Box; a: Vec _ CGMatrix.Map[m,[box.xmin,box.ymin]]; b: Vec _ CGMatrix.Map[m,[box.xmax,box.ymax]]; IF a.x<=b.x THEN { mbox.xmin _ a.x; mbox.xmax _ b.x } ELSE { mbox.xmin _ b.x; mbox.xmax _ a.x }; IF a.y<=b.y THEN { mbox.ymin _ a.y; mbox.ymax _ b.y } ELSE { mbox.ymin _ b.y; mbox.ymax _ a.y }; CGClipper.GenerateBox[clipper,mbox,reducer,emitTrap,emitBox]; } ELSE { CGClipper.Load[clipper,reducer]; CGReducer.Vertex[reducer,CGMatrix.Map[m,[box.xmin,box.ymin]]]; CGReducer.Vertex[reducer,CGMatrix.Map[m,[box.xmax,box.ymin]]]; CGReducer.Vertex[reducer,CGMatrix.Map[m,[box.xmax,box.ymax]]]; CGReducer.Vertex[reducer,CGMatrix.Map[m,[box.xmin,box.ymax]]]; CGReducer.Close[reducer]; CGReducer.Generate[self: reducer, proc: emitTrap, exclude: exclude]; }; }; }. ΚB– "Mesa" style˜IprocšώΟcOœΟk œ žœ'žœjžœ$žœBžœ.žœžœ=žœ,žœžœ,žœžœ%žœ@žœžœžœžœvžœ)žœžœžœžœ&žœžœœ1œΟnœžœžœžœžœžœžœIžœ žœažœŸœžœžœžœžœžœWžœžœ2žœ!Ÿœžœžœžœžœžœ‘žœžœ0žœ)žœ;Ÿœžœžœ(žœžœ£žœ9Ÿœžœžœ*žœΓŸ œžœžœžœ žœžœmžœžœnŸœžœžœ!žœžœ\Ÿ œžœžœžœžœžœžœΊžœŸ œžœžœžœžœžœžœΈžœŸœžœžœ.žœEŸœžœžœžœžœžœŸ œžœžœ!žœžœ_žœ Ÿœžœžœžœžœžœžœžœ=žœ Ÿœžœžœ*žœ žœžœRŸœžœ―Ÿœžœžœ#žœžœ,Ÿœžœ0Ÿœžœ§Ÿœžœžœžœžœžœžœužœ(Ÿ œžœžœžœžœžœ5žœ"Ÿ œžœžœžœžœ žœžœožœžœžœžœžœΙžœ%žœ%žœ%žœžœŸœžœžœžœžœžœžœžœ$Ÿ œžœžœžœžœžœ žœžœ7žœžœ žœžœŸ œžœžœžœžœžœžœžœ7žœžœ"žœ žœŸœžœžœžœžœžœžœžœ žœŸœžœžœ-žœžœžœ žœgŸœžœžœ žœ;žœžœŸœžœžœ9žœžœ2žœžœžœtžœžœ*&œŸœžœžœ)žœžœžœžœ°žœ*žœŸ œžœGŸœžœ žœ žœŸœžœ4Ÿœžœžœžœ Ÿœžœžœžœžœžœ'žœ₯ŸœžœgŸœžœžœžœžœžœkžœ žœ*žœ+žœ žœ*žœ/žœέžœžœ"žœžœ žœŸœžœžœžœžœžœkžœ žœ*žœ+žœ žœ*žœ/žœέžœžœ"žœžœ žœŸœžœžœžœžœ-žœžœTžœžœžœ žœzžœ žœ*žœ+žœ žœ*žœqžœ¬˜Η_—…—/Κ5