From f96d557e733290a79efec31cccbd502291c656b4 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Mon, 30 Jul 2012 09:40:25 +0200 Subject: [PATCH] Fix issues in zones creation (DRC and merging) I created in 3658.1 --- pcbnew/class_zone.cpp | 3 +- pcbnew/class_zone.h | 2 +- pcbnew/class_zone_settings.cpp | 5 +- pcbnew/drc_clearance_test_functions.cpp | 1 + pcbnew/eagle_plugin.cpp | 14 +-- pcbnew/legacy_plugin.cpp | 8 +- pcbnew/pcb_parser.cpp | 6 +- pcbnew/zones_by_polygon.cpp | 8 +- pcbnew/zones_test_and_combine_areas.cpp | 113 +++++++++++++++++++----- polygon/PolyLine.cpp | 110 +++++++++++++++++------ polygon/PolyLine.h | 37 +++++--- polygon/math_for_graphics.cpp | 49 +++++++--- polygon/math_for_graphics.h | 23 ----- 13 files changed, 263 insertions(+), 116 deletions(-) diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index d79c1e4ffc..6603e58710 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -46,6 +46,7 @@ #include #include +#include ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) : @@ -912,7 +913,7 @@ void ZONE_CONTAINER::AddPolygon( std::vector< wxPoint >& aPolygon ) AppendCorner( aPolygon[i] ); } - m_Poly->Close(); + m_Poly->CloseLastContour(); } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 048125c9c2..0e668197c3 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -429,7 +429,7 @@ public: return m_Poly->GetHatchStyle(); } - void SetHatchStyle( CPolyLine::hatch_style aStyle ) + void SetHatchStyle( CPolyLine::HATCH_STYLE aStyle ) { m_Poly->SetHatchStyle( aStyle ); } diff --git a/pcbnew/class_zone_settings.cpp b/pcbnew/class_zone_settings.cpp index 750f6b48c4..fe74aa1bf5 100644 --- a/pcbnew/class_zone_settings.cpp +++ b/pcbnew/class_zone_settings.cpp @@ -99,7 +99,6 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c aTarget.m_FillMode = m_FillMode; aTarget.m_ZoneClearance = m_ZoneClearance; aTarget.m_ZoneMinThickness = m_ZoneMinThickness; - aTarget.m_Poly->SetHatch( m_Zone_HatchingStyle, Mils2iu( 20 ) ); aTarget.m_ArcToSegmentsCount = m_ArcToSegmentsCount; aTarget.m_ThermalReliefGap = m_ThermalReliefGap; aTarget.m_ThermalReliefCopperBridge = m_ThermalReliefCopperBridge; @@ -118,4 +117,8 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c aTarget.SetLayer( m_CurrentZone_Layer ); aTarget.m_Poly->SetLayer( m_CurrentZone_Layer ); } + + // call SetHatch last, because hatch lines will be rebuilt, + // using new parameters values + aTarget.m_Poly->SetHatch( m_Zone_HatchingStyle, Mils2iu( 20 ), true ); } diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index dabf9fe0e9..5caa5e0d10 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -44,6 +44,7 @@ #include #include #include +#include /* compare 2 trapezoids (can be rectangle) and return true if distance > aDist diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 4a00e9b711..72265679ff 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -1404,17 +1404,18 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics ) zone->SetLayer( layer ); zone->SetNet( 0 ); - int outline_hatch = CPolyLine::DIAGONAL_EDGE; + CPolyLine::HATCH_STYLE outline_hatch = CPolyLine::DIAGONAL_EDGE; zone->m_Poly->Start( layer, kicad_x( r.x1 ), kicad_y( r.y1 ), outline_hatch ); zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) ); zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) ); zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) ); - zone->m_Poly->Close(); + zone->m_Poly->CloseLastContour(); // this is not my fault: zone->m_Poly->SetHatch( outline_hatch, - Mils2iu( zone->m_Poly->GetDefaultHatchPitchMils() ) ); + Mils2iu( zone->m_Poly->GetDefaultHatchPitchMils() ), + true ); } m_xpath->pop(); } @@ -2360,7 +2361,7 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) zone->SetNet( netCode ); zone->SetNetName( netName ); - int outline_hatch = CPolyLine::DIAGONAL_EDGE; + CPolyLine::HATCH_STYLE outline_hatch = CPolyLine::DIAGONAL_EDGE; bool first = true; for( CITER vi = it->second.begin(); vi != it->second.end(); ++vi ) @@ -2380,10 +2381,11 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) ); } - zone->m_Poly->Close(); + zone->m_Poly->CloseLastContour(); zone->m_Poly->SetHatch( outline_hatch, - Mils2iu( zone->m_Poly->GetDefaultHatchPitchMils() ) ); + Mils2iu( zone->m_Poly->GetDefaultHatchPitchMils() ), + true ); // clearances, etc. zone->SetArcSegCount( 32 ); // @todo: should be a constructor default? diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 77618154a4..65ed37e26e 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2109,7 +2109,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() { auto_ptr zc( new ZONE_CONTAINER( m_board ) ); - int outline_hatch = CPolyLine::NO_HATCH; + CPolyLine::HATCH_STYLE outline_hatch = CPolyLine::NO_HATCH; bool sawCorner = false; char buf[1024]; @@ -2133,7 +2133,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() sawCorner = true; if( flag ) - zc->m_Poly->Close(); + zc->m_Poly->CloseLastContour(); } else if( TESTLINE( "ZInfo" ) ) // general info found @@ -2350,9 +2350,11 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() zc->SetNet( 0 ); } + // Hatch here, after outlines corners are read // Set hatch here, after outlines corners are read zc->m_Poly->SetHatch( outline_hatch, - Mils2iu( zc->m_Poly->GetDefaultHatchPitchMils() ) ); + Mils2iu( CPolyLine::GetDefaultHatchPitchMils() ), + true ); m_board->Add( zc.release() ); } diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index babb050af0..a7f164beb7 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2292,8 +2292,8 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as ZONE_CONTAINER." ) ); - int hatchStyle = CPolyLine::NO_HATCH; // Fix compile warning - int hatchPitch = 0; // Fix compile warning + CPolyLine::HATCH_STYLE hatchStyle = CPolyLine::NO_HATCH; + int hatchPitch = Mils2iu( CPolyLine::GetDefaultHatchPitchMils() ); wxPoint pt; T token; @@ -2587,7 +2587,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) } // Set hatch here, after outlines corners are read - zone->m_Poly->SetHatch( hatchStyle, hatchPitch ); + zone->m_Poly->SetHatch( hatchStyle, hatchPitch, true ); } if( pts.size() ) diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 12462939a7..b69079fd16 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -679,8 +679,12 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) if( !Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) ) { // Ok, we can add a new corner + if( m_canvas->IsMouseCaptured() ) + m_canvas->CallMouseCapture( DC, wxPoint(0,0), false ); zone->AppendCorner( GetScreen()->GetCrossHairPosition() ); SetCurItem( zone ); // calls DisplayInfo(). + if( m_canvas->IsMouseCaptured() ) + m_canvas->CallMouseCapture( DC, wxPoint(0,0), false ); } } } @@ -738,7 +742,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC ) // Put new zone in list if( !s_CurrentZone ) { - zone->m_Poly->Close(); // Close the current corner list + zone->m_Poly->CloseLastContour(); // Close the current corner list GetBoard()->Add( zone ); GetBoard()->m_CurrentZoneContour = NULL; @@ -753,7 +757,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC ) s_CurrentZone->AppendCorner( zone->GetCornerPosition( ii ) ); } - s_CurrentZone->m_Poly->Close(); // Close the current corner list + s_CurrentZone->m_Poly->CloseLastContour(); // Close the current corner list zone->RemoveAllContours(); // All corners are copied in s_CurrentZone. Free corner list. zone = s_CurrentZone; } diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index 02a6652739..2e6d078bac 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -41,6 +41,7 @@ #include #include +#include static bool bDontShowSelfIntersectionArcsWarning; @@ -311,19 +312,15 @@ int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, str += wxT( "This may result in splitting the area.\n" ); str += wxT( "If the area is complex, this may take a few seconds." ); wxMessageBox( str ); - -// bDontShowSelfIntersectionWarning = dlg.bDontShowBoxState; } } -//** TODO test for cutouts outside of area -//** if( test == 1 ) { std::vector* pa = new std::vector; curr_polygon->UnHatch(); int n_poly = aCurrArea->m_Poly->NormalizeAreaOutlines( pa, bRetainArcs ); - // i.e if clipping has created some polygons, we must add these new copper areas. + // If clipping has created some polygons, we must add these new copper areas. if( n_poly > 1 ) { ZONE_CONTAINER* NewArea; @@ -803,10 +800,10 @@ int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_r } // polygons intersect, combine them -// std::vector arc_array1; -// std::vector arc_array2; - bool keep_area_to_combine = false; // TODO test if areas intersect + // TODO: test here if areas intersect and combine only if so +#if 0 + // do not set to 1 (not fully working): only for me (JP. Charras) until this code is finished KI_POLYGON_WITH_HOLES areaRefPoly; KI_POLYGON_WITH_HOLES areaToMergePoly; CopyPolysListToKiPolygonWithHole( area_ref->m_Poly->m_CornersList, areaRefPoly ); @@ -814,14 +811,12 @@ int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_r KI_POLYGON_WITH_HOLES_SET mergedOutlines; mergedOutlines.push_back( areaRefPoly ); - mergedOutlines += areaToMergePoly; + mergedOutlines |= areaToMergePoly; - // We should have only one polygon with holes in mergedOutlines - // or the 2 initial outlines do not intersect - if( mergedOutlines.size() > 1 ) - return 0; + // We can have more than one polygon with holes in mergedOutlines + // depending on the complexity of outlines - areaRefPoly = mergedOutlines[0]; + areaRefPoly = mergedOutlines[0]; // TODO: read and create all created polygons area_ref->m_Poly->RemoveAllContours(); KI_POLYGON_WITH_HOLES::iterator_type corner = areaRefPoly.begin(); @@ -833,7 +828,7 @@ int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_r area_ref->m_Poly->AppendCorner( corner->x(), corner->y() ); } - area_ref->m_Poly->Close(); + area_ref->m_Poly->CloseLastContour(); // add holes (set of polygons) KI_POLYGON_WITH_HOLES::iterator_holes_type hole = areaRefPoly.begin_holes(); @@ -846,17 +841,83 @@ int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_r area_ref->m_Poly->AppendCorner( hole_corner->x(), hole_corner->y() ); hole_corner++; } - area_ref->m_Poly->Close(); + area_ref->m_Poly->CloseLastContour(); hole++; } +#else + void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); + Bool_Engine* booleng = new Bool_Engine(); + armBoolEng( booleng ); + area_ref->m_Poly->AddPolygonsToBoolEng( booleng, GROUP_A ); + area_to_combine->m_Poly->AddPolygonsToBoolEng(booleng, GROUP_B ); + booleng->Do_Operation( BOOL_OR ); - if( !keep_area_to_combine ) - RemoveArea( aDeletedList, area_to_combine ); + // create area with external contour: Recreate only area edges, NOT holes + if( booleng->StartPolygonGet() ) + { + if( booleng->GetPolygonPointEdgeType() == KB_INSIDE_EDGE ) + { + DisplayError( NULL, wxT( "BOARD::CombineAreas() error: unexpected hole descriptor" ) ); + } + + area_ref->m_Poly->RemoveAllContours(); + + // foreach point in the polygon + bool first = true; + + while( booleng->PolygonHasMorePoints() ) + { + int x = (int) booleng->GetPolygonXPoint(); + int y = (int) booleng->GetPolygonYPoint(); + + if( first ) + { + first = false; + area_ref->m_Poly->Start( area_ref->GetLayer( + ), x, y, area_ref->m_Poly->GetHatchStyle() ); + } + else + { + area_ref->m_Poly->AppendCorner( x, y ); + } + } + + booleng->EndPolygonGet(); + area_ref->m_Poly->CloseLastContour(); + } + + // add holes + bool show_error = true; + + while( booleng->StartPolygonGet() ) + { + // we expect all vertex are holes inside the main outline + if( booleng->GetPolygonPointEdgeType() != KB_INSIDE_EDGE ) + { + if( show_error ) // show this error only once, if happens + DisplayError( NULL, + wxT( "BOARD::CombineAreas() error: unexpected outside contour descriptor" ) ); + + show_error = false; + continue; + } + + while( booleng->PolygonHasMorePoints() ) + { + int x = (int) booleng->GetPolygonXPoint(); + int y = (int) booleng->GetPolygonYPoint(); + area_ref->m_Poly->AppendCorner( x, y ); + } + + area_ref->m_Poly->CloseLastContour(); + booleng->EndPolygonGet(); + } +#endif + + RemoveArea( aDeletedList, area_to_combine ); area_ref->utility = 1; -// area_ref->m_Poly->RestoreArcs( &arc_array1 ); -// area_ref->m_Poly->RestoreArcs( &arc_array2 ); area_ref->m_Poly->Hatch(); return 1; @@ -917,6 +978,11 @@ int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_E // ZONE_CONTAINER::GetClearance(). int zone2zoneClearance = Area_Ref->GetClearance( area_to_test ); + // Keepout areas have no clearance, so set zone2zoneClearance to 1 + // ( zone2zoneClearance = 0 can create problems in test functions) + if( Area_Ref->GetIsKeepout() ) + zone2zoneClearance = 1; + // test for some corners of Area_Ref inside area_to_test for( int ic = 0; ic < refSmoothedPoly->GetNumCorners(); ic++ ) { @@ -1114,6 +1180,11 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) if( area_to_test->GetIsKeepout() != aArea->GetIsKeepout() ) continue; + // For keepout, there is no clearance, so use a minimal value for it + // use 1, not 0 as value to avoid some issues in tests + if( area_to_test->GetIsKeepout() ) + zone_clearance = 1; + // test for ending line inside area_to_test if( area_to_test->m_Poly->TestPointInside( end.x, end.y ) ) { @@ -1159,7 +1230,7 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) 0, ax1, ay1, ax2, ay2, astyle, 0, - 0, + zone_clearance, &x, &y ); if( d < zone_clearance ) diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 57d6190edf..a19ac666ab 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -13,11 +13,13 @@ #include #include #include +#include CPolyLine::CPolyLine() { m_hatchStyle = NO_HATCH; m_hatchPitch = 0; + m_layer = 0; m_width = 0; m_utility = 0; m_Kbool_Poly_Engine = NULL; @@ -44,7 +46,7 @@ CPolyLine::~CPolyLine() * false: holes are not linked: in this mode contours are added clockwise * and polygons added counter clockwise are holes (default) */ -static void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); +void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); /** * Function NormalizeWithKbool @@ -128,16 +130,19 @@ int CPolyLine::NormalizeWithKbool( std::vector* aExtraPolyList, bool } m_Kbool_Poly_Engine->EndPolygonGet(); - Close(); + CloseLastContour(); n_ext_cont++; } - else if( aExtraPolyList ) // a new outside contour is found: create a new CPolyLine + else if( aExtraPolyList ) // a new outside contour is found: create a new CPolyLine { - polyline = new CPolyLine; // create new poly - aExtraPolyList->push_back( polyline ); // put it in array + polyline = new CPolyLine; + polyline->SetLayer( GetLayer() ); + polyline->SetHatchStyle( GetHatchStyle() ); + polyline->SetHatchPitch( GetHatchPitch() ); + aExtraPolyList->push_back( polyline ); // put it in array bool first = true; - while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // read next external contour + while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // read next external contour { int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); @@ -152,7 +157,7 @@ int CPolyLine::NormalizeWithKbool( std::vector* aExtraPolyList, bool } m_Kbool_Poly_Engine->EndPolygonGet(); - polyline->Close( STRAIGHT, false ); + polyline->CloseLastContour(); n_ext_cont++; } } @@ -201,7 +206,7 @@ int CPolyLine::NormalizeWithKbool( std::vector* aExtraPolyList, bool polyline->AppendCorner( x, y, STRAIGHT, false ); } - polyline->Close( STRAIGHT, false ); + polyline->CloseLastContour(); } } @@ -219,6 +224,42 @@ int CPolyLine::NormalizeWithKbool( std::vector* aExtraPolyList, bool } +/** + * Function AddPolygonsToBoolEng + * Add a CPolyLine to a kbool engine, preparing a boolean op between polygons + * @param aBooleng : pointer on a bool engine (handle a set of polygons) + * @param aGroup : group to fill (aGroup = GROUP_A or GROUP_B) operations are made between GROUP_A and GROUP_B + */ +int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng, GroupType aGroup ) +{ + int count = 0; + + /* Convert the current polyline contour to a kbool polygon: */ + MakeKboolPoly(); + + /* add the resulting kbool set of polygons to the current kcool engine */ + while( m_Kbool_Poly_Engine->StartPolygonGet() ) + { + if( aBooleng->StartPolygonAdd( GROUP_A ) ) + { + while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) + { + int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); + int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); + aBooleng->AddPoint( x, y ); + count++; + } + + aBooleng->EndPolygonAdd(); + } + m_Kbool_Poly_Engine->EndPolygonGet(); + } + + delete m_Kbool_Poly_Engine; + m_Kbool_Poly_Engine = NULL; + + return count; +} /** * Function MakeKboolPoly * fill a kbool engine with a closed polyline contour @@ -247,13 +288,32 @@ int CPolyLine::MakeKboolPoly( std::vector* arc_array ) int iarc = 0; - for( int icont = 0; icont<=last_contour; icont++ ) + for( int icont = 0; icont <= last_contour; icont++ ) { // Fill a kbool engine for this contour, // and combine it with previous contours Bool_Engine* booleng = new Bool_Engine(); armBoolEng( booleng, false ); + if( m_Kbool_Poly_Engine ) // a previous contour exists. Put it in new engine + { + while( m_Kbool_Poly_Engine->StartPolygonGet() ) + { + if( booleng->StartPolygonAdd( GROUP_A ) ) + { + while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) + { + int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); + int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); + booleng->AddPoint( x, y ); + } + + booleng->EndPolygonAdd(); + } + m_Kbool_Poly_Engine->EndPolygonGet(); + } + } + // first, calculate number of vertices in contour int n_vertices = 0; int ic_st = GetContourStart( icont ); @@ -735,7 +795,7 @@ int CPolyLine::RestoreArcs( std::vector* arc_array, std::vectorAppendCorner( x1 + nx, y1 + ny ); } - newPoly->Close(); + newPoly->CloseLastContour(); } return newPoly; @@ -1072,7 +1122,7 @@ CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments ) } } - newPoly->Close(); + newPoly->CloseLastContour(); } return newPoly; @@ -1632,11 +1682,13 @@ void CPolyLine::SetEndContour( int ic, bool end_contour ) m_CornersList[ic].end_contour = end_contour; } - +/* + * AppendArc adds segments to current contour to approximate the given arc + */ void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ) { // get radius - double r = sqrt( (double) (xi - xc) * (xi - xc) + (double) (yi - yc) * (yi - yc) ); + double radius = hypot( (double) (xi - xc), (double) (yi - yc) ); // get angles of start and finish double th_i = atan2( (double) (yi - yc), (double) (xi - xc) ); @@ -1645,15 +1697,15 @@ void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int n double theta = th_i; // generate arc - for( int ic = 0; ic - class CArc { public: @@ -107,7 +104,7 @@ class CPolyLine { public: enum m_SideStyle { STRAIGHT, ARC_CW, ARC_CCW }; // side styles - enum hatch_style { NO_HATCH, DIAGONAL_FULL, DIAGONAL_EDGE }; // hatch styles + enum HATCH_STYLE { NO_HATCH, DIAGONAL_FULL, DIAGONAL_EDGE }; // hatch styles // constructors/destructor CPolyLine(); @@ -119,7 +116,7 @@ public: void InsertCorner( int ic, int x, int y ); void DeleteCorner( int ic, bool bDraw = false ); void MoveCorner( int ic, int x, int y ); - void Close( int style = STRAIGHT, bool bDraw = false ); + void CloseLastContour(); void RemoveContour( int icont ); /** @@ -155,6 +152,11 @@ public: void Copy( CPolyLine* src ); bool TestPointInside( int x, int y ); bool IsCutoutContour( int icont ); + + /** + * Function AppendArc. + * Adds segments to current contour to approximate the given arc + */ void AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ); // access functions @@ -181,14 +183,15 @@ public: int GetSideStyle( int is ); int GetHatchPitch() { return m_hatchPitch; } - int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils + static int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils - enum hatch_style GetHatchStyle() { return m_hatchStyle; } - void SetHatch( int hatch, int pitch ) + enum HATCH_STYLE GetHatchStyle() { return m_hatchStyle; } + void SetHatch( int aHatchStyle, int aHatchPitch, bool aRebuildHatch ) { - SetHatchPitch( pitch ); - m_hatchStyle = (enum hatch_style) hatch; - Hatch(); + SetHatchPitch( aHatchPitch ); + m_hatchStyle = (enum HATCH_STYLE) aHatchStyle; + if( aRebuildHatch ) + Hatch(); } void SetX( int ic, int x ); @@ -196,7 +199,7 @@ public: void SetEndContour( int ic, bool end_contour ); void SetSideStyle( int is, int style ); - void SetHatchStyle( enum hatch_style style ) + void SetHatchStyle( enum HATCH_STYLE style ) { m_hatchStyle = style; } @@ -210,6 +213,14 @@ public: // KBOOL functions + /** + * Function AddPolygonsToBoolEng + * Add a CPolyLine to a kbool engine, preparing a boolean op between polygons + * @param aBooleng : pointer on a bool engine (handle a set of polygons) + * @param aGroup : group to fill (aGroup = GROUP_A or GROUP_B) operations are made between GROUP_A and GROUP_B + */ + int AddPolygonsToBoolEng( Bool_Engine* aBooleng, GroupType aGroup ); + /** * Function MakeKboolPoly * fill a kbool engine with a closed polyline contour @@ -261,7 +272,7 @@ public: private: int m_layer; // layer to draw on int m_width; // lines width when drawing. Provided but not really used - enum hatch_style m_hatchStyle; // hatch style, see enum above + enum HATCH_STYLE m_hatchStyle; // hatch style, see enum above int m_hatchPitch; // for DIAGONAL_EDGE hatched outlines, basic distance between 2 hatch lines // and the len of eacvh segment // for DIAGONAL_FULL, the pitch is twice this value diff --git a/polygon/math_for_graphics.cpp b/polygon/math_for_graphics.cpp index 8b3e44968c..de9a802817 100644 --- a/polygon/math_for_graphics.cpp +++ b/polygon/math_for_graphics.cpp @@ -9,9 +9,23 @@ #include #include +#include #define NM_PER_MIL 25400 +typedef struct PointTag +{ + double X,Y; +} PointT; + +typedef struct EllipseTag +{ + PointT Center; /* ellipse center */ + double xrad, yrad; // radii on x and y + double theta1, theta2; // start and end angle for arc +} EllipseKH; + + double Distance( double x1, double y1, double x2, double y2 ) { double dx = x1 - x2; @@ -21,6 +35,13 @@ double Distance( double x1, double y1, double x2, double y2 ) } +static int GetArcIntersections( EllipseKH * el1, EllipseKH * el2, + double * x1=NULL, double * y1=NULL, + double * x2=NULL, double * y2=NULL ); +static bool InRange( double x, double xi, double xf ); + + + /** * Function TestLineHit * test for hit on line segment i.e. a point within a given distance from segment @@ -862,26 +883,26 @@ bool FindLineEllipseIntersections( double a, double b, double c, double d, doubl // Get clearance between 2 segments // Returns point in segment closest to other segment in x, y -// in clearance > max_cl, just returns max_cl and doesn't return x,y +// in clearance > max_cl, just returns max_cl+1 and doesn't return x,y // int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1, int x2i, int y2i, int x2f, int y2f, int style2, int w2, int max_cl, int* x, int* y ) { // check clearance between bounding rectangles - int test = max_cl + w1 / 2 + w2 / 2; + int min_dist = max_cl + ( (w1 + w2) / 2 ); - if( min( x1i, x1f ) - max( x2i, x2f ) > test ) - return max_cl; + if( min( x1i, x1f ) - max( x2i, x2f ) > min_dist ) + return max_cl+1; - if( min( x2i, x2f ) - max( x1i, x1f ) > test ) - return max_cl; + if( min( x2i, x2f ) - max( x1i, x1f ) > min_dist ) + return max_cl+1; - if( min( y1i, y1f ) - max( y2i, y2f ) > test ) - return max_cl; + if( min( y1i, y1f ) - max( y2i, y2f ) > min_dist ) + return max_cl+1; - if( min( y2i, y2f ) - max( y1i, y1f ) > test ) - return max_cl; + if( min( y2i, y2f ) - max( y1i, y1f ) > min_dist ) + return max_cl+1; if( style1 == CPolyLine::STRAIGHT && style1 == CPolyLine::STRAIGHT ) { @@ -890,7 +911,9 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, double dd; TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f, x2i, y2i, x2f, y2f, &xx, &yy, &dd ); - int d = max( 0, (int) dd - w1 / 2 - w2 / 2 ); + int d = (int) dd - ( (w1 + w2) / 2 ); + if( d < 0 ) + d = 0; if( x ) *x = xx; @@ -905,10 +928,10 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, // see if segments intersect double xr[2]; double yr[2]; - test = + int count = FindSegmentIntersections( x1i, y1i, x1f, y1f, style1, x2i, y2i, x2f, y2f, style2, xr, yr ); - if( test ) + if( count ) { if( x ) *x = (int) xr[0]; diff --git a/polygon/math_for_graphics.h b/polygon/math_for_graphics.h index 5119cd7973..a9b1cf2b68 100644 --- a/polygon/math_for_graphics.h +++ b/polygon/math_for_graphics.h @@ -1,22 +1,5 @@ // math stuff for graphics, from FreePCB -#ifndef abs -#define abs(x) (((x) >=0) ? (x) : (-(x))) -#endif - - -typedef struct PointTag -{ - double X,Y; -} PointT; - -typedef struct EllipseTag -{ - PointT Center; /* ellipse center */ - double xrad, yrad; // radii on x and y - double theta1, theta2; // start and end angle for arc -} EllipseKH; - // math stuff for graphics bool Quadratic( double a, double b, double c, double *x1, double *x2 ); @@ -70,11 +53,5 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf ); double GetPointToLineDistance( double a, double b, int x, int y, double * xp=NULL, double * yp=NULL ); -bool InRange( double x, double xi, double xf ); double Distance( double x1, double y1, double x2, double y2 ); - -int GetArcIntersections( EllipseKH * el1, EllipseKH * el2, - double * x1=NULL, double * y1=NULL, - double * x2=NULL, double * y2=NULL ); -