glc_geomtools.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003  This file is part of the GLC-lib library.
00004  Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
00005  Version 2.0.0 Beta 1, packaged on April 2010.
00006 
00007  http://glc-lib.sourceforge.net
00008 
00009  GLC-lib is free software; you can redistribute it and/or modify
00010  it under the terms of the GNU General Public License as published by
00011  the Free Software Foundation; either version 2 of the License, or
00012  (at your option) any later version.
00013 
00014  GLC-lib is distributed in the hope that it will be useful,
00015  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  GNU General Public License for more details.
00018 
00019  You should have received a copy of the GNU General Public License
00020  along with GLC-lib; if not, write to the Free Software
00021  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022 
00023 *****************************************************************************/
00024 
00026 
00027 #include "glc_geomtools.h"
00028 #include "glc_matrix4x4.h"
00029 
00030 #include <QtGlobal>
00031 
00033 //Tools Functions
00035 
00036 // Test if a polygon is convex
00037 bool glc::polygon2DIsConvex(const QList<GLC_Point2d>& vertices)
00038 {
00039         bool isConvex= true;
00040         const int size= vertices.size();
00041         if (vertices.size() > 3)
00042         {
00043                 GLC_Point2d s0(vertices.at(0));
00044                 GLC_Point2d s1(vertices.at(1));
00045                 GLC_Point2d s2(vertices.at(2));
00046                 const bool openAngle= ((s1.getX() - s0.getX()) * (s2.getY() - s0.getY()) - (s2.getX() - s0.getX()) * (s1.getY() - s0.getY())) < 0.0;
00047 
00048                 int i= 3;
00049                 while ((i < size) && isConvex)
00050                 {
00051                         s0= s1;
00052                         s1= s2;
00053                         s2= vertices.at(i);
00054                         isConvex= openAngle == (((s1.getX() - s0.getX()) * (s2.getY() - s0.getY()) - (s2.getX() - s0.getX()) * (s1.getY() - s0.getY())) < 0.0);
00055                         ++i;
00056                 }
00057         }
00058 
00059         return isConvex;
00060 }
00061 
00062 bool glc::polygonIsConvex(QList<GLuint>* pIndexList, const QList<float>& bulkList)
00063 {
00064         bool isConvex= true;
00065         const int size= pIndexList->size();
00066         GLuint currentIndex;
00067         GLC_Vector3d v0;
00068         GLC_Vector3d v1;
00069         int i= 0;
00070         while ((i < size) && isConvex)
00071         {
00072                 currentIndex= pIndexList->at(i);
00073                 v0.setVect(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2));
00074                 currentIndex= pIndexList->at((i + 1) % size);
00075                 v1.setVect(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2));
00076                 isConvex= (v0.angleWithVect(v1) < glc::PI);
00077                 ++i;
00078         }
00079         return isConvex;
00080 }
00081 // find intersection between two 2D segments
00082 QVector<GLC_Point2d> glc::findIntersection(const GLC_Point2d& s1p1, const GLC_Point2d& s1p2, const GLC_Point2d& s2p1, const GLC_Point2d& s2p2)
00083 {
00084         const GLC_Vector2d D0= s1p2 - s1p1;
00085         const GLC_Vector2d D1= s2p2 - s2p1;
00086         // The QVector of result points
00087         QVector<GLC_Point2d> result;
00088 
00089         const GLC_Vector2d E(s2p1 - s1p1);
00090         double kross= D0 ^ D1;
00091         double sqrKross= kross * kross;
00092         const double sqrLen0= D0.getX() * D0.getX() + D0.getY() * D0.getY();
00093         const double sqrLen1= D1.getX() * D1.getX() + D1.getY() * D1.getY();
00094         // Test if the line are nor parallel
00095         if (sqrKross > (EPSILON * sqrLen0 * sqrLen1))
00096         {
00097                 const double s= (E ^ D1) / kross;
00098                 if ((s < 0.0) || (s > 1.0))
00099                 {
00100                         // Intersection of lines is not a point on segment s1p1 + s * DO
00101                         return result; // Return empty QVector
00102                 }
00103                 const double t= (E ^ D0) / kross;
00104 
00105                 if ((t < 0.0) || (t > 1.0))
00106                 {
00107                         // Intersection of lines is not a point on segment s2p1 + t * D1
00108                         return result; // Return empty QVector
00109                 }
00110 
00111                 // Intersection of lines is a point on each segment
00112                 result << (s1p1 + (D0 * s));
00113                 return result; // Return a QVector of One Point
00114         }
00115 
00116         // Lines of the segments are parallel
00117         const double sqrLenE= E.getX() * E.getX() + E.getY() * E.getY();
00118         kross= E ^ D0;
00119         sqrKross= kross * kross;
00120         if (sqrKross > (EPSILON * sqrLen0 * sqrLenE))
00121         {
00122                 // Lines of the segments are different
00123                 return result; // Return empty QVector
00124         }
00125 
00126         // Lines of the segments are the same. Need to test for overlap of segments.
00127         const double s0= (D0 * E) / sqrLen0;
00128         const double s1= (D0 * D1) / sqrLen0;
00129         const double sMin= qMin(s0, s1);
00130         const double sMax= qMax(s0, s1);
00131         QVector<double> overlaps= findIntersection(0.0, 1.0, sMin, sMax);
00132         const int iMax= overlaps.size();
00133         for (int i= 0; i < iMax; ++i)
00134         {
00135                 result.append(s1p1 + (D0 * overlaps[i]));
00136         }
00137         return result;
00138 }
00139 
00140 // return true if there is an intersection between 2 segments
00141 bool glc::isIntersected(const GLC_Point2d& s1p1, const GLC_Point2d& s1p2, const GLC_Point2d& s2p1, const GLC_Point2d& s2p2)
00142 {
00143         const GLC_Vector2d D0= s1p2 - s1p1;
00144         const GLC_Vector2d D1= s2p2 - s2p1;
00145 
00146         const GLC_Vector2d E(s2p1 - s1p1);
00147         double kross= D0 ^ D1;
00148         double sqrKross= kross * kross;
00149         const double sqrLen0= D0.getX() * D0.getX() + D0.getY() * D0.getY();
00150         const double sqrLen1= D1.getX() * D1.getX() + D1.getY() * D1.getY();
00151         // Test if the line are nor parallel
00152         if (sqrKross > (EPSILON * sqrLen0 * sqrLen1))
00153         {
00154                 const double s= (E ^ D1) / kross;
00155                 if ((s < 0.0) || (s > 1.0))
00156                 {
00157                         // Intersection of lines is not a point on segment s1p1 + s * DO
00158                         return false;
00159                 }
00160                 const double t= (E ^ D0) / kross;
00161 
00162                 if ((t < 0.0) || (t > 1.0))
00163                 {
00164                         // Intersection of lines is not a point on segment s2p1 + t * D1
00165                         return false;
00166                 }
00167 
00168                 // Intersection of lines is a point on each segment
00169                 return true;
00170         }
00171 
00172         // Lines of the segments are parallel
00173         const double sqrLenE= E.getX() * E.getX() + E.getY() * E.getY();
00174         kross= E ^ D0;
00175         sqrKross= kross * kross;
00176         if (sqrKross > (EPSILON * sqrLen0 * sqrLenE))
00177         {
00178                 // Lines of the segments are different
00179                 return false;
00180         }
00181 
00182         // Lines of the segments are the same. Need to test for overlap of segments.
00183         const double s0= (D0 * E) / sqrLen0;
00184         const double s1= s0 + (D0 * D1) / sqrLen0;
00185         const double sMin= qMin(s0, s1);
00186         const double sMax= qMax(s0, s1);
00187         if (findIntersection(0.0, 1.0, sMin, sMax).size() == 0) return false; else return true;
00188 
00189 }
00190 
00191 // return true if there is an intersection between a ray and a segment
00192 bool glc::isIntersectedRaySegment(const GLC_Point2d& s1p1, const GLC_Vector2d& s1p2, const GLC_Point2d& s2p1, const GLC_Point2d& s2p2)
00193 {
00194         const GLC_Vector2d D0= s1p2 - s1p1;
00195         const GLC_Vector2d D1= s2p2 - s2p1;
00196 
00197         const GLC_Vector2d E(s2p1 - s1p1);
00198         double kross= D0 ^ D1;
00199         double sqrKross= kross * kross;
00200         const double sqrLen0= D0.getX() * D0.getX() + D0.getY() * D0.getY();
00201         const double sqrLen1= D1.getX() * D1.getX() + D1.getY() * D1.getY();
00202         // Test if the line are nor parallel
00203         if (sqrKross > (EPSILON * sqrLen0 * sqrLen1))
00204         {
00205                 const double s= (E ^ D1) / kross;
00206                 if ((s < 0.0))
00207                 {
00208                         // Intersection of lines is not a point on segment s1p1 + s * DO
00209                         return false;
00210                 }
00211                 const double t= (E ^ D0) / kross;
00212 
00213                 if ((t < 0.0) || (t > 1.0))
00214                 {
00215                         // Intersection of lines is not a point on segment s2p1 + t * D1
00216                         return false;
00217                 }
00218 
00219                 // Intersection of lines is a point on each segment
00220                 return true;
00221         }
00222 
00223         // Lines of the segments are parallel
00224         const double sqrLenE= E.getX() * E.getX() + E.getY() * E.getY();
00225         kross= E ^ D0;
00226         sqrKross= kross * kross;
00227         if (sqrKross > (EPSILON * sqrLen0 * sqrLenE))
00228         {
00229                 // Lines of are different
00230                 return false;
00231         }
00232         else return true;
00233 
00234 }
00235 
00236 // find intersection of two intervals [u0, u1] and [v0, v1]
00237 QVector<double> glc::findIntersection(const double& u0, const double& u1, const double& v0, const double& v1)
00238 {
00239         //Q_ASSERT((u0 < u1) and (v0 < v1));
00240         QVector<double> result;
00241         if (u1 < v0 || u0 > v1) return result; // Return empty QVector
00242 
00243         if (u1 > v0)
00244         {
00245                 if (u0 < v1)
00246                 {
00247                         if (u0 < v0) result.append(v0); else result.append(u0);
00248                         if (u1 > v1) result.append(v1); else result.append(u1);
00249                         return result;
00250                 }
00251                 else // u0 == v1
00252                 {
00253                         result.append(u0);
00254                         return result;
00255                 }
00256         }
00257         else // u1 == v0
00258         {
00259                 result.append(u1);
00260                 return result;
00261         }
00262 }
00263 
00264 // return true if the segment is in polygon cone
00265 bool glc::segmentInCone(const GLC_Point2d& V0, const GLC_Point2d& V1, const GLC_Point2d& VM, const GLC_Point2d& VP)
00266 {
00267         // assert: VM, V0, VP are not collinear
00268         const GLC_Vector2d diff(V1 - V0);
00269         const GLC_Vector2d edgeL(VM - V0);
00270         const GLC_Vector2d edgeR(VP - V0);
00271         if ((edgeR ^ edgeL) > 0)
00272         {
00273                 // Vertex is convex
00274                 return (((diff ^ edgeR) < 0.0) && ((diff ^ edgeL) > 0.0));
00275         }
00276         else
00277         {
00278                 // Vertex is reflex
00279                 return (((diff ^ edgeR) < 0.0) || ((diff ^ edgeL) > 0.0));
00280         }
00281 }
00282 
00283 // Return true if the segment is a polygon diagonal
00284 bool glc::isDiagonal(const QList<GLC_Point2d>& polygon, const int i0, const int i1)
00285 {
00286         const int size= polygon.size();
00287         int iM= (i0 - 1) % size;
00288         if (iM < 0) iM= size - 1;
00289         int iP= (i0 + 1) % size;
00290 
00291         if (!segmentInCone(polygon[i0], polygon[i1], polygon[iM], polygon[iP]))
00292         {
00293                 return false;
00294         }
00295 
00296         int j0= 0;
00297         int j1= size - 1;
00298         // test segment <polygon[i0], polygon[i1]> to see if it is a diagonal
00299         while (j0 < size)
00300         {
00301                 if (j0 != i0 && j0 != i1 && j1 != i0 && j1 != i1)
00302                 {
00303                         if (isIntersected(polygon[i0], polygon[i1], polygon[j0], polygon[j1]))
00304                                 return false;
00305                 }
00306 
00307                 j1= j0;
00308                 ++j0;
00309         }
00310 
00311         return true;
00312 }
00313 
00314 // Triangulate a polygon
00315 void glc::triangulate(QList<GLC_Point2d>& polygon, QList<int>& index, QList<int>& tList)
00316 {
00317         const int size= polygon.size();
00318         if (size == 3)
00319         {
00320                 tList << index[0] << index[1] << index[2];
00321                 return;
00322         }
00323         int i0= 0;
00324         int i1= 1;
00325         int i2= 2;
00326         while(i0 < size)
00327         {
00328                 if (isDiagonal(polygon, i0, i2))
00329                 {
00330                         // Add the triangle before removing the ear.
00331                         tList << index[i0] << index[i1] << index[i2];
00332                         // Remove the ear from polygon and index lists
00333                         polygon.removeAt(i1);
00334                         index.removeAt(i1);
00335                         // recurse to the new polygon
00336                         triangulate(polygon, index, tList);
00337                         return;
00338                 }
00339                 ++i0;
00340                 i1= (i1 + 1) % size;
00341                 i2= (i2 + 1) % size;
00342         }
00343 }
00344 
00345 // return true if the polygon is couterclockwise ordered
00346 bool glc::isCounterclockwiseOrdered(const QList<GLC_Point2d>& polygon)
00347 {
00348         const int size= polygon.size();
00349         int j0= 0;
00350         int j1= size - 1;
00351         // test segment <polygon[i0], polygon[i1]> to see if it is a diagonal
00352         while (j0 < size)
00353         {
00354                 GLC_Vector2d perp((polygon[j0] - polygon[j1]).perp());
00355                 int j2= 0;
00356                 int j3= size - 1;
00357                 bool isIntersect= false;
00358                 // Application of perp vector
00359                 GLC_Point2d moy((polygon[j0] + polygon[j1]) * 0.5);
00360                 while (j2 < size && !isIntersect)
00361                 {
00362                         if(j2 != j0 && j3 != j1)
00363                         {
00364                                 if (isIntersectedRaySegment(moy, (perp + moy), polygon[j2], polygon[j3]))
00365                                         isIntersect= true;
00366                         }
00367                         j3= j2;
00368                         ++j2;
00369                 }
00370                 if(!isIntersect) return false;
00371                 j1= j0;
00372                 ++j0;
00373         }
00374 
00375         return true;
00376 
00377 }
00378 
00379 // Triangulate a no convex polygon
00380 void glc::triangulatePolygon(QList<GLuint>* pIndexList, const QList<float>& bulkList)
00381 {
00382         int size= pIndexList->size();
00383         if (polygonIsConvex(pIndexList, bulkList))
00384         {
00385                 QList<GLuint> indexList(*pIndexList);
00386                 pIndexList->clear();
00387                 for (int i= 0; i < size - 2; ++i)
00388                 {
00389                         pIndexList->append(indexList.at(0));
00390                         pIndexList->append(indexList.at(i + 1));
00391                         pIndexList->append(indexList.at(i + 2));
00392                 }
00393         }
00394         else
00395         {
00396                 // Get the polygon vertice
00397                 QList<GLC_Point3d> originPoints;
00398                 QHash<int, int> indexMap;
00399 
00400                 QList<int> face;
00401                 GLC_Point3d currentPoint;
00402                 int delta= 0;
00403                 for (int i= 0; i < size; ++i)
00404                 {
00405                         const int currentIndex= pIndexList->at(i);
00406                         currentPoint= GLC_Point3d(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2));
00407                         if (!originPoints.contains(currentPoint))
00408                         {
00409                                 originPoints.append(GLC_Point3d(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2)));
00410                                 indexMap.insert(i - delta, currentIndex);
00411                                 face.append(i - delta);
00412                         }
00413                         else
00414                         {
00415                                 qDebug() << "Multi points";
00416                                 ++delta;
00417                         }
00418                 }
00419                 // Values of PindexList must be reset
00420                 pIndexList->clear();
00421 
00422                 // Update size
00423                 size= size - delta;
00424 
00425                 // Check new size
00426                 if (size < 3) return;
00427 
00428                 //-------------- Change frame to mach polygon plane
00429                         // Compute face normal
00430                         const GLC_Point3d point1(originPoints[0]);
00431                         const GLC_Point3d point2(originPoints[1]);
00432                         const GLC_Point3d point3(originPoints[2]);
00433 
00434                         const GLC_Vector3d edge1(point2 - point1);
00435                         const GLC_Vector3d edge2(point3 - point2);
00436 
00437                         GLC_Vector3d polygonPlaneNormal(edge1 ^ edge2);
00438                         polygonPlaneNormal.normalize();
00439 
00440                         // Create the transformation matrix
00441                         GLC_Matrix4x4 transformation;
00442 
00443                         GLC_Vector3d rotationAxis(polygonPlaneNormal ^ Z_AXIS);
00444                         if (!rotationAxis.isNull())
00445                         {
00446                                 const double angle= acos(polygonPlaneNormal * Z_AXIS);
00447                                 transformation.setMatRot(rotationAxis, angle);
00448                         }
00449 
00450                         QList<GLC_Point2d> polygon;
00451                         // Transform polygon vertexs
00452                         for (int i=0; i < size; ++i)
00453                         {
00454                                 originPoints[i]= transformation * originPoints[i];
00455                                 // Create 2d vector
00456                                 polygon << originPoints[i].toVector2d(Z_AXIS);
00457                         }
00458                         // Create the index
00459                         QList<int> index= face;
00460 
00461                         QList<int> tList;
00462                         const bool faceIsCounterclockwise= isCounterclockwiseOrdered(polygon);
00463 
00464                         if(!faceIsCounterclockwise)
00465                         {
00466                                 //qDebug() << "face Is Not Counterclockwise";
00467                                 const int max= size / 2;
00468                                 for (int i= 0; i < max; ++i)
00469                                 {
00470                                         polygon.swap(i, size - 1 -i);
00471                                         int temp= face[i];
00472                                         face[i]= face[size - 1 - i];
00473                                         face[size - 1 - i]= temp;
00474                                 }
00475                         }
00476 
00477                         triangulate(polygon, index, tList);
00478                         size= tList.size();
00479                         for (int i= 0; i < size; i+= 3)
00480                         {
00481                                 // Avoid normal problem
00482                                 if (faceIsCounterclockwise)
00483                                 {
00484                                         pIndexList->append(indexMap.value(face[tList[i]]));
00485                                         pIndexList->append(indexMap.value(face[tList[i + 1]]));
00486                                         pIndexList->append(indexMap.value(face[tList[i + 2]]));
00487                                 }
00488                                 else
00489                                 {
00490                                         pIndexList->append(indexMap.value(face[tList[i + 2]]));
00491                                         pIndexList->append(indexMap.value(face[tList[i + 1]]));
00492                                         pIndexList->append(indexMap.value(face[tList[i]]));
00493                                 }
00494                         }
00495                         Q_ASSERT(size == pIndexList->size());
00496         }
00497 
00498 }
00499 
00500 bool glc::lineIntersectPlane(const GLC_Line3d& line, const GLC_Plane& plane, GLC_Point3d* pPoint)
00501 {
00502         const GLC_Vector3d n= plane.normal();
00503         const GLC_Point3d p= line.startingPoint();
00504         const GLC_Vector3d d= line.direction();
00505 
00506         const double denominator= d * n;
00507         if (qFuzzyCompare(fabs(denominator), 0.0))
00508         {
00509                 qDebug() << " glc::lineIntersectPlane : Line parallel to the plane";
00510                 // The line is parallel to the plane
00511                 return false;
00512         }
00513         else
00514         {
00515                 // The line intersect the plane by one point
00516                 const double t= -((n * p) + plane.coefD()) / denominator;
00517                 (*pPoint)= p + (t * d);
00518 
00519                 return true;
00520         }
00521 }
00522 
00523 GLC_Point3d glc::project(const GLC_Point3d& point, const GLC_Line3d& line)
00524 {
00525         // Create the plane from the point with normal define by the line direction
00526         const GLC_Plane plane(line.direction().normalize(), point);
00527         GLC_Point3d intersection;
00528         const bool intersect= lineIntersectPlane(line, plane, &intersection);
00529         Q_ASSERT(intersect == true);
00530         return intersection;
00531 }
00532 
00533 

SourceForge.net Logo

©2005 Laurent Ribon