KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_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 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
26#include <eda_item.h>
29#include <base_units.h>
30#include <algorithm>
31#include <cstring>
32#include <limits>
33#include <wx/ffile.h>
34#include <wx/filefn.h>
35#include <wx/filename.h>
36
37
39{
40public:
45
46 void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
47 const IMPORTED_STROKE& aStroke ) override
48 {
49 m_lines.push_back( { aStart, aEnd } );
51 }
52
53 bool CanImportSourceLayer( const wxString& aSourceLayer ) const override
54 {
55 if( m_enabledSourceLayers.empty() )
56 return true;
57
58 return std::find( m_enabledSourceLayers.begin(), m_enabledSourceLayers.end(), aSourceLayer )
59 != m_enabledSourceLayers.end();
60 }
61
62 void SetCurrentSourceLayer( const wxString& aSourceLayer ) override { m_currentSourceLayer = aSourceLayer; }
63
64 void AddCircle( const VECTOR2D& aCenter, double aRadius, const IMPORTED_STROKE& aStroke,
65 bool aFilled, const COLOR4D& aFillColor ) override {}
66
67 void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
68 const IMPORTED_STROKE& aStroke ) override {}
69
70 void AddPolygon( const std::vector<VECTOR2D>& aVertices, const IMPORTED_STROKE& aStroke,
71 bool aFilled, const COLOR4D& aFillColor ) override {}
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 void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
78 const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
79 const IMPORTED_STROKE& aStroke ) override {}
80
81 void AddEllipse( const VECTOR2D& aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE& aRotation,
82 const IMPORTED_STROKE& aStroke, bool aFilled, const COLOR4D& aFillColor ) override
83 {
84 }
85
86 void AddEllipseArc( const VECTOR2D& aCenter, double aMajorRadius, double aMinorRadius, const EDA_ANGLE& aRotation,
87 const EDA_ANGLE& aStartAngle, const EDA_ANGLE& aEndAngle,
88 const IMPORTED_STROKE& aStroke ) override
89 {
90 }
91
92 std::vector<std::pair<VECTOR2D, VECTOR2D>> m_lines;
93 std::vector<wxString> m_lineSourceLayers;
94 std::vector<wxString> m_enabledSourceLayers;
96};
97
98
99BOOST_AUTO_TEST_SUITE( GraphicsImporterBuffer )
100
101
102
109BOOST_AUTO_TEST_CASE( LargeCoordinatesAutoOffset )
110{
112 TEST_GRAPHICS_IMPORTER importer;
113
114 // Add a line with coordinates that would overflow INT32 when converted to IU
115 // 2300mm * 1e6 IU/mm = 2.3e9 > INT32_MAX (2.147e9)
116 VECTOR2D start( 2300.0, 1400.0 );
117 VECTOR2D end( 2350.0, 1450.0 );
118
119 IMPORTED_STROKE stroke( 0.1 );
120 buffer.AddLine( start, end, stroke );
121
122 // Import with no offset set (default is 0,0)
123 BOOST_CHECK( importer.GetImportOffsetMM() == VECTOR2D( 0, 0 ) );
124
125 buffer.ImportTo( importer );
126
127 // After import, the offset should have been automatically adjusted
128 // to move the coordinates into the valid range
129 VECTOR2D offset = importer.GetImportOffsetMM();
130
131 // The offset should be negative of the bounding box origin to bring coordinates near zero
132 BOOST_CHECK_MESSAGE( offset.x < 0, "X offset should be negative to shift large coords down" );
133
134 // Verify the resulting coordinates are within valid IU range
135 if( !importer.m_lines.empty() )
136 {
137 VECTOR2D importedStart = importer.m_lines[0].first;
138 VECTOR2D importedEnd = importer.m_lines[0].second;
139
140 // After offset and scale, coordinates should be manageable
141 double maxCoord = static_cast<double>( std::numeric_limits<int>::max() )
142 / importer.GetMillimeterToIuFactor();
143
144 BOOST_CHECK_MESSAGE( ( importedStart.x + offset.x ) < maxCoord,
145 "Imported X coord should be within valid range" );
146 BOOST_CHECK_MESSAGE( ( importedStart.y + offset.y ) < maxCoord,
147 "Imported Y coord should be within valid range" );
148 }
149}
150
151
155BOOST_AUTO_TEST_CASE( NormalCoordinatesNoOffset )
156{
158 TEST_GRAPHICS_IMPORTER importer;
159
160 // Add a line with normal coordinates that fit within the valid range
161 // 100mm * 1e6 IU/mm = 1e8 << INT32_MAX
162 VECTOR2D start( 100.0, 100.0 );
163 VECTOR2D end( 200.0, 200.0 );
164
165 IMPORTED_STROKE stroke( 0.1 );
166 buffer.AddLine( start, end, stroke );
167
168 buffer.ImportTo( importer );
169
170 // Offset should remain at zero since coordinates are valid
171 VECTOR2D offset = importer.GetImportOffsetMM();
172 BOOST_CHECK_MESSAGE( offset == VECTOR2D( 0, 0 ),
173 "Normal coordinates should not trigger auto-offset" );
174}
175
176
177BOOST_AUTO_TEST_CASE( SourceLayersAreReportedAndCanBeSkipped )
178{
180 TEST_GRAPHICS_IMPORTER importer;
181
182 IMPORTED_STROKE stroke( 0.1 );
183
184 buffer.SetCurrentSourceLayer( wxS( "Outline" ) );
185 buffer.AddLine( VECTOR2D( 0.0, 0.0 ), VECTOR2D( 10.0, 0.0 ), stroke );
186
187 buffer.SetCurrentSourceLayer( wxS( "Guide" ) );
188 buffer.AddLine( VECTOR2D( 0.0, 1.0 ), VECTOR2D( 10.0, 1.0 ), stroke );
189
190 std::vector<wxString> sourceLayers = buffer.GetSourceLayers();
191
192 BOOST_CHECK( std::find( sourceLayers.begin(), sourceLayers.end(), wxS( "Outline" ) ) != sourceLayers.end() );
193 BOOST_CHECK( std::find( sourceLayers.begin(), sourceLayers.end(), wxS( "Guide" ) ) != sourceLayers.end() );
194
195 importer.m_enabledSourceLayers.push_back( wxS( "Outline" ) );
196
197 buffer.ImportTo( importer );
198
199 BOOST_REQUIRE_EQUAL( importer.m_lines.size(), 1 );
200 BOOST_REQUIRE_EQUAL( importer.m_lineSourceLayers.size(), 1 );
201 BOOST_CHECK_EQUAL( importer.m_lineSourceLayers[0], wxS( "Outline" ) );
202}
203
204
205BOOST_AUTO_TEST_CASE( DxfSourceLayersArePreserved )
206{
207 const char* dxf =
208 "0\n"
209 "SECTION\n"
210 "2\n"
211 "HEADER\n"
212 "9\n"
213 "$INSUNITS\n"
214 "70\n"
215 "4\n"
216 "0\n"
217 "ENDSEC\n"
218 "0\n"
219 "SECTION\n"
220 "2\n"
221 "TABLES\n"
222 "0\n"
223 "TABLE\n"
224 "2\n"
225 "LAYER\n"
226 "70\n"
227 "2\n"
228 "0\n"
229 "LAYER\n"
230 "2\n"
231 "Outline\n"
232 "70\n"
233 "0\n"
234 "62\n"
235 "7\n"
236 "6\n"
237 "Continuous\n"
238 "0\n"
239 "LAYER\n"
240 "2\n"
241 "Guide\n"
242 "70\n"
243 "0\n"
244 "62\n"
245 "7\n"
246 "6\n"
247 "Continuous\n"
248 "0\n"
249 "ENDTAB\n"
250 "0\n"
251 "ENDSEC\n"
252 "0\n"
253 "SECTION\n"
254 "2\n"
255 "ENTITIES\n"
256 "0\n"
257 "LINE\n"
258 "8\n"
259 "Outline\n"
260 "10\n"
261 "0\n"
262 "20\n"
263 "0\n"
264 "11\n"
265 "10\n"
266 "21\n"
267 "0\n"
268 "0\n"
269 "LINE\n"
270 "8\n"
271 "Guide\n"
272 "10\n"
273 "0\n"
274 "20\n"
275 "1\n"
276 "11\n"
277 "10\n"
278 "21\n"
279 "1\n"
280 "0\n"
281 "ENDSEC\n"
282 "0\n"
283 "EOF\n";
284
285 wxString dxfPath = wxFileName::CreateTempFileName( wxS( "kicad_dxf_layers" ) );
286 BOOST_REQUIRE( !dxfPath.IsEmpty() );
287
288 {
289 wxFFile file( dxfPath, wxT( "wb" ) );
290 BOOST_REQUIRE( file.IsOpened() );
291 BOOST_REQUIRE_EQUAL( file.Write( dxf, strlen( dxf ) ), strlen( dxf ) );
292 }
293
294 DXF_IMPORT_PLUGIN plugin;
295 TEST_GRAPHICS_IMPORTER importer;
296
298 plugin.SetImporter( &importer );
299
300 BOOST_REQUIRE( plugin.Load( dxfPath ) );
301 wxRemoveFile( dxfPath );
302
303 std::vector<wxString> sourceLayers = plugin.GetSourceLayers();
304
305 BOOST_CHECK( std::find( sourceLayers.begin(), sourceLayers.end(), wxS( "Outline" ) ) != sourceLayers.end() );
306 BOOST_CHECK( std::find( sourceLayers.begin(), sourceLayers.end(), wxS( "Guide" ) ) != sourceLayers.end() );
307
308 importer.m_enabledSourceLayers.push_back( wxS( "Outline" ) );
309
310 BOOST_REQUIRE( plugin.Import() );
311
312 BOOST_REQUIRE_EQUAL( importer.m_lines.size(), 1 );
313 BOOST_REQUIRE_EQUAL( importer.m_lineSourceLayers.size(), 1 );
314 BOOST_CHECK_EQUAL( importer.m_lineSourceLayers[0], wxS( "Outline" ) );
315}
316
317
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
Definition base_units.h:72
bool Import() override
Actually imports the file.
std::vector< wxString > GetSourceLayers() const
bool Load(const wxString &aFileName) override
Load file for import.
void SetUnit(DXF_IMPORT_UNITS aUnit)
Set the default units when importing DXFs.
virtual void SetImporter(GRAPHICS_IMPORTER *aImporter) override
Set the receiver of the imported shapes.
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 SetCurrentSourceLayer(const wxString &aSourceLayer) override
Set the source layer for the next buffered shape to be imported.
std::vector< wxString > GetSourceLayers() const
double m_millimeterToIu
Factor to convert millimeters to Internal Units.
const VECTOR2D & GetImportOffsetMM() const
A clone of IMPORTED_STROKE, but with floating-point width.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
void AddLine(const VECTOR2D &aStart, const VECTOR2D &aEnd, const IMPORTED_STROKE &aStroke) override
Create an object representing a line segment.
void AddCircle(const VECTOR2D &aCenter, double aRadius, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor) override
Create an object representing a circle.
std::vector< wxString > m_lineSourceLayers
bool CanImportSourceLayer(const wxString &aSourceLayer) const override
Return true if shapes from a given source layer should be imported.
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::pair< VECTOR2D, VECTOR2D > > m_lines
std::vector< wxString > m_enabledSourceLayers
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 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.
void AddPolygon(const std::vector< VECTOR2D > &aVertices, const IMPORTED_STROKE &aStroke, bool aFilled, const COLOR4D &aFillColor) override
Create an object representing a polygon.
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 AddArc(const VECTOR2D &aCenter, const VECTOR2D &aStart, const EDA_ANGLE &aAngle, const IMPORTED_STROKE &aStroke) override
Create an object representing an arc.
void SetCurrentSourceLayer(const wxString &aSourceLayer) override
Set the source layer for the next buffered shape to be imported.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(LargeCoordinatesAutoOffset)
Test that large coordinates that would overflow when converted to internal units are automatically of...
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")
VECTOR2I end
BOOST_CHECK_EQUAL(result, "25.4")
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