← Back to team overview

yade-dev team mailing list archive

[svn] r1642 - in trunk/pkg/snow: DataClass RenderingEngine

 

Author: cosurgi
Date: 2009-01-25 23:32:18 +0100 (Sun, 25 Jan 2009)
New Revision: 1642

Modified:
   trunk/pkg/snow/DataClass/BshSnowGrain.cpp
   trunk/pkg/snow/DataClass/BshSnowGrain.hpp
   trunk/pkg/snow/RenderingEngine/Ef1_BshSnowGrain_glDraw.cpp
Log:
- added extensive comments to the polyhedron code which will be used for collisions



Modified: trunk/pkg/snow/DataClass/BshSnowGrain.cpp
===================================================================
--- trunk/pkg/snow/DataClass/BshSnowGrain.cpp	2009-01-25 14:28:37 UTC (rev 1641)
+++ trunk/pkg/snow/DataClass/BshSnowGrain.cpp	2009-01-25 22:32:18 UTC (rev 1642)
@@ -183,16 +183,16 @@
 		// now check if the point (when projected on a plane) is within triangle a,b,c
 		// it could be faster with methods from http://softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm
 		// but I don't understand them, so I prefer to use the method which I derived myself
-		Vector3r c1((a - b).Cross(d - a));
-		Vector3r c2((c - a).Cross(d - c));
-		Vector3r c3((b - c).Cross(d - b));
-		if(c1.Dot(N) > 0 && c2.Dot(N) > 0 && c3.Dot(N) > 0)
+		Vector3r c1((a - b).Cross(d - a)); // since points a,b,c are all clockwise, 
+		Vector3r c2((c - a).Cross(d - c)); // then if I put a point 'd' inside a triangle it will be clockwise
+		Vector3r c3((b - c).Cross(d - b)); // with each pair of other points, but will be counterclockwise if it's outside
+		if(c1.Dot(N) > 0 && c2.Dot(N) > 0 && c3.Dot(N) > 0) // therefore if any of them is counterclockwise, the dot product will be negative
 			return true;
 	}
 	return false;
 };
 		
-bool BshSnowGrain::is_inside(Vector3r P)
+bool BshSnowGrain::is_point_inside_polyhedron(Vector3r P)
 {
 	const std::vector<boost::tuple<Vector3r,Vector3r,Vector3r,Vector3r> >& f(get_faces_const_ref());
 	// loop on all faces
@@ -203,24 +203,67 @@
 		Vector3r b(get<1>(f[i]));
 		Vector3r c(get<2>(f[i]));
 		Vector3r N(get<3>(f[i]));
+		Real depth = m_depths[i];
 		Real point_plane_distance = N.Dot(P - c);
 		if(   point_plane_distance < 0             // point has to be inside - on negative side of the plane
-		   && point_plane_distance > m_depths[i] ) // and has to be within the depth of this face 
+		   && point_plane_distance > depth ) // and has to be within the depth of this face 
 		{
 			if(is_point_orthogonally_projected_on_triangle(a,b,c,N,P,point_plane_distance))
 			{
-				// so a point orthogonally projected on triangle is crossing it
-				// now check if this point is inside a tetrahedron made by this triangle and a point Z at m_depths[i]
-				Vector3r Z((a+b+c)/3.0 + N*m_depths[i]);
-				Vector3r N1(-1.0*((a - b).Cross(Z - a)));
-				Vector3r N2(-1.0*((c - a).Cross(Z - c)));
-				Vector3r N3(-1.0*((b - c).Cross(Z - b)));
-				if(
-					is_point_orthogonally_projected_on_triangle(b,a,Z,N1,P) &&
-					is_point_orthogonally_projected_on_triangle(a,c,Z,N2,P) &&
-					is_point_orthogonally_projected_on_triangle(c,b,Z,N3,P)
-					)
+				if( point_plane_distance > depth*0.5 ) // (1-parallelepiped)
+				{ // that's close enough. We can speed up the computation by returning true at this point
+
+// therefore in fact, we are checking if point is inside a volume of parallelepiped (1) the height of 1/2 depth
+// within the polyhedron PLUS (that's the code below - the (2)) a polyhedron the height given by depth
+// like this:
+//              ____________     this weird shape is WHOLE polyhedron
+//             /         Z. \                                                         ------
+//            /          ' ` \                                                             |
+//           /          '2-tetrahedron with the height equal to depth of THIS trangle      |
+//          /          '     ` \                                                           | 
+//         /          '       ` \                                                          |d
+//        /          '         ` \______________ XX face (see description)                 |e - search below for
+//       /          '           `              /                                           |p 'arbitrary safety coefficient'
+//      /      ....'.............`......      /                                            |t
+//      \     '   '           1-parallelepiped with height equal to 1/2 of depth           |h
+//       \    '  '                 `   '    /                                              |
+//        \   ' '                   `  '   /                                               |
+//         \  ''                     ` '  /                                                |
+//          \ '                       `' /                                                 |
+//           \__________________________/                                             ------
+//               THIS triangular face                
+//
+// depth of a triangle is the distance from it to the opposite side of polyhedron, kind of
+// diameter in a sphere. The depth is calculated in four places: at three nodes of a triangle,
+// and in its center point. The shallowest one is chosen as the actual value. This is
+// not describing volume in exactly perfect math, but good enough, and rather fast.
+// Sometimes for example the 'depth' of some triangle can extend the volume of the real polyhedron a bit
+// on the other side. For example if that 'XX face' was closer to 'THIS triangular face' it would 
+// still be considered as inside of polyhedron, because the '1/2 depth parallelepiped' might extend beyond it.
+// this could happen if none of four (points a,b,c and center point) reached 'XX face' when calculating depth,
+// because it was off a bit, and depth calculation ended up on another face.
+
+// From this approach you can see that it's optimized for polyhedrons with large number of faces. For instance it will
+// be terribly wrong if polyhedron is just a single four-noded tetrahedron. But it will work well if polyhedron
+// is made from many triangles.
 					return true;
+				}
+				else
+				{ // (2-terhahdron)
+					// so a point orthogonally projected on triangle is crossing it
+					// now check if this point is inside a tetrahedron made by this triangle
+					// and a point 'Z' at 'depth', see picture
+					Vector3r Z((a+b+c)/3.0 + N*depth);
+					Vector3r N1((Z - a).Cross(a - b)); // normals of each face
+					Vector3r N2((Z - c).Cross(c - a)); // of tetrahedron a,b,c,Z
+					Vector3r N3((Z - b).Cross(b - c));
+					if(
+						is_point_orthogonally_projected_on_triangle(b,a,Z,N1,P) &&
+						is_point_orthogonally_projected_on_triangle(a,c,Z,N2,P) &&
+						is_point_orthogonally_projected_on_triangle(c,b,Z,N3,P)
+						)
+						return true;
+				}
 			}
 		}
 	}
@@ -256,8 +299,13 @@
 	if(m_how_many_faces != -1)
 		return m_how_many_faces;
 
-	std::cerr << "\nrecalculating polyhedron triangular faces depths\n";
+// sorry, I never got around to find time and to check out how LOG_WARN works .... std::cerr is fine for me ;)
+	std::cerr << "\nrecalculating the depths of polyhedron triangular faces - for faster collision detection\n";
 
+
+// CREATE TRIANGULAR FACES. usually a polyhedron has triangular faces, but here it's a snow grain.
+// it has layers, not faces, I have to make faces from layers
+
 	m_faces.clear();
 	//calculate amount of faces..
 
@@ -289,24 +337,28 @@
 	
 	m_how_many_faces = m_faces.size();
 
+
+// NOW I HAVE FACES. That's the code for usual polyhedrons, that already have faces:
+// calculating the depth for each face.
+
 	// now calculate the depth for each face
 	m_depths.resize(m_faces.size(),0);
 	// loop on all faces
 	size_t SS(m_faces.size());
 	for(size_t i = 0; i < SS ; ++i)
-		m_depths[i] = calc_depth(i)*0.7;
+		m_depths[i] = calc_depth(i)*0.7; // 0.7 is an arbitrary safety coefficient
 
 	return m_how_many_faces;
 };
 		
-Real BshSnowGrain::calc_depth(int I)
+Real BshSnowGrain::calc_depth(size_t I)
 {
 	Vector3r A(get<0>(m_faces[I]));
 	Vector3r B(get<1>(m_faces[I]));
 	Vector3r C(get<2>(m_faces[I]));
 	Vector3r N(get<3>(m_faces[I]));
 	Vector3r P((A+B+C)/3.0);
-	// ray N is cast from point P, whenre P is on some triangle.
+	// (1) ray N is cast from point P, where P is on some triangle.
 	// return the distance from P to next closest triangle
 
 	Real depth = 0;
@@ -319,12 +371,13 @@
 		{
 			Vector3r n(get<3>(f[i]));
 			Real parallel = n.Dot(N); // 'N' parallel to 'n' gives 0 dot product
-			if( parallel < 0) // must face in opposite directions
+			if( parallel < 0) // (2) must face in opposite directions
 			{
 				Vector3r a(get<0>(f[i]));
 				Vector3r b(get<1>(f[i]));
 				Vector3r c(get<2>(f[i]));
-				for(int Z = 0 ; Z < 4 ; ++Z)
+				for(int Z = 0 ; Z < 4 ; ++Z) // (ad. 1) OK, in fact it's not just from 'P' - we cast four rays.
+				                             // From 'P' and all triangle nodes
 				{
 					Vector3r PP;
 					switch(Z)
@@ -335,7 +388,7 @@
 						case 3 : PP = C; break;
 					}
 					Real neg_point_plane_distance = n.Dot(c - PP);
-					if( neg_point_plane_distance > 0 )
+					if( neg_point_plane_distance > 0 ) // (ad. 2) must be facing towards each other
 					{
 						// now calculate intersection point 'd' of ray 'N' from point 'PP' with the plane
 						Real u = neg_point_plane_distance/parallel;

Modified: trunk/pkg/snow/DataClass/BshSnowGrain.hpp
===================================================================
--- trunk/pkg/snow/DataClass/BshSnowGrain.hpp	2009-01-25 14:28:37 UTC (rev 1641)
+++ trunk/pkg/snow/DataClass/BshSnowGrain.hpp	2009-01-25 22:32:18 UTC (rev 1642)
@@ -50,7 +50,7 @@
 		Vector3r search(const T_DATA& dat,Vector3r c,Vector3r dir);
 		Vector3r search_plane(const T_DATA& dat,Vector3r c,Vector3r dir);
 
-		bool is_inside(Vector3r point);
+		bool is_point_inside_polyhedron(Vector3r point);
 		int how_many_faces();
 		bool face_is_valid(Vector3r&,Vector3r&,Vector3r&);
 		Real depth(int i){return m_depths[i];};
@@ -58,7 +58,7 @@
 		const std::vector<boost::tuple<Vector3r,Vector3r,Vector3r,Vector3r> >& get_faces_const_ref(){how_many_faces(); return m_faces;};
 	
 	private:
-		Real calc_depth(int);
+		Real calc_depth(size_t);
 		bool is_point_orthogonally_projected_on_triangle(Vector3r& a,Vector3r& b,Vector3r c,Vector3r& N,Vector3r& P,Real point_plane_distance = 0.0);
 
 		friend class boost::serialization::access;

Modified: trunk/pkg/snow/RenderingEngine/Ef1_BshSnowGrain_glDraw.cpp
===================================================================
--- trunk/pkg/snow/RenderingEngine/Ef1_BshSnowGrain_glDraw.cpp	2009-01-25 14:28:37 UTC (rev 1641)
+++ trunk/pkg/snow/RenderingEngine/Ef1_BshSnowGrain_glDraw.cpp	2009-01-25 22:32:18 UTC (rev 1642)
@@ -132,8 +132,9 @@
 //	}
 */
 
-/*
-	// check inside with other grain
+// check inside of selected grain, with grain 17
+
+
 //if(!surface)
 //{
 
@@ -150,8 +151,11 @@
 			{
 				std::cerr << "got body " << me << "\n";
 				int other=17;
-				BshSnowGrain* oth = static_cast<BshSnowGrain*>((*(Omega::instance().getRootBody()->bodies))[other]->geometricalModel.get());
-
+				if(other > 0 && other < Omega::instance().getRootBody()->bodies->size())
+				{
+				BshSnowGrain* oth = dynamic_cast<BshSnowGrain*>((*(Omega::instance().getRootBody()->bodies))[other]->geometricalModel.get());
+				if(oth)
+				{
 				Vector3r    my_pos((*(Omega::instance().getRootBody()->bodies))[me]->physicalParameters->se3.position);
 				Vector3r    oth_pos((*(Omega::instance().getRootBody()->bodies))[other]->physicalParameters->se3.position);
 				Quaternionr my_q((*(Omega::instance().getRootBody()->bodies))[me]->physicalParameters->se3.orientation);
@@ -163,7 +167,7 @@
 					for(size_t j=0 ; j < gr->slices[i].size() ; ++j)
 					{
 						Vector3r v(gr->slices[i][j]);
-						if(oth->is_inside( oth_q.Conjugate()*(my_q * v+my_pos-oth_pos)))
+						if(oth->is_point_inside_polyhedron( oth_q.Conjugate()*(my_q * v+my_pos-oth_pos)))
 						{
 //							me_inside.push_back( my_q * v+my_pos );
 							glTranslatev(v);
@@ -172,9 +176,15 @@
 						}
 					}
 				}
+				}
+				}
 			}
 		}
 	}
+
+
+
+// check inside of grain 17 with the selected one
 	me = 17;
 	if(me > 0 && me < Omega::instance().getRootBody()->bodies->size())
 	{
@@ -185,8 +195,11 @@
 			{
 				std::cerr << "got body " << me << "\n";
 				int other=(int)(Omega::instance().selectedBody);
-				BshSnowGrain* oth = static_cast<BshSnowGrain*>((*(Omega::instance().getRootBody()->bodies))[other]->geometricalModel.get());
-
+				if(other > 0 && other < Omega::instance().getRootBody()->bodies->size())
+				{
+				BshSnowGrain* oth = dynamic_cast<BshSnowGrain*>((*(Omega::instance().getRootBody()->bodies))[other]->geometricalModel.get());
+				if(oth)
+				{
 				Vector3r    my_pos((*(Omega::instance().getRootBody()->bodies))[me]->physicalParameters->se3.position);
 				Vector3r    oth_pos((*(Omega::instance().getRootBody()->bodies))[other]->physicalParameters->se3.position);
 				Quaternionr my_q((*(Omega::instance().getRootBody()->bodies))[me]->physicalParameters->se3.orientation);
@@ -198,7 +211,7 @@
 					for(size_t j=0 ; j < gr->slices[i].size() ; ++j)
 					{
 						Vector3r v(gr->slices[i][j]);
-						if(oth->is_inside( oth_q.Conjugate()*(my_q * v+my_pos-oth_pos)))
+						if(oth->is_point_inside_polyhedron( oth_q.Conjugate()*(my_q * v+my_pos-oth_pos)))
 						{
 //							oth_inside.push_back( my_q * v+my_pos );
 							glTranslatev(v);
@@ -207,11 +220,17 @@
 						}
 					}
 				}
+				}
+				}
 			}
 		}
 	}
 //}
-*/
+
+
+
+
+
 	// check current grain insides
 //if(!surface)
 //{
@@ -228,7 +247,7 @@
 //			for(float z=-1 ; z<1 ; z+=0.15)
 //			{
 //				Vector3r v=Vector3r(x,y,z)*LEN*0.7+my_pos-my_pos;
-//				if(gr->is_inside(v))
+//				if(gr->is_point_inside_polyhedron(v))
 //				{
 //					glTranslatev(v);
 //					glutSolidCube(LEN*0.02);
@@ -239,7 +258,7 @@
 //	}
 //}
 /*
-	// check inside with other grain
+	// check inside with other grain (check 35000 points, very slow)
 if(!surface)
 {
 //	glBegin(GL_POINTS);
@@ -272,7 +291,7 @@
 			for(float z=-1 ; z<1 ; z+=0.06)
 			{
 				Vector3r v=Vector3r(x,y,z)*LEN*1.2;
-						if(oth->is_inside( oth_q.Conjugate()*(my_q * v+my_pos-oth_pos)))
+						if(oth->is_point_inside_polyhedron( oth_q.Conjugate()*(my_q * v+my_pos-oth_pos)))
 						{
 						//	glVertex3v(v);
 					glTranslatev(v);