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 layer
176  if( area_to_test->GetLayer() != area2->GetLayer() )
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  if( TestAreaIntersection( area_to_test, area2 ) )
188  return true;
189  }
190 
191  return false;
192 }
193 
194 
196 {
197  // see if areas are on same layer
198  if( area_ref->GetLayer() != area_to_test->GetLayer() )
199  return false;
200 
201  SHAPE_POLY_SET* poly1 = area_ref->Outline();
202  SHAPE_POLY_SET* poly2 = area_to_test->Outline();
203 
204  // test bounding rects
205  BOX2I b1 = poly1->BBox();
206  BOX2I b2 = poly2->BBox();
207 
208  if( ! b1.Intersects( b2 ) )
209  return false;
210 
211  // Now test for intersecting segments
212  for( auto segIterator1 = poly1->IterateSegmentsWithHoles(); segIterator1; segIterator1++ )
213  {
214  // Build segment
215  SEG firstSegment = *segIterator1;
216 
217  for( auto segIterator2 = poly2->IterateSegmentsWithHoles(); segIterator2; segIterator2++ )
218  {
219  // Build second segment
220  SEG secondSegment = *segIterator2;
221 
222  // Check whether the two segments built collide
223  if( firstSegment.Collide( secondSegment, 0 ) )
224  return true;
225  }
226  }
227 
228  // If a contour is inside another contour, no segments intersects, but the zones
229  // can be combined if a corner is inside an outline (only one corner is enough)
230  for( auto iter = poly2->IterateWithHoles(); iter; iter++ )
231  {
232  if( poly1->Contains( *iter ) )
233  return true;
234  }
235 
236  for( auto iter = poly1->IterateWithHoles(); iter; iter++ )
237  {
238  if( poly2->Contains( *iter ) )
239  return true;
240  }
241 
242  return false;
243 }
244 
245 
246 bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref,
247  ZONE_CONTAINER* area_to_combine )
248 {
249  if( area_ref == area_to_combine )
250  {
251  wxASSERT( 0 );
252  return false;
253  }
254 
255  SHAPE_POLY_SET mergedOutlines = *area_ref->Outline();
256  SHAPE_POLY_SET areaToMergePoly = *area_to_combine->Outline();
257 
258  mergedOutlines.BooleanAdd( areaToMergePoly, SHAPE_POLY_SET::PM_FAST );
259  mergedOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );
260 
261  // We should have one polygon with hole
262  // We can have 2 polygons with hole, if the 2 initial polygons have only one common corner
263  // and therefore cannot be merged (they are dectected as intersecting)
264  // but we should never have more than 2 polys
265  if( mergedOutlines.OutlineCount() > 2 )
266  {
267  wxLogMessage(wxT("BOARD::CombineAreas error: more than 2 polys after merging") );
268  return false;
269  }
270 
271  if( mergedOutlines.OutlineCount() > 1 )
272  return false;
273 
274  // Update the area with the new merged outline
275  delete area_ref->Outline();
276  area_ref->SetOutline( new SHAPE_POLY_SET( mergedOutlines ) );
277 
278  RemoveArea( aDeletedList, area_to_combine );
279 
280  area_ref->SetLocalFlags( 1 );
281  area_ref->Hatch();
282 
283  return true;
284 }
285 
286 
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:414
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
This file is part of the common library.
bool OnAreaPolygonModified(PICKED_ITEMS_LIST *aModifiedZonesList, ZONE_CONTAINER *modified_area)
Function OnAreaPolygonModified Process an area that has been modified, by normalizing its polygon and...
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:171
SHAPE_POLY_SET * Outline()
Definition: class_zone.h:236
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 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.
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...
void SetOutline(SHAPE_POLY_SET *aOutline)
Definition: class_zone.h:239
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:602
Markers used to show a drc problem on boards.
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.
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:224
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
int GetLocalFlags() const
Definition: class_zone.h:230
ZONE_CONTAINERS m_ZoneDescriptorList
edge zone descriptors, owned by pointer.
Definition: class_board.h:181
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:231
The common library.
bool Collide(const SEG &aSeg, int aClearance) const
Definition: seg.cpp:134
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:101
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...