KiCad PCB EDA Suite
Loading...
Searching...
No Matches
point_editor_behavior.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
21
22#include <advanced_config.h>
23#include <commit.h>
25
26
28 const SHAPE_POLY_SET& aOutline )
29{
30 const int cornersCount = aOutline.TotalVertices();
31
32 if( cornersCount == 0 )
33 return;
34
35 for( auto iterator = aOutline.CIterateWithHoles(); iterator; iterator++ )
36 {
37 aPoints.AddPoint( *iterator );
38
39 if( iterator.IsEndContour() )
40 aPoints.AddBreak();
41 }
42
43 // Lines have to be added after creating edit points, as they use EDIT_POINT references
44 for( int i = 0; i < cornersCount - 1; ++i )
45 {
46 if( aPoints.IsContourEnd( i ) )
47 aPoints.AddLine( aPoints.Point( i ), aPoints.Point( aPoints.GetContourStartIdx( i ) ) );
48 else
49 aPoints.AddLine( aPoints.Point( i ), aPoints.Point( i + 1 ) );
50
51 aPoints.Line( i ).SetDragPolicy(
52 std::make_unique<POLYGON_EDGE_DRAG_POLICY>( aPoints.Line( i ), aPoints ) );
53 }
54
55 // The last missing line, connecting the last and the first polygon point
56 aPoints.AddLine( aPoints.Point( cornersCount - 1 ),
57 aPoints.Point( aPoints.GetContourStartIdx( cornersCount - 1 ) ) );
58
59 aPoints.Line( aPoints.LinesSize() - 1 )
60 .SetDragPolicy( std::make_unique<POLYGON_EDGE_DRAG_POLICY>(
61 aPoints.Line( aPoints.LinesSize() - 1 ), aPoints ) );
62}
63
64
66 EDIT_POINTS& aPoints )
67{
68 // No size check here, as we can and will rebuild if that fails
69 if( aPoints.PointsSize() != (unsigned) aOutline.TotalVertices() )
70 {
71 // Rebuild the points list
72 aPoints.Clear();
73 BuildForPolyOutline( aPoints, aOutline );
74 }
75 else
76 {
77 for( int i = 0; i < aOutline.TotalVertices(); ++i )
78 aPoints.Point( i ).SetPosition( aOutline.CVertex( i ) );
79 }
80}
81
82
84 const EDIT_POINT& aEditedPoint,
85 EDIT_POINTS& aPoints )
86{
87 CHECK_POINT_COUNT_GE( aPoints, (unsigned) aOutline.TotalVertices() );
88
89 for( int i = 0; i < aOutline.TotalVertices(); ++i )
90 aOutline.SetVertex( i, aPoints.Point( i ).GetPosition() );
91
92 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
93 {
94 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
95 aPoints.Line( i ).SetDragPolicy(
96 std::make_unique<POLYGON_EDGE_DRAG_POLICY>( aPoints.Line( i ), aPoints ) );
97 }
98}
99
100
102{
103 m_polygon.RemoveNullSegments();
104}
105
106
108{
109 aPoints.AddPoint( m_segment.GetStart() );
110 aPoints.AddPoint( m_segment.GetEnd() );
111}
112
113
115{
116 wxCHECK( aPoints.PointsSize() == SEGMENT_MAX_POINTS, false );
117
118 aPoints.Point( SEGMENT_START ) = m_segment.GetStart();
119 aPoints.Point( SEGMENT_END ) = m_segment.GetEnd();
120 return true;
121}
122
123
125 EDIT_POINTS& aPoints, COMMIT& aCommit,
126 std::vector<EDA_ITEM*>& aUpdatedItems )
127{
129
130 if( isModified( aEditedPoint, aPoints.Point( SEGMENT_START ) ) )
131 m_segment.SetStart( aPoints.Point( SEGMENT_START ).GetPosition() );
132
133 else if( isModified( aEditedPoint, aPoints.Point( SEGMENT_END ) ) )
134 m_segment.SetEnd( aPoints.Point( SEGMENT_END ).GetPosition() );
135}
136
137
139{
140 const ELLIPSE<int>& ellipse = m_ellipse.GetEllipse();
141 return ellipse.GetPointAtAngle( aTheta );
142}
143
144
146{
147 const ELLIPSE<int>& ellipse = m_ellipse.GetEllipse();
148 return ellipse.GetAngleAtPoint( aWorldPt );
149}
150
151
153{
154 const ELLIPSE<int>& ellipse = m_ellipse.GetEllipse();
155
156 aPoints.AddPoint( ellipse.Center );
157 aPoints.AddPoint( ellipse.GetPointAtAngle( ANGLE_0 ) );
158 aPoints.AddPoint( ellipse.GetPointAtAngle( ANGLE_90 ) );
159
160 if( m_ellipse.GetShape() == SHAPE_T::ELLIPSE_ARC )
161 {
162 aPoints.AddPoint( evaluateAt( m_ellipse.GetEllipseStartAngle() ) );
163 aPoints.AddPoint( evaluateAt( m_ellipse.GetEllipseEndAngle() ) );
164
165 aPoints.AddIndicatorLine( aPoints.Point( ELLIPSE_CENTER ), aPoints.Point( ELLIPSE_ARC_START ) );
166 aPoints.AddIndicatorLine( aPoints.Point( ELLIPSE_CENTER ), aPoints.Point( ELLIPSE_ARC_END ) );
167 }
168}
169
170
172{
173 const bool isArc = ( m_ellipse.GetShape() == SHAPE_T::ELLIPSE_ARC );
174 const size_t expected = isArc ? ELLIPSE_ARC_POINTS : ELLIPSE_CLOSED_POINTS;
175
176 wxCHECK( aPoints.PointsSize() == expected, false );
177
178 const ELLIPSE<int>& ellipse = m_ellipse.GetEllipse();
179
180 aPoints.Point( ELLIPSE_CENTER ).SetPosition( ellipse.Center );
183
184 if( isArc )
185 {
186 aPoints.Point( ELLIPSE_ARC_START ).SetPosition( evaluateAt( m_ellipse.GetEllipseStartAngle() ) );
187 aPoints.Point( ELLIPSE_ARC_END ).SetPosition( evaluateAt( m_ellipse.GetEllipseEndAngle() ) );
188 }
189
190 return true;
191}
192
193
194void EDA_ELLIPSE_POINT_EDIT_BEHAVIOR::UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
195 std::vector<EDA_ITEM*>& aUpdatedItems )
196{
197 const bool isArc = ( m_ellipse.GetShape() == SHAPE_T::ELLIPSE_ARC );
198 const size_t expected = isArc ? ELLIPSE_ARC_POINTS : ELLIPSE_CLOSED_POINTS;
199
200 CHECK_POINT_COUNT( aPoints, expected );
201
202 if( isModified( aEditedPoint, aPoints.Point( ELLIPSE_CENTER ) ) )
203 {
204 m_ellipse.SetEllipseCenter( aPoints.Point( ELLIPSE_CENTER ).GetPosition() );
205 }
206 else if( isModified( aEditedPoint, aPoints.Point( ELLIPSE_MAJOR_END ) ) )
207 {
208 const VECTOR2I center = m_ellipse.GetEllipseCenter();
209 const VECTOR2I v = aPoints.Point( ELLIPSE_MAJOR_END ).GetPosition() - center;
210 const double len = std::sqrt( double( v.x ) * v.x + double( v.y ) * v.y );
211
212 m_ellipse.SetEllipseMajorRadius( std::max( 1, KiROUND( len ) ) );
213 m_ellipse.SetEllipseRotation( EDA_ANGLE( std::atan2( (double) v.y, (double) v.x ), RADIANS_T ) );
214 }
215 else if( isModified( aEditedPoint, aPoints.Point( ELLIPSE_MINOR_END ) ) )
216 {
217 const VECTOR2I center = m_ellipse.GetEllipseCenter();
218 const VECTOR2I v = aPoints.Point( ELLIPSE_MINOR_END ).GetPosition() - center;
219 const EDA_ANGLE rotation = m_ellipse.GetEllipseRotation();
220
221 // Absolute value so dragging past the rotation axis keeps radius positive.
222 const double proj = -v.x * rotation.Sin() + v.y * rotation.Cos();
223
224 m_ellipse.SetEllipseMinorRadius( std::max( 1, KiROUND( std::abs( proj ) ) ) );
225 }
226 else if( isArc && isModified( aEditedPoint, aPoints.Point( ELLIPSE_ARC_START ) ) )
227 {
229 EDA_ANGLE prevStart = m_ellipse.GetEllipseStartAngle();
230 EDA_ANGLE sweep = m_ellipse.GetEllipseEndAngle() - prevStart;
231
232 while( ( rawAngle - prevStart ).AsDegrees() > 180.0 )
233 rawAngle = rawAngle - ANGLE_360;
234 while( ( prevStart - rawAngle ).AsDegrees() > 180.0 )
235 rawAngle = rawAngle + ANGLE_360;
236
237 m_ellipse.SetEllipseStartAngle( rawAngle );
238 m_ellipse.SetEllipseEndAngle( rawAngle + sweep );
239 }
240 else if( isArc && isModified( aEditedPoint, aPoints.Point( ELLIPSE_ARC_END ) ) )
241 {
243 EDA_ANGLE prevEnd = m_ellipse.GetEllipseEndAngle();
244
245 while( ( rawAngle - prevEnd ).AsDegrees() > 180.0 )
246 rawAngle = rawAngle - ANGLE_360;
247 while( ( prevEnd - rawAngle ).AsDegrees() > 180.0 )
248 rawAngle = rawAngle + ANGLE_360;
249
250 m_ellipse.SetEllipseEndAngle( rawAngle );
251 }
252}
253
254
256 EDIT_POINTS& aPoints ) const
257{
258 // Select the other end of line
259 return aPoints.Next( aEditedPoint )->GetPosition();
260}
261
262
264{
265 aPoints.AddPoint( m_circle.getCenter() );
266 aPoints.AddPoint( m_circle.GetEnd() );
267}
268
269
271{
272 wxCHECK( aPoints.PointsSize() == CIRC_MAX_POINTS, false );
273
274 aPoints.Point( CIRC_CENTER ).SetPosition( m_circle.getCenter() );
275 aPoints.Point( CIRC_END ).SetPosition( m_circle.GetEnd() );
276 return true;
277}
278
279
281 EDIT_POINTS& aPoints, COMMIT& aCommit,
282 std::vector<EDA_ITEM*>& aUpdatedItems )
283{
285
286 const VECTOR2I& center = aPoints.Point( CIRC_CENTER ).GetPosition();
287 const VECTOR2I& end = aPoints.Point( CIRC_END ).GetPosition();
288
289 if( isModified( aEditedPoint, aPoints.Point( CIRC_CENTER ) ) )
290 m_circle.SetCenter( center );
291 else
292 m_circle.SetEnd( VECTOR2I( end.x, end.y ) );
293}
294
295
297 EDIT_POINTS& aPoints ) const
298{
299 return aPoints.Point( CIRC_CENTER ).GetPosition();
300}
301
302
304{
305 aPoints.AddPoint( m_bezier.GetStart() );
306 aPoints.AddPoint( m_bezier.GetBezierC1() );
307 aPoints.AddPoint( m_bezier.GetBezierC2() );
308 aPoints.AddPoint( m_bezier.GetEnd() );
309
310 aPoints.AddIndicatorLine( aPoints.Point( BEZIER_START ), aPoints.Point( BEZIER_CTRL_PT1 ) );
311 aPoints.AddIndicatorLine( aPoints.Point( BEZIER_CTRL_PT2 ), aPoints.Point( BEZIER_END ) );
312}
313
314
316{
317 wxCHECK( aPoints.PointsSize() == BEZIER_MAX_POINTS, false );
318
319 aPoints.Point( BEZIER_START ).SetPosition( m_bezier.GetStart() );
320 aPoints.Point( BEZIER_CTRL_PT1 ).SetPosition( m_bezier.GetBezierC1() );
321 aPoints.Point( BEZIER_CTRL_PT2 ).SetPosition( m_bezier.GetBezierC2() );
322 aPoints.Point( BEZIER_END ).SetPosition( m_bezier.GetEnd() );
323 return true;
324}
325
326
328 COMMIT& aCommit, std::vector<EDA_ITEM*>& aUpdatedItems )
329{
331
332 if( isModified( aEditedPoint, aPoints.Point( BEZIER_START ) ) )
333 {
334 m_bezier.SetStart( aPoints.Point( BEZIER_START ).GetPosition() );
335 }
336 else if( isModified( aEditedPoint, aPoints.Point( BEZIER_CTRL_PT1 ) ) )
337 {
338 m_bezier.SetBezierC1( aPoints.Point( BEZIER_CTRL_PT1 ).GetPosition() );
339 }
340 else if( isModified( aEditedPoint, aPoints.Point( BEZIER_CTRL_PT2 ) ) )
341 {
342 m_bezier.SetBezierC2( aPoints.Point( BEZIER_CTRL_PT2 ).GetPosition() );
343 }
344 else if( isModified( aEditedPoint, aPoints.Point( BEZIER_END ) ) )
345 {
346 m_bezier.SetEnd( aPoints.Point( BEZIER_END ).GetPosition() );
347 }
348
349 m_bezier.RebuildBezierToSegmentsPointsList( m_maxError );
350}
351
352
353// Note: these static arc functions don't have to be in here - we could ship them out
354// to a utils area for use by other code (e.g. polygon fillet editing).
355
359static void editArcEndpointKeepTangent( EDA_SHAPE& aArc, const VECTOR2I& aCenter, const VECTOR2I& aStart,
360 const VECTOR2I& aMid, const VECTOR2I& aEnd, const VECTOR2I& aCursor )
361{
362 VECTOR2I center = aCenter;
363 bool movingStart;
364 bool arcValid = true;
365
366 VECTOR2I p1, p2, p3;
367 // p1 does not move, p2 does.
368
369 if( aStart != aArc.GetStart() )
370 {
371 p1 = aEnd;
372 p2 = aStart;
373 p3 = aMid;
374 movingStart = true;
375 }
376 else if( aEnd != aArc.GetEnd() )
377 {
378 p1 = aStart;
379 p2 = aEnd;
380 p3 = aMid;
381 movingStart = false;
382 }
383 else
384 {
385 return;
386 }
387
388 VECTOR2D v1, v2, v3, v4;
389
390 // Move the coordinate system
391 v1 = p1 - aCenter;
392 v2 = p2 - aCenter;
393 v3 = p3 - aCenter;
394
395 VECTOR2D u1, u2;
396
397 // A point cannot be both the center and on the arc.
398 if( ( v1.EuclideanNorm() == 0 ) || ( v2.EuclideanNorm() == 0 ) )
399 return;
400
401 u1 = v1 / v1.EuclideanNorm();
402 u2 = v3 - ( u1.x * v3.x + u1.y * v3.y ) * u1;
403 u2 = u2 / u2.EuclideanNorm();
404
405 // [ u1, u3 ] is a base centered on the circle with:
406 // u1 : unit vector toward the point that does not move
407 // u2 : unit vector toward the mid point.
408
409 // Get vectors v1, and v2 in that coordinate system.
410
411 double det = u1.x * u2.y - u2.x * u1.y;
412
413 // u1 and u2 are unit vectors, and perpendicular.
414 // det should not be 0. In case it is, do not change the arc.
415 if( det == 0 )
416 return;
417
418 double tmpx = v1.x * u2.y - v1.y * u2.x;
419 double tmpy = -v1.x * u1.y + v1.y * u1.x;
420 v1.x = tmpx;
421 v1.y = tmpy;
422 v1 = v1 / det;
423
424 tmpx = v2.x * u2.y - v2.y * u2.x;
425 tmpy = -v2.x * u1.y + v2.y * u1.x;
426 v2.x = tmpx;
427 v2.y = tmpy;
428 v2 = v2 / det;
429
430 double R = v1.EuclideanNorm();
431 bool transformCircle = false;
432
433 /* p2
434 * X***
435 * ** <---- This is the arc
436 * y ^ **
437 * | R *
438 * | <-----------> *
439 * x------x------>--------x p1
440 * C' <----> C x
441 * delta
442 *
443 * p1 does not move, and the tangent at p1 remains the same.
444 * => The new center, C', will be on the C-p1 axis.
445 * p2 moves
446 *
447 * The radius of the new circle is delta + R
448 *
449 * || C' p2 || = || C' P1 ||
450 * is the same as :
451 * ( delta + p2.x ) ^ 2 + p2.y ^ 2 = ( R + delta ) ^ 2
452 *
453 * delta = ( R^2 - p2.x ^ 2 - p2.y ^2 ) / ( 2 * p2.x - 2 * R )
454 *
455 * We can use this equation for any point p2 with p2.x < R
456 */
457
458 if( v2.x == R )
459 {
460 // Straight line, do nothing
461 }
462 else
463 {
464 if( v2.x > R )
465 {
466 // If we need to invert the curvature.
467 // We modify the input so we can use the same equation
468 transformCircle = true;
469 v2.x = 2 * R - v2.x;
470 }
471
472 // We can keep the tangent constraint.
473 double delta = ( R * R - v2.x * v2.x - v2.y * v2.y ) / ( 2 * v2.x - 2 * R );
474
475 // This is just to limit the radius, so nothing overflows later when drawing.
476 if( abs( v2.y / ( R - v2.x ) ) > ADVANCED_CFG::GetCfg().m_DrawArcCenterMaxAngle )
477 arcValid = false;
478
479 // Never recorded a problem, but still checking.
480 if( !std::isfinite( delta ) )
481 arcValid = false;
482
483 // v4 is the new center
484 v4 = ( !transformCircle ) ? VECTOR2D( -delta, 0 ) : VECTOR2D( 2 * R + delta, 0 );
485
486 tmpx = v4.x * u1.x + v4.y * u2.x;
487 tmpy = v4.x * u1.y + v4.y * u2.y;
488 v4.x = tmpx;
489 v4.y = tmpy;
490
491 center = v4 + aCenter;
492
493 if( arcValid )
494 {
495 aArc.SetCenter( center );
496
497 if( movingStart )
498 aArc.SetStart( aStart );
499 else
500 aArc.SetEnd( aEnd );
501 }
502 }
503}
504
505
509static void editArcCenterKeepEndpoints( EDA_SHAPE& aArc, const VECTOR2I& aCenter, const VECTOR2I& aStart,
510 const VECTOR2I& aMid, const VECTOR2I& aEnd )
511{
512 const int c_snapEpsilon_sq = 4;
513
514 VECTOR2I m = ( aStart / 2 + aEnd / 2 );
515 VECTOR2I perp = ( aEnd - aStart ).Perpendicular().Resize( INT_MAX / 2 );
516
517 SEG legal( m - perp, m + perp );
518
519 const SEG testSegments[] = {
520 SEG( aCenter, aCenter + VECTOR2( 1, 0 ) ),
521 SEG( aCenter, aCenter + VECTOR2( 0, 1 ) ),
522 };
523
524 std::vector<VECTOR2I> points = { legal.A, legal.B };
525
526 for( const SEG& seg : testSegments )
527 {
528 OPT_VECTOR2I vec = legal.IntersectLines( seg );
529
530 if( vec && legal.SquaredDistance( *vec ) <= c_snapEpsilon_sq )
531 points.push_back( *vec );
532 }
533
534 OPT_VECTOR2I nearest;
536
537 // Snap by distance between cursor and intersections
538 for( const VECTOR2I& pt : points )
539 {
540 SEG::ecoord d_sq = ( pt - aCenter ).SquaredEuclideanNorm();
541
542 if( d_sq < min_d_sq - c_snapEpsilon_sq )
543 {
544 min_d_sq = d_sq;
545 nearest = pt;
546 }
547 }
548
549 if( nearest )
550 aArc.SetCenter( *nearest );
551}
552
553
558 const VECTOR2I& aStart, const VECTOR2I& aMid,
559 const VECTOR2I& aEnd, const VECTOR2I& aCursor,
560 const EDA_IU_SCALE& aIuScale )
561{
562 // 1 mil floor in the caller's units keeps the arc non-degenerate without
563 // snapping small eeschema arcs that are legitimately under 100 mils.
564 int minRadius = EDA_UNIT_UTILS::Mils2IU( aIuScale, 1 );
565 bool movingStart;
566
567 VECTOR2I p1, p2, prev_p1;
568
569 // user is moving p1, we want to move p2 to the new radius.
570
571 if( aStart != aArc.GetStart() )
572 {
573 prev_p1 = aArc.GetStart();
574 p1 = aStart;
575 p2 = aEnd;
576 movingStart = true;
577 }
578 else
579 {
580 prev_p1 = aArc.GetEnd();
581 p1 = aEnd;
582 p2 = aStart;
583 movingStart = false;
584 }
585
586 p1 = p1 - aCenter;
587 p2 = p2 - aCenter;
588
589 if( p1.x == 0 && p1.y == 0 )
590 p1 = prev_p1 - aCenter;
591
592 if( p2.x == 0 && p2.y == 0 )
593 p2 = { 1, 0 };
594
595 double radius = p1.EuclideanNorm();
596
597 if( radius < minRadius )
598 radius = minRadius;
599
600 p1 = aCenter + p1.Resize( KiROUND( radius ) );
601 p2 = aCenter + p2.Resize( KiROUND( radius ) );
602
603 aArc.SetCenter( aCenter );
604
605 if( movingStart )
606 {
607 aArc.SetStart( p1 );
608 aArc.SetEnd( p2 );
609 }
610 else
611 {
612 aArc.SetStart( p2 );
613 aArc.SetEnd( p1 );
614 }
615}
616
617
618static void editArcEndpointKeepCenterAndRadius( EDA_SHAPE& aArc, const VECTOR2I& aCenter, const VECTOR2I& aStart,
619 const VECTOR2I& aMid, const VECTOR2I& aEnd )
620{
621 VECTOR2I p1;
622 bool movingStart = false;
623
624 // User is moving p1, we need to update whichever end that is
625 // The other end won't move.
626
627 if( aStart != aArc.GetStart() )
628 {
629 p1 = aStart;
630 movingStart = true;
631 }
632 else
633 {
634 p1 = aEnd;
635 movingStart = false;
636 }
637
638 // Do not change the radius
639 p1 = p1 - aCenter;
640 p1 = aCenter + p1.Resize( aArc.GetRadius() );
641
642 if( movingStart )
643 {
644 aArc.SetStart( p1 );
645 }
646 else
647 {
648 aArc.SetEnd( p1 );
649 }
650}
651
652
657 const VECTOR2I& aStart, const VECTOR2I& aMid,
658 const VECTOR2I& aEnd, const VECTOR2I& aCursor,
659 const EDA_IU_SCALE& aIuScale )
660{
661 // See EditArcEndpointKeepCenter for why we use the caller's IU scale.
662 int minRadius = EDA_UNIT_UTILS::Mils2IU( aIuScale, 1 );
663
664 // Now, update the edit point position
665 // Express the point in a circle-centered coordinate system.
666 VECTOR2I start = aStart - aCenter;
667 VECTOR2I end = aEnd - aCenter;
668
669 double radius = ( aCursor - aCenter ).EuclideanNorm();
670
671 if( radius < minRadius )
672 radius = minRadius;
673
674 start = start.Resize( KiROUND( radius ) );
675 end = end.Resize( KiROUND( radius ) );
676
677 start = start + aCenter;
678 end = end + aCenter;
679
680 aArc.SetStart( start );
681 aArc.SetEnd( end );
682}
683
684
688static void editArcMidKeepEndpoints( EDA_SHAPE& aArc, const VECTOR2I& aStart, const VECTOR2I& aEnd,
689 const VECTOR2I& aCursor )
690{
691 // Let 'm' be the middle point of the chord between the start and end points
692 VECTOR2I m = ( aStart + aEnd ) / 2;
693
694 // Legal midpoints lie on a vector starting just off the chord midpoint and extending out
695 // past the existing midpoint. We do not allow arc inflection while point editing.
696 const int JUST_OFF = ( aStart - aEnd ).EuclideanNorm() / 100;
697 VECTOR2I v = (VECTOR2I) aArc.GetArcMid() - m;
698 SEG legal( m + v.Resize( JUST_OFF ), m + v.Resize( INT_MAX / 2 ) );
699 VECTOR2I mid = legal.NearestPoint( aCursor );
700
701 aArc.SetArcGeometry( aStart, mid, aEnd );
702}
703
704
706 KIGFX::VIEW_CONTROLS& aViewContols,
707 const EDA_IU_SCALE& aIuScale ) :
708 m_arc( aArc ),
709 m_arcEditMode( aArcEditMode ),
710 m_viewControls( aViewContols ),
711 m_iuScale( aIuScale )
712{
713 wxASSERT( m_arc.GetShape() == SHAPE_T::ARC );
714}
715
716
718{
719 aPoints.AddPoint( m_arc.GetStart() );
720 aPoints.AddPoint( m_arc.GetArcMid() );
721 aPoints.AddPoint( m_arc.GetEnd() );
722 aPoints.AddPoint( m_arc.getCenter() );
723
724 aPoints.AddIndicatorLine( aPoints.Point( ARC_CENTER ), aPoints.Point( ARC_START ) );
725 aPoints.AddIndicatorLine( aPoints.Point( ARC_CENTER ), aPoints.Point( ARC_END ) );
726}
727
728
730{
731 wxCHECK( aPoints.PointsSize() == 4, false );
732
733 aPoints.Point( ARC_START ).SetPosition( m_arc.GetStart() );
734 aPoints.Point( ARC_MID ).SetPosition( m_arc.GetArcMid() );
735 aPoints.Point( ARC_END ).SetPosition( m_arc.GetEnd() );
736 aPoints.Point( ARC_CENTER ).SetPosition( m_arc.getCenter() );
737 return true;
738}
739
740
741void EDA_ARC_POINT_EDIT_BEHAVIOR::UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
742 std::vector<EDA_ITEM*>& aUpdatedItems )
743{
744 CHECK_POINT_COUNT( aPoints, 4 );
745
747 VECTOR2I mid = aPoints.Point( ARC_MID ).GetPosition();
748 VECTOR2I start = aPoints.Point( ARC_START ).GetPosition();
749 VECTOR2I end = aPoints.Point( ARC_END ).GetPosition();
750
751 if( isModified( aEditedPoint, aPoints.Point( ARC_CENTER ) ) )
752 {
753 switch( m_arcEditMode )
754 {
757 break;
758
761 {
762 // Both these modes just move the arc
763 VECTOR2I moveVector = center - m_arc.getCenter();
764
765 m_arc.SetArcGeometry( m_arc.GetStart() + moveVector, m_arc.GetArcMid() + moveVector,
766 m_arc.GetEnd() + moveVector );
767 break;
768 }
769 }
770 }
771 else if( isModified( aEditedPoint, aPoints.Point( ARC_MID ) ) )
772 {
773 const VECTOR2I& cursorPos = m_viewControls.GetCursorPosition( false );
774
775 switch( m_arcEditMode )
776 {
778 editArcMidKeepEndpoints( m_arc, start, end, cursorPos );
779 break;
782 KI_ARC_EDIT::EditArcMidKeepCenter( m_arc, center, start, mid, end, cursorPos, m_iuScale );
783 break;
784 }
785 }
786 else if( isModified( aEditedPoint, aPoints.Point( ARC_START ) )
787 || isModified( aEditedPoint, aPoints.Point( ARC_END ) ) )
788 {
789 const VECTOR2I& cursorPos = m_viewControls.GetCursorPosition();
790
791 switch( m_arcEditMode )
792 {
795 break;
798 break;
800 editArcEndpointKeepTangent( m_arc, center, start, mid, end, cursorPos );
801 break;
802 }
803 }
804}
805
806
808 EDIT_POINTS& aPoints ) const
809{
810 return aPoints.Point( ARC_CENTER ).GetPosition();
811}
812
813
815{
816 aPoints.AddPoint( m_cell.GetEnd() - VECTOR2I( 0, m_cell.GetRectangleHeight() / 2 ) );
817 aPoints.AddPoint( m_cell.GetEnd() - VECTOR2I( m_cell.GetRectangleWidth() / 2, 0 ) );
818}
819
820
822{
823 aPoints.Point( COL_WIDTH ).SetPosition( m_cell.GetEnd() - VECTOR2I( 0, m_cell.GetRectangleHeight() / 2 ) );
824 aPoints.Point( ROW_HEIGHT ).SetPosition( m_cell.GetEnd() - VECTOR2I( m_cell.GetRectangleWidth() / 2, 0 ) );
825 return true;
826}
827
828
ARC_EDIT_MODE
Settings for arc editing.
@ KEEP_ENDPOINTS_OR_START_DIRECTION
Whe editing endpoints, the other end remains in place.
@ KEEP_CENTER_ENDS_ADJUST_ANGLE
When editing endpoints, only the angle is adjusted.
@ KEEP_CENTER_ADJUST_ANGLE_RADIUS
When editing endpoints, the angle and radius are adjusted.
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:68
double Sin() const
Definition eda_angle.h:178
double Cos() const
Definition eda_angle.h:197
EDA_ARC_POINT_EDIT_BEHAVIOR(EDA_SHAPE &aArc, const ARC_EDIT_MODE &aArcEditMode, KIGFX::VIEW_CONTROLS &aViewContols, const EDA_IU_SCALE &aIuScale)
const ARC_EDIT_MODE & m_arcEditMode
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
OPT_VECTOR2I Get45DegreeConstrainer(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints) const override
Get the 45-degree constrainer for the item, when the given point is moved.
KIGFX::VIEW_CONTROLS & m_viewControls
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
OPT_VECTOR2I Get45DegreeConstrainer(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints) const override
Get the 45-degree constrainer for the item, when the given point is moved.
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
EDA_ANGLE parametricAngleOf(const VECTOR2I &aWorldPt) const
Inverse: the parametric angle of a world-space point relative to this ellipse.
VECTOR2I evaluateAt(const EDA_ANGLE &aTheta) const
World-space point on the ellipse at the given parametric angle.
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
OPT_VECTOR2I Get45DegreeConstrainer(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints) const override
Get the 45-degree constrainer for the item, when the given point is moved.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void UpdateItem(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints, COMMIT &aCommit, std::vector< EDA_ITEM * > &aUpdatedItems) override
Update the item with the new positions of the edit points.
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:244
void SetCenter(const VECTOR2I &aCenter)
int GetRadius() const
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:194
VECTOR2I GetArcMid() const
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
bool UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
void SetDragPolicy(std::unique_ptr< POLYGON_EDGE_DRAG_POLICY > aPolicy)
EDIT_POINTS is a VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them.
unsigned int PointsSize() const
Return number of stored EDIT_POINTs.
void AddPoint(const EDIT_POINT &aPoint)
Add an EDIT_POINT.
void Clear()
Clear all stored EDIT_POINTs and EDIT_LINEs.
EDIT_POINT * Next(const EDIT_POINT &aPoint, bool aTraverseContours=true)
Return the point that is before the given point in the list.
EDIT_LINE & Line(unsigned int aIndex)
bool IsContourEnd(int aPointIdx) const
Check is a point with given index is a contour finish.
void AddIndicatorLine(EDIT_POINT &aOrigin, EDIT_POINT &aEnd)
Adds an EDIT_LINE that is shown as an indicator, rather than an editable line (no center point drag,...
void AddBreak()
Adds a break, indicating the end of a contour.
int GetContourStartIdx(int aPointIdx) const
Return index of the contour origin for a point with given index.
unsigned int LinesSize() const
Return number of stored EDIT_LINEs.
EDIT_POINT & Point(unsigned int aIndex)
void AddLine(const EDIT_LINE &aLine)
Adds an EDIT_LINE.
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
Plain ellipse / elliptical-arc data.
Definition ellipse.h:32
VECTOR2< NumericType > GetPointAtAngle(EDA_ANGLE angle) const
Get the point on the ellipse at a given angle.
Definition ellipse.cpp:90
EDA_ANGLE GetAngleAtPoint(const VECTOR2< NumericType > &aPt) const
Get the parametric angle of a point on the ellipse.
Definition ellipse.cpp:109
VECTOR2< NumericType > Center
Definition ellipse.h:101
An interface for classes handling user events controlling the view behavior such as zooming,...
static bool isModified(const EDIT_POINT &aEditedPoint, const EDIT_POINT &aPoint)
Checks if two points are the same instance - which means the point is being edited.
static void UpdateOutlineFromPoints(SHAPE_POLY_SET &aOutline, const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints)
Update the polygon outline with the new positions of the edit points.
static void UpdatePointsFromOutline(const SHAPE_POLY_SET &aOutline, EDIT_POINTS &aPoints)
Update the edit points with the current polygon outline.
void FinalizeItem(EDIT_POINTS &aPoints, COMMIT &aCommit) override
Finalize the edit operation.
static void BuildForPolyOutline(EDIT_POINTS &aPoints, const SHAPE_POLY_SET &aOutline)
Build the edit points for the given polygon outline.
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:76
VECTOR2I::extended_type ecoord
Definition seg.h:40
VECTOR2I B
Definition seg.h:46
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition seg.cpp:629
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition seg.h:216
Represent a set of closed polygons.
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
int TotalVertices() const
Return total number of vertices stored in the set.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
CONST_ITERATOR CIterateWithHoles(int aOutline) const
Define a general 2D-vector/point.
Definition vector2d.h:67
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:72
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:381
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
@ RADIANS_T
Definition eda_angle.h:32
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
@ ELLIPSE_ARC
Definition eda_shape.h:53
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition eda_units.h:171
void EditArcEndpointKeepCenter(EDA_SHAPE &aArc, const VECTOR2I &aCenter, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, const VECTOR2I &aCursor, const EDA_IU_SCALE &aIuScale)
Move an arc endpoint around the existing center, pulling the opposite endpoint along to keep the radi...
void EditArcMidKeepCenter(EDA_SHAPE &aArc, const VECTOR2I &aCenter, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, const VECTOR2I &aCursor, const EDA_IU_SCALE &aIuScale)
Move the mid point of an arc while keeping the center, rotating the endpoints onto the new radius.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
static void editArcEndpointKeepCenterAndRadius(EDA_SHAPE &aArc, const VECTOR2I &aCenter, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
ARC_EDIT_MODE IncrementArcEditMode(ARC_EDIT_MODE aMode)
static void editArcCenterKeepEndpoints(EDA_SHAPE &aArc, const VECTOR2I &aCenter, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Move the arc center but keep endpoint locations.
static void editArcMidKeepEndpoints(EDA_SHAPE &aArc, const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCursor)
Move the mid point of the arc, while keeping the angle.
static void editArcEndpointKeepTangent(EDA_SHAPE &aArc, const VECTOR2I &aCenter, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, const VECTOR2I &aCursor)
Move an end point of the arc, while keeping the tangent at the other endpoint.
#define CHECK_POINT_COUNT(aPoints, aExpected)
#define CHECK_POINT_COUNT_GE(aPoints, aExpected)
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:35
VECTOR3I expected(15, 30, 45)
VECTOR3I v1(5, 5, 5)
VECTOR2I center
int radius
VECTOR2I end
VECTOR2I v2(1, 0)
VECTOR2I v4(1, 1)
VECTOR2I v3(-2, 1)
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682