KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_constraint_labels.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
26
28
29#include <climits>
30#include <set>
31
32#include <base_units.h>
33#include <eda_units.h>
34
35#include <pcb_shape.h>
36
39
40BOOST_AUTO_TEST_SUITE( ConstraintLabels )
41
42
43BOOST_AUTO_TEST_CASE( ValuelessConstraintIsTypeNameOnly )
44{
45 PCB_CONSTRAINT constraint( nullptr, PCB_CONSTRAINT_TYPE::PARALLEL );
46
47 BOOST_TEST( !constraint.HasValue() );
48 BOOST_CHECK_EQUAL( ConstraintDisplayLabel( constraint, EDA_UNITS::MM ), wxString( "Parallel" ) );
49}
50
51
52BOOST_AUTO_TEST_CASE( DrivingLengthShowsValueInDisplayUnits )
53{
55 constraint.SetValue( pcbIUScale.mmToIU( 12.0 ) );
56 constraint.SetDriving( true );
57
58 wxString mm = ConstraintDisplayLabel( constraint, EDA_UNITS::MM );
59 BOOST_TEST( mm.StartsWith( "Fixed length: " ) );
60 BOOST_TEST( mm.Contains( "12" ) );
61 BOOST_TEST( mm.Contains( "mm" ) );
62
63 // A length follows the requested display units, not a fixed unit.
64 wxString in = ConstraintDisplayLabel( constraint, EDA_UNITS::INCH );
65 BOOST_TEST( in.Contains( "in" ) );
66 BOOST_TEST( !in.Contains( "mm" ) );
67}
68
69
70BOOST_AUTO_TEST_CASE( ReferenceValueIsParenthesized )
71{
73 constraint.SetValue( pcbIUScale.mmToIU( 8.0 ) );
74 constraint.SetDriving( false );
75
76 wxString label = ConstraintDisplayLabel( constraint, EDA_UNITS::MM );
77 BOOST_TEST( label.Contains( "(" ) );
78 BOOST_TEST( label.Contains( ")" ) );
79 BOOST_TEST( label.Contains( "8" ) );
80}
81
82
83BOOST_AUTO_TEST_CASE( AngularValueShownInDegrees )
84{
86 constraint.SetValue( 45.0 );
87 constraint.SetDriving( true );
88
89 // An angle ignores the length display units and reads in degrees.
90 wxString label = ConstraintDisplayLabel( constraint, EDA_UNITS::MM );
91 BOOST_TEST( label.StartsWith( "Angular dimension: " ) );
92 BOOST_TEST( label.Contains( "45" ) );
93}
94
95
96BOOST_AUTO_TEST_CASE( VertexMemberOnRectangleReadsCorner )
97{
98 PCB_SHAPE rect( nullptr, SHAPE_T::RECTANGLE );
99 rect.SetLayer( Edge_Cuts );
100 rect.SetStart( VECTOR2I( 0, 0 ) );
101 rect.SetEnd( VECTOR2I( 1000, 1000 ) );
102
103 // Ordinals are 1 based matching the vertex editor pane rows so index 1 labels as corner 2
104 wxString label = ConstraintMemberLabel(
105 &rect, CONSTRAINT_MEMBER( rect.m_Uuid, CONSTRAINT_ANCHOR::VERTEX, 1 ), nullptr );
106
107 BOOST_TEST( label.Contains( "(corner 2)" ), "unexpected label: " << label.ToStdString() );
108}
109
110
111BOOST_AUTO_TEST_CASE( VertexMemberOnPolygonReadsVertex )
112{
113 PCB_SHAPE poly( nullptr, SHAPE_T::POLY );
114 poly.SetLayer( Edge_Cuts );
115 poly.SetPolyPoints( { { 0, 0 }, { 1000, 0 }, { 1500, 800 }, { 500, 1400 }, { -300, 800 } } );
116
117 wxString label = ConstraintMemberLabel(
118 &poly, CONSTRAINT_MEMBER( poly.m_Uuid, CONSTRAINT_ANCHOR::VERTEX, 2 ), nullptr );
119
120 BOOST_TEST( label.Contains( "(vertex 3)" ), "unexpected label: " << label.ToStdString() );
121}
122
123
124BOOST_AUTO_TEST_CASE( VertexMemberIndexAtIntMaxDoesNotOverflow )
125{
126 // Ordinal is computed in long long so a hostile INT_MAX index from a file renders as 2147483648
127 // instead of overflowing
128 PCB_SHAPE rect( nullptr, SHAPE_T::RECTANGLE );
129 rect.SetLayer( Edge_Cuts );
130 rect.SetStart( VECTOR2I( 0, 0 ) );
131 rect.SetEnd( VECTOR2I( 1000, 1000 ) );
132
133 wxString label = ConstraintMemberLabel(
134 &rect, CONSTRAINT_MEMBER( rect.m_Uuid, CONSTRAINT_ANCHOR::VERTEX, INT_MAX ), nullptr );
135
136 BOOST_TEST( label.Contains( "(corner 2147483648)" ), "unexpected label: " << label.ToStdString() );
137
138 PCB_SHAPE poly( nullptr, SHAPE_T::POLY );
139 poly.SetLayer( Edge_Cuts );
140 poly.SetPolyPoints( { { 0, 0 }, { 1000, 0 }, { 500, 1000 } } );
141
142 label = ConstraintMemberLabel(
143 &poly, CONSTRAINT_MEMBER( poly.m_Uuid, CONSTRAINT_ANCHOR::VERTEX, INT_MAX ), nullptr );
144
145 BOOST_TEST( label.Contains( "(vertex 2147483648)" ), "unexpected label: " << label.ToStdString() );
146}
147
148
149BOOST_AUTO_TEST_CASE( NonVertexMemberLabelUnchanged )
150{
151 PCB_SHAPE seg( nullptr, SHAPE_T::SEGMENT );
152 seg.SetLayer( Edge_Cuts );
153 seg.SetStart( VECTOR2I( 0, 0 ) );
154 seg.SetEnd( VECTOR2I( 1000, 0 ) );
155
156 wxString label = ConstraintMemberLabel(
157 &seg, CONSTRAINT_MEMBER( seg.m_Uuid, CONSTRAINT_ANCHOR::START ), nullptr );
158
159 BOOST_TEST( label.Contains( "(start)" ), "unexpected label: " << label.ToStdString() );
160 BOOST_TEST( !label.Contains( "vertex" ) );
161 BOOST_TEST( !label.Contains( "corner" ) );
162}
163
164
166
167
168BOOST_AUTO_TEST_CASE( TypeGlyphIsSingleCodepointAndDistinct )
169{
170 // Each badge is one codepoint carried by both the newstroke stroke font and the OpenGL glyph
171 // atlas, and unique so a badge is unambiguous. A multi-character mark would smear across the
172 // fixed-size badge and read poorly at any zoom.
173 std::set<wxString> seen;
174
175 for( int i = 1; i <= static_cast<int>( PCB_CONSTRAINT_TYPE::ARC_ANGLE ); ++i )
176 {
177 wxString glyph = ConstraintTypeGlyph( static_cast<PCB_CONSTRAINT_TYPE>( i ) );
178
179 BOOST_TEST( !glyph.IsEmpty() );
180 BOOST_TEST( glyph.length() == 1, "multi-codepoint glyph: " << glyph.ToStdString() );
181 BOOST_TEST( seen.insert( glyph ).second, "duplicate glyph: " << glyph.ToStdString() );
182 }
183}
184
185
186BOOST_AUTO_TEST_SUITE( ConstraintShapeAnchorsTests )
187
188
189BOOST_AUTO_TEST_CASE( SegmentExposesStartAndEnd )
190{
191 PCB_SHAPE seg( nullptr, SHAPE_T::SEGMENT );
192 seg.SetStart( VECTOR2I( 0, 0 ) );
193 seg.SetEnd( VECTOR2I( 1000, 2000 ) );
194
195 std::vector<CONSTRAINT_ANCHOR_POINT> anchors = ConstraintShapeAnchors( &seg );
196
197 BOOST_REQUIRE_EQUAL( anchors.size(), 2 );
198 BOOST_CHECK( anchors[0].anchor == CONSTRAINT_ANCHOR::START );
199 BOOST_CHECK( anchors[0].pos == VECTOR2I( 0, 0 ) );
200 BOOST_CHECK( anchors[1].anchor == CONSTRAINT_ANCHOR::END );
201 BOOST_CHECK( anchors[1].pos == VECTOR2I( 1000, 2000 ) );
202}
203
204
205BOOST_AUTO_TEST_CASE( CircleExposesOnlyCenter )
206{
207 PCB_SHAPE circle( nullptr, SHAPE_T::CIRCLE );
208 circle.SetCenter( VECTOR2I( 500, 500 ) );
209 circle.SetEnd( VECTOR2I( 500, 1500 ) ); // radius handle
210
211 std::vector<CONSTRAINT_ANCHOR_POINT> anchors = ConstraintShapeAnchors( &circle );
212
213 BOOST_REQUIRE_EQUAL( anchors.size(), 1 );
214 BOOST_CHECK( anchors[0].anchor == CONSTRAINT_ANCHOR::CENTER );
215 BOOST_CHECK( anchors[0].pos == VECTOR2I( 500, 500 ) );
216}
217
218
219BOOST_AUTO_TEST_CASE( RectangleExposesIndexedCorners )
220{
221 PCB_SHAPE rect( nullptr, SHAPE_T::RECTANGLE );
222 rect.SetStart( VECTOR2I( 0, 0 ) );
223 rect.SetEnd( VECTOR2I( 1000, 1000 ) );
224
225 std::vector<CONSTRAINT_ANCHOR_POINT> anchors = ConstraintShapeAnchors( &rect );
226
227 BOOST_REQUIRE_EQUAL( anchors.size(), 4 );
228
229 // Canonical TL, TR, BR, BL order with matching vertex ordinals.
230 const VECTOR2I expected[4] = { { 0, 0 }, { 1000, 0 }, { 1000, 1000 }, { 0, 1000 } };
231
232 for( int i = 0; i < 4; ++i )
233 {
234 BOOST_CHECK( anchors[i].anchor == CONSTRAINT_ANCHOR::VERTEX );
235 BOOST_CHECK_EQUAL( anchors[i].index, i );
236 BOOST_CHECK_EQUAL( anchors[i].pos, expected[i] );
237 }
238}
239
240
int index
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
const KIID m_Uuid
Definition eda_item.h:531
void SetPolyPoints(const std::vector< VECTOR2I > &aPoints)
A geometric constraint between board items (issue #2329).
bool HasValue() const
void SetValue(std::optional< double > aValue)
void SetDriving(bool aDriving)
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
std::vector< CONSTRAINT_ANCHOR_POINT > ConstraintShapeAnchors(const PCB_SHAPE *aShape)
Enumerate a shape constraint anchors with positions segment and arc endpoints arc centre circle centr...
@ SEGMENT
Definition eda_shape.h:46
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:47
@ Edge_Cuts
Definition layer_ids.h:108
wxString ConstraintTypeGlyph(PCB_CONSTRAINT_TYPE aType)
Compact glyph for a constraint type (e.g. "//", "=") for on-canvas badges.
wxString ConstraintMemberLabel(BOARD_ITEM *aItem, const CONSTRAINT_MEMBER &aMember, UNITS_PROVIDER *aUnitsProvider)
Label for one constrained item in a list combining the item description with its anchored feature suc...
wxString ConstraintDisplayLabel(const PCB_CONSTRAINT &aConstraint, EDA_UNITS aUnits)
Display label for a constraint in lists and menus.
@ VERTEX
An indexed rectangle corner or polygon outline vertex; pairs with CONSTRAINT_MEMBER::m_index.
@ START
First endpoint of a segment or arc.
@ END
Second endpoint of a segment or arc.
@ CENTER
Center of an arc or circle.
PCB_CONSTRAINT_TYPE
The geometric relationship a PCB_CONSTRAINT enforces between its members.
@ FIXED_LENGTH
A segment has a driving length value.
@ ANGULAR_DIMENSION
An angle between members (driving or reference).
@ ARC_ANGLE
An arc has a driving or reference swept-angle value.
@ PARALLEL
Two segments are parallel.
One participant in a constraint: a referenced board item plus the feature of that item that participa...
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(ValuelessConstraintIsTypeNameOnly)
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST(netlist.find("R_G1 ARM_OUT1 DIE_B R='0.001 / ((SW_STATE)") !=std::string::npos)
VECTOR3I expected(15, 30, 45)
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683