KiCad PCB EDA Suite
zones_test_and_combine_areas.cpp
Go to the documentation of this file.
1 
7 /*
8  * This program source code file is part of KiCad, a free EDA CAD application.
9  *
10  * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
11  * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
12  *
13  * Some code comes from FreePCB.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, you may find one here:
27  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
28  * or you may search the http://www.gnu.org website for the version 2 license,
29  * or you may write to the Free Software Foundation, Inc.,
30  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
31  */
32 
33 #include <fctsys.h>
34 #include <common.h>
35 #include <confirm.h>
36 #include <undo_redo_container.h>
37 
38 #include <class_board.h>
39 #include <class_zone.h>
40 #include <class_marker_pcb.h>
41 
42 #include <pcbnew.h>
43 #include <drc.h>
44 #include <math_for_graphics.h>
45 
46 #define STRAIGHT 0 // To be remove after math_for_graphics code cleanup
47 
48 
50  ZONE_CONTAINER* modified_area )
51 {
52  // clip polygon against itself
53  bool modified = NormalizeAreaPolygon( aModifiedZonesList, modified_area );
54 
55  // now see if we need to clip against other areas
56  /*
57  LAYER_NUM layer = modified_area->GetLayer();
58  */
59 
60  bool bCheckAllAreas = TestAreaIntersections( modified_area );
61 
62  if( bCheckAllAreas )
63  {
64  modified = true;
65  CombineAllAreasInNet( aModifiedZonesList, modified_area->GetNetCode(), true );
66  }
67 
68  /*
69 
70  FIXME : do we really need this?
71 
72  if( !IsCopperLayer( layer ) ) // Refill non copper zones on this layer
73  {
74  for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
75  if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
76  m_ZoneDescriptorList[ia]->BuildFilledSolidAreasPolygons( this );
77  }
78 
79  */
80 
81  // Test for bad areas: all zones must have more than 2 corners:
82  // Note: should not happen, but just in case.
83  for( unsigned ii = 0; ii < m_ZoneDescriptorList.size(); )
84  {
86 
87  if( zone->GetNumCorners() >= 3 )
88  ii++;
89  else // Remove zone because it is incorrect:
90  RemoveArea( aModifiedZonesList, zone );
91  }
92 
93  return modified;
94 }
95 
96 
97 bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
98  bool aUseLocalFlags )
99 {
100  if( m_ZoneDescriptorList.size() <= 1 )
101  return false;
102 
103  bool modified = false;
104 
105  // Loop through all combinations
106  for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ia1++ )
107  {
108  ZONE_CONTAINER* curr_area = m_ZoneDescriptorList[ia1];
109 
110  if( curr_area->GetNetCode() != aNetCode )
111  continue;
112 
113  // legal polygon
114  BOX2I b1 = curr_area->Outline()->BBox();
115  bool mod_ia1 = false;
116 
117  for( unsigned ia2 = m_ZoneDescriptorList.size() - 1; ia2 > ia1; ia2-- )
118  {
119  ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2];
120 
121  if( area2->GetNetCode() != aNetCode )
122  continue;
123 
124  if( curr_area->GetPriority() != area2->GetPriority() )
125  continue;
126 
127  if( curr_area->GetIsKeepout() != area2->GetIsKeepout() )
128  continue;
129 
130  if( curr_area->GetLayer() != area2->GetLayer() )
131  continue;
132 
133  BOX2I b2 = area2->Outline()->BBox();
134 
135  if( b1.Intersects( b2 ) )
136  {
137  // check area2 against curr_area
138  if( curr_area->GetLocalFlags() || area2->GetLocalFlags()
139  || aUseLocalFlags == false )
140  {
141  bool ret = TestAreaIntersection( curr_area, area2 );
142 
143  if( ret )
144  ret = CombineAreas( aDeletedList, curr_area, area2 );
145 
146  if( ret )
147  {
148  mod_ia1 = true;
149  modified = true;
150  }
151  }
152  }
153  }
154 
155  if( mod_ia1 )
156  ia1--; // if modified, we need to check it again
157  }
158 
159  return modified;
160 }
161 
162 
164 {
165  for( unsigned ia2 = 0; ia2 < m_ZoneDescriptorList.size(); ia2++ )
166  {
167  ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2];
168 
169  if( area_to_test->GetNetCode() != area2->GetNetCode() )
170  continue;
171 
172  if( area_to_test == area2 )
173  continue;
174 
175  // see if areas are on same layers
176  if( area_to_test->GetLayerSet() != area2->GetLayerSet() )
177  continue;
178 
179  // test for different priorities
180  if( area_to_test->GetPriority() != area2->GetPriority() )
181  continue;
182 
183  // test for different types
184  if( area_to_test->GetIsKeepout() != area2->GetIsKeepout() )
185  continue;
186 
187  // Keepout area-specific tests
188  if( area_to_test->GetIsKeepout() )
189  {
190  if( area_to_test->GetDoNotAllowCopperPour() != area2->GetDoNotAllowCopperPour() )
191  continue;
192 
193  if( area_to_test->GetDoNotAllowTracks() != area2->GetDoNotAllowTracks() )
194  continue;
195 
196  if( area_to_test->GetDoNotAllowVias() != area2->GetDoNotAllowVias() )
197  continue;
198  }
199  // Filled zone specific tests
200  else
201  {
202  if( area_to_test->GetClearance() != area2->GetClearance() )
203  continue;
204 
205  if( area_to_test->GetThermalReliefGap() != area2->GetThermalReliefGap() )
206  continue;
207 
208  if( area_to_test->GetThermalReliefCopperBridge() != area2->GetThermalReliefCopperBridge() )
209  continue;
210 
211  if( area_to_test->GetArcSegmentCount() != area2->GetArcSegmentCount() )
212  continue;
213 
214  if( area_to_test->GetZoneClearance() != area2->GetZoneClearance() )
215  continue;
216 
217  if( area_to_test->GetPadConnection() != area2->GetPadConnection() )
218  continue;
219 
220  if( area_to_test->GetMinThickness() != area2->GetMinThickness() )
221  continue;
222 
223  if( area_to_test->GetCornerSmoothingType() != area2->GetCornerSmoothingType() )
224  continue;
225 
226  if( area_to_test->GetCornerRadius() != area2->GetCornerRadius() )
227  continue;
228  }
229 
230  if( TestAreaIntersection( area_to_test, area2 ) )
231  return true;
232  }
233 
234  return false;
235 }
236 
237 
239 {
240  // see if areas are on same layer
241  if( area_ref->GetLayer() != area_to_test->GetLayer() )
242  return false;
243 
244  SHAPE_POLY_SET* poly1 = area_ref->Outline();
245  SHAPE_POLY_SET* poly2 = area_to_test->Outline();
246 
247  // test bounding rects
248  BOX2I b1 = poly1->BBox();
249  BOX2I b2 = poly2->BBox();
250 
251  if( ! b1.Intersects( b2 ) )
252  return false;
253 
254  // Now test for intersecting segments
255  for( auto segIterator1 = poly1->IterateSegmentsWithHoles(); segIterator1; segIterator1++ )
256  {
257  // Build segment
258  SEG firstSegment = *segIterator1;
259 
260  for( auto segIterator2 = poly2->IterateSegmentsWithHoles(); segIterator2; segIterator2++ )
261  {
262  // Build second segment
263  SEG secondSegment = *segIterator2;
264 
265  // Check whether the two segments built collide
266  if( firstSegment.Collide( secondSegment, 0 ) )
267  return true;
268  }
269  }
270 
271  // If a contour is inside another contour, no segments intersects, but the zones
272  // can be combined if a corner is inside an outline (only one corner is enough)
273  for( auto iter = poly2->IterateWithHoles(); iter; iter++ )
274  {
275  if( poly1->Contains( *iter ) )
276  return true;
277  }
278 
279  for( auto iter = poly1->IterateWithHoles(); iter; iter++ )
280  {
281  if( poly2->Contains( *iter ) )
282  return true;
283  }
284 
285  return false;
286 }
287 
288 
289 bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref,
290  ZONE_CONTAINER* area_to_combine )
291 {
292  if( area_ref == area_to_combine )
293  {
294  wxASSERT( 0 );
295  return false;
296  }
297 
298  SHAPE_POLY_SET mergedOutlines = *area_ref->Outline();
299  SHAPE_POLY_SET areaToMergePoly = *area_to_combine->Outline();
300 
301  mergedOutlines.BooleanAdd( areaToMergePoly, SHAPE_POLY_SET::PM_FAST );
302  mergedOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );
303 
304  // We should have one polygon with hole
305  // We can have 2 polygons with hole, if the 2 initial polygons have only one common corner
306  // and therefore cannot be merged (they are dectected as intersecting)
307  // but we should never have more than 2 polys
308  if( mergedOutlines.OutlineCount() > 2 )
309  {
310  wxLogMessage(wxT("BOARD::CombineAreas error: more than 2 polys after merging") );
311  return false;
312  }
313 
314  if( mergedOutlines.OutlineCount() > 1 )
315  return false;
316 
317  // Update the area with the new merged outline
318  delete area_ref->Outline();
319  area_ref->SetOutline( new SHAPE_POLY_SET( mergedOutlines ) );
320 
321  RemoveArea( aDeletedList, area_to_combine );
322 
323  area_ref->SetLocalFlags( 1 );
324  area_ref->Hatch();
325 
326  return true;
327 }
328 
329 
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition: class_zone.h:435
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset union For aFastMode meaning, see function booleanOp
int GetMinThickness() const
Definition: class_zone.h:204
This file is part of the common library.
bool GetDoNotAllowCopperPour() const
Definition: class_zone.h:624
bool OnAreaPolygonModified(PICKED_ITEMS_LIST *aModifiedZonesList, ZONE_CONTAINER *modified_area)
Function OnAreaPolygonModified Process an area that has been modified, by normalizing its polygon and...
int GetArcSegmentCount() const
Definition: class_zone.h:193
Class BOARD to handle a board.
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:175
SHAPE_POLY_SET * Outline()
Definition: class_zone.h:242
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, bool aIgnoreHoles=false) const
Returns true if a given subpolygon contains the point aP.
void RemoveArea(PICKED_ITEMS_LIST *aDeletedList, ZONE_CONTAINER *area_to_remove)
Function RemoveArea remove copper area from net, and put it in a deleted list (if exists) ...
Classes to handle copper zones.
int GetCornerSmoothingType() const
Definition: class_zone.h:591
int OutlineCount() const
Returns the number of outlines in the set
bool CombineAreas(PICKED_ITEMS_LIST *aDeletedList, ZONE_CONTAINER *area_ref, ZONE_CONTAINER *area_to_combine)
Function CombineAreas If possible, combine 2 copper areas.
int GetThermalReliefCopperBridge(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:637
bool TestAreaIntersection(ZONE_CONTAINER *area_ref, ZONE_CONTAINER *area_to_test)
Function TestAreaIntersection Test for intersection of 2 copper areas area_to_test must be after area...
unsigned int GetCornerRadius() const
Definition: class_zone.h:595
void SetOutline(SHAPE_POLY_SET *aOutline)
Definition: class_zone.h:245
int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
Definition: class_zone.cpp:778
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:623
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_zone.cpp:230
Markers used to show a drc problem on boards.
ZoneConnection GetPadConnection(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:995
bool NormalizeAreaPolygon(PICKED_ITEMS_LIST *aNewZonesList, ZONE_CONTAINER *aCurrArea)
Function NormalizeAreaPolygon Process an area that has been modified, by normalizing its polygon agai...
ITERATOR IterateWithHoles(int aOutline)
Function IterateWithHoles.
Class SHAPE_POLY_SET.
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:628
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:234
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
int GetNetCode() const
Function GetNetCode.
Definition: seg.h:36
bool GetDoNotAllowTracks() const
Definition: class_zone.h:626
int GetLocalFlags() const
Definition: class_zone.h:236
bool GetDoNotAllowVias() const
Definition: class_zone.h:625
ZONE_CONTAINERS m_ZoneDescriptorList
edge zone descriptors, owned by pointer.
Definition: class_board.h:182
void Hatch()
Function Hatch computes the hatch lines depending on the hatch parameters and stores it in the zone&#39;s...
void SetLocalFlags(int aFlags)
Definition: class_zone.h:237
The common library.
bool Collide(const SEG &aSeg, int aClearance) const
Definition: seg.cpp:134
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:107
bool CombineAllAreasInNet(PICKED_ITEMS_LIST *aDeletedList, int aNetCode, bool aUseLocalFlags)
Function CombineAllAreasInNet Checks all copper areas in net for intersections, combining them if fou...
const BOX2I BBox(int aClearance=0) const override
Function BBox()
bool TestAreaIntersections(ZONE_CONTAINER *area_to_test)
Function TestAreaIntersections Check for intersection of a given copper area with other areas in same...
int GetZoneClearance() const
Definition: class_zone.h:198