00001 /*---------------------------------------------------------------------+ 00002 | Library QgarLib, graphics analysis and recognition | 00003 | Copyright (C) 2002 Qgar Project, LORIA | 00004 | | 00005 | This library is free software; you can redistribute it and/or | 00006 | modify it under the terms of the GNU Lesser General Public | 00007 | License version 2.1, as published by the Free Software Foundation. | 00008 | | 00009 | This library is distributed in the hope that it will be useful, | 00010 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 00011 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 00012 | See the GNU Lesser General Public License for more details. | 00013 | | 00014 | The GNU Lesser General Public License is included in the file | 00015 | LICENSE.LGPL, in the root directory of the Qgar packaging. See | 00016 | http://www.gnu.org/licenses/lgpl.html for the terms of the licence. | 00017 | To receive a paper copy, write to the Free Software Foundation, | 00018 | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | 00019 | | 00020 | Contact Project Qgar for any information: | 00021 | LORIA - équipe Qgar | 00022 | B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France | 00023 | email: qgar-contact@loria.fr | 00024 | http://www.qgar.org/ | 00025 *---------------------------------------------------------------------*/ 00026 00027 00028 /** 00029 * @file _QGAR_point.TCC 00030 * @brief Implementation of global functions which compute points. 00031 * 00032 * Computational geometry equations can be found in the FAQ section 00033 * of comp.graphics.algorithms and are based on 00034 * [<a href="Bibliography.html#Kirk-1992">Kirk, 1992</a>], 00035 * pages 199-202, and 00036 * [<a href="Bibliography.html#ORourke-1994">O'Rourke, 1994</a>], 00037 * pages 249-51. 00038 * 00039 * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Gérald Masini">Gérald Masini</a> 00040 * @date February 03, 2005 18:53 00041 * @since Qgar 2.2 00042 */ 00043 00044 00045 00046 // QGAR 00047 #include <qgarlib/math.H> 00048 00049 00050 00051 namespace qgar 00052 { 00053 00054 00055 // ------------------------------------------------------------------- 00056 // A R C S A N D C I R C L E S 00057 // ------------------------------------------------------------------- 00058 00059 00060 // CENTER OF THE CIRCLE PASSING THROUGH THREE GIVEN POINTS 00061 // ======================================================= 00062 // Return 'false' if the 3 points are collinear, 'true' otherwise 00063 00064 00065 // GENERIC VERSION 00066 00067 template <class T> 00068 bool 00069 qgCircleCenter(const GenPoint<T>& t, 00070 const GenPoint<T>& p, 00071 const GenPoint<T>& q, 00072 GenPoint<double>& aCenter) 00073 { 00074 double tX = static_cast<double>(t.x()); 00075 double tY = static_cast<double>(t.y()); 00076 00077 double pX = static_cast<double>(p.x()); 00078 double pY = static_cast<double>(p.y()); 00079 00080 double qX = static_cast<double>(q.x()); 00081 double qY = static_cast<double>(q.y()); 00082 00083 // The coordinates of the center of the circle passing through 00084 // points t, p, and q are: 00085 // 00086 // A = pX - tX 00087 // B = pY - tY 00088 // C = qX - tX 00089 // D = qY - tY 00090 // E = A*(tX + pX) + B*(tY + pY) 00091 // F = C*(tX + qX) + D*(tY + qY) 00092 // G = 2 * (A*(qY - pY) - B*(qX - pX)) 00093 // 00094 // centerX = (D*E - B*F) / G 00095 // centerY = (A*F - C*E) / G 00096 // 00097 // If G is zero then the three points are collinear 00098 // and no finite-radius circle through them exists 00099 00100 double A = pX - tX; 00101 double B = pY - tY; 00102 double G = 2. * (A * (qY - pY) - B * (qX - pX)); 00103 00104 if (qgEq0(G)) 00105 { 00106 return false; // Collinear points 00107 } 00108 00109 double C = qX - tX; 00110 double D = qY - tY; 00111 double E = A * (tX + pX) + B * (tY + pY); 00112 double F = C * (tX + qX) + D * (tY + qY); 00113 00114 aCenter.setXY((D*E - B*F) / G, (A*F - C*E) / G); 00115 00116 return true; 00117 } 00118 00119 00120 // SPECIALIZED VERSION, TO PRESERVE EFFICIENCY WHEN USING DOUBLES 00121 // => no local variables needed 00122 00123 template <> 00124 inline bool 00125 qgCircleCenter<double>(const GenPoint<double>& t, 00126 const GenPoint<double>& p, 00127 const GenPoint<double>& q, 00128 GenPoint<double>& aCenter) 00129 { 00130 double A = p.x() - t.x(); 00131 double B = p.y() - t.y(); 00132 double G = 2. * (A * (q.y() - p.y()) - B * (q.x() - p.x())); 00133 00134 if (qgEq0(G)) 00135 { 00136 return false; // Collinear points 00137 } 00138 00139 double C = q.x() - t.x(); 00140 double D = q.y() - t.y(); 00141 double E = A * (t.x() + p.x()) + B * (t.y() + p.y()); 00142 double F = C * (t.x() + q.x()) + D * (t.y() + q.y()); 00143 00144 aCenter.setXY((D*E - B*F) / G, (A*F - C*E) / G); 00145 00146 return true; 00147 } 00148 00149 00150 // ------------------------------------------------------------------- 00151 // I N T E R S E C T I O N S 00152 // ------------------------------------------------------------------- 00153 00154 00155 // INTERSECTION OF THE LINES SUPPORTING TWO GIVEN SEGMENTS 00156 // ======================================================= 00157 // Return 'false' if the lines supporting the segments are 00158 // approximately collinear/parallel according to threshold 00159 // 'anAngle'. Otherwise, assign the intersection point to 00160 // 'aPt' and return 'true'. 00161 00162 template <class T> 00163 bool 00164 qgIntersect(const GenSegment<T>& ab, 00165 const GenSegment<T>& cd, 00166 GenPoint<double>& i, 00167 double anAngle) 00168 { 00169 // Are the lines approximately collinear or parallel? 00170 if (qgEq(ab.theta(), cd.theta(), anAngle) || 00171 qgEq(std::fabs(ab.theta() - cd.theta()), Math::QG_PI, anAngle)) 00172 { 00173 return false; 00174 } 00175 00176 // ________________________________________________________________ 00177 // 00178 // Each coordinate is separately casted: If only the result of the 00179 // of the operations of the numerator of 'r' were casted, overflows 00180 // may occur when dealing with large integers or floats 00181 00182 double xA = ab.xSource(); 00183 double yA = ab.ySource(); 00184 double xB = ab.xTarget(); 00185 double yB = ab.yTarget(); 00186 00187 double xC = cd.xSource(); 00188 double yC = cd.ySource(); 00189 double xD = cd.xTarget(); 00190 double yD = cd.yTarget(); 00191 // ________________________________________________________________ 00192 00193 // Let A,B,C,D be 2-space position vectors. 00194 // Then the directed line segments AB & CD are given by: 00195 // 00196 // AB = A + r(B - A), r in [0,1] 00197 // CD = C + s(D - C), s in [0,1] 00198 // 00199 // If AB & CD intersect, then 00200 // 00201 // A + r(B-A) = C + s(D-C): XA + r(XB - XA) = XC + s(XD - XC) 00202 // YA + r(YB - YA) = YC + s(YD - YC) 00203 // for r,s in [0,1] 00204 // 00205 // Solving the above for r and s yields 00206 // 00207 // (YA - YC)(XD - XC) - (XA - XC)(YD - YC) 00208 // r = --------------------------------------- [EQN5] 00209 // (XB - XA)(YD - YC) - (YB - YA)(XD - XC) 00210 // 00211 // (YA - YC)(XB - XA) - (XA - XC)(YB - YA) 00212 // s = --------------------------------------- [EQN6] 00213 // (XB - XA)(YD - YC) - (YB - YA)(XD - XC) 00214 // 00215 // Let I be the position vector of the intersection point, then 00216 // 00217 // I = A + r(B - A): XI = XA + r(XB - XA) [EQN7] 00218 // YI = YA + r(YB - YA) [EQN8] 00219 // 00220 // In EQN5 and EQN6, the denominator is: 00221 // d = (XB - XA)(YD - YC) - (YB - YA)(XD - XC) 00222 // 00223 // Let abDX = XB - XA, adDY = YB - YA, cdDX = XD - XC, cdDY = YD - YC 00224 // d = abDX*cdDY - abDY*cdDX 00225 // 00226 // EQN5 is: r = ((YA - YC)(XD - XC) - (XA - XC)(YD - YC)) / d 00227 // r = (cdDX(YA - YC) - cdDY(XA - XC)) / d 00228 // 00229 // EQN7 is: XI = XA + r(XB - XA) = XA + r*abDX 00230 // EQN8 is: YI = YA + r(YB - YA) = YA + r*abDY 00231 // 00232 // By examining the values of r & s, you can also determine some 00233 // other limiting conditions: 00234 // 00235 // If 0 <= r <= 1 & 0 <= s <=1 intersection exists 00236 // If r < 0 or r > 1 or s < 0 or s > 1 line segments do not intersect 00237 // 00238 // If the denominator in EQN5 is zero, AB & CD are parallel 00239 // If the numerator in EQN5 is also zero, AB & CD are coincident 00240 // 00241 // If the intersection point of the 2 lines are needed (lines in this 00242 // context mean infinite lines) regardless whether the two line 00243 // segments intersect, 00244 // then if r > 1, I is located on extension of AB 00245 // if r < 0, I is located on extension of BA 00246 // if s > 1, I is located on extension of CD 00247 // if s < 0, I is located on extension of DC 00248 // 00249 // Also note that the denominators of EQN5 & EQN6 are identical. 00250 00251 double abDX = xB - xA; 00252 double abDY = yB - yA; 00253 double cdDX = xD - xC; 00254 double cdDY = yD - yC; 00255 00256 double r = ((cdDX * (yA - yC)) - (cdDY * (xA - xC))) 00257 / 00258 ((abDX * cdDY) - (abDY * cdDX)); 00259 00260 i.setXY(xA + (r * abDX), yA + (r * abDY)); 00261 00262 return true; 00263 } 00264 00265 00266 // SPECIALIZED VERSION, TO PRESERVE EFFICIENCY WHEN USING DOUBLES: 00267 // NO LOCAL VARIABLES NEEDED 00268 00269 template <> 00270 inline bool 00271 qgIntersect<double>(const GenSegment<double>& ab, 00272 const GenSegment<double>& cd, 00273 GenPoint<double>& i, 00274 double anAngle) 00275 { 00276 // Are the lines approximately collinear or parallel? 00277 00278 if (qgEq(ab.theta(), cd.theta(), anAngle) || 00279 qgEq(std::fabs(ab.theta() - cd.theta()), Math::QG_PI, anAngle)) 00280 { 00281 return false; 00282 } 00283 00284 double abDX = ab.dx(); 00285 double abDY = ab.dy(); 00286 double cdDX = cd.dx(); 00287 double cdDY = cd.dy(); 00288 00289 double r = ( (cdDX * (ab.ySource() - cd.ySource())) 00290 - 00291 (cdDY * (ab.xSource() - cd.xSource())) ) 00292 / 00293 ((abDX * cdDY) - (abDY * cdDX)); 00294 00295 i.setXY(ab.xSource() + (r * abDX), ab.ySource() + (r * abDY)); 00296 00297 return true; 00298 } 00299 00300 00301 // INTERSECTION OF THE LINES SUPPORTING TWO GIVEN Qgar SEGMENTS 00302 // ============================================================ 00303 00304 template <class T> 00305 inline bool 00306 qgIntersect(const GenQgarSegment<T>& aQSeg1, 00307 const GenQgarSegment<T>& aQSeg2, 00308 GenPoint<double>& aPt, 00309 double anAngle) 00310 { 00311 return qgIntersect(aQSeg1.accessGeomStructure(), 00312 aQSeg2.accessGeomStructure(), 00313 aPt, 00314 anAngle); 00315 } 00316 00317 00318 // ------------------------------------------------------------------- 00319 // M I D D L E P O I N T S 00320 // ------------------------------------------------------------------- 00321 00322 00323 // MIDDLE POINT OF A SEGMENT 00324 // ========================= 00325 00326 template <class T> 00327 inline GenPoint<double> 00328 qgMiddle(const GenSegment<T>& aSeg) 00329 { 00330 return qgMiddle(aSeg.accessSource(), aSeg.accessTarget()); 00331 } 00332 00333 00334 // MIDDLE POINT OF A Qgar SEGMENT 00335 // ============================== 00336 00337 template <class T> 00338 inline GenPoint<double> 00339 qgMiddle(const GenQgarSegment<T>& aQSeg) 00340 { 00341 return qgMiddle(aQSeg.accessSource(), aQSeg.accessTarget()); 00342 } 00343 00344 00345 // MIDDLE POINT OF THE SEGMENT JOINING TWO POINTS 00346 // ============================================== 00347 00348 template <class T> 00349 inline GenPoint<double> 00350 qgMiddle(const GenPoint<T>& aPt1, const GenPoint<T>& aPt2) 00351 { 00352 return GenPoint<double>((static_cast<double>(aPt1.xSource()) 00353 + static_cast<double>(aPt2.xTarget())) / 2., 00354 (static_cast<double>(aPt1.ySource()) 00355 + static_cast<double>(aPt2.yTarget())) / 2.); 00356 } 00357 00358 00359 // ------------------------------------------------------------------- 00360 // P R O J E C T I O N S 00361 // ------------------------------------------------------------------- 00362 00363 00364 // RETURN THE ORTHOGONAL PROJECTION OF A POINT ONTO A SEGMENT 00365 // ========================================================== 00366 00367 template <class T> 00368 GenPoint<double> 00369 qgProjectPoint(const GenPoint<T>& aPt, const GenSegment<T>& aSeg) 00370 { 00371 GenPoint<double> p = GenPoint<double>(aPt); 00372 qgProject(p, aSeg); 00373 00374 return p; 00375 } 00376 00377 00378 // ORTHOGONAL PROJECTION OF THE GIVEN POINT ONTO A SEGMENT 00379 // ======================================================= 00380 00381 00382 template <class T> 00383 inline void 00384 qgProject(GenPoint<double>& aPt, const GenSegment<T>& aSeg) 00385 { 00386 qgProject(aPt, static_cast< GenSegment<double> >(aSeg)); 00387 } 00388 00389 00390 // SPECIALIZED VERSION, TO PRESERVE EFFICIENCY WHEN USING DOUBLES 00391 00392 00393 template <> 00394 inline void 00395 qgProject<double>(GenPoint<double>& aPt, const GenSegment<double>& aSeg) 00396 { 00397 // ___________________________________________________________________ 00398 // 00399 // Let the point be C (XC,YC) and the line be AB (XA,YA) to (XB,YB). 00400 // The length of the line segment AB is L: 00401 // 00402 // L = ((XB-XA)**2 + (YB-YA)**2)**0.5 00403 // and 00404 // r = ((YA - YC)(YA - YB) - (XA - XC)(XB - XA)) / L**2 [EQN1] 00405 // s = ((YA - YC)(XB - XA) - (XA - XC)(YB - YA)) / L**2 [EQN2] 00406 // 00407 // Let I be the point of perpendicular projection of C onto AB: 00408 // 00409 // XI = XA + r(XB - XA) [EQN3] 00410 // YI = YA + r(YB - YA) [EQN4] 00411 // ___________________________________________________________________ 00412 00413 // Let dx = XB-XA, dy = YA-YB in [EQN1] 00414 00415 double dx = aSeg.dx(); 00416 double dy = - aSeg.dy(); 00417 00418 // => r = (dy * (YA-YC) - dx * (XA-XC)) / L**2 [EQN1] 00419 00420 double l = aSeg.length(); 00421 double r = ( dy * (aSeg.ySource() - aPt.y()) 00422 - dx * (aSeg.xSource() - aPt.x()) ) 00423 / (l * l); 00424 00425 // => XI = XA + r * dx [EQN3] 00426 // => YI = YA + r * dy [EQN4] 00427 00428 aPt.setX(aSeg.xSource() + (r * dx)); 00429 aPt.setY(aSeg.ySource() - (r * dy)); 00430 } 00431 00432 00433 00434 // RETURN THE ORTHOGONAL PROJECTION OF A POINT ONTO A Qgar SEGMENT 00435 // =============================================================== 00436 00437 00438 template <class T> 00439 inline GenPoint<double> 00440 qgProjectPoint(const GenPoint<T>& aPt, const GenQgarSegment<T>& aQSeg) 00441 { 00442 return qgProjectPoint(aPt, aQSeg.accessGeomStructure()); 00443 } 00444 00445 00446 // ORTHOGONAL PROJECTION OF THE GIVEN POINT ONTO A SEGMENT 00447 // ======================================================= 00448 00449 00450 template <class T> 00451 inline void 00452 qgProject(GenPoint<double>& aPt, 00453 const GenQgarSegment<T>& aQSeg) 00454 { 00455 qgProject(aPt, aQSeg.accessGeomStructure()); 00456 } 00457 00458 00459 // ------------------------------------------------------------------- 00460 00461 00462 } // namespace qgar