KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_array_options.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
27
28#include <base_units.h>
29#include <trigo.h>
30
31#include <array_options.h>
32
36std::ostream& boost_test_print_type( std::ostream& os, const ARRAY_OPTIONS::TRANSFORM& aObj )
37{
38 os << "TRANSFORM[ " << aObj.m_offset << " r " << aObj.m_rotation.AsDegrees() << "deg"
39 << " ]";
40 return os;
41}
42
43
53
54
62void CheckArrayTransforms( const ARRAY_OPTIONS& aOpts, const VECTOR2I& aPos,
63 const std::vector<ARRAY_OPTIONS::TRANSFORM>& aExp )
64{
65 std::vector<ARRAY_OPTIONS::TRANSFORM> transforms;
66
67 for( int i = 0; i < aOpts.GetArraySize(); ++i )
68 {
69 transforms.push_back( aOpts.GetTransform( i, aPos ) );
70 }
71
72 BOOST_CHECK_EQUAL( transforms.size(), aExp.size() );
73
74 for( unsigned i = 0; i < std::min( transforms.size(), aExp.size() ); ++i )
75 {
76 BOOST_TEST_CONTEXT( "Index " << i )
77 {
78 BOOST_CHECK_PREDICATE( TransformIsClose, ( transforms[i] )( aExp[i] ) );
79 }
80 }
81}
82
83
87BOOST_AUTO_TEST_SUITE( ArrayOptions )
88
89
101
103{
104 std::string m_case_name;
107 std::vector<ARRAY_OPTIONS::TRANSFORM> m_exp_transforms;
108};
109
110
111// clang-format off
112static const std::vector<GRID_ARRAY_TEST_CASE> grid_geom_cases = {
113 {
114 "2x3 rect grid",
115 {
116 2,
117 3,
118 { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 2 ) },
119 { 0, 0 },
120 1,
121 true,
122 false,
123 true,
124 },
125 { 0, 0 },
126 {
127 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
128 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
129 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
130 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
131 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
132 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
133 },
134 },
135 {
136 "2x3 offset grid",
137 {
138 2,
139 3,
140 { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 2 ) },
141 { schIUScale.mmToIU( 0.1 ), schIUScale.mmToIU( 0.2 ) },
142 1,
143 true,
144 false,
145 true,
146 },
147 { 0, 0 },
148 {
149 // add the offsets for each positions
150 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
151 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 0.2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
152 { { schIUScale.mmToIU( 0.1 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
153 { { schIUScale.mmToIU( 2.1 ), schIUScale.mmToIU( 2.2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
154 { { schIUScale.mmToIU( 0.2 ), schIUScale.mmToIU( 4.0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
155 { { schIUScale.mmToIU( 2.2 ), schIUScale.mmToIU( 4.2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
156 },
157 },
158 {
159 "2x3 stagger rows",
160 {
161 2,
162 3,
163 { schIUScale.mmToIU( 3 ), schIUScale.mmToIU( 2 ) },
164 { 0, 0 },
165 3,
166 true,
167 false,
168 true,
169 },
170 { 0, 0 },
171 {
172 // add the offsets for each positions
173 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
174 { { schIUScale.mmToIU( 3 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
175 { { schIUScale.mmToIU( 1 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
176 { { schIUScale.mmToIU( 4 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
177 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
178 { { schIUScale.mmToIU( 5 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
179 },
180 },
181 {
182 "2x3 stagger cols",
183 {
184 2,
185 3,
186 { schIUScale.mmToIU( 3 ), schIUScale.mmToIU( 2 ) },
187 { 0, 0 },
188 2,
189 false,
190 false,
191 true,
192 },
193 { 0, 0 },
194 {
195 // add the offsets for each positions
196 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
197 { { schIUScale.mmToIU( 3 ), schIUScale.mmToIU( 1 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
198 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
199 { { schIUScale.mmToIU( 3 ), schIUScale.mmToIU( 3 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
200 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
201 { { schIUScale.mmToIU( 3 ), schIUScale.mmToIU( 5 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
202 },
203 },
204 {
205 "2x3 rect alternate",
206 {
207 2,
208 3,
209 { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 2 ) },
210 { 0, 0 },
211 1,
212 true,
213 true,
214 true,
215 },
216 { 0, 0 },
217 {
218 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
219 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
220 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
221 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
222 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
223 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
224 },
225 },
226 {
227 "2x3 rect v then h",
228 {
229 2,
230 3,
231 { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 2 ) },
232 { 0, 0 },
233 1,
234 true,
235 false,
236 false,
237 },
238 { 0, 0 },
239 {
240 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
241 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
242 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
243 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
244 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 2 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
245 { { schIUScale.mmToIU( 2 ), schIUScale.mmToIU( 4 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
246 },
247 },
248};
249// clang-format on
250
251
255BOOST_AUTO_TEST_CASE( GridGeometry )
256{
257 for( const auto& c : grid_geom_cases )
258 {
259 BOOST_TEST_CONTEXT( c.m_case_name )
260 {
261 ARRAY_GRID_OPTIONS grid_opts;
262
263 grid_opts.m_nx = c.m_geom.m_nx;
264 grid_opts.m_ny = c.m_geom.m_ny;
265 grid_opts.m_delta = c.m_geom.m_delta;
266 grid_opts.m_offset = c.m_geom.m_offset;
267 grid_opts.m_stagger = c.m_geom.m_stagger;
268 grid_opts.m_stagger_rows = c.m_geom.m_stagger_by_row;
269 grid_opts.m_reverseNumberingAlternate = c.m_geom.m_alternate_numbers;
270 grid_opts.m_horizontalThenVertical = c.m_geom.m_h_then_v;
271
272 CheckArrayTransforms( grid_opts, c.m_item_pos, c.m_exp_transforms );
273 }
274 }
275}
276
277
285
287{
288 std::string m_case_name;
291 std::vector<ARRAY_OPTIONS::TRANSFORM> m_exp_transforms;
292};
293
294
295// clang-format off
296static const std::vector<CIRC_ARRAY_TEST_CASE> circ_geom_cases = {
297 {
298 "Quad, no rotate items",
299 {
300 4,
301 0,
302 { 0, 0 },
303 false,
304 },
305 { schIUScale.mmToIU( 10 ), 0 },
306 {
307 // diamond shape
308 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
309 { { schIUScale.mmToIU( -10 ), schIUScale.mmToIU( -10 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
310 { { schIUScale.mmToIU( -20 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
311 { {schIUScale.mmToIU( -10 ), schIUScale.mmToIU( 10 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
312 },
313 },
314 {
315 "Quad, rotate items",
316 {
317 4,
318 0,
319 { 0, 0 },
320 true,
321 },
322 { schIUScale.mmToIU( 10 ), 0 },
323 {
324 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
325 { { schIUScale.mmToIU( -10 ), schIUScale.mmToIU( -10 ) }, EDA_ANGLE( 90.0, DEGREES_T ) },
326 { { schIUScale.mmToIU( -20 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 180.0, DEGREES_T ) },
327 { {schIUScale.mmToIU( -10 ), schIUScale.mmToIU( 10 ) }, EDA_ANGLE( 270.0, DEGREES_T ) },
328 },
329 },
330 {
331 "Three pts, 90 deg angle",
332 {
333 3,
334 45.0,
335 { 0, 0 },
336 true,
337 },
338 { schIUScale.mmToIU( 10 ), 0 },
339 {
340 { { schIUScale.mmToIU( 0 ), schIUScale.mmToIU( 0 ) }, EDA_ANGLE( 0.0, DEGREES_T ) },
341 // 10 * [ 1-sin(45), sin(45) ]
342 { { schIUScale.mmToIU( -2.9289321881 ), schIUScale.mmToIU( -7.0710678118 ) }, EDA_ANGLE( 45.0, DEGREES_T ) },
343 { { schIUScale.mmToIU( -10 ), schIUScale.mmToIU( -10 ) }, EDA_ANGLE( 90.0, DEGREES_T ) },
344 },
345 },
346};
347// clang-format on
348
352BOOST_AUTO_TEST_CASE( CircularGeometry )
353{
354 for( const auto& c : circ_geom_cases )
355 {
356 BOOST_TEST_CONTEXT( c.m_case_name )
357 {
358 ARRAY_CIRCULAR_OPTIONS grid_opts;
359
360 grid_opts.m_nPts = c.m_geom.n;
361 grid_opts.m_angle = EDA_ANGLE( c.m_geom.angle_offset, DEGREES_T );
362 grid_opts.m_centre = c.m_geom.centre;
363 grid_opts.m_rotateItems = c.m_geom.rotate;
364
365 CheckArrayTransforms( grid_opts, c.m_item_pos, c.m_exp_transforms );
366 }
367 }
368}
369
375void CheckArrayNumbering( const ARRAY_OPTIONS& aOpts, const std::vector<std::string>& aExp )
376{
377 std::vector<std::string> names;
378
379 for( int i = 0; i < aOpts.GetArraySize(); ++i )
380 {
381 names.push_back( aOpts.GetItemNumber( i ).ToStdString() );
382 }
383
384 BOOST_CHECK_EQUAL_COLLECTIONS( names.begin(), names.end(), aExp.begin(), aExp.end() );
385}
386
387
399
400
402{
403 std::string m_case_name;
405 std::vector<std::string> m_exp_names;
406};
407
408
409// clang-format off
410static const std::vector<GRID_ARRAY_NAMING_CASE> grid_name_cases = {
411 {
412 "Linear grid",
413 {
416 "1",
417 "2",
418 false,
419 false, // doesn't matter
420 2,
421 3,
422 },
423 { "1", "2", "3", "4", "5", "6" },
424 },
425 {
426 // Tests a 2d grid
427 "2D grid A1",
428 {
431 "A",
432 "1",
433 true,
434 true,
435 2,
436 3,
437 },
438 { "A1", "B1", "A2", "B2", "A3", "B3" },
439 },
440 {
441 // Tests a 2d grid
442 "2D grid 11",
443 {
446 "1",
447 "1",
448 true,
449 false,
450 2,
451 3,
452 },
453 // moving down the "long axis" first
454 // so the first coordinate has a range of 1-3, the second 1-2
455 { "11", "21", "31", "12", "22", "32" },
456 },
457 {
458 // Tests a 2d grid, with different types and offsets (and alphabet wrap)
459 "2D grid offsets",
460 {
463 "5",
464 "Z",
465 true,
466 true,
467 2,
468 3,
469 },
470 { "5Z", "6Z", "5AA", "6AA", "5AB", "6AB" },
471 },
472};
473// clang-format on
474
475
480{
481 for( const auto& c : grid_name_cases )
482 {
483 BOOST_TEST_CONTEXT( c.m_case_name )
484 {
485 ARRAY_GRID_OPTIONS grid_opts;
486
487 grid_opts.m_nx = c.m_prms.m_nx;
488 grid_opts.m_ny = c.m_prms.m_ny;
489
490 grid_opts.m_horizontalThenVertical = c.m_prms.m_h_then_v;
491
492 grid_opts.m_pri_axis.SetAxisType( c.m_prms.m_pri_type );
493 grid_opts.m_sec_axis.SetAxisType( c.m_prms.m_sec_type );
494
495 grid_opts.m_pri_axis.SetOffset( c.m_prms.m_start_at_x );
496 grid_opts.m_sec_axis.SetOffset( c.m_prms.m_start_at_y );
497
498 grid_opts.m_2dArrayNumbering = c.m_prms.m_2d_numbering;
499
500 // other grid settings (geom) can be defaulted, as they don't affect numbering
501
502 CheckArrayNumbering( grid_opts, c.m_exp_names );
503 }
504 }
505}
506
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
bool SetOffset(const wxString &aOffsetName)
Set the axis start (as a string, which should decode to a valid index in the alphabet),...
void SetAxisType(NUMBERING_TYPE aType)
Set the axis numbering type.
@ NUMBERING_NUMERIC
Arabic numerals: 0,1,2,3,4,5,6,7,8,9,10,11...
Definition array_axis.h:40
@ NUMBERING_ALPHA_FULL
Full 26-character alphabet.
Definition array_axis.h:50
Options that govern the setup of an "array" of multiple item.
virtual int GetArraySize() const =0
The number of points in this array.
virtual wxString GetItemNumber(int n) const =0
Get the position number (name) for the n'th array point.
virtual TRANSFORM GetTransform(int aN, const VECTOR2I &aPos) const =0
Get the transform of the n-th point in the array.
double AsDegrees() const
Definition eda_angle.h:116
@ DEGREES_T
Definition eda_angle.h:31
bool IsWithin(T aValue, T aNominal, T aError)
Check if a value is within a tolerance of a nominal value.
Definition numeric.h:57
bool IsVecWithinTol(const VEC &aVec, const VEC &aExp, typename VEC::coord_type aTol)
Check that both x and y of a vector are within expected error.
Definition geometry.h:51
long m_nPts
number of point in the array
EDA_ANGLE m_angle
angle between points, or 0 for each point separated by this value (decideg)
Transform applied to an object by this array.
std::vector< ARRAY_OPTIONS::TRANSFORM > m_exp_transforms
CIRC_ARRAY_GEOM_PARAMS m_geom
Declare the test suite.
std::vector< std::string > m_exp_names
GRID_ARRAY_NAMING_PARAMS m_prms
ARRAY_AXIS::NUMBERING_TYPE m_pri_type
ARRAY_AXIS::NUMBERING_TYPE m_sec_type
GRID_ARRAY_GEOM_PARAMS m_geom
std::vector< ARRAY_OPTIONS::TRANSFORM > m_exp_transforms
void CheckArrayTransforms(const ARRAY_OPTIONS &aOpts, const VECTOR2I &aPos, const std::vector< ARRAY_OPTIONS::TRANSFORM > &aExp)
Generate all array transforms for an array descriptor and compare against a list of expected transfor...
static const std::vector< CIRC_ARRAY_TEST_CASE > circ_geom_cases
static const std::vector< GRID_ARRAY_TEST_CASE > grid_geom_cases
BOOST_AUTO_TEST_CASE(GridGeometry)
Test of grid array geometry.
std::ostream & boost_test_print_type(std::ostream &os, const ARRAY_OPTIONS::TRANSFORM &aObj)
Define a stream function for logging this type.
void CheckArrayNumbering(const ARRAY_OPTIONS &aOpts, const std::vector< std::string > &aExp)
Generate all array names and check against expected.
bool TransformIsClose(const ARRAY_OPTIONS::TRANSFORM &aL, const ARRAY_OPTIONS::TRANSFORM &aR)
Predicate to see if a ARRAY_OPTIONS::TRANSFORM is equal or nearly equal.
static const std::vector< GRID_ARRAY_NAMING_CASE > grid_name_cases
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_PREDICATE(ArePolylineEndPointsNearCircle,(chain)(c.m_geom.m_center_point)(radius)(accuracy+epsilon))
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683