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.

415 lines
11 KiB

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