-- PatchImpl.mesa
-- Last changed by Doug Wyatt, September 22, 1980 5:34 PM

DIRECTORY
Patch,
Vector USING [Vec],
Poly USING [NewRec],
Area USING [Rec, Outside, Inside,
Handle, Vertices, Rectangle, Rectangular, Free],
Pipe USING [Handle, Object, Procs, Put, Ref, Free],
Edge USING [Handle, New, NewPipe, Free],
Memory USING [NewZone];

PatchImpl: PROGRAM
IMPORTS Memory,Poly,Area,Pipe,Edge
EXPORTS Patch SHARES Patch,Pipe = {
OPEN Patch;

zone: UNCOUNTED ZONE = Memory.NewZone["PatchImpl"];

Data: PUBLIC TYPE = RECORD [
area: Area.Handle,
elist: NodeRef
];
DataRef: TYPE = LONG POINTER TO Data;

Node: TYPE = RECORD [
link: NodeRef,
edge: Edge.Handle
];
NodeRef: TYPE = LONG POINTER TO Node;

procs: LONG POINTER TO READONLY Procs = zone.NEW[Procs = [
NewPipe: CNewPipe,
Copy: CCopy,
Free: CFree
]];

New: PUBLIC PROC[area: Area.Handle] RETURNS[Handle] = {
d: DataRef = zone.NEW[Data ← [area: area, elist: NIL]];
first: BOOLEAN←TRUE;
fv,pv: Vector.Vec;
Proc: PROC[v: Vector.Vec] = {
IF first THEN { fv←v; first←FALSE } ELSE AddEdge[d,pv,v];
pv←v;
};
Area.Vertices[area,Proc]; Proc[fv];

RETURN[zone.NEW[Object ← [procs: procs, data: d]]];
};

AddEdge: PROC[d: DataRef, v0,v1: Vector.Vec] = {
e: NodeRef=zone.NEW[Node ← [link: NIL, edge: Edge.New[v0,v1]]];
e.link←d.elist; d.elist←e;
};
FreeEdges: PROC[d: DataRef] = {
list: NodeRef←d.elist; d.elist←NIL;
UNTIL list=NIL DO
e: NodeRef←list; list←e.link;
Edge.Free[@e.edge]; zone.FREE[@e];
ENDLOOP;
};

PData: PUBLIC TYPE = RECORD [
area: Area.Handle,
ipipe,opipe: Pipe.Handle,
epipe: Pipe.Handle
];
PDataRef: TYPE = LONG POINTER TO PData;

pProcs: LONG POINTER TO READONLY Pipe.Procs=
zone.NEW[Pipe.Procs = [Put: PPut, Free: PFree]];

rProcs: LONG POINTER TO READONLY Pipe.Procs=
zone.NEW[Pipe.Procs = [Put: RPut, Free: PFree]];

CNewPipe: PROC[self: Handle, ipipe,opipe: Pipe.Handle]
RETURNS[Pipe.Handle] = {
d: DataRef=self.data;
p: PDataRef=zone.NEW[PData ← [
area: d.area,
ipipe: ipipe, opipe: opipe,
epipe: Pipe.Ref[ipipe]
]];
FOR e: NodeRef←d.elist,e.link UNTIL e=NIL DO
p.epipe←Edge.NewPipe[e.edge,p.epipe,Pipe.Ref[opipe]];
ENDLOOP;
RETURN[zone.NEW[Pipe.Object ← [
procs: IF Area.Rectangular[d.area] THEN rProcs ELSE pProcs,
data: LOOPHOLE[p]]]];
};

-- nonrectangular patch
PPut: PROC[self: Pipe.Handle, area: Area.Handle] = {
p: PDataRef=LOOPHOLE[self.data];
r: Area.Rec=Area.Rectangle[area];
rc: Area.Rec=Area.Rectangle[p.area];
IF Area.Outside[r,rc] THEN Pipe.Put[p.opipe,area]
ELSE Pipe.Put[p.epipe,area];
};

-- rectangular patch
RPut: PROC[self: Pipe.Handle, area: Area.Handle] = {
p: PDataRef=LOOPHOLE[self.data];
r: Area.Rec←Area.Rectangle[area];
rc: Area.Rec=Area.Rectangle[p.area];
IF Area.Outside[r,rc] THEN Pipe.Put[p.opipe,area]
ELSE IF Area.Inside[r,rc] THEN Pipe.Put[p.ipipe,area]
ELSE IF Area.Rectangular[area] THEN {
Area.Free[@area];
IF r.ll.x<rc.ll.x THEN {
rr: Area.Rec←r; rr.ur.x←r.ll.x←rc.ll.x;
Pipe.Put[p.opipe,Poly.NewRec[rr]];
};
IF r.ll.y<rc.ll.y THEN {
rr: Area.Rec←r; rr.ur.y←r.ll.y←rc.ll.y;
Pipe.Put[p.opipe,Poly.NewRec[rr]];
};
IF r.ur.x>rc.ur.x THEN {
rr: Area.Rec←r; rr.ll.x←r.ur.x←rc.ur.x;
Pipe.Put[p.opipe,Poly.NewRec[rr]];
};
IF r.ur.y>rc.ur.y THEN {
rr: Area.Rec←r; rr.ll.y←r.ur.y←rc.ur.y;
Pipe.Put[p.opipe,Poly.NewRec[rr]];
};
Pipe.Put[p.ipipe,Poly.NewRec[r]];
}
ELSE Pipe.Put[p.epipe,area];
};

PFree: PROC[self: Pipe.Handle] = {
p: PDataRef←LOOPHOLE[self.data];
Pipe.Free[@p.epipe];
Pipe.Free[@p.ipipe];
Pipe.Free[@p.opipe];
zone.FREE[@p]; zone.FREE[@self];
};

CCopy: PROC[self: Handle] RETURNS[Handle] = {
RETURN[NIL]; -- *** fix this
};

CFree: PROC[self: Handle] = {
d: DataRef←self.data;
FreeEdges[d];
Area.Free[@d.area];
zone.FREE[@d];
zone.FREE[@self];
};

}.