Index: trunk/VUT/GtpVisibilityPreprocessor/src/ViewCell.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/ViewCell.cpp	(revision 245)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/ViewCell.cpp	(revision 256)
@@ -64,5 +64,5 @@
 	{
 		Intersectable *object = objects[i];
-
+		
 		// extract the mesh instances
 		if (object->Type() == Intersectable::MESH_INSTANCE)
Index: trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.h	(revision 242)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.h	(revision 256)
@@ -53,4 +53,13 @@
 	int Side(const Plane3 &plane) const;
 
+	/** Scales the polygon about its center
+	*/
+	void Scale(const float scale);
+	
+	/** Computes the center of mass of the polygon
+	 */
+	Vector3 Center() const;
+
+		
 	/** Deletes all polygons om the queue.
 	*/
Index: trunk/VUT/GtpVisibilityPreprocessor/src/Plane3.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/Plane3.cpp	(revision 256)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/Plane3.cpp	(revision 256)
@@ -0,0 +1,32 @@
+#include "Plane3.h"
+#include "Matrix4x4.h"
+
+
+
+
+bool
+PlaneIntersection(const Plane3 &a, const Plane3 &b, const Plane3 &c, Vector3 &result)
+{
+  Vector3
+    sx(a.mNormal.x, b.mNormal.x, c.mNormal.x),
+    sy(a.mNormal.y, b.mNormal.y, c.mNormal.y),
+    sz(a.mNormal.z, b.mNormal.z, c.mNormal.z),
+    sd(a.mD, b.mD, c.mD);
+
+  Matrix4x4 md(a.mNormal, b.mNormal, c.mNormal), mx, my, mz;
+
+  mx.SetColumns(sd, sy, sz);
+  my.SetColumns(sx, sd, sz);
+  mz.SetColumns(sx, sy, sd);
+  
+  double det = md.Det3x3();
+
+  if (abs(det)<TRASH)
+    return false;
+
+  result.SetValue(mx.Det3x3()/det,
+		  my.Det3x3()/det,
+		  mz.Det3x3()/det);
+  
+  return true;
+}
Index: trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.h
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.h	(revision 245)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.h	(revision 256)
@@ -16,4 +16,6 @@
 class SamplingPreprocessor : public Preprocessor {
 public:
+	int mPass;
+
   int mSamplesPerPass;
   int mTotalSamples;
@@ -33,8 +35,19 @@
 
   int
-  AddNodeSamples(Intersectable *object, const Ray &ray, const int pass);
+  AddNodeSamples(Intersectable *object, const Ray &ray);
 
   void
   HoleSamplingPass();
+
+	int
+	CastRay(Intersectable *object, Ray &ray);
+
+	void
+	CastEdgeSamples(
+									Intersectable *object,
+									const Vector3 &point,
+									Mesh &mesh,
+									const int samples
+									);
 
 };
Index: trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp	(revision 242)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp	(revision 256)
@@ -154,2 +154,24 @@
 }
 
+
+Vector3
+Polygon3::Center() const
+{
+	int i;
+	Vector3 sum = mVertices[0];
+	for (i=1; i < mVertices.size(); i++)
+		sum += mVertices[i];
+	
+	return sum/i;
+}
+
+
+void
+Polygon3::Scale(const float scale)
+{
+	int i;
+	Vector3 center = Center();
+	for (i=0; i < mVertices.size(); i++) {
+		mVertices[i] = center + scale*(mVertices[i] - center);
+	}
+}
Index: trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp
===================================================================
--- trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp	(revision 245)
+++ trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp	(revision 256)
@@ -5,4 +5,5 @@
 #include "Environment.h"
 #include "MutualVisibility.h"
+#include "Polygon3.h"
 
 SamplingPreprocessor::SamplingPreprocessor()
@@ -37,6 +38,6 @@
 int
 SamplingPreprocessor::AddNodeSamples(Intersectable *object,
-				     const Ray &ray,
-				     const int pass)
+																		 const Ray &ray
+																		 )
 {
   int contributingSamples = 0;
@@ -47,5 +48,5 @@
   }
   
-  if (pass > 10)
+  if (mPass > 10)
     for (j=1; j < ray.leaves.size() - 1; j++) {
       ray.leaves[j]->AddPassingRay(ray, contributingSamples ? 1 : 0);
@@ -67,4 +68,20 @@
     cout<<leaf->mPassingRays<<endl;
   }
+}
+
+
+int
+SamplingPreprocessor::CastRay(Intersectable *object, Ray &ray)
+{
+	mKdTree->CastRay(ray);
+	int sampleContributions = 0;
+	if (ray.leaves.size()) {
+		sampleContributions += AddNodeSamples(object, ray);
+		
+		if (ray.intersections.size()) {
+			sampleContributions += AddNodeSamples(ray.intersections[0].mObject, ray);
+		}
+	}
+	return sampleContributions;
 }
 
@@ -121,4 +138,29 @@
 
 
+void
+SamplingPreprocessor::CastEdgeSamples(
+																			Intersectable *object,
+																			const Vector3 &point,
+																			Mesh &mesh,
+																			const int samples
+																			)
+{
+	Ray ray;
+	int i;
+	for (i=0; i < samples; i++) {
+		// pickup a random face of each mesh 
+		int face = RandomValue(0, mesh.mFaces.size()-1);
+		
+		Polygon3 poly(mesh.mFaces[face], &mesh);
+		poly.Scale(1.001);
+		// now extend a random edge of the face
+		int edge = RandomValue(0, poly.mVertices.size()-1);
+		float t = RandomValue(0.0f,1.0f);
+		Vector3 target = t*poly.mVertices[edge] + (1.0f-t)*poly.mVertices[(edge + 1)%
+																																		 poly.mVertices.size()];
+	  SetupRay(ray, point, target - point);
+	  CastRay(object, ray);
+	}
+}
 
 bool
@@ -137,5 +179,4 @@
   
   int i;
-  int pass = 0;
   int totalSamples = 0;
 
@@ -144,157 +185,163 @@
   vector<Ray> rays[10];
   
-  while (totalSamples < mTotalSamples)
-    {
-      int passContributingSamples = 0;
-      int passSampleContributions = 0;
-      int passSamples = 0;
-      int index = 0;
-
-      for (i =0; i < objects.size(); i++) {
-	KdNode *nodeToSample = NULL;
-	Intersectable *object = objects[i];
+  while (totalSamples < mTotalSamples) {
+		int passContributingSamples = 0;
+		int passSampleContributions = 0;
+		int passSamples = 0;
+		int index = 0;
+		
+		for (i =0; i < objects.size(); i++) {
+			KdNode *nodeToSample = NULL;
+			Intersectable *object = objects[i];
+			
+			int pvsSize = object->mKdPvs.GetSize();
+			
+			
+			
+			if (0 && pvsSize) {
+				// mail all nodes from the pvs
+				Intersectable::NewMail();
+				KdPvsMap::iterator i = object->mKdPvs.mEntries.begin();
+			  
+				for (; i != object->mKdPvs.mEntries.end(); i++) {
+					KdNode *node = (*i).first;
+					node->Mail();
+				}
+				
+				int maxTries = 2*pvsSize;
+				
+				for (int tries = 0; tries < 10; tries++) {
+					index = RandomValue(0, pvsSize - 1);
+					KdPvsData data;
+					KdNode *node;
+					object->mKdPvs.GetData(index, node, data);
+					nodeToSample = mKdTree->FindRandomNeighbor(node, true);
+					if (nodeToSample)
+						break;
+				}
+			}
+			
+			if (0 && pvsSize && mPass == 1000 ) {
+				// mail all nodes from the pvs
+				Intersectable::NewMail();
+				KdPvsMap::iterator i = object->mKdPvs.mEntries.begin();
+				for (; i != object->mKdPvs.mEntries.end(); i++) {
+					KdNode *node = (*i).first;
+					node->Mail();
+				}
+				
+				vector<KdNode *> invisibleNeighbors;
+				// get all neighbors of all PVS nodes
+				i = object->mKdPvs.mEntries.begin();
+				for (; i != object->mKdPvs.mEntries.end(); i++) {
+					KdNode *node = (*i).first;
+					mKdTree->FindNeighbors(node, invisibleNeighbors, true);
+					AxisAlignedBox3 box = object->GetBox();
+					for (int j=0; j < invisibleNeighbors.size(); j++) {
+						int visibility = ComputeBoxVisibility(mSceneGraph,
+																									mKdTree,
+																									box,
+																									mKdTree->GetBox(invisibleNeighbors[j]),
+																									1e-6f);
+						//	      exit(0);
+					}
+					// now rank all the neighbors according to probability that a new
+					// sample creates some contribution
+				}
+			}
+			
+			
+			object->GetRandomSurfacePoint(point, normal);
+			bool viewcellSample = true;
+			int sampleContributions;
+			if (viewcellSample) {
+				nodeToSample = mKdTree->GetRandomLeaf(Plane3(normal, point));
+				
+				for (int k=0; k < mSamplesPerPass; k++) {
+					
+					if (nodeToSample) {
+						int maxTries = 5;
+						
+						for (int tries = 0; tries < maxTries; tries++) {
+							direction = mKdTree->GetBox(nodeToSample).GetRandomPoint() - point;
+							
+							if (DotProd(direction, normal) > Limits::Small)
+								break;
+						}
+						
+						if (tries == maxTries)
+							direction = UniformRandomVector(normal);
+					}
+					else {
+						direction = UniformRandomVector(normal);
+					}
+					
+					// construct a ray
+					SetupRay(ray, point, direction);
+					sampleContributions = CastRay(object, ray);
+				}
+			} else {
+				// edge samples
+				// get random visible mesh
+				//				object->GetRandomVisibleMesh(Plane3(normal, point));
+				
+				
+			}
+				
+			
+			if ( i < pvsOut )
+				rays[i].push_back(ray);
+			
+			if (ray.intersections.size()) {
+					// check whether we can add this to the rays
+				for (int j = 0; j < pvsOut; j++) {
+					if (objects[j] == ray.intersections[0].mObject) {
+						rays[j].push_back(ray);
+					}
+				}
+			}
+			
+			passSamples++;
+			
+			if (sampleContributions) {
+				passContributingSamples++;
+				passSampleContributions += sampleContributions;
+			}
+		}
+		
+		
 	
-	int pvsSize = object->mKdPvs.GetSize();
-
-
-
-	if (0 && pvsSize) {
-	  // mail all nodes from the pvs
-	  Intersectable::NewMail();
-	  KdPvsMap::iterator i = object->mKdPvs.mEntries.begin();
-			  
-	  for (; i != object->mKdPvs.mEntries.end(); i++) {
-	    KdNode *node = (*i).first;
-	    node->Mail();
-	  }
-
-	  int maxTries = 2*pvsSize;
-	
-	  for (int tries = 0; tries < 10; tries++) {
-	    index = RandomValue(0, pvsSize - 1);
-	    KdPvsData data;
-	    KdNode *node;
-	    object->mKdPvs.GetData(index, node, data);
-	    nodeToSample = mKdTree->FindRandomNeighbor(node, true);
-	    if (nodeToSample)
-	      break;
-	  }
+		totalSamples += passSamples;
+		
+		//    if (pass>10)
+		//      HoleSamplingPass();
+    
+		
+		mPass++;
+    
+		int pvsSize = 0;
+		for (i=0; i < objects.size(); i++) {
+			Intersectable *object = objects[i];
+			pvsSize += object->mKdPvs.GetSize();
+		}
+    
+		cout << "#Pass " << mPass<<" : t = " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
+		cout << "#TotalSamples=" << totalSamples/1000 
+				 << "k   #SampleContributions=" << passSampleContributions << " (" 
+				 << 100*passContributingSamples/(float)passSamples<<"%)" << " avgPVS="
+				 << pvsSize/(float)objects.size() << endl 
+				 << "avg ray contrib=" << passSampleContributions/(float)passContributingSamples << endl;
+		
+		
+		mStats <<
+			"#Pass\n" <<mPass<<endl<<
+			"#Time\n" << TimeDiff(startTime, GetTime())*1e-3 << endl<<
+			"#TotalSamples\n" << totalSamples<< endl<<
+			"#SampleContributions\n" << passSampleContributions << endl << 
+			"#PContributingSamples\n"<<100*passContributingSamples/(float)passSamples<<endl <<
+			"#AvgPVS\n"<< pvsSize/(float)objects.size() << endl <<
+			"#AvgRayContrib\n" << passSampleContributions/(float)passContributingSamples << endl;
 	}
 	
-	if (0 && pvsSize && pass == 1000 ) {
-	  // mail all nodes from the pvs
-	  Intersectable::NewMail();
-	  KdPvsMap::iterator i = object->mKdPvs.mEntries.begin();
-	  for (; i != object->mKdPvs.mEntries.end(); i++) {
-	    KdNode *node = (*i).first;
-	    node->Mail();
-	  }
-	
-	  vector<KdNode *> invisibleNeighbors;
-	  // get all neighbors of all PVS nodes
-	  i = object->mKdPvs.mEntries.begin();
-	  for (; i != object->mKdPvs.mEntries.end(); i++) {
-	    KdNode *node = (*i).first;
-	    mKdTree->FindNeighbors(node, invisibleNeighbors, true);
-	    AxisAlignedBox3 box = object->GetBox();
-	    for (int j=0; j < invisibleNeighbors.size(); j++) {
-	      int visibility = ComputeBoxVisibility(mSceneGraph,
-						    mKdTree,
-						    box,
-						    mKdTree->GetBox(invisibleNeighbors[j]),
-						    1e-6f);
-	      //	      exit(0);
-	    }
-	    // now rank all the neighbors according to probability that a new
-	    // sample creates some contribution
-	  }
-	}
-
-	object->GetRandomSurfacePoint(point, normal);
-	nodeToSample = mKdTree->GetRandomLeaf(Plane3(normal, point));
-
-	for (int k=0; k < mSamplesPerPass; k++) {
-	  
-	  if (nodeToSample) {
-	    int maxTries = 5;
-	    
-	    for (int tries = 0; tries < maxTries; tries++) {
-	      direction = mKdTree->GetBox(nodeToSample).GetRandomPoint() - point;
-	      
-	      if (DotProd(direction, normal) > Limits::Small)
-		break;
-	    }
-	    
-	    if (tries == maxTries)
-	      direction = UniformRandomVector(normal);
-	  }
-	  else {
-	    direction = UniformRandomVector(normal);
-	  }
-	  
-	  // construct a ray
-	  SetupRay(ray, point, direction);
-	  mKdTree->CastRay(ray);
-	  
-	  if ( i < pvsOut )
-	    rays[i].push_back(ray);
-	  
-	  int sampleContributions = 0;
-	  
-	  if (ray.leaves.size()) {
-	    sampleContributions += AddNodeSamples(object, ray, pass);
-	    
-	    if (ray.intersections.size()) {
-	      sampleContributions += AddNodeSamples(ray.intersections[0].mObject, ray, pass);
-	      // check whether we can add this to the rays
-	      for (int j = 0; j < pvsOut; j++) {
-		if (objects[j] == ray.intersections[0].mObject) {
-		  rays[j].push_back(ray);
-		}
-	      }
-	    }
-
-	    passSamples++;
-			
-	    if (sampleContributions) {
-	      passContributingSamples++;
-	      passSampleContributions += sampleContributions;
-	    }
-	  }
-	}
-      }
-
-      totalSamples += passSamples;
-
-      //    if (pass>10)
-      //      HoleSamplingPass();
-    
-
-      pass++;
-    
-      int pvsSize = 0;
-      for (i=0; i < objects.size(); i++) {
-	Intersectable *object = objects[i];
-	pvsSize += object->mKdPvs.GetSize();
-      }
-    
-      cout << "#Pass " << pass<<" : t = " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
-      cout << "#TotalSamples=" << totalSamples/1000 
-	   << "k   #SampleContributions=" << passSampleContributions << " (" 
-	   << 100*passContributingSamples/(float)passSamples<<"%)" << " avgPVS="
-	   << pvsSize/(float)objects.size() << endl 
-	   << "avg ray contrib=" << passSampleContributions/(float)passContributingSamples << endl;
-
-
-      mStats <<
-	"#Pass\n" <<pass<<endl<<
-	"#Time\n" << TimeDiff(startTime, GetTime())*1e-3 << endl<<
-	"#TotalSamples\n" << totalSamples<< endl<<
-	"#SampleContributions\n" << passSampleContributions << endl << 
-	"#PContributingSamples\n"<<100*passContributingSamples/(float)passSamples<<endl <<
-	"#AvgPVS\n"<< pvsSize/(float)objects.size() << endl <<
-	"#AvgRayContrib\n" << passSampleContributions/(float)passContributingSamples << endl;
-    }
-
   int totalPvsSize = mKdTree->CollectLeafPvs();
   cout << "#totalPvsSize=" << totalPvsSize << endl;
