KiCad PCB EDA Suite
Loading...
Searching...
No Matches
graphics_importer_buffer.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 (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Janito Vaqueiro Ferreira Filho <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <eda_item.h>
27
30
32
33using namespace std;
34
35template <typename T, typename... Args>
36static std::unique_ptr<T> make_shape( const Args&... aArguments )
37{
38 return std::make_unique<T>( aArguments... );
39}
40
41void GRAPHICS_IMPORTER_BUFFER::AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
42 const IMPORTED_STROKE& aStroke )
43{
44 m_shapes.push_back( make_shape<IMPORTED_LINE>( aStart, aEnd, aStroke ) );
45}
46
47
48void GRAPHICS_IMPORTER_BUFFER::AddCircle( const VECTOR2D& aCenter, double aRadius,
49 const IMPORTED_STROKE& aStroke, bool aFilled,
50 const COLOR4D& aFillColor )
51{
52 m_shapes.push_back(
53 make_shape<IMPORTED_CIRCLE>( aCenter, aRadius, aStroke, aFilled, aFillColor ) );
54}
55
56
57void GRAPHICS_IMPORTER_BUFFER::AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart,
58 const EDA_ANGLE& aAngle, const IMPORTED_STROKE& aStroke )
59{
60 m_shapes.push_back( make_shape<IMPORTED_ARC>( aCenter, aStart, aAngle, aStroke ) );
61}
62
63
64void GRAPHICS_IMPORTER_BUFFER::AddPolygon( const std::vector<VECTOR2D>& aVertices,
65 const IMPORTED_STROKE& aStroke, bool aFilled,
66 const COLOR4D& aFillColor )
67{
68 m_shapes.push_back( make_shape<IMPORTED_POLYGON>( aVertices, aStroke, aFilled, aFillColor ) );
69
70 m_shapes.back()->SetParentShapeIndex( m_shapeFillRules.size() - 1 );
71}
72
73
74void GRAPHICS_IMPORTER_BUFFER::AddText( const VECTOR2D& aOrigin, const wxString& aText,
75 double aHeight, double aWidth, double aThickness,
76 double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
77 GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor )
78{
79 m_shapes.push_back( make_shape<IMPORTED_TEXT>( aOrigin, aText, aHeight, aWidth, aThickness,
80 aOrientation, aHJustify, aVJustify, aColor ) );
81}
82
83
84void GRAPHICS_IMPORTER_BUFFER::AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
85 const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
86 const IMPORTED_STROKE& aStroke )
87{
88 m_shapes.push_back( make_shape<IMPORTED_SPLINE>( aStart, aBezierControl1, aBezierControl2, aEnd,
89 aStroke ) );
90}
91
92
93void GRAPHICS_IMPORTER_BUFFER::AddShape( std::unique_ptr<IMPORTED_SHAPE>& aShape )
94{
95 m_shapes.push_back( std::move( aShape ) );
96}
97
98
100{
101 for( std::unique_ptr<IMPORTED_SHAPE>& shape : m_shapes )
102 shape->ImportTo( aImporter );
103}
104
105// converts a single SVG-style polygon (multiple outlines, hole detection based on orientation, custom fill rule) to a format that can be digested by KiCad (single outline, fractured)
106static void convertPolygon( std::list<std::unique_ptr<IMPORTED_SHAPE>>& aShapes,
107 std::vector<IMPORTED_POLYGON*>& aPaths,
109 const IMPORTED_STROKE& aStroke, bool aFilled,
110 const COLOR4D& aFillColor )
111{
112 double minX = std::numeric_limits<double>::max();
113 double minY = minX;
114 double maxX = std::numeric_limits<double>::min();
115 double maxY = maxX;
116
117 // as Clipper/SHAPE_POLY_SET uses ints we first need to upscale to a reasonably large size (in integer coordinates)
118 // to avoid losing accuracy
119 const double convert_scale = 1000000000.0;
120
121 for( IMPORTED_POLYGON* path : aPaths )
122 {
123 for( VECTOR2D& v : path->Vertices() )
124 {
125 minX = std::min( minX, v.x );
126 minY = std::min( minY, v.y );
127 maxX = std::max( maxX, v.x );
128 maxY = std::max( maxY, v.y );
129 }
130 }
131
132 double origW = ( maxX - minX );
133 double origH = ( maxY - minY );
134 double upscaledW, upscaledH;
135
136 if( origW > origH )
137 {
138 upscaledW = convert_scale;
139 upscaledH = ( origH == 0.0f ? 0.0 : origH * convert_scale / origW );
140 }
141 else
142 {
143 upscaledH = convert_scale;
144 upscaledW = ( origW == 0.0f ? 0.0 : origW * convert_scale / origH );
145 }
146
147 std::vector<IMPORTED_POLYGON*> openPaths;
148 std::vector<SHAPE_LINE_CHAIN> upscaledPaths;
149
150 for( IMPORTED_POLYGON* path : aPaths )
151 {
152 if( path->Vertices().size() < 3 )
153 {
154 openPaths.push_back( path );
155 continue;
156 }
157
159
160 for( VECTOR2D& v : path->Vertices() )
161 {
162 int xp = KiROUND( ( v.x - minX ) * ( upscaledW / origW ) );
163 int yp = KiROUND( ( v.y - minY ) * ( upscaledH / origH ) );
164 lc.Append( xp, yp );
165 }
166 lc.SetClosed( true );
167 upscaledPaths.push_back( lc );
168 }
169
171 upscaledPaths, false, aFillRule == GRAPHICS_IMPORTER::PF_EVEN_ODD );
173
174 for( int outl = 0; outl < result.OutlineCount(); outl++ )
175 {
176 const SHAPE_LINE_CHAIN& ro = result.COutline( outl );
177 std::vector<VECTOR2D> pts;
178 for( int i = 0; i < ro.PointCount(); i++ )
179 {
180 double xp = (double) ro.CPoint( i ).x * ( origW / upscaledW ) + minX;
181 double yp = (double) ro.CPoint( i ).y * ( origH / upscaledH ) + minY;
182 pts.emplace_back( VECTOR2D( xp, yp ) );
183 }
184
185 aShapes.push_back(
186 std::make_unique<IMPORTED_POLYGON>( pts, aStroke, aFilled, aFillColor ) );
187 }
188
189 for( IMPORTED_POLYGON* openPath : openPaths )
190 aShapes.push_back( std::make_unique<IMPORTED_POLYGON>( *openPath ) );
191}
192
193
195{
196 int curShapeIdx = -1;
197 IMPORTED_STROKE lastStroke;
198 bool lastFilled = false;
199 COLOR4D lastFillColor = COLOR4D::UNSPECIFIED;
200
201 std::list<std::unique_ptr<IMPORTED_SHAPE>> newShapes;
202 std::vector<IMPORTED_POLYGON*> polypaths;
203
204 for( std::unique_ptr<IMPORTED_SHAPE>& shape : m_shapes )
205 {
206 IMPORTED_POLYGON* poly = dynamic_cast<IMPORTED_POLYGON*>( shape.get() );
207
208 if( !poly || poly->GetParentShapeIndex() < 0 )
209 {
210 newShapes.push_back( shape->clone() );
211 continue;
212 }
213
214 int index = poly->GetParentShapeIndex();
215
216 if( index != curShapeIdx && curShapeIdx >= 0 )
217 {
218 convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastStroke,
219 lastFilled, lastFillColor );
220
221 polypaths.clear();
222 }
223
224 curShapeIdx = index;
225 lastStroke = poly->GetStroke();
226 lastFilled = poly->IsFilled();
227 lastFillColor = poly->GetFillColor();
228 polypaths.push_back( poly );
229 }
230
231 if( curShapeIdx >= 0 )
232 {
233 convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastStroke, lastFilled,
234 lastFillColor );
235 }
236
237 m_shapes.swap( newShapes );
238}
void AddCircle(const VECTOR2D &aCenter, double aRadius, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor=COLOR4D::UNSPECIFIED) override
Create an object representing a circle.
void AddSpline(const VECTOR2D &aStart, const VECTOR2D &aBezierControl1, const VECTOR2D &aBezierControl2, const VECTOR2D &aEnd, const IMPORTED_STROKE &aStroke) override
Create an object representing an arc.
void AddLine(const VECTOR2D &aStart, const VECTOR2D &aEnd, const IMPORTED_STROKE &aStroke) override
Create an object representing a line segment.
void ImportTo(GRAPHICS_IMPORTER &aImporter)
void AddArc(const VECTOR2D &aCenter, const VECTOR2D &aStart, const EDA_ANGLE &aAngle, const IMPORTED_STROKE &aStroke) override
Create an object representing an arc.
void AddText(const VECTOR2D &aOrigin, const wxString &aText, double aHeight, double aWidth, double aThickness, double aOrientation, GR_TEXT_H_ALIGN_T aHJustify, GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D &aColor=COLOR4D::UNSPECIFIED) override
Create an object representing a text.
std::list< std::unique_ptr< IMPORTED_SHAPE > > m_shapes
< List of imported shapes
void AddShape(std::unique_ptr< IMPORTED_SHAPE > &aShape)
void AddPolygon(const std::vector< VECTOR2D > &aVertices, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor=COLOR4D::UNSPECIFIED) override
Create an object representing a polygon.
Interface that creates objects representing shapes for a given data model.
std::vector< POLY_FILL_RULE > m_shapeFillRules
const IMPORTED_STROKE & GetStroke() const
const COLOR4D & GetFillColor() const
int GetParentShapeIndex() const
A clone of IMPORTED_STROKE, but with floating-point width.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
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.
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.
Represent a set of closed polygons.
static const SHAPE_POLY_SET BuildPolysetFromOrientedPaths(const std::vector< SHAPE_LINE_CHAIN > &aPaths, bool aReverseOrientation=false, bool aEvenOdd=false)
Build a SHAPE_POLY_SET from a bunch of outlines in provided in random order.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
static std::unique_ptr< T > make_shape(const Args &... aArguments)
static void convertPolygon(std::list< std::unique_ptr< IMPORTED_SHAPE > > &aShapes, std::vector< IMPORTED_POLYGON * > &aPaths, GRAPHICS_IMPORTER::POLY_FILL_RULE aFillRule, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor)
STL namespace.
GR_TEXT_H_ALIGN_T
GR_TEXT_V_ALIGN_T
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587