KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gerber_to_polyset.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) 2025 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "gerber_to_polyset.h"
21#include "gerber_file_image.h"
22#include "gerber_draw_item.h"
23#include "dcode.h"
25
26
28{
29 SHAPE_POLY_SET mergedPolygons;
30
31 if( !aImage )
32 return mergedPolygons;
33
34 // Accumulate positive and negative items separately, then perform a single boolean
35 // pass for each negative object: a negative object erase only previously drawn items.
36 SHAPE_POLY_SET positivePolygons;
37 SHAPE_POLY_SET negativePolygons;
38
39 int maxError = static_cast<int>( gerbIUScale.IU_PER_MM * ARC_LOW_DEF_MM );
40
41 for( GERBER_DRAW_ITEM* item : aImage->GetItems() )
42 {
43 SHAPE_POLY_SET itemPoly;
44 bool needsFlashOffset = false;
45
46 if( item->m_ShapeAsPolygon.OutlineCount() > 0 )
47 {
48 itemPoly = item->m_ShapeAsPolygon;
49 }
50 else if( item->m_ShapeType == GBR_SEGMENT )
51 {
52 D_CODE* dcode = item->GetDcodeDescr();
53
54 if( dcode && dcode->m_ApertType != APT_RECT )
55 TransformOvalToPolygon( itemPoly, item->m_Start, item->m_End, item->m_Size.x, maxError, ERROR_INSIDE );
56 else
57 item->ConvertSegmentToPolygon( &itemPoly );
58 }
59 else if( item->m_ShapeType == GBR_ARC )
60 {
61 VECTOR2I centre = item->m_ArcCentre;
62
63 if( item->m_Start == item->m_End )
64 {
65 TransformRingToPolygon( itemPoly, centre, KiROUND( item->m_Start.Distance( centre ) ), item->m_Size.x,
66 maxError, ERROR_INSIDE );
67 }
68 else
69 {
70 double a = atan2( (double) ( item->m_Start - centre ).y, (double) ( item->m_Start - centre ).x );
71 double b = atan2( (double) ( item->m_End - centre ).y, (double) ( item->m_End - centre ).x );
72
73 if( a > b )
74 b += 2 * M_PI;
75
76 VECTOR2I mid = GetRotated( item->m_Start, centre, -EDA_ANGLE( ( b - a ) / 2, RADIANS_T ) );
77
78 TransformArcToPolygon( itemPoly, item->m_Start, mid, item->m_End, item->m_Size.x, maxError,
80 }
81 }
82 else if( item->m_Flashed )
83 {
84 D_CODE* dcode = item->GetDcodeDescr();
85
86 if( dcode )
87 {
88 dcode->ConvertShapeToPolygon( item );
89 itemPoly = dcode->m_Polygon;
90 needsFlashOffset = true;
91 }
92 }
93
94 if( itemPoly.OutlineCount() == 0 )
95 continue;
96
97 // Flashed shapes from ConvertShapeToPolygon are centered at (0,0).
98 // Offset by the item's position before applying the AB transform.
99 VECTOR2I offset = needsFlashOffset ? VECTOR2I( item->m_Start ) : VECTOR2I( 0, 0 );
100
101 SHAPE_POLY_SET& dest = item->GetLayerPolarity() ? negativePolygons : positivePolygons;
102
103 for( int i = 0; i < itemPoly.OutlineCount(); i++ )
104 {
105 const SHAPE_LINE_CHAIN& outline = itemPoly.COutline( i );
106 dest.NewOutline();
107
108 for( int j = 0; j < outline.PointCount(); j++ )
109 dest.Append( item->GetABPosition( outline.CPoint( j ) + offset ) );
110
111 for( int h = 0; h < itemPoly.HoleCount( i ); h++ )
112 {
113 const SHAPE_LINE_CHAIN& hole = itemPoly.CHole( i, h );
114 dest.NewHole();
115
116 for( int j = 0; j < hole.PointCount(); j++ )
117 dest.Append( item->GetABPosition( hole.CPoint( j ) + offset ) );
118 }
119 }
120
121 // Handle negative polygons: they are subtracted to previous polygons
122 if( negativePolygons.OutlineCount() > 0 )
123 {
124 positivePolygons.BooleanSubtract( negativePolygons );
125 negativePolygons.RemoveAllContours();
126 }
127 }
128
129 // Single-pass union of all positive items
130 positivePolygons.Simplify();
131
132 mergedPolygons = std::move( positivePolygons );
133
134 if( aTolerance > 0 )
135 mergedPolygons.Inflate( aTolerance, CORNER_STRATEGY::ROUND_ALL_CORNERS, 16 );
136
137 return mergedPolygons;
138}
@ ERROR_INSIDE
constexpr EDA_IU_SCALE gerbIUScale
Definition base_units.h:127
constexpr double ARC_LOW_DEF_MM
Definition base_units.h:134
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
SizeVec m_Size
Definition box2.h:908
A gerber DCODE (also called Aperture) definition.
Definition dcode.h:76
APERTURE_T m_ApertType
Aperture type ( Line, rectangle, circle, oval poly, macro )
Definition dcode.h:198
SHAPE_POLY_SET m_Polygon
Definition dcode.h:213
void ConvertShapeToPolygon(const GERBER_DRAW_ITEM *aParent)
Convert a shape to an equivalent polygon.
Definition dcode.cpp:288
Hold the image data and parameters for one gerber file and layer parameters.
GERBER_DRAW_ITEMS & GetItems()
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int NewHole(int aOutline=-1)
Creates a new hole 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.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
void TransformRingToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
@ ROUND_ALL_CORNERS
All angles are rounded.
@ APT_RECT
Definition dcode.h:46
@ RADIANS_T
Definition eda_angle.h:31
@ GBR_SEGMENT
@ GBR_ARC
SHAPE_POLY_SET ConvertGerberToPolySet(GERBER_FILE_IMAGE *aImage, int aTolerance)
Convert a GERBER_FILE_IMAGE to a merged SHAPE_POLY_SET.
#define M_PI
VECTOR2I GetRotated(const VECTOR2I &aVector, const EDA_ANGLE &aAngle)
Return a new VECTOR2I that is the result of rotating aVector by aAngle.
Definition trigo.h:73
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708