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.

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