/** * Function NormalizeAreaOutlines * Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s) * @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine * needed by the normalization * @return the polygon count (always >= 1, because there is at least one polygon) * There are new polygons only if the polygon count is > 1 */ int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList ) { SHAPE_POLY_SET polySet = ConvertPolyListToPolySet( m_CornersList ); // We are expecting only one main outline, but this main outline can have holes // if holes: combine holes and remove them from the main outline. // Note also we are using SHAPE_POLY_SET::PM_STRICTLY_SIMPLE in polygon // calculations, but it is not mandatory. It is used mainly // because there is usually only very few vertices in area outlines SHAPE_POLY_SET::POLYGON& outline = polySet.Polygon( 0 ); SHAPE_POLY_SET holesBuffer; // Move holes stored in outline to holesBuffer: // The first SHAPE_LINE_CHAIN is the main outline, others are holes while( outline.size() > 1 ) { holesBuffer.AddOutline( outline.back() ); outline.pop_back(); } polySet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE); // If any hole, substract it to main outline if( holesBuffer.OutlineCount() ) { holesBuffer.Simplify( SHAPE_POLY_SET::PM_FAST); polySet.BooleanSubtract( holesBuffer, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); } RemoveAllContours(); // Note: we can have more than outline, because a self intersecting outline will be // broken to non intersecting polygons, and removing holes can also create a few polygons for( int ii = 0; ii < polySet.OutlineCount(); ii++ ) { CPolyLine* polyline = this; if( ii > 0 ) { polyline = new CPolyLine; polyline->ImportSettings( this ); aNewPolygonList->push_back( polyline ); } SHAPE_POLY_SET pnew; pnew.NewOutline(); pnew.Polygon( 0 ) = polySet.CPolygon( ii ); polyline->m_CornersList = ConvertPolySetToPolyList( pnew ); } return polySet.OutlineCount(); }
bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ) { if( area_ref == area_to_combine ) { wxASSERT( 0 ); return false; } SHAPE_POLY_SET mergedOutlines = ConvertPolyListToPolySet( area_ref->Outline()->m_CornersList ); SHAPE_POLY_SET areaToMergePoly = ConvertPolyListToPolySet( area_to_combine->Outline()->m_CornersList ); mergedOutlines.BooleanAdd( areaToMergePoly ); mergedOutlines.Simplify(); // We should have one polygon with hole // We can have 2 polygons with hole, if the 2 initial polygons have only one common corner // and therefore cannot be merged (they are dectected as intersecting) // but we should never have more than 2 polys if( mergedOutlines.OutlineCount() > 2 ) { wxLogMessage(wxT("BOARD::CombineAreas error: more than 2 polys after merging") ); return false; } if( mergedOutlines.OutlineCount() > 1 ) return false; area_ref->Outline()->m_CornersList = ConvertPolySetToPolyList( mergedOutlines ); RemoveArea( aDeletedList, area_to_combine ); area_ref->SetLocalFlags( 1 ); area_ref->Outline()->Hatch(); return true; }
void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb ) { int segsPerCircle; double correctionFactor; int outline_half_thickness = m_ZoneMinThickness / 2; std::unique_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO( g_DumpZonesWhenFilling ? "zones_dump.txt" : "", SHAPE_FILE_IO::IOM_APPEND ) ); // Set the number of segments in arc approximations if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF ) segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF; else segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF; /* calculates the coeff to compensate radius reduction of holes clearance * due to the segment approx. * For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2) * s_Correction is 1 /cos( PI/s_CircleToSegmentsCount ) */ correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle ); CPOLYGONS_LIST tmp; if(g_DumpZonesWhenFilling) dumper->BeginGroup("clipper-zone"); SHAPE_POLY_SET solidAreas = ConvertPolyListToPolySet( m_smoothedPoly->m_CornersList ); solidAreas.Inflate( -outline_half_thickness, segsPerCircle ); solidAreas.Simplify( POLY_CALC_MODE ); SHAPE_POLY_SET holes; if(g_DumpZonesWhenFilling) dumper->Write( &solidAreas, "solid-areas" ); tmp.RemoveAllContours(); buildFeatureHoleList( aPcb, holes ); if(g_DumpZonesWhenFilling) dumper->Write( &holes, "feature-holes" ); holes.Simplify( POLY_CALC_MODE ); if (g_DumpZonesWhenFilling) dumper->Write( &holes, "feature-holes-postsimplify" ); solidAreas.BooleanSubtract( holes, POLY_CALC_MODE ); if (g_DumpZonesWhenFilling) dumper->Write( &solidAreas, "solid-areas-minus-holes" ); SHAPE_POLY_SET areas_fractured = solidAreas; areas_fractured.Fracture( POLY_CALC_MODE ); if (g_DumpZonesWhenFilling) dumper->Write( &areas_fractured, "areas_fractured" ); m_FilledPolysList = areas_fractured; // Remove insulated islands: if( GetNetCode() > 0 ) TestForCopperIslandAndRemoveInsulatedIslands( aPcb ); SHAPE_POLY_SET thermalHoles; // Test thermal stubs connections and add polygons to remove unconnected stubs. // (this is a refinement for thermal relief shapes) if( GetNetCode() > 0 ) BuildUnconnectedThermalStubsPolygonList( thermalHoles, aPcb, this, correctionFactor, s_thermalRot ); // remove copper areas corresponding to not connected stubs if( !thermalHoles.IsEmpty() ) { thermalHoles.Simplify( POLY_CALC_MODE ); // Remove unconnected stubs solidAreas.BooleanSubtract( thermalHoles, POLY_CALC_MODE ); if( g_DumpZonesWhenFilling ) dumper->Write( &thermalHoles, "thermal-holes" ); // put these areas in m_FilledPolysList SHAPE_POLY_SET th_fractured = solidAreas; th_fractured.Fracture( POLY_CALC_MODE ); if( g_DumpZonesWhenFilling ) dumper->Write ( &th_fractured, "th_fractured" ); m_FilledPolysList = th_fractured; if( GetNetCode() > 0 ) TestForCopperIslandAndRemoveInsulatedIslands( aPcb ); } if(g_DumpZonesWhenFilling) dumper->EndGroup(); }