00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00024
00025 #include "glc_geomtools.h"
00026 #include "glc_matrix4x4.h"
00027
00028 #include <QtGlobal>
00029
00030
00031 double glc::comparedPrecision= glc::defaultPrecision;
00032
00034
00036
00037
00038 bool glc::polygon2DIsConvex(const QList<GLC_Point2d>& vertices)
00039 {
00040 bool isConvex= true;
00041 const int size= vertices.size();
00042 if (vertices.size() > 3)
00043 {
00044 GLC_Point2d s0(vertices.at(0));
00045 GLC_Point2d s1(vertices.at(1));
00046 GLC_Point2d s2(vertices.at(2));
00047 const bool openAngle= ((s1.getX() - s0.getX()) * (s2.getY() - s0.getY()) - (s2.getX() - s0.getX()) * (s1.getY() - s0.getY())) < 0.0;
00048
00049 int i= 3;
00050 while ((i < size) && isConvex)
00051 {
00052 s0= s1;
00053 s1= s2;
00054 s2= vertices.at(i);
00055 isConvex= openAngle == (((s1.getX() - s0.getX()) * (s2.getY() - s0.getY()) - (s2.getX() - s0.getX()) * (s1.getY() - s0.getY())) < 0.0);
00056 ++i;
00057 }
00058 }
00059
00060 return isConvex;
00061 }
00062
00063 bool glc::polygonIsConvex(QList<GLuint>* pIndexList, const QList<float>& bulkList)
00064 {
00065 bool isConvex= true;
00066 const int size= pIndexList->size();
00067 GLuint currentIndex;
00068 GLC_Vector3d v0;
00069 GLC_Vector3d v1;
00070 int i= 0;
00071 while ((i < size) && isConvex)
00072 {
00073 currentIndex= pIndexList->at(i);
00074 v0.setVect(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2));
00075 currentIndex= pIndexList->at((i + 1) % size);
00076 v1.setVect(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2));
00077 isConvex= (v0.angleWithVect(v1) < glc::PI);
00078 ++i;
00079 }
00080 return isConvex;
00081 }
00082
00083 QVector<GLC_Point2d> glc::findIntersection(const GLC_Point2d& s1p1, const GLC_Point2d& s1p2, const GLC_Point2d& s2p1, const GLC_Point2d& s2p2)
00084 {
00085 const GLC_Vector2d D0= s1p2 - s1p1;
00086 const GLC_Vector2d D1= s2p2 - s2p1;
00087
00088 QVector<GLC_Point2d> result;
00089
00090 const GLC_Vector2d E(s2p1 - s1p1);
00091 double kross= D0 ^ D1;
00092 double sqrKross= kross * kross;
00093 const double sqrLen0= D0.getX() * D0.getX() + D0.getY() * D0.getY();
00094 const double sqrLen1= D1.getX() * D1.getX() + D1.getY() * D1.getY();
00095
00096 if (sqrKross > (EPSILON * sqrLen0 * sqrLen1))
00097 {
00098 const double s= (E ^ D1) / kross;
00099 if ((s < 0.0) || (s > 1.0))
00100 {
00101
00102 return result;
00103 }
00104 const double t= (E ^ D0) / kross;
00105
00106 if ((t < 0.0) || (t > 1.0))
00107 {
00108
00109 return result;
00110 }
00111
00112
00113 result << (s1p1 + (D0 * s));
00114 return result;
00115 }
00116
00117
00118 const double sqrLenE= E.getX() * E.getX() + E.getY() * E.getY();
00119 kross= E ^ D0;
00120 sqrKross= kross * kross;
00121 if (sqrKross > (EPSILON * sqrLen0 * sqrLenE))
00122 {
00123
00124 return result;
00125 }
00126
00127
00128 const double s0= (D0 * E) / sqrLen0;
00129 const double s1= (D0 * D1) / sqrLen0;
00130 const double sMin= qMin(s0, s1);
00131 const double sMax= qMax(s0, s1);
00132 QVector<double> overlaps= findIntersection(0.0, 1.0, sMin, sMax);
00133 const int iMax= overlaps.size();
00134 for (int i= 0; i < iMax; ++i)
00135 {
00136 result.append(s1p1 + (D0 * overlaps[i]));
00137 }
00138 return result;
00139 }
00140
00141
00142 bool glc::isIntersected(const GLC_Point2d& s1p1, const GLC_Point2d& s1p2, const GLC_Point2d& s2p1, const GLC_Point2d& s2p2)
00143 {
00144 const GLC_Vector2d D0= s1p2 - s1p1;
00145 const GLC_Vector2d D1= s2p2 - s2p1;
00146
00147 const GLC_Vector2d E(s2p1 - s1p1);
00148 double kross= D0 ^ D1;
00149 double sqrKross= kross * kross;
00150 const double sqrLen0= D0.getX() * D0.getX() + D0.getY() * D0.getY();
00151 const double sqrLen1= D1.getX() * D1.getX() + D1.getY() * D1.getY();
00152
00153 if (sqrKross > (EPSILON * sqrLen0 * sqrLen1))
00154 {
00155 const double s= (E ^ D1) / kross;
00156 if ((s < 0.0) || (s > 1.0))
00157 {
00158
00159 return false;
00160 }
00161 const double t= (E ^ D0) / kross;
00162
00163 if ((t < 0.0) || (t > 1.0))
00164 {
00165
00166 return false;
00167 }
00168
00169
00170 return true;
00171 }
00172
00173
00174 const double sqrLenE= E.getX() * E.getX() + E.getY() * E.getY();
00175 kross= E ^ D0;
00176 sqrKross= kross * kross;
00177 if (sqrKross > (EPSILON * sqrLen0 * sqrLenE))
00178 {
00179
00180 return false;
00181 }
00182
00183
00184 const double s0= (D0 * E) / sqrLen0;
00185 const double s1= s0 + (D0 * D1) / sqrLen0;
00186 const double sMin= qMin(s0, s1);
00187 const double sMax= qMax(s0, s1);
00188 if (findIntersection(0.0, 1.0, sMin, sMax).size() == 0) return false; else return true;
00189
00190 }
00191
00192
00193 bool glc::isIntersectedRaySegment(const GLC_Point2d& s1p1, const GLC_Vector2d& s1p2, const GLC_Point2d& s2p1, const GLC_Point2d& s2p2)
00194 {
00195 const GLC_Vector2d D0= s1p2 - s1p1;
00196 const GLC_Vector2d D1= s2p2 - s2p1;
00197
00198 const GLC_Vector2d E(s2p1 - s1p1);
00199 double kross= D0 ^ D1;
00200 double sqrKross= kross * kross;
00201 const double sqrLen0= D0.getX() * D0.getX() + D0.getY() * D0.getY();
00202 const double sqrLen1= D1.getX() * D1.getX() + D1.getY() * D1.getY();
00203
00204 if (sqrKross > (EPSILON * sqrLen0 * sqrLen1))
00205 {
00206 const double s= (E ^ D1) / kross;
00207 if ((s < 0.0))
00208 {
00209
00210 return false;
00211 }
00212 const double t= (E ^ D0) / kross;
00213
00214 if ((t < 0.0) || (t > 1.0))
00215 {
00216
00217 return false;
00218 }
00219
00220
00221 return true;
00222 }
00223
00224
00225 const double sqrLenE= E.getX() * E.getX() + E.getY() * E.getY();
00226 kross= E ^ D0;
00227 sqrKross= kross * kross;
00228 if (sqrKross > (EPSILON * sqrLen0 * sqrLenE))
00229 {
00230
00231 return false;
00232 }
00233 else return true;
00234
00235 }
00236
00237
00238 QVector<double> glc::findIntersection(const double& u0, const double& u1, const double& v0, const double& v1)
00239 {
00240
00241 QVector<double> result;
00242 if (u1 < v0 || u0 > v1) return result;
00243
00244 if (u1 > v0)
00245 {
00246 if (u0 < v1)
00247 {
00248 if (u0 < v0) result.append(v0); else result.append(u0);
00249 if (u1 > v1) result.append(v1); else result.append(u1);
00250 return result;
00251 }
00252 else
00253 {
00254 result.append(u0);
00255 return result;
00256 }
00257 }
00258 else
00259 {
00260 result.append(u1);
00261 return result;
00262 }
00263 }
00264
00265
00266 bool glc::segmentInCone(const GLC_Point2d& V0, const GLC_Point2d& V1, const GLC_Point2d& VM, const GLC_Point2d& VP)
00267 {
00268
00269 const GLC_Vector2d diff(V1 - V0);
00270 const GLC_Vector2d edgeL(VM - V0);
00271 const GLC_Vector2d edgeR(VP - V0);
00272 if ((edgeR ^ edgeL) > 0)
00273 {
00274
00275 return (((diff ^ edgeR) < 0.0) && ((diff ^ edgeL) > 0.0));
00276 }
00277 else
00278 {
00279
00280 return (((diff ^ edgeR) < 0.0) || ((diff ^ edgeL) > 0.0));
00281 }
00282 }
00283
00284
00285 bool glc::isDiagonal(const QList<GLC_Point2d>& polygon, const int i0, const int i1)
00286 {
00287 const int size= polygon.size();
00288 int iM= (i0 - 1) % size;
00289 if (iM < 0) iM= size - 1;
00290 int iP= (i0 + 1) % size;
00291
00292 if (!segmentInCone(polygon[i0], polygon[i1], polygon[iM], polygon[iP]))
00293 {
00294 return false;
00295 }
00296
00297 int j0= 0;
00298 int j1= size - 1;
00299
00300 while (j0 < size)
00301 {
00302 if (j0 != i0 && j0 != i1 && j1 != i0 && j1 != i1)
00303 {
00304 if (isIntersected(polygon[i0], polygon[i1], polygon[j0], polygon[j1]))
00305 return false;
00306 }
00307
00308 j1= j0;
00309 ++j0;
00310 }
00311
00312 return true;
00313 }
00314
00315
00316 void glc::triangulate(QList<GLC_Point2d>& polygon, QList<int>& index, QList<int>& tList)
00317 {
00318 const int size= polygon.size();
00319 if (size == 3)
00320 {
00321 tList << index[0] << index[1] << index[2];
00322 return;
00323 }
00324 int i0= 0;
00325 int i1= 1;
00326 int i2= 2;
00327 while(i0 < size)
00328 {
00329 if (isDiagonal(polygon, i0, i2))
00330 {
00331
00332 tList << index[i0] << index[i1] << index[i2];
00333
00334 polygon.removeAt(i1);
00335 index.removeAt(i1);
00336
00337 triangulate(polygon, index, tList);
00338 return;
00339 }
00340 ++i0;
00341 i1= (i1 + 1) % size;
00342 i2= (i2 + 1) % size;
00343 }
00344 }
00345
00346
00347 bool glc::isCounterclockwiseOrdered(const QList<GLC_Point2d>& polygon)
00348 {
00349 const int size= polygon.size();
00350 int j0= 0;
00351 int j1= size - 1;
00352
00353 while (j0 < size)
00354 {
00355 GLC_Vector2d perp((polygon[j0] - polygon[j1]).perp());
00356 int j2= 0;
00357 int j3= size - 1;
00358 bool isIntersect= false;
00359
00360 GLC_Point2d moy((polygon[j0] + polygon[j1]) * 0.5);
00361 while (j2 < size && !isIntersect)
00362 {
00363 if(j2 != j0 && j3 != j1)
00364 {
00365 if (isIntersectedRaySegment(moy, (perp + moy), polygon[j2], polygon[j3]))
00366 isIntersect= true;
00367 }
00368 j3= j2;
00369 ++j2;
00370 }
00371 if(!isIntersect) return false;
00372 j1= j0;
00373 ++j0;
00374 }
00375
00376 return true;
00377
00378 }
00379
00380
00381 void glc::triangulatePolygon(QList<GLuint>* pIndexList, const QList<float>& bulkList)
00382 {
00383 int size= pIndexList->size();
00384 if (polygonIsConvex(pIndexList, bulkList))
00385 {
00386 QList<GLuint> indexList(*pIndexList);
00387 pIndexList->clear();
00388 for (int i= 0; i < size - 2; ++i)
00389 {
00390 pIndexList->append(indexList.at(0));
00391 pIndexList->append(indexList.at(i + 1));
00392 pIndexList->append(indexList.at(i + 2));
00393 }
00394 }
00395 else
00396 {
00397
00398 QList<GLC_Point3d> originPoints;
00399 QHash<int, int> indexMap;
00400
00401 QList<int> face;
00402 GLC_Point3d currentPoint;
00403 int delta= 0;
00404 for (int i= 0; i < size; ++i)
00405 {
00406 const int currentIndex= pIndexList->at(i);
00407 currentPoint= GLC_Point3d(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2));
00408 if (!originPoints.contains(currentPoint))
00409 {
00410 originPoints.append(GLC_Point3d(bulkList.at(currentIndex * 3), bulkList.at(currentIndex * 3 + 1), bulkList.at(currentIndex * 3 + 2)));
00411 indexMap.insert(i - delta, currentIndex);
00412 face.append(i - delta);
00413 }
00414 else
00415 {
00416 qDebug() << "Multi points";
00417 ++delta;
00418 }
00419 }
00420
00421 pIndexList->clear();
00422
00423
00424 size= size - delta;
00425
00426
00427 if (size < 3) return;
00428
00429
00430
00431 const GLC_Point3d point1(originPoints[0]);
00432 const GLC_Point3d point2(originPoints[1]);
00433 const GLC_Point3d point3(originPoints[2]);
00434
00435 const GLC_Vector3d edge1(point2 - point1);
00436 const GLC_Vector3d edge2(point3 - point2);
00437
00438 GLC_Vector3d polygonPlaneNormal(edge1 ^ edge2);
00439 polygonPlaneNormal.normalize();
00440
00441
00442 GLC_Matrix4x4 transformation;
00443
00444 GLC_Vector3d rotationAxis(polygonPlaneNormal ^ Z_AXIS);
00445 if (!rotationAxis.isNull())
00446 {
00447 const double angle= acos(polygonPlaneNormal * Z_AXIS);
00448 transformation.setMatRot(rotationAxis, angle);
00449 }
00450
00451 QList<GLC_Point2d> polygon;
00452
00453 for (int i=0; i < size; ++i)
00454 {
00455 originPoints[i]= transformation * originPoints[i];
00456
00457 polygon << originPoints[i].toVector2d(Z_AXIS);
00458 }
00459
00460 QList<int> index= face;
00461
00462 QList<int> tList;
00463 const bool faceIsCounterclockwise= isCounterclockwiseOrdered(polygon);
00464
00465 if(!faceIsCounterclockwise)
00466 {
00467
00468 const int max= size / 2;
00469 for (int i= 0; i < max; ++i)
00470 {
00471 polygon.swap(i, size - 1 -i);
00472 int temp= face[i];
00473 face[i]= face[size - 1 - i];
00474 face[size - 1 - i]= temp;
00475 }
00476 }
00477
00478 triangulate(polygon, index, tList);
00479 size= tList.size();
00480 for (int i= 0; i < size; i+= 3)
00481 {
00482
00483 if (faceIsCounterclockwise)
00484 {
00485 pIndexList->append(indexMap.value(face[tList[i]]));
00486 pIndexList->append(indexMap.value(face[tList[i + 1]]));
00487 pIndexList->append(indexMap.value(face[tList[i + 2]]));
00488 }
00489 else
00490 {
00491 pIndexList->append(indexMap.value(face[tList[i + 2]]));
00492 pIndexList->append(indexMap.value(face[tList[i + 1]]));
00493 pIndexList->append(indexMap.value(face[tList[i]]));
00494 }
00495 }
00496 Q_ASSERT(size == pIndexList->size());
00497 }
00498
00499 }
00500
00501 bool glc::lineIntersectPlane(const GLC_Line3d& line, const GLC_Plane& plane, GLC_Point3d* pPoint)
00502 {
00503 const GLC_Vector3d n= plane.normal();
00504 const GLC_Point3d p= line.startingPoint();
00505 const GLC_Vector3d d= line.direction();
00506
00507 const double denominator= d * n;
00508 if (qFuzzyCompare(fabs(denominator), 0.0))
00509 {
00510 qDebug() << " glc::lineIntersectPlane : Line parallel to the plane";
00511
00512 return false;
00513 }
00514 else
00515 {
00516
00517 const double t= -((n * p) + plane.coefD()) / denominator;
00518 (*pPoint)= p + (t * d);
00519
00520 return true;
00521 }
00522 }
00523
00524 GLC_Point3d glc::project(const GLC_Point3d& point, const GLC_Line3d& line)
00525 {
00526 const GLC_Vector3d lineDirection(line.direction().normalize());
00527 double t= lineDirection * (point - line.startingPoint());
00528 GLC_Point3d projectedPoint= line.startingPoint() + (t * lineDirection);
00529 return projectedPoint;
00530 }
00531
00532 double glc::pointLineDistance(const GLC_Point3d& point, const GLC_Line3d& line)
00533 {
00534 const GLC_Vector3d lineDirection(line.direction().normalize());
00535 double t= lineDirection * (point - line.startingPoint());
00536 GLC_Point3d projectedPoint= line.startingPoint() + (t * lineDirection);
00537 return (point - projectedPoint).length();
00538 }
00539
00540 bool glc::pointsAreCollinear(const GLC_Point3d& p1, const GLC_Point3d& p2, const GLC_Point3d& p3)
00541 {
00542 bool subject= false;
00543 if (compare(p1, p2) || compare(p1, p3) || compare(p2, p3))
00544 {
00545 subject= true;
00546 }
00547 else
00548 {
00549 GLC_Vector3d p1p2= (p2 - p1).setLength(1.0);
00550 GLC_Vector3d p2p3= (p3 - p2).setLength(1.0);
00551 subject= (compare(p1p2, p2p3) || compare(p1p2, p2p3.inverted()));
00552 }
00553 return subject;
00554 }
00555
00556 bool glc::compare(double p1, double p2)
00557 {
00558 return qAbs(p1 - p2) <= comparedPrecision;
00559 }
00560
00561 bool glc::compareAngle(double p1, double p2)
00562 {
00563 const double anglePrecision= toRadian(comparedPrecision);
00564 return qAbs(p1 - p2) <= anglePrecision;
00565 }
00566
00567 bool glc::compare(const GLC_Vector3d& v1, const GLC_Vector3d& v2)
00568 {
00569 bool compareResult= (qAbs(v1.x() - v2.x()) <= comparedPrecision);
00570 compareResult= compareResult && (qAbs(v1.y() - v2.y()) <= comparedPrecision);
00571 compareResult= compareResult && (qAbs(v1.z() - v2.z()) <= comparedPrecision);
00572
00573 return compareResult;
00574 }
00575
00576 bool glc::compare(const GLC_Vector2d& v1, const GLC_Vector2d& v2)
00577 {
00578 bool compareResult= (qAbs(v1.getX() - v2.getX()) <= comparedPrecision);
00579 return compareResult && (qAbs(v1.getY() - v2.getY()) <= comparedPrecision);
00580 }
00581
00582 bool glc::compare(const QPointF& v1, const QPointF& v2)
00583 {
00584 bool compareResult= (qAbs(v1.x() - v2.x()) <= comparedPrecision);
00585 return compareResult && (qAbs(v1.y() - v2.y()) <= comparedPrecision);
00586 }
00587
00588 bool glc::pointInPolygon(const GLC_Point2d& point, const QList<GLC_Point2d>& polygon)
00589 {
00590 const int polygonSize= polygon.size();
00591 bool inside= false;
00592 int i= 0;
00593 int j= polygonSize - 1;
00594
00595 while (i < polygonSize)
00596 {
00597 const GLC_Point2d point0= polygon.at(i);
00598 const GLC_Point2d point1= polygon.at(j);
00599 if (point.getY() < point1.getY())
00600 {
00601
00602 if (point0.getY() <= point.getY())
00603 {
00604
00605 const double val1= (point.getY() - point0.getY()) * (point1.getX() - point0.getX());
00606 const double val2= (point.getX() - point0.getX()) * (point1.getY() - point0.getY());
00607 if (val1 > val2) inside= !inside;
00608 }
00609 }
00610 else if (point.getY() < point0.getY())
00611 {
00612
00613 const double val1= (point.getY() - point0.getY()) * (point1.getX() - point0.getX());
00614 const double val2= (point.getX() - point0.getX()) * (point1.getY() - point0.getY());
00615 if (val1 < val2) inside= !inside;
00616 }
00617 j= i;
00618 ++i;
00619 }
00620 return inside;
00621 }
00622
00623 double glc::zeroTo2PIAngle(double angle)
00624 {
00625 if (qFuzzyCompare(fabs(angle), glc::PI))
00626 {
00627 angle= glc::PI;
00628 }
00629 else if (angle < 0)
00630 {
00631 angle= (2.0 * glc::PI) + angle;
00632 }
00633 return angle;
00634 }