-- CGPathImpl.mesa -- Last changed by Doug Wyatt, September 15, 1982 5:41 pm DIRECTORY CGPath USING [], CGStorage USING [pZone, qZone], GraphicsBasic USING [Box, Vec]; CGPathImpl: CEDAR PROGRAM IMPORTS CGStorage EXPORTS CGPath, GraphicsBasic = { OPEN GraphicsBasic; Ref: TYPE = REF Rep; Rep: TYPE = RECORD[ size: NAT, -- current size data: Data, -- the list of nodes box: REF Box -- bounding box ]; PathRep: PUBLIC TYPE = Rep; -- exported to GraphicsBasic Data: TYPE = REF DataRep; DataRep: TYPE = RECORD[SEQUENCE space: NAT OF Node]; Node: TYPE = REF NodeRep; NodeRep: TYPE = RECORD[ p: Vec, -- coordinates of the point start: BOOLEAN _ FALSE, -- marks the beginning of a new trajectory control: BOOLEAN _ FALSE -- marks a control point for a curve segment ]; Error: PUBLIC ERROR = CODE; dataZone: ZONE = CGStorage.pZone; nodeZone: ZONE = CGStorage.qZone; boxZone: ZONE = CGStorage.qZone; repZone: ZONE = CGStorage.qZone; nullNode: NodeRep = [p: [0,0], start: FALSE, control: FALSE]; nullBox: Box = [0,0,0,0]; New: PUBLIC PROC[size: NAT] RETURNS[Ref] = { self: Ref _ repZone.NEW[Rep _ [size: 0, data: NIL, box: NIL]]; [] _ GetData[self,size]; self.box _ boxZone.NEW[Box _ nullBox]; RETURN[self]; }; GetData: PROC[self: Ref, size: NAT, bump: NAT _ 0] RETURNS[Data] = INLINE { data: Data _ self.data; space: NAT _ IF data=NIL THEN 0 ELSE data.space; IF space0 THEN { self.size _ 0; self.box^ _ nullBox }; }; Empty: PUBLIC PROC[self: Ref] RETURNS[BOOLEAN] = { RETURN[self.size=0] }; LastPoint: PUBLIC PROC[self: Ref] RETURNS[Vec] = { size: NAT _ self.size; IF size>0 THEN RETURN[self.data[size-1].p] ELSE RETURN[[0,0]]; }; MoveTo: PUBLIC PROC[self: Ref, p: Vec] = { Enter[self, [p: p, start: TRUE]]; }; LineTo: PUBLIC PROC[self: Ref, p: Vec] = { IF self.size=0 THEN Enter[self, [p: [0,0], start: TRUE]]; Enter[self, [p: p]]; }; CurveTo: PUBLIC PROC[self: Ref, b1, b2, b3: Vec] = { IF self.size=0 THEN Enter[self, [p: [0,0], start: TRUE]]; Enter[self, [p: b1, control: TRUE]]; Enter[self, [p: b2, control: TRUE]]; Enter[self, [p: b3]]; }; Rectangle: PUBLIC PROC[self: Ref, p, q: Vec] = { Enter[self, [p: p, start: TRUE]]; Enter[self, [p: [q.x, p.y]]]; Enter[self, [p: q]]; Enter[self, [p: [p.x, q.y]]]; }; Enter: PROC[self: Ref, node: NodeRep] = { i: NAT _ self.size; size: NAT _ i + 1; data: Data _ GetData[self,size,MAX[8,MIN[size/2,1024]]]; box: REF Box _ self.box; p: Vec _ node.p; data[i]^ _ node; IF i=0 AND node.start THEN { box.xmin _ box.xmax _ p.x; box.ymin _ box.ymax _ p.y; } ELSE { IF p.xbox.xmax THEN box.xmax _ p.x; IF p.ybox.ymax THEN box.ymax _ p.y; }; self.size _ size; }; Bounds: PUBLIC PROC[self: Ref] RETURNS[Box] = { RETURN[self.box^] }; -- return a bounding box for the current path Generate: PUBLIC PROC[self: Ref, move: PROC[Vec], line: PROC[Vec], curve: PROC[Vec, Vec, Vec]] = { size: NAT _ self.size; data: Data _ self.data; State: TYPE = {state0, state1, state2, state3}; state: State _ state0; b1, b2: Vec; FOR i: NAT IN[0..size) DO node: Node _ data[i]; p: Vec _ node.p; IF node.start AND state#state0 THEN { IF state=state3 THEN state _ state0 ELSE ERROR Error; }; SELECT state FROM state0 => { IF node.control THEN ERROR Error ELSE { move[p]; state _ state3 }; }; state1 => { IF node.control THEN { b2 _ p; state _ state2 } ELSE ERROR Error; }; state2 => { IF node.control THEN ERROR Error ELSE { curve[b1, b2, p]; state _ state3 }; }; state3 => { IF node.control THEN { b1 _ p; state _ state1 } ELSE line[p]; }; ENDCASE => ERROR Error; ENDLOOP; IF NOT(state=state3 OR state=state0) THEN ERROR Error; }; MapAndFilter: PUBLIC PROC[self: Ref, map: PROC[Vec] RETURNS[Vec] _ NIL, move: PROC[Vec], line: PROC[Vec], curve: PROC[Vec, Vec, Vec], close: PROC] = { first: BOOLEAN _ TRUE; lp: Vec; Move: PROC[v: Vec] = { IF map#NIL THEN v _ map[v]; IF first THEN first _ FALSE ELSE close[]; move[v]; lp _ v; }; Line: PROC[v: Vec] = { IF map#NIL THEN v _ map[v]; IF first THEN Move[[0,0]]; IF v#lp THEN line[v]; lp _ v; }; Curve: PROC[v1, v2, v3: Vec] = { matches: NAT _ 0; IF map#NIL THEN { v1 _ map[v1]; v2 _ map[v2]; v3 _ map[v3] }; IF first THEN Move[[0,0]]; IF lp=v1 THEN matches _ matches+1; IF v1=v2 THEN matches _ matches+1; IF v2=v3 THEN matches _ matches+1; IF matches<2 THEN curve[v1, v2, v3] ELSE IF matches<3 THEN line[v3]; lp _ v3; }; Generate[self, Move, Line, Curve]; IF NOT first THEN close[]; }; Copy: PUBLIC PROC[self: Ref] RETURNS[Ref] = { size: NAT _ self.size; old: Data _ self.data; copy: Ref _ New[size]; new: Data _ copy.data; FOR i: NAT IN[0..size) DO new[i]^ _ old[i]^ ENDLOOP; copy.box^ _ self.box^; copy.size _ size; RETURN[copy]; }; Assign: PUBLIC PROC[self: Ref, copy: Ref] = { size: NAT _ copy.size; new: Data _ copy.data; old: Data _ GetData[self,size]; FOR i: NAT IN[0..size) DO old[i]^ _ new[i]^ ENDLOOP; self.box^ _ copy.box^; self.size _ size; }; }. ΚŸ– "Mesa" style˜Iprocš΄ΟcMœΟk œ žœžœ!žœžœžœžœ žœžœžœžœ žœžœ žœœœžœœžœžœœžœžœžœžœžœžœžœžœžœžœžœ œ žœžœ+œ žœžœ-œ žœžœžœ žœžœžœžœ;žœ žœΟnœžœžœžœžœ žœžœžœ4žœžœŸœžœžœžœžœ žœ&žœžœžœžœžœžœ žœžœžœŸœžœžœžœ-žœžœžœžœžœ#žœžœžœžœ žœžœžœžœžœžœžœžœžœ Ÿœžœžœžœ žœ/Ÿœžœžœ žœžœžœŸ œžœžœ žœžœžœžœžœžœžœŸœžœžœ4žœ Ÿœžœžœžœ žœžœ"Ÿœžœžœ#žœ žœžœ#žœ#žœ"Ÿ œžœžœ7žœaŸœžœ$žœžœ+žœžœžœ9žœžœ žœIžœžœžœžœžœžœžœžœžœžœžœ2Ÿœžœžœ žœ žœ.œŸœžœžœžœ žœžœžœ1žœOžœžœžœ žœ4žœ žœžœ žœžœžœžœžœžœžœžœžœžœCžœžœ$žœžœ-žœžœžœžœLžœžœ$žœžœžœ žœžœžœžœžœžœŸ œžœžœžœžœžœ žœ žœžœžœžœžœŸœžœžœžœžœžœžœ žœžœ,ŸœžœžœžœžœžœžœžœžœŸœžœ#žœ žœžœžœ3žœžœžœžœžœžœžœžœžœ žœžœžœ žœFžœžœžœŸœžœžœ žœžœ[žœžœžœ žœžœ1žœŸœžœžœ#žœKžœžœžœ žœžœ9˜Ύ-—…—ΐe