KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_constraint_authoring.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
20#include <map>
21#include <memory>
22#include <vector>
23
25#include <tool/tool_manager.h>
27
28#include <board.h>
29#include <board_commit.h>
30#include <pcb_shape.h>
31#include <project.h>
35
37
38using namespace KI_TEST;
39
40
41BOOST_AUTO_TEST_SUITE( ConstraintSolverAuthoring )
42
43
44BOOST_AUTO_TEST_CASE( BuildParallelFromTwoSegments )
45{
46 BOARD board;
47 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
48 PCB_SHAPE* b = addSegment( board, { 0, 5 * MM }, { 10 * MM, 6 * MM } );
49
50 std::unique_ptr<PCB_CONSTRAINT> c =
52
53 BOOST_REQUIRE( c );
54 BOOST_REQUIRE_EQUAL( c->GetMembers().size(), 2 );
55 BOOST_CHECK( c->GetMembers()[0].m_item == a->m_Uuid );
56 BOOST_CHECK( c->GetMembers()[0].m_anchor == CONSTRAINT_ANCHOR::WHOLE );
57 BOOST_CHECK( c->GetMembers()[1].m_item == b->m_Uuid );
58}
59
60
61BOOST_AUTO_TEST_CASE( BuildFixedLengthMeasuresGeometry )
62{
63 BOARD board;
64 PCB_SHAPE* seg = addSegment( board, { 0, 0 }, { 7 * MM, 0 } );
65
66 std::unique_ptr<PCB_CONSTRAINT> c =
68
69 BOOST_REQUIRE( c );
70 BOOST_REQUIRE( c->HasValue() );
71 BOOST_CHECK_CLOSE( *c->GetValue(), 7.0 * MM, 1e-6 );
72}
73
74
75BOOST_AUTO_TEST_CASE( BuildAngularMeasuresAngle )
76{
77 BOARD board;
78 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } ); // along +x
79 PCB_SHAPE* b = addSegment( board, { 0, 0 }, { 0, 10 * MM } ); // along +y (90 deg)
80
81 std::unique_ptr<PCB_CONSTRAINT> c =
83
84 BOOST_REQUIRE( c );
85 BOOST_REQUIRE_EQUAL( c->GetMembers().size(), 2 );
86 BOOST_REQUIRE( c->HasValue() );
87 BOOST_CHECK_CLOSE( *c->GetValue(), 90.0, 1e-6 ); // degrees
88}
89
90
91BOOST_AUTO_TEST_CASE( BuildAngularIsUndirectedCorner )
92{
93 BOARD board;
94 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } ); // ray +x
95 PCB_SHAPE* b = addSegment( board, { 0, 0 }, { 0, -10 * MM } ); // ray -y
96
97 std::unique_ptr<PCB_CONSTRAINT> c =
99
100 BOOST_REQUIRE( c );
101 BOOST_REQUIRE( c->HasValue() );
102
103 // The corner is undirected: the same 90 degree opening regardless of segment orientation.
104 BOOST_CHECK_CLOSE( *c->GetValue(), 90.0, 1e-3 );
105}
106
107
108// A 120 degree corner authored in all four endpoint permutations and both member orders stores 120,
109// never folded to 60 (Seth: obtuse outline corners are preserved).
110BOOST_AUTO_TEST_CASE( BuildAngularObtuseCornerInvariant )
111{
112 const VECTOR2I vertex{ 0, 0 };
113 const VECTOR2I aFar{ 10 * MM, 0 }; // ray at 0 deg
114 const VECTOR2I bFar{ -5 * MM, 8660254 }; // ray at 120 deg (10 mm at 120)
115
116 for( bool swapA : { false, true } )
117 {
118 for( bool swapB : { false, true } )
119 {
120 for( bool swapOrder : { false, true } )
121 {
122 BOARD board;
123 PCB_SHAPE* a = swapA ? addSegment( board, aFar, vertex )
124 : addSegment( board, vertex, aFar );
125 PCB_SHAPE* b = swapB ? addSegment( board, bFar, vertex )
126 : addSegment( board, vertex, bFar );
127
128 std::vector<BOARD_ITEM*> items = swapOrder ? std::vector<BOARD_ITEM*>{ b, a }
129 : std::vector<BOARD_ITEM*>{ a, b };
130
131 std::unique_ptr<PCB_CONSTRAINT> c = BuildConstraintFromItems(
133
134 BOOST_REQUIRE( c );
135 BOOST_REQUIRE( c->HasValue() );
136 BOOST_CHECK_CLOSE( *c->GetValue(), 120.0, 0.05 );
137 }
138 }
139 }
140}
141
142
143BOOST_AUTO_TEST_CASE( BuildAngularDomainEndpoints )
144{
145 {
146 // Both rays leave the vertex the same way: a 0 degree corner.
147 BOARD board;
148 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
149 PCB_SHAPE* b = addSegment( board, { 0, 0 }, { 20 * MM, 0 } );
151 BOOST_REQUIRE( c && c->HasValue() );
152 BOOST_CHECK_SMALL( *c->GetValue(), 1e-3 );
153 }
154 {
155 // Rays leave the vertex in opposite directions: a straight 180 degree corner.
156 BOARD board;
157 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { -10 * MM, 0 } );
158 PCB_SHAPE* b = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
160 BOOST_REQUIRE( c && c->HasValue() );
161 BOOST_CHECK_CLOSE( *c->GetValue(), 180.0, 1e-3 );
162 }
163}
164
165
166// Two segments that do not touch still get a well-defined corner from nearest-endpoint pairing,
167// with no dependence on SEG::IntersectLines.
168BOOST_AUTO_TEST_CASE( BuildAngularDisconnectedLines )
169{
170 BOARD board;
171 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } ); // ray +x
172 PCB_SHAPE* b = addSegment( board, { 0, 2 * MM }, { 0, 12 * MM } ); // ray +y, 2 mm gap
173
174 std::unique_ptr<PCB_CONSTRAINT> c =
176
177 BOOST_REQUIRE( c && c->HasValue() );
178
179 // SEG::Angle uses each segment's true direction, so the gap does not skew the measurement.
180 BOOST_CHECK_CLOSE( *c->GetValue(), 90.0, 1e-3 );
181}
182
183
184BOOST_AUTO_TEST_CASE( WrongSelectionYieldsNoConstraint )
185{
186 BOARD board;
187 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
188
189 // Parallel needs two segments.
190 BOOST_CHECK( !BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::PARALLEL, { a } ) );
191
192 // Concentric needs circles, not a segment.
193 BOOST_CHECK( !BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::CONCENTRIC, { a, a } ) );
194
195 // Coincident needs point anchors, not whole shapes.
196 BOOST_CHECK( !BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::COINCIDENT, { a, a } ) );
197}
198
199
200BOOST_AUTO_TEST_CASE( AngularRejectsZeroLengthSegment )
201{
202 BOARD board;
203 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
204 PCB_SHAPE* zero = addSegment( board, { 5 * MM, 5 * MM }, { 5 * MM, 5 * MM } ); // no direction
205
207 { a, zero } ) );
208}
209
210
211// The nearest-anchor picker snaps a click to the closest shape endpoint/center.
212BOOST_AUTO_TEST_CASE( NearestAnchorSnapsToEndpoint )
213{
214 BOARD board;
215 PCB_SHAPE* seg = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
216
217 // Close to the end (10mm,0): snaps to that segment's END.
218 auto hit = NearestConstraintAnchor( &board, { 10 * MM + 100, 200 }, 1 * MM );
219 BOOST_REQUIRE( hit.has_value() );
220 BOOST_CHECK( hit->m_item == seg->m_Uuid );
221 BOOST_CHECK( hit->m_anchor == CONSTRAINT_ANCHOR::END );
222
223 // Far from any anchor: nothing within tolerance.
224 BOOST_CHECK( !NearestConstraintAnchor( &board, { 5 * MM, 5 * MM }, 1 * MM ).has_value() );
225}
226
227
228// Excluding a handle skips only that shape and anchor coincident endpoint elsewhere stays reachable
229BOOST_AUTO_TEST_CASE( NearestAnchorExcludesPickedHandleNotCoincident )
230{
231 BOARD board;
232 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
233 PCB_SHAPE* b = addSegment( board, { 10 * MM, 0 }, { 20 * MM, 0 } );
234
235 const VECTOR2I shared{ 10 * MM, 0 }; // a's END and b's START coincide here
236
237 std::optional<CONSTRAINT_MEMBER> first = NearestConstraintAnchor( &board, shared, 1 * MM );
238 BOOST_REQUIRE( first.has_value() );
239
240 // Exclude first handle still finds coincident endpoint as distinct member on b
241 std::optional<CONSTRAINT_MEMBER> second =
242 NearestConstraintAnchor( &board, shared, 1 * MM, { *first } );
243 BOOST_REQUIRE( second.has_value() );
244 BOOST_CHECK( *second != *first );
245 BOOST_CHECK( second->m_item != first->m_item );
246 BOOST_CHECK( ConstraintAnchorPosition( &board, *first )
247 == ConstraintAnchorPosition( &board, *second ) );
248
249 // Two handles are shape a and shape b own endpoints at the shared point
250 BOOST_CHECK( ( first->m_item == a->m_Uuid && second->m_item == b->m_Uuid )
251 || ( first->m_item == b->m_Uuid && second->m_item == a->m_Uuid ) );
252
253 // Both handles excluded nothing else within tolerance
254 BOOST_CHECK( !NearestConstraintAnchor( &board, shared, 1 * MM, { *first, *second } ).has_value() );
255}
256
257
258// Applying an authored constraint through a commit is a single undoable step.
259BOOST_AUTO_TEST_CASE( ApplyIsOneUndoStep )
260{
261 BOARD board;
262 TOOL_MANAGER mgr;
264 mgr.SetEnvironment( &board, nullptr, nullptr, nullptr, nullptr );
265 mgr.RegisterTool( tool );
266
267 PCB_SHAPE* a = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
268 PCB_SHAPE* b = addSegment( board, { 0, 5 * MM }, { 10 * MM, 6 * MM } );
269
270 std::unique_ptr<PCB_CONSTRAINT> c =
272 BOOST_REQUIRE( c );
273
274 BOARD_COMMIT commit( tool );
275 commit.Add( c.release() );
276 commit.Push( wxT( "add constraint" ) );
277
278 BOOST_CHECK_EQUAL( board.Constraints().size(), 1 );
279
280 // Authoring then reverting (here a subsequent removal) returns to no constraints in one step.
281 PCB_CONSTRAINT* added = board.Constraints().front();
282 BOARD_COMMIT removeCommit( tool );
283 removeCommit.Remove( added );
284 removeCommit.Push( wxT( "remove constraint" ) );
285
286 BOOST_CHECK( board.Constraints().empty() );
287}
288
289
290// The radial constraints accept arcs, and concentric also accepts ellipses, matching the solver.
291BOOST_AUTO_TEST_CASE( BuildRadialFromArcsAndEllipses )
292{
293 BOARD board;
294 PCB_SHAPE* circle = addCircle( board, { 0, 0 }, 5 * MM );
295 PCB_SHAPE* arc = addArc( board, { 10 * MM, 0 }, { 12 * MM, 2 * MM }, { 14 * MM, 0 } );
296 PCB_SHAPE* ellipse = addEllipse( board, { 30 * MM, 0 }, 8 * MM, 4 * MM, EDA_ANGLE( 0.0, DEGREES_T ) );
297
298 // Fixed radius and equal radius work on arcs.
299 BOOST_CHECK( BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::FIXED_RADIUS, { arc } ) );
300 BOOST_CHECK( BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::EQUAL_RADIUS, { circle, arc } ) );
301
302 // Concentric additionally works on ellipses.
303 BOOST_CHECK( BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::CONCENTRIC, { circle, ellipse } ) );
304 BOOST_CHECK( BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::CONCENTRIC, { arc, ellipse } ) );
305
306 // Equal radius still rejects an ellipse (no single radius).
307 BOOST_CHECK( !BuildConstraintFromItems( &board, PCB_CONSTRAINT_TYPE::EQUAL_RADIUS, { circle, ellipse } ) );
308}
309
310
311// Nothing remembered dialog opens on measured geometry
312BOOST_AUTO_TEST_CASE( InitialValueDefaultsToMeasured )
313{
314 std::map<PCB_CONSTRAINT_TYPE, double> remembered;
315
316 BOOST_CHECK_CLOSE( InitialConstraintValue( PCB_CONSTRAINT_TYPE::FIXED_LENGTH, 7.0 * MM, remembered ),
317 7.0 * MM, 1e-6 );
318 BOOST_CHECK_CLOSE( InitialConstraintValue( PCB_CONSTRAINT_TYPE::ARC_ANGLE, 90.0, remembered ), 90.0,
319 1e-6 );
320}
321
322
323// Once set remembered value overrides measurement
324BOOST_AUTO_TEST_CASE( InitialValueRemembersLastUsed )
325{
326 std::map<PCB_CONSTRAINT_TYPE, double> remembered;
327 remembered[PCB_CONSTRAINT_TYPE::FIXED_LENGTH] = 5.0 * MM;
328
329 BOOST_CHECK_CLOSE( InitialConstraintValue( PCB_CONSTRAINT_TYPE::FIXED_LENGTH, 7.0 * MM, remembered ),
330 5.0 * MM, 1e-6 );
331}
332
333
334// Keyed by type length value never bleeds into angle default
335BOOST_AUTO_TEST_CASE( InitialValueDoesNotMixTypes )
336{
337 std::map<PCB_CONSTRAINT_TYPE, double> remembered;
338 remembered[PCB_CONSTRAINT_TYPE::FIXED_LENGTH] = 5.0 * MM;
339
340 // ARC_ANGLE unremembered opens on measured 90 degrees
341 BOOST_CHECK_CLOSE( InitialConstraintValue( PCB_CONSTRAINT_TYPE::ARC_ANGLE, 90.0, remembered ), 90.0,
342 1e-6 );
343
344 // Recording an angle leaves the earlier length value untouched.
345 remembered[PCB_CONSTRAINT_TYPE::ARC_ANGLE] = 60.0;
346
347 BOOST_CHECK_CLOSE( InitialConstraintValue( PCB_CONSTRAINT_TYPE::FIXED_LENGTH, 7.0 * MM, remembered ),
348 5.0 * MM, 1e-6 );
349 BOOST_CHECK_CLOSE( InitialConstraintValue( PCB_CONSTRAINT_TYPE::ARC_ANGLE, 90.0, remembered ), 60.0,
350 1e-6 );
351}
352
353
354// Hiding a layer takes its shapes out of the picker even when one lies nearer the click
355BOOST_AUTO_TEST_CASE( OutlinePickerSkipsHiddenLayers )
356{
357 SETTINGS_MANAGER settingsManager;
358 settingsManager.LoadProject( "" );
359
360 BOARD board;
361 board.SetProject( &settingsManager.Prj() );
362
363 PCB_SHAPE* shown = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
364 shown->SetLayer( F_SilkS );
365
366 PCB_SHAPE* hidden = addSegment( board, { 0, 3 * MM }, { 10 * MM, 3 * MM } );
367 hidden->SetLayer( B_SilkS );
368
369 LSET layers = LSET::AllLayersMask();
370 board.SetVisibleLayers( layers );
371
372 const VECTOR2I probe{ 5 * MM, 2 * MM };
373 const double tol = 3 * MM;
374
376 BOOST_REQUIRE( NearestOutlineShape( &board, probe, tol, false ) == hidden->m_Uuid );
377
378 layers.set( B_SilkS, false );
379 board.SetVisibleLayers( layers );
381
382 BOOST_CHECK( NearestOutlineShape( &board, probe, tol, false ) == shown->m_Uuid );
383}
384
385
386BOOST_AUTO_TEST_CASE( AnchorPickerSkipsHiddenLayers )
387{
388 SETTINGS_MANAGER settingsManager;
389 settingsManager.LoadProject( "" );
390
391 BOARD board;
392 board.SetProject( &settingsManager.Prj() );
393
394 PCB_SHAPE* shown = addSegment( board, { 0, 0 }, { 10 * MM, 0 } );
395 shown->SetLayer( F_SilkS );
396
397 PCB_SHAPE* hidden = addSegment( board, { 0, 3 * MM }, { 10 * MM, 3 * MM } );
398 hidden->SetLayer( B_SilkS );
399
400 LSET layers = LSET::AllLayersMask();
401 board.SetVisibleLayers( layers );
402
403 const VECTOR2I probe{ 0, 2 * MM };
404 const double tol = 3 * MM;
405
406 std::optional<CONSTRAINT_MEMBER> first = NearestConstraintAnchor( &board, probe, tol );
407 BOOST_REQUIRE( first.has_value() && first->m_item == hidden->m_Uuid );
408
409 layers.set( B_SilkS, false );
410 board.SetVisibleLayers( layers );
411
412 std::optional<CONSTRAINT_MEMBER> picked = NearestConstraintAnchor( &board, probe, tol );
413 BOOST_REQUIRE( picked.has_value() );
414 BOOST_CHECK( picked->m_item == shown->m_Uuid );
415 BOOST_CHECK( picked->m_anchor == CONSTRAINT_ANCHOR::START );
416}
417
418
BASE_SET & set(size_t pos)
Definition base_set.h:126
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
void SetVisibleLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition board.cpp:1216
const CONSTRAINTS & Constraints() const
Geometric constraints (#2329) owned by this board.
Definition board.h:513
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
Definition board.cpp:374
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition board.cpp:1189
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:86
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:74
const KIID m_Uuid
Definition eda_item.h:597
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllLayersMask()
Definition lset.cpp:637
A geometric constraint between board items (issue #2329).
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
Master controller class:
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
double InitialConstraintValue(PCB_CONSTRAINT_TYPE aType, double aMeasured, const std::map< PCB_CONSTRAINT_TYPE, double > &aRemembered)
Value a freshly authored constraint dialog should open with.
std::optional< KIID > NearestOutlineShape(BOARD *aBoard, const VECTOR2I &aPos, double aMaxDist, bool aAllowCircle, PCB_LAYER_ID aLayer)
The shape whose outline is nearest aPos within aMaxDist.
std::unique_ptr< PCB_CONSTRAINT > BuildConstraintFromItems(BOARD_ITEM *aParent, PCB_CONSTRAINT_TYPE aType, const std::vector< BOARD_ITEM * > &aItems)
Build a constraint of aType from a set of selected board items, or nullptr if the selection does not ...
std::optional< CONSTRAINT_MEMBER > NearestConstraintAnchor(BOARD *aBoard, const VECTOR2I &aPos, double aMaxDist, const std::vector< CONSTRAINT_MEMBER > &aExclude, PCB_LAYER_ID aLayer)
Find the constrainable-item anchor (a shape's segment/arc endpoint or centre, or a dimension's featur...
std::optional< VECTOR2I > ConstraintAnchorPosition(BOARD *aBoard, const CONSTRAINT_MEMBER &aMember)
Current location of a constraint member's anchor (its shape's START/END/CENTER, or a dimension's feat...
@ DEGREES_T
Definition eda_angle.h:31
@ F_SilkS
Definition layer_ids.h:96
@ B_SilkS
Definition layer_ids.h:97
PCB_SHAPE * addSegment(BOARD &aBoard, const VECTOR2I &aStart, const VECTOR2I &aEnd)
PCB_SHAPE * addArc(BOARD &aBoard, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
PCB_SHAPE * addCircle(BOARD &aBoard, const VECTOR2I &aCenter, int aRadius)
PCB_SHAPE * addEllipse(BOARD &aBoard, const VECTOR2I &aCenter, int aMajor, int aMinor, const EDA_ANGLE &aRotation)
constexpr int MM
@ WHOLE
The item as a whole (a segment as a line, a circle).
@ START
First endpoint of a segment or arc.
@ END
Second endpoint of a segment or arc.
@ CONCENTRIC
Two arcs/circles share a center.
@ COINCIDENT
Two points are made to coincide.
@ FIXED_RADIUS
An arc/circle has a driving radius value.
@ EQUAL_RADIUS
Two arcs/circles have equal radius.
@ 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.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(BuildParallelFromTwoSegments)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
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