KiCad PCB EDA Suite
Loading...
Searching...
No Matches
edit_relations.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 3
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 <tool/edit_relations.h>
21
22#include <geometry/circle.h>
23#include <geometry/seg.h>
25#include <math/util.h>
26#include <tool/edit_points.h>
27#include <tool/grid_helper.h>
28
29
30std::unique_ptr<EDIT_RELATION> EDIT_RELATION::make( EDIT_RELATION_KIND aKind, const EDIT_POINT& aReference )
31{
32 auto relation = std::unique_ptr<EDIT_RELATION>( new EDIT_RELATION( aKind ) );
33 relation->m_reference = &aReference;
34 return relation;
35}
36
37
38std::unique_ptr<EDIT_RELATION> EDIT_RELATION::SameX( const EDIT_POINT& aReference )
39{
40 return make( EDIT_RELATION_KIND::SAME_X, aReference );
41}
42
43
44std::unique_ptr<EDIT_RELATION> EDIT_RELATION::SameY( const EDIT_POINT& aReference )
45{
46 return make( EDIT_RELATION_KIND::SAME_Y, aReference );
47}
48
49
50std::unique_ptr<EDIT_RELATION> EDIT_RELATION::Angle45( const EDIT_POINT& aReference )
51{
52 return make( EDIT_RELATION_KIND::ANGLE_STEP_45, aReference );
53}
54
55
56std::unique_ptr<EDIT_RELATION> EDIT_RELATION::Angle90( const EDIT_POINT& aReference )
57{
58 return make( EDIT_RELATION_KIND::ANGLE_STEP_90, aReference );
59}
60
61
62std::unique_ptr<EDIT_RELATION> EDIT_RELATION::PointOnLine( const EDIT_POINT& aConstrained,
63 const EDIT_POINT& aReference )
64{
65 auto relation = make( EDIT_RELATION_KIND::POINT_ON_LINE, aReference );
66 relation->m_direction = aConstrained.GetPosition() - aReference.GetPosition();
67 return relation;
68}
69
70
71std::unique_ptr<EDIT_RELATION> EDIT_RELATION::PointOnCircle( const EDIT_POINT& aCenter, const EDIT_POINT& aEnd )
72{
73 auto relation = make( EDIT_RELATION_KIND::POINT_ON_CIRCLE, aCenter );
74 relation->m_secondaryReference = &aEnd;
75 return relation;
76}
77
78
79std::unique_ptr<EDIT_RELATION> EDIT_RELATION::PerpendicularTranslation( const EDIT_LINE& aLine )
80{
81 auto relation =
82 std::unique_ptr<EDIT_RELATION>( new EDIT_RELATION( EDIT_RELATION_KIND::PERPENDICULAR_TRANSLATION ) );
83 relation->m_origin = aLine.GetPosition();
84 relation->m_direction = ( aLine.GetEnd().GetPosition() - aLine.GetOrigin().GetPosition() ).Perpendicular();
85 return relation;
86}
87
88
89void EDIT_RELATION::Apply( EDIT_POINT& aHandle, const GRID_HELPER& aGrid ) const
90{
91 VECTOR2I point = aHandle.GetPosition();
92
93 switch( m_kind )
94 {
96 if( aHandle.GetGridConstraint() == SNAP_TO_GRID )
97 point = aGrid.AlignGrid( point );
98
99 point.x = m_reference->GetPosition().x;
100 aHandle.SetPosition( point );
101 break;
102
104 if( aHandle.GetGridConstraint() == SNAP_TO_GRID )
105 point = aGrid.AlignGrid( point );
106
107 point.y = m_reference->GetPosition().y;
108 aHandle.SetPosition( point );
109 break;
110
113 {
114 VECTOR2I vector = point - m_reference->GetPosition();
116 : GetVectorSnapped90( vector );
117
118 if( aHandle.GetGridConstraint() == SNAP_TO_GRID
119 && ( m_kind == EDIT_RELATION_KIND::ANGLE_STEP_90 || snapped.x == 0 || snapped.y == 0 ) )
120 {
121 VECTOR2I gridPoint = aGrid.AlignGrid( m_reference->GetPosition() + snapped );
122
123 if( snapped.x == 0 )
124 point = VECTOR2I( m_reference->GetPosition().x, gridPoint.y );
125 else
126 point = VECTOR2I( gridPoint.x, m_reference->GetPosition().y );
127 }
128 else
129 {
130 point = m_reference->GetPosition() + snapped;
131 }
132
133 aHandle.SetPosition( point );
134 break;
135 }
136
138 {
139 if( aHandle.GetGridConstraint() == SNAP_TO_GRID && ( m_direction.x == 0 || m_direction.y == 0 ) )
140 {
141 VECTOR2I gridPoint = aGrid.AlignGrid( point );
142
143 if( m_direction.x == 0 )
144 point.y = gridPoint.y;
145 else
146 point.x = gridPoint.x;
147 }
148
149 const VECTOR2I& reference = m_reference->GetPosition();
150 aHandle.SetPosition( SEG( reference, reference + m_direction ).LineProject( point ) );
151 break;
152 }
153
155 {
156 const VECTOR2I& center = m_reference->GetPosition();
157 const int radius = ( m_secondaryReference->GetPosition() - center ).EuclideanNorm();
158 aHandle.SetPosition( CIRCLE( center, radius ).NearestPoint( point ) );
159 break;
160 }
161
163 }
164}
165
166
167void EDIT_RELATION::Apply( EDIT_LINE& aHandle, const GRID_HELPER& aGrid ) const
168{
170 return;
171
172 aHandle.SetPosition( SEG( m_origin, m_origin + m_direction ).LineProject( aHandle.GetPosition() ) );
173}
174
175
177 m_mode( aMode ),
178 m_editPoints( aPoints ),
179 m_prevOrigin( aPoints.Previous( aLine.GetOrigin(), false ) ),
180 m_nextEnd( aPoints.Next( aLine.GetEnd(), false ) )
181{
182 EDIT_POINT& origin = aLine.GetOrigin();
183 EDIT_POINT& end = aLine.GetEnd();
184
185 m_originSideDirection = origin.GetPosition() - m_prevOrigin->GetPosition();
186 m_endSideDirection = end.GetPosition() - m_nextEnd->GetPosition();
187 m_draggedVector = end.GetPosition() - origin.GetPosition();
189 m_perpVector = m_draggedVector.Perpendicular();
190 m_halfLength = m_draggedVector.EuclideanNorm() / 2.0;
191
192 SEG originSide( origin.GetPosition(), m_prevOrigin->GetPosition() );
193 SEG endSide( end.GetPosition(), m_nextEnd->GetPosition() );
194 SEG dragged( origin.GetPosition(), end.GetPosition() );
195
196 constexpr int alignAngle = 10;
197 m_originCollinear = dragged.Angle( originSide ).AsDegrees() < alignAngle;
198 m_endCollinear = dragged.Angle( endSide ).AsDegrees() < alignAngle;
199
200 if( OPT_VECTOR2I intersection = originSide.IntersectLines( endSide ) )
201 m_convergencePoint = *intersection;
202 else
204}
205
206
208{
210 SEG throughHandle( aHandle.GetPosition(), aHandle.GetPosition() + m_draggedVector );
211 VECTOR2I newCenter = aHandle.GetPosition();
212
213 if( OPT_VECTOR2I intersection = perpendicular.IntersectLines( throughHandle ) )
214 newCenter = *intersection;
215
217 {
218 VECTOR2I centerToConvergence = m_convergencePoint - m_originalCenter;
219 VECTOR2I centerToNew = newCenter - m_originalCenter;
220 auto denominator = centerToConvergence.Dot( m_perpVector );
221
222 if( denominator != 0 && double( centerToNew.Dot( m_perpVector ) ) / double( denominator ) > 1.0 )
223 {
224 newCenter = m_convergencePoint;
225 }
226 }
227
228 aHandle.SetPosition( newCenter );
229
231 applyFixedLength( aHandle );
232 else
233 applyConverging( aHandle );
234}
235
236
238{
239 EDIT_POINT& origin = aHandle.GetOrigin();
240 EDIT_POINT& end = aHandle.GetEnd();
241
243 {
244 const VECTOR2I& reference = m_prevOrigin->GetPosition();
245 const SEG line( reference, reference + m_originSideDirection );
246
247 for( EDIT_POINT* point : { &origin, &end } )
248 point->SetPosition( line.LineProject( point->GetPosition() ) );
249
250 return;
251 }
252
253 VECTOR2I center = aHandle.GetPosition();
254 SEG dragged( center - m_draggedVector / 2, center + m_draggedVector / 2 );
255 SEG originSide( m_prevOrigin->GetPosition(), m_prevOrigin->GetPosition() + m_originSideDirection );
256 SEG endSide( m_nextEnd->GetPosition(), m_nextEnd->GetPosition() + m_endSideDirection );
257
258 if( OPT_VECTOR2I intersection = dragged.IntersectLines( originSide ) )
259 origin.SetPosition( *intersection );
260
261 if( OPT_VECTOR2I intersection = dragged.IntersectLines( endSide ) )
262 end.SetPosition( *intersection );
263
264 originSide = SEG( origin.GetPosition(), m_prevOrigin->GetPosition() );
265 endSide = SEG( end.GetPosition(), m_nextEnd->GetPosition() );
266
267 if( OPT_VECTOR2I intersection = endSide.Intersect( originSide ) )
268 {
269 if( m_editPoints.LinesSize() > 3 )
270 {
271 origin.SetPosition( *intersection );
272 end.SetPosition( *intersection );
273 }
274 }
275}
276
277
279{
280 VECTOR2D direction( m_draggedVector );
281
282 if( direction.EuclideanNorm() > 0 )
283 direction = direction / direction.EuclideanNorm();
284
285 VECTOR2I halfVector = KiROUND( direction * m_halfLength );
286 aHandle.GetOrigin().SetPosition( aHandle.GetPosition() - halfVector );
287 aHandle.GetEnd().SetPosition( aHandle.GetPosition() + halfVector );
288}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
Represent a line connecting two EDIT_POINTs.
virtual void SetPosition(const VECTOR2I &aPosition) override
Return coordinates of an EDIT_POINT.
EDIT_POINT & GetEnd()
Return the end EDIT_POINT.
EDIT_POINT & GetOrigin()
Return the origin EDIT_POINT.
virtual VECTOR2I GetPosition() const override
Return coordinates of an EDIT_POINT.
EDIT_POINTS is a VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them.
Represent a single point that can be used for modifying items.
Definition edit_points.h:44
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition edit_points.h:68
GRID_CONSTRAINT_TYPE GetGridConstraint() const
VECTOR2I m_origin
static std::unique_ptr< EDIT_RELATION > Angle90(const EDIT_POINT &aReference)
static std::unique_ptr< EDIT_RELATION > Angle45(const EDIT_POINT &aReference)
EDIT_RELATION(EDIT_RELATION_KIND aKind)
const EDIT_POINT * m_secondaryReference
static std::unique_ptr< EDIT_RELATION > SameY(const EDIT_POINT &aReference)
static std::unique_ptr< EDIT_RELATION > PerpendicularTranslation(const EDIT_LINE &aLine)
const EDIT_POINT * m_reference
VECTOR2I m_direction
EDIT_RELATION_KIND m_kind
void Apply(EDIT_POINT &aHandle, const GRID_HELPER &aGrid) const
static std::unique_ptr< EDIT_RELATION > PointOnCircle(const EDIT_POINT &aCenter, const EDIT_POINT &aEnd)
static std::unique_ptr< EDIT_RELATION > SameX(const EDIT_POINT &aReference)
static std::unique_ptr< EDIT_RELATION > make(EDIT_RELATION_KIND aKind, const EDIT_POINT &aReference)
static std::unique_ptr< EDIT_RELATION > PointOnLine(const EDIT_POINT &aConstrained, const EDIT_POINT &aReference)
virtual VECTOR2I AlignGrid(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
void Apply(EDIT_LINE &aHandle, const GRID_HELPER &aGrid)
void applyFixedLength(EDIT_LINE &aHandle)
POLYGON_EDGE_DRAG_POLICY(EDIT_LINE &aLine, EDIT_POINTS &aPoints, POLYGON_LINE_MODE aMode=POLYGON_LINE_MODE::CONVERGING)
void applyConverging(EDIT_LINE &aHandle)
POLYGON_LINE_MODE m_mode
Definition seg.h:38
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition seg.cpp:442
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition seg.h:216
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Definition seg.cpp:681
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
Definition vector2d.h:310
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
Definition vector2d.h:542
POLYGON_LINE_MODE
@ SNAP_TO_GRID
EDIT_RELATION_KIND
a few functions useful in geometry calculations.
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec, bool only45=false)
Snap a vector onto the nearest 0, 45 or 90 degree line.
VECTOR2< T > GetVectorSnapped90(const VECTOR2< T > &aVec)
Snap a vector onto the nearest horizontal or vertical line.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:35
VECTOR2I center
int radius
VECTOR2I end
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682