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.

1521 lines
43 KiB

// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
18 years ago
  1. // PolyLine.cpp ... implementation of CPolyLine class from FreePCB.
  2. //
  3. // implementation for kicad, using clipper polygon clipping library
  4. // for transformations not handled (at least for Kicad) by boost::polygon
  5. //
  6. #include <cmath>
  7. #include <vector>
  8. #include <algorithm>
  9. #include <fctsys.h>
  10. #include <common.h> // KiROUND
  11. #include <PolyLine.h>
  12. #include <bezier_curves.h>
  13. #include <polygon_test_point_inside.h>
  14. #include <math_for_graphics.h>
  15. #include <polygon_test_point_inside.h>
  16. CPolyLine::CPolyLine()
  17. {
  18. m_hatchStyle = NO_HATCH;
  19. m_hatchPitch = 0;
  20. m_layer = F_Cu;
  21. m_utility = 0;
  22. }
  23. CPolyLine::CPolyLine( const CPolyLine& aCPolyLine)
  24. {
  25. Copy( &aCPolyLine );
  26. m_HatchLines = aCPolyLine.m_HatchLines; // vector <> copy
  27. }
  28. // destructor, removes display elements
  29. //
  30. CPolyLine::~CPolyLine()
  31. {
  32. UnHatch();
  33. }
  34. /* Removes corners which create a null segment edge
  35. * (i.e. when 2 successive corners are at the same location)
  36. * returns the count of removed corners.
  37. */
  38. int CPolyLine::RemoveNullSegments()
  39. {
  40. int removed = 0;
  41. unsigned startcountour = 0;
  42. for( unsigned icnt = 1; icnt < m_CornersList.GetCornersCount(); icnt ++ )
  43. {
  44. unsigned last = icnt-1;
  45. if( m_CornersList[icnt].end_contour )
  46. {
  47. last = startcountour;
  48. startcountour = icnt+1;
  49. }
  50. if( ( m_CornersList[last].x == m_CornersList[icnt].x ) &&
  51. ( m_CornersList[last].y == m_CornersList[icnt].y ) )
  52. {
  53. DeleteCorner( icnt );
  54. icnt--;
  55. removed ++;
  56. }
  57. if( m_CornersList[icnt].end_contour )
  58. {
  59. startcountour = icnt+1;
  60. icnt++;
  61. }
  62. }
  63. return removed;
  64. }
  65. /**
  66. * Function NormalizeAreaOutlines
  67. * Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
  68. * @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
  69. * needed by the normalization
  70. * @return the polygon count (always >= 1, because there is at least one polygon)
  71. * There are new polygons only if the polygon count is > 1
  72. */
  73. #include "clipper.hpp"
  74. int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
  75. {
  76. ClipperLib::Path raw_polygon;
  77. ClipperLib::Paths normalized_polygons;
  78. unsigned corners_count = m_CornersList.GetCornersCount();
  79. KI_POLYGON_SET polysholes;
  80. KI_POLYGON_WITH_HOLES mainpoly;
  81. std::vector<KI_POLY_POINT> cornerslist;
  82. KI_POLYGON_WITH_HOLES_SET all_contours;
  83. KI_POLYGON poly_tmp;
  84. // Normalize first contour
  85. unsigned ic = 0;
  86. while( ic < corners_count )
  87. {
  88. const CPolyPt& corner = m_CornersList[ic++];
  89. raw_polygon.push_back( ClipperLib::IntPoint( corner.x, corner.y ) );
  90. if( corner.end_contour )
  91. break;
  92. }
  93. ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons );
  94. // enter main outline
  95. for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ )
  96. {
  97. ClipperLib::Path& polygon = normalized_polygons[ii];
  98. cornerslist.clear();
  99. for( unsigned jj = 0; jj < polygon.size(); jj++ )
  100. cornerslist.push_back( KI_POLY_POINT( KiROUND( polygon[jj].X ),
  101. KiROUND( polygon[jj].Y ) ) );
  102. mainpoly.set( cornerslist.begin(), cornerslist.end() );
  103. all_contours.push_back( mainpoly );
  104. }
  105. // Enter holes
  106. while( ic < corners_count )
  107. {
  108. cornerslist.clear();
  109. raw_polygon.clear();
  110. normalized_polygons.clear();
  111. // Normalize current hole and add it to hole list
  112. while( ic < corners_count )
  113. {
  114. const CPolyPt& corner = m_CornersList[ic++];
  115. raw_polygon.push_back( ClipperLib::IntPoint( corner.x, corner.y ) );
  116. if( corner.end_contour )
  117. {
  118. ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons );
  119. for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ )
  120. {
  121. ClipperLib::Path& polygon = normalized_polygons[ii];
  122. cornerslist.clear();
  123. for( unsigned jj = 0; jj < polygon.size(); jj++ )
  124. cornerslist.push_back( KI_POLY_POINT( KiROUND( polygon[jj].X ),
  125. KiROUND( polygon[jj].Y ) ) );
  126. bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() );
  127. polysholes.push_back( poly_tmp );
  128. }
  129. break;
  130. }
  131. }
  132. }
  133. all_contours -= polysholes;
  134. // copy polygon with holes to destination
  135. RemoveAllContours();
  136. #define outlines all_contours
  137. for( unsigned ii = 0; ii < outlines.size(); ii++ )
  138. {
  139. CPolyLine* polyline = this;
  140. if( ii > 0 )
  141. {
  142. polyline = new CPolyLine;
  143. polyline->ImportSettings( this );
  144. aNewPolygonList->push_back( polyline );
  145. }
  146. KI_POLYGON_WITH_HOLES& curr_poly = outlines[ii];
  147. KI_POLYGON_WITH_HOLES::iterator_type corner = curr_poly.begin();
  148. // enter main contour
  149. while( corner != curr_poly.end() )
  150. {
  151. polyline->AppendCorner( corner->x(), corner->y() );
  152. corner++;
  153. }
  154. polyline->CloseLastContour();
  155. // add holes (set of polygons)
  156. KI_POLYGON_WITH_HOLES::iterator_holes_type hole = curr_poly.begin_holes();
  157. while( hole != curr_poly.end_holes() )
  158. {
  159. KI_POLYGON::iterator_type hole_corner = hole->begin();
  160. // create area with external contour: Recreate only area edges, NOT holes
  161. while( hole_corner != hole->end() )
  162. {
  163. polyline->AppendCorner( hole_corner->x(), hole_corner->y() );
  164. hole_corner++;
  165. }
  166. polyline->CloseLastContour();
  167. hole++;
  168. }
  169. polyline->RemoveNullSegments();
  170. }
  171. return outlines.size();
  172. }
  173. /**
  174. * Function ImportSettings
  175. * Copy settings (layer, hatch styles) from aPoly
  176. */
  177. void CPolyLine::ImportSettings( const CPolyLine * aPoly )
  178. {
  179. SetLayer( aPoly->GetLayer() );
  180. SetHatchStyle( aPoly->GetHatchStyle() );
  181. SetHatchPitch( aPoly->GetHatchPitch() );
  182. }
  183. /* initialize a contour
  184. * set layer, hatch style, and starting point
  185. */
  186. void CPolyLine::Start( LAYER_NUM layer, int x, int y, int hatch )
  187. {
  188. m_layer = layer;
  189. SetHatchStyle( (enum HATCH_STYLE) hatch );
  190. CPolyPt poly_pt( x, y );
  191. poly_pt.end_contour = false;
  192. m_CornersList.Append( poly_pt );
  193. }
  194. // add a corner to unclosed polyline
  195. //
  196. void CPolyLine::AppendCorner( int x, int y )
  197. {
  198. UnHatch();
  199. CPolyPt poly_pt( x, y );
  200. poly_pt.end_contour = false;
  201. // add entries for new corner
  202. m_CornersList.Append( poly_pt );
  203. }
  204. // move corner of polyline
  205. //
  206. void CPolyLine::MoveCorner( int ic, int x, int y )
  207. {
  208. UnHatch();
  209. m_CornersList[ic].x = x;
  210. m_CornersList[ic].y = y;
  211. Hatch();
  212. }
  213. // delete corner and adjust arrays
  214. //
  215. void CPolyLine::DeleteCorner( int ic )
  216. {
  217. UnHatch();
  218. int icont = GetContour( ic );
  219. int iend = GetContourEnd( icont );
  220. bool closed = icont < GetContoursCount() - 1 || GetClosed();
  221. if( !closed )
  222. {
  223. // open contour, must be last contour
  224. m_CornersList.DeleteCorner( ic );
  225. }
  226. else
  227. {
  228. // closed contour
  229. m_CornersList.DeleteCorner( ic );
  230. if( ic == iend )
  231. m_CornersList[ic - 1].end_contour = true;
  232. }
  233. if( closed && GetContourSize( icont ) < 3 )
  234. {
  235. // delete the entire contour
  236. RemoveContour( icont );
  237. }
  238. }
  239. /******************************************/
  240. void CPolyLine::RemoveContour( int icont )
  241. /******************************************/
  242. /**
  243. * Function RemoveContour
  244. * @param icont = contour number to remove
  245. * remove a contour only if there is more than 1 contour
  246. */
  247. {
  248. UnHatch();
  249. int istart = GetContourStart( icont );
  250. int iend = GetContourEnd( icont );
  251. int polycount = GetContoursCount();
  252. if( icont == 0 && polycount == 1 )
  253. {
  254. // remove the only contour
  255. wxASSERT( 0 );
  256. }
  257. else
  258. {
  259. // remove closed contour
  260. for( int ic = iend; ic>=istart; ic-- )
  261. {
  262. m_CornersList.DeleteCorner( ic );
  263. }
  264. }
  265. Hatch();
  266. }
  267. CPolyLine* CPolyLine::Chamfer( unsigned int aDistance )
  268. {
  269. CPolyLine* newPoly = new CPolyLine;
  270. if( !aDistance )
  271. {
  272. newPoly->Copy( this );
  273. return newPoly;
  274. }
  275. int polycount = GetContoursCount();
  276. for( int contour = 0; contour < polycount; contour++ )
  277. {
  278. unsigned int startIndex = GetContourStart( contour );
  279. unsigned int endIndex = GetContourEnd( contour );
  280. for( unsigned int index = startIndex; index <= endIndex; index++ )
  281. {
  282. int x1, y1, nx, ny;
  283. long long xa, ya, xb, yb;
  284. x1 = m_CornersList[index].x;
  285. y1 = m_CornersList[index].y;
  286. if( index == startIndex )
  287. {
  288. xa = m_CornersList[endIndex].x - x1;
  289. ya = m_CornersList[endIndex].y - y1;
  290. }
  291. else
  292. {
  293. xa = m_CornersList[index - 1].x - x1;
  294. ya = m_CornersList[index - 1].y - y1;
  295. }
  296. if( index == endIndex )
  297. {
  298. xb = m_CornersList[startIndex].x - x1;
  299. yb = m_CornersList[startIndex].y - y1;
  300. }
  301. else
  302. {
  303. xb = m_CornersList[index + 1].x - x1;
  304. yb = m_CornersList[index + 1].y - y1;
  305. }
  306. unsigned int lena = KiROUND( hypot( xa, ya ) );
  307. unsigned int lenb = KiROUND( hypot( xb, yb ) );
  308. unsigned int distance = aDistance;
  309. // Chamfer one half of an edge at most
  310. if( 0.5 * lena < distance )
  311. distance = int( 0.5 * lena );
  312. if( 0.5 * lenb < distance )
  313. distance = int( 0.5 * lenb );
  314. nx = KiROUND( (distance * xa) / hypot( xa, ya ) );
  315. ny = KiROUND( (distance * ya) / hypot( xa, ya ) );
  316. if( index == startIndex )
  317. newPoly->Start( GetLayer(), x1 + nx, y1 + ny, GetHatchStyle() );
  318. else
  319. newPoly->AppendCorner( x1 + nx, y1 + ny );
  320. nx = KiROUND( (distance * xb) / hypot( xb, yb ) );
  321. ny = KiROUND( (distance * yb) / hypot( xb, yb ) );
  322. newPoly->AppendCorner( x1 + nx, y1 + ny );
  323. }
  324. newPoly->CloseLastContour();
  325. }
  326. return newPoly;
  327. }
  328. CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments )
  329. {
  330. CPolyLine* newPoly = new CPolyLine;
  331. if( !aRadius )
  332. {
  333. newPoly->Copy( this );
  334. return newPoly;
  335. }
  336. int polycount = GetContoursCount();
  337. for( int contour = 0; contour < polycount; contour++ )
  338. {
  339. unsigned int startIndex = GetContourStart( contour );
  340. unsigned int endIndex = GetContourEnd( contour );
  341. for( unsigned int index = startIndex; index <= endIndex; index++ )
  342. {
  343. int x1, y1; // Current vertex
  344. long long xa, ya; // Previous vertex
  345. long long xb, yb; // Next vertex
  346. double nx, ny;
  347. x1 = m_CornersList[index].x;
  348. y1 = m_CornersList[index].y;
  349. if( index == startIndex )
  350. {
  351. xa = m_CornersList[endIndex].x - x1;
  352. ya = m_CornersList[endIndex].y - y1;
  353. }
  354. else
  355. {
  356. xa = m_CornersList[index - 1].x - x1;
  357. ya = m_CornersList[index - 1].y - y1;
  358. }
  359. if( index == endIndex )
  360. {
  361. xb = m_CornersList[startIndex].x - x1;
  362. yb = m_CornersList[startIndex].y - y1;
  363. }
  364. else
  365. {
  366. xb = m_CornersList[index + 1].x - x1;
  367. yb = m_CornersList[index + 1].y - y1;
  368. }
  369. double lena = hypot( xa, ya );
  370. double lenb = hypot( xb, yb );
  371. double cosine = ( xa * xb + ya * yb ) / ( lena * lenb );
  372. double radius = aRadius;
  373. double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 );
  374. // Do nothing in case of parallel edges
  375. if( std::isinf( denom ) )
  376. continue;
  377. // Limit rounding distance to one half of an edge
  378. if( 0.5 * lena * denom < radius )
  379. radius = 0.5 * lena * denom;
  380. if( 0.5 * lenb * denom < radius )
  381. radius = 0.5 * lenb * denom;
  382. // Calculate fillet arc absolute center point (xc, yx)
  383. double k = radius / sqrt( .5 * ( 1 - cosine ) );
  384. double lenab = sqrt( ( xa / lena + xb / lenb ) * ( xa / lena + xb / lenb ) +
  385. ( ya / lena + yb / lenb ) * ( ya / lena + yb / lenb ) );
  386. double xc = x1 + k * ( xa / lena + xb / lenb ) / lenab;
  387. double yc = y1 + k * ( ya / lena + yb / lenb ) / lenab;
  388. // Calculate arc start and end vectors
  389. k = radius / sqrt( 2 / ( 1 + cosine ) - 1 );
  390. double xs = x1 + k * xa / lena - xc;
  391. double ys = y1 + k * ya / lena - yc;
  392. double xe = x1 + k * xb / lenb - xc;
  393. double ye = y1 + k * yb / lenb - yc;
  394. // Cosine of arc angle
  395. double argument = ( xs * xe + ys * ye ) / ( radius * radius );
  396. if( argument < -1 ) // Just in case...
  397. argument = -1;
  398. else if( argument > 1 )
  399. argument = 1;
  400. double arcAngle = acos( argument );
  401. // Calculate the number of segments
  402. double tempSegments = (double) aSegments * ( arcAngle / ( 2 * M_PI ) );
  403. if( tempSegments - (int) tempSegments > 0 )
  404. tempSegments++;
  405. unsigned int segments = (unsigned int) tempSegments;
  406. double deltaAngle = arcAngle / segments;
  407. double startAngle = atan2( -ys, xs );
  408. // Flip arc for inner corners
  409. if( xa * yb - ya * xb <= 0 )
  410. deltaAngle *= -1;
  411. nx = xc + xs;
  412. ny = yc + ys;
  413. if( index == startIndex )
  414. newPoly->Start( GetLayer(), KiROUND( nx ), KiROUND( ny ), GetHatchStyle() );
  415. else
  416. newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) );
  417. for( unsigned int j = 0; j < segments; j++ )
  418. {
  419. nx = xc + cos( startAngle + (j + 1) * deltaAngle ) * radius;
  420. ny = yc - sin( startAngle + (j + 1) * deltaAngle ) * radius;
  421. newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) );
  422. }
  423. }
  424. newPoly->CloseLastContour();
  425. }
  426. return newPoly;
  427. }
  428. /******************************************/
  429. void CPolyLine::RemoveAllContours( void )
  430. /******************************************/
  431. /**
  432. * function RemoveAllContours
  433. * removes all corners from the list.
  434. * Others params are not changed
  435. */
  436. {
  437. m_CornersList.RemoveAllContours();
  438. }
  439. /**
  440. * Function InsertCorner
  441. * insert a new corner between two existing corners
  442. * @param ic = index for the insertion point: the corner is inserted AFTER ic
  443. * @param x, y = coordinates corner to insert
  444. */
  445. void CPolyLine::InsertCorner( int ic, int x, int y )
  446. {
  447. UnHatch();
  448. if( (unsigned) (ic) >= m_CornersList.GetCornersCount() )
  449. {
  450. m_CornersList.Append( CPolyPt( x, y ) );
  451. }
  452. else
  453. {
  454. m_CornersList.InsertCorner(ic, CPolyPt( x, y ) );
  455. }
  456. if( (unsigned) (ic + 1) < m_CornersList.GetCornersCount() )
  457. {
  458. if( m_CornersList[ic].end_contour )
  459. {
  460. m_CornersList[ic + 1].end_contour = true;
  461. m_CornersList[ic].end_contour = false;
  462. }
  463. }
  464. Hatch();
  465. }
  466. // undraw polyline by removing all graphic elements from display list
  467. //
  468. void CPolyLine::UnHatch()
  469. {
  470. m_HatchLines.clear();
  471. }
  472. int CPolyLine::GetEndContour( int ic )
  473. {
  474. return m_CornersList[ic].end_contour;
  475. }
  476. CRect CPolyLine::GetBoundingBox()
  477. {
  478. CRect r;
  479. r.left = r.bottom = INT_MAX;
  480. r.right = r.top = INT_MIN;
  481. for( unsigned i = 0; i< m_CornersList.GetCornersCount(); i++ )
  482. {
  483. r.left = std::min( r.left, m_CornersList[i].x );
  484. r.right = std::max( r.right, m_CornersList[i].x );
  485. r.bottom = std::min( r.bottom, m_CornersList[i].y );
  486. r.top = std::max( r.top, m_CornersList[i].y );
  487. }
  488. return r;
  489. }
  490. CRect CPolyLine::GetBoundingBox( int icont )
  491. {
  492. CRect r;
  493. r.left = r.bottom = INT_MAX;
  494. r.right = r.top = INT_MIN;
  495. int istart = GetContourStart( icont );
  496. int iend = GetContourEnd( icont );
  497. for( int i = istart; i<=iend; i++ )
  498. {
  499. r.left = std::min( r.left, m_CornersList[i].x );
  500. r.right = std::max( r.right, m_CornersList[i].x );
  501. r.bottom = std::min( r.bottom, m_CornersList[i].y );
  502. r.top = std::max( r.top, m_CornersList[i].y );
  503. }
  504. return r;
  505. }
  506. int CPolyLine::GetContoursCount()
  507. {
  508. int ncont = 0;
  509. if( !m_CornersList.GetCornersCount() )
  510. return 0;
  511. for( unsigned ic = 0; ic < m_CornersList.GetCornersCount(); ic++ )
  512. if( m_CornersList[ic].end_contour )
  513. ncont++;
  514. if( !m_CornersList[m_CornersList.GetCornersCount() - 1].end_contour )
  515. ncont++;
  516. return ncont;
  517. }
  518. int CPolyLine::GetContour( int ic )
  519. {
  520. int ncont = 0;
  521. for( int i = 0; i<ic; i++ )
  522. {
  523. if( m_CornersList[i].end_contour )
  524. ncont++;
  525. }
  526. return ncont;
  527. }
  528. int CPolyLine::GetContourStart( int icont )
  529. {
  530. if( icont == 0 )
  531. return 0;
  532. int ncont = 0;
  533. for( unsigned i = 0; i<m_CornersList.GetCornersCount(); i++ )
  534. {
  535. if( m_CornersList[i].end_contour )
  536. {
  537. ncont++;
  538. if( ncont == icont )
  539. return i + 1;
  540. }
  541. }
  542. wxASSERT( 0 );
  543. return 0;
  544. }
  545. int CPolyLine::GetContourEnd( int icont )
  546. {
  547. if( icont < 0 )
  548. return 0;
  549. if( icont == GetContoursCount() - 1 )
  550. return m_CornersList.GetCornersCount() - 1;
  551. int ncont = 0;
  552. for( unsigned i = 0; i<m_CornersList.GetCornersCount(); i++ )
  553. {
  554. if( m_CornersList[i].end_contour )
  555. {
  556. if( ncont == icont )
  557. return i;
  558. ncont++;
  559. }
  560. }
  561. wxASSERT( 0 );
  562. return 0;
  563. }
  564. int CPolyLine::GetContourSize( int icont )
  565. {
  566. return GetContourEnd( icont ) - GetContourStart( icont ) + 1;
  567. }
  568. int CPolyLine::GetClosed()
  569. {
  570. if( m_CornersList.GetCornersCount() == 0 )
  571. return 0;
  572. else
  573. return m_CornersList[m_CornersList.GetCornersCount() - 1].end_contour;
  574. }
  575. // Creates hatch lines inside the outline of the complex polygon
  576. //
  577. // sort function used in ::Hatch to sort points by descending wxPoint.x values
  578. bool sort_ends_by_descending_X( const wxPoint& ref, const wxPoint& tst )
  579. {
  580. return tst.x < ref.x;
  581. }
  582. void CPolyLine::Hatch()
  583. {
  584. m_HatchLines.clear();
  585. if( m_hatchStyle == NO_HATCH || m_hatchPitch == 0 )
  586. return;
  587. if( !GetClosed() ) // If not closed, the poly is beeing created and not finalised. Not not hatch
  588. return;
  589. // define range for hatch lines
  590. int min_x = m_CornersList[0].x;
  591. int max_x = m_CornersList[0].x;
  592. int min_y = m_CornersList[0].y;
  593. int max_y = m_CornersList[0].y;
  594. for( unsigned ic = 1; ic < m_CornersList.GetCornersCount(); ic++ )
  595. {
  596. if( m_CornersList[ic].x < min_x )
  597. min_x = m_CornersList[ic].x;
  598. if( m_CornersList[ic].x > max_x )
  599. max_x = m_CornersList[ic].x;
  600. if( m_CornersList[ic].y < min_y )
  601. min_y = m_CornersList[ic].y;
  602. if( m_CornersList[ic].y > max_y )
  603. max_y = m_CornersList[ic].y;
  604. }
  605. // Calculate spacing betwwen 2 hatch lines
  606. int spacing;
  607. if( m_hatchStyle == DIAGONAL_EDGE )
  608. spacing = m_hatchPitch;
  609. else
  610. spacing = m_hatchPitch * 2;
  611. // set the "length" of hatch lines (the lenght on horizontal axis)
  612. double hatch_line_len = m_hatchPitch;
  613. // To have a better look, give a slope depending on the layer
  614. LAYER_NUM layer = GetLayer();
  615. int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1
  616. double slope = 0.707106 * slope_flag; // 45 degrees slope
  617. int max_a, min_a;
  618. if( slope_flag == 1 )
  619. {
  620. max_a = KiROUND( max_y - slope * min_x );
  621. min_a = KiROUND( min_y - slope * max_x );
  622. }
  623. else
  624. {
  625. max_a = KiROUND( max_y - slope * max_x );
  626. min_a = KiROUND( min_y - slope * min_x );
  627. }
  628. min_a = (min_a / spacing) * spacing;
  629. // calculate an offset depending on layer number,
  630. // for a better look of hatches on a multilayer board
  631. int offset = (layer * 7) / 8;
  632. min_a += offset;
  633. // now calculate and draw hatch lines
  634. int nc = m_CornersList.GetCornersCount();
  635. // loop through hatch lines
  636. #define MAXPTS 200 // Usually we store only few values per one hatch line
  637. // depending on the compexity of the zone outline
  638. static std::vector <wxPoint> pointbuffer;
  639. pointbuffer.clear();
  640. pointbuffer.reserve( MAXPTS + 2 );
  641. for( int a = min_a; a < max_a; a += spacing )
  642. {
  643. // get intersection points for this hatch line
  644. // Note: because we should have an even number of intersections with the
  645. // current hatch line and the zone outline (a closed polygon,
  646. // or a set of closed polygons), if an odd count is found
  647. // we skip this line (should not occur)
  648. pointbuffer.clear();
  649. int i_start_contour = 0;
  650. for( int ic = 0; ic<nc; ic++ )
  651. {
  652. double x, y, x2, y2;
  653. int ok;
  654. if( m_CornersList[ic].end_contour ||
  655. ( ic == (int) (m_CornersList.GetCornersCount() - 1) ) )
  656. {
  657. ok = FindLineSegmentIntersection( a, slope,
  658. m_CornersList[ic].x, m_CornersList[ic].y,
  659. m_CornersList[i_start_contour].x,
  660. m_CornersList[i_start_contour].y,
  661. &x, &y, &x2, &y2 );
  662. i_start_contour = ic + 1;
  663. }
  664. else
  665. {
  666. ok = FindLineSegmentIntersection( a, slope,
  667. m_CornersList[ic].x, m_CornersList[ic].y,
  668. m_CornersList[ic + 1].x, m_CornersList[ic + 1].y,
  669. &x, &y, &x2, &y2 );
  670. }
  671. if( ok )
  672. {
  673. wxPoint point( KiROUND( x ), KiROUND( y ) );
  674. pointbuffer.push_back( point );
  675. }
  676. if( ok == 2 )
  677. {
  678. wxPoint point( KiROUND( x2 ), KiROUND( y2 ) );
  679. pointbuffer.push_back( point );
  680. }
  681. if( pointbuffer.size() >= MAXPTS ) // overflow
  682. {
  683. wxASSERT( 0 );
  684. break;
  685. }
  686. }
  687. // ensure we have found an even intersection points count
  688. // because intersections are the ends of segments
  689. // inside the polygon(s) and a segment has 2 ends.
  690. // if not, this is a strange case (a bug ?) so skip this hatch
  691. if( pointbuffer.size() % 2 != 0 )
  692. continue;
  693. // sort points in order of descending x (if more than 2) to
  694. // ensure the starting point and the ending point of the same segment
  695. // are stored one just after the other.
  696. if( pointbuffer.size() > 2 )
  697. sort( pointbuffer.begin(), pointbuffer.end(), sort_ends_by_descending_X );
  698. // creates lines or short segments inside the complex polygon
  699. for( unsigned ip = 0; ip < pointbuffer.size(); ip += 2 )
  700. {
  701. double dx = pointbuffer[ip + 1].x - pointbuffer[ip].x;
  702. // Push only one line for diagonal hatch,
  703. // or for small lines < twice the line len
  704. // else push 2 small lines
  705. if( m_hatchStyle == DIAGONAL_FULL || fabs( dx ) < 2 * hatch_line_len )
  706. {
  707. m_HatchLines.push_back( CSegment( pointbuffer[ip], pointbuffer[ip + 1] ) );
  708. }
  709. else
  710. {
  711. double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y;
  712. double slope = dy / dx;
  713. if( dx > 0 )
  714. dx = hatch_line_len;
  715. else
  716. dx = -hatch_line_len;
  717. double x1 = pointbuffer[ip].x + dx;
  718. double x2 = pointbuffer[ip + 1].x - dx;
  719. double y1 = pointbuffer[ip].y + dx * slope;
  720. double y2 = pointbuffer[ip + 1].y - dx * slope;
  721. m_HatchLines.push_back( CSegment( pointbuffer[ip].x,
  722. pointbuffer[ip].y,
  723. KiROUND( x1 ), KiROUND( y1 ) ) );
  724. m_HatchLines.push_back( CSegment( pointbuffer[ip + 1].x,
  725. pointbuffer[ip + 1].y,
  726. KiROUND( x2 ), KiROUND( y2 ) ) );
  727. }
  728. }
  729. }
  730. }
  731. // test to see if a point is inside polyline
  732. //
  733. bool CPolyLine::TestPointInside( int px, int py )
  734. {
  735. if( !GetClosed() )
  736. {
  737. wxASSERT( 0 );
  738. }
  739. // Test all polygons.
  740. // Since the first is the main outline, and other are holes,
  741. // if the tested point is inside only one contour, it is inside the whole polygon
  742. // (in fact inside the main outline, and outside all holes).
  743. // if inside 2 contours (the main outline + an hole), it is outside the poly.
  744. int polycount = GetContoursCount();
  745. bool inside = false;
  746. for( int icont = 0; icont < polycount; icont++ )
  747. {
  748. int istart = GetContourStart( icont );
  749. int iend = GetContourEnd( icont );
  750. // test point inside the current polygon
  751. if( TestPointInsidePolygon( m_CornersList, istart, iend, px, py ) )
  752. inside = not inside;
  753. }
  754. return inside;
  755. }
  756. // copy data from another CPolyLine, but don't draw it
  757. void CPolyLine::Copy( const CPolyLine* src )
  758. {
  759. UnHatch();
  760. m_layer = src->m_layer;
  761. m_hatchStyle = src->m_hatchStyle;
  762. m_hatchPitch = src->m_hatchPitch;
  763. m_CornersList.RemoveAllContours();
  764. m_CornersList.Append( src->m_CornersList );
  765. }
  766. /*
  767. * return true if the corner aCornerIdx is on a hole inside the main outline
  768. * and false if it is on the main outline
  769. */
  770. bool CPolyLine::IsCutoutContour( int aCornerIdx )
  771. {
  772. int ncont = GetContour( aCornerIdx );
  773. if( ncont == 0 ) // the first contour is the main outline, not an hole
  774. return false;
  775. return true;
  776. }
  777. void CPolyLine::MoveOrigin( int x_off, int y_off )
  778. {
  779. UnHatch();
  780. for( int ic = 0; ic < GetCornersCount(); ic++ )
  781. {
  782. SetX( ic, GetX( ic ) + x_off );
  783. SetY( ic, GetY( ic ) + y_off );
  784. }
  785. Hatch();
  786. }
  787. /*
  788. * AppendArc:
  789. * adds segments to current contour to approximate the given arc
  790. */
  791. void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num )
  792. {
  793. // get radius
  794. double radius = ::Distance( xi, yi, xf, yf );
  795. // get angles of start pint and end point
  796. double th_i = atan2( (double) (yi - yc), (double) (xi - xc) );
  797. double th_f = atan2( (double) (yf - yc), (double) (xf - xc) );
  798. double th_d = (th_f - th_i) / (num - 1);
  799. double theta = th_i;
  800. // generate arc
  801. for( int ic = 0; ic < num; ic++ )
  802. {
  803. int x = xc + KiROUND( radius * cos( theta ) );
  804. int y = yc + KiROUND( radius * sin( theta ) );
  805. AppendCorner( x, y );
  806. theta += th_d;
  807. }
  808. CloseLastContour();
  809. }
  810. // Bezier Support
  811. void CPolyLine::AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3 )
  812. {
  813. std::vector<wxPoint> bezier_points;
  814. bezier_points = Bezier2Poly( x1, y1, x2, y2, x3, y3 );
  815. for( unsigned int i = 0; i < bezier_points.size(); i++ )
  816. AppendCorner( bezier_points[i].x, bezier_points[i].y );
  817. }
  818. void CPolyLine::AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 )
  819. {
  820. std::vector<wxPoint> bezier_points;
  821. bezier_points = Bezier2Poly( x1, y1, x2, y2, x3, y3, x4, y4 );
  822. for( unsigned int i = 0; i < bezier_points.size(); i++ )
  823. AppendCorner( bezier_points[i].x, bezier_points[i].y );
  824. }
  825. /*
  826. * Function Distance
  827. * Calculates the distance between a segment and a polygon (with holes):
  828. * param aStart is the starting point of the segment.
  829. * param aEnd is the ending point of the segment.
  830. * param aWidth is the width of the segment.
  831. * return distance between the segment and outline.
  832. * 0 if segment intersects or is inside
  833. */
  834. int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth )
  835. {
  836. // We calculate the min dist between the segment and each outline segment
  837. // However, if the segment to test is inside the outline, and does not cross
  838. // any edge, it can be seen outside the polygon.
  839. // Therefore test if a segment end is inside ( testing only one end is enough )
  840. if( TestPointInside( aStart.x, aStart.y ) )
  841. return 0;
  842. int distance = INT_MAX;
  843. int polycount = GetContoursCount();
  844. for( int icont = 0; icont < polycount; icont++ )
  845. {
  846. int ic_start = GetContourStart( icont );
  847. int ic_end = GetContourEnd( icont );
  848. // now test spacing between area outline and segment
  849. for( int ic2 = ic_start; ic2 <= ic_end; ic2++ )
  850. {
  851. int bx1 = GetX( ic2 );
  852. int by1 = GetY( ic2 );
  853. int bx2, by2;
  854. if( ic2 == ic_end )
  855. {
  856. bx2 = GetX( ic_start );
  857. by2 = GetY( ic_start );
  858. }
  859. else
  860. {
  861. bx2 = GetX( ic2 + 1 );
  862. by2 = GetY( ic2 + 1 );
  863. }
  864. int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
  865. aStart.x, aStart.y, aEnd.x, aEnd.y,
  866. aWidth,
  867. 1, // min clearance, should be > 0
  868. NULL, NULL );
  869. if( distance > d )
  870. distance = d;
  871. if( distance <= 0 )
  872. return 0;
  873. }
  874. }
  875. return distance;
  876. }
  877. /*
  878. * Function Distance
  879. * Calculates the distance between a point and polygon (with holes):
  880. * param aPoint is the coordinate of the point.
  881. * return distance between the point and outline.
  882. * 0 if the point is inside
  883. */
  884. int CPolyLine::Distance( const wxPoint& aPoint )
  885. {
  886. // We calculate the dist between the point and each outline segment
  887. // If the point is inside the outline, the dist is 0.
  888. if( TestPointInside( aPoint.x, aPoint.y ) )
  889. return 0;
  890. int distance = INT_MAX;
  891. int polycount = GetContoursCount();
  892. for( int icont = 0; icont < polycount; icont++ )
  893. {
  894. int ic_start = GetContourStart( icont );
  895. int ic_end = GetContourEnd( icont );
  896. // now test spacing between area outline and segment
  897. for( int ic2 = ic_start; ic2 <= ic_end; ic2++ )
  898. {
  899. int bx1 = GetX( ic2 );
  900. int by1 = GetY( ic2 );
  901. int bx2, by2;
  902. if( ic2 == ic_end )
  903. {
  904. bx2 = GetX( ic_start );
  905. by2 = GetY( ic_start );
  906. }
  907. else
  908. {
  909. bx2 = GetX( ic2 + 1 );
  910. by2 = GetY( ic2 + 1 );
  911. }
  912. int d = KiROUND( GetPointToLineSegmentDistance( aPoint.x, aPoint.y,
  913. bx1, by1, bx2, by2 ) );
  914. if( distance > d )
  915. distance = d;
  916. if( distance <= 0 )
  917. return 0;
  918. }
  919. }
  920. return distance;
  921. }
  922. /* test is the point aPos is near (< aDistMax ) a vertex
  923. * return int = the index of the first corner of the vertex, or -1 if not found.
  924. */
  925. int CPolyLine::HitTestForEdge( const wxPoint& aPos, int aDistMax ) const
  926. {
  927. unsigned lim = m_CornersList.GetCornersCount();
  928. int corner = -1; // Set to not found
  929. unsigned first_corner_pos = 0;
  930. for( unsigned item_pos = 0; item_pos < lim; item_pos++ )
  931. {
  932. unsigned end_segm = item_pos + 1;
  933. /* the last corner of the current outline is tested
  934. * the last segment of the current outline starts at current corner, and ends
  935. * at the first corner of the outline
  936. */
  937. if( m_CornersList.IsEndContour ( item_pos ) || end_segm >= lim )
  938. {
  939. unsigned tmp = first_corner_pos;
  940. first_corner_pos = end_segm; // first_corner_pos is now the beginning of the next outline
  941. end_segm = tmp; // end_segm is the beginning of the current outline
  942. }
  943. // test the dist between segment and ref point
  944. int dist = KiROUND( GetPointToLineSegmentDistance(
  945. aPos.x, aPos.y,
  946. m_CornersList.GetX( item_pos ),
  947. m_CornersList.GetY( item_pos ),
  948. m_CornersList.GetX( end_segm ),
  949. m_CornersList.GetY( end_segm ) ) );
  950. if( dist < aDistMax )
  951. {
  952. corner = item_pos;
  953. aDistMax = dist;
  954. }
  955. }
  956. return corner;
  957. }
  958. /* test is the point aPos is near (< aDistMax ) a corner
  959. * return int = the index of corner of the, or -1 if not found.
  960. */
  961. int CPolyLine::HitTestForCorner( const wxPoint& aPos, int aDistMax ) const
  962. {
  963. int corner = -1; // Set to not found
  964. wxPoint delta;
  965. unsigned lim = m_CornersList.GetCornersCount();
  966. for( unsigned item_pos = 0; item_pos < lim; item_pos++ )
  967. {
  968. delta.x = aPos.x - m_CornersList.GetX( item_pos );
  969. delta.y = aPos.y - m_CornersList.GetY( item_pos );
  970. // Calculate a distance:
  971. int dist = std::max( abs( delta.x ), abs( delta.y ) );
  972. if( dist < aDistMax ) // this corner is a candidate:
  973. {
  974. corner = item_pos;
  975. aDistMax = dist;
  976. }
  977. }
  978. return corner;
  979. }
  980. /*
  981. * Copy the contours to a KI_POLYGON_WITH_HOLES
  982. * The first contour is the main outline, others are holes
  983. */
  984. void CPOLYGONS_LIST::ExportTo( KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) const
  985. {
  986. unsigned corners_count = m_cornersList.size();
  987. std::vector<KI_POLY_POINT> cornerslist;
  988. KI_POLYGON poly;
  989. // Enter main outline: this is the first contour
  990. unsigned ic = 0;
  991. while( ic < corners_count )
  992. {
  993. const CPolyPt& corner = GetCorner( ic++ );
  994. cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) );
  995. if( corner.end_contour )
  996. break;
  997. }
  998. aPolygoneWithHole.set( cornerslist.begin(), cornerslist.end() );
  999. // Enter holes: they are next contours (when exist)
  1000. if( ic < corners_count )
  1001. {
  1002. KI_POLYGON_SET holePolyList;
  1003. while( ic < corners_count )
  1004. {
  1005. cornerslist.clear();
  1006. while( ic < corners_count )
  1007. {
  1008. cornerslist.push_back( KI_POLY_POINT( GetX( ic ), GetY( ic ) ) );
  1009. if( IsEndContour( ic++ ) )
  1010. break;
  1011. }
  1012. bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
  1013. holePolyList.push_back( poly );
  1014. }
  1015. aPolygoneWithHole.set_holes( holePolyList.begin(), holePolyList.end() );
  1016. }
  1017. }
  1018. /**
  1019. * Copy all contours to a KI_POLYGON_SET aPolygons
  1020. * Each contour is copied into a KI_POLYGON, and each KI_POLYGON
  1021. * is append to aPolygons
  1022. */
  1023. void CPOLYGONS_LIST::ExportTo( KI_POLYGON_SET& aPolygons ) const
  1024. {
  1025. std::vector<KI_POLY_POINT> cornerslist;
  1026. unsigned corners_count = GetCornersCount();
  1027. // Count the number of polygons in aCornersBuffer
  1028. int polycount = 0;
  1029. for( unsigned ii = 0; ii < corners_count; ii++ )
  1030. {
  1031. if( IsEndContour( ii ) )
  1032. polycount++;
  1033. }
  1034. aPolygons.reserve( polycount );
  1035. for( unsigned icnt = 0; icnt < corners_count; )
  1036. {
  1037. KI_POLYGON poly;
  1038. cornerslist.clear();
  1039. unsigned ii;
  1040. for( ii = icnt; ii < corners_count; ii++ )
  1041. {
  1042. cornerslist.push_back( KI_POLY_POINT( GetX( ii ), GetY( ii ) ) );
  1043. if( IsEndContour( ii ) )
  1044. break;
  1045. }
  1046. bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
  1047. aPolygons.push_back( poly );
  1048. icnt = ii + 1;
  1049. }
  1050. }
  1051. /* Imports all polygons found in a KI_POLYGON_SET in list
  1052. */
  1053. void CPOLYGONS_LIST::ImportFrom( KI_POLYGON_SET& aPolygons )
  1054. {
  1055. CPolyPt corner;
  1056. for( unsigned ii = 0; ii < aPolygons.size(); ii++ )
  1057. {
  1058. KI_POLYGON& poly = aPolygons[ii];
  1059. for( unsigned jj = 0; jj < poly.size(); jj++ )
  1060. {
  1061. KI_POLY_POINT point = *(poly.begin() + jj);
  1062. corner.x = point.x();
  1063. corner.y = point.y();
  1064. corner.end_contour = false;
  1065. AddCorner( corner );
  1066. }
  1067. CloseLastContour();
  1068. }
  1069. }
  1070. /**
  1071. * Function ConvertPolysListWithHolesToOnePolygon
  1072. * converts the outline contours aPolysListWithHoles with holes to one polygon
  1073. * with no holes (only one contour)
  1074. * holes are linked to main outlines by overlap segments, to give only one polygon
  1075. *
  1076. * @param aPolysListWithHoles = the list of corners of contours (haing holes
  1077. * @param aOnePolyList = a polygon with no holes
  1078. */
  1079. void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWithHoles,
  1080. CPOLYGONS_LIST& aOnePolyList )
  1081. {
  1082. unsigned corners_count = aPolysListWithHoles.GetCornersCount();
  1083. int polycount = 0;
  1084. for( unsigned ii = 0; ii < corners_count; ii++ )
  1085. {
  1086. if( aPolysListWithHoles.IsEndContour( ii ) )
  1087. polycount++;
  1088. }
  1089. // If polycount<= 1, there is no holes found, and therefore just copy the polygon.
  1090. if( polycount <= 1 )
  1091. {
  1092. aOnePolyList = aPolysListWithHoles;
  1093. return;
  1094. }
  1095. // Holes are found: convert them to only one polygon with overlap segments
  1096. KI_POLYGON_SET polysholes;
  1097. KI_POLYGON_SET mainpoly;
  1098. KI_POLYGON poly_tmp;
  1099. std::vector<KI_POLY_POINT> cornerslist;
  1100. corners_count = aPolysListWithHoles.GetCornersCount();
  1101. unsigned ic = 0;
  1102. // enter main outline
  1103. while( ic < corners_count )
  1104. {
  1105. const CPolyPt& corner = aPolysListWithHoles.GetCorner( ic++ );
  1106. cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) );
  1107. if( corner.end_contour )
  1108. break;
  1109. }
  1110. bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() );
  1111. mainpoly.push_back( poly_tmp );
  1112. while( ic < corners_count )
  1113. {
  1114. cornerslist.clear();
  1115. {
  1116. while( ic < corners_count )
  1117. {
  1118. const CPolyPt& corner = aPolysListWithHoles.GetCorner( ic++ );
  1119. cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) );
  1120. if( corner.end_contour )
  1121. break;
  1122. }
  1123. bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() );
  1124. polysholes.push_back( poly_tmp );
  1125. }
  1126. }
  1127. mainpoly -= polysholes;
  1128. // copy polygon with no holes to destination
  1129. // Because all holes are now linked to the main outline
  1130. // by overlapping segments, we should have only one polygon in list
  1131. wxASSERT( mainpoly.size() == 1 );
  1132. KI_POLYGON& poly_nohole = mainpoly[0];
  1133. CPolyPt corner( 0, 0, false );
  1134. for( unsigned jj = 0; jj < poly_nohole.size(); jj++ )
  1135. {
  1136. KI_POLY_POINT point = *(poly_nohole.begin() + jj);
  1137. corner.x = point.x();
  1138. corner.y = point.y();
  1139. corner.end_contour = false;
  1140. aOnePolyList.AddCorner( corner );
  1141. }
  1142. aOnePolyList.CloseLastContour();
  1143. }
  1144. /**
  1145. * Function IsPolygonSelfIntersecting
  1146. * Test a CPolyLine for self-intersection of vertex (all contours).
  1147. *
  1148. * @return :
  1149. * false if no intersecting sides
  1150. * true if intersecting sides
  1151. * When a CPolyLine is self intersectic, it need to be normalized.
  1152. * (converted to non intersecting polygons)
  1153. */
  1154. bool CPolyLine::IsPolygonSelfIntersecting()
  1155. {
  1156. // first, check for sides intersecting other sides
  1157. int n_cont = GetContoursCount();
  1158. // make bounding rect for each contour
  1159. std::vector<CRect> cr;
  1160. cr.reserve( n_cont );
  1161. for( int icont = 0; icont<n_cont; icont++ )
  1162. cr.push_back( GetBoundingBox( icont ) );
  1163. for( int icont = 0; icont<n_cont; icont++ )
  1164. {
  1165. int is_start = GetContourStart( icont );
  1166. int is_end = GetContourEnd( icont );
  1167. for( int is = is_start; is<=is_end; is++ )
  1168. {
  1169. int is_prev = is - 1;
  1170. if( is_prev < is_start )
  1171. is_prev = is_end;
  1172. int is_next = is + 1;
  1173. if( is_next > is_end )
  1174. is_next = is_start;
  1175. int x1i = GetX( is );
  1176. int y1i = GetY( is );
  1177. int x1f = GetX( is_next );
  1178. int y1f = GetY( is_next );
  1179. // check for intersection with any other sides
  1180. for( int icont2 = icont; icont2<n_cont; icont2++ )
  1181. {
  1182. if( cr[icont].left > cr[icont2].right
  1183. || cr[icont].bottom > cr[icont2].top
  1184. || cr[icont2].left > cr[icont].right
  1185. || cr[icont2].bottom > cr[icont].top )
  1186. {
  1187. // rectangles don't overlap, do nothing
  1188. }
  1189. else
  1190. {
  1191. int is2_start = GetContourStart( icont2 );
  1192. int is2_end = GetContourEnd( icont2 );
  1193. for( int is2 = is2_start; is2<=is2_end; is2++ )
  1194. {
  1195. int is2_prev = is2 - 1;
  1196. if( is2_prev < is2_start )
  1197. is2_prev = is2_end;
  1198. int is2_next = is2 + 1;
  1199. if( is2_next > is2_end )
  1200. is2_next = is2_start;
  1201. if( icont != icont2
  1202. || ( is2 != is && is2 != is_prev && is2 != is_next &&
  1203. is != is2_prev && is != is2_next )
  1204. )
  1205. {
  1206. int x2i = GetX( is2 );
  1207. int y2i = GetY( is2 );
  1208. int x2f = GetX( is2_next );
  1209. int y2f = GetY( is2_next );
  1210. int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f,
  1211. x2i, y2i, x2f, y2f );
  1212. if( ret )
  1213. {
  1214. // intersection between non-adjacent sides
  1215. return true;
  1216. }
  1217. }
  1218. }
  1219. }
  1220. }
  1221. }
  1222. }
  1223. return false;
  1224. }