Plan 9 from Bell Labs’s /usr/web/sources/contrib/fernan/nhc98/tests/nofib/real/bspt/BSPT.lhs

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


> module BSPT

	Module that defines Binary Space Partitioning Trees and basic 
	operations thereon.

>	(	BSPT(..),Status(..),Point,Region,Line,
>		Face,Faces,buildBSPT,bsp',bsp'',mkCell, partFaces,
>		scanLine,countLeaves,classifyPoint,area, 
>		foldBSPT)

> where
> import EuclidGMS (	Location(..),Partition,Region,
>			 mkPart,getPart,newRegion,location,renderBorder,
>			 bisect,toBack,findVertices,flip_YORK,
>			 Point(..),Line,Face(..),Faces,Halfspace(..),
>			 space,convert,triangleArea,Segment )
> import GeomNum 
> import Stdlib (mapcat,const3)
> import Libfuns


	A binary space partition tree is either:
		A leaf node tagged Cell with three arguments--
			1. Status (as defined below)
				describes the state of the convex cell
			2. Region indicates the area described by the
				cell
			3. Gives the Area of the cell (used as a memoing
				argument).
		A branch node tagged BSP with the following arguments
			1. a Line equation description of the partitioning 
				of space at this node. 
			2. a triple that stores the faces that lie in the plane
				described by 1. an indication of the area 
				covered the tree whose root is this node and 
				the section of the partition that runs through the
				region.
			3/4. BSP trees representing the Rear and Fore 
				halfspaces formed by the partition at this node.

> data BSPT = Cell Status Region Numb | 
>		BSP Partition (Faces,Region) BSPT BSPT -- deriving (Text)


	Status is an enumeration of classifications of points with
	respect to objects.

> data Status = In | Out | On deriving (Eq,Show{-was:Text-})

	A partitioning is a triple of Faces representing the faces
	(w.r.t. a partition) in the rear halfspace, coincident to, and 
	in the fore halfspace respectively.
	
> type Partitioning = (Faces,Faces,Faces)



	buildBSPT : Creates a BSPT for a polygon defined by a B-rep
			(i.e. a list of faces). Building is done by
			auxiliary buildBSPTAux.

> buildBSPT :: Faces -> BSPT
> buildBSPT = buildBSPTAux Out renderBorder 

	buildBSPTAux: Builds a BSPT from the first argument list of 
			faces. The second argument carries the current
			region in consideration and is used for 
			augmenting created nodes and cells. The
			third argument indicates the default value
			of the branch and is In when building the
			left subtree and Out when building the right.
			The function heuristic selects a single face according
			to some determined rule to form the partition at the node.
			convert takes the Face and creates the equation for the
			line that embeds that face.
			partFaces creates a partitioning of the remaining 
			polygon face w.r.t. the partition chosen.

> buildBSPTAux :: Status -> Region -> Faces -> BSPT
> buildBSPTAux status region [] = mkCell status region 
> buildBSPTAux _ region faces   = par right (seq left (BSP partition (coin,region) left right))
>                       where 
>			left = buildBSPTAux In (newRegion region partition) rear
> 			right = buildBSPTAux Out (newRegion region (flip_YORK partition)) fore
>			(rear,coin,fore) = partFaces part faces
>			partition = mkPart region part
>			part = heuristic faces


	bsp' : Used to construct a BSPT when there is a possibility that
			both children are cells with the same status.
			When this occurs the cells are condensed.

> bsp' :: Partition -> (Faces,Region) -> BSPT -> BSPT -> BSPT
> bsp' part (faces,region) (Cell x _ a) (Cell y _ b) | x==y = Cell x region (a+b)
> bsp' part nodeInfo left right = BSP part nodeInfo left right


	bsp'' : Used to construct a BSPT when there is a possibility of 
			condensing as above and, additionally, there may
			be a need to update the faces that lie in the 
			sub-hyperplane formed by the partition.
			bsp'' also checks that a partition is needed.
			A partition is needed if there are faces stored
			in its hyperplane. bsp'' simplifies the tree when
			such a partition occurs, removing the redundent partition.

> bsp'' :: Partition -> (Faces, Region) -> BSPT -> BSPT -> BSPT
> bsp'' part (faces,region) left right 
>		= if newfaces==[] 
>	 	  then simplify part region left right 
>		  else BSP part (newfaces,region) left right
>			where 
>			newfaces = updateFaces left right faces

	simplify : implements the removal of a redundant partition. 
			Note need for region to be passed in. So that
			replacement node represents the correct area.

> simplify :: Partition -> Region -> BSPT -> BSPT -> BSPT
> simplify _ region (Cell _ _ _) (BSP part (faces,_) left right) 
>		= BSP (mkPart region (getPart part)) (faces,region) left right
> simplify _ region (BSP part (faces,_) left right) (Cell _ _ _) 
>		= BSP (mkPart region (getPart part)) (faces,region) left right
> simplify part region tree1 tree2 = bsp' part ([],region) tree1 tree2

	mkCell: construction function defined for simplification.
		Area calculation done by default method.

> mkCell :: Status -> Region -> BSPT
> mkCell status region = Cell status region (areaRegion region)


	partFaces : Splits a list of faces into three groups.
			Those lying in the rear halfspace defined by part.
			Those lying in the sub-hyperplane defined by part.
			Those lying in the fore halfspace defined by part.
			The function location determines the which case 
			applies for each face in the list.
			Note that when the face intersects the partition,
			that face is bisect(ed) and the two resulting faces
			added to the appropriate group.

> partFaces :: Line -> Faces -> (Faces,Faces,Faces) 
> partFaces part [] = ([],[],[])
> partFaces part (face@(Fc section _):faces) 
>			      = par rest 
>				(case (location part section) of
> 					Coincident -> (rear,face:coin,fore)
> 					Intersects -> (rearHalf:rear,coin,foreHalf:fore)
> 					ToTheRear  -> (face:rear,coin,fore)
> 					ToTheFore  -> (rear,coin,face:fore))
> 				where
> 				(rear,coin,fore) = rest
>				rest = partFaces part faces
> 				(rearHalf,foreHalf) = bisect face part


	heuristic : decides according to some rule which faces to pick
			to form the current partition. Returns this face and the rest 
			as a pair.
			Currently is selects the first.
			When going parallel it will need to split the faces
			into two equal(ish) sized groups.

> heuristic :: Faces -> Line
> heuristic (Fc _ l:_) = l


	updateFaces : Takes a list of faces and produces a new list
			where the new list is the old list with segments
			of lines removed that no longer live on the edge
			of the object. It does this by first classfiying 
			each edge with respect to the left subtree.
			These classification are passed down into the right
			subtree which as it classifies the face can decide
			whether it lies on the edge or not. This is done
			on the basis that to lie on the edge a faces 
			classification most differ for each subtree.

> updateFaces :: BSPT -> BSPT -> Faces -> Faces
> updateFaces left right = mapcat (rubout right).classifyFace left


	classifyFace : produces a list of face-classification pairs
			formed by taking the segments of each face 
			with respect a BSP tree and tagging appropriate
			at the Cell nodes.

> classifyFace :: BSPT -> Faces -> [(Face,Status)]
> classifyFace tree = mapcat (segments tagStatus tree) 
> 			where
> 			tagStatus x face = [(face,x)]


	rubout : Effectively classfies to the right and filters away faces
			that have the same classification as they did to the
			right.

> rubout :: BSPT -> (Face,Status) -> Faces
> rubout tree (face,x) = segments (erase x) tree face
> 	where erase x y face | x==y = []
> 			      | otherwise = [face]


	segments : Higher order generalised function. 
			First argument is a cell operation.
			The face defined in the third argument
			is cut into segments by a decent of the BSP tree
			defined in the second argument. A segment of a face
			reaching a Cell node has the cell operation performed
			on it. 
			For example to segment a face into part lying in the different
			concave cells defined by the BSP tree. Use
				segments ignoreStatus
					where ignoreStatus a b = b

> segments :: (Status->Face->[a]) -> BSPT -> Face -> [a]
> segments cellop (Cell status _ _) face = cellop status face
> segments cellop (BSP part@(Fc _ p) _ left right) face@(Fc fs _) 
>		= case (location p fs) of
> 			Coincident -> cellop In face 
> 			Intersects -> segments cellop left leftside ++ 
> 					segments cellop right rightside
> 			ToTheRear  -> segments cellop left face
> 			ToTheFore  -> segments cellop right face
> 		where
> 		(leftside,rightside) = bisect face p


	scanLine : Uses segments to filter away parts of the face given
			that are not in the object.
			filterInside ignores faces in Out cells.

> scanLine :: BSPT -> Face -> Faces
> scanLine = segments filterInside
> 		where
> 		filterInside In face = [face]
> 		filterInside Out _ = []


	foldBSPT : folds up a BSPT applying nodeop to the partition, node
			data and children at nodes and applying cellop to the 
			leafs.
			
> foldBSPT :: (Status->Region->Numb->a)->(Partition->(Faces,Region)->a->a->a)->BSPT->a
> foldBSPT cellop nodeop (Cell x r a) = cellop x r a
> foldBSPT cellop nodeop (BSP part nodeinfo left right)
>               = nodeop part nodeinfo left' right'
>                 where 
>		        left' = f left 
>			right' = f right
>			f = foldBSPT cellop nodeop 

	countLeaves : Uses foldBSPT to fold up the tree into a count 
			of the number of Leaves. cellop counts one for 
			each leaf. Nodeop is simply addition, but we first
			arrange to drop the partition arguments.

> countLeaves :: BSPT -> Int
> countLeaves = foldBSPT (const3 1) plus
>		where
>		plus _ _ = (+)

	area: determines the area of a BSPT represented object
		does this by folding plus over the tree with In cells
		counting their value Out cells counting zero.

> area :: BSPT -> Numb
> area = foldBSPT sumInRegions plus 
>		where 
>		sumInRegions In _ a = a
>		sumInRegions _ _ _ = 0
>		plus _ _ = (+)

	areaRegion - calculates the area of an convex region.

> areaRegion :: Region -> Numb
> areaRegion = sum.map triangleArea.triangles.findVertices

	triangles - splits a convex region into triangles

> triangles :: [Point] -> [[Point]]
> triangles [p1,p2] = []
> triangles [p1,p2,p3] = [[p1,p2,p3]]
> triangles (p1:p2:ps) = if left/=[] && right /=[] then
>                               triangles (p1:p2:left) ++ triangles (p1:p2:right)
>                        else triangles (p1:ps++[p2])
>                              where
>                              (left,right) = partPoints (convert p1 p2) ps



	partPoints - partition a list of points w.r.t. a line

> partPoints :: Line -> [Point] -> ([Point],[Point])
> partPoints eqn [] = ([],[])
> partPoints eqn (p:pts) = if toBack p eqn 
>				then (p:left,right) 
>				else (left,p:right)
> 				where 
> 				(left,right) = partPoints eqn pts


	classifyPoint - point classification w.r.t. object

> classifyPoint :: Point -> BSPT -> Status
> classifyPoint pt = foldBSPT status (deter pt) 
>                       where
>                       status s _ _ = s
>			deter pt (Fc _ part) _ = deter' (space part pt)
>			      where 
>			      deter' Fore _ x = x
>			      deter' Rear x _ = x
>			      deter' Coin x y | x==y = x	-- was: At (no such thing)
>					      | otherwise = On

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].