KiCad PCB EDA Suite
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-2022 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, double aWidth )
42{
43 m_shapes.push_back( make_shape< IMPORTED_LINE >( aStart, aEnd, aWidth ) );
44}
45
46
47void GRAPHICS_IMPORTER_BUFFER::AddCircle( const VECTOR2D& aCenter, double aRadius, double aWidth, bool aFilled )
48{
49 m_shapes.push_back( make_shape<IMPORTED_CIRCLE>( aCenter, aRadius, aWidth, aFilled ) );
50}
51
52
53void GRAPHICS_IMPORTER_BUFFER::AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart,
54 const EDA_ANGLE& aAngle, double aWidth )
55{
56 m_shapes.push_back( make_shape<IMPORTED_ARC>( aCenter, aStart, aAngle, aWidth ) );
57}
58
59
60void GRAPHICS_IMPORTER_BUFFER::AddPolygon( const std::vector< VECTOR2D >& aVertices, double aWidth )
61{
62 m_shapes.push_back( make_shape<IMPORTED_POLYGON>( aVertices, aWidth ) );
63 m_shapes.back()->SetParentShapeIndex( m_shapeFillRules.size() - 1 );
64}
65
66
67void GRAPHICS_IMPORTER_BUFFER::AddText( const VECTOR2D& aOrigin, const wxString& aText,
68 double aHeight, double aWidth, double aThickness,
69 double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
70 GR_TEXT_V_ALIGN_T aVJustify )
71{
72 m_shapes.push_back( make_shape< IMPORTED_TEXT >( aOrigin, aText, aHeight, aWidth,
73 aThickness, aOrientation, aHJustify, aVJustify ) );
74}
75
76
77void GRAPHICS_IMPORTER_BUFFER::AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
78 const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd , double aWidth )
79{
80 m_shapes.push_back( make_shape<IMPORTED_SPLINE>( aStart, aBezierControl1, aBezierControl2, aEnd, aWidth ) );
81}
82
83
84void GRAPHICS_IMPORTER_BUFFER::AddShape( std::unique_ptr<IMPORTED_SHAPE>& aShape )
85{
86 m_shapes.push_back( std::move( aShape ) );
87}
88
89
91{
92 for( std::unique_ptr<IMPORTED_SHAPE>& shape : m_shapes )
93 shape->ImportTo( aImporter );
94}
95
96// 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)
97static void convertPolygon( std::list<std::unique_ptr<IMPORTED_SHAPE>>& aShapes,
98 std::vector<IMPORTED_POLYGON*>& aPaths,
100 double aWidth )
101{
102 double minX = std::numeric_limits<double>::max();
103 double minY = minX;
104 double maxX = std::numeric_limits<double>::min();
105 double maxY = maxX;
106
107 // as Clipper/SHAPE_POLY_SET uses ints we first need to upscale to a reasonably large size (in integer coordinates)
108 // to avoid losing accuracy
109 const double convert_scale = 1000000000.0;
110
111 for( IMPORTED_POLYGON* path : aPaths )
112 {
113 for( VECTOR2D& v : path->Vertices() )
114 {
115 minX = std::min( minX, v.x );
116 minY = std::min( minY, v.y );
117 maxX = std::max( maxX, v.x );
118 maxY = std::max( maxY, v.y );
119 }
120 }
121
122 double origW = ( maxX - minX );
123 double origH = ( maxY - minY );
124 double upscaledW, upscaledH;
125
126 if( origW > origH )
127 {
128 upscaledW = convert_scale;
129 upscaledH = ( origH == 0.0f ? 0.0 : origH * convert_scale / origW );
130 }
131 else
132 {
133 upscaledH = convert_scale;
134 upscaledW = ( origW == 0.0f ? 0.0 : origW * convert_scale / origH );
135 }
136
137 std::vector<SHAPE_LINE_CHAIN> upscaledPaths;
138
139 for( IMPORTED_POLYGON* path : aPaths )
140 {
142
143 for( VECTOR2D& v : path->Vertices() )
144 {
145 int xp = KiROUND( ( v.x - minX ) * ( upscaledW / origW ) );
146 int yp = KiROUND( ( v.y - minY ) * ( upscaledH / origH ) );
147 lc.Append( xp, yp );
148 }
149 lc.SetClosed( true );
150 upscaledPaths.push_back( lc );
151 }
152
154 upscaledPaths, false, aFillRule == GRAPHICS_IMPORTER::PF_EVEN_ODD );
156
157 for( int outl = 0; outl < result.OutlineCount(); outl++ )
158 {
159 const SHAPE_LINE_CHAIN& ro = result.COutline( outl );
160 std::vector<VECTOR2D> pts;
161 for( int i = 0; i < ro.PointCount(); i++ )
162 {
163 double xp = (double) ro.CPoint( i ).x * ( origW / upscaledW ) + minX;
164 double yp = (double) ro.CPoint( i ).y * ( origH / upscaledH ) + minY;
165 pts.emplace_back( VECTOR2D( xp, yp ) );
166 }
167
168 aShapes.push_back( std::make_unique<IMPORTED_POLYGON>( pts, aWidth ) );
169 }
170}
171
172
174{
175 int curShapeIdx = -1;
176 double lastWidth = 0;
177
178 std::list<std::unique_ptr<IMPORTED_SHAPE>> newShapes;
179 std::vector<IMPORTED_POLYGON*> polypaths;
180
181 for( std::unique_ptr<IMPORTED_SHAPE>& shape : m_shapes )
182 {
183 IMPORTED_POLYGON* poly = dynamic_cast<IMPORTED_POLYGON*>( shape.get() );
184
185 if( !poly || poly->GetParentShapeIndex() < 0 )
186 {
187 newShapes.push_back( shape->clone() );
188 continue;
189 }
190
191 int index = poly->GetParentShapeIndex();
192
193 if( index != curShapeIdx && curShapeIdx >= 0 )
194 {
195 convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastWidth );
196 polypaths.clear();
197 }
198
199 curShapeIdx = index;
200 lastWidth = poly->GetWidth();
201 polypaths.push_back( poly );
202 }
203
204 if( curShapeIdx >= 0 )
205 convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastWidth );
206
207 m_shapes.swap( newShapes );
208}
void AddCircle(const VECTOR2D &aCenter, double aRadius, double aWidth, bool aFilled) override
Create an object representing a circle.
void AddSpline(const VECTOR2D &aStart, const VECTOR2D &BezierControl1, const VECTOR2D &BezierControl2, const VECTOR2D &aEnd, double aWidth) override
Create an object representing an arc.
void ImportTo(GRAPHICS_IMPORTER &aImporter)
void AddArc(const VECTOR2D &aCenter, const VECTOR2D &aStart, const EDA_ANGLE &aAngle, double aWidth) override
Create an object representing an arc.
void AddPolygon(const std::vector< VECTOR2D > &aVertices, double aWidth) override
std::list< std::unique_ptr< IMPORTED_SHAPE > > m_shapes
< List of imported shapes
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) override
Create an object representing a text.
void AddShape(std::unique_ptr< IMPORTED_SHAPE > &aShape)
void AddLine(const VECTOR2D &aStart, const VECTOR2D &aEnd, double aWidth) override
Create an object representing a line segment.
Interface that creates objects representing shapes for a given data model.
std::vector< POLY_FILL_RULE > m_shapeFillRules
int GetParentShapeIndex() const
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 single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
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, double aWidth)
Definition: bitmap.cpp:64
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:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:617