KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_autoplace_fields.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
28
30#include "eeschema_test_utils.h"
31
32#include <sch_symbol.h>
33#include <sch_field.h>
34#include <sch_item.h>
35#include <geometry/eda_angle.h>
36
37
39{
40public:
41 SCH_SYMBOL* GetSymbolByRef( const wxString& aRef )
42 {
43 if( !m_schematic )
44 return nullptr;
45
46 SCH_SCREEN* screen = m_schematic->RootScreen();
47
48 if( !screen )
49 return nullptr;
50
51 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
52 {
53 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
54
55 if( symbol && symbol->GetRef( &m_schematic->Hierarchy()[0], false ) == aRef )
56 return symbol;
57 }
58
59 return nullptr;
60 }
61};
62
63
64BOOST_FIXTURE_TEST_SUITE( AutoplaceFields, TEST_AUTOPLACE_FIELDS_FIXTURE )
65
66
67
81BOOST_AUTO_TEST_CASE( RotatedSymbolFieldBoundingBox )
82{
83 wxFileName fn;
84 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
85 fn.AppendDir( wxS( "issue16538" ) );
86 fn.SetName( wxS( "issue16538" ) );
88
89 LoadSchematic( fn.GetFullPath() );
90
91 SCH_SYMBOL* symbol = GetSymbolByRef( wxS( "C1" ) );
92 BOOST_REQUIRE( symbol );
93
94 // Verify the symbol is rotated 90 degrees (y1 != 0)
95 TRANSFORM transform = symbol->GetTransform();
96 BOOST_CHECK( transform.y1 != 0 );
97
98 // Get the reference field
99 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
100 BOOST_REQUIRE( refField );
101
102 // Set the field to horizontal angle (as the fix does)
103 refField->SetTextAngle( ANGLE_HORIZONTAL );
104
105 // Get the bounding box after setting horizontal angle
106 BOX2I bbox = refField->GetBoundingBox();
107
108 // For a 90-degree rotated symbol with horizontal field angle:
109 // The bounding box should be tall and narrow (text displays vertically)
110 // Height should be greater than width for short text like "C1"
111 BOOST_CHECK_MESSAGE( bbox.GetHeight() > bbox.GetWidth(),
112 wxString::Format( "Expected vertical bounding box (height > width) "
113 "for rotated symbol. Got width=%lld, height=%lld",
114 static_cast<long long>( bbox.GetWidth() ),
115 static_cast<long long>( bbox.GetHeight() ) ) );
116}
117
118
122BOOST_AUTO_TEST_CASE( FieldDrawRotationForRotatedSymbol )
123{
124 wxFileName fn;
125 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
126 fn.AppendDir( wxS( "issue16538" ) );
127 fn.SetName( wxS( "issue16538" ) );
129
130 LoadSchematic( fn.GetFullPath() );
131
132 SCH_SYMBOL* symbol = GetSymbolByRef( wxS( "C1" ) );
133 BOOST_REQUIRE( symbol );
134
135 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
136 BOOST_REQUIRE( refField );
137
138 // Set field to horizontal angle (as the fix does for autoplace)
139 refField->SetTextAngle( ANGLE_HORIZONTAL );
140
141 // For a 90-degree rotated symbol with horizontal field angle,
142 // GetDrawRotation should return vertical (the visual orientation)
143 EDA_ANGLE drawRotation = refField->GetDrawRotation();
144 BOOST_CHECK_MESSAGE( drawRotation.IsVertical(),
145 wxString::Format( "Expected vertical draw rotation for 90-degree "
146 "rotated symbol with horizontal field angle. "
147 "Got %f degrees", drawRotation.AsDegrees() ) );
148}
149
150
158BOOST_AUTO_TEST_CASE( RotatedSymbolFieldAngleForHorizontalDisplay )
159{
160 wxFileName fn;
161 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
162 fn.AppendDir( wxS( "issue16538" ) );
163 fn.SetName( wxS( "issue16538" ) );
165
166 LoadSchematic( fn.GetFullPath() );
167
168 // C1 is a 90-degree rotated capacitor (y1 != 0)
169 SCH_SYMBOL* rotatedSymbol = GetSymbolByRef( wxS( "C1" ) );
170 BOOST_REQUIRE( rotatedSymbol );
171 BOOST_REQUIRE( rotatedSymbol->GetTransform().y1 != 0 );
172
173 SCH_FIELD* refField = rotatedSymbol->GetField( FIELD_T::REFERENCE );
174 BOOST_REQUIRE( refField );
175
176 // Simulate what the autoplacer should do for rotated symbols
177 refField->SetTextAngle( ANGLE_VERTICAL );
178
179 EDA_ANGLE drawRotation = refField->GetDrawRotation();
180 BOOST_CHECK_MESSAGE( drawRotation.IsHorizontal(),
181 wxString::Format( wxS( "Rotated symbol with VERTICAL field angle "
182 "should display horizontally. Got %f degrees" ),
183 drawRotation.AsDegrees() ) );
184
185 // R1 is a non-rotated resistor (y1 == 0)
186 SCH_SYMBOL* normalSymbol = GetSymbolByRef( wxS( "R1" ) );
187 BOOST_REQUIRE( normalSymbol );
188 BOOST_REQUIRE( normalSymbol->GetTransform().y1 == 0 );
189
190 refField = normalSymbol->GetField( FIELD_T::REFERENCE );
191 BOOST_REQUIRE( refField );
192
193 // For non-rotated symbols, HORIZONTAL field angle should stay horizontal
194 refField->SetTextAngle( ANGLE_HORIZONTAL );
195
196 drawRotation = refField->GetDrawRotation();
197 BOOST_CHECK_MESSAGE( drawRotation.IsHorizontal(),
198 wxString::Format( wxS( "Non-rotated symbol with HORIZONTAL field angle "
199 "should display horizontally. Got %f degrees" ),
200 drawRotation.AsDegrees() ) );
201}
202
203
210BOOST_AUTO_TEST_CASE( RotatedSymbolBBoxAngleEffects )
211{
212 wxFileName fn;
213 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
214 fn.AppendDir( wxS( "issue16538" ) );
215 fn.SetName( wxS( "issue16538" ) );
217
218 LoadSchematic( fn.GetFullPath() );
219
220 SCH_SYMBOL* symbol = GetSymbolByRef( wxS( "C1" ) );
221 BOOST_REQUIRE( symbol );
222
223 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
224 BOOST_REQUIRE( refField );
225
226 // HORIZONTAL angle + 90-degree symbol transform = 90-degree visual rotation.
227 // For short text like "C1", this produces a tall, narrow bbox.
228 refField->SetTextAngle( ANGLE_HORIZONTAL );
229 BOX2I hBox = refField->GetBoundingBox();
230
231 // VERTICAL angle + 90-degree symbol transform = 180-degree net rotation.
232 // After Normalize() the dimensions match horizontal display (wider than tall).
233 refField->SetTextAngle( ANGLE_VERTICAL );
234 BOX2I vBox = refField->GetBoundingBox();
235
236 BOOST_CHECK_MESSAGE( hBox.GetHeight() > hBox.GetWidth(),
237 wxString::Format( wxS( "HORIZONTAL angle bbox should be taller than "
238 "wide. Got width=%lld, height=%lld" ),
239 static_cast<long long>( hBox.GetWidth() ),
240 static_cast<long long>( hBox.GetHeight() ) ) );
241
242 BOOST_CHECK_MESSAGE( vBox.GetWidth() > vBox.GetHeight(),
243 wxString::Format( wxS( "VERTICAL angle bbox should be wider than "
244 "tall. Got width=%lld, height=%lld" ),
245 static_cast<long long>( vBox.GetWidth() ),
246 static_cast<long long>( vBox.GetHeight() ) ) );
247
248 refField->SetTextAngle( ANGLE_VERTICAL );
249}
250
251
260BOOST_AUTO_TEST_CASE( RotatedSymbolFieldSizingDimensions )
261{
262 wxFileName fn;
263 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
264 fn.AppendDir( wxS( "issue16538" ) );
265 fn.SetName( wxS( "issue16538" ) );
267
268 LoadSchematic( fn.GetFullPath() );
269
270 // R1 is a non-rotated resistor, C1 is a 90-degree rotated capacitor
271 SCH_SYMBOL* normalSymbol = GetSymbolByRef( wxS( "R1" ) );
272 BOOST_REQUIRE( normalSymbol );
273 BOOST_REQUIRE( normalSymbol->GetTransform().y1 == 0 );
274
275 SCH_SYMBOL* rotatedSymbol = GetSymbolByRef( wxS( "C1" ) );
276 BOOST_REQUIRE( rotatedSymbol );
277 BOOST_REQUIRE( rotatedSymbol->GetTransform().y1 != 0 );
278
279 SCH_FIELD* normalRef = normalSymbol->GetField( FIELD_T::REFERENCE );
280 SCH_FIELD* rotatedRef = rotatedSymbol->GetField( FIELD_T::REFERENCE );
281 BOOST_REQUIRE( normalRef && rotatedRef );
282
283 // For the non-rotated symbol, display angle = HORIZONTAL
284 normalRef->SetTextAngle( ANGLE_HORIZONTAL );
285 BOX2I normalBBox = normalRef->GetBoundingBox();
286
287 // For the 90-degree rotated symbol, display angle = VERTICAL.
288 // VERTICAL + 90-degree symbol transform = 180 net rotation, which preserves
289 // the native text dimensions (width > height for short text).
290 rotatedRef->SetTextAngle( ANGLE_VERTICAL );
291 BOX2I rotatedBBox = rotatedRef->GetBoundingBox();
292
293 // Both should produce bboxes where width > height (horizontal text dimensions).
294 // The normal symbol trivially gets this from HORIZONTAL angle + identity transform.
295 // The rotated symbol gets this from VERTICAL + 90-degree transform = 180 net rotation.
296 BOOST_CHECK_MESSAGE( normalBBox.GetWidth() > normalBBox.GetHeight(),
297 wxString::Format( wxS( "Normal symbol with HORIZONTAL angle should have "
298 "width > height. Got width=%lld, height=%lld" ),
299 static_cast<long long>( normalBBox.GetWidth() ),
300 static_cast<long long>( normalBBox.GetHeight() ) ) );
301
302 BOOST_CHECK_MESSAGE( rotatedBBox.GetWidth() > rotatedBBox.GetHeight(),
303 wxString::Format( wxS( "Rotated symbol with VERTICAL angle should have "
304 "width > height (native dims). Got width=%lld, "
305 "height=%lld" ),
306 static_cast<long long>( rotatedBBox.GetWidth() ),
307 static_cast<long long>( rotatedBBox.GetHeight() ) ) );
308
309 // The height (used for vertical spacing) should be comparable between the two.
310 // Both represent the text height for horizontal display.
311 int normalH = normalBBox.GetHeight();
312 int rotatedH = rotatedBBox.GetHeight();
313 double heightRatio = static_cast<double>( std::max( normalH, rotatedH ) )
314 / static_cast<double>( std::max( 1, std::min( normalH, rotatedH ) ) );
315
316 BOOST_CHECK_MESSAGE( heightRatio < 2.0,
317 wxString::Format( wxS( "Field height ratio should be < 2.0. "
318 "Normal=%d, Rotated=%d, Ratio=%.2f" ),
319 normalH, rotatedH, heightRatio ) );
320
321 // Verify that using HORIZONTAL angle on the rotated symbol would produce wrong
322 // dimensions (height > width, swapped). This is what the bug looked like.
323 rotatedRef->SetTextAngle( ANGLE_HORIZONTAL );
324 BOX2I wrongBBox = rotatedRef->GetBoundingBox();
325
326 BOOST_CHECK_MESSAGE( wrongBBox.GetHeight() > wrongBBox.GetWidth(),
327 wxString::Format( wxS( "HORIZONTAL angle on rotated symbol should swap "
328 "dims (height > width). Got width=%lld, "
329 "height=%lld" ),
330 static_cast<long long>( wrongBBox.GetWidth() ),
331 static_cast<long long>( wrongBBox.GetHeight() ) ) );
332
333 // Restore
334 rotatedRef->SetTextAngle( ANGLE_VERTICAL );
335}
336
337
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr size_type GetHeight() const
Definition box2.h:215
double AsDegrees() const
Definition eda_angle.h:116
bool IsHorizontal() const
Definition eda_angle.h:142
bool IsVertical() const
Definition eda_angle.h:148
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:313
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
A generic fixture for loading schematics and associated settings for qa tests.
std::unique_ptr< SCHEMATIC > m_schematic
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
EDA_ANGLE GetDrawRotation() const override
Adjusters to allow EDA_TEXT to draw/print/etc.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
Schematic symbol object.
Definition sch_symbol.h:76
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
const TRANSFORM & GetTransform() const
Definition symbol.h:247
SCH_SYMBOL * GetSymbolByRef(const wxString &aRef)
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:46
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static const std::string KiCadSchematicFileExtension
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
static void LoadSchematic(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, const wxString &aFileName)
@ REFERENCE
Field Reference of part, i.e. "IC21".
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(RotatedSymbolFieldBoundingBox)
Test that field bounding boxes for rotated symbols have correct dimensions.
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
@ SCH_SYMBOL_T
Definition typeinfo.h:176