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