00001
00002
00003
00004
00005
00006
00007 #ifndef _COMPGEOM_H
00008 #define _COMPGEOM_H
00009
00010 #include <pthread.h>
00011 #include <iostream>
00012 #include <vector>
00013 #include <map>
00014 #include <list>
00015 #include <boost/shared_ptr.hpp>
00016 #include <Physsim/Constants.h>
00017 #include <Physsim/Triangle.h>
00018 #include <Physsim/Vector2.h>
00019 #include <Physsim/Polyhedron.h>
00020
00021
00022 extern "C"
00023 {
00024 #include <qhull/qhull.h>
00025 #include <qhull/qset.h>
00026 #include <qhull/user.h>
00027 }
00028
00029 namespace Physsim {
00030
00031 class Polyhedron;
00032
00034 class CompGeom
00035 {
00036 public:
00037 enum SegSegIntersectType { SegSegNoIntersect, SegSegIntersect, SegSegVertex, SegSegEdge };
00038 enum SegTriIntersectType { SegTriNoIntersect, SegTriInclFace, SegTriInclVertex, SegTriInclEdge, SegTriInside, SegTriVertex, SegTriEdge, SegTriFace, SegTriEdgeOverlap, SegTriPlanarIntersect };
00039 enum SegPlaneIntersectType { SegPlaneInPlane, SegPlaneToSide, SegPlaneFirst, SegPlaneSecond, SegPlaneOtherIntersect };
00040 enum PolygonLocation { PolygonInside, PolygonOutside, PolygonOnVertex, PolygonOnEdge };
00041 enum SegBoxIntersectType { SegBoxNoIntersect, SegBoxFullyInside, SegBoxPartiallyInside, SegBoxSurfaceIntersect, SegBoxPointIntersect, SegBoxPassThrough };
00042
00043 static Vector3 generate_point_on_plane(const Vector3& normal, Real d);
00044 static SegBoxIntersectType intersect_seg_box(const Vector3& lo, const Vector3& hi, const std::pair<Vector3, Vector3>& seg, Vector3& isect1, Vector3& isect2);
00045 static bool is_convex_polygon(const std::list<Vector3>& polygon, const Vector3& normal);
00046 static std::list<TrianglePtr> triangulate_convex_polygon(const std::list<Vector3>& polygon);
00047 static bool intersect_noncoplanar_tris(const Triangle& t1, const Triangle& t2, Vector3& p1, Vector3& p2);
00048 static boost::shared_ptr<std::list<Vector3> > intersect_tris(const Triangle& t1, const Triangle& t2);
00049 static Real fit_plane(const std::list<Vector3>& points, Vector3& normal, Real& d);
00050 static SegTriIntersectType intersect_seg_tri(const Triangle& t, const std::pair<Vector3, Vector3>& seg, Vector3& isect, Vector3& isect2);
00051 static SegSegIntersectType intersect_segs_3D(const std::pair<Vector3, Vector3>& s1, const std::pair<Vector3, Vector3>& s2, Vector3& isect, Vector3& isect2);
00052 static SegPlaneIntersectType intersect_seg_plane(const Triangle& tri, const std::pair<Vector3, Vector3>& seg, Vector3& isect, unsigned int& big_dim);
00053 static boost::shared_ptr<std::list<Vector3> > calc_convex_hull_2D(const std::list<Vector3>& points, const VectorN& normal);
00054 static PolyhedronPtr calc_convex_hull_3D(const std::list<Vector3>& points);
00055 static boost::shared_ptr<std::list<Vector3> > intersect_coplanar_tris(const Triangle& t1, const Triangle& t2, const Vector3& normal, Real d);
00056 static SegSegIntersectType intersect_segs_2D(const std::pair<Vector2, Vector2>& s1, const std::pair<Vector2, Vector2>& s2, Vector2& isect, Vector2& isect2);
00057 static PolygonLocation polygon_location(const std::list<Vector2>& polygon, const Vector2& point);
00058 static bool collinear(const Vector3& a, const Vector3& b, const Vector3& c);
00059 static bool collinear(const Vector2& a, const Vector2& b, const Vector2& c);
00060 static LongReal volume(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d);
00061 static int volume_sign(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d);
00062 static Vector3 calc_centroid_2D(const std::list<Vector3>& poly, const Vector3& normal);
00063 static void project_plane(std::list<Vector3>& points, const Vector3& normal, Real d);
00064 static bool coplanar(const Triangle& t1, const Triangle& t2);
00065 static Real calc_area(const std::list<Vector3>& poly, const Vector3& normal);
00066 static Vector3 to_3D(const Vector2& v);
00067 static Vector3 to_3D(const Vector2& v, Real d);
00068 static Vector2 to_2D(const Vector3& v);
00069
00070 static void det_line_endpoints(std::list<Vector3>& points, std::pair<Vector3, Vector3>& endpoints);
00071 static void det_line_endpoints(std::list<Vector2>& points, std::pair<Vector2, Vector2>& endpoints);
00072 static bool query_intersect_tri_tri(const Triangle& t1, const Triangle& t2);
00073
00074 template <class ForwardIterator>
00075 static bool collinear(ForwardIterator first, ForwardIterator last);
00076
00077 template <class ForwardIterator>
00078 static PolyhedronPtr calc_convex_hull_3D(ForwardIterator first, ForwardIterator last);
00079
00080 template <class ForwardIterator>
00081 static Vector3 calc_centroid(ForwardIterator first, ForwardIterator last);
00082
00083 private:
00084 static pthread_mutex_t _qhull_mutex;
00085 static bool compute_intervals_isectline(const Triangle& t1, Real vv0, Real vv1, Real vv2, Real d0, Real d1, Real d2, Real d0d1, Real d0d2, Real& isect0, Real& isect1, Vector3& isectpoint0, Vector3& isectpoint1);
00086 static void isect2X(const Vector3& vtx0, const Vector3& vtx1, const Vector3& vtx2, Real vv0, Real vv1, Real vv2, Real d0, Real d1, Real d2, Real& isect0, Real& isect1, Vector3& isectpoint0, Vector3& isectpoint1);
00087 static SegSegIntersectType get_parallel_intersect_type(const std::pair<Vector2, Vector2>& s1, const std::pair<Vector2, Vector2>& s2, Vector2& isect, Vector2& isect2);
00088 static bool between(const Vector2& a, const Vector2& b, const Vector2& c);
00089 static unsigned advance(unsigned a, unsigned* aa, unsigned n, bool inside, const Vector2& v, std::list<Vector3>& poly, const Matrix3& RT, Real d);
00090 static SegTriIntersectType seg_tri_cross(const Triangle& t, const Vector3& q, const Vector3& r);
00091 static SegTriIntersectType in_tri_3D(const Triangle& t, const Vector3& p, unsigned int skip_dim);
00092 static SegTriIntersectType in_tri_2D(const Vector2& ta, const Vector2& tb, const Vector2& tc, const Vector2& p);
00093 static void find_plane_coeff(const Triangle& t, Vector3& N, unsigned int& m, Real& dot);
00094 static VectorN normal_vec(const Vector3& a, const Vector3& b, const Vector3& c);
00095 static int area_sign(const Vector2& a, const Vector2& b, const Vector2& c);
00096 static bool test_edge_edge(const Vector3& p, const Vector3& a, const Vector3& b, Real Ax, Real Ay, unsigned i0, unsigned i1);
00097 static bool test_edge_tri(const Vector3& a, const Vector3& b, const Triangle& t, unsigned i0, unsigned i1);
00098 static bool test_point_in_tri(const Vector3& p, const Triangle& t, unsigned i0, unsigned i1);
00099 static bool test_coplanar_tri_tri(const Vector3& N, const Triangle& t1, const Triangle& t2);
00100 };
00101
00102
00103
00104
00105
00107 template <class ForwardIterator>
00108 bool CompGeom::collinear(ForwardIterator first, ForwardIterator last)
00109 {
00110 for (ForwardIterator i = first; i != last; i++)
00111 {
00112 ForwardIterator j = i;
00113 j++;
00114 for (; j != last; j++)
00115 {
00116 ForwardIterator k = j;
00117 k++;
00118 for (; k != last; k++)
00119 if (!collinear(*i, *j, *k))
00120 return false;
00121 }
00122 }
00123
00124 return true;
00125 }
00126
00128
00131 template <class ForwardIterator>
00132 Vector3 CompGeom::calc_centroid(ForwardIterator first, ForwardIterator last)
00133 {
00134 Real area_sum = 0;
00135
00136
00137 Vector3 centroid = ZEROS_3;
00138 for (ForwardIterator i = first; i != last; i++)
00139 {
00140 Real area = (*i)->get_area();
00141 area_sum += area;
00142 centroid += area * (*(*i)->a() + *(*i)->b() + *(*i)->c());
00143 }
00144
00145
00146 centroid /= (area_sum * 3);
00147
00148 return centroid;
00149 }
00150
00152
00157 template <class ForwardIterator>
00158 PolyhedronPtr CompGeom::calc_convex_hull_3D(ForwardIterator first, ForwardIterator last)
00159 {
00160 const unsigned X = 0, Y = 1, Z = 2;
00161 FILE* outfile=NULL;
00162 FILE* errfile=stderr;
00163 int exit_code;
00164 int curlong, totlong;
00165
00166
00167 #ifdef _DEBUG_COMPGEOM_
00168 outfile = stdout;
00169 #endif
00170
00171
00172 unsigned sz = 0;
00173 for (ForwardIterator i = first; i != last; i++)
00174 sz++;
00175
00176
00177 const int DIM = 3;
00178 const int N_POINTS = sz;
00179 const boolT IS_MALLOC = false;
00180 char flags[] = "qhull ";
00181
00182
00183 assert(N_POINTS >= 4);
00184
00185
00186 coordT* qhull_points = new coordT[N_POINTS*DIM];
00187 unsigned j=0;
00188 for (ForwardIterator i = first; i != last; i++)
00189 {
00190 qhull_points[j] = (*i)[X];
00191 qhull_points[j+1] = (*i)[Y];
00192 qhull_points[j+2] = (*i)[Z];
00193 j += DIM;
00194 }
00195
00196 #ifdef _DEBUG_COMPGEOM_
00197 std::cout << "computing 3D convex hull of: " << std::endl;
00198 for (ForwardIterator i = first; i != last; i++)
00199 std::cout << *i << std::endl;
00200 #endif
00201
00202
00203 pthread_mutex_lock(&_qhull_mutex);
00204
00205
00206 exit_code = qh_new_qhull(DIM, N_POINTS, qhull_points, IS_MALLOC, flags, outfile, errfile);
00207 if (exit_code)
00208 {
00209
00210 pthread_mutex_unlock(&_qhull_mutex);
00211 return PolyhedronPtr();
00212 }
00213
00214
00215 std::vector<TriangleConstPtr> mesh;
00216
00217
00218 std::map<vertexT*, Vector3Ptr > vertices;
00219 for (vertexT* vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next)
00220 {
00221 Vector3Ptr v(new Vector3);
00222 for (unsigned i=0; i< (unsigned) DIM; i++)
00223 (*v)[i] = vertex->point[i];
00224 vertices[vertex] = v;
00225 }
00226
00227
00228 for (facetT* facet=qh facet_list;facet && facet->next;facet=facet->next)
00229 {
00230 if (!facet->vertices)
00231 continue;
00232
00233
00234 std::vector<Vector3Ptr> facet_vertices;
00235
00236
00237 vertexT* vertex;
00238 for (vertexT** vertex_pointer = (vertexT**)& ((facet->vertices)->e[0].p); (vertex = (*vertex_pointer++));)
00239 facet_vertices.push_back(vertices[vertex]);
00240
00241
00242 bool colin = false;
00243 std::list<TrianglePtr > new_tris;
00244 for (unsigned i=1; i< facet_vertices.size()-1; i++)
00245 {
00246
00247 if (collinear(*facet_vertices[i], *facet_vertices[i+1], *facet_vertices.front()))
00248 {
00249 colin = true;
00250 new_tris.clear();
00251 break;
00252 }
00253 new_tris.push_back(TrianglePtr(new Triangle(facet_vertices[i], facet_vertices[i+1], facet_vertices.front())));
00254 }
00255
00256
00257 if (colin)
00258 {
00259
00260 Vector3Ptr centroid(new Vector3(ZEROS_3));
00261 for (unsigned i=0; i< facet_vertices.size(); i++)
00262 (*centroid) += *facet_vertices[i];
00263 (*centroid) /= facet_vertices.size();
00264
00265
00266 facet_vertices.push_back(facet_vertices.front());
00267 for (unsigned i=0; i< facet_vertices.size()-1; i++)
00268 new_tris.push_back(TrianglePtr(new Triangle(facet_vertices[i], facet_vertices[i+1], centroid)));
00269 }
00270
00271
00272 Vector3 normal = new_tris.front()->normal();
00273
00274
00275 Vector3 true_normal(facet->normal[X], facet->normal[Y], facet->normal[Z]);
00276 if (Vector3::dot(normal, true_normal) < 0)
00277 for (std::list<TrianglePtr >::iterator i = new_tris.begin(); i != new_tris.end(); i++)
00278 {
00279 Vector3ConstPtr a = (*i)->a();
00280 (*i)->set_a((*i)->b());
00281 (*i)->set_b(a);
00282 }
00283
00284
00285 while (!new_tris.empty())
00286 {
00287 mesh.push_back(new_tris.front());
00288 new_tris.pop_front();
00289 }
00290 }
00291
00292
00293 delete [] qhull_points;
00294
00295
00296 qh_freeqhull(!qh_ALL);
00297 qh_memfreeshort(&curlong, &totlong);
00298 assert(!curlong && !totlong);
00299
00300
00301 pthread_mutex_unlock(&_qhull_mutex);
00302
00303
00304 assert(mesh.size() >= 4);
00305
00306
00307 PolyhedronPtr polyhedron(new Polyhedron(mesh));
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 #ifdef _DEBUG_COMPGEOM_
00321 std::cout << "3D convex hull is:" << std::endl << *polyhedron;
00322 #endif
00323
00324 return polyhedron;
00325 }
00326
00327 }
00328
00329 #endif