1 /* 2 * This program source code file is part of KiCad, a free EDA CAD application. 3 * 4 * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr 5 * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, you may find one here: 19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 20 * or you may search the http://www.gnu.org website for the version 2 license, 21 * or you may write to the Free Software Foundation, Inc., 22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24 25 #ifndef ZONE_H 26 #define ZONE_H 27 28 29 #include <mutex> 30 #include <vector> 31 #include <gr_basic.h> 32 #include <board_item.h> 33 #include <board_connected_item.h> 34 #include <layer_ids.h> 35 #include <geometry/shape_poly_set.h> 36 #include <zone_settings.h> 37 38 39 class EDA_RECT; 40 class LINE_READER; 41 class PCB_EDIT_FRAME; 42 class BOARD; 43 class ZONE; 44 class MSG_PANEL_ITEM; 45 46 47 /** 48 * Handle a list of polygons defining a copper zone. 49 * 50 * A zone is described by a main polygon, a time stamp, a layer or a layer set, and a net name. 51 * Other polygons inside the main polygon are holes in the zone. 52 * 53 * a item ZONE is living in a board 54 * a variant FP_ZONE is living in a footprint 55 */ 56 class ZONE : public BOARD_CONNECTED_ITEM 57 { 58 public: 59 60 /** 61 * The ctor to build ZONE, but compatible with FP_ZONE requirement. 62 * if aInFP is true, a FP_ZONE is actually built 63 * (same item, but with a specific type id: 64 * The type is PCB_ZONE_T for a ZONE 65 * The type is PCB_FP_ZONE_T for a FP_ZONE 66 */ 67 ZONE( BOARD_ITEM_CONTAINER* parent, bool aInFP = false ); 68 69 ZONE( const ZONE& aZone ); 70 ZONE& operator=( const ZONE &aOther ); 71 72 ~ZONE(); 73 ClassOf(const EDA_ITEM * aItem)74 static inline bool ClassOf( const EDA_ITEM* aItem ) 75 { 76 return aItem && aItem->Type() == PCB_ZONE_T; 77 } 78 79 /** 80 * Not all ZONEs are *really* BOARD_CONNECTED_ITEMs.... 81 */ IsConnected()82 bool IsConnected() const override 83 { 84 return !GetIsRuleArea(); 85 } 86 GetNetClass()87 NETCLASS* GetNetClass() const override 88 { 89 if( GetIsRuleArea() ) 90 return nullptr; 91 92 return BOARD_CONNECTED_ITEM::GetNetClass(); 93 } 94 GetNetClassName()95 wxString GetNetClassName() const override 96 { 97 if( GetIsRuleArea() ) 98 return "UNDEFINED"; 99 100 return BOARD_CONNECTED_ITEM::GetNetClassName(); 101 } 102 103 /** 104 * Copy aZone data to me 105 */ 106 void InitDataFromSrcInCopyCtor( const ZONE& aZone ); 107 108 /** 109 * @return a wxPoint, position of the first point of the outline 110 */ 111 wxPoint GetPosition() const override; SetPosition(const wxPoint & aPos)112 void SetPosition( const wxPoint& aPos ) override {} 113 114 /** 115 * @param aPriority is the priority level. 116 */ SetPriority(unsigned aPriority)117 void SetPriority( unsigned aPriority ) { m_priority = aPriority; } 118 119 /** 120 * @return the priority level of this zone. 121 */ GetPriority()122 unsigned GetPriority() const { return m_priority; } 123 124 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override; 125 126 void SetLayerSet( LSET aLayerSet ) override; 127 virtual LSET GetLayerSet() const override; 128 GetZoneName()129 wxString GetZoneName() const { return m_zoneName; } SetZoneName(const wxString & aName)130 void SetZoneName( const wxString& aName ) { m_zoneName = aName; } 131 Matches(const wxFindReplaceData & aSearchData,void * aAuxData)132 bool Matches( const wxFindReplaceData& aSearchData, void* aAuxData ) const override 133 { 134 return BOARD_ITEM::Matches( GetZoneName(), aSearchData ); 135 } 136 137 /** 138 * @return an EDA_RECT that is the bounding box of the zone outline. 139 */ 140 const EDA_RECT GetBoundingBox() const override; 141 142 /** 143 * ONLY TO BE USED BY CLIENTS WHICH SET UP THE CACHE! 144 */ GetCachedBoundingBox()145 const EDA_RECT GetCachedBoundingBox() const { return m_bboxCache; } CacheBoundingBox()146 void CacheBoundingBox() { m_bboxCache = GetBoundingBox(); } 147 148 /** 149 * Return any local clearances set in the "classic" (ie: pre-rule) system. These are 150 * things like zone clearance which are NOT an override. 151 * 152 * @param aSource [out] optionally reports the source as a user-readable string 153 * @return the clearance in internal units. 154 */ 155 int GetLocalClearance( wxString* aSource ) const override; 156 GetLocalClearance()157 int GetLocalClearance() const { return GetLocalClearance( nullptr ); } SetLocalClearance(int aClearance)158 void SetLocalClearance( int aClearance ) { m_ZoneClearance = aClearance; } 159 160 /** 161 * @return true if this zone is on a copper layer, false if on a technical layer. 162 */ 163 bool IsOnCopperLayer() const override; 164 165 /** 166 * Test if this zone shares a common layer with the given layer set. 167 */ 168 bool CommonLayerExists( const LSET aLayerSet ) const; 169 170 virtual void SetLayer( PCB_LAYER_ID aLayer ) override; 171 172 virtual PCB_LAYER_ID GetLayer() const override; 173 174 virtual bool IsOnLayer( PCB_LAYER_ID ) const override; 175 176 virtual void ViewGetLayers( int aLayers[], int& aCount ) const override; 177 178 double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override; 179 SetFillMode(ZONE_FILL_MODE aFillMode)180 void SetFillMode( ZONE_FILL_MODE aFillMode ) { m_fillMode = aFillMode; } GetFillMode()181 ZONE_FILL_MODE GetFillMode() const { return m_fillMode; } 182 SetThermalReliefGap(int aThermalReliefGap)183 void SetThermalReliefGap( int aThermalReliefGap ) 184 { 185 if( m_thermalReliefGap != aThermalReliefGap ) 186 SetNeedRefill( true ); 187 188 m_thermalReliefGap = aThermalReliefGap; 189 } 190 GetThermalReliefGap()191 int GetThermalReliefGap() const { return m_thermalReliefGap; } 192 int GetThermalReliefGap( PAD* aPad, wxString* aSource = nullptr ) const; 193 SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)194 void SetThermalReliefSpokeWidth( int aThermalReliefSpokeWidth ) 195 { 196 if( m_thermalReliefSpokeWidth != aThermalReliefSpokeWidth ) 197 SetNeedRefill( true ); 198 199 m_thermalReliefSpokeWidth = aThermalReliefSpokeWidth; 200 } 201 GetThermalReliefSpokeWidth()202 int GetThermalReliefSpokeWidth() const { return m_thermalReliefSpokeWidth; } 203 int GetThermalReliefSpokeWidth( PAD* aPad, wxString* aSource = nullptr ) const; 204 205 /** 206 * Compute the area currently occupied by the zone fill. 207 * 208 * @return the currently filled area 209 */ 210 double CalculateFilledArea(); 211 212 /** 213 * This area is cached from the most recent call to CalculateFilledArea(). 214 * 215 * @return the filled area 216 */ GetFilledArea()217 double GetFilledArea() 218 { 219 return m_area; 220 } 221 GetLock()222 std::mutex& GetLock() 223 { 224 return m_lock; 225 } 226 GetFillFlag(PCB_LAYER_ID aLayer)227 int GetFillFlag( PCB_LAYER_ID aLayer ) 228 { 229 return m_fillFlags.count( aLayer ) ? m_fillFlags[ aLayer ] : false; 230 } 231 SetFillFlag(PCB_LAYER_ID aLayer,bool aFlag)232 void SetFillFlag( PCB_LAYER_ID aLayer, bool aFlag ) { m_fillFlags[ aLayer ] = aFlag; } 233 IsFilled()234 bool IsFilled() const { return m_isFilled; } SetIsFilled(bool isFilled)235 void SetIsFilled( bool isFilled ) { m_isFilled = isFilled; } 236 NeedRefill()237 bool NeedRefill() const { return m_needRefill; } SetNeedRefill(bool aNeedRefill)238 void SetNeedRefill( bool aNeedRefill ) { m_needRefill = aNeedRefill; } 239 240 ZONE_CONNECTION GetPadConnection( PAD* aPad, wxString* aSource = nullptr ) const; GetPadConnection()241 ZONE_CONNECTION GetPadConnection() const { return m_PadConnection; } SetPadConnection(ZONE_CONNECTION aPadConnection)242 void SetPadConnection( ZONE_CONNECTION aPadConnection ) { m_PadConnection = aPadConnection; } 243 GetMinThickness()244 int GetMinThickness() const { return m_ZoneMinThickness; } SetMinThickness(int aMinThickness)245 void SetMinThickness( int aMinThickness ) 246 { 247 if( m_ZoneMinThickness != aMinThickness ) 248 SetNeedRefill( true ); 249 250 m_ZoneMinThickness = aMinThickness; 251 } 252 GetHatchThickness()253 int GetHatchThickness() const { return m_hatchThickness; } SetHatchThickness(int aThickness)254 void SetHatchThickness( int aThickness ) { m_hatchThickness = aThickness; } 255 GetHatchGap()256 int GetHatchGap() const { return m_hatchGap; } SetHatchGap(int aStep)257 void SetHatchGap( int aStep ) { m_hatchGap = aStep; } 258 GetHatchOrientation()259 double GetHatchOrientation() const { return m_hatchOrientation; } SetHatchOrientation(double aStep)260 void SetHatchOrientation( double aStep ) { m_hatchOrientation = aStep; } 261 GetHatchSmoothingLevel()262 int GetHatchSmoothingLevel() const { return m_hatchSmoothingLevel; } SetHatchSmoothingLevel(int aLevel)263 void SetHatchSmoothingLevel( int aLevel ) { m_hatchSmoothingLevel = aLevel; } 264 GetHatchSmoothingValue()265 double GetHatchSmoothingValue() const { return m_hatchSmoothingValue; } SetHatchSmoothingValue(double aValue)266 void SetHatchSmoothingValue( double aValue ) { m_hatchSmoothingValue = aValue; } 267 GetHatchHoleMinArea()268 double GetHatchHoleMinArea() const { return m_hatchHoleMinArea; } SetHatchHoleMinArea(double aPct)269 void SetHatchHoleMinArea( double aPct ) { m_hatchHoleMinArea = aPct; } 270 GetHatchBorderAlgorithm()271 int GetHatchBorderAlgorithm() const { return m_hatchBorderAlgorithm; } SetHatchBorderAlgorithm(int aAlgo)272 void SetHatchBorderAlgorithm( int aAlgo ) { m_hatchBorderAlgorithm = aAlgo; } 273 GetSelectedCorner()274 int GetSelectedCorner() const 275 { 276 // Transform relative indices to global index 277 int globalIndex = -1; 278 279 if( m_CornerSelection ) 280 m_Poly->GetGlobalIndex( *m_CornerSelection, globalIndex ); 281 282 return globalIndex; 283 } 284 SetSelectedCorner(int aCorner)285 void SetSelectedCorner( int aCorner ) 286 { 287 SHAPE_POLY_SET::VERTEX_INDEX selectedCorner; 288 289 // If the global index of the corner is correct, assign it to m_CornerSelection 290 if( m_Poly->GetRelativeIndices( aCorner, &selectedCorner ) ) 291 { 292 if( m_CornerSelection == nullptr ) 293 m_CornerSelection = new SHAPE_POLY_SET::VERTEX_INDEX; 294 295 *m_CornerSelection = selectedCorner; 296 } 297 else 298 throw( std::out_of_range( "aCorner-th vertex does not exist" ) ); 299 } 300 301 /// 302 // Like HitTest but selects the current corner to be operated on 303 void SetSelectedCorner( const wxPoint& aPosition, int aAccuracy ); 304 GetLocalFlags()305 int GetLocalFlags() const { return m_localFlgs; } SetLocalFlags(int aFlags)306 void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; } 307 FillSegments(PCB_LAYER_ID aLayer)308 std::vector<SEG>& FillSegments( PCB_LAYER_ID aLayer ) 309 { 310 wxASSERT( m_FillSegmList.count( aLayer ) ); 311 return m_FillSegmList.at( aLayer ); 312 } 313 FillSegments(PCB_LAYER_ID aLayer)314 const std::vector<SEG>& FillSegments( PCB_LAYER_ID aLayer ) const 315 { 316 wxASSERT( m_FillSegmList.count( aLayer ) ); 317 return m_FillSegmList.at( aLayer ); 318 } 319 Outline()320 SHAPE_POLY_SET* Outline() { return m_Poly; } Outline()321 const SHAPE_POLY_SET* Outline() const { return m_Poly; } 322 SetOutline(SHAPE_POLY_SET * aOutline)323 void SetOutline( SHAPE_POLY_SET* aOutline ) { m_Poly = aOutline; } 324 325 // @copydoc BOARD_ITEM::GetEffectiveShape 326 virtual std::shared_ptr<SHAPE> 327 GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override; 328 329 /** 330 * Test if a point is near an outline edge or a corner of this zone. 331 * 332 * @param aPosition the wxPoint to test 333 * @return true if a hit, else false 334 */ 335 bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; 336 337 /** 338 * Test if the given wxPoint is within the bounds of a filled area of this zone. 339 * 340 * @param aLayer is the layer to test on 341 * @param aRefPos A wxPoint to test 342 * @param aAccuracy Expand the distance by which the areas are expanded for the hittest 343 * @return true if a hit, else false 344 */ 345 bool HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint &aRefPos, int aAccuracy = 0 ) const; 346 347 /** 348 * Test if the given point is contained within a cutout of the zone. 349 * 350 * @param aRefPos is the point to test 351 * @param aOutlineIdx is the index of the outline containing the cutout 352 * @param aHoleIdx is the index of the hole 353 * @return true if aRefPos is inside a zone cutout 354 */ 355 bool HitTestCutout( const VECTOR2I& aRefPos, int* aOutlineIdx = nullptr, 356 int* aHoleIdx = nullptr ) const; 357 358 bool HitTestCutout( const wxPoint& aRefPos, int* aOutlineIdx = nullptr, 359 int* aHoleIdx = nullptr ) const 360 { 361 return HitTestCutout( VECTOR2I( aRefPos.x, aRefPos.y ), aOutlineIdx, aHoleIdx ); 362 } 363 364 /** 365 * Some intersecting zones, despite being on the same layer with the same net, cannot be 366 * merged due to other parameters such as fillet radius. The copper pour will end up 367 * effectively merged though, so we need to do some calculations with them in mind. 368 */ 369 void GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aZones ) const; 370 371 /** 372 * Convert solid areas full shapes to polygon set 373 * (the full shape is the polygon area with a thick outline) 374 * Used in 3D view 375 * Arcs (ends of segments) are approximated by segments 376 * 377 * @param aLayer is the layer of the zone to retrieve 378 * @param aCornerBuffer = a buffer to store the polygons 379 * @param aError = Maximum error allowed between true arc and polygon approx 380 */ 381 void TransformSolidAreasShapesToPolygon( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aCornerBuffer, 382 int aError = ARC_HIGH_DEF ) const; 383 384 /** 385 * Convert the outlines shape to a polygon with no holes 386 * inflated (optional) by max( aClearanceValue, the zone clearance) 387 * (holes are linked to external outline by overlapping segments) 388 * Used in filling zones calculations 389 * Circles (vias) and arcs (ends of tracks) are approximated by segments. 390 * 391 * @param aCornerBuffer is a buffer to store the polygon 392 * @param aClearance is the min clearance around outlines 393 * @param aBoardOutline is the board outline (if a valid one exists; nullptr otherwise) 394 */ 395 void TransformSmoothedOutlineToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearance, 396 SHAPE_POLY_SET* aBoardOutline ) const; 397 398 /** 399 * Convert the zone shape to a closed polygon 400 * Used in filling zones calculations 401 * Circles and arcs are approximated by segments 402 * 403 * @param aLayer is the layer of the filled zone to retrieve 404 * @param aCornerBuffer is a buffer to store the polygon 405 * @param aClearanceValue is the clearance around the pad 406 * @param aError is the maximum deviation from true circle 407 * @param ignoreLineWidth is used for edge cut items where the line width is only 408 * for visualization 409 */ 410 void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, 411 PCB_LAYER_ID aLayer, int aClearanceValue, 412 int aError, ERROR_LOC aErrorLoc, 413 bool ignoreLineWidth = false ) const override; 414 415 /** 416 * Test if the given wxPoint is near a corner. 417 * 418 * @param refPos is the wxPoint to test. 419 * @param aAccuracy increase the item bounding box by this amount. 420 * @param aCornerHit [out] is the index of the closest vertex found, useless when return 421 * value is false. 422 * @return true if some corner was found to be closer to refPos than aClearance; false 423 * otherwise. 424 */ 425 bool HitTestForCorner( const wxPoint& refPos, int aAccuracy, 426 SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const; 427 428 /** 429 * Test if the given wxPoint is near a corner. 430 * @param refPos is the wxPoint to test. 431 * @param aAccuracy increase the item bounding box by this amount. 432 * @return true if some corner was found to be closer to refPos than aClearance; false 433 * otherwise. 434 */ 435 bool HitTestForCorner( const wxPoint& refPos, int aAccuracy ) const; 436 437 /** 438 * Test if the given wxPoint is near a segment defined by 2 corners. 439 * 440 * @param refPos is the wxPoint to test. 441 * @param aAccuracy increase the item bounding box by this amount. 442 * @param aCornerHit [out] is the index of the closest vertex found, useless when return 443 * value is false. 444 * @return true if some edge was found to be closer to refPos than aClearance. 445 */ 446 bool HitTestForEdge( const wxPoint& refPos, int aAccuracy, 447 SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const; 448 449 /** 450 * Test if the given wxPoint is near a segment defined by 2 corners. 451 * 452 * @param refPos is the wxPoint to test. 453 * @param aAccuracy increase the item bounding box by this amount. 454 * @return true if some edge was found to be closer to refPos than aClearance. 455 */ 456 bool HitTestForEdge( const wxPoint& refPos, int aAccuracy ) const; 457 458 /** 459 * @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, 460 * bool aContained = true, int aAccuracy) const 461 */ 462 bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override; 463 464 /** 465 * Removes the zone filling. 466 * 467 * @return true if a previous filling is removed, false if no change (when no filling found). 468 */ 469 bool UnFill(); 470 471 /* Geometric transformations: */ 472 473 /** 474 * Move the outlines 475 * 476 * @param offset is moving vector 477 */ 478 void Move( const wxPoint& offset ) override; 479 480 /** 481 * Move the outline Edge. 482 * 483 * @param offset is moving vector 484 * @param aEdge is start point of the outline edge 485 */ 486 void MoveEdge( const wxPoint& offset, int aEdge ); 487 488 /** 489 * Move the outlines. 490 * 491 * @param aCentre is rot centre 492 * @param aAngle is in 0.1 degree 493 */ 494 void Rotate( const wxPoint& aCentre, double aAngle ) override; 495 496 /** 497 * Flip this object, i.e. change the board side for this object 498 * (like Mirror() but changes layer). 499 * 500 * @param aCentre is the rotation point. 501 */ 502 virtual void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override; 503 504 /** 505 * Mirror the outlines relative to a given horizontal axis the layer is not changed. 506 * 507 * @param aMirrorRef is axis position 508 * @param aMirrorLeftRight mirror across Y axis (otherwise mirror across X) 509 */ 510 void Mirror( const wxPoint& aMirrorRef, bool aMirrorLeftRight ); 511 512 /** 513 * @return the class name. 514 */ GetClass()515 wxString GetClass() const override 516 { 517 return wxT( "ZONE" ); 518 } 519 520 /** 521 * Access to m_Poly parameters 522 */ GetNumCorners(void)523 int GetNumCorners( void ) const 524 { 525 return m_Poly->TotalVertices(); 526 } 527 528 /** 529 * Return an iterator to visit all points of the zone's main outline without holes. 530 * 531 * @return an iterator to visit the zone vertices without holes. 532 */ Iterate()533 SHAPE_POLY_SET::ITERATOR Iterate() 534 { 535 return m_Poly->Iterate(); 536 } 537 538 /** 539 * Return an iterator to visit all points of the zone's main outline with holes. 540 * 541 * @return an iterator to visit the zone vertices with holes. 542 */ IterateWithHoles()543 SHAPE_POLY_SET::ITERATOR IterateWithHoles() 544 { 545 return m_Poly->IterateWithHoles(); 546 } 547 548 /** 549 * Return an iterator to visit all points of the zone's main outline with holes. 550 * 551 * @return an iterator to visit the zone vertices with holes. 552 */ CIterateWithHoles()553 SHAPE_POLY_SET::CONST_ITERATOR CIterateWithHoles() const 554 { 555 return m_Poly->CIterateWithHoles(); 556 } 557 RemoveAllContours(void)558 void RemoveAllContours( void ) 559 { 560 m_Poly->RemoveAllContours(); 561 } 562 GetCornerPosition(int aCornerIndex)563 const VECTOR2I& GetCornerPosition( int aCornerIndex ) const 564 { 565 SHAPE_POLY_SET::VERTEX_INDEX index; 566 567 // Convert global to relative indices 568 if( !m_Poly->GetRelativeIndices( aCornerIndex, &index ) ) 569 throw( std::out_of_range( "aCornerIndex-th vertex does not exist" ) ); 570 571 return m_Poly->CVertex( index ); 572 } 573 SetCornerPosition(int aCornerIndex,const wxPoint & new_pos)574 void SetCornerPosition( int aCornerIndex, const wxPoint& new_pos ) 575 { 576 SHAPE_POLY_SET::VERTEX_INDEX relativeIndices; 577 578 // Convert global to relative indices 579 if( m_Poly->GetRelativeIndices( aCornerIndex, &relativeIndices ) ) 580 { 581 if( m_Poly->CVertex( relativeIndices ).x != new_pos.x 582 || m_Poly->CVertex( relativeIndices ).y != new_pos.y ) 583 { 584 SetNeedRefill( true ); 585 m_Poly->SetVertex( relativeIndices, new_pos ); 586 } 587 } 588 else 589 { 590 throw( std::out_of_range( "aCornerIndex-th vertex does not exist" ) ); 591 } 592 } 593 594 /** 595 * Create a new hole on the zone; i.e., a new contour on the zone's outline. 596 */ NewHole()597 void NewHole() 598 { 599 m_Poly->NewHole(); 600 } 601 602 /** 603 * Add a new corner to the zone outline (to the main outline or a hole) 604 * 605 * @param aPosition is the position of the new corner. 606 * @param aHoleIdx is the index of the hole (-1 for the main outline, >= 0 for hole). 607 * @param aAllowDuplication is a flag to indicate whether it is allowed to add this corner 608 * even if it is duplicated. 609 * @return true if the corner was added, false if error (aHoleIdx > hole count -1) 610 */ 611 bool AppendCorner( wxPoint aPosition, int aHoleIdx, bool aAllowDuplication = false ); 612 GetHatchStyle()613 ZONE_BORDER_DISPLAY_STYLE GetHatchStyle() const { return m_borderStyle; } SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)614 void SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE aStyle ) { m_borderStyle = aStyle; } 615 616 /** 617 * Test if 2 zones are equivalent. 618 * 619 * Zones are equivalent if they have same parameters and same outline info. 620 * 621 * @note Filling is not taken into account. 622 * 623 * @param aZoneToCompare is the zone to compare with "this" 624 */ 625 bool IsSame( const ZONE &aZoneToCompare ); 626 HasFilledPolysForLayer(PCB_LAYER_ID aLayer)627 bool HasFilledPolysForLayer( PCB_LAYER_ID aLayer ) const 628 { 629 return m_FilledPolysList.count( aLayer ) > 0; 630 } 631 632 /** 633 * @return a reference to the list of filled polygons. 634 */ GetFilledPolysList(PCB_LAYER_ID aLayer)635 const SHAPE_POLY_SET& GetFilledPolysList( PCB_LAYER_ID aLayer ) const 636 { 637 wxASSERT( m_FilledPolysList.count( aLayer ) ); 638 return m_FilledPolysList.at( aLayer ); 639 } 640 641 /** 642 * Create a list of triangles that "fill" the solid areas used for instance to draw 643 * these solid areas on OpenGL. 644 */ 645 void CacheTriangulation( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ); 646 647 /** 648 * Set the list of filled polygons. 649 */ SetFilledPolysList(PCB_LAYER_ID aLayer,const SHAPE_POLY_SET & aPolysList)650 void SetFilledPolysList( PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPolysList ) 651 { 652 m_FilledPolysList[aLayer] = aPolysList; 653 } 654 655 /** 656 * Set the list of filled polygons. 657 */ SetRawPolysList(PCB_LAYER_ID aLayer,const SHAPE_POLY_SET & aPolysList)658 void SetRawPolysList( PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPolysList ) 659 { 660 m_RawPolysList[aLayer] = aPolysList; 661 } 662 663 /** 664 * Check if a given filled polygon is an insulated island. 665 * 666 * @param aLayer is the layer to test 667 * @param aPolyIdx is an index into m_FilledPolysList[aLayer] 668 * @return true if the given polygon is insulated (i.e. has no net connection) 669 */ 670 bool IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const; 671 SetIsIsland(PCB_LAYER_ID aLayer,int aPolyIdx)672 void SetIsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) 673 { 674 m_insulatedIslands[aLayer].insert( aPolyIdx ); 675 } 676 677 bool BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer, 678 SHAPE_POLY_SET* aBoardOutline, 679 SHAPE_POLY_SET* aSmoothedPolyWithApron = nullptr ) const; 680 SetCornerSmoothingType(int aType)681 void SetCornerSmoothingType( int aType ) { m_cornerSmoothingType = aType; }; 682 GetCornerSmoothingType()683 int GetCornerSmoothingType() const { return m_cornerSmoothingType; } 684 685 void SetCornerRadius( unsigned int aRadius ); 686 GetCornerRadius()687 unsigned int GetCornerRadius() const { return m_cornerRadius; } 688 GetFilledPolysUseThickness()689 bool GetFilledPolysUseThickness() const { return m_fillVersion == 5; } 690 bool GetFilledPolysUseThickness( PCB_LAYER_ID aLayer ) const; 691 GetFillVersion()692 int GetFillVersion() const { return m_fillVersion; } SetFillVersion(int aVersion)693 void SetFillVersion( int aVersion ) { m_fillVersion = aVersion; } 694 695 /** 696 * Remove a cutout from the zone. 697 * 698 * @param aOutlineIdx is the zone outline the hole belongs to 699 * @param aHoleIdx is the hole in the outline to remove 700 */ 701 void RemoveCutout( int aOutlineIdx, int aHoleIdx ); 702 703 /** 704 * Add a polygon to the zone outline. 705 * 706 * If the zone outline is empty, this is the main outline. Otherwise it is a hole 707 * inside the main outline. 708 */ 709 void AddPolygon( std::vector< wxPoint >& aPolygon ); 710 711 void AddPolygon( const SHAPE_LINE_CHAIN& aPolygon ); 712 SetFillSegments(PCB_LAYER_ID aLayer,const std::vector<SEG> & aSegments)713 void SetFillSegments( PCB_LAYER_ID aLayer, const std::vector<SEG>& aSegments ) 714 { 715 m_FillSegmList[aLayer] = aSegments; 716 } 717 RawPolysList(PCB_LAYER_ID aLayer)718 SHAPE_POLY_SET& RawPolysList( PCB_LAYER_ID aLayer ) 719 { 720 wxASSERT( m_RawPolysList.count( aLayer ) ); 721 return m_RawPolysList.at( aLayer ); 722 } 723 724 wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; 725 726 BITMAPS GetMenuImage() const override; 727 728 EDA_ITEM* Clone() const override; 729 730 /** 731 * Accessors to parameters used in Rule Area zones: 732 */ GetIsRuleArea()733 bool GetIsRuleArea() const { return m_isRuleArea; } GetDoNotAllowCopperPour()734 bool GetDoNotAllowCopperPour() const { return m_doNotAllowCopperPour; } GetDoNotAllowVias()735 bool GetDoNotAllowVias() const { return m_doNotAllowVias; } GetDoNotAllowTracks()736 bool GetDoNotAllowTracks() const { return m_doNotAllowTracks; } GetDoNotAllowPads()737 bool GetDoNotAllowPads() const { return m_doNotAllowPads; } GetDoNotAllowFootprints()738 bool GetDoNotAllowFootprints() const { return m_doNotAllowFootprints; } 739 bool IsKeepout() const; 740 bool KeepoutAll() const; 741 SetIsRuleArea(bool aEnable)742 void SetIsRuleArea( bool aEnable ) { m_isRuleArea = aEnable; } SetDoNotAllowCopperPour(bool aEnable)743 void SetDoNotAllowCopperPour( bool aEnable ) { m_doNotAllowCopperPour = aEnable; } SetDoNotAllowVias(bool aEnable)744 void SetDoNotAllowVias( bool aEnable ) { m_doNotAllowVias = aEnable; } SetDoNotAllowTracks(bool aEnable)745 void SetDoNotAllowTracks( bool aEnable ) { m_doNotAllowTracks = aEnable; } SetDoNotAllowPads(bool aEnable)746 void SetDoNotAllowPads( bool aEnable ) { m_doNotAllowPads = aEnable; } SetDoNotAllowFootprints(bool aEnable)747 void SetDoNotAllowFootprints( bool aEnable ) { m_doNotAllowFootprints = aEnable; } 748 GetIslandRemovalMode()749 const ISLAND_REMOVAL_MODE GetIslandRemovalMode() const { return m_islandRemovalMode; } SetIslandRemovalMode(ISLAND_REMOVAL_MODE aRemove)750 void SetIslandRemovalMode( ISLAND_REMOVAL_MODE aRemove ) { m_islandRemovalMode = aRemove; } 751 GetMinIslandArea()752 long long int GetMinIslandArea() const { return m_minIslandArea; } SetMinIslandArea(long long int aArea)753 void SetMinIslandArea( long long int aArea ) { m_minIslandArea = aArea; } 754 755 /** 756 * HatchBorder related methods 757 */ 758 759 /** 760 * @return the zone hatch pitch in iu. 761 */ 762 int GetBorderHatchPitch() const; 763 764 /** 765 * @return the default hatch pitch in internal units. 766 */ 767 static int GetDefaultHatchPitch(); 768 769 /** 770 * Set all hatch parameters for the zone. 771 * 772 * @param aHatchStyle is the style of the hatch, specified as one of HATCH_STYLE possible 773 * values. 774 * @param aHatchPitch is the hatch pitch in iu. 775 * @param aRebuildHatch is a flag to indicate whether to re-hatch after having set the 776 * previous parameters. 777 */ 778 void SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE aHatchStyle, int aHatchPitch, 779 bool aRebuildHatch ); 780 781 /** 782 * Set the hatch pitch parameter for the zone. 783 * 784 * @param aPitch is the hatch pitch in iu. 785 */ 786 void SetHatchPitch( int aPitch ); 787 788 /** 789 * Clear the zone's hatch. 790 */ 791 void UnHatchBorder(); 792 793 /** 794 * Compute the hatch lines depending on the hatch parameters and stores it in the zone's 795 * attribute m_borderHatchLines. 796 */ 797 void HatchBorder(); 798 GetHatchLines()799 const std::vector<SEG>& GetHatchLines() const { return m_borderHatchLines; } 800 GetHV45()801 bool GetHV45() const { return m_hv45; } SetHV45(bool aConstrain)802 void SetHV45( bool aConstrain ) { m_hv45 = aConstrain; } 803 804 /** 805 * Build the hash value of m_FilledPolysList, and store it internally in m_filledPolysHash. 806 * Used in zone filling calculations, to know if m_FilledPolysList is up to date. 807 */ 808 void BuildHashValue( PCB_LAYER_ID aLayer ); 809 810 /** 811 * @return the hash value previously calculated by BuildHashValue(). 812 */ 813 MD5_HASH GetHashValue( PCB_LAYER_ID aLayer ); 814 815 #if defined(DEBUG) Show(int nestLevel,std::ostream & os)816 virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); } 817 #endif 818 819 virtual void SwapData( BOARD_ITEM* aImage ) override; 820 821 protected: 822 SHAPE_POLY_SET* m_Poly; ///< Outline of the zone. 823 int m_cornerSmoothingType; 824 unsigned int m_cornerRadius; 825 826 /// An optional unique name for this zone, used for identifying it in DRC checking 827 wxString m_zoneName; 828 829 LSET m_layerSet; 830 831 /* Priority: when a zone outline is inside and other zone, if its priority is higher 832 * the other zone priority, it will be created inside. 833 * if priorities are equal, a DRC error is set 834 */ 835 unsigned m_priority; 836 837 /* A zone outline can be a keepout zone. 838 * It will be never filled, and DRC should test for pads, tracks and vias 839 */ 840 bool m_isRuleArea; 841 842 /* For keepout zones only: 843 * what is not allowed inside the keepout ( pads, tracks and vias ) 844 */ 845 bool m_doNotAllowCopperPour; 846 bool m_doNotAllowVias; 847 bool m_doNotAllowTracks; 848 bool m_doNotAllowPads; 849 bool m_doNotAllowFootprints; 850 851 ZONE_CONNECTION m_PadConnection; 852 int m_ZoneClearance; // Clearance value in internal units. 853 int m_ZoneMinThickness; // Minimum thickness value in filled areas. 854 int m_fillVersion; // See BOARD_DESIGN_SETTINGS for version 855 // differences. 856 ISLAND_REMOVAL_MODE m_islandRemovalMode; 857 858 /** 859 * When island removal mode is set to AREA, islands below this area will be removed. 860 * If this value is negative, all islands will be removed. 861 */ 862 long long int m_minIslandArea; 863 864 /** True when a zone was filled, false after deleting the filled areas. */ 865 bool m_isFilled; 866 867 /** 868 * False when a zone was refilled, true after changes in zone params. 869 * m_needRefill = false does not imply filled areas are up to date, just 870 * the zone was refilled after edition, and does not need refilling 871 */ 872 bool m_needRefill; 873 874 int m_thermalReliefGap; // Width of the gap in thermal reliefs. 875 int m_thermalReliefSpokeWidth; // Width of the copper bridge in thermal reliefs. 876 877 878 /** 879 * How to fill areas: 880 * 881 * ZONE_FILL_MODE::POLYGONS => use solid polygons 882 * ZONE_FILL_MODE::HATCH_PATTERN => use a grid pattern as shape 883 */ 884 ZONE_FILL_MODE m_fillMode; 885 int m_hatchThickness; // thickness of lines (if 0 -> solid shape) 886 int m_hatchGap; // gap between lines (0 -> solid shape 887 double m_hatchOrientation; // orientation in degrees of grid lines 888 int m_hatchSmoothingLevel; // 0 = no smoothing 889 // 1 = fillet 890 // 2 = arc low def 891 // 3 = arc high def 892 double m_hatchSmoothingValue; // hole chamfer/fillet size (ratio of hole size) 893 double m_hatchHoleMinArea; // min size before holes are dropped (ratio) 894 int m_hatchBorderAlgorithm; // 0 = use min zone thickness 895 // 1 = use hatch thickness 896 897 /// The index of the corner being moved or nullptr if no corner is selected. 898 SHAPE_POLY_SET::VERTEX_INDEX* m_CornerSelection; 899 900 int m_localFlgs; // Variable used in polygon calculations. 901 902 /** 903 * Segments used to fill the zone (#m_FillMode ==1 ), when fill zone by segment is used. 904 * In this case the segments have #m_ZoneMinThickness width. 905 */ 906 std::map<PCB_LAYER_ID, std::vector<SEG> > m_FillSegmList; 907 908 /* set of filled polygons used to draw a zone as a filled area. 909 * from outlines (m_Poly) but unlike m_Poly these filled polygons have no hole 910 * (they are all in one piece) In very simple cases m_FilledPolysList is same 911 * as m_Poly. In less simple cases (when m_Poly has holes) m_FilledPolysList is 912 * a polygon equivalent to m_Poly, without holes but with extra outline segment 913 * connecting "holes" with external main outline. In complex cases an outline 914 * described by m_Poly can have many filled areas 915 */ 916 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_FilledPolysList; 917 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> m_RawPolysList; 918 919 /// Temp variables used while filling 920 EDA_RECT m_bboxCache; 921 std::map<PCB_LAYER_ID, bool> m_fillFlags; 922 923 /// A hash value used in zone filling calculations to see if the filled areas are up to date 924 std::map<PCB_LAYER_ID, MD5_HASH> m_filledPolysHash; 925 926 ZONE_BORDER_DISPLAY_STYLE m_borderStyle; // border display style, see enum above 927 int m_borderHatchPitch; // for DIAGONAL_EDGE, distance between 2 lines 928 std::vector<SEG> m_borderHatchLines; // hatch lines 929 930 /// For each layer, a set of insulated islands that were not removed 931 std::map<PCB_LAYER_ID, std::set<int>> m_insulatedIslands; 932 933 bool m_hv45; // constrain edges to horiz, vert or 45º 934 935 double m_area; // The filled zone area 936 937 /// Lock used for multi-threaded filling on multi-layer zones 938 std::mutex m_lock; 939 }; 940 941 942 /** 943 * A specialization of ZONE for use in footprints. 944 */ 945 class FP_ZONE : public ZONE 946 { 947 public: 948 FP_ZONE( BOARD_ITEM_CONTAINER* aParent ); 949 FP_ZONE( const FP_ZONE& aZone ); 950 FP_ZONE& operator=( const FP_ZONE &aOther ); 951 952 EDA_ITEM* Clone() const override; 953 954 double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override; 955 }; 956 957 #endif // ZONE_H 958