-- EdgeImpl.mesa -- Last changed by Doug Wyatt, October 29, 1980 3:09 PM DIRECTORY Edge, Vector USING [Vec, Add, Sub, Mul, Cross], Poly USING [Handle, New, Put, NewArea, Free], Area USING [Handle, Vertices, Free], Pipe USING [Handle, Object, Procs, Put, Free], Real USING [FComp], RealFns USING [SqRt], Memory USING [NewZone]; EdgeImpl: PROGRAM IMPORTS Memory,Vector,Poly,Area,Pipe,Real,RealFns EXPORTS Edge SHARES Edge,Pipe = { OPEN Edge; zone: UNCOUNTED ZONE = Memory.NewZone["EdgeImpl"]; Vec: TYPE = Vector.Vec; Line: TYPE = RECORD [SELECT tag: * FROM u,d => [x: REAL], -- vertical edge l,r => [y: REAL], -- horizontal edge oblique => [u: Vec, d: REAL], -- oblique edge ENDCASE ]; LineRef: TYPE = LONG POINTER TO READONLY Line; Data: PUBLIC TYPE = RECORD [ line: LineRef ]; DataRef: TYPE = LONG POINTER TO Data; procs: LONG POINTER TO READONLY Procs = zone.NEW[Procs = [ NewPipe: CNewPipe, Free: CFree ]]; -- Procedure for creating an Edge object New: PUBLIC PROC[v0,v1: Vector.Vec] RETURNS[Handle] = { line: LineRef=NewLine[@v0,@v1]; d: DataRef = zone.NEW[Data _ [line: line]]; RETURN[zone.NEW[Object _ [procs: procs, data: d]]]; }; Normalize: PROC[v: Vec] RETURNS[Vec] = INLINE { d: REAL=RealFns.SqRt[v.x*v.x+v.y*v.y]; RETURN[[x: v.x/d, y: v.y/d]] }; NewLine: PROC[v0,v1: POINTER TO Vector.Vec] RETURNS[LineRef] = --INLINE-- { SELECT TRUE FROM (v0.x=v1.x) => RETURN[zone.NEW[Line = IF v1.y>v0.y THEN [u[v0.x]] ELSE [d[v0.x]]]]; (v0.y=v1.y) => RETURN[zone.NEW[Line = IF v1.x>v0.x THEN [r[v0.y]] ELSE [l[v0.y]]]]; ENDCASE => { u: Vec=Normalize[Vector.Sub[v1^,v0^]]; RETURN[zone.NEW[Line = [oblique[u: u, d: Vector.Cross[v0^,u]]]]]; }; }; Vertex: TYPE = RECORD[v: Vec, dis: REAL] _ [[0,0],0]; Distance: PROC[line: LineRef, v: Vector.Vec] RETURNS[REAL] = INLINE { WITH l:line SELECT FROM u => RETURN[l.x-v.x]; d => RETURN[v.x-l.x]; l => RETURN[l.y-v.y]; r => RETURN[v.y-l.y]; oblique => RETURN[l.d-Vector.Cross[v,l.u]]; ENDCASE => ERROR; }; Intersect: PROC[line: LineRef, old,new: POINTER TO Vertex] RETURNS[Vec] = --INLINE-- { r: REAL=old.dis/(old.dis-new.dis); w: Vec=Vector.Add[old.v,Vector.Mul[Vector.Sub[new.v,old.v],r]]; WITH l:line SELECT FROM u,d => RETURN[[x: l.x, y: w.y]]; l,r => RETURN[[x: w.x, y: l.y]]; oblique => RETURN[w]; ENDCASE => ERROR; }; -- Operations on an Edge PData: PUBLIC TYPE = RECORD [ line: LineRef, ipoly,opoly: Poly.Handle, ipipe,opipe: Pipe.Handle ]; PDataRef: TYPE = LONG POINTER TO PData; pprocs: LONG POINTER TO READONLY Pipe.Procs = zone.NEW[Pipe.Procs = [ Put: PPut, Free: PFree ]]; CNewPipe: PROC[self: Handle, ipipe, opipe: Pipe.Handle] RETURNS[Pipe.Handle] = { d: DataRef=self.data; p: PDataRef=zone.NEW[PData _ [ line: d.line, ipoly: Poly.New[], opoly: Poly.New[], ipipe: ipipe, opipe: opipe ]]; RETURN[zone.NEW[Pipe.Object _ [procs: pprocs, data: LOOPHOLE[p]]]]; }; PPut: PROC[self: Pipe.Handle, area: Area.Handle] = { p: PDataRef=LOOPHOLE[self.data]; vfirst,vnew,vold: Vertex; first: BOOLEAN_TRUE; DoVertex: PROC[v: Vector.Vec] = { vnew_[v: v, dis: Distance[p.line,v]]; IF first THEN { vfirst_vnew; first_FALSE } ELSE DoEdge[p,@vold,@vnew]; vold_vnew; }; Area.Vertices[area,DoVertex]; DoEdge[p,@vold,@vfirst]; Area.Free[@area]; Pipe.Put[p.ipipe,Poly.NewArea[p.ipoly]]; Pipe.Put[p.opipe,Poly.NewArea[p.opoly]]; }; DoEdge: PROC[p: PDataRef, old,new: POINTER TO Vertex] = { OPut: PROC[v: Vec] = INLINE { Poly.Put[p.opoly,v] }; IPut: PROC[v: Vec] = INLINE { Poly.Put[p.ipoly,v] }; SELECT Real.FComp[old.dis,0] FROM <0 => { OPut[old.v]; SELECT Real.FComp[new.dis,0] FROM <0 => NULL; =0 => OPut[new.v]; >0 => { w: Vec_Intersect[p.line,old,new]; OPut[w]; IPut[w] }; ENDCASE; }; =0 => { SELECT Real.FComp[new.dis,0] FROM <0 => OPut[old.v]; =0 => NULL; >0 => IPut[old.v]; ENDCASE; }; >0 => { IPut[old.v]; SELECT Real.FComp[new.dis,0] FROM <0 => { w: Vec_Intersect[p.line,old,new]; IPut[w]; OPut[w] }; =0 => IPut[new.v]; >0 => NULL; ENDCASE; }; ENDCASE; }; PFree: PROC[self: Pipe.Handle] = { p: PDataRef_LOOPHOLE[self.data]; Pipe.Free[@p.ipipe]; Pipe.Free[@p.opipe]; Poly.Free[@p.ipoly]; Poly.Free[@p.opoly]; zone.FREE[@p]; zone.FREE[@self]; }; CFree: PROC[self: Handle] = { d: DataRef_self.data; zone.FREE[@d.line]; zone.FREE[@d]; zone.FREE[@self]; }; }.(670)