INTERFACE Scene; IMPORT HLR3, Wr, SceneArrangement; FROM SceneArrangement IMPORT Point, Line, Plane; TYPE T = RECORD v: VertexList; e: EdgeList; f: FaceList; END; CONST Empty = T{NIL,NIL,NIL}; TYPE VertexList = REF RECORD v: REF Vertex; rest: VertexList; END; EdgeList = REF RECORD e: REF Edge; rest: EdgeList; END; FaceList = REF RECORD f: REF Face; rest: FaceList; END; CONST MaxLights = 4; TYPE Vertex = RECORD (* Vertex *) num: CARDINAL; (* Serial number *) point: REF Point; (* The point in the arrangement *) org: REFANY; (* Original element *) mark: BOOLEAN; (* Used by Close *) END; Edge = RECORD (* Edge of fragment *) num: CARDINAL; (* Serial number *) line: REF Line; (* Supporting line *) vert: VertexPair; (* Endpoints *) org: REFANY; (* Original element *) mark: BOOLEAN; (* Used by Close *) part: EdgePair; (* (Work) Origin and destination pieces of edge *) cut: REF Vertex; (* (Work) Cut vertex, used by CutScene *) END; VertexPair = ARRAY [0..1] OF REF Vertex; EdgePair = ARRAY [0..1] OF REF Edge; Face = RECORD (* A fragment of a face *) num: CARDINAL; (* Serial number *) plane: REF Plane; (* Supporting plane *) edge: REF EdgeArray; (* Edges of fragment *) edir: REF EDirArray; (* Edge directions *) lights: LightSet; (* Lights that see this face *) org: REFANY; (* Original element *) mark: BOOLEAN; (* Used by Close *) END; EdgeArray = ARRAY OF REF Edge; EDirArray = ARRAY OF BITS 8 FOR EDir; EDir = [0..1]; (* Which "vert" is the origin. *) LightSet = ARRAY [0..MaxLights-1] OF BOOLEAN; PROCEDURE MakeVertex( org: REFANY; READONLY point: REF Point; ): REF Vertex; PROCEDURE MakeEdge( org: REFANY; a, b: REF Vertex; line: REF Line; ): REF Edge; PROCEDURE MakeFace( org: REFANY; READONLY e: EdgeArray; READONLY ed: EDirArray; plane: REF Plane; lights: LightSet := LightSet{TRUE, ..} ): REF Face; PROCEDURE GatherEdges(fls: FaceList): EdgeList; (* Creates a list of all edges that are sides of the faces in "tls", without repetitions. *) PROCEDURE GatherVertices(els: EdgeList): VertexList; (* Creates a list of all vertices that are endpoints of the edges in "els", without repetitions. *) PROCEDURE CloseScene(VAR sc: T); (* A scene is {\em closed} if the sides of every face in "t" are listed in "e", and the endpoits of every edge in "e" are listed in "v". This procedure makes "sc" into a closed scene. Note: it reuses the nodes of "sc.t", "sc.e", "sc.l". *) TYPE Vertices = ARRAY OF REF Vertex; Planes = ARRAY OF HLR3.Plane; Sides = ARRAY OF HLR3.Sign; PROCEDURE ClipSceneToRegion( VAR in, bd, ot: T; (* (I/O) Outside, boundary, and inside elements *) READONLY plane: Planes; (* Clipping planes *) READONLY side: Sides; (* Which side of "plane[i]" contains the region *) inF, bdF, otF: BOOLEAN; (* Which parts to return *) debug: BOOLEAN := FALSE; (* TRUE to print diagnostics *) ); (* The lists "in", "bd", and "ot" are assumed to contain the elements of a scene "S" that lie respectively inside, on the boundary, and outside some region "R0" of space. The procedure intersects that region with the "side[i]" halfspace of each "plane[i]", resulting in a new region "R1"; and clips the elements of "S" against "R1", returning the clipped elements in "in", "bd", and "ot". The "in" parts are returned only if "inF = TRUE"; otherwise those parts are discarded, and the "in" lists are set to NIL. In the same way, "bdF" and "otF" control the disposal of the "bd" and "ot" parts. If the region is not trivial (i.e. it has at least one plane), and at least one of "inF", "bdF", and "otF" is TRUE, the complete "in" and "bd" lists must be provided, since they are needed to compute the desired output. *) PROCEDURE CutSceneByPlane( VAR sc: T; (* Scene to cut *) READONLY plane: HLR3.Plane; (* Cutting plane *) side: HLR3.Sign := +1; (* Multiplies "plane" *) READONLY null: Vertices; (* Vertices known to be on "plane" *) negF, zerF, posF: BOOLEAN; (* Which parts to return *) VAR neg, zer, pos: T; (* (I/O): Negative, zero, and positive parts. *) ); (* Cuts the elements of "sc" by the given "plane" (reversed if "side=-1"), and prepends the negative, zero, and positive parts onto "neg", "zer", and "pos", respectively. The negative parts are returned only if "negF = TRUE"; otherwise those parts are discarded, and the "neg" scene is not changed. In the same way, "zerF" and "posF" control the disposal of the zero and positive parts. The "null" vertices are assumed to lie on the given plane. The signs of all other vertices are evaluated numerically. Beware that the variable "sc" is cleared, and the nodes of the input lists may be reused in the output lists. The variables "sc", "neg", "zer", and "pos" need not be distinct from each other. *) PROCEDURE CopyScene(src: T; VAR dst: T); PROCEDURE CopyVertexList(src: VertexList; VAR dst: VertexList); PROCEDURE CopyEdgeList(src: EdgeList; VAR dst: EdgeList); PROCEDURE CopyFaceList(src: FaceList; VAR dst: FaceList); (* Make a top-level copy of "src", prepends it to "dst": *) PROCEDURE MoveScene(VAR src: T; VAR dst: T); PROCEDURE MoveVertexList(VAR src: VertexList; VAR dst: VertexList); PROCEDURE MoveEdgeList(VAR src: EdgeList; VAR dst: EdgeList); PROCEDURE MoveFaceList(VAR src: FaceList; VAR dst: FaceList); (* Destructively prepend of "src" onto "dst": *) PROCEDURE CountVertices(lst: VertexList): CARDINAL; PROCEDURE CountEdges(lst: EdgeList): CARDINAL; PROCEDURE CountFaces(lst: FaceList): CARDINAL; (* Counts elements in scene. *) PROCEDURE PrintCounts(wr: Wr.T; sc: T); (* Prints size of scene. *) PROCEDURE PrintVertex(wr: Wr.T; v: REF Vertex); PROCEDURE PrintEdge(wr: Wr.T; e: REF Edge); PROCEDURE PrintFace(wr: Wr.T; e: REF Face); PROCEDURE PrintScene(wr: Wr.T; sc: T); (* Prints scene in readable format. *) PROCEDURE PrintNum(wr: Wr.T; r: REFANY; pad: CARDINAL := 0); PROCEDURE PrintBoolean(wr: Wr.T; b: BOOLEAN); PROCEDURE PrintPoint(wr: Wr.T; READONLY p: HLR3.Point); (* Useful hacks... *) PROCEDURE PlotScene( filename: TEXT; sc: T; xmin, xmax: LONGREAL; ymin, ymax: LONGREAL; READONLY w2i: HLR3.PMap; ); (* Generates a Postscript plot of the scene, useful for debugging purposes. *) END Scene.