KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_shape.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include "pcb_shape.h"
24
25#include <google/protobuf/any.pb.h>
26#include <magic_enum.hpp>
27
28#include <bitmaps.h>
29#include <macros.h>
30#include <pcb_edit_frame.h>
32#include <board.h>
33#include <footprint.h>
34#include <lset.h>
35#include <pad.h>
36#include <base_units.h>
37#include <trigo.h>
38#include <drc/drc_engine.h>
44#include <pcb_painter.h>
45#include <api/board/board_types.pb.h>
46#include <api/api_enums.h>
47#include <api/api_utils.h>
48#include <properties/property.h>
50
51
52namespace
53{
54struct BOARD_ELLIPSE
55{
56 double major;
57 double minor;
58 EDA_ANGLE rotation;
59 EDA_ANGLE startShift;
60};
61
62
63// SVD of a 2x2 matrix into ellipse major / minor / rotation and the arc angle shift.
64static BOARD_ELLIPSE decompose2x2( double m00, double m01, double m10, double m11 )
65{
66 const double A = m00 * m00 + m10 * m10;
67 const double B = m00 * m01 + m10 * m11;
68 const double C = m01 * m01 + m11 * m11;
69
70 const double diff = A - C;
71 const double rad = std::hypot( diff, 2.0 * B );
72 const double lambda1 = ( A + C + rad ) * 0.5;
73 const double lambda2 = ( A + C - rad ) * 0.5;
74
75 const double sigma1 = std::sqrt( std::max( 0.0, lambda1 ) );
76 const double sigma2 = std::sqrt( std::max( 0.0, lambda2 ) );
77
78 double v0x;
79 double v0y;
80
81 if( std::abs( B ) > 1e-12 )
82 {
83 v0x = lambda1 - C;
84 v0y = B;
85 }
86 else if( A >= C )
87 {
88 v0x = 1.0;
89 v0y = 0.0;
90 }
91 else
92 {
93 v0x = 0.0;
94 v0y = 1.0;
95 }
96
97 const double vn = std::hypot( v0x, v0y );
98 v0x /= vn;
99 v0y /= vn;
100
101 double u0x = 1.0;
102 double u0y = 0.0;
103
104 if( sigma1 > 1e-12 )
105 {
106 u0x = ( m00 * v0x + m01 * v0y ) / sigma1;
107 u0y = ( m10 * v0x + m11 * v0y ) / sigma1;
108 }
109
110 BOARD_ELLIPSE out;
111 out.major = sigma1;
112 out.minor = sigma2;
113 out.rotation = EDA_ANGLE( std::atan2( u0y, u0x ), RADIANS_T );
114 out.startShift = EDA_ANGLE( -std::atan2( v0y, v0x ), RADIANS_T );
115 return out;
116}
117
118
119// Board ellipse from a lib ellipse: M = R(theta) * diag(sx, sy) * R(phi) * diag(a, b).
120static BOARD_ELLIPSE decomposeBoardEllipse( const TRANSFORM_TRS& aXform, int aLibMajor, int aLibMinor,
121 const EDA_ANGLE& aLibRotation )
122{
123 const double sx = aXform.GetScaleX();
124 const double sy = aXform.GetScaleY();
125 // Lib rotation and xform rotation use opposite signs, negate to match.
126 const double theta = -aXform.GetRotate().AsRadians();
127 const double phi = aLibRotation.AsRadians();
128 const double cTheta = std::cos( theta );
129 const double sTheta = std::sin( theta );
130 const double cPhi = std::cos( phi );
131 const double sPhi = std::sin( phi );
132 const double a = aLibMajor;
133 const double b = aLibMinor;
134
135 const double m00 = a * ( sx * cTheta * cPhi - sy * sTheta * sPhi );
136 const double m01 = -b * ( sx * cTheta * sPhi + sy * sTheta * cPhi );
137 const double m10 = a * ( sx * sTheta * cPhi + sy * cTheta * sPhi );
138 const double m11 = b * ( -sx * sTheta * sPhi + sy * cTheta * cPhi );
139
140 return decompose2x2( m00, m01, m10, m11 );
141}
142
143
144// Inverse of decomposeBoardEllipse: lib ellipse from a board ellipse.
145static BOARD_ELLIPSE composeLibEllipse( const TRANSFORM_TRS& aXform, double aBoardMajor, double aBoardMinor,
146 const EDA_ANGLE& aBoardRotation )
147{
148 const double sx = aXform.GetScaleX();
149 const double sy = aXform.GetScaleY();
150 const double theta = -aXform.GetRotate().AsRadians();
151 const double beta = aBoardRotation.AsRadians();
152
153 const double li00 = std::cos( theta ) / sx;
154 const double li01 = std::sin( theta ) / sx;
155 const double li10 = -std::sin( theta ) / sy;
156 const double li11 = std::cos( theta ) / sy;
157
158 const double e00 = aBoardMajor * std::cos( beta );
159 const double e01 = -aBoardMinor * std::sin( beta );
160 const double e10 = aBoardMajor * std::sin( beta );
161 const double e11 = aBoardMinor * std::cos( beta );
162
163 return decompose2x2( li00 * e00 + li01 * e10, li00 * e01 + li01 * e11, li10 * e00 + li11 * e10,
164 li10 * e01 + li11 * e11 );
165}
166} // namespace
167
168
169PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T aItemType, SHAPE_T aShapeType ) :
170 BOARD_CONNECTED_ITEM( aParent, aItemType ),
171 EDA_SHAPE( aShapeType, pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL ),
172 m_libStart( 0, 0 ),
173 m_libEnd( 0, 0 ),
174 m_libArcMid( 0, 0 ),
175 m_libBezierC1( 0, 0 ),
176 m_libBezierC2( 0, 0 ),
177 m_libEllipseCenter( 0, 0 ),
183 m_libShape( aShapeType )
184{
185 m_hasSolderMask = false;
186}
187
188
191 EDA_SHAPE( shapetype, pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL ),
192 m_libStart( 0, 0 ),
193 m_libEnd( 0, 0 ),
194 m_libArcMid( 0, 0 ),
195 m_libBezierC1( 0, 0 ),
196 m_libBezierC2( 0, 0 ),
197 m_libEllipseCenter( 0, 0 ),
203 m_libShape( shapetype )
204{
205 m_hasSolderMask = false;
206}
207
208
212
213
214void PCB_SHAPE::CopyFrom( const BOARD_ITEM* aOther )
215{
216 wxCHECK( aOther && aOther->Type() == PCB_SHAPE_T, /* void */ );
217 *this = *static_cast<const PCB_SHAPE*>( aOther );
218}
219
220
221void PCB_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
222{
223 using namespace kiapi::common;
224 using namespace kiapi::board::types;
225 BoardGraphicShape msg;
226
228 PackNet( msg.mutable_net() );
229 msg.mutable_id()->set_value( m_Uuid.AsStdString() );
230 msg.set_locked( IsLocked() ? types::LockedState::LS_LOCKED : types::LockedState::LS_UNLOCKED );
231
232 google::protobuf::Any any;
234 any.UnpackTo( msg.mutable_shape() );
235
236 // TODO m_hasSolderMask and m_solderMaskMargin
237
238 aContainer.PackFrom( msg );
239}
240
241
242bool PCB_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
243{
244 using namespace kiapi::common;
245 using namespace kiapi::board::types;
246
247 BoardGraphicShape msg;
248
249 if( !aContainer.UnpackTo( &msg ) )
250 return false;
251
252 // Initialize everything to a known state that doesn't get touched by every
253 // codepath below, to make sure the equality operator is consistent
254 m_start = {};
255 m_end = {};
256 m_arcCenter = {};
257 m_arcMidData = {};
258 m_bezierC1 = {};
259 m_bezierC2 = {};
260 m_editState = 0;
261 m_proxyItem = false;
262 m_endsSwapped = false;
263
264 SetUuidDirect( KIID( msg.id().value() ) );
265 SetLocked( msg.locked() == types::LS_LOCKED );
267 UnpackNet( msg.net() );
268
269 google::protobuf::Any any;
270 any.PackFrom( msg.shape() );
272
273 // TODO m_hasSolderMask and m_solderMaskMargin
274
275 return true;
276}
277
278
279bool PCB_SHAPE::IsType( const std::vector<KICAD_T>& aScanTypes ) const
280{
281 if( BOARD_ITEM::IsType( aScanTypes ) )
282 return true;
283
284 bool sametype = false;
285
286 for( KICAD_T scanType : aScanTypes )
287 {
288 if( scanType == PCB_LOCATE_BOARD_EDGE_T )
289 sametype = m_layer == Edge_Cuts;
290 else if( scanType == PCB_SHAPE_LOCATE_ARC_T )
291 sametype = m_shape == SHAPE_T::ARC;
292 else if( scanType == PCB_SHAPE_LOCATE_CIRCLE_T )
293 sametype = m_shape == SHAPE_T::CIRCLE;
294 else if( scanType == PCB_SHAPE_LOCATE_RECT_T )
295 sametype = m_shape == SHAPE_T::RECTANGLE;
296 else if( scanType == PCB_SHAPE_LOCATE_SEGMENT_T )
297 sametype = m_shape == SHAPE_T::SEGMENT;
298 else if( scanType == PCB_SHAPE_LOCATE_POLY_T )
299 sametype = m_shape == SHAPE_T::POLY;
300 else if( scanType == PCB_SHAPE_LOCATE_BEZIER_T )
301 sametype = m_shape == SHAPE_T::BEZIER;
302 else if( scanType == PCB_SHAPE_LOCATE_ELLIPSE_T )
303 sametype = m_shape == SHAPE_T::ELLIPSE;
304 else if( scanType == PCB_SHAPE_LOCATE_ELLIPSE_ARC_T )
305 sametype = m_shape == SHAPE_T::ELLIPSE_ARC;
306
307 if( sametype )
308 return true;
309 }
310
311 return false;
312}
313
314
316{
317 // Only board-level copper shapes are connectable
318 return IsOnCopperLayer() && !GetParentFootprint();
319}
320
321
323{
324 BOARD_ITEM::SetLayer( aLayer );
325
326 if( !IsOnCopperLayer() )
327 SetNetCode( -1 );
328}
329
330
332{
333 int margin = 0;
334
335 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine
336 && GetBoard()->GetDesignSettings().m_DRCEngine->HasRulesForConstraintType(
338 {
339 DRC_CONSTRAINT constraint;
340 std::shared_ptr<DRC_ENGINE> drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
341
342 constraint = drcEngine->EvalRules( SOLDER_MASK_EXPANSION_CONSTRAINT, this, nullptr, m_layer );
343
344 if( constraint.m_Value.HasOpt() )
345 margin = constraint.m_Value.Opt();
346 }
347 else if( m_solderMaskMargin.has_value() )
348 {
349 margin = m_solderMaskMargin.value();
350 }
351 else if( const BOARD* board = GetBoard() )
352 {
353 margin = board->GetDesignSettings().m_SolderMaskExpansion;
354 }
355
356 // Ensure the resulting mask opening has a non-negative size
357 if( margin < 0 && !IsSolidFill() )
358 margin = std::max( margin, -GetWidth() / 2 );
359
360 return margin;
361}
362
363
365{
366 if( aLayer == m_layer )
367 {
368 return true;
369 }
370
372 && ( ( aLayer == F_Mask && m_layer == F_Cu )
373 || ( aLayer == B_Mask && m_layer == B_Cu ) ) )
374 {
375 return true;
376 }
377
378 return false;
379}
380
381
383{
384 LSET layermask( { m_layer } );
385
386 if( m_hasSolderMask )
387 {
388 if( layermask.test( F_Cu ) )
389 layermask.set( F_Mask );
390
391 if( layermask.test( B_Cu ) )
392 layermask.set( B_Mask );
393 }
394
395 return layermask;
396}
397
398
399void PCB_SHAPE::SetLayerSet( const LSET& aLayerSet )
400{
401 aLayerSet.RunOnLayers(
402 [&]( PCB_LAYER_ID layer )
403 {
404 if( IsCopperLayer( layer ) )
405 SetLayer( layer );
406 else if( IsSolderMaskLayer( layer ) )
407 SetHasSolderMask( true );
408 } );
409}
410
411
412std::vector<VECTOR2I> PCB_SHAPE::GetConnectionPoints() const
413{
414 std::vector<VECTOR2I> ret;
415
416 // For filled shapes, we may as well use a centroid
417 if( IsSolidFill() )
418 {
419 ret.emplace_back( GetCenter() );
420 return ret;
421 }
422
423 switch( m_shape )
424 {
425 case SHAPE_T::CIRCLE:
426 {
427 const CIRCLE circle( GetCenter(), GetRadius() );
428
429 for( const TYPED_POINT2I& pt : KIGEOM::GetCircleKeyPoints( circle, false ) )
430 ret.emplace_back( pt.m_point );
431
432 break;
433 }
434
435 case SHAPE_T::ARC:
436 ret.emplace_back( GetArcMid() );
438 case SHAPE_T::SEGMENT:
439 case SHAPE_T::BEZIER:
440 ret.emplace_back( GetStart() );
441 ret.emplace_back( GetEnd() );
442 break;
443
444 case SHAPE_T::POLY:
445 for( auto iter = GetPolyShape().CIterate(); iter; ++iter )
446 ret.emplace_back( *iter );
447
448 break;
449
451 for( const VECTOR2I& pt : GetRectCorners() )
452 ret.emplace_back( pt );
453
454 break;
455
456 case SHAPE_T::ELLIPSE:
457 {
458 const double phi = GetEllipseRotation().AsRadians();
459 const double cosPhi = std::cos( phi );
460 const double sinPhi = std::sin( phi );
461 const int a = GetEllipseMajorRadius();
462 const int b = GetEllipseMinorRadius();
463 const VECTOR2I c = GetEllipseCenter();
464
465 ret.emplace_back( c + VECTOR2I( KiROUND( a * cosPhi ), KiROUND( a * sinPhi ) ) );
466 ret.emplace_back( c + VECTOR2I( KiROUND( -a * cosPhi ), KiROUND( -a * sinPhi ) ) );
467 ret.emplace_back( c + VECTOR2I( KiROUND( -b * sinPhi ), KiROUND( b * cosPhi ) ) );
468 ret.emplace_back( c + VECTOR2I( KiROUND( b * sinPhi ), KiROUND( -b * cosPhi ) ) );
469 break;
470 }
471
473 {
474 const double a = GetEllipseMajorRadius();
475 const double b = GetEllipseMinorRadius();
476 const double phi = GetEllipseRotation().AsRadians();
477 const double cosPhi = std::cos( phi );
478 const double sinPhi = std::sin( phi );
479 const VECTOR2I c = GetEllipseCenter();
480
481 auto eval = [&]( double theta ) -> VECTOR2I
482 {
483 const double lx = a * std::cos( theta );
484 const double ly = b * std::sin( theta );
485 return c + VECTOR2I( KiROUND( lx * cosPhi - ly * sinPhi ), KiROUND( lx * sinPhi + ly * cosPhi ) );
486 };
487
488 double thetaStart = GetEllipseStartAngle().AsRadians();
489 double thetaEnd = GetEllipseEndAngle().AsRadians();
490
491 if( thetaEnd < thetaStart )
492 thetaEnd += 2.0 * M_PI;
493
494 ret.emplace_back( eval( thetaStart ) );
495 ret.emplace_back( eval( thetaEnd ) );
496 ret.emplace_back( eval( 0.5 * ( thetaStart + thetaEnd ) ) );
497 break;
498 }
499
502 break;
503 }
504
505 return ret;
506}
507
508
510{
511 // Force update; we don't bother to propagate damage from all the things that might
512 // knock-out parts of our hatching.
513 m_hatchingDirty = true;
514
516}
517
518
520{
521 SHAPE_POLY_SET knockouts;
522 PCB_LAYER_ID layer = GetLayer();
523 BOX2I bbox = GetBoundingBox();
524 int maxError = ARC_LOW_DEF;
525
526 auto knockoutItem =
527 [&]( BOARD_ITEM* item )
528 {
529 int margin = GetHatchLineSpacing() / 2;
530
531 if( item->Type() == PCB_TEXTBOX_T )
532 margin = 0;
533
534 item->TransformShapeToPolygon( knockouts, layer, margin, maxError, ERROR_OUTSIDE );
535 };
536
537 for( BOARD_ITEM* item : GetBoard()->Drawings() )
538 {
539 if( item == this )
540 continue;
541
542 if( item->Type() == PCB_FIELD_T
543 || item->Type() == PCB_TEXT_T
544 || item->Type() == PCB_TEXTBOX_T
545 || item->Type() == PCB_SHAPE_T )
546 {
547 if( item->GetLayer() == layer && item->GetBoundingBox().Intersects( bbox ) )
548 knockoutItem( item );
549 }
550 }
551
552 for( FOOTPRINT* footprint : GetBoard()->Footprints() )
553 {
554 if( footprint == GetParentFootprint() )
555 continue;
556
557 // GetCourtyard() returns the front courtyard for any non-back layer, so only knock it
558 // out when the hatched shape actually lives on a courtyard layer.
559 if( layer == F_CrtYd || layer == B_CrtYd )
560 knockouts.Append( footprint->GetCourtyard( layer ) );
561
562 // Knockout footprint fields
563 footprint->RunOnChildren(
564 [&]( BOARD_ITEM* item )
565 {
566 if( ( item->Type() == PCB_FIELD_T || item->Type() == PCB_SHAPE_T )
567 && item->GetLayer() == layer
568 && !( item->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>(item)->IsVisible() )
569 && item->GetBoundingBox().Intersects( bbox ) )
570 {
571 knockoutItem( item );
572 }
573 },
575 }
576
577 return knockouts;
578}
579
580
581static double fpScaleLinear( const FOOTPRINT* aFp )
582{
583 if( !aFp )
584 return 1.0;
585
586 const TRANSFORM_TRS& xform = aFp->GetTransform();
587 return ( xform.GetScaleX() + xform.GetScaleY() ) * 0.5;
588}
589
590
592{
593 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
594 return nullptr;
595
596 return GetParentFootprint();
597}
598
599
601{
602 // Clamp negative widths to zero. They mean something in eeschema but break
603 // plotters and exporters here.
604 const int lib = std::max( EDA_SHAPE::GetWidth(), 0 );
605 const double s = fpScaleLinear( transformFp() );
606 return s == 1.0 ? lib : KiROUND( lib * s );
607}
608
609
610void PCB_SHAPE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
611{
612 m_stroke.SetWidth( settings.GetLineThickness( GetLayer() ) );
613}
614
615
617{
618 // For some shapes return the visual center, but for not filled polygonal shapes,
619 // the center is usually far from the shape: a point on the outline is better
620
621 switch( m_shape )
622 {
623 case SHAPE_T::CIRCLE:
624 if( !IsAnyFill() )
625 return VECTOR2I( GetCenter().x + GetRadius(), GetCenter().y );
626 else
627 return GetCenter();
628
630 if( !IsAnyFill() )
631 return GetStart();
632 else
633 return GetCenter();
634
635 case SHAPE_T::POLY:
636 if( !IsAnyFill() )
637 {
638 VECTOR2I pos = GetPolyShape().Outline(0).CPoint(0);
639 return VECTOR2I( pos.x, pos.y );
640 }
641 else
642 {
643 return GetCenter();
644 }
645
646 case SHAPE_T::ARC:
647 return GetArcMid();
648
649 case SHAPE_T::BEZIER:
650 return GetStart();
651
652 default:
653 return GetCenter();
654 }
655}
656
657
658std::vector<VECTOR2I> PCB_SHAPE::GetCorners() const
659{
660 std::vector<VECTOR2I> pts;
661
663 {
664 pts = GetRectCorners();
665 }
666 else if( GetShape() == SHAPE_T::POLY )
667 {
668 for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
669 {
670 for( const VECTOR2I& pt : GetPolyShape().Outline( ii ).CPoints() )
671 pts.emplace_back( pt );
672 }
673 }
674 else
675 {
677 }
678
679 while( pts.size() < 4 )
680 pts.emplace_back( pts.back() + VECTOR2I( 10, 10 ) );
681
682 return pts;
683}
684
685
686void PCB_SHAPE::Move( const VECTOR2I& aMoveVector )
687{
688 move( aMoveVector );
690}
691
692
693void PCB_SHAPE::Scale( double aScale )
694{
695 scale( aScale );
696}
697
698
700{
702 {
703 VECTOR2I start = GetStart();
704 VECTOR2I end = GetEnd();
705
706 BOX2I rect( start, end - start );
707 rect.Normalize();
708
709 SetStart( rect.GetPosition() );
710 SetEnd( rect.GetEnd() );
711 }
712 else if( m_shape == SHAPE_T::POLY )
713 {
714 auto horizontal =
715 []( const SEG& seg )
716 {
717 return seg.A.y == seg.B.y;
718 };
719
720 auto vertical =
721 []( const SEG& seg )
722 {
723 return seg.A.x == seg.B.x;
724 };
725
726 // Convert a poly back to a rectangle if appropriate
727 if( GetPolyShape().OutlineCount() == 1 && GetPolyShape().Outline( 0 ).SegmentCount() == 4 )
728 {
729 SHAPE_LINE_CHAIN& outline = GetPolyShape().Outline( 0 );
730
731 if( horizontal( outline.Segment( 0 ) )
732 && vertical( outline.Segment( 1 ) )
733 && horizontal( outline.Segment( 2 ) )
734 && vertical( outline.Segment( 3 ) ) )
735 {
737 m_start.x = std::min( outline.Segment( 0 ).A.x, outline.Segment( 0 ).B.x );
738 m_start.y = std::min( outline.Segment( 1 ).A.y, outline.Segment( 1 ).B.y );
739 m_end.x = std::max( outline.Segment( 0 ).A.x, outline.Segment( 0 ).B.x );
740 m_end.y = std::max( outline.Segment( 1 ).A.y, outline.Segment( 1 ).B.y );
741 }
742 else if( vertical( outline.Segment( 0 ) )
743 && horizontal( outline.Segment( 1 ) )
744 && vertical( outline.Segment( 2 ) )
745 && horizontal( outline.Segment( 3 ) ) )
746 {
748 m_start.x = std::min( outline.Segment( 1 ).A.x, outline.Segment( 1 ).B.x );
749 m_start.y = std::min( outline.Segment( 0 ).A.y, outline.Segment( 0 ).B.y );
750 m_end.x = std::max( outline.Segment( 1 ).A.x, outline.Segment( 1 ).B.x );
751 m_end.y = std::max( outline.Segment( 0 ).A.y, outline.Segment( 0 ).B.y );
752 }
753 }
754 }
755}
756
757
759{
761 {
762 VECTOR2I libStart = GetLibraryStart();
763 VECTOR2I libEnd = GetLibraryEnd();
764
765 if( ( libStart.x > libEnd.x ) || ( libStart.x == libEnd.x && libStart.y < libEnd.y ) )
766 {
767 VECTOR2I s = GetStart();
768 VECTOR2I e = GetEnd();
769 SetStart( e );
770 SetEnd( s );
771 }
772 }
773 else
774 Normalize();
775}
776
777
778void PCB_SHAPE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
779{
780 rotate( aRotCentre, aAngle );
782}
783
784
785void PCB_SHAPE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
786{
787 // Null for pad-local primitives, which mirror directly rather than through the FP transform.
788 const FOOTPRINT* fp = transformFp();
789
790 if( fp
793 {
794 const VECTOR2I libCenter = fp->GetTransform().InverseApply( aCentre );
795
796 auto mirrorPt = [&]( VECTOR2I& p )
797 {
798 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
799 p.x = 2 * libCenter.x - p.x;
800 else
801 p.y = 2 * libCenter.y - p.y;
802 };
803
804 if( m_libShape == SHAPE_T::ARC )
805 {
806 mirrorPt( m_libStart );
807 mirrorPt( m_libEnd );
808 mirrorPt( m_libArcMid );
809 std::swap( m_libStart, m_libEnd );
810 }
811 else
812 {
813 mirrorPt( m_libStart );
814 mirrorPt( m_libEnd );
815 }
816
818 {
819 mirrorPt( m_libBezierC1 );
820 mirrorPt( m_libBezierC2 );
821 }
822
824 {
825 for( auto it = m_libPoly.IterateWithHoles(); it; it++ )
826 {
827 VECTOR2I p = *it;
828 mirrorPt( p );
829 m_libPoly.SetVertex( it.GetIndex(), p );
830 }
831 }
832
835 return;
836 }
837
839 {
840 const VECTOR2I libCenter = fp->GetTransform().InverseApply( aCentre );
841
842 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
843 m_libEllipseCenter.x = 2 * libCenter.x - m_libEllipseCenter.x;
844 else
845 m_libEllipseCenter.y = 2 * libCenter.y - m_libEllipseCenter.y;
846
848
849 const EDA_ANGLE oldStart = m_libEllipseStartAngle;
850 const EDA_ANGLE oldEnd = m_libEllipseEndAngle;
851
852 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
853 {
855 m_libEllipseEndAngle = ANGLE_180 - oldStart;
856 }
857 else
858 {
859 m_libEllipseStartAngle = -oldEnd;
860 m_libEllipseEndAngle = -oldStart;
861 }
862
865 return;
866 }
867
868 flip( aCentre, aFlipDirection );
869
872}
873
874
875void PCB_SHAPE::SetStart( const VECTOR2I& aStart )
876{
877 EDA_SHAPE::SetStart( aStart );
879}
880
881
882void PCB_SHAPE::SetEnd( const VECTOR2I& aEnd )
883{
884 EDA_SHAPE::SetEnd( aEnd );
886}
887
888
889void PCB_SHAPE::OnFootprintRescaled( double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I& aAnchor,
890 const EDA_ANGLE& aParentRotate )
891{
893}
894
895
896void PCB_SHAPE::SetWidth( int aWidth )
897{
898 const double s = fpScaleLinear( transformFp() );
899
900 if( s == 1.0 )
901 m_stroke.SetWidth( aWidth );
902 else
903 m_stroke.SetWidth( KiROUND( aWidth / s ) );
904
905 m_hatchingDirty = true;
906}
907
908
910{
911 m_stroke.SetWidth( aWidth );
912 m_hatchingDirty = true;
913}
914
915
917{
919 s.SetWidth( GetWidth() );
920 return s;
921}
922
923
925{
926 m_stroke = aStroke;
927 SetWidth( aStroke.GetWidth() );
928}
929
930
931void PCB_SHAPE::RebakeWithScale( double aScaleX, double aScaleY )
932{
933 TRANSFORM_TRS xform;
934 xform.SetScale( aScaleX, aScaleY );
935 rebakeFromTransform( xform );
936}
937
938
940{
941 const FOOTPRINT* fp = transformFp();
942
943 if( !fp )
944 return;
945
947}
948
949
951{
952 const bool nonUniform = xform.GetScaleX() != xform.GetScaleY();
953
955 {
956 VECTOR2I libCenter = m_libStart;
957 int libRadius = ( m_libEnd - m_libStart ).EuclideanNorm();
958 VECTOR2I newCenter = xform.Apply( libCenter );
959
960 if( nonUniform )
961 {
962 int majorRadius = std::abs( KiROUND( libRadius * xform.GetScaleX() ) );
963 int minorRadius = std::abs( KiROUND( libRadius * xform.GetScaleY() ) );
964
965 EDA_ANGLE rotation = -xform.GetRotate();
966
967 if( minorRadius > majorRadius )
968 {
969 std::swap( majorRadius, minorRadius );
970 rotation += EDA_ANGLE( 90.0, DEGREES_T );
971 }
972
974 SetEllipseCenter( newCenter );
975 SetEllipseMajorRadius( majorRadius );
976 SetEllipseMinorRadius( minorRadius );
977 SetEllipseRotation( rotation );
978 }
979 else
980 {
982 EDA_SHAPE::SetStart( newCenter );
983 EDA_SHAPE::SetEnd( xform.Apply( m_libEnd ) );
984 }
985
986 return;
987 }
988
989 if( m_libShape == SHAPE_T::ARC )
990 {
992 int libRadius = ( m_libStart - libCenter ).EuclideanNorm();
993 VECTOR2I newCenter = xform.Apply( libCenter );
994
995 if( nonUniform )
996 {
997 int majorRadius = std::abs( KiROUND( libRadius * xform.GetScaleX() ) );
998 int minorRadius = std::abs( KiROUND( libRadius * xform.GetScaleY() ) );
999
1000 EDA_ANGLE rotation = -xform.GetRotate();
1001 EDA_ANGLE startAngle( VECTOR2D( m_libStart - libCenter ) );
1002 EDA_ANGLE midAngle( VECTOR2D( m_libArcMid - libCenter ) );
1003 EDA_ANGLE endAngle( VECTOR2D( m_libEnd - libCenter ) );
1004
1005 auto wrap = []( EDA_ANGLE a, EDA_ANGLE base )
1006 {
1007 while( a < base )
1008 a += ANGLE_360;
1009 return a;
1010 };
1011
1012 if( wrap( midAngle, startAngle ) > wrap( endAngle, startAngle ) )
1013 std::swap( startAngle, endAngle );
1014
1015 while( endAngle < startAngle )
1016 endAngle += ANGLE_360;
1017
1018 if( minorRadius > majorRadius )
1019 {
1020 std::swap( majorRadius, minorRadius );
1021 rotation += EDA_ANGLE( 90.0, DEGREES_T );
1022 startAngle -= EDA_ANGLE( 90.0, DEGREES_T );
1023 endAngle -= EDA_ANGLE( 90.0, DEGREES_T );
1024 }
1025
1027 SetEllipseCenter( newCenter );
1028 SetEllipseMajorRadius( majorRadius );
1029 SetEllipseMinorRadius( minorRadius );
1030 SetEllipseRotation( rotation );
1031 SetEllipseStartAngle( startAngle );
1032 SetEllipseEndAngle( endAngle );
1033 }
1034 else
1035 {
1038 }
1039
1040 return;
1041 }
1042
1044 {
1045 // The linear transform preserves ellipse-ness only when scale is uniform
1046 // or the lib ellipse's axes are aligned with the scale axes (cardinal lib
1047 // rotation). Otherwise the result is a sheared shape that no standard
1048 // ellipse can represent; tessellate to POLY in that case.
1049 const bool keepNative = xform.IsUniformScale() || m_libEllipseRotation.IsCardinal();
1050
1051 if( keepNative )
1052 {
1055
1056 if( xform.IsUniformScale() )
1057 {
1058 double absScale = std::abs( xform.GetScaleX() );
1062
1064 {
1067 }
1068 }
1069 else
1070 {
1071 BOARD_ELLIPSE be = decomposeBoardEllipse( xform, m_libEllipseMajorRadius,
1074
1077 EDA_SHAPE::SetEllipseRotation( be.rotation );
1078
1080 {
1083 }
1084 }
1085 }
1086 else
1087 {
1088 const bool isArc = ( m_libShape == SHAPE_T::ELLIPSE_ARC );
1089
1090 std::unique_ptr<SHAPE_ELLIPSE> libEllipse;
1091
1092 if( isArc )
1093 {
1094 libEllipse = std::make_unique<SHAPE_ELLIPSE>(
1097 }
1098 else
1099 {
1100 libEllipse = std::make_unique<SHAPE_ELLIPSE>(
1103 }
1104
1105 SHAPE_LINE_CHAIN chain = libEllipse->ConvertToPolyline( getMaxError() );
1106
1108 SHAPE_POLY_SET& poly = GetPolyShape();
1109 poly.RemoveAllContours();
1110 poly.NewOutline();
1111
1112 for( int ii = 0; ii < chain.PointCount(); ++ii )
1113 poly.Append( xform.Apply( chain.CPoint( ii ) ) );
1114
1115 poly.Outline( 0 ).SetClosed( !isArc );
1116 }
1117
1118 return;
1119 }
1120
1122 {
1123 const VECTOR2I c1 = xform.Apply( m_libStart );
1124 const VECTOR2I c2 = xform.Apply( VECTOR2I( m_libEnd.x, m_libStart.y ) );
1125 const VECTOR2I c3 = xform.Apply( m_libEnd );
1126 const VECTOR2I c4 = xform.Apply( VECTOR2I( m_libStart.x, m_libEnd.y ) );
1127
1128 if( xform.GetRotate().IsCardinal() )
1129 {
1131 BOX2I bbox( c1, VECTOR2I( 0, 0 ) );
1132 bbox.Merge( c2 );
1133 bbox.Merge( c3 );
1134 bbox.Merge( c4 );
1136 EDA_SHAPE::SetEnd( bbox.GetEnd() );
1137 }
1138 else
1139 {
1141 SHAPE_POLY_SET& poly = GetPolyShape();
1142 poly.RemoveAllContours();
1143 poly.NewOutline();
1144 poly.Append( c1 );
1145 poly.Append( c2 );
1146 poly.Append( c3 );
1147 poly.Append( c4 );
1148
1149 EDA_SHAPE::SetStart( c1 );
1150 EDA_SHAPE::SetEnd( c3 );
1151 }
1152
1153 return;
1154 }
1155
1156 if( m_libShape == SHAPE_T::POLY )
1157 {
1158 SHAPE_POLY_SET& poly = GetPolyShape();
1159 poly = m_libPoly;
1160
1161 for( auto it = poly.IterateWithHoles(); it; it++ )
1162 poly.SetVertex( it.GetIndex(), xform.Apply( *it ) );
1163
1164 // m_libStart/m_libEnd are not seeded for POLY, skip the start/end fall-through below.
1165 return;
1166 }
1167
1169 EDA_SHAPE::SetEnd( xform.Apply( m_libEnd ) );
1170
1172 {
1176 }
1177}
1178
1179
1181{
1182 if( m_libShape == SHAPE_T::ARC )
1183 return m_libArcMid;
1184
1185 if( const FOOTPRINT* fp = transformFp() )
1186 return fp->GetTransform().InverseApply( GetArcMid() );
1187
1188 return GetArcMid();
1189}
1190
1191
1193{
1194 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1195 return m_libBezierC1;
1196
1197 if( const FOOTPRINT* fp = transformFp() )
1198 return fp->GetTransform().InverseApply( GetBezierC1() );
1199
1200 return GetBezierC1();
1201}
1202
1203
1205{
1206 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1207 return m_libBezierC2;
1208
1209 if( const FOOTPRINT* fp = transformFp() )
1210 return fp->GetTransform().InverseApply( GetBezierC2() );
1211
1212 return GetBezierC2();
1213}
1214
1215
1217{
1218 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1219 return m_libPoly;
1220
1222
1223 if( const FOOTPRINT* fp = transformFp() )
1224 {
1225 const TRANSFORM_TRS& xform = fp->GetTransform();
1226
1227 for( auto it = poly.IterateWithHoles(); it; it++ )
1228 poly.SetVertex( it.GetIndex(), xform.InverseApply( *it ) );
1229 }
1230
1231 return poly;
1232}
1233
1234
1235void PCB_SHAPE::SetArcGeometry( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
1236{
1237 EDA_SHAPE::SetArcGeometry( aStart, aMid, aEnd );
1238 syncLibCoords();
1239}
1240
1241
1243{
1245 syncLibCoords();
1246}
1247
1248
1250{
1252 syncLibCoords();
1253}
1254
1255
1257{
1258 EDA_SHAPE::SetPolyShape( aShape );
1259 syncLibCoords();
1260}
1261
1262
1264{
1266 syncLibCoords();
1267}
1268
1269
1275
1276
1282
1283
1289
1290
1296
1297
1303
1304
1306{
1307 TRANSFORM_TRS xform;
1308 bool hasXform = false;
1309
1310 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1311 {
1312 double sx = 1.0, sy = 1.0;
1313 static_cast<const PAD*>( static_cast<const BOARD_ITEM*>( GetParent() ) )->GetPrimitiveLibScale( sx, sy );
1314 xform.SetScale( sx, sy );
1315 hasXform = ( sx != 1.0 || sy != 1.0 );
1316 }
1317 else if( const FOOTPRINT* fp = transformFp() )
1318 {
1319 xform = fp->GetTransform();
1320 hasXform = true;
1321 }
1322
1324 {
1325 if( hasXform )
1326 {
1328
1329 if( xform.IsUniformScale() )
1330 {
1331 double invScale = 1.0 / std::abs( xform.GetScaleX() );
1337 }
1338 else
1339 {
1340 // Non-uniform scale shears the ellipse, so invert the whole board ellipse to lib.
1341 BOARD_ELLIPSE le = composeLibEllipse( xform, GetEllipseMajorRadius(), GetEllipseMinorRadius(),
1343 m_libEllipseMajorRadius = KiROUND( le.major );
1344 m_libEllipseMinorRadius = KiROUND( le.minor );
1345 m_libEllipseRotation = le.rotation;
1346 m_libEllipseStartAngle = GetEllipseStartAngle() + le.startShift;
1347 m_libEllipseEndAngle = GetEllipseEndAngle() + le.startShift;
1348 }
1349 }
1350 else
1351 {
1358 }
1359
1360 return;
1361 }
1362
1363 if( m_shape == SHAPE_T::POLY )
1364 {
1366
1367 if( hasXform )
1368 {
1369 for( auto it = m_libPoly.IterateWithHoles(); it; it++ )
1370 m_libPoly.SetVertex( it.GetIndex(), xform.InverseApply( *it ) );
1371 }
1372
1373 return;
1374 }
1375
1376 if( hasXform )
1377 {
1378 m_libStart = xform.InverseApply( GetStart() );
1379 m_libEnd = xform.InverseApply( GetEnd() );
1380
1381 if( m_shape == SHAPE_T::ARC )
1382 m_libArcMid = xform.InverseApply( GetArcMid() );
1383
1384 if( m_shape == SHAPE_T::BEZIER )
1385 {
1388 }
1389 }
1390 else
1391 {
1392 m_libStart = GetStart();
1393 m_libEnd = GetEnd();
1394
1395 if( m_shape == SHAPE_T::ARC )
1397
1398 if( m_shape == SHAPE_T::BEZIER )
1399 {
1402 }
1403 }
1404}
1405
1406
1407void PCB_SHAPE::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1408{
1409 flip( aCentre, aFlipDirection );
1410}
1411
1412
1413void PCB_SHAPE::SetIsProxyItem( bool aIsProxy )
1414{
1415 PAD* parentPad = nullptr;
1416
1417 if( GetBoard() && GetBoard()->IsFootprintHolder() )
1418 {
1419 for( FOOTPRINT* fp : GetBoard()->Footprints() )
1420 {
1421 for( PAD* pad : fp->Pads() )
1422 {
1423 if( pad->IsEntered() )
1424 {
1425 parentPad = pad;
1426 break;
1427 }
1428 }
1429 }
1430 }
1431
1432 if( aIsProxy && !m_proxyItem )
1433 {
1434 if( GetShape() == SHAPE_T::SEGMENT )
1435 {
1436 if( parentPad && parentPad->GetLocalThermalSpokeWidthOverride().has_value() )
1437 SetWidth( parentPad->GetLocalThermalSpokeWidthOverride().value() );
1438 else
1440 }
1441 else
1442 {
1443 SetWidth( 1 );
1444 }
1445 }
1446 else if( m_proxyItem && !aIsProxy )
1447 {
1449 }
1450
1451 m_proxyItem = aIsProxy;
1452}
1453
1454
1455double PCB_SHAPE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
1456{
1457 KIGFX::PCB_PAINTER& painter = static_cast<KIGFX::PCB_PAINTER&>( *aView->GetPainter() );
1458 KIGFX::PCB_RENDER_SETTINGS& renderSettings = *painter.GetSettings();
1459
1460 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
1461 {
1462 // Hide shadow if the main layer is not shown
1463 if( !aView->IsLayerVisibleCached( m_layer ) )
1464 return LOD_HIDE;
1465
1466 // Hide shadow on dimmed tracks
1467 if( renderSettings.GetHighContrast() )
1468 {
1469 if( m_layer != renderSettings.GetPrimaryHighContrastLayer() )
1470 return LOD_HIDE;
1471 }
1472 }
1473
1474 if( FOOTPRINT* parent = GetParentFootprint() )
1475 {
1476 PCB_LAYER_ID checkLayer = m_layer;
1477
1478 if( !IsFrontLayer( checkLayer ) && !IsBackLayer( checkLayer ) )
1479 checkLayer = parent->GetLayer();
1480
1481 if( IsFrontLayer( checkLayer ) && !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_FR ) )
1482 return LOD_HIDE;
1483
1484 if( IsBackLayer( checkLayer ) && !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_BK ) )
1485 return LOD_HIDE;
1486 }
1487
1488 return LOD_SHOW;
1489}
1490
1491
1492std::vector<int> PCB_SHAPE::ViewGetLayers() const
1493{
1494 std::vector<int> layers;
1495 layers.reserve( 4 );
1496
1497 layers.push_back( GetLayer() );
1498
1499 if( IsOnCopperLayer() )
1500 {
1501 layers.push_back( GetNetnameLayer( GetLayer() ) );
1502
1503 if( m_hasSolderMask )
1504 {
1505 if( m_layer == F_Cu )
1506 layers.push_back( F_Mask );
1507 else if( m_layer == B_Cu )
1508 layers.push_back( B_Mask );
1509 }
1510 }
1511
1513 layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
1514
1515 return layers;
1516}
1517
1518
1519void PCB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1520{
1521 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1522 {
1523 if( FOOTPRINT* parent = GetParentFootprint() )
1524 aList.emplace_back( _( "Footprint" ), parent->GetReference() );
1525 }
1526
1527 aList.emplace_back( _( "Type" ), _( "Drawing" ) );
1528
1529 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
1530 aList.emplace_back( _( "Status" ), _( "Locked" ) );
1531
1532 ShapeGetMsgPanelInfo( aFrame, aList );
1533
1534 aList.emplace_back( _( "Layer" ), GetLayerName() );
1535
1536 if( IsOnCopperLayer() )
1537 {
1538 if( GetNetCode() > 0 ) // Only graphics connected to a net have a netcode > 0
1539 aList.emplace_back( _( "Net" ), GetNetname() );
1540 }
1541}
1542
1543
1544wxString PCB_SHAPE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1545{
1546 FOOTPRINT* parentFP = GetParentFootprint();
1547
1548 // Don't report parent footprint info from footprint editor, viewer, etc.
1549 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
1550 parentFP = nullptr;
1551
1552 if( IsOnCopperLayer() )
1553 {
1554 if( parentFP )
1555 {
1556 return wxString::Format( _( "%s %s of %s on %s" ),
1558 GetNetnameMsg(),
1559 parentFP->GetReference(),
1560 GetLayerName() );
1561 }
1562 else
1563 {
1564 return wxString::Format( _( "%s %s on %s" ),
1566 GetNetnameMsg(),
1567 GetLayerName() );
1568 }
1569 }
1570 else
1571 {
1572 if( parentFP )
1573 {
1574 return wxString::Format( _( "%s of %s on %s" ),
1576 parentFP->GetReference(),
1577 GetLayerName() );
1578 }
1579 else
1580 {
1581 return wxString::Format( _( "%s on %s" ),
1583 GetLayerName() );
1584 }
1585 }
1586}
1587
1588
1590{
1591 if( GetParentFootprint() )
1593 else
1595}
1596
1597
1599{
1600 return new PCB_SHAPE( *this );
1601}
1602
1603
1605{
1606 BOX2I return_box = EDA_ITEM::ViewBBox();
1607
1608 // Inflate the bounding box by just a bit more for safety.
1609 return_box.Inflate( GetWidth() );
1610
1611 return return_box;
1612}
1613
1614
1615std::shared_ptr<SHAPE> PCB_SHAPE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
1616{
1617 return std::make_shared<SHAPE_COMPOUND>( MakeEffectiveShapes() );
1618}
1619
1620
1622{
1623 return GetMaxError();
1624}
1625
1626
1628{
1629 PCB_SHAPE* image = dynamic_cast<PCB_SHAPE*>( aImage );
1630 wxCHECK( image, /* void */ );
1631
1632 SwapShape( image );
1633
1634 // Swap params not handled by SwapShape( image )
1635 std::swap( m_layer, image->m_layer );
1636 std::swap( m_isKnockout, image->m_isKnockout );
1637 std::swap( m_isLocked, image->m_isLocked );
1638 std::swap( m_flags, image->m_flags );
1639 std::swap( m_parent, image->m_parent );
1640 std::swap( m_forceVisible, image->m_forceVisible );
1641 std::swap( m_netinfo, image->m_netinfo );
1642 std::swap( m_hasSolderMask, image->m_hasSolderMask );
1643 std::swap( m_solderMaskMargin, image->m_solderMaskMargin );
1644}
1645
1646
1648 const BOARD_ITEM* aSecond ) const
1649{
1650 if( aFirst->Type() != aSecond->Type() )
1651 return aFirst->Type() < aSecond->Type();
1652
1653 if( aFirst->GetLayer() != aSecond->GetLayer() )
1654 return aFirst->GetLayer() < aSecond->GetLayer();
1655
1656 if( aFirst->Type() == PCB_SHAPE_T )
1657 {
1658 const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( aFirst );
1659 const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( aSecond );
1660
1661 if( dwgA->GetShape() != dwgB->GetShape() )
1662 return dwgA->GetShape() < dwgB->GetShape();
1663 }
1664
1665 return aFirst->m_Uuid < aSecond->m_Uuid;
1666}
1667
1668
1670 int aClearance, int aError, ERROR_LOC aErrorLoc,
1671 bool ignoreLineWidth ) const
1672{
1673 EDA_SHAPE::TransformShapeToPolygon( aBuffer, aClearance, aError, aErrorLoc, ignoreLineWidth,
1674 false );
1675}
1676
1677
1679 int aClearance, int aError, ERROR_LOC aErrorLoc,
1680 KIGFX::RENDER_SETTINGS* aRenderSettings ) const
1681{
1682 EDA_SHAPE::TransformShapeToPolygon( aBuffer, aClearance, aError, aErrorLoc, false, true );
1683}
1684
1685
1686bool PCB_SHAPE::operator==( const BOARD_ITEM& aOther ) const
1687{
1688 if( aOther.Type() != Type() )
1689 return false;
1690
1691 const PCB_SHAPE& other = static_cast<const PCB_SHAPE&>( aOther );
1692
1693 return *this == other;
1694}
1695
1696
1697bool PCB_SHAPE::operator==( const PCB_SHAPE& aOther ) const
1698{
1699 if( aOther.Type() != Type() )
1700 return false;
1701
1702 const PCB_SHAPE& other = static_cast<const PCB_SHAPE&>( aOther );
1703
1704 if( m_layer != other.m_layer )
1705 return false;
1706
1707 if( m_isKnockout != other.m_isKnockout )
1708 return false;
1709
1710 if( m_isLocked != other.m_isLocked )
1711 return false;
1712
1713 if( m_flags != other.m_flags )
1714 return false;
1715
1716 if( m_forceVisible != other.m_forceVisible )
1717 return false;
1718
1719 if( m_netinfo->GetNetCode() != other.m_netinfo->GetNetCode() )
1720 return false;
1721
1722 if( m_hasSolderMask != other.m_hasSolderMask )
1723 return false;
1724
1726 return false;
1727
1728 return EDA_SHAPE::operator==( other );
1729}
1730
1731
1732double PCB_SHAPE::Similarity( const BOARD_ITEM& aOther ) const
1733{
1734 if( aOther.Type() != Type() )
1735 return 0.0;
1736
1737 const PCB_SHAPE& other = static_cast<const PCB_SHAPE&>( aOther );
1738
1739 double similarity = 1.0;
1740
1741 if( GetLayer() != other.GetLayer() )
1742 similarity *= 0.9;
1743
1744 if( m_isKnockout != other.m_isKnockout )
1745 similarity *= 0.9;
1746
1747 if( m_isLocked != other.m_isLocked )
1748 similarity *= 0.9;
1749
1750 if( m_flags != other.m_flags )
1751 similarity *= 0.9;
1752
1753 if( m_forceVisible != other.m_forceVisible )
1754 similarity *= 0.9;
1755
1756 if( m_netinfo->GetNetCode() != other.m_netinfo->GetNetCode() )
1757 similarity *= 0.9;
1758
1759 if( m_hasSolderMask != other.m_hasSolderMask )
1760 similarity *= 0.9;
1761
1763 similarity *= 0.9;
1764
1765 similarity *= EDA_SHAPE::Similarity( other );
1766
1767 return similarity;
1768}
1769
1770
1771static struct PCB_SHAPE_DESC
1772{
1774 {
1781
1782 // Need to initialise enum_map before we can use a Property enum for it
1784
1785 if( layerEnum.Choices().GetCount() == 0 )
1786 {
1787 layerEnum.Undefined( UNDEFINED_LAYER );
1788
1789 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
1790 layerEnum.Map( layer, LSET::Name( layer ) );
1791 }
1792
1793 void ( PCB_SHAPE::*shapeLayerSetter )( PCB_LAYER_ID ) = &PCB_SHAPE::SetLayer;
1794 PCB_LAYER_ID ( PCB_SHAPE::*shapeLayerGetter )() const = &PCB_SHAPE::GetLayer;
1795
1796 auto layerProperty = new PROPERTY_ENUM<PCB_SHAPE, PCB_LAYER_ID>(
1797 _HKI( "Layer" ), shapeLayerSetter, shapeLayerGetter );
1798
1799 propMgr.ReplaceProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ), layerProperty );
1800
1801 auto isPolygonOrEllipse = []( INSPECTABLE* aItem ) -> bool
1802 {
1803 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1804 {
1805 const SHAPE_T t = shape->GetShape();
1806 return t == SHAPE_T::POLY || t == SHAPE_T::ELLIPSE || t == SHAPE_T::ELLIPSE_ARC;
1807 }
1808 return false;
1809 };
1810
1811 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
1812 isPolygonOrEllipse );
1813 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
1814 isPolygonOrEllipse );
1815
1816 propMgr.Mask( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Color" ) );
1817 propMgr.Mask( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Fill Color" ) );
1818
1819 auto isNotBezierOrEllipseArc = []( INSPECTABLE* aItem ) -> bool
1820 {
1821 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1822 {
1823 const SHAPE_T t = shape->GetShape();
1824 return t != SHAPE_T::BEZIER && t != SHAPE_T::ELLIPSE_ARC;
1825 }
1826 return true;
1827 };
1828
1830 isNotBezierOrEllipseArc );
1831
1832 auto isCircle =
1833 []( INSPECTABLE* aItem ) -> bool
1834 {
1835 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1836 return shape->GetShape() == SHAPE_T::CIRCLE;
1837
1838 return false;
1839 };
1840
1841 auto isNotCircleOrEllipse = []( INSPECTABLE* aItem ) -> bool
1842 {
1843 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1844 {
1845 const SHAPE_T t = shape->GetShape();
1846 return t != SHAPE_T::CIRCLE && t != SHAPE_T::ELLIPSE && t != SHAPE_T::ELLIPSE_ARC;
1847 }
1848 return true;
1849 };
1850
1851 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start X" ),
1852 isNotCircleOrEllipse );
1853 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start Y" ),
1854 isNotCircleOrEllipse );
1855 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "End X" ),
1856 isNotCircleOrEllipse );
1857 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "End Y" ),
1858 isNotCircleOrEllipse );
1860 _HKI( "Center X" ), isCircle );
1862 _HKI( "Center Y" ), isCircle );
1864 _HKI( "Radius" ), isCircle );
1865
1866 auto isCopper =
1867 []( INSPECTABLE* aItem ) -> bool
1868 {
1869 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1870 return shape->IsOnCopperLayer();
1871
1872 return false;
1873 };
1874
1876 _HKI( "Net" ), isCopper );
1877
1878 auto isPadEditMode =
1879 []( BOARD* aBoard ) -> bool
1880 {
1881 if( aBoard && aBoard->IsFootprintHolder() )
1882 {
1883 for( FOOTPRINT* fp : aBoard->Footprints() )
1884 {
1885 for( PAD* pad : fp->Pads() )
1886 {
1887 if( pad->IsEntered() )
1888 return true;
1889 }
1890 }
1891 }
1892
1893 return false;
1894 };
1895
1896 auto showNumberBoxProperty =
1897 [&]( INSPECTABLE* aItem ) -> bool
1898 {
1899 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1900 {
1901 if( shape->GetShape() == SHAPE_T::RECTANGLE )
1902 return isPadEditMode( shape->GetBoard() );
1903 }
1904
1905 return false;
1906 };
1907
1908 auto showSpokeTemplateProperty =
1909 [&]( INSPECTABLE* aItem ) -> bool
1910 {
1911 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1912 {
1913 if( shape->GetShape() == SHAPE_T::SEGMENT )
1914 return isPadEditMode( shape->GetBoard() );
1915 }
1916
1917 return false;
1918 };
1919
1920 const wxString groupPadPrimitives = _HKI( "Pad Primitives" );
1921
1922 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, bool>( _HKI( "Number Box" ),
1925 groupPadPrimitives )
1926 .SetAvailableFunc( showNumberBoxProperty )
1928
1929 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, bool>( _HKI( "Thermal Spoke Template" ),
1931 groupPadPrimitives )
1932 .SetAvailableFunc( showSpokeTemplateProperty )
1934
1935 const wxString groupTechLayers = _HKI( "Technical Layers" );
1936
1937 auto isExternalCuLayer =
1938 []( INSPECTABLE* aItem )
1939 {
1940 if( auto shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1941 return IsExternalCopperLayer( shape->GetLayer() );
1942
1943 return false;
1944 };
1945
1946 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, bool>( _HKI( "Soldermask" ),
1948 groupTechLayers )
1949 .SetAvailableFunc( isExternalCuLayer );
1950
1951 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
1954 groupTechLayers )
1955 .SetAvailableFunc( isExternalCuLayer );
1956 }
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:47
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
constexpr int ARC_LOW_DEF
Definition base_units.h:136
BITMAPS
A list of all bitmap identifiers.
@ add_dashed_line
@ FPHOLDER
Definition board.h:364
#define DEFAULT_LINE_WIDTH
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
BOARD_CONNECTED_ITEM(BOARD_ITEM *aParent, KICAD_T idtype)
void PackNet(kiapi::board::types::Net *aProto) const
NETINFO_ITEM * m_netinfo
Store all information about the net that item belongs to.
void UnpackNet(const kiapi::board::types::Net &aProto)
Assigns a net to this item from an API message.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:83
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:265
friend class BOARD
Definition board_item.h:512
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:356
bool m_isKnockout
Definition board_item.h:509
PCB_LAYER_ID m_layer
Definition board_item.h:508
bool m_isLocked
Definition board_item.h:510
bool IsLocked() const override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:313
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:231
virtual bool IsOnCopperLayer() const
Definition board_item.h:172
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
int GetMaxError() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
constexpr const Vec & GetPosition() const
Definition box2.h:207
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr const Vec GetEnd() const
Definition box2.h:208
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:142
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr const Vec & GetOrigin() const
Definition box2.h:206
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:307
Represent basic circle geometry with utility geometry functions.
Definition circle.h:33
MINOPTMAX< int > m_Value
Definition drc_rule.h:240
bool IsCardinal() const
Definition eda_angle.cpp:40
double AsRadians() const
Definition eda_angle.h:120
The base class for create windows for drawing purpose.
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:135
const KIID m_Uuid
Definition eda_item.h:531
bool m_forceVisible
Definition eda_item.h:548
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:542
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:202
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition eda_item.cpp:370
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:543
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:37
virtual int GetHatchLineSpacing() const
Definition eda_shape.h:176
SHAPE_T m_shape
Definition eda_shape.h:592
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:244
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false, bool includeFill=false) const
Convert the shape to a closed polygon.
int GetEllipseMinorRadius() const
Definition eda_shape.h:310
bool m_proxyItem
Definition eda_shape.h:618
bool m_hatchingDirty
Definition eda_shape.h:598
bool m_endsSwapped
Definition eda_shape.h:591
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:283
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:292
int m_editState
Definition eda_shape.h:617
void rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle)
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:338
int GetEllipseMajorRadius() const
Definition eda_shape.h:301
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition eda_shape.h:462
SHAPE_POLY_SET & GetPolyShape()
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:319
void ShapeGetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList)
virtual void SetEllipseEndAngle(const EDA_ANGLE &aA)
Definition eda_shape.h:331
bool operator==(const EDA_SHAPE &aOther) const
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:185
virtual void SetBezierC2(const VECTOR2I &aPt)
Definition eda_shape.h:282
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
VECTOR2I m_arcCenter
Definition eda_shape.h:607
virtual void SetBezierC1(const VECTOR2I &aPt)
Definition eda_shape.h:279
virtual void SetEllipseRotation(const EDA_ANGLE &aA)
Definition eda_shape.h:312
ARC_MID m_arcMidData
Definition eda_shape.h:608
bool IsSolidFill() const
Definition eda_shape.h:133
void flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
EDA_SHAPE(SHAPE_T aType, int aLineWidth, FILL_T aFill)
Definition eda_shape.cpp:53
VECTOR2I m_start
Definition eda_shape.h:604
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
virtual void SetEllipseCenter(const VECTOR2I &aPt)
Definition eda_shape.h:285
virtual void SetEllipseMinorRadius(int aR)
Definition eda_shape.h:303
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
virtual void SetEllipseMajorRadius(int aR)
Definition eda_shape.h:294
void SwapShape(EDA_SHAPE *aImage)
std::vector< VECTOR2I > GetRectCorners() const
bool IsAnyFill() const
Definition eda_shape.h:128
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:329
virtual void UpdateHatching() const
virtual void SetEllipseStartAngle(const EDA_ANGLE &aA)
Definition eda_shape.h:322
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
wxString SHAPE_T_asString() const
double Similarity(const EDA_SHAPE &aOther) const
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:280
VECTOR2I m_end
Definition eda_shape.h:605
virtual int GetWidth() const
Definition eda_shape.h:173
STROKE_PARAMS m_stroke
Definition eda_shape.h:593
void RebuildBezierToSegmentsPointsList()
Definition eda_shape.h:452
VECTOR2I m_bezierC1
Definition eda_shape.h:610
virtual void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition eda_shape.h:427
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:194
VECTOR2I m_bezierC2
Definition eda_shape.h:611
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
VECTOR2I GetArcMid() const
virtual bool IsVisible() const
Definition eda_text.h:208
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:727
static ENUM_MAP< T > & Instance()
Definition property.h:721
ENUM_MAP & Undefined(T aValue)
Definition property.h:734
wxPGChoices & Choices()
Definition property.h:772
const TRANSFORM_TRS & GetTransform() const
Definition footprint.h:419
const wxString & GetReference() const
Definition footprint.h:841
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:38
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:78
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:176
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:437
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
Definition kiid.h:44
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
void RunOnLayers(const std::function< void(PCB_LAYER_ID)> &aFunction) const
Execute a function on each layer of the LSET.
Definition lset.h:263
static const LSET & AllLayersMask()
Definition lset.cpp:637
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
T Opt() const
Definition minoptmax.h:31
bool HasOpt() const
Definition minoptmax.h:35
int GetNetCode() const
Definition netinfo.h:94
Definition pad.h:61
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:729
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition pcb_shape.h:151
virtual void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
VECTOR2I m_libEllipseCenter
Definition pcb_shape.h:377
void swapData(BOARD_ITEM *aImage) override
bool IsConnected() const override
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
void SetEllipseCenter(const VECTOR2I &aPt) override
EDA_ANGLE m_libEllipseStartAngle
Definition pcb_shape.h:381
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
VECTOR2I m_libEnd
Definition pcb_shape.h:368
VECTOR2I m_libBezierC1
Definition pcb_shape.h:372
virtual void syncLibCoords()
SHAPE_POLY_SET getHatchingKnockouts() const override
void SetBezierC1(const VECTOR2I &aPt) override
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_shape.h:332
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:78
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
VECTOR2I GetLibraryBezierC1() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
PCB_SHAPE(BOARD_ITEM *aParent, KICAD_T aItemType, SHAPE_T aShapeType)
void SetWidth(int aWidth) override
EDA_ANGLE m_libEllipseEndAngle
Definition pcb_shape.h:382
void SetLibStrokeWidth(int aWidth)
SHAPE_T m_libShape
Definition pcb_shape.h:384
void rebakeFromTransform(const TRANSFORM_TRS &aXform)
int GetWidth() const override
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
bool HasSolderMask() const
Definition pcb_shape.h:329
void SetEllipseStartAngle(const EDA_ANGLE &aA) override
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Make a set of SHAPE objects representing the PCB_SHAPE.
void SetHasSolderMask(bool aVal)
Definition pcb_shape.h:328
std::optional< int > m_solderMaskMargin
Definition pcb_shape.h:365
int GetSolderMaskExpansion() const
void NormalizeForCompare() override
Normalize coordinates to compare 2 similar PCB_SHAPES similat to Normalize(), but also normalize SEGM...
void TransformShapeToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const override
Convert the item shape to a polyset.
VECTOR2I m_libArcMid
Definition pcb_shape.h:370
void SetEllipseEndAngle(const EDA_ANGLE &aA) override
int m_libEllipseMinorRadius
Definition pcb_shape.h:379
const VECTOR2I GetFocusPosition() const override
Allows items to return their visual center rather than their anchor.
virtual void SetLayerSet(const LSET &aLayers) override
void SetEnd(const VECTOR2I &aEnd) override
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
VECTOR2I GetLibraryEnd() const
Definition pcb_shape.h:221
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
void SetPolyShape(const SHAPE_POLY_SET &aShape) override
virtual std::vector< VECTOR2I > GetCorners() const
Return 4 corners for a rectangle or rotated rectangle (stored as a poly).
bool IsProxyItem() const override
Definition pcb_shape.h:146
void SetEllipseRotation(const EDA_ANGLE &aA) override
bool m_hasSolderMask
Definition pcb_shape.h:364
const FOOTPRINT * transformFp() const
VECTOR2I GetLibraryStart() const
Definition pcb_shape.h:220
void OnFootprintRescaled(double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I &aAnchor, const EDA_ANGLE &aParentRotate) override
Apply a parent footprint scale to this item.
~PCB_SHAPE() override
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool operator==(const PCB_SHAPE &aShape) const
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetEllipseMinorRadius(int aR) override
wxString GetFriendlyName() const override
Definition pcb_shape.h:63
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
STROKE_PARAMS GetStroke() const override
void SetIsProxyItem(bool aIsProxy=true) override
void RebakeWithScale(double aScaleX, double aScaleY)
SHAPE_POLY_SET m_libPoly
Definition pcb_shape.h:375
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_shape.h:331
void Move(const VECTOR2I &aMoveVector) override
Move this object.
std::vector< VECTOR2I > GetConnectionPoints() const
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
int getMaxError() const override
void SetStart(const VECTOR2I &aStart) override
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
void SetBezierC2(const VECTOR2I &aPt) override
void UpdateHatching() const override
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
void Scale(double aScale)
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
SHAPE_POLY_SET GetLibraryPolyShape() const
void SetStroke(const STROKE_PARAMS &aStroke) override
void Normalize() override
Perform any normalization required after a user rotate and/or flip.
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
void CopyFrom(const BOARD_ITEM *aOther) override
VECTOR2I GetLibraryBezierC2() const
VECTOR2I m_libBezierC2
Definition pcb_shape.h:373
std::vector< int > ViewGetLayers() const override
void RebakeFromLib()
double Similarity(const BOARD_ITEM &aBoardItem) const override
Return a measure of how likely the other object is to represent the same object.
VECTOR2I m_libStart
Definition pcb_shape.h:367
EDA_ANGLE m_libEllipseRotation
Definition pcb_shape.h:380
int m_libEllipseMajorRadius
Definition pcb_shape.h:378
VECTOR2I GetLibraryArcMid() const
void SetEllipseMajorRadius(int aR) override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:68
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
PROPERTY_BASE & SetIsHiddenFromRulesEditor(bool aHide=true)
Definition property.h:326
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void OverrideAvailability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override availability functor for a base class property of a given derived class.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
ITERATOR IterateWithHoles(int aOutline)
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
Simple container to manage line stroke parameters.
int GetWidth() const
void SetWidth(int aWidth)
VECTOR2I InverseApply(const VECTOR2I &aPoint) const
bool IsUniformScale() const
const EDA_ANGLE & GetRotate() const
double GetScaleX() const
VECTOR2I Apply(const VECTOR2I &aPoint) const
double GetScaleY() const
void SetScale(double aSx, double aSy)
A type-safe container of any type.
Definition ki_any.h:92
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:68
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
@ RADIANS_T
Definition eda_angle.h:32
@ DEGREES_T
Definition eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
#define PCB_EDIT_FRAME_NAME
@ RECURSE
Definition eda_item.h:49
SHAPE_T
Definition eda_shape.h:44
@ UNDEFINED
Definition eda_shape.h:45
@ ELLIPSE
Definition eda_shape.h:52
@ SEGMENT
Definition eda_shape.h:46
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:47
@ ELLIPSE_ARC
Definition eda_shape.h:53
FILL_T
Definition eda_shape.h:59
@ NO_FILL
Definition eda_shape.h:60
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:173
bool IsSolderMaskLayer(int aLayer)
Definition layer_ids.h:746
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:778
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:180
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:801
int GetNetnameLayer(int aLayer)
Return a netname layer corresponding to the given layer.
Definition layer_ids.h:852
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
@ LAYER_LOCKED_ITEM_SHADOW
Shadow layer for locked items.
Definition layer_ids.h:303
@ LAYER_FOOTPRINTS_FR
Show footprints on front.
Definition layer_ids.h:255
@ LAYER_FOOTPRINTS_BK
Show footprints on back.
Definition layer_ids.h:256
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:686
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_CrtYd
Definition layer_ids.h:112
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ B_CrtYd
Definition layer_ids.h:111
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
FLIP_DIRECTION
Definition mirror.h:23
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
std::vector< TYPED_POINT2I > GetCircleKeyPoints(const CIRCLE &aCircle, bool aIncludeCenter)
Get key points of an CIRCLE.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
#define _HKI(x)
Definition page_info.cpp:40
static double fpScaleLinear(const FOOTPRINT *aFp)
static struct PCB_SHAPE_DESC _PCB_SHAPE_DESC
static bool isCopper(const PNS::ITEM *aItem)
#define TYPE_HASH(x)
Definition property.h:74
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
Utility functions for working with shapes.
const int scale
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
const SHAPE_LINE_CHAIN chain
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
#define M_PI
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition trigo.cpp:530
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ PCB_SHAPE_LOCATE_ELLIPSE_ARC_T
Definition typeinfo.h:237
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:81
@ PCB_LOCATE_BOARD_EDGE_T
Definition typeinfo.h:127
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:86
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:83
@ PCB_SHAPE_LOCATE_CIRCLE_T
Definition typeinfo.h:132
@ PCB_SHAPE_LOCATE_SEGMENT_T
Definition typeinfo.h:130
@ PCB_SHAPE_LOCATE_RECT_T
Definition typeinfo.h:131
@ PCB_SHAPE_LOCATE_ELLIPSE_T
Definition typeinfo.h:236
@ PCB_SHAPE_LOCATE_BEZIER_T
Definition typeinfo.h:135
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
@ PCB_SHAPE_LOCATE_POLY_T
Definition typeinfo.h:134
@ PCB_SHAPE_LOCATE_ARC_T
Definition typeinfo.h:133
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
#define ZONE_THERMAL_RELIEF_COPPER_WIDTH_MM
Definition zones.h:29