KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_transform_trs.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
21
23
24
25BOOST_AUTO_TEST_SUITE( TransformTrs )
26
27
28// 1 unit slack for float-to-int rounding.
29static constexpr int IUNIT_TOL = 1;
30
31
32static void CHECK_VEC_NEAR( const VECTOR2I& aActual, const VECTOR2I& aExpected, int aTol )
33{
34 BOOST_CHECK_MESSAGE( std::abs( aActual.x - aExpected.x ) <= aTol
35 && std::abs( aActual.y - aExpected.y ) <= aTol,
36 "actual ( " << aActual.x << ", " << aActual.y << " ) "
37 "expected ( " << aExpected.x << ", " << aExpected.y << " ) "
38 "tol " << aTol );
39}
40
41
42BOOST_AUTO_TEST_CASE( IdentityApply )
43{
45 BOOST_CHECK( t.IsIdentity() );
46 BOOST_CHECK( t.IsUniformScale() );
47
48 VECTOR2I p( 12345, -6789 );
49 CHECK_VEC_NEAR( t.Apply( p ), p, 0 );
50 CHECK_VEC_NEAR( t.InverseApply( p ), p, 0 );
51}
52
53
54BOOST_AUTO_TEST_CASE( TranslateOnly )
55{
56 TRANSFORM_TRS t( VECTOR2I( 100, 200 ), ANGLE_0, 1.0, 1.0 );
57 BOOST_CHECK( !t.IsIdentity() );
58
59 CHECK_VEC_NEAR( t.Apply( VECTOR2I( 0, 0 ) ), VECTOR2I( 100, 200 ), 0 );
60 CHECK_VEC_NEAR( t.Apply( VECTOR2I( 50, 50 ) ), VECTOR2I( 150, 250 ), 0 );
61
62 CHECK_VEC_NEAR( t.InverseApply( VECTOR2I( 100, 200 ) ), VECTOR2I( 0, 0 ), 0 );
63 CHECK_VEC_NEAR( t.InverseApply( VECTOR2I( 150, 250 ) ), VECTOR2I( 50, 50 ), 0 );
64}
65
66
68{
69 // Expected values match trigo.h::RotatePoint conventions.
70 struct CASE { EDA_ANGLE angle; VECTOR2I p; VECTOR2I expected; };
71
72 const std::vector<CASE> cases = {
73 { ANGLE_0, VECTOR2I( 100, 0 ), VECTOR2I( 100, 0 ) },
74 { ANGLE_90, VECTOR2I( 100, 0 ), VECTOR2I( 0, -100 ) },
75 { ANGLE_180, VECTOR2I( 100, 0 ), VECTOR2I( -100, 0 ) },
76 { ANGLE_270, VECTOR2I( 100, 0 ), VECTOR2I( 0, 100 ) },
77 };
78
79 for( const CASE& c : cases )
80 {
81 TRANSFORM_TRS t( VECTOR2I( 0, 0 ), c.angle, 1.0, 1.0 );
82 CHECK_VEC_NEAR( t.Apply( c.p ), c.expected, IUNIT_TOL );
83 CHECK_VEC_NEAR( t.InverseApply( c.expected ), c.p, IUNIT_TOL );
84 }
85}
86
87
89{
90 TRANSFORM_TRS uniform( VECTOR2I( 0, 0 ), ANGLE_0, 2.0, 2.0 );
91 BOOST_CHECK( uniform.IsUniformScale() );
92 CHECK_VEC_NEAR( uniform.Apply( VECTOR2I( 100, 50 ) ), VECTOR2I( 200, 100 ), 0 );
93 CHECK_VEC_NEAR( uniform.InverseApply( VECTOR2I( 200, 100 ) ), VECTOR2I( 100, 50 ), 0 );
94
95 TRANSFORM_TRS half( VECTOR2I( 0, 0 ), ANGLE_0, 0.5, 0.5 );
96 CHECK_VEC_NEAR( half.Apply( VECTOR2I( 100, 50 ) ), VECTOR2I( 50, 25 ), 0 );
97
98 TRANSFORM_TRS nonuniform( VECTOR2I( 0, 0 ), ANGLE_0, 2.0, 0.5 );
99 BOOST_CHECK( !nonuniform.IsUniformScale() );
100 CHECK_VEC_NEAR( nonuniform.Apply( VECTOR2I( 100, 100 ) ), VECTOR2I( 200, 50 ), 0 );
101 CHECK_VEC_NEAR( nonuniform.InverseApply( VECTOR2I( 200, 50 ) ), VECTOR2I( 100, 100 ), 0 );
102}
103
104
105BOOST_AUTO_TEST_CASE( CompoundSrtOracle )
106{
107 // p (10, 0): scale 2x to (20, 0); rotate 90 to (0, -20); translate to (1000, 480).
108 TRANSFORM_TRS t( VECTOR2I( 1000, 500 ), ANGLE_90, 2.0, 2.0 );
109
110 CHECK_VEC_NEAR( t.Apply( VECTOR2I( 10, 0 ) ), VECTOR2I( 1000, 480 ), IUNIT_TOL );
111 CHECK_VEC_NEAR( t.InverseApply( t.Apply( VECTOR2I( 10, 0 ) ) ), VECTOR2I( 10, 0 ), IUNIT_TOL );
112}
113
114
115BOOST_AUTO_TEST_CASE( InverseApplyRoundTrip )
116{
117 const std::vector<TRANSFORM_TRS> ts = {
118 TRANSFORM_TRS( VECTOR2I( 100, 200 ), EDA_ANGLE( 37.5, DEGREES_T ), 1.0, 1.0 ),
119 TRANSFORM_TRS( VECTOR2I( -50, 75 ), EDA_ANGLE( 123.4, DEGREES_T ), 1.5, 1.5 ),
120 TRANSFORM_TRS( VECTOR2I( 0, 0 ), EDA_ANGLE( 60.0, DEGREES_T ), 2.0, 0.5 ),
121 TRANSFORM_TRS( VECTOR2I( 1234, -567 ), EDA_ANGLE( 89.0, DEGREES_T ), 0.75, 1.25 ),
122 };
123
124 const std::vector<VECTOR2I> probes = {
125 { 0, 0 }, { 100, 0 }, { 0, 100 }, { 250, -125 }, { -300, 400 },
126 };
127
128 for( const TRANSFORM_TRS& t : ts )
129 {
130 for( const VECTOR2I& p : probes )
131 {
132 VECTOR2I round = t.InverseApply( t.Apply( p ) );
133 CHECK_VEC_NEAR( round, p, IUNIT_TOL );
134 }
135 }
136}
137
138
139BOOST_AUTO_TEST_CASE( RescaleAroundFixedPointInvariant )
140{
141 TRANSFORM_TRS t( VECTOR2I( 1000, 500 ), ANGLE_0, 1.0, 1.0 );
142 const VECTOR2I libPoint( 25, 25 );
143 const VECTOR2I fixedPoint = t.Apply( libPoint );
144
145 TRANSFORM_TRS rescaled = t.RescaleAround( fixedPoint, 3.0, 3.0 );
146
147 CHECK_VEC_NEAR( rescaled.Apply( libPoint ), fixedPoint, IUNIT_TOL );
148}
149
150
151BOOST_AUTO_TEST_CASE( RescaleAroundComposesScale )
152{
153 TRANSFORM_TRS t( VECTOR2I( 1000, 500 ), ANGLE_0, 1.5, 1.5 );
154
155 TRANSFORM_TRS rescaled = t.RescaleAround( VECTOR2I( 0, 0 ), 2.0, 2.0 );
156
157 BOOST_CHECK_CLOSE( rescaled.GetScaleX(), 3.0, 1e-6 );
158 BOOST_CHECK_CLOSE( rescaled.GetScaleY(), 3.0, 1e-6 );
159}
160
161
162BOOST_AUTO_TEST_CASE( RescaleAroundAnchorFollowsCenter )
163{
164 // 2x rescale around (0, 0): anchor (1000, 500) goes to (2000, 1000).
165 TRANSFORM_TRS t( VECTOR2I( 1000, 500 ), ANGLE_0, 1.0, 1.0 );
166 TRANSFORM_TRS r = t.RescaleAround( VECTOR2I( 0, 0 ), 2.0, 2.0 );
167
168 CHECK_VEC_NEAR( r.GetTranslate(), VECTOR2I( 2000, 1000 ), 0 );
169}
170
171
172BOOST_AUTO_TEST_CASE( RescaleAroundRotatedNonUniformScalesLocalAxes )
173{
174 // The scale factors act in the footprint's own frame, so a non-uniform
175 // rescale must apply directly (Sx *= aSx, Sy *= aSy) and never swap axes
176 // with the rotation.
177 TRANSFORM_TRS t( VECTOR2I( 1000, 500 ), EDA_ANGLE( 90.0, DEGREES_T ), 1.0, 1.0 );
178
179 TRANSFORM_TRS r = t.RescaleAround( VECTOR2I( 0, 0 ), 2.0, 3.0 );
180
181 BOOST_CHECK_CLOSE( r.GetScaleX(), 2.0, 1e-6 );
182 BOOST_CHECK_CLOSE( r.GetScaleY(), 3.0, 1e-6 );
183}
184
185
186BOOST_AUTO_TEST_CASE( RescaleAroundRotatedFixedPointInvariant )
187{
188 // The fixed point stays put even with rotation and a non-uniform scale.
189 TRANSFORM_TRS t( VECTOR2I( 1000, 500 ), EDA_ANGLE( 90.0, DEGREES_T ), 1.0, 1.0 );
190 const VECTOR2I libPoint( 25, 40 );
191 const VECTOR2I fixedPoint = t.Apply( libPoint );
192
193 TRANSFORM_TRS r = t.RescaleAround( fixedPoint, 2.0, 3.0 );
194
195 CHECK_VEC_NEAR( r.Apply( libPoint ), fixedPoint, IUNIT_TOL );
196}
197
198
199BOOST_AUTO_TEST_CASE( EqualityAndInequality )
200{
201 TRANSFORM_TRS a( VECTOR2I( 100, 200 ), ANGLE_45, 1.5, 0.5 );
202 TRANSFORM_TRS b( VECTOR2I( 100, 200 ), ANGLE_45, 1.5, 0.5 );
203 TRANSFORM_TRS c( VECTOR2I( 100, 200 ), ANGLE_45, 1.5, 0.6 );
204
205 BOOST_CHECK( a == b );
206 BOOST_CHECK( !( a == c ) );
207 BOOST_CHECK( a != c );
208}
209
210
211BOOST_AUTO_TEST_CASE( ApplyLinearScaleArithmeticMean )
212{
213 TRANSFORM_TRS t( VECTOR2I( 0, 0 ), ANGLE_0, 2.0, 1.0 );
214 BOOST_CHECK_CLOSE( t.ApplyLinearScale( 100.0 ), 150.0, 1e-9 );
215
216 TRANSFORM_TRS uniform( VECTOR2I( 0, 0 ), ANGLE_0, 0.5, 0.5 );
217 BOOST_CHECK_CLOSE( uniform.ApplyLinearScale( 100.0 ), 50.0, 1e-9 );
218}
219
220
VECTOR2I InverseApply(const VECTOR2I &aPoint) const
bool IsUniformScale() const
double GetScaleX() const
VECTOR2I Apply(const VECTOR2I &aPoint) const
double GetScaleY() const
double ApplyLinearScale(double aLength) const
TRANSFORM_TRS RescaleAround(const VECTOR2I &aFixedPoint, double aSx, double aSy) const
bool IsIdentity() const
const VECTOR2I & GetTranslate() const
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
@ DEGREES_T
Definition eda_angle.h:30
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:449
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:453
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:452
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
static void CHECK_VEC_NEAR(const VECTOR2I &aActual, const VECTOR2I &aExpected, int aTol)
BOOST_AUTO_TEST_CASE(IdentityApply)
static constexpr int IUNIT_TOL
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708