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.

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