KiCad PCB EDA Suite
Loading...
Searching...
No Matches
polygon_triangulation.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2017 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Alejandro GarcĂ­a Montoro <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
25
27
29
30#include <board.h>
31#include <core/ignore.h>
32#include <zone.h>
33#include <core/profile.h>
34
35#include <atomic>
36#include <thread>
37#include <unordered_set>
38#include <utility>
39
40
42{
43 assert( aPoly->size() == 1 );
44
45 struct EDGE
46 {
47 int m_index = 0;
48 SHAPE_LINE_CHAIN* m_poly = nullptr;
49 bool m_duplicate = false;
50
51 EDGE( SHAPE_LINE_CHAIN *aPolygon, int aIndex ) :
52 m_index(aIndex),
53 m_poly(aPolygon)
54 {}
55
56 bool compareSegs( const SEG& s1, const SEG& s2) const
57 {
58 return (s1.A == s2.A && s1.B == s2.B) || (s1.A == s2.B && s1.B == s2.A);
59 }
60
61 bool operator==( const EDGE& aOther ) const
62 {
63 return compareSegs(
64 m_poly->Segment( m_index ), aOther.m_poly->Segment( aOther.m_index ) );
65 }
66
67 bool operator!=( const EDGE& aOther ) const
68 {
69 return !compareSegs(
70 m_poly->Segment( m_index ), aOther.m_poly->Segment( aOther.m_index ) );
71 }
72
73 struct HASH
74 {
75 std::size_t operator()( const EDGE& aEdge ) const
76 {
77 const auto& a = aEdge.m_poly->Segment( aEdge.m_index );
78 return (std::size_t) ( a.A.x + a.B.x + a.A.y + a.B.y );
79 }
80 };
81
82 };
83
84 struct EDGE_LIST_ENTRY
85 {
86 int index;
87 EDGE_LIST_ENTRY *next;
88 };
89
90 std::unordered_set<EDGE, EDGE::HASH> uniqueEdges;
91
92 auto lc = (*aPoly)[0];
93 lc.Simplify();
94
95 auto edgeList = std::make_unique<EDGE_LIST_ENTRY []>( lc.SegmentCount() );
96
97 for(int i = 0; i < lc.SegmentCount(); i++)
98 {
99 edgeList[i].index = i;
100 edgeList[i].next = &edgeList[ (i != lc.SegmentCount() - 1) ? i + 1 : 0 ];
101 }
102
103 std::unordered_set<EDGE_LIST_ENTRY*> queue;
104
105 for(int i = 0; i < lc.SegmentCount(); i++)
106 {
107 EDGE e ( &lc, i );
108 uniqueEdges.insert( e );
109 }
110
111 for(int i = 0; i < lc.SegmentCount(); i++)
112 {
113 EDGE e ( &lc, i );
114 auto it = uniqueEdges.find(e);
115 if (it != uniqueEdges.end() && it->m_index != i )
116 {
117 int e1 = it->m_index;
118 int e2 = i;
119 if( e1 > e2 )
120 std::swap(e1, e2);
121
122 int e1_prev = e1 - 1;
123 if (e1_prev < 0)
124 e1_prev = lc.SegmentCount() - 1;
125
126 int e2_prev = e2 - 1;
127 if (e2_prev < 0)
128 e2_prev = lc.SegmentCount() - 1;
129
130 int e1_next = e1 + 1;
131 if (e1_next == lc.SegmentCount() )
132 e1_next = 0;
133
134 int e2_next = e2 + 1;
135 if (e2_next == lc.SegmentCount() )
136 e2_next = 0;
137
138 edgeList[e1_prev].next = &edgeList[ e2_next ];
139 edgeList[e2_prev].next = &edgeList[ e1_next ];
140 edgeList[i].next = nullptr;
141 edgeList[it->m_index].next = nullptr;
142 }
143 }
144
145 for(int i = 0; i < lc.SegmentCount(); i++)
146 {
147 if ( edgeList[i].next )
148 queue.insert ( &edgeList[i] );
149 }
150
151 auto edgeBuf = std::make_unique<EDGE_LIST_ENTRY* []>( lc.SegmentCount() );
152
153 int n = 0;
154 int outline = -1;
155aResult->clear();
156 while (queue.size())
157 {
158 auto e_first = (*queue.begin());
159 auto e = e_first;
160 int cnt=0;
161
162 do
163 {
164 edgeBuf[cnt++] = e;
165 e = e->next;
166 } while( e != e_first );
167
168 SHAPE_LINE_CHAIN outl;
169
170 for(int i = 0; i < cnt ;i++)
171 {
172 auto p = lc.CPoint(edgeBuf[i]->index);
173 outl.Append( p );
174 queue.erase( edgeBuf[i] );
175 }
176
177 // auto p_last = lc.Point( edgeBuf[cnt-1]->index + 1 );
178 // outl.Append( p_last );
179
180 outl.SetClosed(true);
181
182 bool cw = outl.Area() > 0.0;
183
184 if(cw)
185 outline = n;
186
187 aResult->push_back(outl);
188 n++;
189 }
190
191 assert(outline >= 0);
192
193 if(outline !=0 )
194 std::swap( (*aResult) [0], (*aResult)[outline] );
195}
196
197
202
203
204int polygon_triangulation_main( int argc, char *argv[] )
205{
206 std::string filename;
207
208 if( argc > 1 )
209 filename = argv[1];
210
211 auto brd = KI_TEST::ReadBoardFromFileOrStream( filename );
212
213 if( !brd )
215
216
217 PROF_TIMER cnt( "allBoard" );
218
219
220 std::atomic<size_t> zonesToTriangulate( 0 );
221 std::atomic<size_t> threadsFinished( 0 );
222
223 size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
224 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
225 {
226 std::thread t = std::thread( [&brd, &zonesToTriangulate, &threadsFinished]() {
227 for( size_t areaId = zonesToTriangulate.fetch_add( 1 );
228 areaId < static_cast<size_t>( brd->GetAreaCount() );
229 areaId = zonesToTriangulate.fetch_add( 1 ) )
230 {
231 auto zone = brd->GetArea( areaId );
232
233 // NOTE: this could be refactored to do multiple layers from the same zone in
234 // parallel, but since the test case doesn't have any of these, I'm not bothering
235 // to do that right now.
236 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
237 {
238 SHAPE_POLY_SET poly = *zone->GetFilledPolysList( layer );
239
240 poly.CacheTriangulation();
241
242 ignore_unused( poly );
243#if 0
244 PROF_TIMER unfrac("unfrac");
245 poly.Unfracture();
246 unfrac.Show();
247
248 PROF_TIMER triangulate("triangulate");
249
250 for(int i =0; i< poly.OutlineCount(); i++)
251 {
252 poly.triangulatePoly( &poly.Polygon(i) );
253 }
254 triangulate.Show();
255#endif
256 }
257 }
258
259 threadsFinished++;
260 } );
261
262 t.detach();
263 }
264
265 while( threadsFinished < parallelThreadCount )
266 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
267
268 cnt.Show();
269
271}
272
273
275 "polygon_triangulation",
276 "Process polygon triangulation on a PCB",
278} );
int index
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
General utilities for PCB file IO for QA programs.
bool operator!=(const BOM_FIELD &lhs, const BOM_FIELD &rhs)
A small class to help profiling.
Definition profile.h:46
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition profile.h:103
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
virtual void CacheTriangulation(bool aSimplify=false, const TASK_SUBMITTER &aSubmitter={})
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void Unfracture()
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int OutlineCount() const
Return the number of outlines in the set.
static bool Register(const KI_TEST::UTILITY_PROGRAM &aProgInfo)
Register a utility program factory function against an ID string.
static bool registered
void ignore_unused(const T &)
Definition ignore.h:20
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
@ OK
Tool exited OK.
@ TOOL_SPECIFIC
Tools can define their own statuses from here onwards.
@ LOAD_FAILED
int polygon_triangulation_main(int argc, char *argv[])
void unfracture(SHAPE_POLY_SET::POLYGON *aPoly, SHAPE_POLY_SET::POLYGON *aResult)
CITER next(CITER it)
Definition ptree.cpp:120
bool cw