-- PolyImpl.mesa
-- Last changed by Doug Wyatt, September 22, 1980 5:32 PM

DIRECTORY
Poly,
Vector USING [Vec],
Area USING [Rec, Handle, Object, Procs],
Boxer USING [Handle, New, Put, Rectangle, Free],
Memory USING [NewZone];

PolyImpl: PROGRAM
IMPORTS Memory,Boxer
EXPORTS Poly SHARES Poly,Area = {
OPEN Poly;

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

Node: TYPE = RECORD[next: NodeRef, v: Vector.Vec];
NodeRef: TYPE = LONG POINTER TO Node;

free: NodeRef ← NIL; -- head of list of free Nodes

NewNode: PROC[v: Vector.Vec] RETURNS[NodeRef] = INLINE {
n: NodeRef←free;
IF n=NIL THEN n←zone.NEW[Node] ELSE free←n.next;
n↑←[next: NIL, v: v]; RETURN[n];
};

FreeList: PROC[head,tail: NodeRef] = INLINE {
tail.next←free; free←head;
};

Data: PUBLIC TYPE = RECORD[
head,tail: NodeRef,
boxer: Boxer.Handle,
rect: BOOLEAN
];
DataRef: TYPE = LONG POINTER TO Data;

AData: TYPE = RECORD[head,tail: NodeRef, rec: Area.Rec];
ADataRef: TYPE = LONG POINTER TO AData;

eprocs: LONG POINTER TO READONLY Procs = zone.NEW[Procs = [
Put: EPut, NewArea: ENewArea, Free: EFree
]];

fprocs: LONG POINTER TO READONLY Procs = zone.NEW[Procs = [
Put: FPut, NewArea: FNewArea, Free: FFree
]];

pAreaProcs: LONG POINTER TO READONLY Area.Procs = zone.NEW[Area.Procs = [
Vertices: PVertices, Rectangle: ARectangle, Free: PFree
]];

rAreaProcs: LONG POINTER TO READONLY Area.Procs = zone.NEW[Area.Procs = [
Vertices: RVertices, Rectangle: ARectangle, Free: RFree
]];

New: PUBLIC PROC RETURNS[Handle] = {
d: DataRef = zone.NEW[Data ← [
head: NIL, tail: NIL, boxer: NIL, rect: FALSE]];
RETURN[zone.NEW[Object ← [procs: eprocs, data: d]]];
};

EPut: PROC[self: Handle, v: Vector.Vec] = {
d: DataRef=self.data;
d.head←d.tail←NewNode[v];
d.boxer←Boxer.New[]; Boxer.Put[d.boxer,v]; d.rect←TRUE;
self.procs←fprocs;
};

FPut: PROC[self: Handle, v: Vector.Vec] = {
d: DataRef=self.data;
u: Vector.Vec=d.tail.v;
n: NodeRef=NewNode[v];
d.tail.next←n; d.tail←n; Boxer.Put[d.boxer,v];
IF u.x#v.x AND u.y#v.y THEN d.rect←FALSE;
};

ENewArea: PROC[self: Handle] RETURNS[Area.Handle] = {
RETURN[NIL]
};

FNewArea: PROC[self: Handle] RETURNS[Area.Handle] = {
d: DataRef=self.data;
a: ADataRef = zone.NEW[AData ← [
head: NIL, tail: NIL, rec: Boxer.Rectangle[d.boxer]
]];
u: Vector.Vec=d.tail.v;
v: Vector.Vec=d.head.v;
IF u.x#v.x AND u.y#v.y THEN d.rect←FALSE;
IF d.rect THEN FreeList[d.head,d.tail]
ELSE { a.head←d.head; a.tail←d.tail };
d.head←d.tail←NIL; Boxer.Free[@d.boxer];
self.procs←eprocs;
RETURN[zone.NEW[Area.Object ← [
procs: IF d.rect THEN rAreaProcs ELSE pAreaProcs,
data: LOOPHOLE[a], rect: d.rect
]]];
};

EFree: PROC[self: Handle] = {
d: DataRef←self.data;
zone.FREE[@d]; zone.FREE[@self]
};

FFree: PROC[self: Handle] = {
d: DataRef←self.data;
FreeList[d.head,d.tail]; Boxer.Free[@d.boxer];
zone.FREE[@d]; zone.FREE[@self];
};

NewRec: PUBLIC PROC[rec: Area.Rec] RETURNS[Area.Handle] = {
a: ADataRef = zone.NEW[AData ← [head: NIL, tail: NIL, rec: rec]];
RETURN[zone.NEW[Area.Object ← [
procs: rAreaProcs, data: LOOPHOLE[a], rect: TRUE]]];
};

PVertices: PROC[self: Area.Handle, Proc: PROC[Vector.Vec]] = {
a: ADataRef=LOOPHOLE[self.data];
FOR n: NodeRef←a.head,n.next UNTIL n=NIL DO Proc[n.v] ENDLOOP;
};

RVertices: PROC[self: Area.Handle, Proc: PROC[Vector.Vec]] = {
a: ADataRef=LOOPHOLE[self.data];
r: Area.Rec=a.rec;
Proc[[r.ll.x,r.ll.y]];
Proc[[r.ur.x,r.ll.y]];
Proc[[r.ur.x,r.ur.y]];
Proc[[r.ll.x,r.ur.y]];
};

ARectangle: PROC[self: Area.Handle] RETURNS[Area.Rec] = {
a: ADataRef=LOOPHOLE[self.data];
RETURN[a.rec];
};

PFree: PROC[self: Area.Handle] = {
a: ADataRef←LOOPHOLE[self.data];
FreeList[a.head,a.tail];
zone.FREE[@a]; zone.FREE[@self];
};

RFree: PROC[self: Area.Handle] = {
a: ADataRef←LOOPHOLE[self.data];
zone.FREE[@a]; zone.FREE[@self];
};

Purge: PROC = {
UNTIL free=NIL DO
n: NodeRef←free; free←free.next;
zone.FREE[@n];
ENDLOOP;
};

}.