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 AddPolygon( const std::vector<VECTOR2D>& aVertices, const IMPORTED_STROKE& aStroke,
57 bool aFilled, const COLOR4D& aFillColor ) override
58 {
59 m_polygons.push_back( aVertices );
60 }
61
62 void AddText( const VECTOR2D& aOrigin, const wxString& aText, double aHeight, double aWidth,
63 double aThickness, double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
64 GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor ) override
65 {
66 }
67
68 void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
69 const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
70 const IMPORTED_STROKE& aStroke ) override
71 {
72 m_splines.push_back( { aStart, aBezierControl1, aBezierControl2, aEnd } );
73 }
74
75 std::vector<std::pair<VECTOR2D, VECTOR2D>> m_lines;
76 std::vector<std::vector<VECTOR2D>> m_polygons;
77 std::vector<std::tuple<VECTOR2D, VECTOR2D, VECTOR2D, VECTOR2D>> m_splines;
78};
79
80
81BOOST_AUTO_TEST_SUITE( SvgImport )
82
83
84
91BOOST_AUTO_TEST_CASE( SingleNodeClosedPath )
92{
93 const char* svg =
94 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
95 "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\""
96 " width=\"100mm\" height=\"100mm\">"
97 "<path d=\"M 50,80 C 80,20 20,20 50,80 Z\" fill=\"black\" stroke=\"none\" />"
98 "</svg>";
99
100 wxMemoryBuffer buf;
101 buf.AppendData( svg, strlen( svg ) + 1 );
102
103 SVG_IMPORT_PLUGIN plugin;
105 plugin.SetImporter( &importer );
106
107 BOOST_REQUIRE( plugin.LoadFromMemory( buf ) );
108 BOOST_REQUIRE( plugin.Import() );
109
110 // The single-node closed path should produce at least one polygon with non-degenerate area
111 BOOST_REQUIRE_MESSAGE( !importer.m_polygons.empty(),
112 "Single-node closed SVG path should produce a polygon" );
113
114 const auto& poly = importer.m_polygons[0];
115
116 BOOST_CHECK_MESSAGE( poly.size() > 3,
117 "Polygon should have more than 3 vertices (got " << poly.size() << ")" );
118
119 // Verify the polygon has non-zero area by checking that not all vertices are identical
120 bool hasDistinctVertices = false;
121
122 for( size_t i = 1; i < poly.size(); ++i )
123 {
124 if( poly[i] != poly[0] )
125 {
126 hasDistinctVertices = true;
127 break;
128 }
129 }
130
131 BOOST_CHECK_MESSAGE( hasDistinctVertices,
132 "Polygon vertices should not all be at the same point" );
133
134 // Compute approximate area using the shoelace formula to verify non-degenerate polygon
135 double area = 0.0;
136
137 for( size_t i = 0; i < poly.size(); ++i )
138 {
139 size_t j = ( i + 1 ) % poly.size();
140 area += poly[i].x * poly[j].y;
141 area -= poly[j].x * poly[i].y;
142 }
143
144 area = std::fabs( area ) / 2.0;
145
146 BOOST_CHECK_MESSAGE( area > 0.01,
147 "Polygon should have non-zero area (got " << area << ")" );
148}
149
150
154BOOST_AUTO_TEST_CASE( MultiNodeClosedPath )
155{
156 const char* svg =
157 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
158 "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\""
159 " width=\"100mm\" height=\"100mm\">"
160 "<path d=\"M 10,10 C 40,0 60,0 90,10 C 100,40 100,60 90,90"
161 " C 60,100 40,100 10,90 C 0,60 0,40 10,10 Z\" fill=\"black\" stroke=\"none\" />"
162 "</svg>";
163
164 wxMemoryBuffer buf;
165 buf.AppendData( svg, strlen( svg ) + 1 );
166
167 SVG_IMPORT_PLUGIN plugin;
169 plugin.SetImporter( &importer );
170
171 BOOST_REQUIRE( plugin.LoadFromMemory( buf ) );
172 BOOST_REQUIRE( plugin.Import() );
173
174 BOOST_REQUIRE_MESSAGE( !importer.m_polygons.empty(),
175 "Multi-node closed SVG path should produce a polygon" );
176
177 BOOST_CHECK_MESSAGE( importer.m_polygons[0].size() > 4,
178 "Multi-node polygon should have many vertices" );
179}
180
181
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
Definition base_units.h:70
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 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
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