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