Index: /trunk/VUT/GtpVisibilityPreprocessor/scripts/default.env
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/scripts/default.env	(revision 310)
+++ /trunk/VUT/GtpVisibilityPreprocessor/scripts/default.env	(revision 312)
@@ -9,7 +9,7 @@
 #	filename vienna.x3d
 #	filename ../data/vienna/vienna-simple.x3d
-	filename ../data/vienna/vienna-buildings.x3d
+#	filename ../data/vienna/vienna-buildings.x3d
 #	filename ../data/vienna/viewcells-25-sel.x3d
-#	filename ../data/atlanta/atlanta2.x3d
+	filename ../data/atlanta/atlanta2.x3d
 #	filename ../data/soda/soda.dat
 #	filename ../data/soda/soda5.dat
@@ -56,14 +56,14 @@
 
 Sampling {
-	totalSamples	1000000
-	samplesPerPass  5
+	totalSamples	100000
+	samplesPerPass  10
 }
 
 ViewCells {
 	hierarchyType bspTree
+	height 5.0
 	#hierarchyType kdTree
 	#hierarchyType sceneDependent
 #	filename ../data/atlanta/atlanta_viewcells_large.x3d
-#	filename ../data/atlanta/atlanta_viewcells_large2.x3d
 	filename ../data/vienna/viewcells-25-sel.x3d
 #	filename ../data/vienna/viewcells-25.x3d
@@ -84,5 +84,5 @@
 	# vertical axis        = 64
 	
-	splitPlaneStrategy 66
+	splitPlaneStrategy 8
 	# least splits + balanced polygons
 	#splitPlaneStrategy 12
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCell.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCell.cpp	(revision 308)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCell.cpp	(revision 312)
@@ -69,12 +69,9 @@
 	// add base vertices and calculate top vertices
 	for (int i = 0; i < 3; ++i)
-	{
-		 mesh->mVertices.push_back(baseTri.mVertices[i]);
-		 topTri.mVertices[i] = baseTri.mVertices[i] + height * triNorm;
-	}
-
+		 mesh->mVertices.push_back(baseTri.mVertices[i] + height * 0.5 * triNorm);
+	
 	// add top vertices	
 	for (int i = 0; i < 3; ++i)
-		mesh->mVertices.push_back(topTri.mVertices[i]);
+		mesh->mVertices.push_back(baseTri.mVertices[i] + height * triNorm);
 	
 	mesh->Preprocess();
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParser.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParser.cpp	(revision 294)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParser.cpp	(revision 312)
@@ -385,5 +385,6 @@
 //  StdInParseHandlers: Constructors and Destructor
 // ---------------------------------------------------------------------------
-X3dViewCellsParseHandlers::X3dViewCellsParseHandlers(ViewCellContainer *viewCells) :
+X3dViewCellsParseHandlers::X3dViewCellsParseHandlers(ViewCellContainer *viewCells, 
+													 float viewCellHeight) :
   mElementCount(0)
   , mAttrCount(0)
@@ -391,4 +392,5 @@
   , mSpaceCount(0)
   , mViewCells(viewCells)
+  , mViewCellHeight(viewCellHeight)
 {
 }
@@ -505,13 +507,12 @@
 
 
-    for (int i = 0; i < mCurrentVertexIndices.size(); i+=3)
+    for (int i = 0; i < mCurrentVertexIndices.size(); i += 3)
 	{
-		Triangle3 baseTri(vertices[mCurrentVertexIndices[i]], 
-						  vertices[mCurrentVertexIndices[i+1]],
-						  vertices[mCurrentVertexIndices[i+2]]);
+		Triangle3 baseTri(vertices[mCurrentVertexIndices[i + 0]], 
+						  vertices[mCurrentVertexIndices[i + 1]],
+						  vertices[mCurrentVertexIndices[i + 2]]);
 
 		// create view cell from base triangle
-		const float height = 10;
-		mViewCells->push_back(ViewCell::ExtrudeViewCell(baseTri, height));
+		mViewCells->push_back(ViewCell::ExtrudeViewCell(baseTri, mViewCellHeight));
 
 		Mesh *mesh = mViewCells->back()->GetMesh();
@@ -640,5 +641,5 @@
   //  to do.
   //
-  X3dViewCellsParseHandlers handler(&viewCells);
+  X3dViewCellsParseHandlers handler(&viewCells, mViewCellHeight);
   parser->setDocumentHandler(&handler);
   parser->setErrorHandler(&handler);
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/Pvs.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/Pvs.h	(revision 311)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/Pvs.h	(revision 312)
@@ -98,6 +98,7 @@
 
 typedef std::map<KdNode *, PvsData<KdNode *>, LtSample<KdNode *> > KdPvsMap;
+typedef std::map<Intersectable *, PvsData<Intersectable *>, LtSample<Intersectable *> > ViewCellPvsMap;
+typedef PvsData<Intersectable *> ViewCellPvsData;
 typedef PvsData<KdNode *> KdPvsData;
-
 //typedef Pvs<KdNode *> KdPvs;
 typedef Pvs<Intersectable *> ViewCellPvs;
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.h	(revision 308)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.h	(revision 312)
@@ -25,5 +25,5 @@
 	Polygon3(const VertexContainer &vertices);
 	Polygon3(MeshInstance *parent);
-
+	
 	/** Copies all the vertices of the face.
 	*/
@@ -36,8 +36,12 @@
 	/** Splits polygon.
 		@param partition the split plane
-		@param front the front polygon
-		@param back the back polygon
+		@param front returns the front the front polygon
+		@param back returns the back polygon
+		@param splitPts returns the split points
 	*/
-	void Split(Plane3 *partition, Polygon3 *front, Polygon3 *back);
+	void Polygon3::Split(const Plane3 &partition, 
+						 Polygon3 &front, 
+						 Polygon3 &back, 
+						 VertexContainer &splitPts);
 
 	/** Returns the area of this polygon.
@@ -69,4 +73,6 @@
 	bool Valid() const; 
 
+	/** Returns the surface normal.
+	*/
 	Vector3 GetNormal() const;
 
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h	(revision 310)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h	(revision 312)
@@ -443,5 +443,5 @@
 		@returns number of polygons
 	*/
-	int AddMesh2Polygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent);
+	int AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent);
 
 	/** returns next candidate index and reorders polygons so no candidate is chosen two times
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/AxisAlignedBox3.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/AxisAlignedBox3.h	(revision 302)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/AxisAlignedBox3.h	(revision 312)
@@ -7,5 +7,4 @@
 #include "Plane3.h"
 
-class Plane3;
 class Ray;
 class Polygon3;
@@ -302,4 +301,12 @@
   float ProjectToSphereSA(const Vector3 &viewpoint, int *tcase) const;
 
+  /** Returns vertex indices of edge.
+  */
+  void GetEdge(const int edge, int  &aIdx, int &bIdx) const;
+
+  /** Bounds plane with box. Returns polygon resulting from the bounded
+	  plane.
+  */
+  Polygon3 *BoundPlane(const Plane3 &plane);
 
 #define __EXTENT_HACK
@@ -353,4 +360,7 @@
   static const int fsvertices[27][9];
 
+  // table storing the complementary edges of each edge
+  //static const int complEdgeTbl[12][3];
+
   // input and output operator with stream
   friend ostream& operator<<(ostream &s, const AxisAlignedBox3 &A);
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/UnigraphicsParser.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/UnigraphicsParser.cpp	(revision 179)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/UnigraphicsParser.cpp	(revision 312)
@@ -117,5 +117,5 @@
 
       // add vertices to the mesh vertex list
-      int index = currentMesh->mVertices.size();
+      int index = (int)currentMesh->mVertices.size();
       for (i=0; i < vertices.size(); i++, index++) {
 	currentMesh->mVertices.push_back(vertices[i]);
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/Camera.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/Camera.h	(revision 308)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/Camera.h	(revision 312)
@@ -24,5 +24,5 @@
     mWidth = 640;
     mHeight = 480;
-    mFovy = 60*M_PI/180.0f;
+    mFovy = 60.0*M_PI/180.0;
   }
   
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp	(revision 311)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp	(revision 312)
@@ -1160,4 +1160,8 @@
 		 "atlanta_viewcells_large.x3d");
 
+   RegisterOption("ViewCells.height",
+		 optFloat,
+		 "-view_cells_height=",
+		 "5.0");
 
   RegisterOption("BspTree.constructionMethod",
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/Exporter.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/Exporter.h	(revision 261)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/Exporter.h	(revision 312)
@@ -56,7 +56,10 @@
   virtual void 
   ExportViewCells(ViewCellContainer *viewCells) = 0;
-
+  virtual void 
+  ExportViewCell(ViewCell *viewCell) = 0;
   virtual void
   ExportIntersectable(Intersectable *object) = 0;
+
+  virtual void ExportBspSplits(const BspTree &tree) = 0;
 
   void SetExportRayDensity(const bool d) { mExportRayDensity = d; }
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp	(revision 311)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp	(revision 312)
@@ -173,4 +173,6 @@
 		Polygon3 *back_piece = NULL;
 	
+		VertexContainer splitVertices;
+
 		switch (classification)
 		{
@@ -192,5 +194,5 @@
 
 				//-- split polygon into front and back part
-				poly->Split(&mPlane, front_piece, back_piece);
+				poly->Split(mPlane, *front_piece, *back_piece, splitVertices);
 
 				++ splits; // increase number of splits
@@ -365,5 +367,5 @@
 
 	// extract polygons that guide the split process
-	mStat.polys += AddMesh2Polygons(viewCell->GetMesh(), *polys, viewCell);
+	mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell);
 	mBox.Include(viewCell->GetBox()); // add to BSP aabb
 
@@ -399,5 +401,5 @@
 				int splits = 0;
 		
-				// split viecell polygons with respect to split plane
+				// split viewcell polygons with respect to split plane
 				interior->SplitPolygons(tData.mPolygons, 
 										frontPolys, 
@@ -445,5 +447,6 @@
 				
 				dynamic_cast<BspLeaf *>(root)->SetViewCell(viewCell);
-		}
+			}
+
 			if (!mRoot) // tree empty => new root
 				mRoot = root;
@@ -452,5 +455,5 @@
 }
 
-int BspTree::AddMesh2Polygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent)
+int BspTree::AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent)
 {
 	FaceContainer::const_iterator fi;
@@ -481,5 +484,5 @@
 		{
 			mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
-			AddMesh2Polygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
+			AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
 		}
 	}
@@ -514,5 +517,5 @@
 		{
 			mBox.Include(object->GetBox()); // add to BSP tree aabb
-			AddMesh2Polygons(mesh, polys, mViewCell);
+			AddMeshToPolygons(mesh, polys, mViewCell);
 		}
 	}
@@ -545,26 +548,6 @@
 	mStat.polys = Copy2PolygonSoup(objects, *polys);
 
-	bool tmpStorePolys = mStoreSplitPolys;
-	mStoreSplitPolys = false;
-
 	// construct tree from polygon soup
 	Construct(polys, viewCells);
-
-	mStoreSplitPolys = tmpStorePolys;
-	// filter scene bounding box down the tree in order to store split polygons
-	if (mStoreSplitPolys)
-	{
-		Mesh *polyMesh = new Mesh();
-
-		for (int i = 0; i < 6; ++i)
-			polyMesh->AddRectangle(mBox.GetFace(i));
-
-		PolygonContainer *polys = new PolygonContainer();
-		 		AddMesh2Polygons(polyMesh, *polys, NULL);
-		
-		InsertPolygons(polys);
-
-		delete polyMesh;
-	}
 }
 
@@ -579,5 +562,4 @@
 	
 	BspTraversalData tData(new BspLeaf(), polys, 0, mViewCell);
-
 	tStack.push(tData);
 
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/Preprocessor.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/Preprocessor.cpp	(revision 310)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/Preprocessor.cpp	(revision 312)
@@ -27,5 +27,8 @@
 Preprocessor::LoadViewCells(const string filename)
 {
-	return X3dParser().ParseFile(filename, mViewCells);
+	X3dParser parser;
+	environment->GetFloatValue("ViewCells.height", parser.mViewCellHeight);
+	 
+	return parser.ParseFile(filename, mViewCells);
 }
 
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/X3dExporter.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/X3dExporter.h	(revision 292)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/X3dExporter.h	(revision 312)
@@ -69,5 +69,8 @@
   virtual void 
   ExportViewCells(ViewCellContainer *viewCells);
-static ViewCellContainer foundViewCells; // todo: delete later
+
+  virtual void ExportBspSplits(const BspTree &tree);
+
+  static ViewCellContainer foundViewCells; // todo: remove this
 protected:
   virtual void
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/main.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/main.cpp	(revision 310)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/main.cpp	(revision 312)
@@ -58,5 +58,13 @@
 	  p->BspTreeStatistics(Debug);
 	  p->Export("vc_bsptree2.x3d", false, false, true);
- 
+	  // export the bsp splits
+	  Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
+
+	  if (exporter) 
+	  {	
+		  Debug << "Exporting bsp splits" << endl;
+		  exporter->ExportBspSplits(*p->mBspTree);
+		  delete exporter;
+	  }
 #if 0
 	  //-- export the complementary view cells
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/X3dExporter.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/X3dExporter.cpp	(revision 311)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/X3dExporter.cpp	(revision 312)
@@ -115,5 +115,5 @@
 {
   // $$JB$$
-  // in the future check whether the mesh was not already exportet
+  // in the future check whether the mesh was not already exported
   // and use a reference to the that mesh instead
   ExportMesh(object->GetMesh());
@@ -610,2 +610,140 @@
   return true;
 }
+
+struct BspSplitData
+{
+	/// the current node
+	BspNode *mNode;
+
+	PolygonContainer *mPolygons;
+	vector<Plane3 *> mPlanes;
+	vector<bool> mSides;
+	bool mIsFront;
+
+	BspSplitData(BspNode *node, PolygonContainer *polys): 
+	mNode(node), mPolygons(polys), mIsFront(false)
+	{};	
+	BspSplitData(BspNode *node, 
+				 PolygonContainer *polys, 
+				 vector<Plane3 *> planes, 
+				 vector<bool> sides, 
+				 bool isFront): 
+	mNode(node), mPolygons(polys), mPlanes(planes), 
+	mSides(sides), mIsFront(isFront)
+	{};
+};
+
+void X3dExporter::ExportBspSplits(const BspTree &tree)
+{
+	int mask = Random(50000);
+	
+	std::stack<BspSplitData> tStack;
+
+	BspSplitData tData(tree.GetRoot(), new PolygonContainer());
+	tStack.push(tData);
+  
+	while (!tStack.empty())
+	{
+		// filter polygons donw the tree
+		BspSplitData tData = tStack.top();
+	    tStack.pop();	
+		
+		if (!tData.mNode->IsLeaf())
+		{
+			BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
+
+			tData.mPlanes.push_back(interior->GetPlane());
+			tData.mSides.push_back(tData.mIsFront);
+
+			// bounded plane is added to the polygons
+			Polygon3 *planePoly = tree.GetBoundingBox().BoundPlane(*tData.mPlanes.back());
+		
+			PolygonContainer *frontPolys = new PolygonContainer();
+			PolygonContainer *backPolys = new PolygonContainer();
+			PolygonContainer coincident;
+
+			int splits = 0;
+		
+			// split polygons with respect to split plane
+			interior->SplitPolygons(tData.mPolygons, 
+									frontPolys, 
+									backPolys,
+									&coincident,
+									splits, 
+									false);
+
+			// do all the splits with the previous planes
+			for (int i = 0; i < (int)tData.mPlanes.size(); ++i)
+			{
+				VertexContainer splitPts;
+				Polygon3 *frontPoly = new Polygon3();
+				Polygon3 *backPoly = new Polygon3();
+
+				if (planePoly->ClassifyPlane(*tData.mPlanes[i]) == Polygon3::SPLIT)
+				{
+					planePoly->Split(*tData.mPlanes[i], *frontPoly, *backPoly, splitPts);
+					DEL_PTR(planePoly);
+
+					if(tData.mSides[i] == true)
+					{
+						planePoly = frontPoly;
+						DEL_PTR(backPoly);
+					}
+					else
+					{
+						Debug << "take backpoly" << endl;
+						planePoly = backPoly;
+						DEL_PTR(frontPoly);
+					}
+				}
+			}
+
+			PolygonContainer *polys;
+			BspNode *next;
+			bool side = false;
+
+			// random decision
+			if (mask & 1)
+			{
+				next = interior->GetBack();
+				polys = backPolys;
+				CLEAR_CONTAINER(*frontPolys);
+				DEL_PTR(frontPolys);
+				side = false;
+			}
+			else
+			{
+				next = interior->GetFront();
+				polys = frontPolys;
+				
+				CLEAR_CONTAINER(*backPolys);
+				DEL_PTR(backPolys);
+				side = true;
+			}
+
+			mask = mask >> 1;
+			polys->push_back(planePoly);
+
+			// push the children on the stack
+			tStack.push(BspSplitData(next, polys, tData.mPlanes, 
+									 tData.mSides, side));
+			//tStack.push(BspSplitData(interior->GetBack(), backPolys, 
+			//						 tData.mPlanes, tData.mSides, false));
+
+			// clean up
+			CLEAR_CONTAINER(coincident); // NOTE: should contain nothing
+			CLEAR_CONTAINER(*tData.mPolygons);
+			DEL_PTR(tData.mPolygons);
+		}
+		else // reached leaf
+		{
+			//Debug << "\nsplits: " << endl;
+			//for (int i = 0; i < (int)tData.mSides.size(); ++ i)Debug << " " << tData.mSides[i];
+			ExportPolygons(tData.mPolygons);
+			
+			// clean up
+			CLEAR_CONTAINER(*tData.mPolygons);
+			DEL_PTR(tData.mPolygons);
+		}
+	}
+}
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp	(revision 308)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp	(revision 312)
@@ -5,9 +5,4 @@
 #include "AxisAlignedBox3.h"
 
-// tolerance value for side relation
-#define SIDE_TOLERANCE 0.002f // TODO: Test different values
-#define SIDE_TOLERANCE_SQRD 0.000004f
-#define AREA_LIMIT 0.0001f
-
 Polygon3::Polygon3(): mMaterial(NULL), mParent(NULL)
 {}
@@ -17,6 +12,7 @@
 
 Polygon3::Polygon3(MeshInstance *parent): mMaterial(NULL), mParent(parent)
-{
-}
+{}
+
+
 Polygon3::Polygon3(Face *face, Mesh *parentMesh)
 {	
@@ -41,24 +37,24 @@
 Vector3 Polygon3::GetNormal() const 
 {
-    return Normalize(CrossProd(mVertices[0]-mVertices[1],
-							   mVertices[2]-mVertices[1]));
-}
-
-void Polygon3::Split(Plane3 *partition, Polygon3 *front, Polygon3 *back)
+    return Normalize(CrossProd(mVertices[0] - mVertices[1],
+							   mVertices[2] - mVertices[1]));
+}
+
+void Polygon3::Split(const Plane3 &partition, 
+					 Polygon3 &front, 
+					 Polygon3 &back, 
+					 VertexContainer &splitPts)
 {
 	Vector3 ptA = mVertices.back();
 	
-	int sideA = partition->Side(ptA, SIDE_TOLERANCE);
+	int sideA = partition.Side(ptA, SIDE_TOLERANCE);
 	
 	VertexContainer::const_iterator it;
-	bool foundSplit = false;
-
-	Vector3 prevSplitPt(ptA);
-
+	
 	// find line - plane intersections
 	for (it = mVertices.begin(); it != mVertices.end(); ++ it)
 	{
 		Vector3 ptB = *it;
-		int sideB = partition->Side(ptB, SIDE_TOLERANCE);
+		int sideB = partition.Side(ptB, SIDE_TOLERANCE);
 	
 		// vertices on different sides => split
@@ -68,17 +64,18 @@
 			{
 				//-- plane - line intersection
-				Vector3 splitPt = partition->FindIntersection(ptA, ptB);
+				Vector3 splitPt = partition.FindIntersection(ptA, ptB);
 			
-				if (!foundSplit || (SqrDistance(splitPt, prevSplitPt) > SIDE_TOLERANCE_SQRD))
+				// test if split point not too close to previous split point
+				if ((splitPts.size() == 0) || 
+					(SqrDistance(splitPt, splitPts.back()) > SIDE_TOLERANCE_SQRD))
 				{
 					// add vertex to both polygons
-					front->mVertices.push_back(splitPt);
-					back->mVertices.push_back(splitPt);
-
-					foundSplit = true;
-					prevSplitPt = splitPt;
+					front.mVertices.push_back(splitPt);
+					back.mVertices.push_back(splitPt);
+					
+					splitPts.push_back(splitPt);
 				}
 			}
-			front->mVertices.push_back(ptB);
+			front.mVertices.push_back(ptB);
 		}
 		else if (sideB < 0)
@@ -87,23 +84,24 @@
 			{
 				//-- plane - line intersection
-				Vector3 splitPt = partition->FindIntersection(ptA, ptB);
-			
-				if (!foundSplit || (SqrDistance(splitPt, prevSplitPt) > SIDE_TOLERANCE_SQRD))
+				Vector3 splitPt = partition.FindIntersection(ptA, ptB);
+				// test if split point not too close to other split point
+					// test if split point not too close to previous split point
+				if ((splitPts.size() == 0) || 
+					(SqrDistance(splitPt, splitPts.back()) > SIDE_TOLERANCE_SQRD))
 				{
 					// add vertex to both polygons
-					front->mVertices.push_back(splitPt);
-					back->mVertices.push_back(splitPt);
-
-					foundSplit = true;
-					prevSplitPt = splitPt;
+					front.mVertices.push_back(splitPt);
+					back.mVertices.push_back(splitPt);
+
+					splitPts.push_back(splitPt);
 				}	
 			}
-			back->mVertices.push_back(ptB);
+			back.mVertices.push_back(ptB);
 		}
 		else
 		{
 			// vertex on plane => add vertex to both polygons
-			front->mVertices.push_back(ptB);
-			back->mVertices.push_back(ptB); 
+			front.mVertices.push_back(ptB);
+			back.mVertices.push_back(ptB); 
 		}
 	
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParser.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParser.h	(revision 261)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParser.h	(revision 312)
@@ -10,8 +10,10 @@
 {
 public:
-  X3dParser():Parser() {}
+  X3dParser():Parser(), mViewCellHeight(5.0f) {}
   
   bool ParseFile(const string filename, SceneGraphNode **root);
   bool ParseFile(const string filename, ViewCellContainer &viewCells);
+
+  float mViewCellHeight;
 };
 
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp	(revision 311)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp	(revision 312)
@@ -243,6 +243,8 @@
 			Intersectable *object = objects[i];
 		
-			int pvsSize = object->mKdPvs.GetSize();
-			
+			int pvsSize = 0;
+			if (mViewCellsType == KD_VIEW_CELLS)
+				pvsSize = object->mKdPvs.GetSize();
+						
 			if (0 && pvsSize) {
 				// mail all nodes from the pvs
@@ -407,4 +409,5 @@
     exporter->SetExportRayDensity(true);
     exporter->ExportKdTree(*mKdTree);
+
 	if (mViewCellsType == BSP_VIEW_CELLS)	
 		exporter->ExportBspTree(*mBspTree);
@@ -429,4 +432,61 @@
 
   if (1) {
+	
+      if (mViewCellsType == BSP_VIEW_CELLS)
+	  {
+		   int limit = Min((int)mViewCells.size(), 1);
+
+		   //char s[64]; sprintf(s, "bsp-pvs%04d.x3d", k);
+		   Exporter *exporter = Exporter::GetExporter("bsp-pvs.x3d");
+		   exporter->SetFilled();
+
+		   Intersectable::NewMail();
+
+		   for (int j = 0; j < limit; ++ j)
+		   {		       
+			   // j random view cells
+			   int k = Random((int)mViewCells.size());
+
+			   Debug << "next vc: " << k << endl;
+			   ViewCellPvsMap::iterator it = mViewCells[k]->GetPvs().mEntries.begin();
+
+			   Material m;//= RandomMaterial();
+			   m.mDiffuseColor = RgbColor(0, 1, 0);
+			   exporter->SetForcedMaterial(m);
+
+			   exporter->ExportViewCell(mViewCells[k]);
+
+			   m.mDiffuseColor = RgbColor(1, 0, 0);
+			   exporter->SetForcedMaterial(m);
+
+			   Debug << "pvs size: " << mViewCells[k]->GetPvs().GetSize() << " of " << objects.size() << endl;
+
+			   for (; it != mViewCells[k]->GetPvs().mEntries.end(); ++ it) 
+			   {
+				   Intersectable *intersect = (*it).first;
+				   if (!intersect->Mailed())
+				   {
+					   exporter->ExportIntersectable(intersect);
+					   intersect->Mail();
+				   }
+			   
+			   }
+		   }
+			
+		   // output rest of the objects
+		   Material m;//= RandomMaterial();
+		   m.mDiffuseColor = RgbColor(0, 0, 1);
+		   exporter->SetForcedMaterial(m);
+
+		   for (int j = 0; j < objects.size(); ++ j)
+			   if (!objects[j]->Mailed())
+			   {
+				   exporter->ExportIntersectable(objects[j]);
+				   objects[j]->Mail();
+			   }
+
+		   DEL_PTR(exporter);
+	  }	  
+
     for (int k=0; k < pvsOut; k++) {
       Intersectable *object = objects[k];
@@ -436,38 +496,32 @@
       exporter->SetWireframe();
 
-	  if (mViewCellsType == BSP_VIEW_CELLS)
+	
+	  KdPvsMap::iterator i = object->mKdPvs.mEntries.begin();
+	  Intersectable::NewMail();
+		  
+	  // avoid adding the object to the list
+	  object->Mail();
+	  ObjectContainer visibleObjects;
+
+	  for (; i != object->mKdPvs.mEntries.end(); i++) 
 	  {
-
+		  KdNode *node = (*i).first;
+		  exporter->ExportBox(mKdTree->GetBox(node));
+		  mKdTree->CollectObjects(node, visibleObjects);
 	  }
-	  else
-	  {
-		  KdPvsMap::iterator i = object->mKdPvs.mEntries.begin();
-	  	  Intersectable::NewMail();
-		  
-		  // avoid adding the object to the list
-		  object->Mail();
-		  ObjectContainer visibleObjects;
-
-		  for (; i != object->mKdPvs.mEntries.end(); i++) 
-		  {
-			  KdNode *node = (*i).first;
-			  exporter->ExportBox(mKdTree->GetBox(node));
-			  mKdTree->CollectObjects(node, visibleObjects);
-		  }
-
-		  exporter->ExportRays(rays[k], 1000, RgbColor(0, 1, 0));
-		  exporter->SetFilled();
-
-		  for (int j = 0; j < visibleObjects.size(); j++)
-			  exporter->ExportIntersectable(visibleObjects[j]);
+
+	  exporter->ExportRays(rays[k], 1000, RgbColor(0, 1, 0));
+	  exporter->SetFilled();
+
+	  for (int j = 0; j < visibleObjects.size(); j++)
+		  exporter->ExportIntersectable(visibleObjects[j]);
 	
 
-		  Material m;
-	      m.mDiffuseColor = RgbColor(1, 0, 0);
-		  exporter->SetForcedMaterial(m);
-		  exporter->ExportIntersectable(object);
-	  }
-
-      delete exporter;
+	  Material m;
+	  m.mDiffuseColor = RgbColor(1, 0, 0);
+	  exporter->SetForcedMaterial(m);
+	  exporter->ExportIntersectable(object);
+
+	  delete exporter;
     }
   }
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/AxisAlignedBox3.cpp
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/AxisAlignedBox3.cpp	(revision 302)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/AxisAlignedBox3.cpp	(revision 312)
@@ -125,4 +125,25 @@
     b->SetValue(mMax.x, mMin.y, mMax.z);
     break;
+  }
+}
+
+// returns the vertex indices in the range <0..7>, v = 4.x + 2.y + z, where
+// x,y,z are either 0 or 1; (0 .. min coordinate, 1 .. max coordinate)
+void
+AxisAlignedBox3::GetEdge(const int edge, int  &aIdx, int &bIdx) const
+{
+  switch(edge) {
+  case 0: aIdx = 0; bIdx = 1; break;
+  case 1: aIdx = 0; bIdx = 2; break;
+  case 2: aIdx = 0; bIdx = 4; break;
+  case 3: aIdx = 7; bIdx = 6; break;
+  case 4: aIdx = 7; bIdx = 5; break;
+  case 5: aIdx = 7; bIdx = 3; break;
+  case 6: aIdx = 1; bIdx = 3; break;
+  case 7: aIdx = 1; bIdx = 5; break;
+  case 8: aIdx = 2; bIdx = 3; break;
+  case 9: aIdx = 2; bIdx = 6; break;
+  case 10: aIdx = 4; bIdx = 6; break;
+  case 11: aIdx = 4; bIdx = 5; break;
   }
 }
@@ -1023,4 +1044,5 @@
 };
 
+
 // The fast computation of arctangent .. the maximal error is less
 // than 4.1 degrees, according to Graphics GEMSII, 1991, pages 389--391
@@ -1624,2 +1646,105 @@
   return Rectangle3(v[0], v[1], v[2], v[3]);
 }
+/*
+const int AxisAlignedBox3::complEdgeTbl[12][3] =
+{
+	{3, 4, 5},
+	{3, 4, 5},
+	{3, 4, 5},
+	{0, 1, 2},
+	{0, 1, 2},
+	{0, 1, 2},
+	{9, 10, 11},
+	{8, 9, 10},
+	{7, 10, 11},
+	{6, 7, 11},
+	{6, 7, 8},
+	{6, 8, 9},
+};
+*/
+// TODO: use a table to avoid normal and distance computations
+Polygon3 *AxisAlignedBox3::BoundPlane(const Plane3 &plane)
+{
+	Vector3 ptA, ptB;
+	int sideA = 0, sideB = 0;
+
+	VertexContainer vertices;
+
+	int side[8];
+
+	bool onFrontSide, onBackSide = false;
+
+	Vector3 vtx;
+	for (int i = 0; i < 8; ++i)
+	{
+		GetVertex(i, vtx);
+		side[i] = plane.Side(vtx, SIDE_TOLERANCE);
+		if (side[i] > 0)
+			onFrontSide = true;
+		else if (side[i] < 0)
+			onBackSide = true;
+		else // vertex coincident => push_back
+			vertices.push_back(vtx);
+	}
+
+	// does not intersect
+	if (!onFrontSide && !onBackSide)
+		return NULL;
+
+	for (int i = 0; i < 12; ++ i)
+	{
+		int aIdx, bIdx;
+		GetEdge(i, aIdx, bIdx);
+
+		ptA = GetVertex(aIdx);
+		ptB = GetVertex(bIdx);
+
+		int sideA = side[aIdx];
+		int sideB = side[bIdx];
+
+		if (((sideA > 0) && (sideB < 0)) || (sideA < 0) && (sideB > 0))
+			vertices.push_back(plane.FindIntersection(ptA, ptB));	
+	}
+
+	if (vertices.size() == 4)
+	{
+		float maxDist = 0;
+		int maxIdx = 0;
+
+		for (int i = 1; i < 4; ++ i)
+		{
+			float dist = SqrDistance(vertices[0], vertices[i]);
+			if (dist > maxDist)
+			{
+				maxDist = dist;
+				maxIdx = i;
+			}
+		}
+		// illformed polygon = swap
+		if ((maxIdx == 1) || (maxIdx == 3) )
+		{
+			Vector3 vtx = vertices[maxIdx];
+			vertices[maxIdx] = vertices[2];
+			vertices[2] = vtx;
+		}
+	}
+
+	// wrong surface orientation?
+    Vector3 norm = Normalize(CrossProd(vertices[0] - vertices[1],
+									   vertices[2] - vertices[1]));
+
+	Polygon3 *planePoly = new Polygon3();
+
+	if (DotProd(norm, plane.mNormal) > 0)
+		for (int i = 0; i < (int)vertices.size(); ++ i)
+			planePoly->mVertices.push_back(vertices[i]);
+	else
+	{
+		for (int i = (int)vertices.size() - 1; i >= 0; -- i)
+			planePoly->mVertices.push_back(vertices[i]);
+	}
+
+	//Debug << *planePoly << "\narea: " << planePoly->GetArea() << endl;
+	
+	return planePoly;
+}
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParserXerces.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParserXerces.h	(revision 261)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/X3dParserXerces.h	(revision 312)
@@ -114,5 +114,5 @@
   //  Constructors and Destructor
   // -----------------------------------------------------------------------
-  X3dViewCellsParseHandlers(ViewCellContainer *mViewCells);
+  X3dViewCellsParseHandlers(ViewCellContainer *mViewCells, float viewCellHeight);
   ~X3dViewCellsParseHandlers();
   
@@ -152,4 +152,6 @@
 
   ViewCellContainer *mViewCells;
+  float mViewCellHeight;
+
   VertexIndexContainer mCurrentVertexIndices;
 
Index: /trunk/VUT/GtpVisibilityPreprocessor/src/common.h
===================================================================
--- /trunk/VUT/GtpVisibilityPreprocessor/src/common.h	(revision 262)
+++ /trunk/VUT/GtpVisibilityPreprocessor/src/common.h	(revision 312)
@@ -127,4 +127,9 @@
 #define MAX_FLOAT  1e30f
 
+// tolerance value for side relation
+#define SIDE_TOLERANCE 0.002f // TODO: Test different values
+#define SIDE_TOLERANCE_SQRD 0.000004f
+#define AREA_LIMIT 0.0001f
+
 #ifndef DEL_PTR
 #define DEL_PTR(ptr) do {if (ptr) {        \
