KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_sch_ellipse_roundtrip.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21#include <eeschema_test_utils.h>
22
24#include <sch_screen.h>
25#include <sch_sheet.h>
26#include <sch_shape.h>
27#include <schematic.h>
28#include <lib_symbol.h>
29#include <stroke_params.h>
30#include <geometry/eda_angle.h>
32
33#include <wx/filename.h>
34#include <wx/stdpaths.h>
35
36
38{
41 {
42 wxString tempDir = wxStandardPaths::Get().GetTempDir();
43 wxString projectPath = tempDir + wxFileName::GetPathSeparator() + wxT( "test_sch_ellipse.kicad_pro" );
44 m_tempFiles.push_back( projectPath );
45
46 m_settingsManager.LoadProject( projectPath.ToStdString() );
47 m_schematic = std::make_unique<SCHEMATIC>( nullptr );
49 m_schematic->SetProject( m_project );
50 }
51
53 {
54 for( const wxString& file : m_tempFiles )
55 {
56 if( wxFileExists( file ) )
57 wxRemoveFile( file );
58 }
59
60 m_schematic.reset();
61 }
62
63 wxString GetTempFileName( const wxString& aPrefix )
64 {
65 wxString tempDir = wxStandardPaths::Get().GetTempDir();
66 wxString fileName = wxFileName::CreateTempFileName( tempDir + wxFileName::GetPathSeparator() + aPrefix );
67 m_tempFiles.push_back( fileName );
68 return fileName;
69 }
70
75 SCH_SHAPE* RoundTrip( SCH_SHAPE* aShape, const wxString& aTag )
76 {
77 SHAPE_T shapeType = aShape->GetShape();
78
79 m_schematic->CreateDefaultScreens();
80 std::vector<SCH_SHEET*> topSheets = m_schematic->GetTopLevelSheets();
81 SCH_SCREEN* screen = topSheets[0]->GetScreen();
82 screen->SetFileName( "test.kicad_sch" );
83
84 screen->Append( aShape );
85
86 wxString fileName = GetTempFileName( aTag );
87 fileName += ".kicad_sch";
88 m_tempFiles.push_back( fileName );
89
91 io.SaveSchematicFile( fileName, topSheets[0], m_schematic.get() );
92
93 // aShape is now owned by the old screen and will be destroyed by Reset().
94 aShape = nullptr;
95
96 m_schematic->Reset();
97 SCH_SHEET* defaultSheet = m_schematic->GetTopLevelSheet( 0 );
98 SCH_SHEET* loaded = io.LoadSchematicFile( fileName, m_schematic.get() );
99 m_schematic->AddTopLevelSheet( loaded );
100 m_schematic->RemoveTopLevelSheet( defaultSheet );
101 delete defaultSheet;
102
103 SCH_SCREEN* reScreen = loaded->GetScreen();
104
105 for( SCH_ITEM* item : reScreen->Items() )
106 {
107 if( SCH_SHAPE* ps = dynamic_cast<SCH_SHAPE*>( item ) )
108 {
109 if( ps->GetShape() == shapeType )
110 return ps;
111 }
112 }
113
114 return nullptr;
115 }
116
118 std::unique_ptr<SCHEMATIC> m_schematic;
120 std::vector<wxString> m_tempFiles;
121};
122
123
124BOOST_FIXTURE_TEST_SUITE( SchEllipseRoundTrip, SCH_ELLIPSE_FIXTURE )
125
126
127BOOST_AUTO_TEST_CASE( SchematicClosedEllipse )
128{
129 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE, LAYER_NOTES );
130 shape->SetEllipseCenter( VECTOR2I( 2540, 5080 ) ); // 100 mil, 200 mil
131 shape->SetEllipseMajorRadius( 1270 ); // 50 mil
132 shape->SetEllipseMinorRadius( 762 ); // 30 mil
133 shape->SetEllipseRotation( EDA_ANGLE( 30.0, DEGREES_T ) );
134 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
135
136 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_closed" );
137 BOOST_REQUIRE_MESSAGE( found, "Schematic ellipse not found after roundtrip" );
138
139 BOOST_CHECK_EQUAL( found->GetEllipseCenter().x, 2540 );
140 BOOST_CHECK_EQUAL( found->GetEllipseCenter().y, 5080 );
143 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), 30.0, 1e-6 );
144}
145
146
147BOOST_AUTO_TEST_CASE( SchematicEllipseArc )
148{
149 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE_ARC, LAYER_NOTES );
150 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
151 shape->SetEllipseMajorRadius( 1016 ); // 40 mil
152 shape->SetEllipseMinorRadius( 635 ); // 25 mil
153 shape->SetEllipseRotation( EDA_ANGLE( 45.0, DEGREES_T ) );
154 shape->SetEllipseStartAngle( EDA_ANGLE( 20.0, DEGREES_T ) );
155 shape->SetEllipseEndAngle( EDA_ANGLE( 160.0, DEGREES_T ) );
156 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
157
158 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_arc" );
159 BOOST_REQUIRE_MESSAGE( found, "Schematic elliptical arc not found after roundtrip" );
160
163 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), 45.0, 1e-6 );
164 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 20.0, 1e-6 );
165 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 160.0, 1e-6 );
166}
167
168
169BOOST_AUTO_TEST_CASE( SchematicEllipseNegativeRotation )
170{
171 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE, LAYER_NOTES );
172 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
173 shape->SetEllipseMajorRadius( 2000 );
174 shape->SetEllipseMinorRadius( 1000 );
175 shape->SetEllipseRotation( EDA_ANGLE( -60.0, DEGREES_T ) );
176 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
177
178 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_negrot" );
179 BOOST_REQUIRE_MESSAGE( found, "Schematic ellipse not found after roundtrip" );
180
181 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), -60.0, 1e-6 );
182}
183
184
185BOOST_AUTO_TEST_CASE( SchematicEllipseStrokeAndFill )
186{
187 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE, LAYER_NOTES );
188 shape->SetEllipseCenter( VECTOR2I( 1000, 1000 ) );
189 shape->SetEllipseMajorRadius( 500 );
190 shape->SetEllipseMinorRadius( 300 );
191 shape->SetEllipseRotation( ANGLE_0 );
192 shape->SetStroke( STROKE_PARAMS( 50, LINE_STYLE::DASH ) );
193 shape->SetFillMode( FILL_T::FILLED_SHAPE );
194
195 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_stroke_fill" );
196 BOOST_REQUIRE_MESSAGE( found, "Schematic ellipse not found after roundtrip" );
197
198 BOOST_CHECK_EQUAL( found->GetStroke().GetWidth(), 50 );
199 BOOST_CHECK( found->GetStroke().GetLineStyle() == LINE_STYLE::DASH );
200 BOOST_CHECK( found->GetFillMode() == FILL_T::FILLED_WITH_COLOR );
201}
202
203
204BOOST_AUTO_TEST_CASE( SymbolEllipse )
205{
206 auto symbol = std::make_unique<LIB_SYMBOL>( wxT( "TestEllipse" ), nullptr );
207
208 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE, LAYER_DEVICE );
209 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
210 shape->SetEllipseMajorRadius( 508 ); // 20 mil
211 shape->SetEllipseMinorRadius( 254 ); // 10 mil
212 shape->SetEllipseRotation( EDA_ANGLE( 15.0, DEGREES_T ) );
213 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
214 symbol->AddDrawItem( shape );
215
216 // Verify the shape was added and fields are accessible.
217 SCH_SHAPE* found = nullptr;
218
219 for( SCH_ITEM& item : symbol->GetDrawItems() )
220 {
221 if( SCH_SHAPE* ps = dynamic_cast<SCH_SHAPE*>( &item ) )
222 {
223 if( ps->GetShape() == SHAPE_T::ELLIPSE )
224 {
225 found = ps;
226 break;
227 }
228 }
229 }
230
231 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in symbol draw items" );
234 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), 15.0, 1e-6 );
235}
236
237
238BOOST_AUTO_TEST_CASE( SymbolEllipseArc )
239{
240 auto symbol = std::make_unique<LIB_SYMBOL>( wxT( "TestEllipseArc" ), nullptr );
241
242 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE_ARC, LAYER_DEVICE );
243 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
244 shape->SetEllipseMajorRadius( 762 ); // 30 mil
245 shape->SetEllipseMinorRadius( 381 ); // 15 mil
246 shape->SetEllipseRotation( EDA_ANGLE( -45.0, DEGREES_T ) );
247 shape->SetEllipseStartAngle( EDA_ANGLE( 30.0, DEGREES_T ) );
248 shape->SetEllipseEndAngle( EDA_ANGLE( 300.0, DEGREES_T ) );
249 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
250 symbol->AddDrawItem( shape );
251
252 SCH_SHAPE* found = nullptr;
253
254 for( SCH_ITEM& item : symbol->GetDrawItems() )
255 {
256 if( SCH_SHAPE* ps = dynamic_cast<SCH_SHAPE*>( &item ) )
257 {
258 if( ps->GetShape() == SHAPE_T::ELLIPSE_ARC )
259 {
260 found = ps;
261 break;
262 }
263 }
264 }
265
266 BOOST_REQUIRE_MESSAGE( found, "Elliptical arc not found in symbol draw items" );
269 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), -45.0, 1e-6 );
270 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 30.0, 1e-6 );
271 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 300.0, 1e-6 );
272}
273
274
275BOOST_AUTO_TEST_CASE( SchematicEllipseArcStartEqualsEnd )
276{
277 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE_ARC, LAYER_NOTES );
278 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
279 shape->SetEllipseMajorRadius( 500 );
280 shape->SetEllipseMinorRadius( 300 );
281 shape->SetEllipseRotation( ANGLE_0 );
282 shape->SetEllipseStartAngle( EDA_ANGLE( 90.0, DEGREES_T ) );
283 shape->SetEllipseEndAngle( EDA_ANGLE( 90.0, DEGREES_T ) );
284 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
285
286 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_arc_eq" );
287 BOOST_REQUIRE_MESSAGE( found, "Schematic elliptical arc not found after roundtrip" );
288
289 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 90.0, 1e-6 );
290 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 90.0, 1e-6 );
291}
292
293
294BOOST_AUTO_TEST_CASE( SymbolEllipseWithFill )
295{
296 auto symbol = std::make_unique<LIB_SYMBOL>( wxT( "TestEllipseFill" ), nullptr );
297
298 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE, LAYER_DEVICE );
299 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
300 shape->SetEllipseMajorRadius( 762 );
301 shape->SetEllipseMinorRadius( 381 );
302 shape->SetEllipseRotation( ANGLE_0 );
303 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
304 shape->SetFillMode( FILL_T::FILLED_SHAPE );
305 symbol->AddDrawItem( shape );
306
307 SCH_SHAPE* found = nullptr;
308
309 for( SCH_ITEM& item : symbol->GetDrawItems() )
310 {
311 if( SCH_SHAPE* ps = dynamic_cast<SCH_SHAPE*>( &item ) )
312 {
313 if( ps->GetShape() == SHAPE_T::ELLIPSE )
314 {
315 found = ps;
316 break;
317 }
318 }
319 }
320
321 BOOST_REQUIRE_MESSAGE( found, "Ellipse not found in symbol draw items" );
322 BOOST_CHECK( found->GetFillMode() == FILL_T::FILLED_SHAPE );
323}
324
325
326BOOST_AUTO_TEST_CASE( SchematicEllipseMinimumRadii )
327{
328 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE, LAYER_NOTES );
329 shape->SetEllipseCenter( VECTOR2I( 0, 0 ) );
330 shape->SetEllipseMajorRadius( 1 );
331 shape->SetEllipseMinorRadius( 1 );
332 shape->SetEllipseRotation( ANGLE_0 );
333 shape->SetStroke( STROKE_PARAMS( 25, LINE_STYLE::SOLID ) );
334
335 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_minradii" );
336 BOOST_REQUIRE_MESSAGE( found, "Schematic ellipse not found after roundtrip" );
337
338 BOOST_CHECK( found->GetEllipseMajorRadius() >= 1 );
339 BOOST_CHECK( found->GetEllipseMinorRadius() >= 1 );
340}
341
342
348BOOST_AUTO_TEST_CASE( SchematicEllipseAllFieldsPreserved )
349{
350 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE, LAYER_NOTES );
351 shape->SetEllipseCenter( VECTOR2I( 3810, 7620 ) );
352 shape->SetEllipseMajorRadius( 2540 );
353 shape->SetEllipseMinorRadius( 1270 );
354 shape->SetEllipseRotation( EDA_ANGLE( 77.5, DEGREES_T ) );
355 shape->SetStroke( STROKE_PARAMS( 38, LINE_STYLE::DOT ) );
356 shape->SetFillMode( FILL_T::NO_FILL );
357
358 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_all_fields" );
359 BOOST_REQUIRE_MESSAGE( found, "Schematic ellipse not found after roundtrip" );
360
361 BOOST_CHECK_EQUAL( found->GetEllipseCenter().x, 3810 );
362 BOOST_CHECK_EQUAL( found->GetEllipseCenter().y, 7620 );
365 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), 77.5, 1e-6 );
366 BOOST_CHECK_EQUAL( found->GetStroke().GetWidth(), 38 );
367 BOOST_CHECK( found->GetStroke().GetLineStyle() == LINE_STYLE::DOT );
368 BOOST_CHECK( found->GetFillMode() == FILL_T::NO_FILL );
369}
370
371
377BOOST_AUTO_TEST_CASE( SchematicEllipseArcAllFieldsPreserved )
378{
379 auto* shape = new SCH_SHAPE( SHAPE_T::ELLIPSE_ARC, LAYER_NOTES );
380 shape->SetEllipseCenter( VECTOR2I( 1270, 2540 ) );
381 shape->SetEllipseMajorRadius( 5080 );
382 shape->SetEllipseMinorRadius( 2540 );
383 shape->SetEllipseRotation( EDA_ANGLE( -22.5, DEGREES_T ) );
384 shape->SetEllipseStartAngle( EDA_ANGLE( 15.0, DEGREES_T ) );
385 shape->SetEllipseEndAngle( EDA_ANGLE( 315.0, DEGREES_T ) );
386 shape->SetStroke( STROKE_PARAMS( 50, LINE_STYLE::DASHDOT ) );
387
388 SCH_SHAPE* found = RoundTrip( shape, "sch_ellipse_arc_all_fields" );
389 BOOST_REQUIRE_MESSAGE( found, "Schematic elliptical arc not found after roundtrip" );
390
391 BOOST_CHECK_EQUAL( found->GetEllipseCenter().x, 1270 );
392 BOOST_CHECK_EQUAL( found->GetEllipseCenter().y, 2540 );
395 BOOST_CHECK_CLOSE( found->GetEllipseRotation().AsDegrees(), -22.5, 1e-6 );
396 BOOST_CHECK_CLOSE( found->GetEllipseStartAngle().AsDegrees(), 15.0, 1e-6 );
397 BOOST_CHECK_CLOSE( found->GetEllipseEndAngle().AsDegrees(), 315.0, 1e-6 );
398 BOOST_CHECK_EQUAL( found->GetStroke().GetWidth(), 50 );
399 BOOST_CHECK( found->GetStroke().GetLineStyle() == LINE_STYLE::DASHDOT );
400}
401
402
double AsDegrees() const
Definition eda_angle.h:116
int GetEllipseMinorRadius() const
Definition eda_shape.h:306
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:288
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:334
FILL_T GetFillMode() const
Definition eda_shape.h:162
int GetEllipseMajorRadius() const
Definition eda_shape.h:297
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:315
SHAPE_T GetShape() const
Definition eda_shape.h:189
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:325
Container for project specific data.
Definition project.h:66
A SCH_IO derivation for loading schematic files using the new s-expression file format.
void SaveSchematicFile(const wxString &aFileName, SCH_SHEET *aSheet, SCHEMATIC *aSchematic, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aSchematic to a storage file in a format that this SCH_IO implementation knows about,...
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
STROKE_PARAMS GetStroke() const override
Definition sch_shape.h:61
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:143
Simple container to manage line stroke parameters.
int GetWidth() const
LINE_STYLE GetLineStyle() const
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
@ DEGREES_T
Definition eda_angle.h:31
SHAPE_T
Definition eda_shape.h:48
@ ELLIPSE
Definition eda_shape.h:56
@ ELLIPSE_ARC
Definition eda_shape.h:57
@ FILLED_WITH_COLOR
Definition eda_shape.h:67
@ NO_FILL
Definition eda_shape.h:64
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:65
@ LAYER_DEVICE
Definition layer_ids.h:468
@ LAYER_NOTES
Definition layer_ids.h:469
wxString GetTempFileName(const wxString &aPrefix)
std::vector< wxString > m_tempFiles
std::unique_ptr< SCHEMATIC > m_schematic
SCH_SHAPE * RoundTrip(SCH_SHAPE *aShape, const wxString &aTag)
Helper: add a SCH_SHAPE to the first screen, save, reload, and return the matching shape from the rel...
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(SchematicClosedEllipse)
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687