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_GenSegment.TCC 00030 * @brief Implementation of function members of class qgar::GenSegment. 00031 * 00032 * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Gérald Masini">Gérald Masini</a> 00033 * @date December 14, 2004 18:28 00034 * @since Qgar 2.2 00035 */ 00036 00037 00038 00039 // STD 00040 #include <cmath> 00041 // QGAR 00042 #include <qgarlib/ISerializable.H> 00043 #include <qgarlib/math.H> 00044 00045 00046 00047 namespace qgar 00048 { 00049 00050 00051 // ------------------------------------------------------------------- 00052 // C O N S T R U C T O R S 00053 // ------------------------------------------------------------------- 00054 00055 00056 // DEFAULT CONSTRUCTOR 00057 00058 template <class T> 00059 GenSegment<T>::GenSegment() 00060 { 00061 // VOID 00062 } 00063 00064 00065 // COPY-CONSTRUCTOR 00066 00067 template <class T> 00068 GenSegment<T>::GenSegment(const GenSegment<T>& aSeg) 00069 00070 : AbstractGenPrimitive<T>(aSeg) 00071 00072 { 00073 // VOID 00074 } 00075 00076 00077 // INITIALIZE FROM A QGAR SEGMENT 00078 00079 template <class T> 00080 GenSegment<T>::GenSegment(const GenQgarSegment<T>& aQSeg) 00081 00082 : AbstractGenPrimitive<T>(aQSeg.accessSource(), 00083 aQSeg.accessTarget()) 00084 00085 { 00086 // VOID 00087 } 00088 00089 00090 // INITIALIZE FROM SOURCE AND TARGET POINTS 00091 00092 template <class T> 00093 GenSegment<T>::GenSegment(const GenPoint<T>& aSource, 00094 const GenPoint<T>& aTarget) 00095 00096 : AbstractGenPrimitive<T>(aSource, aTarget) 00097 00098 { 00099 // VOID 00100 } 00101 00102 00103 // INITIALIZE FROM COORDINATES 00104 00105 template <class T> 00106 GenSegment<T>::GenSegment(const T aXSource, 00107 const T aYSource, 00108 const T aXTarget, 00109 const T aYTarget) 00110 00111 : AbstractGenPrimitive<T>(aXSource, aYSource, aXTarget, aYTarget) 00112 00113 { 00114 // VOID 00115 } 00116 00117 00118 // ------------------------------------------------------------------- 00119 // D E S T R U C T O R 00120 // ------------------------------------------------------------------- 00121 00122 00123 template <class T> GenSegment<T>::~GenSegment() 00124 { 00125 // VOID 00126 } 00127 00128 00129 // ------------------------------------------------------------------- 00130 // C O P Y 00131 // ------------------------------------------------------------------- 00132 00133 00134 template <class T> 00135 GenSegment<T>* 00136 GenSegment<T>::clone() const 00137 { 00138 return new GenSegment<T>(*this); 00139 } 00140 00141 00142 // ------------------------------------------------------------------- 00143 // ACCESS TO GEOMETRICAL CHARACTERISTICS 00144 // ------------------------------------------------------------------- 00145 00146 00147 // GET SEGMENT LENGTH 00148 00149 template <class T> 00150 inline double 00151 GenSegment<T>::length() const 00152 { 00153 return hypot(this->dx(), this->dy()); 00154 } 00155 00156 00157 // GET SEGMENT SQUARED LENGTH 00158 00159 template <class T> 00160 double 00161 GenSegment<T>::sqr_length() const 00162 { 00163 double l = this->length(); 00164 return l * l; 00165 } 00166 00167 00168 // SIGNED DISTANCE BETWEEN (0,0) AND ITS PERPENDICULAR 00169 // PROJECTION ONTO THE LINE SUPPORTING THE SEGMENT 00170 // Precomputed 00171 00172 template <class T> 00173 double 00174 GenSegment<T>::rho() const 00175 { 00176 // Signed distance between point (0,0) and its perpendicular 00177 // projection onto the line supporting the current segment. 00178 // The value is negative if the line supporting the current 00179 // segment intersects the Y axis at a negative value. 00180 00181 // Let A (XA,YA) be the source point, 00182 // B (XB,YB) be the target point, 00183 // C (XC,YC) be the origin of the coordinate system 00184 // L be the length of AB 00185 // I be the projection of C onto line AB 00186 // 00187 // s = ((YA-YC)(XB-XA)-(XA-XC)(YB-YA)) / L**2 [EQN2] 00188 // (XC,YC) == 0 00189 // s = (YA(XB-XA) - XA(YB-YA)) / L**2 00190 // s = (YA*XB - XA*YB) / L**2 00191 // 00192 // Distance from C to I: 00193 // rho = s*L = (YA*XB - XA*YB) / L 00194 00195 return 00196 (double) qgAbs((this->ySource() * this->xTarget()) - (this->xSource() * this->yTarget())) 00197 / this->length(); 00198 00199 // _________________________________________________________________ 00200 // 00201 // Let A,B,C,D be 2-space position vectors. 00202 // The directed line segments AB & CD are given by: 00203 // 00204 // AB = A + r(B - A), r in [0,1] 00205 // CD = C + s(D - C), s in [0,1] 00206 // 00207 // If AB & CD intersect, then: 00208 // 00209 // A + r(B - A) = C + s(D - C) 00210 //: XA + r(XB - XA) = XC + s(XD - XC) 00211 // YA + r(YB - YA) = YC + s(YD - YC) for r,s in [0,1] 00212 // 00213 // Solving the above for r and s yields: 00214 // 00215 // ((YA - YC)(XD - XC)) - ((XA - XC)(YD - YC)) 00216 // r = ------------------------------------------- [EQN5] 00217 // ((XB - XA)(YD - YC)) - ((YB - YA)(XD - XC)) 00218 // 00219 // ((YA - YC)(XB - XA)) - ((XA - XC)(YB - YA)) 00220 // s = ------------------------------------------- [EQN6] 00221 // ((XB - XA)(YD - YC)) - ((Y B -YA)(XD - XC)) 00222 // 00223 // Let I be the position vector of the intersection point, then: 00224 // 00225 // I = A + r(B - A) 00226 // XI = XA + r(XB - XA) [EQN7] 00227 // YI = YA + r(YB - YA) [EQN8] 00228 // _________________________________________________________________ 00229 // 00230 // Intersection of the line supporting AB 00231 // and the Y axis supporting segment CD 00232 // 00233 // (XC,YC) = (0,0) 00234 // (XD,YD) = (0,-1) 00235 // 00236 // In EQN5 and EQN6, the denominator is: 00237 // d = ((XB - XA)(YD - YC)) - ((YB - YA)(XD - XC)) 00238 // d = ((XB - XA)(-1)) - ((YB - YA)(0)) 00239 // d = XA - XB 00240 // EQN5 is: 00241 // r = ((YA - YC)(XD - XC) - (XA - XC)(YD - YC)) / d 00242 // r = ((YA) (0) - (XA) (-1)) / (XA - XB) 00243 // r = XA / (XA - XB) 00244 // EQN8 is: 00245 // YI = YA + r(YB - YA) 00246 // YI = YA + XA (YB - YA) / (XA - XB) 00247 // YI = (YA (XA - XB) + XA (YB - YA)) / (XA - XB) 00248 // YI = (XA*YB - XB*YA) / (XA - XB) 00249 // YI = -rho / (XA - XB) = rho / (XB - XA) 00250 // _________________________________________________________________ 00251 // 00252 00253 // The distance is negative if the line supporting the 00254 // segment intersects the Y axis at a negative value. 00255 // 00256 // WARNING: When the line is parallel to the Y axis, the sign is + 00257 // when the segment is oriented towards positive Y coordinates and 00258 // its X coordinates are positive, or when the segment is oriented 00259 // towards negative Y coordinates ans its X coordinates are negative. 00260 // 00261 // if (this->dx() < 0) 00262 // { 00263 // return -rho; 00264 // } 00265 // else 00266 // { 00267 // return rho; 00268 // } 00269 } 00270 00271 00272 // ------------------------------------------------------------------- 00273 // G E O M E T R Y : A N G L E S 00274 // ------------------------------------------------------------------- 00275 00276 00277 // ANGLE BETWEEN THE X AXIS AND THE SEGMENT, IN [0, 2PI[ RADIANS 00278 00279 template <class T> 00280 inline double 00281 GenSegment<T>::theta() const 00282 { 00283 return qgAngle(this->_source, this->_target); 00284 } 00285 00286 00287 // SAME AS PREVIOUS 00288 00289 template <class T> 00290 inline double 00291 GenSegment<T>::angle() const 00292 { 00293 return this->theta(); 00294 } 00295 00296 00297 // ANGLE BETWEEN THE X AXIS AND THE SEGMENT, IN DEGREES 00298 00299 template <class T> 00300 inline double 00301 GenSegment<T>::thetaDegrees() const 00302 { 00303 return qgRadiansToDegrees(this->theta()); 00304 } 00305 00306 // SAME AS PREVIOUS 00307 00308 template <class T> 00309 inline double 00310 GenSegment<T>::angleDegrees() const 00311 { 00312 return qgRadiansToDegrees(this->theta()); 00313 } 00314 00315 00316 // ANGLE BETWEEN THE X AXIS AND THE SEGMENT, IN [0, PI[ RADIANS 00317 00318 template <class T> 00319 inline double 00320 GenSegment<T>::slope() const 00321 { 00322 return qgSlope(this->accessSource(), this->accessTarget()); 00323 } 00324 00325 00326 // ANGLE BETWEEN THE X AXIS AND THE SEGMENT, IN [0, 180[ DEGREES 00327 00328 template <class T> 00329 inline double 00330 GenSegment<T>::slopeDegrees() const 00331 { 00332 return qgRadiansToDegrees(this->slope()); 00333 } 00334 00335 00336 // ------------------------------------------------------------------- 00337 // G E O M E T R I C A L P R E D I C A T E S 00338 // ------------------------------------------------------------------- 00339 00340 00341 // DOES THE GIVEN POINT APPROXIMATELY BELONGS TO THE CURRENT SEGMENT? 00342 00343 template <class T> 00344 inline bool 00345 GenSegment<T>::contains(const GenPoint<T>& c, double aDist) 00346 { 00347 // ________________________________________________________________ 00348 // 00349 // Each coordinate is separately casted: If only the result 00350 // of the operations of the numerator of 'r' were casted, 00351 // overflows may occur when dealing with large integers or floats 00352 00353 double xA = static_cast<double>(this->xSource()); 00354 double yA = static_cast<double>(this->ySource()); 00355 00356 double xB = static_cast<double>(this->xTarget()); 00357 double yB = static_cast<double>(this->yTarget()); 00358 00359 double yC = static_cast<double>(c.y()); 00360 double xC = static_cast<double>(c.x()); 00361 // ________________________________________________________________ 00362 00363 // Let C be the point (XC,YC) 00364 // AB be the line (XA,YA) to (XB,YB) 00365 // L be the length of the line segment AB 00366 // 00367 // r = ((YA-YC)(YA-YB)-(XA-XC)(XB-XA)) / L**2 [EQN1] 00368 // 00369 // Let I be the point of perpendicular projection of C onto AB. 00370 // 00371 // if r < 0 I is on backward extension of AB 00372 // if r > 1 I is on ahead extension of AB 00373 // if 0 <= r <= 1 I is on AB 00374 00375 double l = this->length(); 00376 double r = (((yA - yC) * (yA - yB)) - ((xA - xC) * (xB - xA))) / (l * l); 00377 00378 if ((r >= 0.) && (r <= 1.)) 00379 { 00380 // C is on AB 00381 // => it must be close to AB 00382 return qgDist(c,*this) <= aDist; 00383 } 00384 else 00385 { 00386 // C is on a backward or ahead extension of AB 00387 // => it must close to A or to B 00388 return ( qgDist(c,this->accessSource()) <= aDist ) 00389 || 00390 ( qgDist(c,this->accessTarget()) <= aDist ); 00391 } 00392 } 00393 00394 00395 // SPECIALIZED VERSION, TO PRESERVE EFFICIENCY WHEN USING DOUBLES 00396 // => no cast/local variable needed 00397 00398 template <> 00399 inline bool 00400 GenSegment<double>::contains(const GenPoint<double>& c, double aDist) 00401 { 00402 double l = this->length(); 00403 double r = ( (-this->dy() * (this->ySource() - c.y())) 00404 - ( this->dx() * (this->xSource() - c.x()))) 00405 / 00406 (l * l); 00407 00408 if ((r >= 0.) && (r <= 1.)) 00409 { 00410 // C is on AB 00411 // => it must be close to AB 00412 return qgDist(c,*this) <= aDist; 00413 } 00414 else 00415 { 00416 // C is on a backward or ahead extension of AB 00417 // => it must close to A or to B 00418 return ( qgDist(c,this->accessSource()) <= aDist ) 00419 || 00420 ( qgDist(c,this->accessTarget()) <= aDist ); 00421 } 00422 } 00423 00424 00425 // ------------------------------------------------------------------- 00426 // O P E R A T O R S 00427 // ------------------------------------------------------------------- 00428 00429 00430 // ASSIGNMENT 00431 00432 template <class T> 00433 inline GenSegment<T>& 00434 GenSegment<T>::operator=(const GenSegment<T>& aSeg) 00435 { 00436 // ___________________________________________________________ 00437 // 00438 // Test removed for more efficiency 00439 // ___________________________________________________________ 00440 // 00441 // Are left hand side and right hand side different objects? 00442 // if (this != &aSeg) 00443 // { 00444 // ___________________________________________________________ 00445 00446 AbstractGenPrimitive<T>::operator=(aSeg); 00447 // ___________________________________________________________ 00448 // 00449 // } 00450 // ___________________________________________________________ 00451 00452 return *this; 00453 } 00454 00455 00456 // SAME AS FUNCTION qgar::GenSegment::eq 00457 00458 template <class T> 00459 inline bool 00460 GenSegment<T>::operator==(const GenSegment<T>& aSeg) const 00461 { 00462 return eq(aSeg); 00463 } 00464 00465 00466 // SAME AS FUNCTION qgar::GenSegment::notEq 00467 00468 template <class T> 00469 inline bool 00470 GenSegment<T>::operator!=(const GenSegment<T>& aSeg) const 00471 { 00472 return notEq(aSeg); 00473 } 00474 00475 00476 // ------------------------------------------------------------------- 00477 // F U N C T I O N A L O P E R A T O R S 00478 // ------------------------------------------------------------------- 00479 00480 00481 // EQUALITY 00482 00483 template <class T> 00484 bool 00485 GenSegment<T>::eq(const GenSegment<T>& aSeg) const 00486 { 00487 return (this->_source == aSeg._source) 00488 && (this->_target == aSeg._target); 00489 } 00490 00491 00492 // INEQUALITY 00493 00494 template <class T> 00495 bool 00496 GenSegment<T>::notEq(const GenSegment<T>& aSeg) const 00497 { 00498 return (this->_source != aSeg._source) 00499 || (this->_target != aSeg._target); 00500 } 00501 00502 00503 // ------------------------------------------------------------------- 00504 // S E R I A L I Z A T I O N / D E S E R I A L I Z A T I O N 00505 // ------------------------------------------------------------------- 00506 00507 00508 template <class T> 00509 std::istream& 00510 GenSegment<T>::read(std::istream& anInStream) 00511 { 00512 qgReadObjName(anInStream, "Segment"); 00513 00514 qgReadObjData(anInStream, this->_source); 00515 qgReadObjData(anInStream, this->_target); 00516 00517 return anInStream; 00518 } 00519 00520 template <class T> 00521 std::ostream& 00522 GenSegment<T>::write(std::ostream& anOutStream) const 00523 { 00524 anOutStream << "Segment(" 00525 << this->_source 00526 << ")(" 00527 << this->_target 00528 << ')'; 00529 return anOutStream; 00530 } 00531 00532 00533 // VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV 00534 // V V 00535 // V IMPLEMENTATION OF PURE VIRTUAL FUNCTIONS V 00536 // V INHERITED FROM AbstractGenPrimitive V 00537 // V V 00538 // VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV 00539 00540 00541 // ------------------------------------------------------------------- 00542 // G E O M E T R I C A L S T R U C T U R E U P D A T E S 00543 // ------------------------------------------------------------------- 00544 00545 00546 // THE SOURCE HAS BEEN CHANGED 00547 00548 template <class T> 00549 void 00550 GenSegment<T>::updateSource() 00551 { 00552 // NOTHING TO DO 00553 } 00554 00555 00556 // THE TARGET HAS BEEN CHANGED 00557 00558 template <class T> 00559 void 00560 GenSegment<T>::updateTarget() 00561 { 00562 // NOTHING TO DO 00563 } 00564 00565 00566 // BOTH SOURCE AND TARGET HAVE BEEN CHANGED 00567 00568 template <class T> 00569 void 00570 GenSegment<T>::updateSourceTarget() 00571 { 00572 // NOTHING TO DO 00573 } 00574 00575 00576 // ------------------------------------------------------------------- 00577 // G E O M E T R Y : T R A N S L A T I O N 00578 // ------------------------------------------------------------------- 00579 00580 00581 template <class T> 00582 inline void 00583 GenSegment<T>::translate(T aTransX, T aTransY) 00584 { 00585 this->setSourceTarget(this->xSource() + aTransX, 00586 this->ySource() + aTransY, 00587 this->xTarget() + aTransX, 00588 this->yTarget() + aTransY); 00589 } 00590 00591 00592 // VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV 00593 // V V 00594 // VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV 00595 00596 00597 } // namespace qgar