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.

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