You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
11 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 CERN
  5. * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #ifndef __SEG_H
  25. #define __SEG_H
  26. #include <math.h> // for sqrt
  27. #include <stdlib.h> // for abs
  28. #include <ostream> // for operator<<, ostream, basic_os...
  29. #include <type_traits> // for swap
  30. #include <core/optional.h>
  31. #include <math/util.h> // for rescale
  32. #include <math/vector2d.h>
  33. typedef OPT<VECTOR2I> OPT_VECTOR2I;
  34. class SEG
  35. {
  36. public:
  37. using ecoord = VECTOR2I::extended_type;
  38. friend inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg );
  39. /* Start and the of the segment. Public, to make access simpler.
  40. */
  41. VECTOR2I A;
  42. VECTOR2I B;
  43. /** Default constructor
  44. * Creates an empty (0, 0) segment
  45. */
  46. SEG()
  47. {
  48. m_index = -1;
  49. }
  50. /**
  51. * Constructor
  52. * Creates a segment between (aX1, aY1) and (aX2, aY2)
  53. */
  54. SEG( int aX1, int aY1, int aX2, int aY2 ) :
  55. A ( VECTOR2I( aX1, aY1 ) ),
  56. B ( VECTOR2I( aX2, aY2 ) )
  57. {
  58. m_index = -1;
  59. }
  60. /**
  61. * Constructor
  62. * Creates a segment between (aA) and (aB)
  63. */
  64. SEG( const VECTOR2I& aA, const VECTOR2I& aB ) : A( aA ), B( aB )
  65. {
  66. m_index = -1;
  67. }
  68. /**
  69. * Constructor
  70. * Creates a segment between (aA) and (aB), referenced to a multi-segment shape
  71. * @param aA reference to the start point in the parent shape
  72. * @param aB reference to the end point in the parent shape
  73. * @param aIndex index of the segment within the parent shape
  74. */
  75. SEG( const VECTOR2I& aA, const VECTOR2I& aB, int aIndex ) : A( aA ), B( aB )
  76. {
  77. m_index = aIndex;
  78. }
  79. /**
  80. * Copy constructor
  81. */
  82. SEG( const SEG& aSeg ) : A( aSeg.A ), B( aSeg.B ), m_index( aSeg.m_index )
  83. {
  84. }
  85. SEG& operator=( const SEG& aSeg )
  86. {
  87. A = aSeg.A;
  88. B = aSeg.B;
  89. m_index = aSeg.m_index;
  90. return *this;
  91. }
  92. bool operator==( const SEG& aSeg ) const
  93. {
  94. return (A == aSeg.A && B == aSeg.B) ;
  95. }
  96. bool operator!=( const SEG& aSeg ) const
  97. {
  98. return (A != aSeg.A || B != aSeg.B);
  99. }
  100. static SEG::ecoord Square( int a )
  101. {
  102. return ecoord( a ) * a;
  103. }
  104. /**
  105. * Function LineProject()
  106. *
  107. * Computes the perpendicular projection point of aP on a line passing through
  108. * ends of the segment.
  109. * @param aP point to project
  110. * @return projected point
  111. */
  112. VECTOR2I LineProject( const VECTOR2I& aP ) const;
  113. /**
  114. * Function Side()
  115. *
  116. * Determines on which side of directed line passing via segment ends point aP lies.
  117. * @param aP point to determine the orientation wrs to self
  118. * @return: < 0: left, 0 : on the line, > 0 : right
  119. */
  120. int Side( const VECTOR2I& aP ) const
  121. {
  122. const ecoord det = ( B - A ).Cross( aP - A );
  123. return det < 0 ? -1 : ( det > 0 ? 1 : 0 );
  124. }
  125. /**
  126. * Function LineDistance()
  127. *
  128. * Returns the closest Euclidean distance between point aP and the line defined by
  129. * the ends of segment (this).
  130. * @param aP the point to test
  131. * @param aDetermineSide: when true, the sign of the returned value indicates
  132. * the side of the line at which we are (negative = left)
  133. * @return the distance
  134. */
  135. int LineDistance( const VECTOR2I& aP, bool aDetermineSide = false ) const;
  136. /**
  137. * Function NearestPoint()
  138. *
  139. * Computes a point on the segment (this) that is closest to point aP.
  140. * @return the nearest point
  141. */
  142. const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
  143. /**
  144. * Computes a point on the segment (this) that is closest to any point on aSeg.
  145. * @return the nearest point
  146. */
  147. const VECTOR2I NearestPoint( const SEG &aSeg ) const;
  148. /**
  149. * Function Intersect()
  150. *
  151. * Computes intersection point of segment (this) with segment aSeg.
  152. * @param aSeg: segment to intersect with
  153. * @param aIgnoreEndpoints: don't treat corner cases (i.e. end of one segment touching the
  154. * other) as intersections.
  155. * @param aLines: treat segments as infinite lines
  156. * @return intersection point, if exists
  157. */
  158. OPT_VECTOR2I Intersect( const SEG& aSeg, bool aIgnoreEndpoints = false,
  159. bool aLines = false ) const;
  160. /**
  161. * Function IntersectLines()
  162. *
  163. * Computes the intersection point of lines passing through ends of (this) and aSeg
  164. * @param aSeg segment defining the line to intersect with
  165. * @return intersection point, if exists
  166. */
  167. OPT_VECTOR2I IntersectLines( const SEG& aSeg ) const
  168. {
  169. return Intersect( aSeg, false, true );
  170. }
  171. bool Collide( const SEG& aSeg, int aClearance ) const;
  172. ecoord SquaredDistance( const SEG& aSeg ) const;
  173. /**
  174. * Function Distance()
  175. *
  176. * Computes minimum Euclidean distance to segment aSeg.
  177. * @param aSeg other segment
  178. * @return minimum distance
  179. */
  180. int Distance( const SEG& aSeg ) const
  181. {
  182. return sqrt( SquaredDistance( aSeg ) );
  183. }
  184. ecoord SquaredDistance( const VECTOR2I& aP ) const
  185. {
  186. return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm();
  187. }
  188. /**
  189. * Function Distance()
  190. *
  191. * Computes minimum Euclidean distance to point aP.
  192. * @param aP the point
  193. * @return minimum distance
  194. */
  195. int Distance( const VECTOR2I& aP ) const
  196. {
  197. return sqrt( SquaredDistance( aP ) );
  198. }
  199. void CanonicalCoefs( ecoord& qA, ecoord& qB, ecoord& qC ) const
  200. {
  201. qA = A.y - B.y;
  202. qB = B.x - A.x;
  203. qC = -qA * A.x - qB * A.y;
  204. }
  205. /**
  206. * Function Collinear()
  207. *
  208. * Checks if segment aSeg lies on the same line as (this).
  209. * @param aSeg the segment to chech colinearity with
  210. * @return true, when segments are collinear.
  211. */
  212. bool Collinear( const SEG& aSeg ) const
  213. {
  214. ecoord qa, qb, qc;
  215. CanonicalCoefs( qa, qb, qc );
  216. ecoord d1 = std::abs( aSeg.A.x * qa + aSeg.A.y * qb + qc );
  217. ecoord d2 = std::abs( aSeg.B.x * qa + aSeg.B.y * qb + qc );
  218. return ( d1 <= 1 && d2 <= 1 );
  219. }
  220. bool ApproxCollinear( const SEG& aSeg ) const
  221. {
  222. ecoord p, q, r;
  223. CanonicalCoefs( p, q, r );
  224. ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
  225. ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
  226. return std::abs( dist1 ) <= 1 && std::abs( dist2 ) <= 1;
  227. }
  228. bool ApproxParallel ( const SEG& aSeg ) const
  229. {
  230. ecoord p, q, r;
  231. CanonicalCoefs( p, q, r );
  232. ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
  233. ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
  234. return std::abs( dist1 - dist2 ) <= 1;
  235. }
  236. bool Overlaps( const SEG& aSeg ) const
  237. {
  238. if( aSeg.A == aSeg.B ) // single point corner case
  239. {
  240. if( A == aSeg.A || B == aSeg.A )
  241. return false;
  242. return Contains( aSeg.A );
  243. }
  244. if( !Collinear( aSeg ) )
  245. return false;
  246. if( Contains( aSeg.A ) || Contains( aSeg.B ) )
  247. return true;
  248. if( aSeg.Contains( A ) || aSeg.Contains( B ) )
  249. return true;
  250. return false;
  251. }
  252. bool Contains( const SEG& aSeg ) const
  253. {
  254. if( aSeg.A == aSeg.B ) // single point corner case
  255. return Contains( aSeg.A );
  256. if( !Collinear( aSeg ) )
  257. return false;
  258. if( Contains( aSeg.A ) && Contains( aSeg.B ) )
  259. return true;
  260. return false;
  261. }
  262. /**
  263. * Function Length()
  264. *
  265. * Returns the length (this)
  266. * @return length
  267. */
  268. int Length() const
  269. {
  270. return ( A - B ).EuclideanNorm();
  271. }
  272. ecoord SquaredLength() const
  273. {
  274. return ( A - B ).SquaredEuclideanNorm();
  275. }
  276. ecoord TCoef( const VECTOR2I& aP ) const;
  277. /**
  278. * Function Index()
  279. *
  280. * Return the index of this segment in its parent shape (applicable only to non-local segments)
  281. * @return index value
  282. */
  283. int Index() const
  284. {
  285. return m_index;
  286. }
  287. bool Contains( const VECTOR2I& aP ) const;
  288. bool PointCloserThan( const VECTOR2I& aP, int aDist ) const;
  289. void Reverse()
  290. {
  291. std::swap( A, B );
  292. }
  293. ///> Returns the center point of the line
  294. VECTOR2I Center() const
  295. {
  296. return A + ( B - A ) / 2;
  297. }
  298. private:
  299. bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const;
  300. ///> index withing the parent shape (used when m_is_local == false)
  301. int m_index;
  302. };
  303. inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const
  304. {
  305. VECTOR2I d = B - A;
  306. ecoord l_squared = d.Dot( d );
  307. if( l_squared == 0 )
  308. return A;
  309. ecoord t = d.Dot( aP - A );
  310. int xp = rescale( t, (ecoord)d.x, l_squared );
  311. int yp = rescale( t, (ecoord)d.y, l_squared );
  312. return A + VECTOR2I( xp, yp );
  313. }
  314. inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
  315. {
  316. ecoord p = A.y - B.y;
  317. ecoord q = B.x - A.x;
  318. ecoord r = -p * A.x - q * A.y;
  319. ecoord dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q );
  320. return aDetermineSide ? dist : std::abs( dist );
  321. }
  322. inline SEG::ecoord SEG::TCoef( const VECTOR2I& aP ) const
  323. {
  324. VECTOR2I d = B - A;
  325. return d.Dot( aP - A);
  326. }
  327. inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const
  328. {
  329. VECTOR2I d = B - A;
  330. ecoord l_squared = d.Dot( d );
  331. if( l_squared == 0 )
  332. return A;
  333. ecoord t = d.Dot( aP - A );
  334. if( t < 0 )
  335. return A;
  336. else if( t > l_squared )
  337. return B;
  338. int xp = rescale( t, (ecoord)d.x, l_squared );
  339. int yp = rescale( t, (ecoord)d.y, l_squared );
  340. return A + VECTOR2I( xp, yp );
  341. }
  342. inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg )
  343. {
  344. aStream << "[ " << aSeg.A << " - " << aSeg.B << " ]";
  345. return aStream;
  346. }
  347. #endif // __SEG_H