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, see <https://www.gnu.org/licenses/>.
18 */
19
24
26#include "eeschema_test_utils.h"
27
28#include <sch_symbol.h>
29#include <sch_field.h>
30#include <sch_item.h>
31#include <geometry/eda_angle.h>
32
33
35{
36public:
37 SCH_SYMBOL* GetSymbolByRef( const wxString& aRef )
38 {
39 if( !m_schematic )
40 return nullptr;
41
42 SCH_SCREEN* screen = m_schematic->RootScreen();
43
44 if( !screen )
45 return nullptr;
46
47 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
48 {
49 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
50
51 if( symbol && symbol->GetRef( &m_schematic->Hierarchy()[0], false ) == aRef )
52 return symbol;
53 }
54
55 return nullptr;
56 }
57};
58
59
60BOOST_FIXTURE_TEST_SUITE( AutoplaceFields, TEST_AUTOPLACE_FIELDS_FIXTURE )
61
62
63
77BOOST_AUTO_TEST_CASE( RotatedSymbolFieldBoundingBox )
78{
79 wxFileName fn;
80 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
81 fn.AppendDir( wxS( "issue16538" ) );
82 fn.SetName( wxS( "issue16538" ) );
84
85 LoadSchematic( fn.GetFullPath() );
86
87 SCH_SYMBOL* symbol = GetSymbolByRef( wxS( "C1" ) );
88 BOOST_REQUIRE( symbol );
89
90 // Verify the symbol is rotated 90 degrees (y1 != 0)
91 TRANSFORM transform = symbol->GetTransform();
92 BOOST_CHECK( transform.y1 != 0 );
93
94 // Get the reference field
95 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
96 BOOST_REQUIRE( refField );
97
98 // Set the field to horizontal angle (as the fix does)
99 refField->SetTextAngle( ANGLE_HORIZONTAL );
100
101 // Get the bounding box after setting horizontal angle
102 BOX2I bbox = refField->GetBoundingBox();
103
104 // For a 90-degree rotated symbol with horizontal field angle:
105 // The bounding box should be tall and narrow (text displays vertically)
106 // Height should be greater than width for short text like "C1"
107 BOOST_CHECK_MESSAGE( bbox.GetHeight() > bbox.GetWidth(),
108 wxString::Format( "Expected vertical bounding box (height > width) "
109 "for rotated symbol. Got width=%lld, height=%lld",
110 static_cast<long long>( bbox.GetWidth() ),
111 static_cast<long long>( bbox.GetHeight() ) ) );
112}
113
114
118BOOST_AUTO_TEST_CASE( FieldDrawRotationForRotatedSymbol )
119{
120 wxFileName fn;
121 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
122 fn.AppendDir( wxS( "issue16538" ) );
123 fn.SetName( wxS( "issue16538" ) );
125
126 LoadSchematic( fn.GetFullPath() );
127
128 SCH_SYMBOL* symbol = GetSymbolByRef( wxS( "C1" ) );
129 BOOST_REQUIRE( symbol );
130
131 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
132 BOOST_REQUIRE( refField );
133
134 // Set field to horizontal angle (as the fix does for autoplace)
135 refField->SetTextAngle( ANGLE_HORIZONTAL );
136
137 // For a 90-degree rotated symbol with horizontal field angle,
138 // GetDrawRotation should return vertical (the visual orientation)
139 EDA_ANGLE drawRotation = refField->GetDrawRotation();
140 BOOST_CHECK_MESSAGE( drawRotation.IsVertical(),
141 wxString::Format( "Expected vertical draw rotation for 90-degree "
142 "rotated symbol with horizontal field angle. "
143 "Got %f degrees", drawRotation.AsDegrees() ) );
144}
145
146
154BOOST_AUTO_TEST_CASE( RotatedSymbolFieldAngleForHorizontalDisplay )
155{
156 wxFileName fn;
157 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
158 fn.AppendDir( wxS( "issue16538" ) );
159 fn.SetName( wxS( "issue16538" ) );
161
162 LoadSchematic( fn.GetFullPath() );
163
164 // C1 is a 90-degree rotated capacitor (y1 != 0)
165 SCH_SYMBOL* rotatedSymbol = GetSymbolByRef( wxS( "C1" ) );
166 BOOST_REQUIRE( rotatedSymbol );
167 BOOST_REQUIRE( rotatedSymbol->GetTransform().y1 != 0 );
168
169 SCH_FIELD* refField = rotatedSymbol->GetField( FIELD_T::REFERENCE );
170 BOOST_REQUIRE( refField );
171
172 // Simulate what the autoplacer should do for rotated symbols
173 refField->SetTextAngle( ANGLE_VERTICAL );
174
175 EDA_ANGLE drawRotation = refField->GetDrawRotation();
176 BOOST_CHECK_MESSAGE( drawRotation.IsHorizontal(),
177 wxString::Format( wxS( "Rotated symbol with VERTICAL field angle "
178 "should display horizontally. Got %f degrees" ),
179 drawRotation.AsDegrees() ) );
180
181 // R1 is a non-rotated resistor (y1 == 0)
182 SCH_SYMBOL* normalSymbol = GetSymbolByRef( wxS( "R1" ) );
183 BOOST_REQUIRE( normalSymbol );
184 BOOST_REQUIRE( normalSymbol->GetTransform().y1 == 0 );
185
186 refField = normalSymbol->GetField( FIELD_T::REFERENCE );
187 BOOST_REQUIRE( refField );
188
189 // For non-rotated symbols, HORIZONTAL field angle should stay horizontal
190 refField->SetTextAngle( ANGLE_HORIZONTAL );
191
192 drawRotation = refField->GetDrawRotation();
193 BOOST_CHECK_MESSAGE( drawRotation.IsHorizontal(),
194 wxString::Format( wxS( "Non-rotated symbol with HORIZONTAL field angle "
195 "should display horizontally. Got %f degrees" ),
196 drawRotation.AsDegrees() ) );
197}
198
199
206BOOST_AUTO_TEST_CASE( RotatedSymbolBBoxAngleEffects )
207{
208 wxFileName fn;
209 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
210 fn.AppendDir( wxS( "issue16538" ) );
211 fn.SetName( wxS( "issue16538" ) );
213
214 LoadSchematic( fn.GetFullPath() );
215
216 SCH_SYMBOL* symbol = GetSymbolByRef( wxS( "C1" ) );
217 BOOST_REQUIRE( symbol );
218
219 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
220 BOOST_REQUIRE( refField );
221
222 // HORIZONTAL angle + 90-degree symbol transform = 90-degree visual rotation.
223 // For short text like "C1", this produces a tall, narrow bbox.
224 refField->SetTextAngle( ANGLE_HORIZONTAL );
225 BOX2I hBox = refField->GetBoundingBox();
226
227 // VERTICAL angle + 90-degree symbol transform = 180-degree net rotation.
228 // After Normalize() the dimensions match horizontal display (wider than tall).
229 refField->SetTextAngle( ANGLE_VERTICAL );
230 BOX2I vBox = refField->GetBoundingBox();
231
232 BOOST_CHECK_MESSAGE( hBox.GetHeight() > hBox.GetWidth(),
233 wxString::Format( wxS( "HORIZONTAL angle bbox should be taller than "
234 "wide. Got width=%lld, height=%lld" ),
235 static_cast<long long>( hBox.GetWidth() ),
236 static_cast<long long>( hBox.GetHeight() ) ) );
237
238 BOOST_CHECK_MESSAGE( vBox.GetWidth() > vBox.GetHeight(),
239 wxString::Format( wxS( "VERTICAL angle bbox should be wider than "
240 "tall. Got width=%lld, height=%lld" ),
241 static_cast<long long>( vBox.GetWidth() ),
242 static_cast<long long>( vBox.GetHeight() ) ) );
243
244 refField->SetTextAngle( ANGLE_VERTICAL );
245}
246
247
256BOOST_AUTO_TEST_CASE( RotatedSymbolFieldSizingDimensions )
257{
258 wxFileName fn;
259 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
260 fn.AppendDir( wxS( "issue16538" ) );
261 fn.SetName( wxS( "issue16538" ) );
263
264 LoadSchematic( fn.GetFullPath() );
265
266 // R1 is a non-rotated resistor, C1 is a 90-degree rotated capacitor
267 SCH_SYMBOL* normalSymbol = GetSymbolByRef( wxS( "R1" ) );
268 BOOST_REQUIRE( normalSymbol );
269 BOOST_REQUIRE( normalSymbol->GetTransform().y1 == 0 );
270
271 SCH_SYMBOL* rotatedSymbol = GetSymbolByRef( wxS( "C1" ) );
272 BOOST_REQUIRE( rotatedSymbol );
273 BOOST_REQUIRE( rotatedSymbol->GetTransform().y1 != 0 );
274
275 SCH_FIELD* normalRef = normalSymbol->GetField( FIELD_T::REFERENCE );
276 SCH_FIELD* rotatedRef = rotatedSymbol->GetField( FIELD_T::REFERENCE );
277 BOOST_REQUIRE( normalRef && rotatedRef );
278
279 // For the non-rotated symbol, display angle = HORIZONTAL
280 normalRef->SetTextAngle( ANGLE_HORIZONTAL );
281 BOX2I normalBBox = normalRef->GetBoundingBox();
282
283 // For the 90-degree rotated symbol, display angle = VERTICAL.
284 // VERTICAL + 90-degree symbol transform = 180 net rotation, which preserves
285 // the native text dimensions (width > height for short text).
286 rotatedRef->SetTextAngle( ANGLE_VERTICAL );
287 BOX2I rotatedBBox = rotatedRef->GetBoundingBox();
288
289 // Both should produce bboxes where width > height (horizontal text dimensions).
290 // The normal symbol trivially gets this from HORIZONTAL angle + identity transform.
291 // The rotated symbol gets this from VERTICAL + 90-degree transform = 180 net rotation.
292 BOOST_CHECK_MESSAGE( normalBBox.GetWidth() > normalBBox.GetHeight(),
293 wxString::Format( wxS( "Normal symbol with HORIZONTAL angle should have "
294 "width > height. Got width=%lld, height=%lld" ),
295 static_cast<long long>( normalBBox.GetWidth() ),
296 static_cast<long long>( normalBBox.GetHeight() ) ) );
297
298 BOOST_CHECK_MESSAGE( rotatedBBox.GetWidth() > rotatedBBox.GetHeight(),
299 wxString::Format( wxS( "Rotated symbol with VERTICAL angle should have "
300 "width > height (native dims). Got width=%lld, "
301 "height=%lld" ),
302 static_cast<long long>( rotatedBBox.GetWidth() ),
303 static_cast<long long>( rotatedBBox.GetHeight() ) ) );
304
305 // The height (used for vertical spacing) should be comparable between the two.
306 // Both represent the text height for horizontal display.
307 int normalH = normalBBox.GetHeight();
308 int rotatedH = rotatedBBox.GetHeight();
309 double heightRatio = static_cast<double>( std::max( normalH, rotatedH ) )
310 / static_cast<double>( std::max( 1, std::min( normalH, rotatedH ) ) );
311
312 BOOST_CHECK_MESSAGE( heightRatio < 2.0,
313 wxString::Format( wxS( "Field height ratio should be < 2.0. "
314 "Normal=%d, Rotated=%d, Ratio=%.2f" ),
315 normalH, rotatedH, heightRatio ) );
316
317 // Verify that using HORIZONTAL angle on the rotated symbol would produce wrong
318 // dimensions (height > width, swapped). This is what the bug looked like.
319 rotatedRef->SetTextAngle( ANGLE_HORIZONTAL );
320 BOX2I wrongBBox = rotatedRef->GetBoundingBox();
321
322 BOOST_CHECK_MESSAGE( wrongBBox.GetHeight() > wrongBBox.GetWidth(),
323 wxString::Format( wxS( "HORIZONTAL angle on rotated symbol should swap "
324 "dims (height > width). Got width=%lld, "
325 "height=%lld" ),
326 static_cast<long long>( wrongBBox.GetWidth() ),
327 static_cast<long long>( wrongBBox.GetHeight() ) ) );
328
329 // Restore
330 rotatedRef->SetTextAngle( ANGLE_VERTICAL );
331}
332
333
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr size_type GetHeight() const
Definition box2.h:211
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:294
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:221
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:162
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:115
Schematic symbol object.
Definition sch_symbol.h:69
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:243
SCH_SYMBOL * GetSymbolByRef(const wxString &aRef)
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:42
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()
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
@ SCH_SYMBOL_T
Definition typeinfo.h:169