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, see <https://www.gnu.org/licenses/>.
18 */
19
21
24#include <eda_item.h>
25#include <base_units.h>
26
27
29{
30public:
35
36 void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
37 const IMPORTED_STROKE& aStroke ) override
38 {
39 m_lines.push_back( { aStart, aEnd } );
40 }
41
42 void AddCircle( const VECTOR2D& aCenter, double aRadius, const IMPORTED_STROKE& aStroke,
43 bool aFilled, const COLOR4D& aFillColor ) override
44 {
45 }
46
47 void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
48 const IMPORTED_STROKE& aStroke ) override
49 {
50 }
51
52 void AddEllipse( const VECTOR2D& aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE& aRotation,
53 const IMPORTED_STROKE& aStroke, bool aFilled, const COLOR4D& aFillColor ) override
54 {
55 }
56
57 void AddEllipseArc( const VECTOR2D& aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE& aRotation,
58 const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aEndAngle,
59 const IMPORTED_STROKE& aStroke ) override
60 {
61 }
62
63 void AddPolygon( const std::vector<VECTOR2D>& aVertices, const IMPORTED_STROKE& aStroke,
64 bool aFilled, const COLOR4D& aFillColor ) override
65 {
66 m_polygons.push_back( aVertices );
67 }
68
69 void AddText( const VECTOR2D& aOrigin, const wxString& aText, double aHeight, double aWidth,
70 double aThickness, double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
71 GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor ) override
72 {
73 }
74
75 void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
76 const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
77 const IMPORTED_STROKE& aStroke ) override
78 {
79 m_splines.push_back( { aStart, aBezierControl1, aBezierControl2, aEnd } );
80 }
81
82 std::vector<std::pair<VECTOR2D, VECTOR2D>> m_lines;
83 std::vector<std::vector<VECTOR2D>> m_polygons;
84 std::vector<std::tuple<VECTOR2D, VECTOR2D, VECTOR2D, VECTOR2D>> m_splines;
85};
86
87
88BOOST_AUTO_TEST_SUITE( SvgImport )
89
90
91
98BOOST_AUTO_TEST_CASE( SingleNodeClosedPath )
99{
100 const char* svg =
101 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
102 "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\""
103 " width=\"100mm\" height=\"100mm\">"
104 "<path d=\"M 50,80 C 80,20 20,20 50,80 Z\" fill=\"black\" stroke=\"none\" />"
105 "</svg>";
106
107 wxMemoryBuffer buf;
108 buf.AppendData( svg, strlen( svg ) + 1 );
109
110 SVG_IMPORT_PLUGIN plugin;
112 plugin.SetImporter( &importer );
113
114 BOOST_REQUIRE( plugin.LoadFromMemory( buf ) );
115 BOOST_REQUIRE( plugin.Import() );
116
117 // The single-node closed path should produce at least one polygon with non-degenerate area
118 BOOST_REQUIRE_MESSAGE( !importer.m_polygons.empty(),
119 "Single-node closed SVG path should produce a polygon" );
120
121 const auto& poly = importer.m_polygons[0];
122
123 BOOST_CHECK_MESSAGE( poly.size() > 3,
124 "Polygon should have more than 3 vertices (got " << poly.size() << ")" );
125
126 // Verify the polygon has non-zero area by checking that not all vertices are identical
127 bool hasDistinctVertices = false;
128
129 for( size_t i = 1; i < poly.size(); ++i )
130 {
131 if( poly[i] != poly[0] )
132 {
133 hasDistinctVertices = true;
134 break;
135 }
136 }
137
138 BOOST_CHECK_MESSAGE( hasDistinctVertices,
139 "Polygon vertices should not all be at the same point" );
140
141 // Compute approximate area using the shoelace formula to verify non-degenerate polygon
142 double area = 0.0;
143
144 for( size_t i = 0; i < poly.size(); ++i )
145 {
146 size_t j = ( i + 1 ) % poly.size();
147 area += poly[i].x * poly[j].y;
148 area -= poly[j].x * poly[i].y;
149 }
150
151 area = std::fabs( area ) / 2.0;
152
153 BOOST_CHECK_MESSAGE( area > 0.01,
154 "Polygon should have non-zero area (got " << area << ")" );
155}
156
157
161BOOST_AUTO_TEST_CASE( MultiNodeClosedPath )
162{
163 const char* svg =
164 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
165 "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\""
166 " width=\"100mm\" height=\"100mm\">"
167 "<path d=\"M 10,10 C 40,0 60,0 90,10 C 100,40 100,60 90,90"
168 " C 60,100 40,100 10,90 C 0,60 0,40 10,10 Z\" fill=\"black\" stroke=\"none\" />"
169 "</svg>";
170
171 wxMemoryBuffer buf;
172 buf.AppendData( svg, strlen( svg ) + 1 );
173
174 SVG_IMPORT_PLUGIN plugin;
176 plugin.SetImporter( &importer );
177
178 BOOST_REQUIRE( plugin.LoadFromMemory( buf ) );
179 BOOST_REQUIRE( plugin.Import() );
180
181 BOOST_REQUIRE_MESSAGE( !importer.m_polygons.empty(),
182 "Multi-node closed SVG path should produce a polygon" );
183
184 BOOST_CHECK_MESSAGE( importer.m_polygons[0].size() > 4,
185 "Multi-node polygon should have many vertices" );
186}
187
188
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
Definition base_units.h:68
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:101
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:682