KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_geometry_extractor.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <board.h>
27#include <board_item.h>
28#include <eda_shape.h>
29#include <footprint.h>
30#include <geometry/shape_arc.h>
33#include <layer_ids.h>
34#include <pad.h>
35#include <pcb_shape.h>
36#include <pcb_track.h>
37#include <zone.h>
38
39
40namespace KICAD_DIFF
41{
42
43namespace
44{
45
48 void emitPolyline( const SHAPE_LINE_CHAIN& aChain, int aWidth, const KIGFX::COLOR4D& aColor, const LSET& aLayers,
49 DOCUMENT_GEOMETRY& aOut )
50 {
51 for( int i = 0; i + 1 < aChain.PointCount(); ++i )
52 {
54 seg.start = aChain.CPoint( i );
55 seg.end = aChain.CPoint( i + 1 );
56 seg.width = aWidth;
57 seg.color = aColor;
58 seg.layers = aLayers;
59 aOut.segments.push_back( seg );
60 }
61 }
62
63
64 void addShapeAsGeometry( const PCB_SHAPE& aShape, const KIGFX::COLOR4D& aColor, DOCUMENT_GEOMETRY& aOut )
65 {
66 const int width = aShape.GetWidth();
67 const bool fill = aShape.IsSolidFill();
68 const LSET layers( { aShape.GetLayer() } );
69
70 switch( aShape.GetShape() )
71 {
73 {
75 seg.start = aShape.GetStart();
76 seg.end = aShape.GetEnd();
77 seg.width = width;
78 seg.color = aColor;
79 seg.layers = layers;
80 aOut.segments.push_back( seg );
81 break;
82 }
83
85 {
86 const VECTOR2I a = aShape.GetStart();
87 const VECTOR2I b = aShape.GetEnd();
89 poly.outline = { a, { b.x, a.y }, b, { a.x, b.y } };
90 poly.filled = fill;
91 poly.lineWidth = width;
92 poly.color = aColor;
93 poly.layers = layers;
94 aOut.polygons.push_back( poly );
95 break;
96 }
97
98 case SHAPE_T::CIRCLE:
99 {
101 c.center = aShape.GetCenter();
102 c.radius = aShape.GetRadius();
103 c.filled = fill;
104 c.lineWidth = width;
105 c.color = aColor;
106 c.layers = layers;
107 aOut.circles.push_back( c );
108 break;
109 }
110
111 case SHAPE_T::POLY:
112 {
113 const SHAPE_POLY_SET& set = aShape.GetPolyShape();
114
115 for( int outline = 0; outline < set.OutlineCount(); ++outline )
116 {
117 const SHAPE_LINE_CHAIN& chain = set.COutline( outline );
118
119 DOCUMENT_POLYGON poly;
120 poly.filled = fill;
121 poly.lineWidth = width;
122 poly.color = aColor;
123 poly.layers = layers;
124 poly.outline.reserve( chain.PointCount() );
125
126 for( int i = 0; i < chain.PointCount(); ++i )
127 poly.outline.push_back( chain.CPoint( i ) );
128
129 aOut.polygons.push_back( std::move( poly ) );
130
131 // Holes — emitted as separate (unfilled) outlines so they're at
132 // least visible. True polygon-with-holes rendering would need a
133 // tessellator and isn't worth the complexity for a context view.
134 for( int hole = 0; hole < set.HoleCount( outline ); ++hole )
135 {
136 const SHAPE_LINE_CHAIN& holeChain = set.CHole( outline, hole );
137
138 DOCUMENT_POLYGON holePoly;
139 holePoly.filled = false;
140 holePoly.lineWidth = width;
141 holePoly.color = aColor;
142 holePoly.layers = layers;
143 holePoly.outline.reserve( holeChain.PointCount() );
144
145 for( int i = 0; i < holeChain.PointCount(); ++i )
146 holePoly.outline.push_back( holeChain.CPoint( i ) );
147
148 aOut.polygons.push_back( std::move( holePoly ) );
149 }
150 }
151
152 break;
153 }
154
155 case SHAPE_T::ARC:
156 {
157 const SHAPE_ARC arc( aShape.GetStart(), aShape.GetArcMid(), aShape.GetEnd(), 0 );
158 emitPolyline( arc.ConvertToPolyline(), width, aColor, layers, aOut );
159 break;
160 }
161
162 case SHAPE_T::BEZIER:
163 {
164 const std::vector<VECTOR2I>& pts = aShape.GetBezierPoints();
165
166 if( pts.size() >= 2 )
167 {
168 SHAPE_LINE_CHAIN chain;
169
170 for( const VECTOR2I& pt : pts )
171 chain.Append( pt );
172
173 emitPolyline( chain, width, aColor, layers, aOut );
174 }
175 else
176 {
177 // Bezier wasn't tessellated; fall back to start→end chord so
178 // the user at least sees a placeholder for the curve.
180 seg.start = aShape.GetStart();
181 seg.end = aShape.GetEnd();
182 seg.width = width;
183 seg.color = aColor;
184 seg.layers = layers;
185 aOut.segments.push_back( seg );
186 }
187
188 break;
189 }
190
191 default: break;
192 }
193 }
194
195
196 void addTrackAsGeometry( const PCB_TRACK& aTrack, const KIGFX::COLOR4D& aColor, DOCUMENT_GEOMETRY& aOut )
197 {
198 if( aTrack.Type() == PCB_VIA_T )
199 {
200 const PCB_VIA& via = static_cast<const PCB_VIA&>( aTrack );
201
203 c.center = via.GetPosition();
204 c.radius = via.GetWidth( PADSTACK::ALL_LAYERS ) / 2;
205 c.filled = true;
206 c.lineWidth = 0;
207 c.color = aColor;
208 c.layers = via.GetLayerSet();
209 aOut.circles.push_back( c );
210 return;
211 }
212
214 seg.start = aTrack.GetStart();
215 seg.end = aTrack.GetEnd();
216 seg.width = aTrack.GetWidth();
217 seg.color = aColor;
218 seg.layers = aTrack.GetLayerSet();
219 aOut.segments.push_back( seg );
220 }
221
222
223 void addBBoxAsGeometry( const BOARD_ITEM& aItem, const KIGFX::COLOR4D& aColor, DOCUMENT_GEOMETRY& aOut )
224 {
225 DOCUMENT_POLYGON poly = MakeBBoxOutline( aItem.GetBoundingBox(), aColor );
226
227 if( poly.outline.empty() )
228 return;
229
230 poly.layers = aItem.GetLayerSet();
231 aOut.polygons.push_back( std::move( poly ) );
232 }
233
234} // namespace
235
236
238{
240
241 // Board-level drawings: pull anything on Edge.Cuts to anchor the outline,
242 // then user-doc layers so the user has a sense of the board shape.
243 for( BOARD_ITEM* item : aBoard.Drawings() )
244 {
245 if( !item )
246 continue;
247
248 const PCB_SHAPE* shape = dynamic_cast<const PCB_SHAPE*>( item );
249
250 if( !shape )
251 continue;
252
253 const PCB_LAYER_ID layer = shape->GetLayer();
254 const bool isOutline = ( layer == Edge_Cuts );
255 const bool isDoc = ( layer == Dwgs_User || layer == Cmts_User || layer == Eco1_User || layer == Eco2_User
256 || layer == F_SilkS || layer == B_SilkS );
257
258 if( !isOutline && !isDoc )
259 continue;
260
261 addShapeAsGeometry( *shape, aColor, out );
262 }
263
264 // Copper tracks and vias give the context view its board-shaped content
265 // and let layer filtering actually isolate routing layers.
266 for( const PCB_TRACK* track : aBoard.Tracks() )
267 {
268 if( track )
269 addTrackAsGeometry( *track, aColor, out );
270 }
271
272 // Pads and zones are shown as bbox outlines for now. This keeps the
273 // geometry model cheap but still gives layer-aware context around common
274 // copper objects.
275 for( const PAD* pad : aBoard.GetPads() )
276 {
277 if( pad )
278 addBBoxAsGeometry( *pad, aColor, out );
279 }
280
281 for( const ZONE* zone : aBoard.Zones() )
282 {
283 if( zone )
284 addBBoxAsGeometry( *zone, aColor, out );
285 }
286
287 // Footprint bounding boxes anchor component placement.
288 for( const FOOTPRINT* fp : aBoard.Footprints() )
289 {
290 if( !fp )
291 continue;
292
293 DOCUMENT_POLYGON poly = MakeBBoxOutline( fp->GetBoundingBox( false ), aColor );
294
295 if( poly.outline.empty() )
296 continue;
297
298 poly.layers = LSET( { fp->GetLayer() } );
299 out.polygons.push_back( std::move( poly ) );
300 }
301
302 return out;
303}
304
305
307{
309
310 for( const PAD* pad : aFootprint.Pads() )
311 {
312 if( pad )
313 addBBoxAsGeometry( *pad, aColor, out );
314 }
315
316 for( const BOARD_ITEM* item : aFootprint.GraphicalItems() )
317 {
318 if( !item )
319 continue;
320
321 if( const PCB_SHAPE* shape = dynamic_cast<const PCB_SHAPE*>( item ) )
322 addShapeAsGeometry( *shape, aColor, out );
323 else
324 addBBoxAsGeometry( *item, aColor, out );
325 }
326
327 for( const ZONE* zone : aFootprint.Zones() )
328 {
329 if( zone )
330 addBBoxAsGeometry( *zone, aColor, out );
331 }
332
333 DOCUMENT_POLYGON poly = MakeBBoxOutline( aFootprint.GetBoundingBox( false ), aColor );
334
335 if( !poly.outline.empty() )
336 {
337 poly.layers = LSET( { aFootprint.GetLayer() } );
338 out.polygons.push_back( std::move( poly ) );
339 }
340
341 return out;
342}
343
344} // namespace KICAD_DIFF
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:80
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:284
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:320
const ZONES & Zones() const
Definition board.h:372
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
Definition board.cpp:3431
const FOOTPRINTS & Footprints() const
Definition board.h:368
const TRACKS & Tracks() const
Definition board.h:366
const DRAWINGS & Drawings() const
Definition board.h:370
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:135
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
SHAPE_POLY_SET & GetPolyShape()
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:185
bool IsSolidFill() const
Definition eda_shape.h:133
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:232
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition eda_shape.h:396
VECTOR2I GetArcMid() const
ZONES & Zones()
Definition footprint.h:379
std::deque< PAD * > & Pads()
Definition footprint.h:373
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:413
DRAWINGS & GraphicalItems()
Definition footprint.h:376
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:61
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:77
int GetWidth() const override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:67
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
const VECTOR2I & GetEnd() const
Definition pcb_track.h:90
virtual int GetWidth() const
Definition pcb_track.h:87
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Handle a list of polygons defining a copper zone.
Definition zone.h:70
@ SEGMENT
Definition eda_shape.h:46
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:47
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
@ Dwgs_User
Definition layer_ids.h:103
@ Cmts_User
Definition layer_ids.h:104
@ Eco1_User
Definition layer_ids.h:105
@ F_SilkS
Definition layer_ids.h:96
@ Eco2_User
Definition layer_ids.h:106
@ B_SilkS
Definition layer_ids.h:97
DOCUMENT_POLYGON MakeBBoxOutline(const BOX2I &aBBox, const KIGFX::COLOR4D &aColor, int aLineWidth)
Build a DOCUMENT_POLYGON outlining a bounding box.
DOCUMENT_GEOMETRY ExtractFootprintGeometry(const FOOTPRINT &aFootprint, const KIGFX::COLOR4D &aColor)
Extract drawable context geometry from a single FOOTPRINT.
DOCUMENT_GEOMETRY ExtractBoardGeometry(const BOARD &aBoard, const KIGFX::COLOR4D &aColor)
Extract a coarse outline of a BOARD into a DOCUMENT_GEOMETRY for use as background context in DIFF_SC...
Filled or stroked circle.
Definition diff_scene.h:146
Aggregate of background geometry extracted from one source document.
Definition diff_scene.h:163
std::vector< DOCUMENT_POLYGON > polygons
Definition diff_scene.h:165
Closed polygon outline from a source document.
Definition diff_scene.h:133
std::vector< VECTOR2I > outline
Definition diff_scene.h:134
Stroked line segment from one of the source documents.
Definition diff_scene.h:117
const SHAPE_LINE_CHAIN chain
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683