KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_point_editor.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 (C) 2013-2021 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <functional>
27#include <memory>
28
29using namespace std::placeholders;
30#include <advanced_config.h>
31#include <kiplatform/ui.h>
32#include <view/view_controls.h>
36#include <geometry/seg.h>
38#include <confirm.h>
39#include <tool/tool_manager.h>
42#include <tools/pcb_actions.h>
48#include <board_commit.h>
49#include <pcb_edit_frame.h>
50#include <pcb_reference_image.h>
51#include <pcb_generator.h>
52#include <pcb_dimension.h>
53#include <pcb_textbox.h>
54#include <pcb_tablecell.h>
55#include <pcb_table.h>
56#include <pad.h>
57#include <zone.h>
58#include <footprint.h>
61#include <progress_reporter.h>
62
63const unsigned int PCB_POINT_EDITOR::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
64
65// Few constants to avoid using bare numbers for point indices
67{
73
74 RECT_MAX_POINTS, // Must be last
75};
76
77
79{
81};
82
83
85{
92
97};
98
99
102{
105};
106
107
109{
110public:
112 m_rectangle( aRectangle )
113 {
114 wxASSERT( m_rectangle.GetShape() == SHAPE_T::RECTANGLE );
115 }
116
121 static void MakePoints( const PCB_SHAPE& aRectangle, EDIT_POINTS& aPoints )
122 {
123 wxCHECK( aRectangle.GetShape() == SHAPE_T::RECTANGLE, /* void */ );
124
125 VECTOR2I topLeft = aRectangle.GetTopLeft();
126 VECTOR2I botRight = aRectangle.GetBotRight();
127
128 aPoints.SetSwapX( topLeft.x > botRight.x );
129 aPoints.SetSwapY( topLeft.y > botRight.y );
130
131 if( aPoints.SwapX() )
132 std::swap( topLeft.x, botRight.x );
133
134 if( aPoints.SwapY() )
135 std::swap( topLeft.y, botRight.y );
136
137 aPoints.AddPoint( topLeft );
138 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
139 aPoints.AddPoint( botRight );
140 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
141 aPoints.AddPoint( aRectangle.GetCenter() );
142
143 aPoints.AddLine( aPoints.Point( RECT_TOP_LEFT ), aPoints.Point( RECT_TOP_RIGHT ) );
144 aPoints.Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_TOP ) ) );
145 aPoints.AddLine( aPoints.Point( RECT_TOP_RIGHT ), aPoints.Point( RECT_BOT_RIGHT ) );
146 aPoints.Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_RIGHT ) ) );
147 aPoints.AddLine( aPoints.Point( RECT_BOT_RIGHT ), aPoints.Point( RECT_BOT_LEFT ) );
148 aPoints.Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_BOT ) ) );
149 aPoints.AddLine( aPoints.Point( RECT_BOT_LEFT ), aPoints.Point( RECT_TOP_LEFT ) );
150 aPoints.Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( aPoints.Line( RECT_LEFT ) ) );
151 }
152
153 static void UpdateItem( PCB_SHAPE& aRectangle, const EDIT_POINT& aEditedPoint,
154 EDIT_POINTS& aPoints )
155 {
156 // You can have more points if your item wants to have more points
157 // (this class assumes the rect points come first, but that can be changed)
159
160 auto setLeft =
161 [&]( int left )
162 {
163 aPoints.SwapX() ? aRectangle.SetRight( left ) : aRectangle.SetLeft( left );
164 };
165 auto setRight =
166 [&]( int right )
167 {
168 aPoints.SwapX() ? aRectangle.SetLeft( right ) : aRectangle.SetRight( right );
169 };
170 auto setTop =
171 [&]( int top )
172 {
173 aPoints.SwapY() ? aRectangle.SetBottom( top ) : aRectangle.SetTop( top );
174 };
175 auto setBottom =
176 [&]( int bottom )
177 {
178 aPoints.SwapY() ? aRectangle.SetTop( bottom ) : aRectangle.SetBottom( bottom );
179 };
180
181 VECTOR2I topLeft = aPoints.Point( RECT_TOP_LEFT ).GetPosition();
182 VECTOR2I topRight = aPoints.Point( RECT_TOP_RIGHT ).GetPosition();
183 VECTOR2I botLeft = aPoints.Point( RECT_BOT_LEFT ).GetPosition();
184 VECTOR2I botRight = aPoints.Point( RECT_BOT_RIGHT ).GetPosition();
185
186 PinEditedCorner( aEditedPoint, aPoints, topLeft, topRight, botLeft, botRight );
187
188 if( isModified( aEditedPoint, aPoints.Point( RECT_TOP_LEFT ) )
189 || isModified( aEditedPoint, aPoints.Point( RECT_TOP_RIGHT ) )
190 || isModified( aEditedPoint, aPoints.Point( RECT_BOT_RIGHT ) )
191 || isModified( aEditedPoint, aPoints.Point( RECT_BOT_LEFT ) ) )
192 {
193 setTop( topLeft.y );
194 setLeft( topLeft.x );
195 setRight( botRight.x );
196 setBottom( botRight.y );
197 }
198 else if( isModified( aEditedPoint, aPoints.Point( RECT_CENTER ) ) )
199 {
200 const VECTOR2I moveVector =
201 aPoints.Point( RECT_CENTER ).GetPosition() - aRectangle.GetCenter();
202 aRectangle.Move( moveVector );
203 }
204 else if( isModified( aEditedPoint, aPoints.Line( RECT_TOP ) ) )
205 {
206 setTop( topLeft.y );
207 }
208 else if( isModified( aEditedPoint, aPoints.Line( RECT_LEFT ) ) )
209 {
210 setLeft( topLeft.x );
211 }
212 else if( isModified( aEditedPoint, aPoints.Line( RECT_BOT ) ) )
213 {
214 setBottom( botRight.y );
215 }
216 else if( isModified( aEditedPoint, aPoints.Line( RECT_RIGHT ) ) )
217 {
218 setRight( botRight.x );
219 }
220
221 for( unsigned i = 0; i < aPoints.LinesSize(); ++i )
222 {
223 if( !isModified( aEditedPoint, aPoints.Line( i ) ) )
224 {
225 aPoints.Line( i ).SetConstraint( new EC_PERPLINE( aPoints.Line( i ) ) );
226 }
227 }
228 }
229
230 static void UpdatePoints( PCB_SHAPE& aRectangle, EDIT_POINTS& aPoints )
231 {
232 wxCHECK( aPoints.PointsSize() >= RECT_MAX_POINTS, /* void */ );
233
234 VECTOR2I topLeft = aRectangle.GetTopLeft();
235 VECTOR2I botRight = aRectangle.GetBotRight();
236
237 aPoints.SetSwapX( topLeft.x > botRight.x );
238 aPoints.SetSwapY( topLeft.y > botRight.y );
239
240 if( aPoints.SwapX() )
241 std::swap( topLeft.x, botRight.x );
242
243 if( aPoints.SwapY() )
244 std::swap( topLeft.y, botRight.y );
245
246 aPoints.Point( RECT_TOP_LEFT ).SetPosition( topLeft );
247 aPoints.Point( RECT_TOP_RIGHT ).SetPosition( botRight.x, topLeft.y );
248 aPoints.Point( RECT_BOT_RIGHT ).SetPosition( botRight );
249 aPoints.Point( RECT_BOT_LEFT ).SetPosition( topLeft.x, botRight.y );
250 aPoints.Point( RECT_CENTER ).SetPosition( aRectangle.GetCenter() );
251 }
252
253 void MakePoints( EDIT_POINTS& aPoints ) override
254 {
255 // Just call the static helper
256 MakePoints( m_rectangle, aPoints );
257 }
258
259 void UpdatePoints( EDIT_POINTS& aPoints ) override
260 {
261 UpdatePoints( m_rectangle, aPoints );
262 }
263
264 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
265 std::vector<EDA_ITEM*>& aUpdatedItems ) override
266 {
267 UpdateItem( m_rectangle, aEditedPoint, aPoints );
268 }
269
283 static void PinEditedCorner( const EDIT_POINT& aEditedPoint, const EDIT_POINTS& aEditPoints,
284 VECTOR2I& aTopLeft, VECTOR2I& aTopRight, VECTOR2I& aBotLeft,
285 VECTOR2I& aBotRight, const VECTOR2I& aHole = { 0, 0 },
286 const VECTOR2I& aHoleSize = { 0, 0 } )
287 {
288 int minWidth = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 1 );
289 int minHeight = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 1 );
290
291 if( isModified( aEditedPoint, aEditPoints.Point( RECT_TOP_LEFT ) ) )
292 {
293 if( aHoleSize.x )
294 {
295 // pin edited point to the top/left of the hole
296 aTopLeft.x = std::min( aTopLeft.x, aHole.x - aHoleSize.x / 2 - minWidth );
297 aTopLeft.y = std::min( aTopLeft.y, aHole.y - aHoleSize.y / 2 - minHeight );
298 }
299 else
300 {
301 // pin edited point within opposite corner
302 aTopLeft.x = std::min( aTopLeft.x, aBotRight.x - minWidth );
303 aTopLeft.y = std::min( aTopLeft.y, aBotRight.y - minHeight );
304 }
305
306 // push edited point edges to adjacent corners
307 aTopRight.y = aTopLeft.y;
308 aBotLeft.x = aTopLeft.x;
309 }
310 else if( isModified( aEditedPoint, aEditPoints.Point( RECT_TOP_RIGHT ) ) )
311 {
312 if( aHoleSize.x )
313 {
314 // pin edited point to the top/right of the hole
315 aTopRight.x = std::max( aTopRight.x, aHole.x + aHoleSize.x / 2 + minWidth );
316 aTopRight.y = std::min( aTopRight.y, aHole.y - aHoleSize.y / 2 - minHeight );
317 }
318 else
319 {
320 // pin edited point within opposite corner
321 aTopRight.x = std::max( aTopRight.x, aBotLeft.x + minWidth );
322 aTopRight.y = std::min( aTopRight.y, aBotLeft.y - minHeight );
323 }
324
325 // push edited point edges to adjacent corners
326 aTopLeft.y = aTopRight.y;
327 aBotRight.x = aTopRight.x;
328 }
329 else if( isModified( aEditedPoint, aEditPoints.Point( RECT_BOT_LEFT ) ) )
330 {
331 if( aHoleSize.x )
332 {
333 // pin edited point to the bottom/left of the hole
334 aBotLeft.x = std::min( aBotLeft.x, aHole.x - aHoleSize.x / 2 - minWidth );
335 aBotLeft.y = std::max( aBotLeft.y, aHole.y + aHoleSize.y / 2 + minHeight );
336 }
337 else
338 {
339 // pin edited point within opposite corner
340 aBotLeft.x = std::min( aBotLeft.x, aTopRight.x - minWidth );
341 aBotLeft.y = std::max( aBotLeft.y, aTopRight.y + minHeight );
342 }
343
344 // push edited point edges to adjacent corners
345 aBotRight.y = aBotLeft.y;
346 aTopLeft.x = aBotLeft.x;
347 }
348 else if( isModified( aEditedPoint, aEditPoints.Point( RECT_BOT_RIGHT ) ) )
349 {
350 if( aHoleSize.x )
351 {
352 // pin edited point to the bottom/right of the hole
353 aBotRight.x = std::max( aBotRight.x, aHole.x + aHoleSize.x / 2 + minWidth );
354 aBotRight.y = std::max( aBotRight.y, aHole.y + aHoleSize.y / 2 + minHeight );
355 }
356 else
357 {
358 // pin edited point within opposite corner
359 aBotRight.x = std::max( aBotRight.x, aTopLeft.x + minWidth );
360 aBotRight.y = std::max( aBotRight.y, aTopLeft.y + minHeight );
361 }
362
363 // push edited point edges to adjacent corners
364 aBotLeft.y = aBotRight.y;
365 aTopRight.x = aBotRight.x;
366 }
367 else if( isModified( aEditedPoint, aEditPoints.Line( RECT_TOP ) ) )
368 {
369 aTopLeft.y = std::min( aTopLeft.y, aBotRight.y - minHeight );
370 }
371 else if( isModified( aEditedPoint, aEditPoints.Line( RECT_LEFT ) ) )
372 {
373 aTopLeft.x = std::min( aTopLeft.x, aBotRight.x - minWidth );
374 }
375 else if( isModified( aEditedPoint, aEditPoints.Line( RECT_BOT ) ) )
376 {
377 aBotRight.y = std::max( aBotRight.y, aTopLeft.y + minHeight );
378 }
379 else if( isModified( aEditedPoint, aEditPoints.Line( RECT_RIGHT ) ) )
380 {
381 aBotRight.x = std::max( aBotRight.x, aTopLeft.x + minWidth );
382 }
383 }
384
385private:
387};
388
389
391{
392public:
394 POLYGON_POINT_EDIT_BEHAVIOR( *aZone.Outline() ),
395 m_zone( aZone )
396 {
397 }
398
399 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
400 std::vector<EDA_ITEM*>& aUpdatedItems ) override
401 {
402 m_zone.UnFill();
403
404 // Defer to the base class to update the polygon
405 POLYGON_POINT_EDIT_BEHAVIOR::UpdateItem( aEditedPoint, aPoints, aCommit, aUpdatedItems );
406
408 }
409
410private:
412};
413
414
416{
418 {
419 REFIMG_ORIGIN = RECT_CENTER, // Reuse the center point fo rthe transform origin
420
422 };
423
424public:
426 m_refImage( aRefImage )
427 {
428 }
429
430 void MakePoints( EDIT_POINTS& aPoints ) override
431 {
433
434 const VECTOR2I topLeft = refImage.GetPosition() - refImage.GetSize() / 2;
435 const VECTOR2I botRight = refImage.GetPosition() + refImage.GetSize() / 2;
436
437 aPoints.AddPoint( topLeft );
438 aPoints.AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
439 aPoints.AddPoint( botRight );
440 aPoints.AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
441
442 aPoints.AddPoint( refImage.GetPosition() + refImage.GetTransformOriginOffset() );
443 }
444
445 void UpdatePoints( EDIT_POINTS& aPoints ) override
446 {
448
450
451 const VECTOR2I topLeft = refImage.GetPosition() - refImage.GetSize() / 2;
452 const VECTOR2I botRight = refImage.GetPosition() + refImage.GetSize() / 2;
453
454 aPoints.Point( RECT_TOP_LEFT ).SetPosition( topLeft );
455 aPoints.Point( RECT_TOP_RIGHT ).SetPosition( botRight.x, topLeft.y );
456 aPoints.Point( RECT_BOT_RIGHT ).SetPosition( botRight );
457 aPoints.Point( RECT_BOT_LEFT ).SetPosition( topLeft.x, botRight.y );
458
459 aPoints.Point( REFIMG_ORIGIN ).SetPosition( refImage.GetPosition() + refImage.GetTransformOriginOffset() );
460 }
461
462 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
463 std::vector<EDA_ITEM*>& aUpdatedItems ) override
464 {
466
468
469 const VECTOR2I topLeft = aPoints.Point( RECT_TOP_LEFT ).GetPosition();
470 const VECTOR2I topRight = aPoints.Point( RECT_TOP_RIGHT ).GetPosition();
471 const VECTOR2I botRight = aPoints.Point( RECT_BOT_RIGHT ).GetPosition();
472 const VECTOR2I botLeft = aPoints.Point( RECT_BOT_LEFT ).GetPosition();
473 const VECTOR2I xfrmOrigin = aPoints.Point( REFIMG_ORIGIN ).GetPosition();
474
475 if( isModified( aEditedPoint, aPoints.Point( REFIMG_ORIGIN ) ) )
476 {
477 // Moving the transform origin
478 // As the other points didn't move, we can get the image extent from them
479 const VECTOR2I newOffset = xfrmOrigin - ( topLeft + botRight ) / 2;
480 refImage.SetTransformOriginOffset( newOffset );
481 }
482 else
483 {
484 const VECTOR2I oldOrigin = m_refImage.GetPosition() + refImage.GetTransformOriginOffset();
485 const VECTOR2I oldSize = refImage.GetSize();
486 const VECTOR2I pos = refImage.GetPosition();
487
488 OPT_VECTOR2I newCorner;
489 VECTOR2I oldCorner = pos;
490
491 if( isModified( aEditedPoint, aPoints.Point( RECT_TOP_LEFT ) ) )
492 {
493 newCorner = topLeft;
494 oldCorner -= oldSize / 2;
495 }
496 else if( isModified( aEditedPoint, aPoints.Point( RECT_TOP_RIGHT ) ) )
497 {
498 newCorner = topRight;
499 oldCorner -= VECTOR2I( -oldSize.x, oldSize.y ) / 2;
500 }
501 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOT_LEFT ) ) )
502 {
503 newCorner = botLeft;
504 oldCorner -= VECTOR2I( oldSize.x, -oldSize.y ) / 2;
505 }
506 else if( isModified( aEditedPoint, aPoints.Point( RECT_BOT_RIGHT ) ) )
507 {
508 newCorner = botRight;
509 oldCorner += oldSize / 2;
510 }
511
512 if( newCorner )
513 {
514 // Turn in the respective vectors from the origin
515 *newCorner -= xfrmOrigin;
516 oldCorner -= oldOrigin;
517
518 // If we tried to cross the origin, clamp it to stop it
519 if( sign( newCorner->x ) != sign( oldCorner.x )
520 || sign( newCorner->y ) != sign( oldCorner.y ) )
521 {
522 *newCorner = VECTOR2I( 0, 0 );
523 }
524
525 const double newLength = newCorner->EuclideanNorm();
526 const double oldLength = oldCorner.EuclideanNorm();
527
528 double ratio = oldLength > 0 ? ( newLength / oldLength ) : 1.0;
529
530 // Clamp the scaling to a minimum of 50 mils
531 VECTOR2I newSize = oldSize * ratio;
532 double newWidth = std::max( newSize.x, EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 50 ) );
533 double newHeight = std::max( newSize.y, EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 50 ) );
534 ratio = std::min( newWidth / oldSize.x, newHeight / oldSize.y );
535
536 // Also handles the origin offset
537 refImage.SetImageScale( refImage.GetImageScale() * ratio );
538 }
539 }
540 }
541
542private:
544};
545
546
548{
549public:
552 m_cell( aCell )
553 {
554 }
555
556 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
557 std::vector<EDA_ITEM*>& aUpdatedItems ) override
558 {
560
561 PCB_TABLE& table = static_cast<PCB_TABLE&>( *m_cell.GetParent() );
562 aCommit.Modify( &table );
563 aUpdatedItems.push_back( &table );
564
566 {
567 if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
568 {
569 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
570
571 int colWidth = std::abs( m_cell.GetRectangleHeight() );
572
573 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
574 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
575
576 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
577 }
578 else if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
579 {
580 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
581
582 int rowHeight = m_cell.GetRectangleWidth();
583
584 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
585 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
586
587 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
588 }
589 }
590 else
591 {
592 if( isModified( aEditedPoint, aPoints.Point( COL_WIDTH ) ) )
593 {
594 m_cell.SetEnd( VECTOR2I( aPoints.Point( COL_WIDTH ).GetX(), m_cell.GetEndY() ) );
595
596 int colWidth = m_cell.GetRectangleWidth();
597
598 for( int ii = 0; ii < m_cell.GetColSpan() - 1; ++ii )
599 colWidth -= table.GetColWidth( m_cell.GetColumn() + ii );
600
601 table.SetColWidth( m_cell.GetColumn() + m_cell.GetColSpan() - 1, colWidth );
602 }
603 else if( isModified( aEditedPoint, aPoints.Point( ROW_HEIGHT ) ) )
604 {
605 m_cell.SetEnd( VECTOR2I( m_cell.GetEndX(), aPoints.Point( ROW_HEIGHT ).GetY() ) );
606
607 int rowHeight = m_cell.GetRectangleHeight();
608
609 for( int ii = 0; ii < m_cell.GetRowSpan() - 1; ++ii )
610 rowHeight -= table.GetRowHeight( m_cell.GetRow() + ii );
611
612 table.SetRowHeight( m_cell.GetRow() + m_cell.GetRowSpan() - 1, rowHeight );
613 }
614 }
615
616 table.Normalize();
617 }
618
619private:
621};
622
623
625{
626public:
628 m_pad( aPad ),
629 m_layer( aLayer )
630 {}
631
632 void MakePoints( EDIT_POINTS& aPoints ) override
633 {
634 VECTOR2I shapePos = m_pad.ShapePos( m_layer );
635 VECTOR2I halfSize( m_pad.GetSize( m_layer ).x / 2, m_pad.GetSize( m_layer ).y / 2 );
636
637 if( m_pad.IsLocked() )
638 return;
639
640 switch( m_pad.GetShape( m_layer ) )
641 {
642 case PAD_SHAPE::CIRCLE:
643 aPoints.AddPoint( VECTOR2I( shapePos.x + halfSize.x, shapePos.y ) );
644 break;
645
646 case PAD_SHAPE::OVAL:
647 case PAD_SHAPE::TRAPEZOID:
648 case PAD_SHAPE::RECTANGLE:
649 case PAD_SHAPE::ROUNDRECT:
650 case PAD_SHAPE::CHAMFERED_RECT:
651 {
653 break;
654
656 std::swap( halfSize.x, halfSize.y );
657
658 // It's important to fill these according to the RECT indices
659 aPoints.AddPoint( shapePos - halfSize );
660 aPoints.AddPoint( VECTOR2I( shapePos.x + halfSize.x, shapePos.y - halfSize.y ) );
661 aPoints.AddPoint( shapePos + halfSize );
662 aPoints.AddPoint( VECTOR2I( shapePos.x - halfSize.x, shapePos.y + halfSize.y ) );
663 }
664 break;
665
666 default: // suppress warnings
667 break;
668 }
669 }
670
671 void UpdatePoints( EDIT_POINTS& aPoints ) override
672 {
673 bool locked = m_pad.GetParent() && m_pad.IsLocked();
674 VECTOR2I shapePos = m_pad.ShapePos( m_layer );
675 VECTOR2I halfSize( m_pad.GetSize( m_layer ).x / 2, m_pad.GetSize( m_layer ).y / 2 );
676
677 switch( m_pad.GetShape( m_layer ) )
678 {
679 case PAD_SHAPE::CIRCLE:
680 {
681 int target = locked ? 0 : 1;
682
683 // Careful; pad shape is mutable...
684 if( int( aPoints.PointsSize() ) != target )
685 {
686 aPoints.Clear();
687 MakePoints( aPoints );
688 }
689 else if( target == 1 )
690 {
691 shapePos.x += halfSize.x;
692 aPoints.Point( 0 ).SetPosition( shapePos );
693 }
694 }
695 break;
696
697 case PAD_SHAPE::OVAL:
698 case PAD_SHAPE::TRAPEZOID:
699 case PAD_SHAPE::RECTANGLE:
700 case PAD_SHAPE::ROUNDRECT:
701 case PAD_SHAPE::CHAMFERED_RECT:
702 {
703 // Careful; pad shape and orientation are mutable...
704 int target = locked || !m_pad.GetOrientation().IsCardinal() ? 0 : 4;
705
706 if( int( aPoints.PointsSize() ) != target )
707 {
708 aPoints.Clear();
709 MakePoints( aPoints );
710 }
711 else if( target == 4 )
712 {
714 std::swap( halfSize.x, halfSize.y );
715
716 aPoints.Point( RECT_TOP_LEFT ).SetPosition( shapePos - halfSize );
717 aPoints.Point( RECT_TOP_RIGHT ).SetPosition( VECTOR2I( shapePos.x + halfSize.x,
718 shapePos.y - halfSize.y ) );
719 aPoints.Point( RECT_BOT_RIGHT ).SetPosition( shapePos + halfSize );
720 aPoints.Point( RECT_BOT_LEFT ).SetPosition( VECTOR2I( shapePos.x - halfSize.x,
721 shapePos.y + halfSize.y ) );
722 }
723
724 break;
725 }
726
727 default: // suppress warnings
728 break;
729 }
730 }
731
732 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
733 std::vector<EDA_ITEM*>& aUpdatedItems ) override
734 {
735 switch( m_pad.GetShape( m_layer ) )
736 {
737 case PAD_SHAPE::CIRCLE:
738 {
739 VECTOR2I end = aPoints.Point( 0 ).GetPosition();
740 int diameter = 2 * ( end - m_pad.GetPosition() ).EuclideanNorm();
741
742 m_pad.SetSize( m_layer, VECTOR2I( diameter, diameter ) );
743 break;
744 }
745
746 case PAD_SHAPE::OVAL:
747 case PAD_SHAPE::TRAPEZOID:
748 case PAD_SHAPE::RECTANGLE:
749 case PAD_SHAPE::ROUNDRECT:
750 case PAD_SHAPE::CHAMFERED_RECT:
751 {
752 VECTOR2I topLeft = aPoints.Point( RECT_TOP_LEFT ).GetPosition();
753 VECTOR2I topRight = aPoints.Point( RECT_TOP_RIGHT ).GetPosition();
754 VECTOR2I botLeft = aPoints.Point( RECT_BOT_LEFT ).GetPosition();
755 VECTOR2I botRight = aPoints.Point( RECT_BOT_RIGHT ).GetPosition();
756 VECTOR2I holeCenter = m_pad.GetPosition();
757 VECTOR2I holeSize = m_pad.GetDrillSize();
758
759 RECTANGLE_POINT_EDIT_BEHAVIOR::PinEditedCorner( aEditedPoint, aPoints, topLeft, topRight,
760 botLeft, botRight, holeCenter, holeSize );
761
763 || ( m_pad.GetDrillSize().x && m_pad.GetDrillSize().y ) )
764 {
765 // Keep hole pinned at the current location; adjust the pad around the hole
766
768 int dist[4];
769
770 if( isModified( aEditedPoint, aPoints.Point( RECT_TOP_LEFT ) )
771 || isModified( aEditedPoint, aPoints.Point( RECT_BOT_RIGHT ) ) )
772 {
773 dist[0] = center.x - topLeft.x;
774 dist[1] = center.y - topLeft.y;
775 dist[2] = botRight.x - center.x;
776 dist[3] = botRight.y - center.y;
777 }
778 else
779 {
780 dist[0] = center.x - botLeft.x;
781 dist[1] = center.y - topRight.y;
782 dist[2] = topRight.x - center.x;
783 dist[3] = botLeft.y - center.y;
784 }
785
786 VECTOR2I padSize( dist[0] + dist[2], dist[1] + dist[3] );
787 VECTOR2I deltaOffset( padSize.x / 2 - dist[2], padSize.y / 2 - dist[3] );
788
790 std::swap( padSize.x, padSize.y );
791
792 RotatePoint( deltaOffset, -m_pad.GetOrientation() );
793
794 m_pad.SetSize( m_layer, padSize );
795 m_pad.SetOffset( m_layer, -deltaOffset );
796 }
797 else
798 {
799 // Keep pad position at the center of the pad shape
800
801 int left, top, right, bottom;
802
803 if( isModified( aEditedPoint, aPoints.Point( RECT_TOP_LEFT ) )
804 || isModified( aEditedPoint, aPoints.Point( RECT_BOT_RIGHT ) ) )
805 {
806 left = topLeft.x;
807 top = topLeft.y;
808 right = botRight.x;
809 bottom = botRight.y;
810 }
811 else
812 {
813 left = botLeft.x;
814 top = topRight.y;
815 right = topRight.x;
816 bottom = botLeft.y;
817 }
818
819 VECTOR2I padSize( abs( right - left ), abs( bottom - top ) );
820
822 std::swap( padSize.x, padSize.y );
823
824 m_pad.SetSize( m_layer, padSize );
825 m_pad.SetPosition( VECTOR2I( ( left + right ) / 2, ( top + bottom ) / 2 ) );
826 }
827 break;
828 }
829 default: // suppress warnings
830 break;
831 }
832 }
833
834private:
837};
838
839
846{
847public:
849 m_generator( aGenerator )
850 {}
851
852 void MakePoints( EDIT_POINTS& aPoints ) override
853 {
854 m_generator.MakeEditPoints( aPoints );
855 }
856
857 void UpdatePoints( EDIT_POINTS& aPoints ) override
858 {
859 m_generator.UpdateEditPoints( aPoints );
860 }
861
862 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
863 std::vector<EDA_ITEM*>& aUpdatedItems ) override
864 {
866 }
867
868private:
870};
871
872
882{
883public:
885 m_dimension( aDimension ),
886 m_originalTextPos( aDimension.GetTextPos() ),
887 m_oldCrossBar( SEG{ aDimension.GetCrossbarStart(), aDimension.GetCrossbarEnd() } )
888 {
889 }
890
892 {
894
895 if( newCrossBar == m_oldCrossBar )
896 {
897 // Crossbar didn't change, text doesn't need to change
898 return;
899 }
900
901 const VECTOR2I newTextPos = getDimensionNewTextPosition();
902 m_dimension.SetTextPos( newTextPos );
903
904 const GR_TEXT_H_ALIGN_T oldJustify = m_dimension.GetHorizJustify();
905
906 // We may need to update the justification if we go past vertical.
907 if( oldJustify == GR_TEXT_H_ALIGN_T::GR_TEXT_H_ALIGN_LEFT
908 || oldJustify == GR_TEXT_H_ALIGN_T::GR_TEXT_H_ALIGN_RIGHT )
909 {
911 const VECTOR2I newProject = newCrossBar.LineProject( newTextPos );
912
913 const VECTOR2I oldProjectedOffset =
914 oldProject - m_oldCrossBar.NearestPoint( oldProject );
915 const VECTOR2I newProjectedOffset = newProject - newCrossBar.NearestPoint( newProject );
916
917 const bool textWasLeftOf = oldProjectedOffset.x < 0
918 || ( oldProjectedOffset.x == 0 && oldProjectedOffset.y > 0 );
919 const bool textIsLeftOf = newProjectedOffset.x < 0
920 || ( newProjectedOffset.x == 0 && newProjectedOffset.y > 0 );
921
922 if( textWasLeftOf != textIsLeftOf )
923 {
924 // Flip whatever the user had set
925 m_dimension.SetHorizJustify( ( oldJustify == GR_TEXT_H_ALIGN_T::GR_TEXT_H_ALIGN_LEFT )
926 ? GR_TEXT_H_ALIGN_T::GR_TEXT_H_ALIGN_RIGHT
927 : GR_TEXT_H_ALIGN_T::GR_TEXT_H_ALIGN_LEFT );
928 }
929 }
930
931 // Update the dimension (again) to ensure the text knockouts are correct
933 }
934
935private:
937 {
939
940 const EDA_ANGLE oldAngle = EDA_ANGLE( m_oldCrossBar.B - m_oldCrossBar.A );
941 const EDA_ANGLE newAngle = EDA_ANGLE( newCrossBar.B - newCrossBar.A );
942 const EDA_ANGLE rotation = oldAngle - newAngle;
943
944 // There are two modes - when the text is between the crossbar points, and when it's not.
946 {
948 const VECTOR2I rotTextOffsetFromCbCenter = GetRotated( m_originalTextPos - m_oldCrossBar.Center(),
949 rotation );
950 const VECTOR2I rotTextOffsetFromCbEnd = GetRotated( m_originalTextPos - cbNearestEndToText, rotation );
951
952 // Which of the two crossbar points is now in the right direction? They could be swapped over now.
953 // If zero-length, doesn't matter, they're the same thing
954 const bool startIsInOffsetDirection = KIGEOM::PointIsInDirection( m_dimension.GetCrossbarStart(),
955 rotTextOffsetFromCbCenter,
956 newCrossBar.Center() );
957
958 const VECTOR2I& newCbRefPt = startIsInOffsetDirection ? m_dimension.GetCrossbarStart()
960
961 // Apply the new offset to the correct crossbar point
962 return newCbRefPt + rotTextOffsetFromCbEnd;
963 }
964
965 // If the text was between the crossbar points, it should stay there, but we need to find a
966 // good place for it. Keep it the same distance from the crossbar line, but rotated as needed.
967
968 const VECTOR2I origTextPointProjected = m_oldCrossBar.NearestPoint( m_originalTextPos );
969 const double oldRatio = KIGEOM::GetLengthRatioFromStart( origTextPointProjected, m_oldCrossBar );
970
971 // Perpendicular from the crossbar line to the text position
972 // We need to keep this length constant
973 const VECTOR2I rotCbNormalToText = GetRotated( m_originalTextPos - origTextPointProjected, rotation );
974
975 const VECTOR2I newProjected = newCrossBar.A + ( newCrossBar.B - newCrossBar.A ) * oldRatio;
976 return newProjected + rotCbNormalToText;
977 }
978
982};
983
984
989{
990public:
992 m_dimension( aDimension )
993 {
994 }
995
996 void MakePoints( EDIT_POINTS& aPoints ) override
997 {
998 aPoints.AddPoint( m_dimension.GetStart() );
999 aPoints.AddPoint( m_dimension.GetEnd() );
1000 aPoints.AddPoint( m_dimension.GetTextPos() );
1002 aPoints.AddPoint( m_dimension.GetCrossbarEnd() );
1003
1006
1008 {
1009 // Dimension height setting - edit points should move only along the feature lines
1011 aPoints.Point( DIM_START ) ) );
1012 aPoints.Point( DIM_CROSSBAREND ).SetConstraint( new EC_LINE( aPoints.Point( DIM_CROSSBAREND ),
1013 aPoints.Point( DIM_END ) ) );
1014 }
1015 }
1016
1017 void UpdatePoints( EDIT_POINTS& aPoints ) override
1018 {
1020
1022 aPoints.Point( DIM_END ).SetPosition( m_dimension.GetEnd() );
1026 }
1027
1028 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
1029 std::vector<EDA_ITEM*>& aUpdatedItems ) override
1030 {
1032
1034 updateAlignedDimension( aEditedPoint, aPoints );
1035 else
1036 updateOrthogonalDimension( aEditedPoint, aPoints );
1037 }
1038
1039 OPT_VECTOR2I Get45DegreeConstrainer( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints ) const override
1040 {
1041 // Constraint for crossbar
1042 if( isModified( aEditedPoint, aPoints.Point( DIM_START ) ) )
1043 return aPoints.Point( DIM_END ).GetPosition();
1044
1045 else if( isModified( aEditedPoint, aPoints.Point( DIM_END ) ) )
1046 return aPoints.Point( DIM_START ).GetPosition();
1047
1048 // No constraint
1049 return aEditedPoint.GetPosition();
1050 }
1051
1052private:
1056 void updateAlignedDimension( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints )
1057 {
1058 DIM_ALIGNED_TEXT_UPDATER textPositionUpdater( m_dimension );
1059
1060 // Check which point is currently modified and updated dimension's points respectively
1061 if( isModified( aEditedPoint, aPoints.Point( DIM_CROSSBARSTART ) ) )
1062 {
1063 VECTOR2D featureLine( aEditedPoint.GetPosition() - m_dimension.GetStart() );
1065
1066 if( featureLine.Cross( crossBar ) > 0 )
1067 m_dimension.SetHeight( -featureLine.EuclideanNorm() );
1068 else
1069 m_dimension.SetHeight( featureLine.EuclideanNorm() );
1070
1072 }
1073 else if( isModified( aEditedPoint, aPoints.Point( DIM_CROSSBAREND ) ) )
1074 {
1075 VECTOR2D featureLine( aEditedPoint.GetPosition() - m_dimension.GetEnd() );
1077
1078 if( featureLine.Cross( crossBar ) > 0 )
1079 m_dimension.SetHeight( -featureLine.EuclideanNorm() );
1080 else
1081 m_dimension.SetHeight( featureLine.EuclideanNorm() );
1082
1084 }
1085 else if( isModified( aEditedPoint, aPoints.Point( DIM_START ) ) )
1086 {
1087 m_dimension.SetStart( aEditedPoint.GetPosition() );
1089
1091 aPoints.Point( DIM_START ) ) );
1092 aPoints.Point( DIM_CROSSBAREND ).SetConstraint( new EC_LINE( aPoints.Point( DIM_CROSSBAREND ),
1093 aPoints.Point( DIM_END ) ) );
1094 }
1095 else if( isModified( aEditedPoint, aPoints.Point( DIM_END ) ) )
1096 {
1097 m_dimension.SetEnd( aEditedPoint.GetPosition() );
1099
1101 aPoints.Point( DIM_START ) ) );
1102 aPoints.Point( DIM_CROSSBAREND ).SetConstraint( new EC_LINE( aPoints.Point( DIM_CROSSBAREND ),
1103 aPoints.Point( DIM_END ) ) );
1104 }
1105 else if( isModified( aEditedPoint, aPoints.Point( DIM_TEXT ) ) )
1106 {
1107 // Force manual mode if we weren't already in it
1108 m_dimension.SetTextPositionMode( DIM_TEXT_POSITION::MANUAL );
1109 m_dimension.SetTextPos( aEditedPoint.GetPosition() );
1111 }
1112
1113 textPositionUpdater.UpdateTextAfterChange();
1114 }
1115
1119 void updateOrthogonalDimension( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints )
1120 {
1121 DIM_ALIGNED_TEXT_UPDATER textPositionUpdater( m_dimension );
1122 PCB_DIM_ORTHOGONAL& orthDimension = static_cast<PCB_DIM_ORTHOGONAL&>( m_dimension );
1123
1124 if( isModified( aEditedPoint, aPoints.Point( DIM_CROSSBARSTART ) )
1125 || isModified( aEditedPoint, aPoints.Point( DIM_CROSSBAREND ) ) )
1126 {
1128
1129 const VECTOR2I& cursorPos = aEditedPoint.GetPosition();
1130
1131 // Find vector from nearest dimension point to edit position
1132 VECTOR2I directionA( cursorPos - m_dimension.GetStart() );
1133 VECTOR2I directionB( cursorPos - m_dimension.GetEnd() );
1134 VECTOR2I direction = ( directionA < directionB ) ? directionA : directionB;
1135
1136 bool vert;
1137 VECTOR2D featureLine( cursorPos - m_dimension.GetStart() );
1138
1139 // Only change the orientation when we move outside the bounds
1140 if( !bounds.Contains( cursorPos ) )
1141 {
1142 // If the dimension is horizontal or vertical, set correct orientation
1143 // otherwise, test if we're left/right of the bounding box or above/below it
1144 if( bounds.GetWidth() == 0 )
1145 vert = true;
1146 else if( bounds.GetHeight() == 0 )
1147 vert = false;
1148 else if( cursorPos.x > bounds.GetLeft() && cursorPos.x < bounds.GetRight() )
1149 vert = false;
1150 else if( cursorPos.y > bounds.GetTop() && cursorPos.y < bounds.GetBottom() )
1151 vert = true;
1152 else
1153 vert = std::abs( direction.y ) < std::abs( direction.x );
1154
1157 }
1158 else
1159 {
1160 vert = orthDimension.GetOrientation() == PCB_DIM_ORTHOGONAL::DIR::VERTICAL;
1161 }
1162
1163 m_dimension.SetHeight( vert ? featureLine.x : featureLine.y );
1164 }
1165 else if( isModified( aEditedPoint, aPoints.Point( DIM_START ) ) )
1166 {
1167 m_dimension.SetStart( aEditedPoint.GetPosition() );
1168 }
1169 else if( isModified( aEditedPoint, aPoints.Point( DIM_END ) ) )
1170 {
1171 m_dimension.SetEnd( aEditedPoint.GetPosition() );
1172 }
1173 else if( isModified( aEditedPoint, aPoints.Point( DIM_TEXT ) ) )
1174 {
1175 // Force manual mode if we weren't already in it
1176 m_dimension.SetTextPositionMode( DIM_TEXT_POSITION::MANUAL );
1177 m_dimension.SetTextPos( VECTOR2I( aEditedPoint.GetPosition() ) );
1178 }
1179
1181
1182 // After recompute, find the new text position
1183 textPositionUpdater.UpdateTextAfterChange();
1184 }
1185
1187};
1188
1189
1191{
1192public:
1194 m_dimension( aDimension )
1195 {}
1196
1197 void MakePoints( EDIT_POINTS& aPoints ) override
1198 {
1199 aPoints.AddPoint( m_dimension.GetStart() );
1200 aPoints.AddPoint( m_dimension.GetEnd() );
1201
1203
1204 aPoints.Point( DIM_END ).SetConstraint(new EC_45DEGREE( aPoints.Point( DIM_END ),
1205 aPoints.Point( DIM_START ) ) );
1207 }
1208
1209 void UpdatePoints( EDIT_POINTS& aPoints ) override
1210 {
1212
1214 aPoints.Point( DIM_END ).SetPosition( m_dimension.GetEnd() );
1215 }
1216
1217 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
1218 std::vector<EDA_ITEM*>& aUpdatedItems ) override
1219 {
1221
1222 if( isModified( aEditedPoint, aPoints.Point( DIM_START ) ) )
1223 m_dimension.SetStart( aEditedPoint.GetPosition() );
1224 else if( isModified( aEditedPoint, aPoints.Point( DIM_END ) ) )
1225 m_dimension.SetEnd( aEditedPoint.GetPosition() );
1226
1228 }
1229
1230 OPT_VECTOR2I Get45DegreeConstrainer( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints ) const override
1231 {
1232 if( isModified( aEditedPoint, aPoints.Point( DIM_END ) ) )
1233 return aPoints.Point( DIM_START ).GetPosition();
1234
1235 return std::nullopt;
1236 }
1237
1238private:
1240};
1241
1242
1244{
1245public:
1247 m_dimension( aDimension )
1248 {}
1249
1250 void MakePoints( EDIT_POINTS& aPoints ) override
1251 {
1252 aPoints.AddPoint( m_dimension.GetStart() );
1253 aPoints.AddPoint( m_dimension.GetEnd() );
1254 aPoints.AddPoint( m_dimension.GetTextPos() );
1255 aPoints.AddPoint( m_dimension.GetKnee() );
1256
1259
1260 aPoints.Point( DIM_KNEE ).SetConstraint( new EC_LINE( aPoints.Point( DIM_START ),
1261 aPoints.Point( DIM_END ) ) );
1263
1264 aPoints.Point( DIM_TEXT ).SetConstraint( new EC_45DEGREE( aPoints.Point( DIM_TEXT ),
1265 aPoints.Point( DIM_KNEE ) ) );
1267 }
1268
1269 void UpdatePoints( EDIT_POINTS& aPoints ) override
1270 {
1272
1274 aPoints.Point( DIM_END ).SetPosition( m_dimension.GetEnd() );
1277 }
1278
1279 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
1280 std::vector<EDA_ITEM*>& aUpdatedItems ) override
1281 {
1283
1284 if( isModified( aEditedPoint, aPoints.Point( DIM_START ) ) )
1285 {
1286 m_dimension.SetStart( aEditedPoint.GetPosition() );
1288
1289 aPoints.Point( DIM_KNEE ).SetConstraint( new EC_LINE( aPoints.Point( DIM_START ),
1290 aPoints.Point( DIM_END ) ) );
1291 }
1292 else if( isModified( aEditedPoint, aPoints.Point( DIM_END ) ) )
1293 {
1294 VECTOR2I oldKnee = m_dimension.GetKnee();
1295
1296 m_dimension.SetEnd( aEditedPoint.GetPosition() );
1298
1299 VECTOR2I kneeDelta = m_dimension.GetKnee() - oldKnee;
1302
1303 aPoints.Point( DIM_KNEE ).SetConstraint( new EC_LINE( aPoints.Point( DIM_START ),
1304 aPoints.Point( DIM_END ) ) );
1305 }
1306 else if( isModified( aEditedPoint, aPoints.Point( DIM_KNEE ) ) )
1307 {
1308 VECTOR2I oldKnee = m_dimension.GetKnee();
1309 VECTOR2I arrowVec = aPoints.Point( DIM_KNEE ).GetPosition() - aPoints.Point( DIM_END ).GetPosition();
1310
1313
1314 VECTOR2I kneeDelta = m_dimension.GetKnee() - oldKnee;
1317 }
1318 else if( isModified( aEditedPoint, aPoints.Point( DIM_TEXT ) ) )
1319 {
1320 m_dimension.SetTextPos( aEditedPoint.GetPosition() );
1322 }
1323 }
1324
1325 OPT_VECTOR2I Get45DegreeConstrainer( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints ) const override
1326 {
1327 if( isModified( aEditedPoint, aPoints.Point( DIM_TEXT ) ) )
1328 return aPoints.Point( DIM_KNEE ).GetPosition();
1329
1330 return std::nullopt;
1331 }
1332
1333private:
1335};
1336
1337
1339{
1340public:
1342 m_dimension( aDimension )
1343 {}
1344
1345 void MakePoints( EDIT_POINTS& aPoints ) override
1346 {
1347 aPoints.AddPoint( m_dimension.GetStart() );
1348 aPoints.AddPoint( m_dimension.GetEnd() );
1349 aPoints.AddPoint( m_dimension.GetTextPos() );
1350
1353
1354 aPoints.Point( DIM_TEXT ).SetConstraint( new EC_45DEGREE( aPoints.Point( DIM_TEXT ),
1355 aPoints.Point( DIM_END ) ) );
1357 }
1358
1359 void UpdatePoints( EDIT_POINTS& aPoints ) override
1360 {
1362
1364 aPoints.Point( DIM_END ).SetPosition( m_dimension.GetEnd() );
1366 }
1367
1368 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
1369 std::vector<EDA_ITEM*>& aUpdatedItems ) override
1370 {
1372
1373 if( isModified( aEditedPoint, aPoints.Point( DIM_START ) ) )
1374 {
1375 m_dimension.SetStart( aEditedPoint.GetPosition() );
1376 }
1377 else if( isModified( aEditedPoint, aPoints.Point( DIM_END ) ) )
1378 {
1379 const VECTOR2I newPoint( aEditedPoint.GetPosition() );
1380 const VECTOR2I delta = newPoint - m_dimension.GetEnd();
1381
1382 m_dimension.SetEnd( newPoint );
1384 }
1385 else if( isModified( aEditedPoint, aPoints.Point( DIM_TEXT ) ) )
1386 {
1387 m_dimension.SetTextPos( aEditedPoint.GetPosition() );
1388 }
1389
1391 }
1392
1393private:
1395};
1396
1397
1402{
1403public:
1405 m_textbox( aTextbox )
1406 {}
1407
1408 void MakePoints( EDIT_POINTS& aPoints ) override
1409 {
1410 if( m_textbox.GetShape() == SHAPE_T::RECTANGLE )
1411 {
1413 }
1414 else
1415 {
1416 // Rotated textboxes are implemented as polygons and these
1417 // aren't currently editable.
1418 }
1419 }
1420
1421 void UpdatePoints( EDIT_POINTS& aPoints ) override
1422 {
1423 // When textboxes are rotated, they act as polygons, not rectangles
1424 const unsigned target = m_textbox.GetShape() == SHAPE_T::RECTANGLE ? TEXTBOX_POINT_COUNT::WHEN_RECTANGLE
1425 : TEXTBOX_POINT_COUNT::WHEN_POLYGON;
1426
1427 // Careful; textbox shape is mutable between cardinal and non-cardinal rotations...
1428 if( aPoints.PointsSize() != target )
1429 {
1430 aPoints.Clear();
1431 MakePoints( aPoints );
1432 return;
1433 }
1434
1435 if( m_textbox.GetShape() == SHAPE_T::RECTANGLE )
1436 {
1437 // Dispatch to the rectangle behavior
1439 }
1440 else if( m_textbox.GetShape() == SHAPE_T::POLY )
1441 {
1442 // Not currently editable while rotated.
1443 }
1444 }
1445
1446 void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
1447 std::vector<EDA_ITEM*>& aUpdatedItems ) override
1448 {
1449 if( m_textbox.GetShape() == SHAPE_T::RECTANGLE )
1450 {
1451 RECTANGLE_POINT_EDIT_BEHAVIOR::UpdateItem( m_textbox, aEditedPoint, aPoints );
1452 }
1453 }
1454
1455private:
1457};
1458
1460 PCB_TOOL_BASE( "pcbnew.PointEditor" ),
1461 m_frame( nullptr ),
1462 m_selectionTool( nullptr ),
1463 m_editedPoint( nullptr ),
1464 m_hoveredPoint( nullptr ),
1465 m_original( VECTOR2I( 0, 0 ) ),
1467 m_altConstrainer( VECTOR2I( 0, 0 ) ),
1468 m_inPointEditorTool( false )
1469{
1470}
1471
1472
1474{
1475 m_frame = getEditFrame<PCB_BASE_FRAME>();
1476 m_editPoints.reset();
1477 m_altConstraint.reset();
1478 getViewControls()->SetAutoPan( false );
1479}
1480
1481
1485static bool canAddCorner( const EDA_ITEM& aItem )
1486{
1487 const KICAD_T type = aItem.Type();
1488
1489 if( type == PCB_ZONE_T )
1490 return true;
1491
1492 if( type == PCB_SHAPE_T )
1493 {
1494 const PCB_SHAPE& shape = static_cast<const PCB_SHAPE&>( aItem );
1495 const SHAPE_T shapeType = shape.GetShape();
1496 return shapeType == SHAPE_T::SEGMENT || shapeType == SHAPE_T::POLY || shapeType == SHAPE_T::ARC;
1497 }
1498
1499 return false;
1500}
1501
1506static bool canChamferCorner( const EDA_ITEM& aItem )
1507{
1508 const auto type = aItem.Type();
1509
1510 // Works only for zones and polygons
1511 if( type == PCB_ZONE_T )
1512 return true;
1513
1514 if( type == PCB_SHAPE_T )
1515 {
1516 const PCB_SHAPE& shape = static_cast<const PCB_SHAPE&>( aItem );
1517 const SHAPE_T shapeType = shape.GetShape();
1518 return shapeType == SHAPE_T::POLY;
1519 }
1520
1521 return false;
1522}
1523
1524
1526{
1527 // Find the selection tool, so they can cooperate
1529
1530 wxASSERT_MSG( m_selectionTool, wxT( "pcbnew.InteractiveSelection tool is not available" ) );
1531
1532 const auto addCornerCondition = [&]( const SELECTION& aSelection ) -> bool
1533 {
1534 const EDA_ITEM* item = aSelection.Front();
1535 return ( item != nullptr ) && canAddCorner( *item );
1536 };
1537
1538 const auto addChamferCondition = [&]( const SELECTION& aSelection ) -> bool
1539 {
1540 const EDA_ITEM* item = aSelection.Front();
1541 return ( item != nullptr ) && canChamferCorner( *item );
1542 };
1543
1544 const auto removeCornerCondition = [&]( const SELECTION& aSelection ) -> bool
1545 {
1546 return PCB_POINT_EDITOR::removeCornerCondition( aSelection );
1547 };
1548
1549 const auto arcIsEdited = [&]( const SELECTION& aSelection ) -> bool
1550 {
1551 const EDA_ITEM* item = aSelection.Front();
1552 return ( item != nullptr ) && ( item->Type() == PCB_SHAPE_T )
1553 && static_cast<const PCB_SHAPE*>( item )->GetShape() == SHAPE_T::ARC;
1554 };
1555
1556 using S_C = SELECTION_CONDITIONS;
1557
1558 auto& menu = m_selectionTool->GetToolMenu().GetMenu();
1559
1560 // clang-format off
1561 menu.AddItem( PCB_ACTIONS::pointEditorAddCorner, S_C::Count( 1 ) && addCornerCondition );
1563 menu.AddItem( PCB_ACTIONS::pointEditorChamferCorner, S_C::Count( 1 ) && addChamferCondition );
1564 menu.AddItem( PCB_ACTIONS::cycleArcEditMode, S_C::Count( 1 ) && arcIsEdited );
1565 // clang-format on
1566
1567 return true;
1568}
1569
1570
1571std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
1572{
1573 std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
1574
1575 if( !aItem )
1576 return points;
1577
1578 // Reset the behaviour and we'll make a new one
1579 m_editorBehavior = nullptr;
1580
1581 switch( aItem->Type() )
1582 {
1584 {
1585 PCB_REFERENCE_IMAGE& refImage = static_cast<PCB_REFERENCE_IMAGE&>( *aItem );
1586 m_editorBehavior = std::make_unique<REFERENCE_IMAGE_POINT_EDIT_BEHAVIOR>( refImage );
1587 break;
1588 }
1589 case PCB_TEXTBOX_T:
1590 {
1591 PCB_TEXTBOX& textbox = static_cast<PCB_TEXTBOX&>( *aItem );
1592 m_editorBehavior = std::make_unique<TEXTBOX_POINT_EDIT_BEHAVIOR>( textbox );
1593 break;
1594 }
1595 case PCB_SHAPE_T:
1596 {
1597 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
1598
1599 switch( shape->GetShape() )
1600 {
1601 case SHAPE_T::SEGMENT:
1602 m_editorBehavior = std::make_unique<EDA_SEGMENT_POINT_EDIT_BEHAVIOR>( *shape );
1603 break;
1604
1605 case SHAPE_T::RECTANGLE:
1606 m_editorBehavior = std::make_unique<RECTANGLE_POINT_EDIT_BEHAVIOR>( *shape );
1607 break;
1608
1609 case SHAPE_T::ARC:
1610 m_editorBehavior = std::make_unique<EDA_ARC_POINT_EDIT_BEHAVIOR>(
1611 *shape, m_arcEditMode, *getViewControls() );
1612 break;
1613
1614 case SHAPE_T::CIRCLE:
1615 m_editorBehavior = std::make_unique<EDA_CIRCLE_POINT_EDIT_BEHAVIOR>( *shape );
1616 break;
1617
1618 case SHAPE_T::POLY:
1619 m_editorBehavior = std::make_unique<EDA_POLYGON_POINT_EDIT_BEHAVIOR>( *shape );
1620 break;
1621
1622 case SHAPE_T::BEZIER:
1623 m_editorBehavior = std::make_unique<EDA_BEZIER_POINT_EDIT_BEHAVIOR>(
1624 *shape, board()->GetDesignSettings().m_MaxError );
1625 break;
1626
1627 default: // suppress warnings
1628 break;
1629 }
1630
1631 break;
1632 }
1633
1634 case PCB_TABLECELL_T:
1635 {
1636 PCB_TABLECELL* cell = static_cast<PCB_TABLECELL*>( aItem );
1637
1638 // No support for point-editing of a rotated table
1639 if( cell->GetShape() == SHAPE_T::RECTANGLE )
1640 m_editorBehavior = std::make_unique<PCB_TABLECELL_POINT_EDIT_BEHAVIOR>( *cell );
1641
1642 break;
1643 }
1644
1645 case PCB_PAD_T:
1646 {
1647 // Pad edit only for the footprint editor
1649 {
1650 PAD& pad = static_cast<PAD&>( *aItem );
1652
1653 // Point editor only handles copper shape changes
1654 if( !IsCopperLayer( activeLayer ) )
1655 activeLayer = IsFrontLayer( activeLayer ) ? F_Cu : B_Cu;
1656
1657 m_editorBehavior = std::make_unique<PAD_POINT_EDIT_BEHAVIOR>( pad, activeLayer );
1658 }
1659 break;
1660 }
1661
1662 case PCB_ZONE_T:
1663 {
1664 ZONE& zone = static_cast<ZONE&>( *aItem );
1665 m_editorBehavior = std::make_unique<ZONE_POINT_EDIT_BEHAVIOR>( zone );
1666 break;
1667 }
1668
1669 case PCB_GENERATOR_T:
1670 {
1671 PCB_GENERATOR* generator = static_cast<PCB_GENERATOR*>( aItem );
1672 m_editorBehavior = std::make_unique<GENERATOR_POINT_EDIT_BEHAVIOR>( *generator );
1673 break;
1674 }
1675
1676 case PCB_DIM_ALIGNED_T:
1678 {
1679 PCB_DIM_ALIGNED& dimension = static_cast<PCB_DIM_ALIGNED&>( *aItem );
1680 m_editorBehavior = std::make_unique<ALIGNED_DIMENSION_POINT_EDIT_BEHAVIOR>( dimension );
1681 break;
1682 }
1683
1684 case PCB_DIM_CENTER_T:
1685 {
1686 PCB_DIM_CENTER& dimension = static_cast<PCB_DIM_CENTER&>( *aItem );
1687 m_editorBehavior = std::make_unique<DIM_CENTER_POINT_EDIT_BEHAVIOR>( dimension );
1688 break;
1689 }
1690
1691 case PCB_DIM_RADIAL_T:
1692 {
1693 PCB_DIM_RADIAL& dimension = static_cast<PCB_DIM_RADIAL&>( *aItem );
1694 m_editorBehavior = std::make_unique<DIM_RADIAL_POINT_EDIT_BEHAVIOR>( dimension );
1695 break;
1696 }
1697
1698 case PCB_DIM_LEADER_T:
1699 {
1700 PCB_DIM_LEADER& dimension = static_cast<PCB_DIM_LEADER&>( *aItem );
1701 m_editorBehavior = std::make_unique<DIM_LEADER_POINT_EDIT_BEHAVIOR>( dimension );
1702 break;
1703 }
1704
1705 default:
1706 points.reset();
1707 break;
1708 }
1709
1710 if( m_editorBehavior )
1711 m_editorBehavior->MakePoints( *points );
1712
1713 return points;
1714}
1715
1716
1718{
1719 EDIT_POINT* point;
1720 EDIT_POINT* hovered = nullptr;
1721
1722 if( aEvent.IsMotion() )
1723 {
1724 point = m_editPoints->FindPoint( aEvent.Position(), getView() );
1725 hovered = point;
1726 }
1727 else if( aEvent.IsDrag( BUT_LEFT ) )
1728 {
1729 point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
1730 }
1731 else
1732 {
1733 point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition(), getView() );
1734 }
1735
1736 if( hovered )
1737 {
1738 if( m_hoveredPoint != hovered )
1739 {
1740 if( m_hoveredPoint )
1741 m_hoveredPoint->SetHover( false );
1742
1743 m_hoveredPoint = hovered;
1745 }
1746 }
1747 else if( m_hoveredPoint )
1748 {
1749 m_hoveredPoint->SetHover( false );
1750 m_hoveredPoint = nullptr;
1751 }
1752
1753 if( m_editedPoint != point )
1754 setEditedPoint( point );
1755}
1756
1757
1759{
1761 return 0;
1762
1764 return 0;
1765
1767
1768 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1770
1772 return 0;
1773
1774 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
1775
1776 if( !item || item->IsLocked() )
1777 return 0;
1778
1779 Activate();
1780 // Must be done after Activate() so that it gets set into the correct context
1781 getViewControls()->ShowCursor( true );
1782
1784
1785 // Use the original object as a construction item
1786 std::vector<std::unique_ptr<BOARD_ITEM>> clones;
1787
1788 m_editorBehavior.reset();
1789 // Will also make the edit behavior if supported
1790 m_editPoints = makePoints( item );
1791
1792 if( !m_editPoints )
1793 return 0;
1794
1796 getView()->Add( &m_preview );
1797
1798 getView()->Add( m_editPoints.get() );
1799 setEditedPoint( nullptr );
1800 updateEditedPoint( aEvent );
1801 bool inDrag = false;
1802
1803 BOARD_COMMIT commit( editFrame );
1804
1805 // Main loop: keep receiving events
1806 while( TOOL_EVENT* evt = Wait() )
1807 {
1808 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1809 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1810
1811 if( editFrame->IsType( FRAME_PCB_EDITOR ) )
1813 else
1815
1816 if( !m_editPoints || evt->IsSelectionEvent() || evt->Matches( EVENTS::InhibitSelectionEditing ) )
1817 {
1818 break;
1819 }
1820
1821 EDIT_POINT* prevHover = m_hoveredPoint;
1822
1823 if( !inDrag )
1824 updateEditedPoint( *evt );
1825
1826 if( prevHover != m_hoveredPoint )
1827 getView()->Update( m_editPoints.get() );
1828
1829 if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
1830 {
1831 if( !inDrag )
1832 {
1833 frame()->UndoRedoBlock( true );
1834
1835 if( item->Type() == PCB_GENERATOR_T )
1836 {
1838 static_cast<PCB_GENERATOR*>( item ) );
1839 }
1840
1842 m_original = *m_editedPoint; // Save the original position
1843 getViewControls()->SetAutoPan( true );
1844 inDrag = true;
1845
1847 grid.SetAuxAxes( true, m_original.GetPosition() );
1848
1849 setAltConstraint( true );
1851
1852 for( size_t ii = 0; ii < m_editPoints->PointsSize(); ++ii )
1853 {
1854 EDIT_POINT& point = m_editPoints->Point( ii );
1855
1856 if( &point != m_editedPoint )
1857 point.SetActive( false );
1858 }
1859
1860 // When we start dragging, create a clone of the item to use as the original
1861 // reference geometry (e.g. for intersections and extensions)
1862 BOARD_ITEM* clone = static_cast<BOARD_ITEM*>( item->Clone() );
1863 clone->SetParent( nullptr );
1864
1865 if( PCB_SHAPE* shape= dynamic_cast<PCB_SHAPE*>( item ) )
1866 {
1867 shape->SetFlags( IS_MOVING );
1868 shape->UpdateHatching();
1869
1870 static_cast<PCB_SHAPE*>( clone )->SetFillMode( FILL_T::NO_FILL );
1871 }
1872
1873 clones.emplace_back( clone );
1874 grid.AddConstructionItems( { clone }, false, true );
1875 }
1876
1877 // Keep point inside of limits with some padding
1878 VECTOR2I pos = GetClampedCoords<double, int>( evt->Position(), COORDS_PADDING );
1879 LSET snapLayers;
1880
1881 switch( m_editedPoint->GetSnapConstraint() )
1882 {
1883 case IGNORE_SNAPS: break;
1884 case OBJECT_LAYERS: snapLayers = item->GetLayerSet(); break;
1885 case ALL_LAYERS: snapLayers = LSET::AllLayersMask(); break;
1886 }
1887
1889 {
1890 if( grid.GetUseGrid() )
1891 {
1892 VECTOR2I gridPt = grid.BestSnapAnchor( pos, {}, grid.GetItemGrid( item ), { item } );
1893
1895 VECTOR2I delta = pos - last;
1896 VECTOR2I deltaGrid = gridPt - grid.BestSnapAnchor( last, {}, grid.GetItemGrid( item ),
1897 { item } );
1898
1899 if( abs( delta.x ) > grid.GetGrid().x / 2 )
1900 pos.x = last.x + deltaGrid.x;
1901 else
1902 pos.x = last.x;
1903
1904 if( abs( delta.y ) > grid.GetGrid().y / 2 )
1905 pos.y = last.y + deltaGrid.y;
1906 else
1907 pos.y = last.y;
1908 }
1909 }
1910
1911 m_editedPoint->SetPosition( pos );
1912
1913 // Constrain edited line midpoints to move normal to themselves
1914 if( dynamic_cast<EDIT_LINE*>( m_editedPoint ) )
1915 {
1916 m_altConstraint->Apply( grid );
1917 }
1918 else if( m_editedPoint->IsConstrained() )
1919 {
1921 }
1923 {
1924 m_editedPoint->SetPosition( grid.BestSnapAnchor( m_editedPoint->GetPosition(), snapLayers,
1925 grid.GetItemGrid( item ), { item } ) );
1926 }
1927
1928 updateItem( commit );
1930 updatePoints();
1931 }
1932 else if( m_editedPoint && evt->Action() == TA_MOUSE_DOWN && evt->Buttons() == BUT_LEFT )
1933 {
1935
1936 for( size_t ii = 0; ii < m_editPoints->PointsSize(); ++ii )
1937 {
1938 EDIT_POINT& point = m_editPoints->Point( ii );
1939
1940 if( &point != m_editedPoint )
1941 point.SetActive( false );
1942 }
1943
1944 getView()->Update( m_editPoints.get() );
1945 }
1946 else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
1947 {
1948 if( m_editedPoint )
1949 {
1950 m_editedPoint->SetActive( false );
1951 getView()->Update( m_editPoints.get() );
1952 }
1953
1954 getViewControls()->SetAutoPan( false );
1955 setAltConstraint( false );
1956
1957 if( item->Type() == PCB_GENERATOR_T )
1958 {
1961 static_cast<PCB_GENERATOR*>( item ) );
1962 }
1963 else if( item->Type() == PCB_TABLECELL_T )
1964 {
1965 commit.Push( _( "Resize Table Cells" ) );
1966 }
1967 else
1968 {
1969 commit.Push( _( "Move Point" ) );
1970 }
1971
1972 if( PCB_SHAPE* shape= dynamic_cast<PCB_SHAPE*>( item ) )
1973 {
1974 shape->ClearFlags( IS_MOVING );
1975 shape->UpdateHatching();
1976 }
1977
1978 inDrag = false;
1979 frame()->UndoRedoBlock( false );
1980
1982 item ); // FIXME: Needed for generators
1983 }
1984 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1985 {
1986 if( inDrag ) // Restore the last change
1987 {
1988 if( item->Type() == PCB_GENERATOR_T )
1989 {
1991 static_cast<PCB_GENERATOR*>( item ) );
1992 }
1993 commit.Revert();
1994
1995 if( PCB_SHAPE* shape= dynamic_cast<PCB_SHAPE*>( item ) )
1996 {
1997 shape->ClearFlags( IS_MOVING );
1998 shape->UpdateHatching();
1999 }
2000
2001 inDrag = false;
2002 frame()->UndoRedoBlock( false );
2003 }
2004
2005 // Only cancel point editor when activating a new tool
2006 // Otherwise, allow the points to persist when moving up the
2007 // tool stack
2008 if( evt->IsActivate() && !evt->IsMoveTool() )
2009 break;
2010 }
2011 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2012 {
2013 // Re-create the points for items which can have different behavior on different layers
2014 if( item->Type() == PCB_PAD_T && m_isFootprintEditor )
2015 {
2016 getView()->Remove( m_editPoints.get() );
2017 m_editPoints = makePoints( item );
2018 getView()->Add( m_editPoints.get() );
2019 }
2020 }
2021 else if( evt->Action() == TA_UNDO_REDO_POST )
2022 {
2023 break;
2024 }
2025 else
2026 {
2027 evt->SetPassEvent();
2028 }
2029 }
2030
2031 if( PCB_SHAPE* shape= dynamic_cast<PCB_SHAPE*>( item ) )
2032 {
2033 shape->ClearFlags( IS_MOVING );
2034 shape->UpdateHatching();
2035 }
2036
2038 getView()->Remove( &m_preview );
2039
2040 if( m_editPoints )
2041 {
2042 getView()->Remove( m_editPoints.get() );
2043 m_editPoints.reset();
2044 }
2045
2046 m_editedPoint = nullptr;
2047
2048 return 0;
2049}
2050
2051
2053{
2054 if( !m_editPoints || !m_editPoints->GetParent() || !HasPoint() )
2055 return 0;
2056
2057 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2058
2059 BOARD_COMMIT commit( editFrame );
2060 commit.Stage( m_editPoints->GetParent(), CHT_MODIFY );
2061
2063 wxString title;
2064 wxString msg;
2065
2066 if( dynamic_cast<EDIT_LINE*>( m_editedPoint ) )
2067 {
2068 title = _( "Move Midpoint to Location" );
2069 msg = _( "Move Midpoint" );
2070 }
2071 else
2072 {
2073 title = _( "Move Corner to Location" );
2074 msg = _( "Move Corner" );
2075 }
2076
2077 WX_PT_ENTRY_DIALOG dlg( editFrame, title, _( "X:" ), _( "Y:" ), pt, false );
2078
2079 if( dlg.ShowModal() == wxID_OK )
2080 {
2082 updateItem( commit );
2083 commit.Push( msg );
2084 }
2085
2086 return 0;
2087}
2088
2089
2091{
2092 wxCHECK( m_editPoints, /* void */ );
2093 EDA_ITEM* item = m_editPoints->GetParent();
2094
2095 if( !item )
2096 return;
2097
2098 // item is always updated
2099 std::vector<EDA_ITEM*> updatedItems = { item };
2100 aCommit.Modify( item );
2101
2102 if( m_editorBehavior )
2103 {
2104 wxCHECK( m_editedPoint, /* void */ );
2105 m_editorBehavior->UpdateItem( *m_editedPoint, *m_editPoints, aCommit, updatedItems );
2106 }
2107
2108 // Perform any post-edit actions that the item may require
2109
2110 switch( item->Type() )
2111 {
2112 case PCB_TEXTBOX_T:
2113 case PCB_SHAPE_T:
2114 {
2115 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
2116
2117 if( shape->IsProxyItem() )
2118 {
2119 for( PAD* pad : shape->GetParentFootprint()->Pads() )
2120 {
2121 if( pad->IsEntered() )
2122 view()->Update( pad );
2123 }
2124 }
2125
2126 // Nuke outline font render caches
2127 if( PCB_TEXTBOX* textBox = dynamic_cast<PCB_TEXTBOX*>( item ) )
2128 textBox->ClearRenderCache();
2129
2130 break;
2131 }
2132 case PCB_GENERATOR_T:
2133 {
2134 GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
2135 PCB_GENERATOR* generatorItem = static_cast<PCB_GENERATOR*>( item );
2136
2137 m_toolMgr->RunSynchronousAction( PCB_ACTIONS::genUpdateEdit, &aCommit, generatorItem );
2138
2139 // Note: POINT_EDITOR::m_preview holds only the canvas-draw status "popup"; the meanders
2140 // themselves (ROUTER_PREVIEW_ITEMs) are owned by the router.
2141
2143
2144 for( EDA_ITEM* previewItem : generatorItem->GetPreviewItems( generatorTool, frame(), STATUS_ITEMS_ONLY ) )
2145 m_preview.Add( previewItem );
2146
2147 getView()->Update( &m_preview );
2148 break;
2149 }
2150 default:
2151 break;
2152 }
2153
2154 // Update the item and any affected items
2155 for( EDA_ITEM* updatedItem : updatedItems )
2156 {
2157 getView()->Update( updatedItem );
2158 }
2159
2160 frame()->SetMsgPanel( item );
2161}
2162
2163
2165{
2166 if( !m_editPoints )
2167 return;
2168
2169 EDA_ITEM* item = m_editPoints->GetParent();
2170
2171 if( !item )
2172 return;
2173
2174 if( !m_editorBehavior )
2175 return;
2176
2177 m_editorBehavior->UpdatePoints( *m_editPoints );
2178 getView()->Update( m_editPoints.get() );
2179}
2180
2181
2183{
2185
2186 if( aPoint )
2187 {
2188 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2189 controls->ForceCursorPosition( true, aPoint->GetPosition() );
2190 controls->ShowCursor( true );
2191 }
2192 else
2193 {
2194 if( frame()->ToolStackIsEmpty() )
2195 controls->ShowCursor( false );
2196
2197 controls->ForceCursorPosition( false );
2198 }
2199
2200 m_editedPoint = aPoint;
2201}
2202
2203
2205{
2206 if( aEnabled )
2207 {
2208 EDA_ITEM* parent = m_editPoints->GetParent();
2209 EDIT_LINE* line = dynamic_cast<EDIT_LINE*>( m_editedPoint );
2210 bool isPoly;
2211
2212 switch( parent->Type() )
2213 {
2214 case PCB_ZONE_T:
2215 isPoly = true;
2216 break;
2217
2218 case PCB_SHAPE_T:
2219 isPoly = static_cast<PCB_SHAPE*>( parent )->GetShape() == SHAPE_T::POLY;
2220 break;
2221
2222 default:
2223 isPoly = false;
2224 break;
2225 }
2226
2227 if( line && isPoly )
2228 {
2229 EC_CONVERGING* altConstraint = new EC_CONVERGING( *line, *m_editPoints );
2230 m_altConstraint.reset( (EDIT_CONSTRAINT<EDIT_POINT>*) altConstraint );
2231 }
2232 else
2233 {
2234 // Find a proper constraining point for 45 degrees mode
2237 }
2238 }
2239 else
2240 {
2241 m_altConstraint.reset();
2242 }
2243}
2244
2245
2247{
2248 // If there's a behaviour and it provides a constrainer, use that
2249 if( m_editorBehavior )
2250 {
2251 const OPT_VECTOR2I constrainer = m_editorBehavior->Get45DegreeConstrainer( *m_editedPoint, *m_editPoints );
2252
2253 if( constrainer )
2254 return EDIT_POINT( *constrainer );
2255 }
2256
2257 // In any other case we may align item to its original position
2258 return m_original;
2259}
2260
2261
2262// Finds a corresponding vertex in a polygon set
2263static std::pair<bool, SHAPE_POLY_SET::VERTEX_INDEX>
2264findVertex( SHAPE_POLY_SET& aPolySet, const EDIT_POINT& aPoint )
2265{
2266 for( auto it = aPolySet.IterateWithHoles(); it; ++it )
2267 {
2268 auto vertexIdx = it.GetIndex();
2269
2270 if( aPolySet.CVertex( vertexIdx ) == aPoint.GetPosition() )
2271 return std::make_pair( true, vertexIdx );
2272 }
2273
2274 return std::make_pair( false, SHAPE_POLY_SET::VERTEX_INDEX() );
2275}
2276
2277
2279{
2280 if( !m_editPoints || !m_editedPoint )
2281 return false;
2282
2283 EDA_ITEM* item = m_editPoints->GetParent();
2284 SHAPE_POLY_SET* polyset = nullptr;
2285
2286 if( !item )
2287 return false;
2288
2289 switch( item->Type() )
2290 {
2291 case PCB_ZONE_T:
2292 polyset = static_cast<ZONE*>( item )->Outline();
2293 break;
2294
2295 case PCB_SHAPE_T:
2296 if( static_cast<PCB_SHAPE*>( item )->GetShape() == SHAPE_T::POLY )
2297 polyset = &static_cast<PCB_SHAPE*>( item )->GetPolyShape();
2298 else
2299 return false;
2300
2301 break;
2302
2303 default:
2304 return false;
2305 }
2306
2307 std::pair<bool, SHAPE_POLY_SET::VERTEX_INDEX> vertex = findVertex( *polyset, *m_editedPoint );
2308
2309 if( !vertex.first )
2310 return false;
2311
2312 const SHAPE_POLY_SET::VERTEX_INDEX& vertexIdx = vertex.second;
2313
2314 // Check if there are enough vertices so one can be removed without
2315 // degenerating the polygon.
2316 // The first condition allows one to remove all corners from holes (when
2317 // there are only 2 vertices left, a hole is removed).
2318 if( vertexIdx.m_contour == 0
2319 && polyset->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour].PointCount() <= 3 )
2320 {
2321 return false;
2322 }
2323
2324 // Remove corner does not work with lines
2325 if( dynamic_cast<EDIT_LINE*>( m_editedPoint ) )
2326 return false;
2327
2328 return m_editedPoint != nullptr;
2329}
2330
2331
2333{
2334 if( !m_editPoints )
2335 return 0;
2336
2337 EDA_ITEM* item = m_editPoints->GetParent();
2338 PCB_BASE_EDIT_FRAME* frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2339 const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
2340
2341 // called without an active edited polygon
2342 if( !item || !canAddCorner( *item ) )
2343 return 0;
2344
2345 PCB_SHAPE* graphicItem = dynamic_cast<PCB_SHAPE*>( item );
2346 BOARD_COMMIT commit( frame );
2347
2348 if( item->Type() == PCB_ZONE_T || ( graphicItem && graphicItem->GetShape() == SHAPE_T::POLY ) )
2349 {
2350 unsigned int nearestIdx = 0;
2351 unsigned int nextNearestIdx = 0;
2352 unsigned int nearestDist = INT_MAX;
2353 unsigned int firstPointInContour = 0;
2354 SHAPE_POLY_SET* zoneOutline;
2355
2356 if( item->Type() == PCB_ZONE_T )
2357 {
2358 ZONE* zone = static_cast<ZONE*>( item );
2359 zoneOutline = zone->Outline();
2360 zone->SetNeedRefill( true );
2361 }
2362 else
2363 {
2364 zoneOutline = &( graphicItem->GetPolyShape() );
2365 }
2366
2367 commit.Modify( item );
2368
2369 // Search the best outline segment to add a new corner
2370 // and therefore break this segment into two segments
2371
2372 // Object to iterate through the corners of the outlines (main contour and its holes)
2373 SHAPE_POLY_SET::ITERATOR iterator = zoneOutline->Iterate( 0, zoneOutline->OutlineCount()-1,
2374 /* IterateHoles */ true );
2375 int curr_idx = 0;
2376
2377 // Iterate through all the corners of the outlines and search the best segment
2378 for( ; iterator; iterator++, curr_idx++ )
2379 {
2380 int jj = curr_idx+1;
2381
2382 if( iterator.IsEndContour() )
2383 { // We reach the last point of the current contour (main or hole)
2384 jj = firstPointInContour;
2385 firstPointInContour = curr_idx+1; // Prepare next contour analysis
2386 }
2387
2388 SEG curr_segment( zoneOutline->CVertex( curr_idx ), zoneOutline->CVertex( jj ) );
2389
2390 unsigned int distance = curr_segment.Distance( cursorPos );
2391
2392 if( distance < nearestDist )
2393 {
2394 nearestDist = distance;
2395 nearestIdx = curr_idx;
2396 nextNearestIdx = jj;
2397 }
2398 }
2399
2400 // Find the point on the closest segment
2401 const VECTOR2I& sideOrigin = zoneOutline->CVertex( nearestIdx );
2402 const VECTOR2I& sideEnd = zoneOutline->CVertex( nextNearestIdx );
2403 SEG nearestSide( sideOrigin, sideEnd );
2404 VECTOR2I nearestPoint = nearestSide.NearestPoint( cursorPos );
2405
2406 // Do not add points that have the same coordinates as ones that already belong to polygon
2407 // instead, add a point in the middle of the side
2408 if( nearestPoint == sideOrigin || nearestPoint == sideEnd )
2409 nearestPoint = ( sideOrigin + sideEnd ) / 2;
2410
2411 zoneOutline->InsertVertex( nextNearestIdx, nearestPoint );
2412
2413 if( item->Type() == PCB_ZONE_T )
2414 static_cast<ZONE*>( item )->HatchBorder();
2415
2416 commit.Push( _( "Add Zone Corner" ) );
2417 }
2418 else if( graphicItem )
2419 {
2420 switch( graphicItem->GetShape() )
2421 {
2422 case SHAPE_T::SEGMENT:
2423 {
2424 commit.Modify( graphicItem );
2425
2426 SEG seg( graphicItem->GetStart(), graphicItem->GetEnd() );
2427 VECTOR2I nearestPoint = seg.NearestPoint( cursorPos );
2428
2429 // Move the end of the line to the break point..
2430 graphicItem->SetEnd( nearestPoint );
2431
2432 // and add another one starting from the break point
2433 PCB_SHAPE* newSegment = static_cast<PCB_SHAPE*>( graphicItem->Duplicate( true, &commit ) );
2434 newSegment->ClearSelected();
2435 newSegment->SetStart( nearestPoint );
2436 newSegment->SetEnd( VECTOR2I( seg.B.x, seg.B.y ) );
2437
2438 commit.Add( newSegment );
2439 commit.Push( _( "Split Segment" ) );
2440 break;
2441 }
2442 case SHAPE_T::ARC:
2443 {
2444 commit.Modify( graphicItem );
2445
2446 const SHAPE_ARC arc( graphicItem->GetStart(), graphicItem->GetArcMid(), graphicItem->GetEnd(), 0 );
2447 const VECTOR2I nearestPoint = arc.NearestPoint( cursorPos );
2448
2449 // Move the end of the arc to the break point..
2450 graphicItem->SetEnd( nearestPoint );
2451
2452 // and add another one starting from the break point
2453 PCB_SHAPE* newArc = static_cast<PCB_SHAPE*>( graphicItem->Duplicate( true, &commit ) );
2454
2455 newArc->ClearSelected();
2456 newArc->SetEnd( arc.GetP1() );
2457 newArc->SetStart( nearestPoint );
2458
2459 commit.Add( newArc );
2460 commit.Push( _( "Split Arc" ) );
2461 break;
2462 }
2463 default:
2464 // No split implemented for other shapes
2465 break;
2466 }
2467 }
2468
2469 updatePoints();
2470 return 0;
2471}
2472
2473
2475{
2476 if( !m_editPoints || !m_editedPoint )
2477 return 0;
2478
2479 EDA_ITEM* item = m_editPoints->GetParent();
2480
2481 if( !item )
2482 return 0;
2483
2484 SHAPE_POLY_SET* polygon = nullptr;
2485
2486 if( item->Type() == PCB_ZONE_T )
2487 {
2488 ZONE* zone = static_cast<ZONE*>( item );
2489 polygon = zone->Outline();
2490 zone->SetNeedRefill( true );
2491 }
2492 else if( item->Type() == PCB_SHAPE_T )
2493 {
2494 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
2495
2496 if( shape->GetShape() == SHAPE_T::POLY )
2497 polygon = &shape->GetPolyShape();
2498 }
2499
2500 if( !polygon )
2501 return 0;
2502
2503 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
2504 BOARD_COMMIT commit( frame );
2505 auto vertex = findVertex( *polygon, *m_editedPoint );
2506
2507 if( vertex.first )
2508 {
2509 const auto& vertexIdx = vertex.second;
2510 auto& outline = polygon->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour];
2511
2512 if( outline.PointCount() > 3 )
2513 {
2514 // the usual case: remove just the corner when there are >3 vertices
2515 commit.Modify( item );
2516 polygon->RemoveVertex( vertexIdx );
2517 }
2518 else
2519 {
2520 // either remove a hole or the polygon when there are <= 3 corners
2521 if( vertexIdx.m_contour > 0 )
2522 {
2523 // remove hole
2524 commit.Modify( item );
2525 polygon->RemoveContour( vertexIdx.m_contour );
2526 }
2527 else
2528 {
2530 commit.Remove( item );
2531 }
2532 }
2533
2534 setEditedPoint( nullptr );
2535
2536 if( item->Type() == PCB_ZONE_T )
2537 commit.Push( _( "Remove Zone Corner" ) );
2538 else
2539 commit.Push( _( "Remove Polygon Corner" ) );
2540
2541 if( item->Type() == PCB_ZONE_T )
2542 static_cast<ZONE*>( item )->HatchBorder();
2543
2544 updatePoints();
2545 }
2546
2547 return 0;
2548}
2549
2550
2552{
2553 if( !m_editPoints || !m_editedPoint )
2554 return 0;
2555
2556 EDA_ITEM* item = m_editPoints->GetParent();
2557
2558 if( !item )
2559 return 0;
2560
2561 SHAPE_POLY_SET* polygon = nullptr;
2562
2563 if( item->Type() == PCB_ZONE_T )
2564 {
2565 ZONE* zone = static_cast<ZONE*>( item );
2566 polygon = zone->Outline();
2567 zone->SetNeedRefill( true );
2568 }
2569 else if( item->Type() == PCB_SHAPE_T )
2570 {
2571 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
2572
2573 if( shape->GetShape() == SHAPE_T::POLY )
2574 polygon = &shape->GetPolyShape();
2575 }
2576
2577 if( !polygon )
2578 return 0;
2579
2580 // Search the best outline corner to break
2581
2582 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
2583 BOARD_COMMIT commit( frame );
2584 const VECTOR2I& cursorPos = getViewControls()->GetCursorPosition();
2585
2586 unsigned int nearestIdx = 0;
2587 unsigned int nearestDist = INT_MAX;
2588
2589 int curr_idx = 0;
2590 // Object to iterate through the corners of the outlines (main contour and its holes)
2591 SHAPE_POLY_SET::ITERATOR iterator = polygon->Iterate( 0, polygon->OutlineCount() - 1,
2592 /* IterateHoles */ true );
2593
2594 // Iterate through all the corners of the outlines and search the best segment
2595 for( ; iterator; iterator++, curr_idx++ )
2596 {
2597 unsigned int distance = polygon->CVertex( curr_idx ).Distance( cursorPos );
2598
2599 if( distance < nearestDist )
2600 {
2601 nearestDist = distance;
2602 nearestIdx = curr_idx;
2603 }
2604 }
2605
2606 int prevIdx, nextIdx;
2607 if( polygon->GetNeighbourIndexes( nearestIdx, &prevIdx, &nextIdx ) )
2608 {
2609 const SEG segA{ polygon->CVertex( prevIdx ), polygon->CVertex( nearestIdx ) };
2610 const SEG segB{ polygon->CVertex( nextIdx ), polygon->CVertex( nearestIdx ) };
2611
2612 // A plausible setback that won't consume a whole edge
2613 int setback = pcbIUScale.mmToIU( 5 );
2614 setback = std::min( setback, (int) ( segA.Length() * 0.25 ) );
2615 setback = std::min( setback, (int) ( segB.Length() * 0.25 ) );
2616
2617 CHAMFER_PARAMS chamferParams{ setback, setback };
2618
2619 std::optional<CHAMFER_RESULT> chamferResult = ComputeChamferPoints( segA, segB, chamferParams );
2620
2621 if( chamferResult && chamferResult->m_updated_seg_a && chamferResult->m_updated_seg_b )
2622 {
2623 commit.Modify( item );
2624 polygon->RemoveVertex( nearestIdx );
2625
2626 // The two end points of the chamfer are the new corners
2627 polygon->InsertVertex( nearestIdx, chamferResult->m_updated_seg_b->B );
2628 polygon->InsertVertex( nearestIdx, chamferResult->m_updated_seg_a->B );
2629 }
2630 }
2631
2632 setEditedPoint( nullptr );
2633
2634 if( item->Type() == PCB_ZONE_T )
2635 commit.Push( _( "Break Zone Corner" ) );
2636 else
2637 commit.Push( _( "Break Polygon Corner" ) );
2638
2639 if( item->Type() == PCB_ZONE_T )
2640 static_cast<ZONE*>( item )->HatchBorder();
2641
2642 updatePoints();
2643
2644 return 0;
2645}
2646
2647
2649{
2650 updatePoints();
2651 return 0;
2652}
2653
2654
2656{
2657 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2658
2660 {
2661 if( editFrame->IsType( FRAME_PCB_EDITOR ) )
2663 else
2665
2667 }
2668 else
2669 {
2671 }
2672
2673 if( editFrame->IsType( FRAME_PCB_EDITOR ) )
2675 else
2677
2678 return 0;
2679}
2680
2681
2683{
2701}
ARC_EDIT_MODE
Settings for arc editing.
Definition: app_settings.h:52
@ KEEP_CENTER_ADJUST_ANGLE_RADIUS
When editing endpoints, the angle and radius are adjusted.
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
static TOOL_ACTION cycleArcEditMode
Definition: actions.h:269
static TOOL_ACTION pointEditorArcKeepCenter
Definition: actions.h:270
static TOOL_ACTION pointEditorArcKeepRadius
Definition: actions.h:272
static TOOL_ACTION reselectItem
Definition: actions.h:226
static TOOL_ACTION activatePointEditor
Definition: actions.h:268
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:221
static TOOL_ACTION pointEditorArcKeepEndpoint
Definition: actions.h:271
This covers both aligned and the orthogonal sub-type.
void updateOrthogonalDimension(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints)
Update orthogonal dimension points.
ALIGNED_DIMENSION_POINT_EDIT_BEHAVIOR(PCB_DIM_ALIGNED &aDimension)
void updateAlignedDimension(const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints)
Update non-orthogonal dimension points.
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
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 UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
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.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE) override
Add a change of the item aItem of type aChangeType to the change list.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual BOARD_ITEM * Duplicate(bool addToParentGroup, BOARD_COMMIT *aCommit=nullptr) const
Create a copy of this BOARD_ITEM.
Definition: board_item.cpp:283
bool IsLocked() const override
Definition: board_item.cpp:103
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:97
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:252
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:210
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr coord_type GetBottom() const
Definition: box2.h:222
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition: commit.h:73
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:91
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition: commit.h:107
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:79
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
int ShowModal() override
Class to help update the text position of a dimension when the crossbar changes.
DIM_ALIGNED_TEXT_UPDATER(PCB_DIM_ALIGNED &aDimension)
PCB_DIM_ALIGNED & m_dimension
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.
void UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
DIM_CENTER_POINT_EDIT_BEHAVIOR(PCB_DIM_CENTER &aDimension)
DIM_LEADER_POINT_EDIT_BEHAVIOR(PCB_DIM_LEADER &aDimension)
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
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 UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
DIM_RADIAL_POINT_EDIT_BEHAVIOR(PCB_DIM_RADIAL &aDimension)
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
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 UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
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.
EDIT_CONSTRAINT that imposes a constraint that two points have to be located at angle of 45 degree mu...
EDIT_CONSTRAINT for 3 segments: dragged and two adjacent ones, enforcing to keep their slopes and all...
EDIT_CONSTRAINT that imposes a constraint that a point has to lie on a line (determined by 2 points).
EDIT_CONSTRAINT for a EDIT_LINE, that constrains the line to move perpendicular to the line itself.
bool IsHorizontal() const
Definition: eda_angle.h:142
bool IsCardinal() const
Definition: eda_angle.cpp:40
bool IsType(FRAME_T aType) const
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:148
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
void ClearSelected()
Definition: eda_item.h:137
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:113
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:118
virtual VECTOR2I GetTopLeft() const
Definition: eda_shape.h:246
int GetEndX() const
Definition: eda_shape.h:217
int GetRectangleWidth() const
Definition: eda_shape.cpp:422
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:337
SHAPE_T GetShape() const
Definition: eda_shape.h:168
virtual VECTOR2I GetBotRight() const
Definition: eda_shape.h:247
virtual void SetBottom(int val)
Definition: eda_shape.h:252
virtual void SetTop(int val)
Definition: eda_shape.h:249
int GetEndY() const
Definition: eda_shape.h:216
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:215
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:177
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:173
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:219
virtual void SetLeft(int val)
Definition: eda_shape.h:250
int GetRectangleHeight() const
Definition: eda_shape.cpp:408
virtual void SetRight(int val)
Definition: eda_shape.h:251
VECTOR2I GetArcMid() const
Definition: eda_shape.cpp:975
"Standard" table-cell editing behavior.
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:270
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:578
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:197
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:409
Describe constraints between two edit handles.
Represent a line connecting two EDIT_POINTs.
Definition: edit_points.h:223
void SetConstraint(EDIT_CONSTRAINT< EDIT_LINE > *aConstraint)
Set a constraint for and EDIT_POINT.
Definition: edit_points.h:267
EDIT_POINTS is a VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them.
Definition: edit_points.h:353
unsigned int PointsSize() const
Return number of stored EDIT_POINTs.
Definition: edit_points.h:534
void AddPoint(const EDIT_POINT &aPoint)
Add an EDIT_POINT.
Definition: edit_points.h:390
void SetSwapY(bool aSwap)
Definition: edit_points.h:579
void Clear()
Clear all stored EDIT_POINTs and EDIT_LINEs.
Definition: edit_points.h:378
EDIT_LINE & Line(unsigned int aIndex)
Definition: edit_points.h:521
bool SwapX() const
Definition: edit_points.h:575
bool SwapY() const
Definition: edit_points.h:578
void SetSwapX(bool aSwap)
Definition: edit_points.h:576
unsigned int LinesSize() const
Return number of stored EDIT_LINEs.
Definition: edit_points.h:542
EDIT_POINT & Point(unsigned int aIndex)
Definition: edit_points.h:511
void AddLine(const EDIT_LINE &aLine)
Adds an EDIT_LINE.
Definition: edit_points.h:410
Represent a single point that can be used for modifying items.
Definition: edit_points.h:48
int GetY() const
Return Y coordinate of an EDIT_POINT.
Definition: edit_points.h:95
SNAP_CONSTRAINT_TYPE GetSnapConstraint() const
Definition: edit_points.h:181
virtual void SetPosition(const VECTOR2I &aPosition)
Set new coordinates for an EDIT_POINT.
Definition: edit_points.h:107
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition: edit_points.h:71
void SetSnapConstraint(SNAP_CONSTRAINT_TYPE aConstraint)
Definition: edit_points.h:182
virtual void ApplyConstraint(const GRID_HELPER &aGrid)
Correct coordinates of an EDIT_POINT by applying previously set constraint.
Definition: edit_points.h:166
void SetHover(bool aHover=true)
Definition: edit_points.h:176
bool IsConstrained() const
Check if point is constrained.
Definition: edit_points.h:158
void SetConstraint(EDIT_CONSTRAINT< EDIT_POINT > *aConstraint)
Set a constraint for and EDIT_POINT.
Definition: edit_points.h:131
int GetX() const
Return X coordinate of an EDIT_POINT.
Definition: edit_points.h:87
void SetActive(bool aActive=true)
Definition: edit_points.h:173
GRID_CONSTRAINT_TYPE GetGridConstraint() const
Definition: edit_points.h:178
static const TOOL_EVENT InhibitSelectionEditing
Definition: actions.h:355
static const TOOL_EVENT SelectedEvent
Definition: actions.h:342
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:349
static const TOOL_EVENT UninhibitSelectionEditing
Used to inform tool that it should display the disambiguation menu.
Definition: actions.h:356
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:341
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:352
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:343
std::deque< PAD * > & Pads()
Definition: footprint.h:209
Point editor behavior for the PCB_GENERATOR class.
void 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.
GENERATOR_POINT_EDIT_BEHAVIOR(PCB_GENERATOR &aGenerator)
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
Handle actions specific to filling copper zones.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: pcb_view.cpp:91
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
void FreeItems()
Free all the items that were added to the group.
Definition: view_group.cpp:218
bool IsBOARD_ITEM() const
Definition: view_item.h:102
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:341
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1685
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static const LSET & AllLayersMask()
Definition: lset.cpp:624
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:145
void 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.
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.
PAD_POINT_EDIT_BEHAVIOR(PAD &aPad, PCB_LAYER_ID aLayer)
Definition: pad.h:54
const VECTOR2I & GetDrillSize() const
Definition: pad.h:305
bool IsLocked() const override
Definition: pad.cpp:252
VECTOR2I GetPosition() const override
Definition: pad.h:208
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:195
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition: pad.h:311
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:202
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition: pad.h:317
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:408
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition: pad.h:259
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1068
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:264
ARC_EDIT_MODE m_ArcEditMode
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:372
static TOOL_ACTION pointEditorMoveMidpoint
Definition: pcb_actions.h:291
static TOOL_ACTION genPushEdit
Definition: pcb_actions.h:279
static TOOL_ACTION genStartEdit
Definition: pcb_actions.h:277
static TOOL_ACTION pointEditorMoveCorner
Definition: pcb_actions.h:290
static TOOL_ACTION genUpdateEdit
Definition: pcb_actions.h:278
static TOOL_ACTION pointEditorChamferCorner
Definition: pcb_actions.h:288
static TOOL_ACTION pointEditorRemoveCorner
Definition: pcb_actions.h:287
static TOOL_ACTION pointEditorAddCorner
Definition: pcb_actions.h:286
static TOOL_ACTION genRevertEdit
Definition: pcb_actions.h:280
Common, abstract interface for edit frames.
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual PCB_LAYER_ID GetActiveLayer() const
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
FOOTPRINT_EDITOR_SETTINGS * GetFootprintEditorSettings() const
void Update()
Update the dimension's cached text and geometry.
void SetTextPositionMode(DIM_TEXT_POSITION aMode)
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
virtual const VECTOR2I & GetEnd() const
For better understanding of the points that make a dimension:
const VECTOR2I & GetCrossbarStart() const
const VECTOR2I & GetCrossbarEnd() const
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
Mark the center of a circle or arc with a cross shape.
A leader is a dimension-like object pointing to a specific point.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
void SetOrientation(DIR aOrientation)
Set the orientation of the dimension line (so, perpendicular to the feature lines).
DIR GetOrientation() const
A radial dimension indicates either the radius or diameter of an arc or circle.
void SetLeaderLength(int aLength)
VECTOR2I GetKnee() const
virtual bool UpdateFromEditPoints(EDIT_POINTS &aEditPoints)
virtual bool MakeEditPoints(EDIT_POINTS &aEditPoints) const
virtual bool UpdateEditPoints(EDIT_POINTS &aEditPoints)
int changeArcEditMode(const TOOL_EVENT &aEvent)
void updateItem(BOARD_COMMIT &aCommit)
Update edit points with item's points.
int OnSelectionChange(const TOOL_EVENT &aEvent)
Change selection event handler.
void setAltConstraint(bool aEnabled)
Return a point that should be used as a constrainer for 45 degrees mode.
static const unsigned int COORDS_PADDING
bool removeCornerCondition(const SELECTION &aSelection)
EDIT_POINT * m_hoveredPoint
int addCorner(const TOOL_EVENT &aEvent)
bool HasPoint()
Indicate the cursor is over an edit point.
EDIT_POINT m_original
Original pos for the current drag point.
EDIT_POINT get45DegConstrainer() const
Condition to display "Remove corner" context menu entry.
int modifiedSelection(const TOOL_EVENT &aEvent)
Change the edit method for arcs.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
std::unique_ptr< POINT_EDIT_BEHAVIOR > m_editorBehavior
int removeCorner(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
PCB_SELECTION m_preview
int movePoint(const TOOL_EVENT &aEvent)
TOOL_ACTION handlers.
void setEditedPoint(EDIT_POINT *aPoint)
EDIT_POINT m_altConstrainer
ARC_EDIT_MODE m_arcEditMode
EDIT_POINT * m_editedPoint
void updateEditedPoint(const TOOL_EVENT &aEvent)
Set the current point being edited. NULL means none.
std::shared_ptr< EDIT_CONSTRAINT< EDIT_POINT > > m_altConstraint
void updatePoints()
Update which point is being edited.
int chamferCorner(const TOOL_EVENT &aEvent)
void setTransitions() override
< Set up handlers for various events.
std::shared_ptr< EDIT_POINTS > m_editPoints
PCB_BASE_FRAME * m_frame
std::shared_ptr< EDIT_POINTS > makePoints(EDA_ITEM *aItem)
Update item's points with edit points.
PCB_SELECTION_TOOL * m_selectionTool
Object to handle a bitmap image that can be inserted in a PCB.
VECTOR2I GetPosition() const override
Get the position of the image (this is the center of the image).
REFERENCE_IMAGE & GetReferenceImage()
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:81
bool IsProxyItem() const override
Definition: pcb_shape.h:116
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:471
PCB_TABLECELL_POINT_EDIT_BEHAVIOR(PCB_TABLECELL &aCell)
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.
int GetRowSpan() const
Definition: pcb_tablecell.h:71
int GetColSpan() const
Definition: pcb_tablecell.h:68
int GetRow() const
int GetColumn() const
T * frame() const
KIGFX::PCB_VIEW * view() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
bool m_isFootprintEditor
const PCB_SELECTION & selection() const
A helper class interface to manage the edit points for a single item.
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.
Class that implements "standard" polygon editing behavior.
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.
static void UpdateItem(SCH_SHAPE &aRect, const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints)
static void UpdatePoints(SCH_SHAPE &aRect, EDIT_POINTS &aPoints)
static void PinEditedCorner(const EDIT_POINT &aEditedPoint, const EDIT_POINTS &aPoints, int minWidth, int minHeight, VECTOR2I &topLeft, VECTOR2I &topRight, VECTOR2I &botLeft, VECTOR2I &botRight)
Update the coordinates of 4 corners of a rectangle, according to constraints and the moved corner.
static void UpdatePoints(PCB_SHAPE &aRectangle, EDIT_POINTS &aPoints)
static void PinEditedCorner(const EDIT_POINT &aEditedPoint, const EDIT_POINTS &aEditPoints, VECTOR2I &aTopLeft, VECTOR2I &aTopRight, VECTOR2I &aBotLeft, VECTOR2I &aBotRight, const VECTOR2I &aHole={ 0, 0 }, const VECTOR2I &aHoleSize={ 0, 0 })
Update the coordinates of 4 corners of a rectangle, according to pad constraints and the moved corner...
static void MakePoints(SCH_SHAPE &aRect, EDIT_POINTS &aPoints)
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.
static void MakePoints(const PCB_SHAPE &aRectangle, EDIT_POINTS &aPoints)
Standard rectangle points construction utility (other shapes may use this as well)
static void UpdateItem(PCB_SHAPE &aRectangle, const EDIT_POINT &aEditedPoint, EDIT_POINTS &aPoints)
void UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
RECTANGLE_POINT_EDIT_BEHAVIOR(PCB_SHAPE &aRectangle)
REFERENCE_IMAGE_POINT_EDIT_BEHAVIOR(PCB_REFERENCE_IMAGE &aRefImage)
void 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.
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.
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
void SetTransformOriginOffset(const VECTOR2I &aCenter)
VECTOR2I GetTransformOriginOffset() const
Get the center of scaling, etc, relative to the image center (GetPosition()).
VECTOR2I GetPosition() const
VECTOR2I GetSize() const
double GetImageScale() const
void SetImageScale(double aScale)
Set the image "zoom" value.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:606
VECTOR2I Center() const
Definition: seg.h:379
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition: seg.cpp:675
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:658
Class that groups generic conditions for selected items.
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
EDA_ITEM * Front() const
Definition: selection.h:177
int Size() const
Returns the number of selected parts.
Definition: selection.h:121
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Definition: shape_arc.cpp:427
const VECTOR2I & GetP1() const
Definition: shape_arc.h:117
Base class for iterating over all vertices in a given SHAPE_POLY_SET.
Represent a set of closed polygons.
ITERATOR IterateWithHoles(int aOutline)
void InsertVertex(int aGlobalIndex, const VECTOR2I &aNewVertex)
Adds a vertex in the globally indexed position aGlobalIndex.
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
void RemoveVertex(int aGlobalIndex)
Delete the aGlobalIndex-th vertex.
void RemoveContour(int aContourIdx, int aPolygonIdx=-1)
Delete the aContourIdx-th contour of the aPolygonIdx-th polygon in the set.
bool GetNeighbourIndexes(int aGlobalIndex, int *aPrevious, int *aNext) const
Return the global indexes of the previous and the next corner of the aGlobalIndex-th corner of a cont...
ITERATOR Iterate(int aFirst, int aLast, bool aIterateHoles=false)
Return an object to iterate through the points of the polygons between aFirst and aLast.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
int OutlineCount() const
Return the number of outlines in the set.
A textbox is edited as a rectnagle when it is orthogonally aligned.
TEXTBOX_POINT_EDIT_BEHAVIOR(PCB_TEXTBOX &aTextbox)
void MakePoints(EDIT_POINTS &aPoints) override
Construct the initial set of edit points for the item and append to the given list.
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 UpdatePoints(EDIT_POINTS &aPoints) override
Update the list of the edit points for the item.
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:38
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
Generic, UI-independent tool event.
Definition: tool_event.h:168
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:389
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition: tool_event.h:290
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:312
const VECTOR2D DragOrigin() const
Return the point where dragging has started.
Definition: tool_event.h:296
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
bool IsMotion() const
Definition: tool_event.h:327
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU & GetToolMenu()
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
bool RunSynchronousAction(const TOOL_ACTION &aAction, COMMIT *aCommit, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:197
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition: vector2d.h:546
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition: vector2d.h:561
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:283
VECTOR2I GetValue()
Return the value in internal units.
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.
Handle a list of polygons defining a copper zone.
Definition: zone.h:74
void SetNeedRefill(bool aNeedRefill)
Definition: zone.h:296
bool UnFill()
Removes the zone filling.
Definition: zone.cpp:442
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition: zone.cpp:1244
SHAPE_POLY_SET * Outline()
Definition: zone.h:335
@ CHT_MODIFY
Definition: commit.h:45
This file is part of the common library.
std::optional< CHAMFER_RESULT > ComputeChamferPoints(const SEG &aSegA, const SEG &aSegB, const CHAMFER_PARAMS &aChamferParams)
Compute the chamfer points for a given line pair and chamfer parameters.
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:416
#define IS_MOVING
Item being moved.
SHAPE_T
Definition: eda_shape.h:43
@ ALL_LAYERS
@ OBJECT_LAYERS
@ IGNORE_SNAPS
@ SNAP_BY_GRID
@ SNAP_TO_GRID
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
a few functions useful in geometry calculations.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition: layer_ids.h:767
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:665
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:65
@ F_Cu
Definition: layer_ids.h:64
constexpr int Mils2IU(const EDA_IU_SCALE &aIuScale, int mils)
Definition: eda_units.h:166
bool PointProjectsOntoSegment(const VECTOR2I &aPoint, const SEG &aSeg)
Determine if a point projects onto a segment.
double GetLengthRatioFromStart(const VECTOR2I &aPoint, const SEG &aSeg)
Get the ratio of the vector to a point from the segment's start, compared to the segment's length.
const VECTOR2I & GetNearestEndpoint(const SEG &aSeg, const VECTOR2I &aPoint)
Get the nearest end of a segment to a point.
bool PointIsInDirection(const VECTOR2< T > &aPoint, const VECTOR2< T > &aDirection, const VECTOR2< T > &aFrom)
Definition: vector_utils.h:57
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:400
#define STATUS_ITEMS_ONLY
Definition: pcb_generator.h:67
RECT_LINES
@ RECT_RIGHT
@ RECT_LEFT
@ RECT_BOT
@ RECT_TOP
static std::pair< bool, SHAPE_POLY_SET::VERTEX_INDEX > findVertex(SHAPE_POLY_SET &aPolySet, const EDIT_POINT &aPoint)
static bool canAddCorner(const EDA_ITEM &aItem)
Condition to check if a point editor can add a corner to the given item.
TEXTBOX_POINT_COUNT
@ WHEN_POLYGON
@ WHEN_RECTANGLE
RECT_POINTS
@ RECT_MAX_POINTS
@ RECT_BOT_LEFT
@ RECT_BOT_RIGHT
@ RECT_CENTER
@ RECT_TOP_RIGHT
@ RECT_TOP_LEFT
DIMENSION_POINTS
@ DIM_LEADER_MAX
@ DIM_KNEE
@ DIM_TEXT
@ DIM_RADIAL_MAX
@ DIM_CROSSBAREND
@ DIM_END
@ DIM_START
@ DIM_ALIGNED_MAX
@ DIM_CENTER_MAX
@ DIM_CROSSBARSTART
static bool canChamferCorner(const EDA_ITEM &aItem)
Condition to check if a point editor can add a chamfer to a corner of the given item.
ARC_EDIT_MODE IncrementArcEditMode(ARC_EDIT_MODE aMode)
#define CHECK_POINT_COUNT(aPoints, aExpected)
#define CHECK_POINT_COUNT_GE(aPoints, aExpected)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
Parameters that define a simple chamfer operation.
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
VECTOR2I center
VECTOR2I end
int delta
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
@ TA_MOUSE_DOWN
Definition: tool_event.h:70
@ TA_UNDO_REDO_POST
This event is sent after undo/redo command is performed.
Definition: tool_event.h:109
@ MD_SHIFT
Definition: tool_event.h:143
@ BUT_LEFT
Definition: tool_event.h:132
VECTOR2I GetRotated(const VECTOR2I &aVector, const EDA_ANGLE &aAngle)
Return a new VECTOR2I that is the result of rotating aVector by aAngle.
Definition: trigo.h:77
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition: typeinfo.h:91
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition: typeinfo.h:95
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
constexpr int sign(T val)
Definition: util.h:145
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
Supplemental functions for working with vectors and simple objects that interact with vectors.