Scene: TYPE = REF SceneObj;
SceneObj: TYPE = DisplayList3d.SceneObj;
AssemblyList: TYPE = REF AssemblyListObj;
AssemblyListObj: TYPE = DisplayList3d.AssemblyListObj;
PointSetOp: TYPE = CSG.PointSetOp;-- {union, intersection, difference}
Assembly: TYPE = REF AssemblyObj;
AssemblyObj: TYPE = DisplayList3d.AssemblyObj;
Camera: TYPE = CSGGraphics.Camera;
MasterObject: TYPE = REF MasterObjectRec;
MasterObjectRec: TYPE = DisplayList3d.MasterObjectRec;
CSGTree: TYPE = REF CSGTreeObj;
CSGTreeObj: TYPE = CSG.CSGTreeObj;
Primitive: TYPE = REF PrimitiveObj;
PrimitiveObj: TYPE = CSG.PrimitiveObj;
Matrix4by4: TYPE = Matrix3d.Matrix4by4;
SurfaceArray: TYPE = REF SurfaceArrayObj;
SurfaceArrayObj: TYPE = CSG.SurfaceArrayObj;-- ARRAY[1..maxSceneDepth] OF Surface;
Surface: TYPE = REF ANY; -- may be RectSurface, TubeSurface, DiskSurface, or ShellSurface (of BasicObject3d), etc.
Composite: TYPE = REF CompositeObj;
CompositeObj: TYPE = CSG.CompositeObj;
SceneToTree:
PUBLIC
PROC [scene: Scene, camera: Camera]
RETURNS [tree: CSGTree] = {
Here's the plan: Each assembly list has an associated PointSetOp. If this op is null, it defaults to "union". Intersection means the intersection of all objects on the assembly list. Union is the union of all of them. Difference is the first one minus all of the others.
topAssembly: Assembly;
topNode: REF ANY;
SVTransforms.TellAboutCameraAndWorld[scene.assembly, camera, scene];
Preprocess the scene to make sure all the assemblies know where they are so they can tell the primitives at PrimitiveFromAssembly time (see BasicObject3dImpl.mesa for example)
topAssembly ← scene.assembly;
topNode ← AssemblyToNode[topAssembly];
tree ← CSG.MakeCSGTree[topNode, scene.backgroundColor, scene.shadows];
};
AssemblyToNode:
PROC [assembly: Assembly]
RETURNS [node:
REF
ANY] = {
If assembly is a primitive assembly, return a primitive CSG node. Otherwise, call AssemblyListToNode on its children and return the resulting tree.
IF assembly = NIL THEN RETURN[ NIL ];
WITH assembly.object
SELECT
FROM
mo: MasterObject => {
newPrim: Primitive;
newPrim ← SVPrimitive.FromAssembly[assembly];
node ← newPrim;
RETURN};
alist: AssemblyList => {
node ← AssemblyListToNode[alist, assembly.name];
RETURN};
ENDCASE => ERROR;
}; -- end of AssemblyToNode
AssemblyListToNode:
PROC [assemblyList: AssemblyList, name: Rope.
ROPE]
RETURNS [node:
REF
ANY] = {
list: LIST OF Assembly ← assemblyList.list;
treeList: LIST OF REF ANY;
We have a list of composite assemblies and/or primitive assemblies. Turn this into a list of Composites, Primitives and NILs:
treeList ← AssemblyListToTreeList[list];
Now we will inspect our list in order to combine the trees we have made.
If there are no children, then this node is NIL. It has no effect on the ray tracing.
IF treeList = NIL THEN RETURN[ NIL ];
If there is only one item in the list then the node for this assembly is the node produced for its son.
IF treeList.rest =
NIL
THEN {
node ← treeList.first;
RETURN}
ELSE {
-- Inspect the treeList more carefully.
If all of the children are NIL, so is this node.
IF AllAreNil[treeList] THEN RETURN[NIL];
If the operation is intersection and any are NIL then so is the node.
IF assemblyList.pointSetOp = intersection AND AnyAreNIL[treeList] THEN RETURN[ NIL ];
IF the first is NIL and the operation is difference then the node is NIL.
IF treeList.first = NIL AND assemblyList.pointSetOp = difference THEN RETURN[ NIL ];
We have handled all cases which involve NILs. For all other cases, we should ignore them, so we will remove them now:
treeList ← SpliceOutNILs[treeList];
At this point, we must reconsider the possibility that we may have a null list or single member list.
IF treeList = NIL THEN RETURN[NIL];
IF treeList.rest =
NIL
THEN {
node ← treeList.first;
RETURN}
ELSE {
Since it is now clear that this node has more than one child, we make n-1 Composite nodes for it (if there are n children remaining).
SELECT assemblyList.pointSetOp
FROM
union => node ← MakeUnionNode[treeList, name, 1];
intersection => node ← MakeIntersectionNode[treeList, name, 1];
difference => node ← MakeDifferenceNode[treeList, name, 1];
ENDCASE => ERROR;
}; -- end ELSE
}; -- end of ELSE
}; -- end of AssemblyListToNode
MakeUnionNode:
PROC [treeList:
LIST
OF
REF
ANY, name: Rope.
ROPE, level:
NAT]
RETURNS [node:
REF
ANY] = {
In the top level call to MakeUnionNode, treeList should have at least 2 members and none of its members should be NIL.
leftNode, rightNode: REF ANY;
intermediateName: Rope.ROPE;
IF treeList = NIL THEN RETURN[ NIL];
IF treeList.rest = NIL THEN RETURN [treeList.first];
leftNode ← treeList.first;
rightNode ← MakeUnionNode[treeList.rest, name, level + 1];
intermediateName ← Rope.Concat [name, Convert.ValueToRope[[unsigned[level]]]];
node ← NEW[CompositeObj ← [intermediateName, union, leftNode, rightNode]];
}; -- end of MakeUnionNode
MakeIntersectionNode:
PROC [treeList:
LIST
OF
REF
ANY, name: Rope.
ROPE, level:
NAT]
RETURNS [node:
REF
ANY] = {
In the top level call to MakeIntersectionNode, treeList should have at least 2 members and none of its members should be NIL.
leftNode, rightNode: REF ANY;
intermediateName: Rope.ROPE;
IF treeList = NIL THEN RETURN[ NIL];
IF treeList.rest = NIL THEN RETURN [treeList.first];
leftNode ← treeList.first;
rightNode ← MakeIntersectionNode[treeList.rest, name, level + 1];
intermediateName ← Rope.Concat [name, Convert.ValueToRope[[unsigned[level]]]];
node ← NEW[CompositeObj ← [intermediateName, intersection, leftNode, rightNode]];
}; -- end of MakeIntersectionNode
MakeDifferenceNode:
PROC [treeList:
LIST
OF
REF
ANY, name: Rope.
ROPE, level:
NAT]
RETURNS [node:
REF
ANY] = {
In the top level call to MakeDifferenceNode, treeList should have at least 2 members and none of its members should be NIL.
leftNode, rightNode: REF ANY;
intermediateName: Rope.ROPE;
leftNode ← treeList.first;
rightNode ← MakeUnionNode[treeList.rest, name, level + 1];
intermediateName ← Rope.Concat [name, Convert.ValueToRope[[unsigned[level]]]];
node ← NEW[CompositeObj ← [intermediateName, difference, leftNode, rightNode]];
}; -- end of MakeDifferenceNode
AssemblyListToTreeList:
PROC [list:
LIST
OF Assembly]
RETURNS [treeList:
LIST
OF
REF
ANY] = {
If there are no children, then this node is NIL. It has no effect on the ray tracing.
IF list = NIL THEN RETURN[ NIL ];
Go down the list turning each primitive or composite assembly into a Composite or Primitive.
treeList ← CONS[AssemblyToNode[list.first], AssemblyListToTreeList[list.rest]];
}; -- end of AssemblyListToNodeNoNILs
AllAreNil:
PRIVATE
PROC [list:
LIST
OF
REF
ANY]
RETURNS [
BOOL] = {
FOR l:
LIST
OF
REF
ANY ← list, l.rest
UNTIL l =
NIL
DO
IF l.first # NIL THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
};
AnyAreNIL:
PRIVATE
PROC [list:
LIST
OF
REF
ANY]
RETURNS [
BOOL] = {
FOR l:
LIST
OF
REF
ANY ← list, l.rest
UNTIL l =
NIL
DO
IF l.first = NIL THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
SpliceOutNILs:
PRIVATE
PROC [list:
LIST
OF
REF
ANY]
RETURNS [compressed:
LIST
OF
REF
ANY] = {
IF list = NIL THEN RETURN[ NIL];
IF list.first # NIL THEN compressed ← CONS[list.first, SpliceOutNILs[list.rest]]
ELSE compressed ← SpliceOutNILs[list.rest];
};
---- ---- ---- ----
---- ---- ---- ----
ListTree:
PUBLIC
PROC [outHandle:
IO.
STREAM, tree: CSGTree] = {
indent: NAT ← 0;
node: REF ANY ← tree.son;
ListNode[outHandle, node, indent];
};
ListNode:
PROC [outHandle:
IO.
STREAM, node:
REF
ANY, indent:
NAT] = {
WITH node
SELECT
FROM
prim: Primitive => ListPrimitive[outHandle, prim, indent];
comp: Composite => ListComposite[outHandle, comp, indent];
ENDCASE => ERROR;
};
ListPrimitive:
PROC [outHandle:
IO.
STREAM, prim: Primitive, indent:
NAT] = {
FOR i: NAT IN[1..indent] DO outHandle.PutChar[IO.TAB] ENDLOOP;
outHandle.PutF["Primitive: %g\n",[rope[prim.name]]];
};
ListComposite:
PROC [outHandle:
IO.
STREAM, comp: Composite, indent:
NAT] = {
op: Rope.ROPE;
FOR i: NAT IN[1..indent] DO outHandle.PutChar[IO.TAB] ENDLOOP;
SELECT comp.operation
FROM
union => op ← "union";
intersection => op ← "intersection";
difference => op ← "difference";
ENDCASE => ERROR;
outHandle.PutF["Composite: %g op: %g\n",[rope[comp.name]], [rope[op]]];
ListNode[outHandle, comp.leftSolid, indent + 1];
ListNode[outHandle, comp.rightSolid, indent + 1];
};
FindNodeFromName:
PUBLIC
PROC [tree:
REF
ANY, name: Rope.
ROPE]
RETURNS [node:
REF
ANY, success:
BOOL] = {
WITH tree
SELECT
FROM
c: Composite => {[node, success] ← FindNodeFromNameInComposite[c, name]; RETURN};
p: Primitive => {[node, success] ← FindNodeFromNameInPrimitive[p, name]; RETURN};
ENDCASE => ERROR;
};
FindNodeFromNameInComposite:
PROC [c: Composite, name: Rope.
ROPE]
RETURNS [node:
REF
ANY, success:
BOOL] = {
IF Rope.Equal[c.name, name, TRUE] THEN RETURN[c, TRUE];
[node, success] ← FindNodeFromName[c.leftSolid, name];
IF success THEN RETURN;
[node, success] ← FindNodeFromName[c.rightSolid, name];
IF success THEN RETURN
ELSE RETURN[NIL, FALSE];
};
FindNodeFromNameInPrimitive:
PROC [p: Primitive, name: Rope.
ROPE]
RETURNS [node:
REF
ANY, success:
BOOL] = {
IF p.name = name THEN RETURN[p, TRUE]
ELSE RETURN[NIL, FALSE];
};