KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_constraint_arc_angle.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
25
27
28#include <vector>
29
30#include <board.h>
31#include <pcb_shape.h>
32
36
38
39using namespace KI_TEST;
40
41namespace
42{
43PCB_SHAPE* addQuarterArc( BOARD& aBoard )
44{
45 // A quarter arc (0 -> 90 deg) about the origin, radius 10 mm.
46 return addArc( aBoard, { 10 * MM, 0 }, { 7071068, 7071068 }, { 0, 10 * MM } );
47}
48}
49
50
51BOOST_AUTO_TEST_SUITE( ConstraintArcAngle )
52
53
54BOOST_AUTO_TEST_CASE( AuthorMeasuresSweptAngle )
55{
56 BOARD board;
57 PCB_SHAPE* arc = addQuarterArc( board );
58
59 std::unique_ptr<PCB_CONSTRAINT> c =
61
62 BOOST_REQUIRE( c );
63 BOOST_REQUIRE( c->HasValue() );
64 BOOST_CHECK_CLOSE( *c->GetValue(), 90.0, 0.1 );
65 BOOST_CHECK( c->IsDriving() );
66}
67
68
69BOOST_AUTO_TEST_CASE( AuthorRejectsNonArc )
70{
71 BOARD board;
72 PCB_SHAPE* circle = addCircle( board, { 0, 0 }, 5 * MM );
73
75}
76
77
78BOOST_AUTO_TEST_CASE( DriveSweptAngleReachesTarget )
79{
80 BOARD board;
81 PCB_SHAPE* arc = addQuarterArc( board );
82
84 { { arc->m_Uuid, CONSTRAINT_ANCHOR::WHOLE } }, 60.0 );
85
86 solveAndApply( board, { arc } );
87
88 BOOST_CHECK_CLOSE( arc->GetArcAngle().AsDegrees(), 60.0, 0.5 );
89}
90
91
92// The apply-on-create path holds the free arc radius, so shrinking the swept angle rotates an
93// endpoint about a stable radius instead of collapsing the arc to a point. (Winding is preserved
94// only once the arc is otherwise constrained; a fully free arc can still flip -- that is arc-edit
95// robustness, item 4.)
96BOOST_AUTO_TEST_CASE( ApplyHoldsArcRadius )
97{
98 BOARD board;
99 PCB_SHAPE* arc = addQuarterArc( board );
100 int radius0 = arc->GetRadius();
101
103 { { arc->m_Uuid, CONSTRAINT_ANCHOR::WHOLE } }, 60.0 );
104
105 std::vector<PCB_SHAPE*> modified;
106 ApplyConstraintImmediately( &board, c, &modified );
107
108 BOOST_CHECK_CLOSE( arc->GetArcAngle().AsDegrees(), 60.0, 0.5 );
109 BOOST_CHECK_LE( std::abs( arc->GetRadius() - radius0 ), 5000 );
110}
111
112
113// Driving a 90 degree arc up to 270 degrees reaches the reflex value rather than no-oping on the
114// nearer 90 degree reading -- the target is the mod-2*pi representative that moves the endpoint.
115BOOST_AUTO_TEST_CASE( DriveToReflexAngle )
116{
117 BOARD board;
118 PCB_SHAPE* arc = addQuarterArc( board );
119
121 { { arc->m_Uuid, CONSTRAINT_ANCHOR::WHOLE } }, 270.0 );
122
123 solveAndApply( board, { arc } );
124
125 BOOST_CHECK_CLOSE( arc->GetArcAngle().AsDegrees(), 270.0, 0.5 );
126}
127
128
129BOOST_AUTO_TEST_CASE( ArcAngleOnCircleIsUnmapped )
130{
131 BOARD board;
132 PCB_SHAPE* circle = addCircle( board, { 0, 0 }, 5 * MM );
133
135 { { circle->m_Uuid, CONSTRAINT_ANCHOR::WHOLE } }, 90.0 );
136
137 std::vector<PCB_CONSTRAINT*> constraints = { c };
139 BOOST_REQUIRE( adapter.Build( { circle }, constraints ) );
140
141 BOOST_CHECK( std::find( adapter.UnmappedConstraints().begin(), adapter.UnmappedConstraints().end(),
142 c->m_Uuid )
143 != adapter.UnmappedConstraints().end() );
144}
145
146
147// A reference arc-angle stays live: reshape the arc, re-solve, and the stored value follows.
148BOOST_AUTO_TEST_CASE( ReferenceArcAngleTracksGeometry )
149{
150 BOARD board;
151 PCB_SHAPE* arc = addQuarterArc( board ); // 90 deg
152
154 { { arc->m_Uuid, CONSTRAINT_ANCHOR::WHOLE } }, 90.0 );
155 c->SetDriving( false );
156
157 // Widen the arc to a half turn (0 -> 180 deg).
158 arc->SetArcGeometry( { 10 * MM, 0 }, { 0, 10 * MM }, { -10 * MM, 0 } );
159
160 std::vector<BOARD_ITEM*> staged;
161 ReSolveShapeClusters( &board, { arc }, nullptr, [&]( BOARD_ITEM* i ) { staged.push_back( i ); } );
162
163 BOOST_REQUIRE( c->GetValue().has_value() );
164 BOOST_CHECK_CLOSE( *c->GetValue(), 180.0, 0.5 );
165 BOOST_CHECK( std::find( staged.begin(), staged.end(), c ) != staged.end() );
166}
167
168
CONSTRAINT_DIAGNOSIS ApplyConstraintImmediately(BOARD *aBoard, const PCB_CONSTRAINT *aConstraint, std::vector< PCB_SHAPE * > *aModified, const std::function< void(BOARD_ITEM *)> &aBeforeModify)
Solve a just-created constraint's cluster so the geometry snaps to satisfy it (SolidWorks-style),...
void ReSolveShapeClusters(BOARD *aBoard, const std::vector< PCB_SHAPE * > &aShapes, std::vector< PCB_SHAPE * > *aModified, const std::function< void(BOARD_ITEM *)> &aBeforeModify)
Re-solve the clusters of shapes edited outside the solver, e.g.
Translates KiCad board geometry to and from the planegcs solver (issue #2329).
const std::vector< KIID > & UnmappedConstraints() const
Constraints from the last Build() that could not be mapped onto a solver primitive (wrong member coun...
bool Build(const std::vector< PCB_SHAPE * > &aShapes, const std::vector< PCB_CONSTRAINT * > &aConstraints, const std::set< KIID > *aFixedShapes=nullptr, const std::vector< PCB_DIMENSION_BASE * > &aDimensions={})
Translate a cluster into a planegcs system.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
double AsDegrees() const
Definition eda_angle.h:116
const KIID m_Uuid
Definition eda_item.h:531
EDA_ANGLE GetArcAngle() const
int GetRadius() const
A geometric constraint between board items (issue #2329).
std::optional< double > GetValue() const
void SetDriving(bool aDriving)
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
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 ...
PCB_SHAPE * addArc(BOARD &aBoard, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
PCB_SHAPE * addCircle(BOARD &aBoard, const VECTOR2I &aCenter, int aRadius)
void solveAndApply(BOARD &aBoard, const std::vector< PCB_SHAPE * > &aShapes)
Build the cluster of aShapes against every constraint on aBoard, solve it, and write the result back ...
constexpr int MM
PCB_CONSTRAINT * addConstraint(BOARD &aBoard, PCB_CONSTRAINT_TYPE aType, const std::vector< CONSTRAINT_MEMBER > &aMembers, std::optional< double > aValue=std::nullopt)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ WHOLE
The item as a whole (a segment as a line, a circle).
@ ARC_ANGLE
An arc has a driving or reference swept-angle value.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(AuthorMeasuresSweptAngle)
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)