KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_svg_import.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 2
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/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 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
28#include <eda_item.h>
29#include <base_units.h>
30
31
33{
34public:
39
40 void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
41 const IMPORTED_STROKE& aStroke ) override
42 {
43 m_lines.push_back( { aStart, aEnd } );
44 }
45
46 void AddCircle( const VECTOR2D& aCenter, double aRadius, const IMPORTED_STROKE& aStroke,
47 bool aFilled, const COLOR4D& aFillColor ) override
48 {
49 }
50
51 void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
52 const IMPORTED_STROKE& aStroke ) override
53 {
54 }
55
56 void AddEllipse( const VECTOR2D& aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE& aRotation,
57 const IMPORTED_STROKE& aStroke, bool aFilled, const COLOR4D& aFillColor ) override
58 {
59 }
60
61 void AddEllipseArc( const VECTOR2D& aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE& aRotation,
62 const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aEndAngle,
63 const IMPORTED_STROKE& aStroke ) override
64 {
65 }
66
67 void AddPolygon( const std::vector<VECTOR2D>& aVertices, const IMPORTED_STROKE& aStroke,
68 bool aFilled, const COLOR4D& aFillColor ) override
69 {
70 m_polygons.push_back( aVertices );
71 }
72
73 void AddText( const VECTOR2D& aOrigin, const wxString& aText, double aHeight, double aWidth,
74 double aThickness, double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
75 GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor ) override
76 {
77 }
78
79 void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
80 const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
81 const IMPORTED_STROKE& aStroke ) override
82 {
83 m_splines.push_back( { aStart, aBezierControl1, aBezierControl2, aEnd } );
84 }
85
86 std::vector<std::pair<VECTOR2D, VECTOR2D>> m_lines;
87 std::vector<std::vector<VECTOR2D>> m_polygons;
88 std::vector<std::tuple<VECTOR2D, VECTOR2D, VECTOR2D, VECTOR2D>> m_splines;
89};
90
91
92BOOST_AUTO_TEST_SUITE( SvgImport )
93
94
95
102BOOST_AUTO_TEST_CASE( SingleNodeClosedPath )
103{
104 const char* svg =
105 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
106 "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\""
107 " width=\"100mm\" height=\"100mm\">"
108 "<path d=\"M 50,80 C 80,20 20,20 50,80 Z\" fill=\"black\" stroke=\"none\" />"
109 "</svg>";
110
111 wxMemoryBuffer buf;
112 buf.AppendData( svg, strlen( svg ) + 1 );
113
114 SVG_IMPORT_PLUGIN plugin;
116 plugin.SetImporter( &importer );
117
118 BOOST_REQUIRE( plugin.LoadFromMemory( buf ) );
119 BOOST_REQUIRE( plugin.Import() );
120
121 // The single-node closed path should produce at least one polygon with non-degenerate area
122 BOOST_REQUIRE_MESSAGE( !importer.m_polygons.empty(),
123 "Single-node closed SVG path should produce a polygon" );
124
125 const auto& poly = importer.m_polygons[0];
126
127 BOOST_CHECK_MESSAGE( poly.size() > 3,
128 "Polygon should have more than 3 vertices (got " << poly.size() << ")" );
129
130 // Verify the polygon has non-zero area by checking that not all vertices are identical
131 bool hasDistinctVertices = false;
132
133 for( size_t i = 1; i < poly.size(); ++i )
134 {
135 if( poly[i] != poly[0] )
136 {
137 hasDistinctVertices = true;
138 break;
139 }
140 }
141
142 BOOST_CHECK_MESSAGE( hasDistinctVertices,
143 "Polygon vertices should not all be at the same point" );
144
145 // Compute approximate area using the shoelace formula to verify non-degenerate polygon
146 double area = 0.0;
147
148 for( size_t i = 0; i < poly.size(); ++i )
149 {
150 size_t j = ( i + 1 ) % poly.size();
151 area += poly[i].x * poly[j].y;
152 area -= poly[j].x * poly[i].y;
153 }
154
155 area = std::fabs( area ) / 2.0;
156
157 BOOST_CHECK_MESSAGE( area > 0.01,
158 "Polygon should have non-zero area (got " << area << ")" );
159}
160
161
165BOOST_AUTO_TEST_CASE( MultiNodeClosedPath )
166{
167 const char* svg =
168 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
169 "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\""
170 " width=\"100mm\" height=\"100mm\">"
171 "<path d=\"M 10,10 C 40,0 60,0 90,10 C 100,40 100,60 90,90"
172 " C 60,100 40,100 10,90 C 0,60 0,40 10,10 Z\" fill=\"black\" stroke=\"none\" />"
173 "</svg>";
174
175 wxMemoryBuffer buf;
176 buf.AppendData( svg, strlen( svg ) + 1 );
177
178 SVG_IMPORT_PLUGIN plugin;
180 plugin.SetImporter( &importer );
181
182 BOOST_REQUIRE( plugin.LoadFromMemory( buf ) );
183 BOOST_REQUIRE( plugin.Import() );
184
185 BOOST_REQUIRE_MESSAGE( !importer.m_polygons.empty(),
186 "Multi-node closed SVG path should produce a polygon" );
187
188 BOOST_CHECK_MESSAGE( importer.m_polygons[0].size() > 4,
189 "Multi-node polygon should have many vertices" );
190}
191
192
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
Definition base_units.h:72
double m_millimeterToIu
Factor to convert millimeters to Internal Units.
virtual void SetImporter(GRAPHICS_IMPORTER *aImporter)
Set the receiver of the imported shapes.
A clone of IMPORTED_STROKE, but with floating-point width.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
bool Import() override
Actually imports the file.
bool LoadFromMemory(const wxMemoryBuffer &aMemBuffer) override
Set memory buffer with content for import.
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 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) override
Create an object representing a text.
std::vector< std::vector< VECTOR2D > > m_polygons
void AddArc(const VECTOR2D &aCenter, const VECTOR2D &aStart, const EDA_ANGLE &aAngle, const IMPORTED_STROKE &aStroke) override
Create an object representing an arc.
void AddCircle(const VECTOR2D &aCenter, double aRadius, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor) override
Create an object representing a circle.
void AddEllipseArc(const VECTOR2D &aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aEndAngle, const IMPORTED_STROKE &aStroke) override
Create an object representing an elliptical arc.
void AddLine(const VECTOR2D &aStart, const VECTOR2D &aEnd, const IMPORTED_STROKE &aStroke) override
Create an object representing a line segment.
std::vector< std::tuple< VECTOR2D, VECTOR2D, VECTOR2D, VECTOR2D > > m_splines
void AddEllipse(const VECTOR2D &aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor) override
Create an object representing a closed ellipse.
std::vector< std::pair< VECTOR2D, VECTOR2D > > m_lines
void AddPolygon(const std::vector< VECTOR2D > &aVertices, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor) override
Create an object representing a polygon.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_AUTO_TEST_CASE(SingleNodeClosedPath)
Regression test for https://gitlab.com/kicad/code/kicad/-/issues/11445.
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
VECTOR2< double > VECTOR2D
Definition vector2d.h:686