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 EDA_SHAPE::Serialize( *msg.mutable_shape(), pcbIUScale );
233
234 if( FOOTPRINT* parent = GetParentFootprint() )
235 msg.mutable_parent()->set_value( parent->m_Uuid.AsStdString() );
236 else if( const BOARD* board = GetBoard() )
237 msg.mutable_parent()->set_value( board->m_Uuid.AsStdString() );
238
239 if( HasSolderMask() )
240 {
241 SolderMaskOverrides* sm = msg.mutable_solder_mask();
242 sm->set_expose_copper( true );
243
244 if( GetLocalSolderMaskMargin().has_value() )
245 sm->mutable_solder_mask_margin()->set_value_nm( GetLocalSolderMaskMargin().value() );
246 }
247
248 kiapi::common::PackCustomProperties( msg.mutable_custom_properties(), *this );
249 aContainer.PackFrom( msg );
250}
251
252
253bool PCB_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
254{
255 using namespace kiapi::common;
256 using namespace kiapi::board::types;
257
258 BoardGraphicShape msg;
259
260 if( !aContainer.UnpackTo( &msg ) )
261 return false;
262
263 // Initialize everything to a known state that doesn't get touched by every
264 // codepath below, to make sure the equality operator is consistent
265 m_start = {};
266 m_end = {};
267 m_arcCenter = {};
268 m_arcMidData = {};
269 m_bezierC1 = {};
270 m_bezierC2 = {};
271 m_editState = 0;
272 m_proxyItem = false;
273 m_endsSwapped = false;
274
275 SetUuidDirect( KIID( msg.id().value() ) );
276 SetLocked( msg.locked() == types::LS_LOCKED );
278 UnpackNet( msg.net() );
279 kiapi::common::UnpackCustomProperties( msg.custom_properties(), *this );
280
281 EDA_SHAPE::Deserialize( msg.shape(), pcbIUScale );
282
283 if( msg.has_solder_mask() )
284 {
285 SetHasSolderMask( msg.solder_mask().expose_copper() );
286
287 if( msg.solder_mask().has_solder_mask_margin() )
288 SetLocalSolderMaskMargin( msg.solder_mask().solder_mask_margin().value_nm() );
289 else
291 }
292 else
293 {
294 SetHasSolderMask( false );
296 }
297
298 return true;
299}
300
301
302bool PCB_SHAPE::IsType( const std::vector<KICAD_T>& aScanTypes ) const
303{
304 if( BOARD_ITEM::IsType( aScanTypes ) )
305 return true;
306
307 bool sametype = false;
308
309 for( KICAD_T scanType : aScanTypes )
310 {
311 if( scanType == PCB_LOCATE_BOARD_EDGE_T )
312 sametype = m_layer == Edge_Cuts;
313 else if( scanType == PCB_SHAPE_LOCATE_ARC_T )
314 sametype = m_shape == SHAPE_T::ARC;
315 else if( scanType == PCB_SHAPE_LOCATE_CIRCLE_T )
316 sametype = m_shape == SHAPE_T::CIRCLE;
317 else if( scanType == PCB_SHAPE_LOCATE_RECT_T )
318 sametype = m_shape == SHAPE_T::RECTANGLE;
319 else if( scanType == PCB_SHAPE_LOCATE_SEGMENT_T )
320 sametype = m_shape == SHAPE_T::SEGMENT;
321 else if( scanType == PCB_SHAPE_LOCATE_POLY_T )
322 sametype = m_shape == SHAPE_T::POLY;
323 else if( scanType == PCB_SHAPE_LOCATE_BEZIER_T )
324 sametype = m_shape == SHAPE_T::BEZIER;
325 else if( scanType == PCB_SHAPE_LOCATE_ELLIPSE_T )
326 sametype = m_shape == SHAPE_T::ELLIPSE;
327 else if( scanType == PCB_SHAPE_LOCATE_ELLIPSE_ARC_T )
328 sametype = m_shape == SHAPE_T::ELLIPSE_ARC;
329
330 if( sametype )
331 return true;
332 }
333
334 return false;
335}
336
337
339{
340 // Only board-level copper shapes are connectable
341 return IsOnCopperLayer() && !GetParentFootprint();
342}
343
344
346{
347 BOARD_ITEM::SetLayer( aLayer );
348
349 if( !IsOnCopperLayer() )
350 SetNetCode( -1 );
351}
352
353
355{
356 int margin = 0;
357
358 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine
359 && GetBoard()->GetDesignSettings().m_DRCEngine->HasRulesForConstraintType(
361 {
362 DRC_CONSTRAINT constraint;
363 std::shared_ptr<DRC_ENGINE> drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
364
365 constraint = drcEngine->EvalRules( SOLDER_MASK_EXPANSION_CONSTRAINT, this, nullptr, m_layer );
366
367 if( constraint.m_Value.HasOpt() )
368 margin = constraint.m_Value.Opt();
369 }
370 else if( m_solderMaskMargin.has_value() )
371 {
372 margin = m_solderMaskMargin.value();
373 }
374 else if( const BOARD* board = GetBoard() )
375 {
376 margin = board->GetDesignSettings().m_SolderMaskExpansion;
377 }
378
379 // Ensure the resulting mask opening has a non-negative size
380 if( margin < 0 && !IsSolidFill() )
381 margin = std::max( margin, -GetWidth() / 2 );
382
383 return margin;
384}
385
386
388{
389 if( aLayer == m_layer )
390 {
391 return true;
392 }
393
395 && ( ( aLayer == F_Mask && m_layer == F_Cu )
396 || ( aLayer == B_Mask && m_layer == B_Cu ) ) )
397 {
398 return true;
399 }
400
401 return false;
402}
403
404
406{
407 LSET layermask( { m_layer } );
408
409 if( m_hasSolderMask )
410 {
411 if( layermask.test( F_Cu ) )
412 layermask.set( F_Mask );
413
414 if( layermask.test( B_Cu ) )
415 layermask.set( B_Mask );
416 }
417
418 return layermask;
419}
420
421
422void PCB_SHAPE::SetLayerSet( const LSET& aLayerSet )
423{
424 aLayerSet.RunOnLayers(
425 [&]( PCB_LAYER_ID layer )
426 {
427 if( IsCopperLayer( layer ) )
428 SetLayer( layer );
429 else if( IsSolderMaskLayer( layer ) )
430 SetHasSolderMask( true );
431 } );
432}
433
434
435std::vector<VECTOR2I> PCB_SHAPE::GetConnectionPoints() const
436{
437 std::vector<VECTOR2I> ret;
438
439 // For filled shapes, we may as well use a centroid
440 if( IsSolidFill() )
441 {
442 ret.emplace_back( GetCenter() );
443 return ret;
444 }
445
446 switch( m_shape )
447 {
448 case SHAPE_T::CIRCLE:
449 {
450 const CIRCLE circle( GetCenter(), GetRadius() );
451
452 for( const TYPED_POINT2I& pt : KIGEOM::GetCircleKeyPoints( circle, false ) )
453 ret.emplace_back( pt.m_point );
454
455 break;
456 }
457
458 case SHAPE_T::ARC:
459 ret.emplace_back( GetArcMid() );
461 case SHAPE_T::SEGMENT:
462 case SHAPE_T::BEZIER:
463 ret.emplace_back( GetStart() );
464 ret.emplace_back( GetEnd() );
465 break;
466
467 case SHAPE_T::POLY:
468 for( auto iter = GetPolyShape().CIterate(); iter; ++iter )
469 ret.emplace_back( *iter );
470
471 break;
472
474 for( const VECTOR2I& pt : GetRectCorners() )
475 ret.emplace_back( pt );
476
477 break;
478
479 case SHAPE_T::ELLIPSE:
480 {
481 const double phi = GetEllipseRotation().AsRadians();
482 const double cosPhi = std::cos( phi );
483 const double sinPhi = std::sin( phi );
484 const int a = GetEllipseMajorRadius();
485 const int b = GetEllipseMinorRadius();
486 const VECTOR2I c = GetEllipseCenter();
487
488 ret.emplace_back( c + VECTOR2I( KiROUND( a * cosPhi ), KiROUND( a * sinPhi ) ) );
489 ret.emplace_back( c + VECTOR2I( KiROUND( -a * cosPhi ), KiROUND( -a * sinPhi ) ) );
490 ret.emplace_back( c + VECTOR2I( KiROUND( -b * sinPhi ), KiROUND( b * cosPhi ) ) );
491 ret.emplace_back( c + VECTOR2I( KiROUND( b * sinPhi ), KiROUND( -b * cosPhi ) ) );
492 break;
493 }
494
496 {
497 const double a = GetEllipseMajorRadius();
498 const double b = GetEllipseMinorRadius();
499 const double phi = GetEllipseRotation().AsRadians();
500 const double cosPhi = std::cos( phi );
501 const double sinPhi = std::sin( phi );
502 const VECTOR2I c = GetEllipseCenter();
503
504 auto eval = [&]( double theta ) -> VECTOR2I
505 {
506 const double lx = a * std::cos( theta );
507 const double ly = b * std::sin( theta );
508 return c + VECTOR2I( KiROUND( lx * cosPhi - ly * sinPhi ), KiROUND( lx * sinPhi + ly * cosPhi ) );
509 };
510
511 double thetaStart = GetEllipseStartAngle().AsRadians();
512 double thetaEnd = GetEllipseEndAngle().AsRadians();
513
514 if( thetaEnd < thetaStart )
515 thetaEnd += 2.0 * M_PI;
516
517 ret.emplace_back( eval( thetaStart ) );
518 ret.emplace_back( eval( thetaEnd ) );
519 ret.emplace_back( eval( 0.5 * ( thetaStart + thetaEnd ) ) );
520 break;
521 }
522
525 break;
526 }
527
528 return ret;
529}
530
531
533{
534 // Force update; we don't bother to propagate damage from all the things that might
535 // knock-out parts of our hatching.
536 m_hatchingDirty = true;
537
539}
540
541
543{
544 SHAPE_POLY_SET knockouts;
545 PCB_LAYER_ID layer = GetLayer();
546 BOX2I bbox = GetBoundingBox();
547 int maxError = ARC_LOW_DEF;
548
549 auto knockoutItem =
550 [&]( BOARD_ITEM* item )
551 {
552 int margin = GetHatchLineSpacing() / 2;
553
554 if( item->Type() == PCB_TEXTBOX_T )
555 margin = 0;
556
557 item->TransformShapeToPolygon( knockouts, layer, margin, maxError, ERROR_OUTSIDE );
558 };
559
560 for( BOARD_ITEM* item : GetBoard()->Drawings() )
561 {
562 if( item == this )
563 continue;
564
565 if( item->Type() == PCB_FIELD_T
566 || item->Type() == PCB_TEXT_T
567 || item->Type() == PCB_TEXTBOX_T
568 || item->Type() == PCB_SHAPE_T )
569 {
570 if( item->GetLayer() == layer && item->GetBoundingBox().Intersects( bbox ) )
571 knockoutItem( item );
572 }
573 }
574
575 for( FOOTPRINT* footprint : GetBoard()->Footprints() )
576 {
577 if( footprint == GetParentFootprint() )
578 continue;
579
580 // GetCourtyard() returns the front courtyard for any non-back layer, so only knock it
581 // out when the hatched shape actually lives on a courtyard layer.
582 if( layer == F_CrtYd || layer == B_CrtYd )
583 knockouts.Append( footprint->GetCourtyard( layer ) );
584
585 // Knockout footprint fields
586 footprint->RunOnChildren(
587 [&]( BOARD_ITEM* item )
588 {
589 if( ( item->Type() == PCB_FIELD_T || item->Type() == PCB_SHAPE_T )
590 && item->GetLayer() == layer
591 && !( item->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>(item)->IsVisible() )
592 && item->GetBoundingBox().Intersects( bbox ) )
593 {
594 knockoutItem( item );
595 }
596 },
598 }
599
600 return knockouts;
601}
602
603
604static double fpScaleLinear( const FOOTPRINT* aFp )
605{
606 if( !aFp )
607 return 1.0;
608
609 const TRANSFORM_TRS& xform = aFp->GetTransform();
610 return ( xform.GetScaleX() + xform.GetScaleY() ) * 0.5;
611}
612
613
615{
616 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
617 return nullptr;
618
619 return GetParentFootprint();
620}
621
622
624{
625 // Clamp negative widths to zero. They mean something in eeschema but break
626 // plotters and exporters here.
627 const int lib = std::max( EDA_SHAPE::GetWidth(), 0 );
628 const double s = fpScaleLinear( transformFp() );
629 return s == 1.0 ? lib : KiROUND( lib * s );
630}
631
632
633void PCB_SHAPE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
634{
635 m_stroke.SetWidth( settings.GetLineThickness( GetLayer() ) );
636}
637
638
640{
641 // For some shapes return the visual center, but for not filled polygonal shapes,
642 // the center is usually far from the shape: a point on the outline is better
643
644 switch( m_shape )
645 {
646 case SHAPE_T::CIRCLE:
647 if( !IsAnyFill() )
648 return VECTOR2I( GetCenter().x + GetRadius(), GetCenter().y );
649 else
650 return GetCenter();
651
653 if( !IsAnyFill() )
654 return GetStart();
655 else
656 return GetCenter();
657
658 case SHAPE_T::POLY:
659 if( !IsAnyFill() )
660 {
661 VECTOR2I pos = GetPolyShape().Outline(0).CPoint(0);
662 return VECTOR2I( pos.x, pos.y );
663 }
664 else
665 {
666 return GetCenter();
667 }
668
669 case SHAPE_T::ARC:
670 return GetArcMid();
671
672 case SHAPE_T::BEZIER:
673 return GetStart();
674
675 default:
676 return GetCenter();
677 }
678}
679
680
681std::vector<VECTOR2I> PCB_SHAPE::GetCorners() const
682{
683 std::vector<VECTOR2I> pts;
684
686 {
687 pts = GetRectCorners();
688 }
689 else if( GetShape() == SHAPE_T::POLY )
690 {
691 for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
692 {
693 for( const VECTOR2I& pt : GetPolyShape().Outline( ii ).CPoints() )
694 pts.emplace_back( pt );
695 }
696 }
697 else
698 {
700 }
701
702 while( pts.size() < 4 )
703 pts.emplace_back( pts.back() + VECTOR2I( 10, 10 ) );
704
705 return pts;
706}
707
708
709void PCB_SHAPE::Move( const VECTOR2I& aMoveVector )
710{
711 move( aMoveVector );
713}
714
715
716void PCB_SHAPE::Scale( double aScale )
717{
718 scale( aScale );
719}
720
721
723{
725 {
726 VECTOR2I start = GetStart();
727 VECTOR2I end = GetEnd();
728
729 BOX2I rect( start, end - start );
730 rect.Normalize();
731
732 SetStart( rect.GetPosition() );
733 SetEnd( rect.GetEnd() );
734 }
735 else if( m_shape == SHAPE_T::POLY )
736 {
737 auto horizontal =
738 []( const SEG& seg )
739 {
740 return seg.A.y == seg.B.y;
741 };
742
743 auto vertical =
744 []( const SEG& seg )
745 {
746 return seg.A.x == seg.B.x;
747 };
748
749 // Convert a poly back to a rectangle if appropriate
750 if( GetPolyShape().OutlineCount() == 1 && GetPolyShape().Outline( 0 ).SegmentCount() == 4 )
751 {
752 SHAPE_LINE_CHAIN& outline = GetPolyShape().Outline( 0 );
753
754 if( horizontal( outline.Segment( 0 ) )
755 && vertical( outline.Segment( 1 ) )
756 && horizontal( outline.Segment( 2 ) )
757 && vertical( outline.Segment( 3 ) ) )
758 {
760 SetStart( VECTOR2I( std::min( outline.Segment( 0 ).A.x, outline.Segment( 0 ).B.x ),
761 std::min( outline.Segment( 1 ).A.y, outline.Segment( 1 ).B.y ) ) );
762 SetEnd( VECTOR2I( std::max( outline.Segment( 0 ).A.x, outline.Segment( 0 ).B.x ),
763 std::max( outline.Segment( 1 ).A.y, outline.Segment( 1 ).B.y ) ) );
764 }
765 else if( vertical( outline.Segment( 0 ) )
766 && horizontal( outline.Segment( 1 ) )
767 && vertical( outline.Segment( 2 ) )
768 && horizontal( outline.Segment( 3 ) ) )
769 {
771 SetStart( VECTOR2I( std::min( outline.Segment( 1 ).A.x, outline.Segment( 1 ).B.x ),
772 std::min( outline.Segment( 0 ).A.y, outline.Segment( 0 ).B.y ) ) );
773 SetEnd( VECTOR2I( std::max( outline.Segment( 1 ).A.x, outline.Segment( 1 ).B.x ),
774 std::max( outline.Segment( 0 ).A.y, outline.Segment( 0 ).B.y ) ) );
775 }
776 }
777 }
778}
779
780
782{
784 {
785 VECTOR2I libStart = GetLibraryStart();
786 VECTOR2I libEnd = GetLibraryEnd();
787
788 if( ( libStart.x > libEnd.x ) || ( libStart.x == libEnd.x && libStart.y < libEnd.y ) )
789 {
790 VECTOR2I s = GetStart();
791 VECTOR2I e = GetEnd();
792 SetStart( e );
793 SetEnd( s );
794 }
795 }
796 else
797 Normalize();
798}
799
800
801void PCB_SHAPE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
802{
803 rotate( aRotCentre, aAngle );
805}
806
807
808void PCB_SHAPE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
809{
810 const FOOTPRINT* fp = transformFp();
811
812 TRANSFORM_TRS xform;
813 bool mirrorLib = false;
814
815 if( fp )
816 {
817 xform = fp->GetTransform();
818 mirrorLib = true;
819 }
820 else if( GetParent() && GetParent()->Type() == PCB_PAD_T && m_shape != m_libShape )
821 {
822 double sx = 1.0, sy = 1.0;
823 static_cast<const PAD*>( static_cast<const BOARD_ITEM*>( GetParent() ) )->GetPrimitiveLibScale( sx, sy );
824 xform.SetScale( sx, sy );
825 mirrorLib = true;
826 }
827
828 if( mirrorLib
831 {
832 const VECTOR2I libCenter = xform.InverseApply( aCentre );
833
834 auto mirrorPt =
835 [&]( VECTOR2I& p )
836 {
837 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
838 p.x = 2 * libCenter.x - p.x;
839 else
840 p.y = 2 * libCenter.y - p.y;
841 };
842
843 if( m_libShape == SHAPE_T::ARC )
844 {
845 mirrorPt( m_libStart );
846 mirrorPt( m_libEnd );
847 mirrorPt( m_libArcMid );
848 std::swap( m_libStart, m_libEnd );
849 }
850 else
851 {
852 mirrorPt( m_libStart );
853 mirrorPt( m_libEnd );
854 }
855
857 {
858 mirrorPt( m_libBezierC1 );
859 mirrorPt( m_libBezierC2 );
860 }
861
863 {
864 for( auto it = m_libPoly.IterateWithHoles(); it; it++ )
865 {
866 VECTOR2I p = *it;
867 mirrorPt( p );
868 m_libPoly.SetVertex( it.GetIndex(), p );
869 }
870 }
871
873 rebakeFromTransform( xform );
874 return;
875 }
876
877 if( mirrorLib && ( m_libShape == SHAPE_T::ELLIPSE || m_libShape == SHAPE_T::ELLIPSE_ARC ) )
878 {
879 const VECTOR2I libCenter = xform.InverseApply( aCentre );
880
881 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
882 m_libEllipseCenter.x = 2 * libCenter.x - m_libEllipseCenter.x;
883 else
884 m_libEllipseCenter.y = 2 * libCenter.y - m_libEllipseCenter.y;
885
887
888 const EDA_ANGLE oldStart = m_libEllipseStartAngle;
889 const EDA_ANGLE oldEnd = m_libEllipseEndAngle;
890
891 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
892 {
894 m_libEllipseEndAngle = ANGLE_180 - oldStart;
895 }
896 else
897 {
898 m_libEllipseStartAngle = -oldEnd;
899 m_libEllipseEndAngle = -oldStart;
900 }
901
903 rebakeFromTransform( xform );
904 return;
905 }
906
907 flip( aCentre, aFlipDirection );
908
911}
912
913
914void PCB_SHAPE::SetStart( const VECTOR2I& aStart )
915{
916 EDA_SHAPE::SetStart( aStart );
918}
919
920
921void PCB_SHAPE::SetEnd( const VECTOR2I& aEnd )
922{
923 EDA_SHAPE::SetEnd( aEnd );
925}
926
927
928void PCB_SHAPE::OnFootprintRescaled( double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I& aAnchor,
929 const EDA_ANGLE& aParentRotate )
930{
932}
933
934
935void PCB_SHAPE::SetWidth( int aWidth )
936{
937 const double s = fpScaleLinear( transformFp() );
938
939 if( s == 1.0 )
940 m_stroke.SetWidth( aWidth );
941 else
942 m_stroke.SetWidth( KiROUND( aWidth / s ) );
943
944 m_hatchingDirty = true;
945}
946
947
949{
950 m_stroke.SetWidth( aWidth );
951 m_hatchingDirty = true;
952}
953
954
956{
958 s.SetWidth( GetWidth() );
959 return s;
960}
961
962
964{
965 m_stroke = aStroke;
966 SetWidth( aStroke.GetWidth() );
967}
968
969
970void PCB_SHAPE::RebakeWithScale( double aScaleX, double aScaleY )
971{
972 TRANSFORM_TRS xform;
973 xform.SetScale( aScaleX, aScaleY );
974 rebakeFromTransform( xform );
975}
976
977
979{
980 const FOOTPRINT* fp = transformFp();
981
982 if( !fp )
983 return;
984
986}
987
988
990{
991 const bool nonUniform = xform.GetScaleX() != xform.GetScaleY();
992
994 {
995 VECTOR2I libCenter = m_libStart;
996 int libRadius = ( m_libEnd - m_libStart ).EuclideanNorm();
997 VECTOR2I newCenter = xform.Apply( libCenter );
998
999 if( nonUniform )
1000 {
1001 int majorRadius = std::abs( KiROUND( libRadius * xform.GetScaleX() ) );
1002 int minorRadius = std::abs( KiROUND( libRadius * xform.GetScaleY() ) );
1003
1004 EDA_ANGLE rotation = -xform.GetRotate();
1005
1006 if( minorRadius > majorRadius )
1007 {
1008 std::swap( majorRadius, minorRadius );
1009 rotation += EDA_ANGLE( 90.0, DEGREES_T );
1010 }
1011
1013 SetEllipseCenter( newCenter );
1014 SetEllipseMajorRadius( majorRadius );
1015 SetEllipseMinorRadius( minorRadius );
1016 SetEllipseRotation( rotation );
1017 }
1018 else
1019 {
1021 EDA_SHAPE::SetStart( newCenter );
1022 EDA_SHAPE::SetEnd( xform.Apply( m_libEnd ) );
1023 }
1024
1025 return;
1026 }
1027
1028 if( m_libShape == SHAPE_T::ARC )
1029 {
1031 int libRadius = ( m_libStart - libCenter ).EuclideanNorm();
1032 VECTOR2I newCenter = xform.Apply( libCenter );
1033
1034 if( nonUniform )
1035 {
1036 int majorRadius = std::abs( KiROUND( libRadius * xform.GetScaleX() ) );
1037 int minorRadius = std::abs( KiROUND( libRadius * xform.GetScaleY() ) );
1038
1039 EDA_ANGLE rotation = -xform.GetRotate();
1040 EDA_ANGLE startAngle( VECTOR2D( m_libStart - libCenter ) );
1041 EDA_ANGLE midAngle( VECTOR2D( m_libArcMid - libCenter ) );
1042 EDA_ANGLE endAngle( VECTOR2D( m_libEnd - libCenter ) );
1043
1044 auto wrap = []( EDA_ANGLE a, EDA_ANGLE base )
1045 {
1046 while( a < base )
1047 a += ANGLE_360;
1048 return a;
1049 };
1050
1051 if( wrap( midAngle, startAngle ) > wrap( endAngle, startAngle ) )
1052 std::swap( startAngle, endAngle );
1053
1054 while( endAngle < startAngle )
1055 endAngle += ANGLE_360;
1056
1057 if( minorRadius > majorRadius )
1058 {
1059 std::swap( majorRadius, minorRadius );
1060 rotation += EDA_ANGLE( 90.0, DEGREES_T );
1061 startAngle -= EDA_ANGLE( 90.0, DEGREES_T );
1062 endAngle -= EDA_ANGLE( 90.0, DEGREES_T );
1063 }
1064
1066 SetEllipseCenter( newCenter );
1067 SetEllipseMajorRadius( majorRadius );
1068 SetEllipseMinorRadius( minorRadius );
1069 SetEllipseRotation( rotation );
1070 SetEllipseStartAngle( startAngle );
1071 SetEllipseEndAngle( endAngle );
1072 }
1073 else
1074 {
1077 }
1078
1079 return;
1080 }
1081
1083 {
1084 // The linear transform preserves ellipse-ness only when scale is uniform
1085 // or the lib ellipse's axes are aligned with the scale axes (cardinal lib
1086 // rotation). Otherwise the result is a sheared shape that no standard
1087 // ellipse can represent; tessellate to POLY in that case.
1088 const bool keepNative = xform.IsUniformScale() || m_libEllipseRotation.IsCardinal();
1089
1090 if( keepNative )
1091 {
1094
1095 if( xform.IsUniformScale() )
1096 {
1097 double absScale = std::abs( xform.GetScaleX() );
1101
1103 {
1106 }
1107 }
1108 else
1109 {
1110 BOARD_ELLIPSE be = decomposeBoardEllipse( xform, m_libEllipseMajorRadius,
1113
1116 EDA_SHAPE::SetEllipseRotation( be.rotation );
1117
1119 {
1122 }
1123 }
1124 }
1125 else
1126 {
1127 const bool isArc = ( m_libShape == SHAPE_T::ELLIPSE_ARC );
1128
1129 std::unique_ptr<SHAPE_ELLIPSE> libEllipse;
1130
1131 if( isArc )
1132 {
1133 libEllipse = std::make_unique<SHAPE_ELLIPSE>(
1136 }
1137 else
1138 {
1139 libEllipse = std::make_unique<SHAPE_ELLIPSE>(
1142 }
1143
1144 SHAPE_LINE_CHAIN chain = libEllipse->ConvertToPolyline( getMaxError() );
1145
1147 SHAPE_POLY_SET& poly = GetPolyShape();
1148 poly.RemoveAllContours();
1149 poly.NewOutline();
1150
1151 for( int ii = 0; ii < chain.PointCount(); ++ii )
1152 poly.Append( xform.Apply( chain.CPoint( ii ) ) );
1153
1154 poly.Outline( 0 ).SetClosed( !isArc );
1155 }
1156
1157 return;
1158 }
1159
1161 {
1162 const VECTOR2I c1 = xform.Apply( m_libStart );
1163 const VECTOR2I c2 = xform.Apply( VECTOR2I( m_libEnd.x, m_libStart.y ) );
1164 const VECTOR2I c3 = xform.Apply( m_libEnd );
1165 const VECTOR2I c4 = xform.Apply( VECTOR2I( m_libStart.x, m_libEnd.y ) );
1166
1167 if( xform.GetRotate().IsCardinal() )
1168 {
1170 BOX2I bbox( c1, VECTOR2I( 0, 0 ) );
1171 bbox.Merge( c2 );
1172 bbox.Merge( c3 );
1173 bbox.Merge( c4 );
1175 EDA_SHAPE::SetEnd( bbox.GetEnd() );
1176 }
1177 else
1178 {
1180 SHAPE_POLY_SET& poly = GetPolyShape();
1181 poly.RemoveAllContours();
1182 poly.NewOutline();
1183 poly.Append( c1 );
1184 poly.Append( c2 );
1185 poly.Append( c3 );
1186 poly.Append( c4 );
1187
1188 EDA_SHAPE::SetStart( c1 );
1189 EDA_SHAPE::SetEnd( c3 );
1190 }
1191
1192 return;
1193 }
1194
1195 if( m_libShape == SHAPE_T::POLY )
1196 {
1197 SHAPE_POLY_SET& poly = GetPolyShape();
1198 poly = m_libPoly;
1199
1200 for( auto it = poly.IterateWithHoles(); it; it++ )
1201 poly.SetVertex( it.GetIndex(), xform.Apply( *it ) );
1202
1203 // m_libStart/m_libEnd are not seeded for POLY, skip the start/end fall-through below.
1204 return;
1205 }
1206
1208 EDA_SHAPE::SetEnd( xform.Apply( m_libEnd ) );
1209
1211 {
1215 }
1216}
1217
1218
1220{
1221 if( m_libShape == SHAPE_T::ARC )
1222 return m_libArcMid;
1223
1224 if( const FOOTPRINT* fp = transformFp() )
1225 return fp->GetTransform().InverseApply( GetArcMid() );
1226
1227 return GetArcMid();
1228}
1229
1230
1232{
1233 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1234 return m_libBezierC1;
1235
1236 if( const FOOTPRINT* fp = transformFp() )
1237 return fp->GetTransform().InverseApply( GetBezierC1() );
1238
1239 return GetBezierC1();
1240}
1241
1242
1244{
1245 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1246 return m_libBezierC2;
1247
1248 if( const FOOTPRINT* fp = transformFp() )
1249 return fp->GetTransform().InverseApply( GetBezierC2() );
1250
1251 return GetBezierC2();
1252}
1253
1254
1256{
1257 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1258 return m_libPoly;
1259
1261
1262 if( const FOOTPRINT* fp = transformFp() )
1263 {
1264 const TRANSFORM_TRS& xform = fp->GetTransform();
1265
1266 for( auto it = poly.IterateWithHoles(); it; it++ )
1267 poly.SetVertex( it.GetIndex(), xform.InverseApply( *it ) );
1268 }
1269
1270 return poly;
1271}
1272
1273
1274void PCB_SHAPE::SetArcGeometry( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
1275{
1276 EDA_SHAPE::SetArcGeometry( aStart, aMid, aEnd );
1277 syncLibCoords();
1278}
1279
1280
1282{
1284 syncLibCoords();
1285}
1286
1287
1289{
1291 syncLibCoords();
1292}
1293
1294
1296{
1297 EDA_SHAPE::SetPolyShape( aShape );
1298 syncLibCoords();
1299}
1300
1301
1303{
1305 syncLibCoords();
1306}
1307
1308
1314
1315
1321
1322
1328
1329
1335
1336
1342
1343
1345{
1346 TRANSFORM_TRS xform;
1347 bool hasXform = false;
1348
1349 if( GetParent() && GetParent()->Type() == PCB_PAD_T )
1350 {
1351 double sx = 1.0, sy = 1.0;
1352 static_cast<const PAD*>( static_cast<const BOARD_ITEM*>( GetParent() ) )->GetPrimitiveLibScale( sx, sy );
1353 xform.SetScale( sx, sy );
1354 hasXform = ( sx != 1.0 || sy != 1.0 );
1355 }
1356 else if( const FOOTPRINT* fp = transformFp() )
1357 {
1358 xform = fp->GetTransform();
1359 hasXform = true;
1360 }
1361
1363 {
1364 if( hasXform )
1365 {
1367
1368 if( xform.IsUniformScale() )
1369 {
1370 double invScale = 1.0 / std::abs( xform.GetScaleX() );
1376 }
1377 else
1378 {
1379 // Non-uniform scale shears the ellipse, so invert the whole board ellipse to lib.
1380 BOARD_ELLIPSE le = composeLibEllipse( xform, GetEllipseMajorRadius(), GetEllipseMinorRadius(),
1382 m_libEllipseMajorRadius = KiROUND( le.major );
1383 m_libEllipseMinorRadius = KiROUND( le.minor );
1384 m_libEllipseRotation = le.rotation;
1385 m_libEllipseStartAngle = GetEllipseStartAngle() + le.startShift;
1386 m_libEllipseEndAngle = GetEllipseEndAngle() + le.startShift;
1387 }
1388 }
1389 else
1390 {
1397 }
1398
1399 return;
1400 }
1401
1402 if( m_shape == SHAPE_T::POLY )
1403 {
1405
1406 if( hasXform )
1407 {
1408 for( auto it = m_libPoly.IterateWithHoles(); it; it++ )
1409 m_libPoly.SetVertex( it.GetIndex(), xform.InverseApply( *it ) );
1410 }
1411
1412 return;
1413 }
1414
1415 if( hasXform )
1416 {
1417 m_libStart = xform.InverseApply( GetStart() );
1418 m_libEnd = xform.InverseApply( GetEnd() );
1419
1420 if( m_shape == SHAPE_T::ARC )
1421 m_libArcMid = xform.InverseApply( GetArcMid() );
1422
1423 if( m_shape == SHAPE_T::BEZIER )
1424 {
1427 }
1428 }
1429 else
1430 {
1431 m_libStart = GetStart();
1432 m_libEnd = GetEnd();
1433
1434 if( m_shape == SHAPE_T::ARC )
1436
1437 if( m_shape == SHAPE_T::BEZIER )
1438 {
1441 }
1442 }
1443}
1444
1445
1446void PCB_SHAPE::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1447{
1448 flip( aCentre, aFlipDirection );
1449}
1450
1451
1452void PCB_SHAPE::SetIsProxyItem( bool aIsProxy )
1453{
1454 PAD* parentPad = nullptr;
1455
1456 if( GetBoard() && GetBoard()->IsFootprintHolder() )
1457 {
1458 for( FOOTPRINT* fp : GetBoard()->Footprints() )
1459 {
1460 for( PAD* pad : fp->Pads() )
1461 {
1462 if( pad->IsEntered() )
1463 {
1464 parentPad = pad;
1465 break;
1466 }
1467 }
1468 }
1469 }
1470
1471 if( aIsProxy && !m_proxyItem )
1472 {
1473 if( GetShape() == SHAPE_T::SEGMENT )
1474 {
1475 if( parentPad && parentPad->GetLocalThermalSpokeWidthOverride().has_value() )
1476 SetWidth( parentPad->GetLocalThermalSpokeWidthOverride().value() );
1477 else
1479 }
1480 else
1481 {
1482 SetWidth( 1 );
1483 }
1484 }
1485 else if( m_proxyItem && !aIsProxy )
1486 {
1488 }
1489
1490 m_proxyItem = aIsProxy;
1491}
1492
1493
1494double PCB_SHAPE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
1495{
1496 KIGFX::PCB_PAINTER& painter = static_cast<KIGFX::PCB_PAINTER&>( *aView->GetPainter() );
1497 KIGFX::PCB_RENDER_SETTINGS& renderSettings = *painter.GetSettings();
1498
1499 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
1500 {
1501 // Hide shadow if the main layer is not shown
1502 if( !aView->IsLayerVisibleCached( m_layer ) )
1503 return LOD_HIDE;
1504
1505 // Hide shadow on dimmed tracks
1506 if( renderSettings.GetHighContrast() )
1507 {
1508 if( m_layer != renderSettings.GetPrimaryHighContrastLayer() )
1509 return LOD_HIDE;
1510 }
1511 }
1512
1513 if( aLayer == LAYER_CONSTRAINT_SHADOW )
1514 {
1515 // Shadow always appended gate draw here on live constrained-item set not in
1516 // ViewGetLayers which caches
1517 if( !renderSettings.GetConstrainedItems().count( m_Uuid ) )
1518 return LOD_HIDE;
1519
1520 if( !aView->IsLayerVisibleCached( m_layer ) )
1521 return LOD_HIDE;
1522
1523 if( renderSettings.GetHighContrast() && m_layer != renderSettings.GetPrimaryHighContrastLayer() )
1524 return LOD_HIDE;
1525 }
1526
1527 if( FOOTPRINT* parent = GetParentFootprint() )
1528 {
1529 PCB_LAYER_ID checkLayer = m_layer;
1530
1531 if( !IsFrontLayer( checkLayer ) && !IsBackLayer( checkLayer ) )
1532 checkLayer = parent->GetLayer();
1533
1534 if( IsFrontLayer( checkLayer ) && !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_FR ) )
1535 return LOD_HIDE;
1536
1537 if( IsBackLayer( checkLayer ) && !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_BK ) )
1538 return LOD_HIDE;
1539 }
1540
1541 return LOD_SHOW;
1542}
1543
1544
1545std::vector<int> PCB_SHAPE::ViewGetLayers() const
1546{
1547 std::vector<int> layers;
1548 layers.reserve( 5 );
1549
1550 layers.push_back( GetLayer() );
1551
1552 if( IsOnCopperLayer() )
1553 {
1554 layers.push_back( GetNetnameLayer( GetLayer() ) );
1555
1556 if( m_hasSolderMask )
1557 {
1558 if( m_layer == F_Cu )
1559 layers.push_back( F_Mask );
1560 else if( m_layer == B_Cu )
1561 layers.push_back( B_Mask );
1562 }
1563 }
1564
1566 layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
1567
1568 // Always advertise constraint-shadow layer ViewGetLOD gates draw by constrained state
1569 layers.push_back( LAYER_CONSTRAINT_SHADOW );
1570
1571 return layers;
1572}
1573
1574
1575void PCB_SHAPE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1576{
1577 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1578 {
1579 if( FOOTPRINT* parent = GetParentFootprint() )
1580 aList.emplace_back( _( "Footprint" ), parent->GetReference() );
1581 }
1582
1583 aList.emplace_back( _( "Type" ), _( "Drawing" ) );
1584
1585 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
1586 aList.emplace_back( _( "Status" ), _( "Locked" ) );
1587
1588 ShapeGetMsgPanelInfo( aFrame, aList );
1589
1590 aList.emplace_back( _( "Layer" ), GetLayerName() );
1591
1592 if( IsOnCopperLayer() )
1593 {
1594 if( GetNetCode() > 0 ) // Only graphics connected to a net have a netcode > 0
1595 aList.emplace_back( _( "Net" ), GetNetname() );
1596 }
1597}
1598
1599
1600wxString PCB_SHAPE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1601{
1602 FOOTPRINT* parentFP = GetParentFootprint();
1603
1604 // Don't report parent footprint info from footprint editor, viewer, etc.
1605 if( GetBoard() && GetBoard()->GetBoardUse() == BOARD_USE::FPHOLDER )
1606 parentFP = nullptr;
1607
1608 if( IsOnCopperLayer() )
1609 {
1610 if( parentFP )
1611 {
1612 return wxString::Format( _( "%s %s of %s on %s" ),
1614 GetNetnameMsg(),
1615 parentFP->GetReference(),
1616 GetLayerName() );
1617 }
1618 else
1619 {
1620 return wxString::Format( _( "%s %s on %s" ),
1622 GetNetnameMsg(),
1623 GetLayerName() );
1624 }
1625 }
1626 else
1627 {
1628 if( parentFP )
1629 {
1630 return wxString::Format( _( "%s of %s on %s" ),
1632 parentFP->GetReference(),
1633 GetLayerName() );
1634 }
1635 else
1636 {
1637 return wxString::Format( _( "%s on %s" ),
1639 GetLayerName() );
1640 }
1641 }
1642}
1643
1644
1646{
1647 if( GetParentFootprint() )
1649 else
1651}
1652
1653
1655{
1656 return new PCB_SHAPE( *this );
1657}
1658
1659
1661{
1662 BOX2I return_box = EDA_ITEM::ViewBBox();
1663
1664 // Inflate the bounding box by just a bit more for safety.
1665 return_box.Inflate( GetWidth() );
1666
1667 return return_box;
1668}
1669
1670
1672{
1673 BOX2I bbox = getBoundingBox();
1674 BOX2I endingsBBox;
1675
1676 if( GetLineEndingsBoundingBox( endingsBBox, GetEffectiveWidth() ) )
1677 bbox.Merge( endingsBBox );
1678
1679 bbox.Normalize();
1680
1681 return bbox;
1682}
1683
1684
1686{
1687 return std::make_shared<SHAPE_COMPOUND>( MakeEffectiveShapesWithLineEndings( GetEffectiveWidth() ) );
1688}
1689
1690
1692{
1693 return GetMaxError();
1694}
1695
1696
1698{
1699 PCB_SHAPE* image = dynamic_cast<PCB_SHAPE*>( aImage );
1700 wxCHECK( image, /* void */ );
1701
1702 SwapShape( image );
1703
1704 // Swap params not handled by SwapShape( image )
1705 std::swap( m_layer, image->m_layer );
1706 std::swap( m_isKnockout, image->m_isKnockout );
1707 std::swap( m_isLocked, image->m_isLocked );
1708 std::swap( m_flags, image->m_flags );
1709 std::swap( m_parent, image->m_parent );
1710 std::swap( m_forceVisible, image->m_forceVisible );
1711 std::swap( m_netinfo, image->m_netinfo );
1712 std::swap( m_hasSolderMask, image->m_hasSolderMask );
1713 std::swap( m_solderMaskMargin, image->m_solderMaskMargin );
1714 std::swap( m_customProperties, image->m_customProperties );
1715}
1716
1717
1719 const BOARD_ITEM* aSecond ) const
1720{
1721 if( aFirst->Type() != aSecond->Type() )
1722 return aFirst->Type() < aSecond->Type();
1723
1724 if( aFirst->GetLayer() != aSecond->GetLayer() )
1725 return aFirst->GetLayer() < aSecond->GetLayer();
1726
1727 if( aFirst->Type() == PCB_SHAPE_T )
1728 {
1729 const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( aFirst );
1730 const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( aSecond );
1731
1732 if( dwgA->GetShape() != dwgB->GetShape() )
1733 return dwgA->GetShape() < dwgB->GetShape();
1734 }
1735
1736 return aFirst->m_Uuid < aSecond->m_Uuid;
1737}
1738
1739
1741 int aClearance, int aError, ERROR_LOC aErrorLoc,
1742 bool ignoreLineWidth ) const
1743{
1744 EDA_SHAPE::TransformShapeToPolygon( aBuffer, aClearance, aError, aErrorLoc, ignoreLineWidth,
1745 false );
1746}
1747
1748
1750 int aClearance, int aError, ERROR_LOC aErrorLoc,
1751 KIGFX::RENDER_SETTINGS* aRenderSettings ) const
1752{
1753 EDA_SHAPE::TransformShapeToPolygon( aBuffer, aClearance, aError, aErrorLoc, false, true );
1754}
1755
1756
1757bool PCB_SHAPE::operator==( const BOARD_ITEM& aOther ) const
1758{
1759 if( aOther.Type() != Type() )
1760 return false;
1761
1762 const PCB_SHAPE& other = static_cast<const PCB_SHAPE&>( aOther );
1763
1764 return *this == other;
1765}
1766
1767
1768bool PCB_SHAPE::operator==( const PCB_SHAPE& aOther ) const
1769{
1770 if( aOther.Type() != Type() )
1771 return false;
1772
1773 const PCB_SHAPE& other = static_cast<const PCB_SHAPE&>( aOther );
1774
1775 if( m_layer != other.m_layer )
1776 return false;
1777
1778 if( m_isKnockout != other.m_isKnockout )
1779 return false;
1780
1781 if( m_isLocked != other.m_isLocked )
1782 return false;
1783
1784 if( m_flags != other.m_flags )
1785 return false;
1786
1787 if( m_forceVisible != other.m_forceVisible )
1788 return false;
1789
1790 if( m_netinfo->GetNetCode() != other.m_netinfo->GetNetCode() )
1791 return false;
1792
1793 if( m_hasSolderMask != other.m_hasSolderMask )
1794 return false;
1795
1797 return false;
1798
1799 return EDA_SHAPE::operator==( other );
1800}
1801
1802
1803double PCB_SHAPE::Similarity( const BOARD_ITEM& aOther ) const
1804{
1805 if( aOther.Type() != Type() )
1806 return 0.0;
1807
1808 const PCB_SHAPE& other = static_cast<const PCB_SHAPE&>( aOther );
1809
1810 double similarity = 1.0;
1811
1812 if( GetLayer() != other.GetLayer() )
1813 similarity *= 0.9;
1814
1815 if( m_isKnockout != other.m_isKnockout )
1816 similarity *= 0.9;
1817
1818 if( m_isLocked != other.m_isLocked )
1819 similarity *= 0.9;
1820
1821 if( m_flags != other.m_flags )
1822 similarity *= 0.9;
1823
1824 if( m_forceVisible != other.m_forceVisible )
1825 similarity *= 0.9;
1826
1827 if( m_netinfo->GetNetCode() != other.m_netinfo->GetNetCode() )
1828 similarity *= 0.9;
1829
1830 if( m_hasSolderMask != other.m_hasSolderMask )
1831 similarity *= 0.9;
1832
1834 similarity *= 0.9;
1835
1836 similarity *= EDA_SHAPE::Similarity( other );
1837
1838 return similarity;
1839}
1840
1841
1842static struct PCB_SHAPE_DESC
1843{
1845 {
1852
1853 // Need to initialise enum_map before we can use a Property enum for it
1855
1856 if( layerEnum.Choices().GetCount() == 0 )
1857 {
1858 layerEnum.Undefined( UNDEFINED_LAYER );
1859
1860 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
1861 layerEnum.Map( layer, LSET::Name( layer ) );
1862 }
1863
1864 void ( PCB_SHAPE::*shapeLayerSetter )( PCB_LAYER_ID ) = &PCB_SHAPE::SetLayer;
1865 PCB_LAYER_ID ( PCB_SHAPE::*shapeLayerGetter )() const = &PCB_SHAPE::GetLayer;
1866
1867 propMgr.ReplaceProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ),
1869 shapeLayerSetter, shapeLayerGetter ) ).SetIsCopyable();
1870
1871 auto isPolygonOrEllipse =
1872 []( INSPECTABLE* aItem ) -> bool
1873 {
1874 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1875 {
1876 const SHAPE_T t = shape->GetShape();
1877 return t == SHAPE_T::POLY || t == SHAPE_T::ELLIPSE || t == SHAPE_T::ELLIPSE_ARC;
1878 }
1879
1880 return false;
1881 };
1882
1883 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
1884 isPolygonOrEllipse );
1885 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
1886 isPolygonOrEllipse );
1887
1888 propMgr.Mask( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Color" ) );
1889 propMgr.Mask( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Fill Color" ) );
1890
1891 auto isNotBezierOrEllipseArc =
1892 []( INSPECTABLE* aItem ) -> bool
1893 {
1894 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1895 {
1896 const SHAPE_T t = shape->GetShape();
1897 return t != SHAPE_T::BEZIER && t != SHAPE_T::ELLIPSE_ARC;
1898 }
1899
1900 return true;
1901 };
1902
1904 isNotBezierOrEllipseArc );
1905
1906 auto isCircle =
1907 []( INSPECTABLE* aItem ) -> bool
1908 {
1909 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1910 return shape->GetShape() == SHAPE_T::CIRCLE;
1911
1912 return false;
1913 };
1914
1915 auto isNotCircleOrEllipse =
1916 []( INSPECTABLE* aItem ) -> bool
1917 {
1918 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1919 {
1920 const SHAPE_T t = shape->GetShape();
1921 return t != SHAPE_T::CIRCLE && t != SHAPE_T::ELLIPSE && t != SHAPE_T::ELLIPSE_ARC;
1922 }
1923
1924 return true;
1925 };
1926
1927 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start X" ),
1928 isNotCircleOrEllipse );
1929 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start Y" ),
1930 isNotCircleOrEllipse );
1931 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "End X" ),
1932 isNotCircleOrEllipse );
1933 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "End Y" ),
1934 isNotCircleOrEllipse );
1935 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Center X" ),
1936 isCircle );
1937 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Center Y" ),
1938 isCircle );
1939 propMgr.OverrideAvailability( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ), _HKI( "Radius" ),
1940 isCircle );
1941
1942 auto isCopper =
1943 []( INSPECTABLE* aItem ) -> bool
1944 {
1945 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1946 return shape->IsOnCopperLayer();
1947
1948 return false;
1949 };
1950
1952 isCopper );
1953
1954 auto isPadEditMode =
1955 []( BOARD* aBoard ) -> bool
1956 {
1957 if( aBoard && aBoard->IsFootprintHolder() )
1958 {
1959 for( FOOTPRINT* fp : aBoard->Footprints() )
1960 {
1961 for( PAD* pad : fp->Pads() )
1962 {
1963 if( pad->IsEntered() )
1964 return true;
1965 }
1966 }
1967 }
1968
1969 return false;
1970 };
1971
1972 auto showNumberBoxProperty =
1973 [&]( INSPECTABLE* aItem ) -> bool
1974 {
1975 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1976 {
1977 if( shape->GetShape() == SHAPE_T::RECTANGLE )
1978 return isPadEditMode( shape->GetBoard() );
1979 }
1980
1981 return false;
1982 };
1983
1984 auto showSpokeTemplateProperty =
1985 [&]( INSPECTABLE* aItem ) -> bool
1986 {
1987 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
1988 {
1989 if( shape->GetShape() == SHAPE_T::SEGMENT )
1990 return isPadEditMode( shape->GetBoard() );
1991 }
1992
1993 return false;
1994 };
1995
1996 const wxString groupPadPrimitives = _HKI( "Pad Primitives" );
1997
1998 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, bool>( _HKI( "Number Box" ),
2000 groupPadPrimitives )
2001 .SetAvailableFunc( showNumberBoxProperty )
2003
2004 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, bool>( _HKI( "Thermal Spoke Template" ),
2006 groupPadPrimitives )
2007 .SetAvailableFunc( showSpokeTemplateProperty )
2009
2010 const wxString groupTechLayers = _HKI( "Technical Layers" );
2011
2012 auto isExternalCuLayer =
2013 []( INSPECTABLE* aItem )
2014 {
2015 if( auto shape = dynamic_cast<PCB_SHAPE*>( aItem ) )
2016 return IsExternalCopperLayer( shape->GetLayer() );
2017
2018 return false;
2019 };
2020
2021 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, bool>( _HKI( "Soldermask" ),
2023 groupTechLayers )
2024 .SetAvailableFunc( isExternalCuLayer ).SetIsCopyable();
2025
2026 propMgr.AddProperty( new PROPERTY<PCB_SHAPE, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
2029 groupTechLayers )
2030 .SetAvailableFunc( isExternalCuLayer ).SetIsCopyable();
2031 }
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
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:401
#define DEFAULT_LINE_WIDTH
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
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:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
friend class BOARD
Definition board_item.h:578
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:417
bool m_isKnockout
Definition board_item.h:572
PCB_LAYER_ID m_layer
Definition board_item.h:571
bool m_isLocked
Definition board_item.h:573
bool IsLocked() const override
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:374
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:266
virtual bool IsOnCopperLayer() const
Definition board_item.h:189
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:409
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
constexpr const Vec & GetPosition() const
Definition box2.h:208
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
Represent basic circle geometry with utility geometry functions.
Definition circle.h:33
MINOPTMAX< int > m_Value
Definition drc_rule.h:244
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:270
const KIID m_Uuid
Definition eda_item.h:597
bool m_forceVisible
Definition eda_item.h:612
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:606
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:214
std::map< wxString, wxString > m_customProperties
Definition eda_item.h:615
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition eda_item.cpp:509
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:607
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
virtual int GetHatchLineSpacing() const
Definition eda_shape.h:166
SHAPE_T m_shape
Definition eda_shape.h:733
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:329
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:395
bool m_proxyItem
Definition eda_shape.h:761
bool m_hatchingDirty
Definition eda_shape.h:741
bool m_endsSwapped
Definition eda_shape.h:732
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:368
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:377
bool GetLineEndingsBoundingBox(BOX2I &aBBox, int aLineWidth) const
int m_editState
Definition eda_shape.h:760
void rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle)
std::vector< SHAPE * > MakeEffectiveShapesWithLineEndings(int aLineWidth) const
Make effective geometry for the shape body shortened for line endings plus the line-ending geometry i...
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:423
int GetEllipseMajorRadius() const
Definition eda_shape.h:386
virtual int GetEffectiveWidth() const
Definition eda_shape.h:164
SHAPE_POLY_SET & GetPolyShape()
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:404
void ShapeGetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList)
virtual void SetEllipseEndAngle(const EDA_ANGLE &aA)
Definition eda_shape.h:416
bool operator==(const EDA_SHAPE &aOther) const
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:175
virtual void SetBezierC2(const VECTOR2I &aPt)
Definition eda_shape.h:367
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
VECTOR2I m_arcCenter
Definition eda_shape.h:750
virtual void SetBezierC1(const VECTOR2I &aPt)
Definition eda_shape.h:364
virtual void SetEllipseRotation(const EDA_ANGLE &aA)
Definition eda_shape.h:397
ARC_MID m_arcMidData
Definition eda_shape.h:751
bool IsSolidFill() const
Definition eda_shape.h:123
void flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
EDA_SHAPE(SHAPE_T aType, int aLineWidth, FILL_T aFill)
Definition eda_shape.cpp:56
VECTOR2I m_start
Definition eda_shape.h:747
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
virtual void SetEllipseCenter(const VECTOR2I &aPt)
Definition eda_shape.h:370
virtual void SetEllipseMinorRadius(int aR)
Definition eda_shape.h:388
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
virtual void SetEllipseMajorRadius(int aR)
Definition eda_shape.h:379
void SwapShape(EDA_SHAPE *aImage)
std::vector< VECTOR2I > GetRectCorners() const
bool IsAnyFill() const
Definition eda_shape.h:118
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:414
virtual void UpdateHatching() const
virtual void SetEllipseStartAngle(const EDA_ANGLE &aA)
Definition eda_shape.h:407
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:365
VECTOR2I m_end
Definition eda_shape.h:748
const BOX2I getBoundingBox() const
virtual int GetWidth() const
Definition eda_shape.h:163
STROKE_PARAMS m_stroke
Definition eda_shape.h:734
void RebuildBezierToSegmentsPointsList()
Definition eda_shape.h:539
VECTOR2I m_bezierC1
Definition eda_shape.h:753
virtual void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition eda_shape.h:514
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:279
VECTOR2I m_bezierC2
Definition eda_shape.h:754
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:226
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:776
static ENUM_MAP< T > & Instance()
Definition property.h:770
ENUM_MAP & Undefined(T aValue)
Definition property.h:783
wxPGChoices & Choices()
Definition property.h:821
const TRANSFORM_TRS & GetTransform() const
Definition footprint.h:451
const wxString & GetReference() const
Definition footprint.h:901
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
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:84
const std::unordered_set< KIID > & GetConstrainedItems() const
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:439
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
Definition kiid.h:46
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:36
int GetNetCode() const
Definition netinfo.h:104
Definition pad.h:61
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:736
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
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:384
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:388
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:375
VECTOR2I m_libBezierC1
Definition pcb_shape.h:379
virtual void syncLibCoords()
SHAPE_POLY_SET getHatchingKnockouts() const override
void SetBezierC1(const VECTOR2I &aPt) override
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_shape.h:339
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:389
void SetLibStrokeWidth(int aWidth)
SHAPE_T m_libShape
Definition pcb_shape.h:391
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:336
void SetEllipseStartAngle(const EDA_ANGLE &aA) override
void SetHasSolderMask(bool aVal)
Definition pcb_shape.h:335
std::optional< int > m_solderMaskMargin
Definition pcb_shape.h:372
int GetSolderMaskExpansion() const
void NormalizeForCompare() override
Normalize coordinates to compare 2 similar PCB_SHAPES similat to Normalize(), but also normalize SEGM...
void SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:207
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:377
void SetEllipseEndAngle(const EDA_ANGLE &aA) override
int m_libEllipseMinorRadius
Definition pcb_shape.h:386
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:228
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:153
void SetEllipseRotation(const EDA_ANGLE &aA) override
bool m_hasSolderMask
Definition pcb_shape.h:371
const FOOTPRINT * transformFp() const
VECTOR2I GetLibraryStart() const
Definition pcb_shape.h:227
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
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Make a set of SHAPE objects representing the PCB_SHAPE.
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:382
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_shape.h:338
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:380
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:374
EDA_ANGLE m_libEllipseRotation
Definition pcb_shape.h:387
int m_libEllipseMajorRadius
Definition pcb_shape.h:385
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:263
PROPERTY_BASE & SetIsCopyable(bool aIsCopyable=true)
Definition property.h:359
PROPERTY_BASE & SetIsHiddenFromRulesEditor(bool aHide=true)
Definition property.h:332
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)
DRC_CONSTRAINT_T
Definition drc_rule.h:49
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:68
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:422
@ RADIANS_T
Definition eda_angle.h:32
@ DEGREES_T
Definition eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:428
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:426
#define PCB_EDIT_FRAME_NAME
FILL_T
Definition eda_fill.h:29
@ NO_FILL
Definition eda_fill.h:30
@ RECURSE
Definition eda_item.h:51
SHAPE_T
Definition eda_shape.h:54
@ UNDEFINED
Definition eda_shape.h:55
@ ELLIPSE
Definition eda_shape.h:62
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
@ ELLIPSE_ARC
Definition eda_shape.h:63
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:179
bool IsSolderMaskLayer(int aLayer)
Definition layer_ids.h:774
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:806
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:829
int GetNetnameLayer(int aLayer)
Return a netname layer corresponding to the given layer.
Definition layer_ids.h:880
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
@ 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_CONSTRAINT_SHADOW
Shadow layer for items bound to a constraint.
Definition layer_ids.h:320
@ 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:714
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.
KICOMMON_API void PackCustomProperties(google::protobuf::RepeatedPtrField< types::CustomProperty > *aOutput, const EDA_ITEM &aItem)
KICOMMON_API void UnpackCustomProperties(const google::protobuf::RepeatedPtrField< types::CustomProperty > &aInput, EDA_ITEM &aItem)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
#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:562
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_SHAPE_LOCATE_ELLIPSE_ARC_T
Definition typeinfo.h:236
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_LOCATE_BOARD_EDGE_T
Definition typeinfo.h:126
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_SHAPE_LOCATE_CIRCLE_T
Definition typeinfo.h:131
@ PCB_SHAPE_LOCATE_SEGMENT_T
Definition typeinfo.h:129
@ PCB_SHAPE_LOCATE_RECT_T
Definition typeinfo.h:130
@ PCB_SHAPE_LOCATE_ELLIPSE_T
Definition typeinfo.h:235
@ PCB_SHAPE_LOCATE_BEZIER_T
Definition typeinfo.h:134
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_SHAPE_LOCATE_POLY_T
Definition typeinfo.h:133
@ PCB_SHAPE_LOCATE_ARC_T
Definition typeinfo.h:132
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