From 99b90d2fa35689201bb4908c41caf6e2e5f72f73 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Wed, 25 Jul 2012 20:46:25 +0200 Subject: [PATCH] More work on a better support of polygons in Kicad (code cleaning). --- eeschema/lib_arc.cpp | 12 +- eeschema/lib_arc.h | 10 +- pcbnew/autorouter/solve.cpp | 4 +- pcbnew/class_board.cpp | 4 +- pcbnew/class_track.cpp | 2 +- pcbnew/class_zone.h | 2 +- pcbnew/clean.cpp | 35 +- pcbnew/editrack.cpp | 4 +- pcbnew/move_or_drag_track.cpp | 8 +- pcbnew/pcbnew.h | 4 +- pcbnew/zone_filling_algorithm.cpp | 41 +- ...nvert_brd_items_to_polygons_with_Boost.cpp | 4 - pcbnew/zones_test_and_combine_areas.cpp | 53 - polygon/PolyLine.cpp | 1004 ++++++++++------- polygon/PolyLine.h | 227 ++-- {pcbnew => polygon}/polygons_defs.h | 0 16 files changed, 745 insertions(+), 669 deletions(-) rename {pcbnew => polygon}/polygons_defs.h (100%) diff --git a/eeschema/lib_arc.cpp b/eeschema/lib_arc.cpp index f1fcb5f319..489b7a07eb 100644 --- a/eeschema/lib_arc.cpp +++ b/eeschema/lib_arc.cpp @@ -561,15 +561,15 @@ void LIB_ARC::BeginEdit( int aEditMode, const wxPoint aPosition ) // Drag either the start, end point or the outline if( HitTestPoints( m_ArcStart, aPosition, MINIMUM_SELECTION_DISTANCE ) ) { - m_editSelectPoint = START; + m_editSelectPoint = ARC_STATUS_START; } else if( HitTestPoints( m_ArcEnd, aPosition, MINIMUM_SELECTION_DISTANCE ) ) { - m_editSelectPoint = END; + m_editSelectPoint = ARC_STATUS_END; } else { - m_editSelectPoint = OUTLINE; + m_editSelectPoint = ARC_STATUS_OUTLINE; } m_editState = 0; @@ -619,12 +619,12 @@ void LIB_ARC::calcEdit( const wxPoint& aPosition ) wxPoint newCenterPoint, startPos, endPos; // Choose the point of the arc to be adjusted - if( m_editSelectPoint == START ) + if( m_editSelectPoint == ARC_STATUS_START ) { startPos = aPosition; endPos = m_ArcEnd; } - else if( m_editSelectPoint == END ) + else if( m_editSelectPoint == ARC_STATUS_END ) { endPos = aPosition; startPos = m_ArcStart; @@ -658,7 +658,7 @@ void LIB_ARC::calcEdit( const wxPoint& aPosition ) newCenterPoint = m_Pos; } - if( m_editSelectPoint == START || m_editSelectPoint == END ) + if( m_editSelectPoint == ARC_STATUS_START || m_editSelectPoint == ARC_STATUS_END ) { // Compute the new center point when the start/end points are modified wxPoint middlePoint = wxPoint( (startPos.x + endPos.x) / 2, diff --git a/eeschema/lib_arc.h b/eeschema/lib_arc.h index ab179a98ef..139c55335a 100644 --- a/eeschema/lib_arc.h +++ b/eeschema/lib_arc.h @@ -37,15 +37,15 @@ class TRANSFORM; class LIB_ARC : public LIB_ITEM { - enum SELECT_T + enum SELECT_T // When creating an arc: status of arc { - START, - END, - OUTLINE, + ARC_STATUS_START, + ARC_STATUS_END, + ARC_STATUS_OUTLINE, }; int m_Radius; - int m_t1; /* First radius angle of the arc in 0.1 degrees. */ + int m_t1; // First radius angle of the arc in 0.1 degrees. int m_t2; /* Second radius angle of the arc in 0.1 degrees. */ wxPoint m_ArcStart; wxPoint m_ArcEnd; /* Arc end position. */ diff --git a/pcbnew/autorouter/solve.cpp b/pcbnew/autorouter/solve.cpp index c3c00a2c0a..17f9ae35f6 100644 --- a/pcbnew/autorouter/solve.cpp +++ b/pcbnew/autorouter/solve.cpp @@ -1302,12 +1302,12 @@ static void AddNewTrace( PCB_EDIT_FRAME* pcbframe, wxDC* DC ) g_CurrentTrackList.PushBack( newTrack ); } - g_FirstTrackSegment->start = pcbframe->GetBoard()->GetPad( g_FirstTrackSegment, START ); + g_FirstTrackSegment->start = pcbframe->GetBoard()->GetPad( g_FirstTrackSegment, FLG_START ); if( g_FirstTrackSegment->start ) g_FirstTrackSegment->SetState( BEGIN_ONPAD, ON ); - g_CurrentTrackSegment->end = pcbframe->GetBoard()->GetPad( g_CurrentTrackSegment, END ); + g_CurrentTrackSegment->end = pcbframe->GetBoard()->GetPad( g_CurrentTrackSegment, FLG_END ); if( g_CurrentTrackSegment->end ) g_CurrentTrackSegment->SetState( END_ONPAD, ON ); diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index a495faf219..2da338f002 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -1681,7 +1681,7 @@ D_PAD* BOARD::GetPad( TRACK* aTrace, int aEndPoint ) int aLayerMask = GetLayerMask( aTrace->GetLayer() ); - if( aEndPoint == START ) + if( aEndPoint == FLG_START ) { aPosition = aTrace->m_Start; } @@ -2271,7 +2271,7 @@ TRACK* BOARD::CreateLockPoint( wxPoint& aPosition, TRACK* aSegment, PICKED_ITEMS aSegment->end = newTrack; aSegment->SetState( END_ONPAD, OFF ); - D_PAD * pad = GetPad( newTrack, START ); + D_PAD * pad = GetPad( newTrack, FLG_START ); if ( pad ) { diff --git a/pcbnew/class_track.cpp b/pcbnew/class_track.cpp index 788072f471..120a64e398 100644 --- a/pcbnew/class_track.cpp +++ b/pcbnew/class_track.cpp @@ -1282,7 +1282,7 @@ TRACK* TRACK::GetTrace( TRACK* aStartTrace, TRACK* aEndTrace, int aEndPoint ) int ii; int max_dist; - if( aEndPoint == START ) + if( aEndPoint == FLG_START ) position = m_Start; else position = m_End; diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index e6e33cc06b..048125c9c2 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -613,7 +613,7 @@ private: /* set of filled polygons used to draw a zone as a filled area. * from outlines (m_Poly) but unlike m_Poly these filled polygons have no hole - * (they are* all in one piece) In very simple cases m_FilledPolysList is same + * (they are all in one piece) In very simple cases m_FilledPolysList is same * as m_Poly. In less simple cases (when m_Poly has holes) m_FilledPolysList is * a polygon equivalent to m_Poly, without holes but with extra outline segment * connecting "holes" with external main outline. In complex cases an outline diff --git a/pcbnew/clean.cpp b/pcbnew/clean.cpp index 4f22db1182..b93b88081f 100644 --- a/pcbnew/clean.cpp +++ b/pcbnew/clean.cpp @@ -272,7 +272,7 @@ static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* aFrame ) if( (type_end & START_ON_PAD ) == 0 ) { - other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, START ); + other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_START ); if( other == NULL ) // Test a connection to zones { @@ -306,7 +306,7 @@ static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* aFrame ) segment->SetState( BUSY, ON ); SEGVIA* via = (SEGVIA*) other; - other = via->GetTrace( aFrame->GetBoard()->m_Track, NULL, START ); + other = via->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_START ); if( other == NULL ) { @@ -327,7 +327,7 @@ static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* aFrame ) // if not connected to a pad, test if segment's END is connected to another track if( (type_end & END_ON_PAD ) == 0 ) { - other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, END ); + other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_END ); if( other == NULL ) // Test a connection to zones { @@ -362,7 +362,7 @@ static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* aFrame ) segment->SetState( BUSY, ON ); SEGVIA* via = (SEGVIA*) other; - other = via->GetTrace( aFrame->GetBoard()->m_Track, NULL, END ); + other = via->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_END ); if( other == NULL ) { @@ -486,7 +486,7 @@ static void clean_segments( PCB_EDIT_FRAME* aFrame ) // search for a possible point that connects on the START point of the segment for( segStart = segment->Next(); ; ) { - segStart = segment->GetTrace( segStart, NULL, START ); + segStart = segment->GetTrace( segStart, NULL, FLG_START ); if( segStart ) { @@ -500,7 +500,7 @@ static void clean_segments( PCB_EDIT_FRAME* aFrame ) // We must have only one segment connected segStart->SetState( BUSY, ON ); - other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, START ); + other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_START ); segStart->SetState( BUSY, OFF ); if( other == NULL ) @@ -514,7 +514,7 @@ static void clean_segments( PCB_EDIT_FRAME* aFrame ) if( flag ) // We have the starting point of the segment is connected to an other segment { segDelete = MergeColinearSegmentIfPossible( aFrame->GetBoard(), segment, segStart, - START ); + FLG_START ); if( segDelete ) { @@ -526,7 +526,7 @@ static void clean_segments( PCB_EDIT_FRAME* aFrame ) // search for a possible point that connects on the END point of the segment: for( segEnd = segment->Next(); ; ) { - segEnd = segment->GetTrace( segEnd, NULL, END ); + segEnd = segment->GetTrace( segEnd, NULL, FLG_END ); if( segEnd ) { @@ -538,7 +538,7 @@ static void clean_segments( PCB_EDIT_FRAME* aFrame ) // We must have only one segment connected segEnd->SetState( BUSY, ON ); - other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, END ); + other = segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_END ); segEnd->SetState( BUSY, OFF ); if( other == NULL ) @@ -554,7 +554,8 @@ static void clean_segments( PCB_EDIT_FRAME* aFrame ) if( flag & 2 ) // We have the ending point of the segment is connected to an other segment { - segDelete = MergeColinearSegmentIfPossible( aFrame->GetBoard(), segment, segEnd, END ); + segDelete = MergeColinearSegmentIfPossible( aFrame->GetBoard(), + segment, segEnd, FLG_END ); if( segDelete ) { @@ -643,7 +644,7 @@ TRACK* MergeColinearSegmentIfPossible( BOARD* aPcb, TRACK* aTrackRef, TRACK* aCa * (this function) is called when there is only 2 connected segments, *and if this point is not on a pad, it can be removed and the 2 segments will be merged */ - if( aEndType == START ) + if( aEndType == FLG_START ) { // We must not have a pad, which is a always terminal point for a track if( aPcb->GetPadFast( aTrackRef->m_Start, aTrackRef->ReturnMaskLayer() ) ) @@ -712,7 +713,7 @@ bool PCB_EDIT_FRAME::RemoveMisConnectedTracks() } else { - other = segment->GetTrace( GetBoard()->m_Track, NULL, START ); + other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_START ); if( other ) net_code_s = other->GetNet(); @@ -730,7 +731,7 @@ bool PCB_EDIT_FRAME::RemoveMisConnectedTracks() } else { - other = segment->GetTrace( GetBoard()->m_Track, NULL, END ); + other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_END ); if( other ) net_code_e = other->GetNet(); @@ -871,14 +872,14 @@ void ConnectDanglingEndToPad( PCB_EDIT_FRAME* aFrame ) if( aFrame->GetCanvas()->GetAbortRequest() ) return; - pad = aFrame->GetBoard()->GetPad( segment, START ); + pad = aFrame->GetBoard()->GetPad( segment, FLG_START ); if( pad ) { // test if the track start point is not exactly starting on the pad if( segment->m_Start != pad->GetPosition() ) { - if( segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, START ) == NULL ) + if( segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_START ) == NULL ) { TRACK* newTrack = (TRACK*) segment->Clone(); @@ -893,14 +894,14 @@ void ConnectDanglingEndToPad( PCB_EDIT_FRAME* aFrame ) } } - pad = aFrame->GetBoard()->GetPad( segment, END ); + pad = aFrame->GetBoard()->GetPad( segment, FLG_END ); if( pad ) { // test if the track end point is not exactly on the pad if( segment->m_End != pad->GetPosition() ) { - if( segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, END ) == NULL ) + if( segment->GetTrace( aFrame->GetBoard()->m_Track, NULL, FLG_END ) == NULL ) { TRACK* newTrack = (TRACK*)segment->Clone(); diff --git a/pcbnew/editrack.cpp b/pcbnew/editrack.cpp index 472e1ca18d..b43eeacf44 100644 --- a/pcbnew/editrack.cpp +++ b/pcbnew/editrack.cpp @@ -263,7 +263,7 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC ) newTrack->SetState( BEGIN_ONPAD | END_ONPAD, OFF ); - D_PAD* pad = GetBoard()->GetPad( previousTrack, END ); + D_PAD* pad = GetBoard()->GetPad( previousTrack, FLG_END ); if( pad ) { @@ -1042,7 +1042,7 @@ void DeleteNullTrackSegments( BOARD* pcb, DLIST& aTrackList ) while( track != NULL ) { TRACK* next_track = track->Next(); - LockPoint = pcb->GetPad( track, END ); + LockPoint = pcb->GetPad( track, FLG_END ); if( LockPoint ) { diff --git a/pcbnew/move_or_drag_track.cpp b/pcbnew/move_or_drag_track.cpp index b72387ccfe..c58c4fdbc4 100644 --- a/pcbnew/move_or_drag_track.cpp +++ b/pcbnew/move_or_drag_track.cpp @@ -887,7 +887,7 @@ void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC* DC s_StartSegmentPresent = s_EndSegmentPresent = true; if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) ) - TrackToStartPoint = track->GetTrace( GetBoard()->m_Track, NULL, START ); + TrackToStartPoint = track->GetTrace( GetBoard()->m_Track, NULL, FLG_START ); // Test if more than one segment is connected to this point if( TrackToStartPoint ) @@ -895,14 +895,14 @@ void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC* DC TrackToStartPoint->SetState( BUSY, ON ); if( ( TrackToStartPoint->Type() == PCB_VIA_T ) - || track->GetTrace( GetBoard()->m_Track, NULL, START ) ) + || track->GetTrace( GetBoard()->m_Track, NULL, FLG_START ) ) error = true; TrackToStartPoint->SetState( BUSY, OFF ); } if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) ) - TrackToEndPoint = track->GetTrace( GetBoard()->m_Track, NULL, END ); + TrackToEndPoint = track->GetTrace( GetBoard()->m_Track, NULL, FLG_END ); // Test if more than one segment is connected to this point if( TrackToEndPoint ) @@ -910,7 +910,7 @@ void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC* DC TrackToEndPoint->SetState( BUSY, ON ); if( (TrackToEndPoint->Type() == PCB_VIA_T) - || track->GetTrace( GetBoard()->m_Track, NULL, END ) ) + || track->GetTrace( GetBoard()->m_Track, NULL, FLG_END ) ) error = true; TrackToEndPoint->SetState( BUSY, OFF ); diff --git a/pcbnew/pcbnew.h b/pcbnew/pcbnew.h index bc5df44334..78624ab4fd 100644 --- a/pcbnew/pcbnew.h +++ b/pcbnew/pcbnew.h @@ -25,8 +25,8 @@ #define VISIBLE_ONLY (1 << 3) ///< if module not on a visible layer, do not select -#define START 0 /* Flag used in locate routines */ -#define END 1 +#define FLG_START 0 // Flag used in locate routines +#define FLG_END 1 // Flag used in locate routines #define DIM_ANCRE_MODULE 3 /* Anchor size (footprint center) */ #define DIM_ANCRE_TEXTE 2 /* Anchor size (Text center) */ diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index e829c37f96..0a29804f28 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -89,39 +89,12 @@ int ZONE_CONTAINER::BuildFilledPolysListData( BOARD* aPcb, std::vector break; } - m_smoothedPoly->MakeKboolPoly( -1, -1, NULL, true ); - int count = 0; - while( m_smoothedPoly->GetKboolEngine()->StartPolygonGet() ) - { - CPolyPt corner( 0, 0, false ); - while( m_smoothedPoly->GetKboolEngine()->PolygonHasMorePoints() ) - { - corner.x = (int) m_smoothedPoly->GetKboolEngine()->GetPolygonXPoint(); - corner.y = (int) m_smoothedPoly->GetKboolEngine()->GetPolygonYPoint(); - corner.end_contour = false; - if( aCornerBuffer ) - aCornerBuffer->push_back( corner ); - else - m_FilledPolysList.push_back( corner ); - count++; - } - - corner.end_contour = true; - if( aCornerBuffer ) - { - aCornerBuffer->pop_back(); - aCornerBuffer->push_back( corner ); - } - else - { - m_FilledPolysList.pop_back(); - m_FilledPolysList.push_back( corner ); - } - m_smoothedPoly->GetKboolEngine()->EndPolygonGet(); - } - - m_smoothedPoly->FreeKboolEngine(); - + if( aCornerBuffer ) + ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, + *aCornerBuffer ); + else + ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, + m_FilledPolysList ); /* For copper layers, we now must add holes in the Polygon list. * holes are pads and tracks with their clearance area */ @@ -134,7 +107,7 @@ int ZONE_CONTAINER::BuildFilledPolysListData( BOARD* aPcb, std::vector Fill_Zone_Areas_With_Segments( ); } - return count; + return 1; } // Sort function to build filled zones diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp index 48e1e418b5..85d9012b4d 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp @@ -524,10 +524,6 @@ int CopyPolygonsFromKiPolygonListToFilledPolysList( ZONE_CONTAINER* aZone, corner.x = point.x(); corner.y = point.y(); corner.end_contour = false; - - // Flag this corner if starting a hole connection segment: - // This is used by draw functions to draw only useful segments (and not extra segments) - // corner.utility = (aBoolengine->GetPolygonPointEdgeType() == KB_FALSE_EDGE) ? 1 : 0; polysList.push_back( corner ); count++; } diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index fd5092d0bf..02a6652739 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -31,7 +31,6 @@ */ #include -#include #include #include #include @@ -779,58 +778,6 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ return 1; } -/** - * Function CopyPolysListToKiPolygonWithHole - * converts the outline contours aPolysList to a KI_POLYGON_WITH_HOLES - * - * @param aPolysList = the list of corners of contours - * @param aPolygoneWithHole = a KI_POLYGON_WITH_HOLES to populate - */ -void CopyPolysListToKiPolygonWithHole( const std::vector& aPolysList, - KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) -{ - unsigned corners_count = aPolysList.size(); - - std::vector cornerslist; - KI_POLYGON poly; - - // Enter main outline: this is the first contour - unsigned ic = 0; - while( ic < corners_count ) - { - const CPolyPt& corner = aPolysList[ic++]; - cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) ); - - if( corner.end_contour ) - break; - } - - aPolygoneWithHole.set( cornerslist.begin(), cornerslist.end() ); - - // Enter holes: they are next contours (when exist) - if( ic < corners_count ) - { - KI_POLYGON_SET holePolyList; - while( ic < corners_count ) - { - cornerslist.clear(); - - while( ic < corners_count ) - { - const CPolyPt& corner = aPolysList[ic++]; - cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) ); - - if( corner.end_contour ) - break; - } - - bpl::set_points( poly, cornerslist.begin(), cornerslist.end() ); - holePolyList.push_back( poly ); - } - aPolygoneWithHole.set_holes( holePolyList.begin(), holePolyList.end() ); - } -} - /** * Function CombineAreas diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 99fa36f76c..57d6190edf 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -16,10 +16,10 @@ CPolyLine::CPolyLine() { - m_hatchStyle = NO_HATCH; - m_hatchPitch = 0; - m_width = 0; - m_utility = 0; + m_hatchStyle = NO_HATCH; + m_hatchPitch = 0; + m_width = 0; + m_utility = 0; m_Kbool_Poly_Engine = NULL; } @@ -29,10 +29,12 @@ CPolyLine::CPolyLine() CPolyLine::~CPolyLine() { UnHatch(); + if( m_Kbool_Poly_Engine ) delete m_Kbool_Poly_Engine; } + /** * Function armBoolEng * Initialise parameters used in kbool @@ -56,11 +58,11 @@ static void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); * @param bRetainArcs == true, try to retain arcs in polys * @return number of external contours, or -1 if error */ -int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, bool bRetainArcs ) +int CPolyLine::NormalizeWithKbool( std::vector* aExtraPolyList, bool bRetainArcs ) { std::vector arc_array; std::vector hole_array; // list of holes - std::vector * hole; // used to store corners for a given hole + std::vector* hole; // used to store corners for a given hole CPolyLine* polyline; int n_ext_cont = 0; // CPolyLine count @@ -71,9 +73,9 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo * True holes are combined if possible */ if( bRetainArcs ) - MakeKboolPoly( -1, -1, &arc_array ); + MakeKboolPoly( &arc_array ); else - MakeKboolPoly( -1, -1, NULL ); + MakeKboolPoly( NULL ); UnHatch(); @@ -92,10 +94,11 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo { hole = new std::vector; hole_array.push_back( hole ); + while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // store hole { - int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); - int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); + int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); + int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); hole->push_back( x ); hole->push_back( y ); } @@ -108,11 +111,13 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo m_CornersList.clear(); m_SideStyle.clear(); bool first = true; + while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) { // foreach point in the polygon - int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); - int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); + int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); + int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); + if( first ) { first = false; @@ -131,10 +136,12 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo polyline = new CPolyLine; // create new poly aExtraPolyList->push_back( polyline ); // put it in array bool first = true; + 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(); + int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); + int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); + if( first ) { first = false; @@ -153,8 +160,9 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo // now add cutouts to the corresponding CPolyLine(s) for( unsigned ii = 0; ii < hole_array.size(); ii++ ) { - hole = (std::vector *)hole_array[ii]; - polyline = NULL; + hole = (std::vector*)hole_array[ii]; + polyline = NULL; + if( n_ext_cont == 1 ) { polyline = this; @@ -164,8 +172,9 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo // find the polygon that contains this hole // testing one corner inside is enought because a hole is entirely inside the polygon // so we test only the first corner - int x = (*hole)[0]; - int y = (*hole)[1]; + int x = (*hole)[0]; + int y = (*hole)[1]; + if( TestPointInside( x, y ) ) polyline = this; else if( aExtraPolyList ) @@ -187,8 +196,8 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo { for( unsigned ii = 0; ii< (*hole).size(); ii++ ) { - int x = (*hole)[ii]; ii++; - int y = (*hole)[ii]; + int x = (*hole)[ii]; ii++; + int y = (*hole)[ii]; polyline->AppendCorner( x, y, STRAIGHT, false ); } @@ -204,76 +213,21 @@ int CPolyLine::NormalizeWithKbool( std::vector * aExtraPolyList, boo // free hole list for( unsigned ii = 0; ii < hole_array.size(); ii++ ) - delete (std::vector *)hole_array[ii]; + delete (std::vector*)hole_array[ii]; return n_ext_cont; } -/** - * Function AddPolygonsToBoolEng - * Add a CPolyLine to a kbool engine, preparing a boolean op between polygons - * @param aStart_contour: starting contour number (-1 = all, 0 is the outlines of zone, > 1 = holes in zone - * @param aEnd_contour: ending contour number (-1 = all after aStart_contour) - * @param arc_array: arc converted to poly segments (NULL if not exists) - * @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 aStart_contour, - int aEnd_contour, - std::vector * arc_array ) -{ - int count = 0; - - if( (aGroup != GROUP_A) && (aGroup != GROUP_B ) ) - return 0; //Error ! - - /* Convert the current polyline contour to a kbool polygon: */ - MakeKboolPoly( aStart_contour, aEnd_contour, arc_array ); - - /* 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 * approximates arcs with multiple straight-line segments - * @param aStart_contour: starting contour number (-1 = all, 0 is the outlines of zone, > 1 = holes in zone - * @param aEnd_contour: ending contour number (-1 = all after aStart_contour) * combining intersecting contours if possible * @param arc_array : return corners computed from arcs approximations in arc_array - * @param aConvertHoles = mode for holes when a boolean operation is made - * true: holes are linked into outer contours by double overlapping segments - * false: holes are not linked: in this mode contours are added clockwise - * and polygons added counter clockwise are holes (default) * @return error: 0 if Ok, 1 if error */ -int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector * arc_array, - bool aConvertHoles ) +int CPolyLine::MakeKboolPoly( std::vector* arc_array ) { if( m_Kbool_Poly_Engine ) { @@ -281,65 +235,40 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< m_Kbool_Poly_Engine = NULL; } - int polycount = GetContoursCount(); - - if( !GetClosed() && (aStart_contour == (polycount - 1) || aStart_contour == -1) ) + if( !GetClosed() ) return 1; // error int n_arcs = 0; + int polycount = GetContoursCount(); + int last_contour = polycount - 1; - int first_contour = aStart_contour; - int last_contour = aEnd_contour; - if( aStart_contour == -1 ) - { - first_contour = 0; - last_contour = polycount - 1; - } - if( aEnd_contour == -1 ) - { - last_contour = polycount - 1; - } if( arc_array ) arc_array->clear(); + int iarc = 0; - for( int icont = first_contour; 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, aConvertHoles ); - - 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(); - } - } + armBoolEng( booleng, false ); // first, calculate number of vertices in contour int n_vertices = 0; - int ic_st = GetContourStart( icont ); - int ic_end = GetContourEnd( icont ); + int ic_st = GetContourStart( icont ); + int ic_end = GetContourEnd( icont ); + if( !booleng->StartPolygonAdd( GROUP_B ) ) { wxASSERT( 0 ); - return 1; //error + return 1; // error } + for( int ic = ic_st; ic<=ic_end; ic++ ) { int style = m_SideStyle[ic]; + if( style == STRAIGHT ) n_vertices++; else @@ -353,22 +282,25 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< // now enter this contour to booleng int ivtx = 0; + for( int ic = ic_st; ic<=ic_end; ic++ ) { - int style = m_SideStyle[ic]; - int x1 = m_CornersList[ic].x; - int y1 = m_CornersList[ic].y; + int style = m_SideStyle[ic]; + int x1 = m_CornersList[ic].x; + int y1 = m_CornersList[ic].y; int x2, y2; + if( ic < ic_end ) { - x2 = m_CornersList[ic + 1].x; - y2 = m_CornersList[ic + 1].y; + x2 = m_CornersList[ic + 1].x; + y2 = m_CornersList[ic + 1].y; } else { - x2 = m_CornersList[ic_st].x; - y2 = m_CornersList[ic_st].y; + x2 = m_CornersList[ic_st].x; + y2 = m_CornersList[ic_st].y; } + if( style == STRAIGHT ) { booleng->AddPoint( x1, y1 ); @@ -377,44 +309,45 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< else { // style is arc_cw or arc_ccw - int n; // number of steps for arcs + int n; // number of steps for arcs n = CArc::ARC_STEPS; - double xo, yo, theta1, theta2, a, b; - a = fabs( (double) (x1 - x2) ); - b = fabs( (double) (y1 - y2) ); + double xo, yo, theta1, theta2, a, b; + a = fabs( (double) (x1 - x2) ); + b = fabs( (double) (y1 - y2) ); + if( style == CPolyLine::ARC_CW ) { // clockwise arc (ie.quadrant of ellipse) if( x2 > x1 && y2 > y1 ) { // first quadrant, draw second quadrant of ellipse - xo = x2; - yo = y1; - theta1 = M_PI; - theta2 = M_PI / 2.0; + xo = x2; + yo = y1; + theta1 = M_PI; + theta2 = M_PI / 2.0; } else if( x2 < x1 && y2 > y1 ) { // second quadrant, draw third quadrant of ellipse - xo = x1; - yo = y2; - theta1 = 3.0 * M_PI / 2.0; - theta2 = M_PI; + xo = x1; + yo = y2; + theta1 = 3.0 * M_PI / 2.0; + theta2 = M_PI; } else if( x2 < x1 && y2 < y1 ) { // third quadrant, draw fourth quadrant of ellipse - xo = x2; - yo = y1; - theta1 = 2.0 * M_PI; - theta2 = 3.0 * M_PI / 2.0; + xo = x2; + yo = y1; + theta1 = 2.0 * M_PI; + theta2 = 3.0 * M_PI / 2.0; } else { - xo = x1; // fourth quadrant, draw first quadrant of ellipse - yo = y2; - theta1 = M_PI / 2.0; - theta2 = 0.0; + xo = x1; // fourth quadrant, draw first quadrant of ellipse + yo = y2; + theta1 = M_PI / 2.0; + theta2 = 0.0; } } else @@ -422,31 +355,31 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< // counter-clockwise arc if( x2 > x1 && y2 > y1 ) { - xo = x1; // first quadrant, draw fourth quadrant of ellipse - yo = y2; - theta1 = 3.0 * M_PI / 2.0; - theta2 = 2.0 * M_PI; + xo = x1; // first quadrant, draw fourth quadrant of ellipse + yo = y2; + theta1 = 3.0 * M_PI / 2.0; + theta2 = 2.0 * M_PI; } else if( x2 < x1 && y2 > y1 ) { - xo = x2; // second quadrant - yo = y1; - theta1 = 0.0; - theta2 = M_PI / 2.0; + xo = x2; // second quadrant + yo = y1; + theta1 = 0.0; + theta2 = M_PI / 2.0; } else if( x2 < x1 && y2 < y1 ) { - xo = x1; // third quadrant - yo = y2; - theta1 = M_PI / 2.0; - theta2 = M_PI; + xo = x1; // third quadrant + yo = y2; + theta1 = M_PI / 2.0; + theta2 = M_PI; } else { - xo = x2; // fourth quadrant - yo = y1; - theta1 = M_PI; - theta2 = 3.0 * M_PI / 2.0; + xo = x2; // fourth quadrant + yo = y1; + theta1 = M_PI; + theta2 = 3.0 * M_PI / 2.0; } } @@ -456,23 +389,26 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< CArc new_arc; new_arc.style = style; new_arc.n_steps = n; - new_arc.xi = x1; - new_arc.yi = y1; - new_arc.xf = x2; - new_arc.yf = y2; + new_arc.xi = x1; + new_arc.yi = y1; + new_arc.xf = x2; + new_arc.yf = y2; arc_array->push_back( new_arc ); iarc++; } + for( int is = 0; isAddPoint( x, y ); ivtx++; } @@ -484,7 +420,7 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< wxASSERT( 0 ); } - // close list added to the bool engine + // close list added to the bool engine booleng->EndPolygonAdd(); /* now combine polygon to the previous polygons. @@ -494,7 +430,7 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< * Others polygons are substract to the outline and corners will be ordered counter clockwise * by the kbool engine */ - if( aStart_contour <= 0 && icont != 0 ) // substract hole to outside ( if the outline contour is take in account) + if( icont != 0 ) // substract hole to outside ( if the outline contour is take in account) { booleng->Do_Operation( BOOL_A_SUB_B ); } @@ -506,6 +442,7 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector< // now use result as new polygon (delete the old one if exists) if( m_Kbool_Poly_Engine ) delete m_Kbool_Poly_Engine; + m_Kbool_Poly_Engine = booleng; } @@ -528,55 +465,56 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) // input points are scaled up with GetDGrid() * GetGrid() // DGRID is only meant to make fractional parts of input data which - /* - The input data scaled up with DGrid is related to the accuracy the user has in his input data. - User data with a minimum accuracy of 0.001, means set the DGrid to 1000. - The input data may contain data with a minimum accuracy much smaller, but by setting the DGrid - everything smaller than 1/DGrid is rounded. + /* + * The input data scaled up with DGrid is related to the accuracy the user has in his input data. + * User data with a minimum accuracy of 0.001, means set the DGrid to 1000. + * The input data may contain data with a minimum accuracy much smaller, but by setting the DGrid + * everything smaller than 1/DGrid is rounded. + * + * DGRID is only meant to make fractional parts of input data which can be + * doubles, part of the integers used in vertexes within the boolean algorithm. + * And therefore DGRID bigger than 1 is not usefull, you would only loose accuracy. + * Within the algorithm all input data is multiplied with DGRID, and the result + * is rounded to an integer. + */ + double DGRID = 1000.0; // round coordinate X or Y value in calculations to this (initial value = 1000.0 in kbool example) + // kbool uses DGRID to convert float user units to integer + // kbool unit = (int)(user unit * DGRID) + // Note: in kicad, coordinates are already integer so DGRID could be set to 1 + // we can choose 1.0, + // but choose DGRID = 1000.0 solves some filling problems +// (perhaps because this allows a better precision in kbool internal calculations - DGRID is only meant to make fractional parts of input data which can be - doubles, part of the integers used in vertexes within the boolean algorithm. - And therefore DGRID bigger than 1 is not usefull, you would only loose accuracy. - Within the algorithm all input data is multiplied with DGRID, and the result - is rounded to an integer. - */ - double DGRID = 1000.0; // round coordinate X or Y value in calculations to this (initial value = 1000.0 in kbool example) - // kbool uses DGRID to convert float user units to integer - // kbool unit = (int)(user unit * DGRID) - // Note: in kicad, coordinates are already integer so DGRID could be set to 1 - // we can choose 1.0, - // but choose DGRID = 1000.0 solves some filling problems -// (perhaps because this allows a better precision in kbool internal calculations - - double MARGE = 1.0/DGRID; // snap with in this range points to lines in the intersection routines - // should always be >= 1/DGRID a MARGE >= 10/DGRID is ok - // this is also used to remove small segments and to decide when - // two segments are in line. ( initial value = 0.001 ) - // For kicad we choose MARGE = 1/DGRID + double MARGE = 1.0 / DGRID; // snap with in this range points to lines in the intersection routines + // should always be >= 1/DGRID a MARGE >= 10/DGRID is ok + // this is also used to remove small segments and to decide when + // two segments are in line. ( initial value = 0.001 ) + // For kicad we choose MARGE = 1/DGRID double CORRECTIONFACTOR = 0.0; // correct the polygons by this number: used in BOOL_CORRECTION operation // this operation shrinks a polygon if CORRECTIONFACTOR < 0 // or stretch it if CORRECTIONFACTOR > 0 // the size change is CORRECTIONFACTOR (holes are correctly handled) - double CORRECTIONABER = 1.0; // the accuracy for the rounded shapes used in correction - double ROUNDFACTOR = 1.5; // when will we round the correction shape to a circle - double SMOOTHABER = 10.0; // accuracy when smoothing a polygon - double MAXLINEMERGE = 1000.0; // leave as is, segments of this length in smoothen + double CORRECTIONABER = 1.0; // the accuracy for the rounded shapes used in correction + double ROUNDFACTOR = 1.5; // when will we round the correction shape to a circle + double SMOOTHABER = 10.0; // accuracy when smoothing a polygon + double MAXLINEMERGE = 1000.0; // leave as is, segments of this length in smoothen - /* - Grid makes sure that the integer data used within the algorithm has room for extra intersections - smaller than the smallest number within the input data. - The input data scaled up with DGrid is related to the accuracy the user has in his input data. - Another scaling with Grid is applied on top of it to create space in the integer number for - even smaller numbers. - */ - int GRID = (int) ( 10000.0 / DGRID ); // initial value = 10000 in kbool example but we use - // 10000/DGRID because the scaling is made by DGRID - // on integer pcbnew units and the global scaling - // ( GRID*DGRID) must be < 30000 to avoid overflow - // in calculations (made in long long in kbool) - if ( GRID <= 1 ) // Cannot be null! + /* + * Grid makes sure that the integer data used within the algorithm has room for extra intersections + * smaller than the smallest number within the input data. + * The input data scaled up with DGrid is related to the accuracy the user has in his input data. + * Another scaling with Grid is applied on top of it to create space in the integer number for + * even smaller numbers. + */ + int GRID = (int) ( 10000.0 / DGRID ); // initial value = 10000 in kbool example but we use + + // 10000/DGRID because the scaling is made by DGRID + // on integer pcbnew units and the global scaling + // ( GRID*DGRID) must be < 30000 to avoid overflow + // in calculations (made in long long in kbool) + if( GRID <= 1 ) // Cannot be null! GRID = 1; aBooleng->SetMarge( MARGE ); @@ -591,9 +529,9 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) if( aConvertHoles ) { -#if 1 // Can be set to 1 for kbool version >= 2.1, must be set to 0 for previous versions - // SetAllowNonTopHoleLinking() exists only in kbool >= 2.1 - aBooleng->SetAllowNonTopHoleLinking( false ); // Default = true, but i have problems (filling errors) when true +#if 1 // Can be set to 1 for kbool version >= 2.1, must be set to 0 for previous versions + // SetAllowNonTopHoleLinking() exists only in kbool >= 2.1 + aBooleng->SetAllowNonTopHoleLinking( false ); // Default = true, but i have problems (filling errors) when true #endif aBooleng->SetLinkHoles( true ); // holes will be connected by double overlapping segments aBooleng->SetOrientationEntryMode( false ); // all polygons are contours, not holes @@ -606,7 +544,7 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) } -int CPolyLine::NormalizeAreaOutlines( std::vector * pa, bool bRetainArcs ) +int CPolyLine::NormalizeAreaOutlines( std::vector* pa, bool bRetainArcs ) { return NormalizeWithKbool( pa, bRetainArcs ); } @@ -615,13 +553,14 @@ int CPolyLine::NormalizeAreaOutlines( std::vector * pa, bool bRetain // Restore arcs to a polygon where they were replaced with steps // If pa != NULL, also use polygons in pa array // -int CPolyLine::RestoreArcs( std::vector * arc_array, std::vector * pa ) +int CPolyLine::RestoreArcs( std::vector* arc_array, std::vector* pa ) { // get poly info int n_polys = 1; if( pa ) n_polys += pa->size(); + CPolyLine* poly; // undraw polys and clear m_utility flag for all corners @@ -631,7 +570,9 @@ int CPolyLine::RestoreArcs( std::vector * arc_array, std::vectorUnHatch(); + for( int ic = 0; icGetNumCorners(); ic++ ) poly->SetUtility( ic, 0 ); @@ -639,9 +580,10 @@ int CPolyLine::RestoreArcs( std::vector * arc_array, std::vectorsize(); iarc++ ) { int arc_xi = (*arc_array)[iarc].xi; @@ -659,52 +601,65 @@ int CPolyLine::RestoreArcs( std::vector * arc_array, std::vectorGetContoursCount(); + for( int icont = 0; icont < polycount; icont++ ) { - int ic_start = poly->GetContourStart( icont ); - int ic_end = poly->GetContourEnd( icont ); + int ic_start = poly->GetContourStart( icont ); + int ic_end = poly->GetContourEnd( icont ); + if( (ic_end - ic_start) > n_steps ) { for( int ic = ic_start; ic<=ic_end; ic++ ) { int ic_next = ic + 1; + if( ic_next > ic_end ) ic_next = ic_start; - int xi = poly->GetX( ic ); - int yi = poly->GetY( ic ); + + int xi = poly->GetX( ic ); + int yi = poly->GetY( ic ); + if( xi == arc_xi && yi == arc_yi ) { // test for forward arc int ic2 = ic + n_steps; + if( ic2 > ic_end ) ic2 = ic2 - ic_end + ic_start - 1; - int xf = poly->GetX( ic2 ); - int yf = poly->GetY( ic2 ); + + int xf = poly->GetX( ic2 ); + int yf = poly->GetY( ic2 ); + if( xf == arc_xf && yf == arc_yf ) { // arc from ic to ic2 - bFound = true; - arc_start = ic; - arc_end = ic2; + bFound = true; + arc_start = ic; + arc_end = ic2; } else { // try reverse arc ic2 = ic - n_steps; + if( ic2 < ic_start ) ic2 = ic2 - ic_start + ic_end + 1; - xf = poly->GetX( ic2 ); - yf = poly->GetY( ic2 ); + + xf = poly->GetX( ic2 ); + yf = poly->GetY( ic2 ); + if( xf == arc_xf && yf == arc_yf ) { // arc from ic2 to ic - bFound = true; - arc_start = ic2; - arc_end = ic; - style = 3 - style; + bFound = true; + arc_start = ic2; + arc_end = ic; + style = 3 - style; } } + if( bFound ) { poly->m_SideStyle[arc_start] = style; @@ -714,7 +669,9 @@ int CPolyLine::RestoreArcs( std::vector * arc_array, std::vector ic_end ) i = ic_start; + poly->SetUtility( i, 1 ); + if( i == ic_end ) i = ic_start; else @@ -724,10 +681,12 @@ int CPolyLine::RestoreArcs( std::vector * arc_array, std::vector * arc_array, std::vectorGetNumCorners() - 1; ic>=0; ic-- ) { if( poly->GetUtility( ic ) ) @@ -761,20 +721,20 @@ int CPolyLine::RestoreArcs( std::vector * arc_array, std::vector 0 && !m_CornersList[m_CornersList.size() - 1].end_contour ) m_SideStyle[m_CornersList.size() - 1] = style; + if( bDraw ) Hatch(); } @@ -810,9 +772,11 @@ void CPolyLine::Close( int style, bool bDraw ) { wxASSERT( 0 ); } + UnHatch(); m_SideStyle[m_CornersList.size() - 1] = style; m_CornersList[m_CornersList.size() - 1].end_contour = true; + if( bDraw ) Hatch(); } @@ -834,10 +798,10 @@ void CPolyLine::MoveCorner( int ic, int x, int y ) void CPolyLine::DeleteCorner( int ic, bool bDraw ) { UnHatch(); - int icont = GetContour( ic ); - int istart = GetContourStart( icont ); - int iend = GetContourEnd( icont ); - bool bClosed = icont < GetContoursCount() - 1 || GetClosed(); + int icont = GetContour( ic ); + int istart = GetContourStart( icont ); + int iend = GetContourEnd( icont ); + bool bClosed = icont < GetContoursCount() - 1 || GetClosed(); if( !bClosed ) { @@ -852,14 +816,17 @@ void CPolyLine::DeleteCorner( int ic, bool bDraw ) // closed contour m_CornersList.erase( m_CornersList.begin() + ic ); m_SideStyle.erase( m_SideStyle.begin() + ic ); + if( ic == iend ) m_CornersList[ic - 1].end_contour = true; } + if( bClosed && GetContourSize( icont ) < 3 ) { // delete the entire contour RemoveContour( icont ); } + if( bDraw ) Hatch(); } @@ -876,10 +843,11 @@ void CPolyLine::RemoveContour( int icont ) */ { UnHatch(); - int istart = GetContourStart( icont ); - int iend = GetContourEnd( icont ); + int istart = GetContourStart( icont ); + int iend = GetContourEnd( icont ); int polycount = GetContoursCount(); + if( icont == 0 && polycount == 1 ) { // remove the only contour @@ -900,6 +868,7 @@ void CPolyLine::RemoveContour( int icont ) m_SideStyle.erase( m_SideStyle.begin() + ic ); } } + Hatch(); } @@ -915,64 +884,66 @@ CPolyLine* CPolyLine::Chamfer( unsigned int aDistance ) } int polycount = GetContoursCount(); + for( int contour = 0; contour < polycount; contour++ ) { - unsigned int startIndex = GetContourStart( contour ); - unsigned int endIndex = GetContourEnd( contour ); + unsigned int startIndex = GetContourStart( contour ); + unsigned int endIndex = GetContourEnd( contour ); for( unsigned int index = startIndex; index <= endIndex; index++ ) { - int x1, y1, nx, ny; - long long xa, ya, xb, yb; + int x1, y1, nx, ny; + long long xa, ya, xb, yb; - x1 = m_CornersList[index].x; - y1 = m_CornersList[index].y; + x1 = m_CornersList[index].x; + y1 = m_CornersList[index].y; if( index == startIndex ) { - xa = m_CornersList[endIndex].x - x1; - ya = m_CornersList[endIndex].y - y1; + xa = m_CornersList[endIndex].x - x1; + ya = m_CornersList[endIndex].y - y1; } else { - xa = m_CornersList[index-1].x - x1; - ya = m_CornersList[index-1].y - y1; + xa = m_CornersList[index - 1].x - x1; + ya = m_CornersList[index - 1].y - y1; } if( index == endIndex ) { - xb = m_CornersList[startIndex].x - x1; - yb = m_CornersList[startIndex].y - y1; + xb = m_CornersList[startIndex].x - x1; + yb = m_CornersList[startIndex].y - y1; } else { - xb = m_CornersList[index+1].x - x1; - yb = m_CornersList[index+1].y - y1; + xb = m_CornersList[index + 1].x - x1; + yb = m_CornersList[index + 1].y - y1; } - unsigned int lena = (unsigned int)sqrt( (double)(xa*xa + ya*ya) ); - unsigned int lenb = (unsigned int)sqrt( (double)(xb*xb + yb*yb) ); - unsigned int distance = aDistance; + unsigned int lena = (unsigned int) sqrt( (double) (xa * xa + ya * ya) ); + unsigned int lenb = (unsigned int) sqrt( (double) (xb * xb + yb * yb) ); + unsigned int distance = aDistance; // Chamfer one half of an edge at most - if( 0.5*lena < distance ) - distance = (unsigned int)(0.5*(double)lena); + if( 0.5 * lena < distance ) + distance = (unsigned int) (0.5 * (double) lena); - if( 0.5*lenb < distance ) - distance = (unsigned int)(0.5*(double)lenb); + if( 0.5 * lenb < distance ) + distance = (unsigned int) (0.5 * (double) lenb); - nx = (int) ( (double) (distance*xa)/sqrt( (double) (xa*xa + ya*ya) ) ); - ny = (int) ( (double) (distance*ya)/sqrt( (double) (xa*xa + ya*ya) ) ); + nx = (int) ( (double) (distance * xa) / sqrt( (double) (xa * xa + ya * ya) ) ); + ny = (int) ( (double) (distance * ya) / sqrt( (double) (xa * xa + ya * ya) ) ); if( index == startIndex ) newPoly->Start( GetLayer(), x1 + nx, y1 + ny, GetHatchStyle() ); else newPoly->AppendCorner( x1 + nx, y1 + ny ); - nx = (int) ( (double) (distance*xb)/sqrt( (double) (xb*xb + yb*yb) ) ); - ny = (int) ( (double) (distance*yb)/sqrt( (double) (xb*xb + yb*yb) ) ); + nx = (int) ( (double) (distance * xb) / sqrt( (double) (xb * xb + yb * yb) ) ); + ny = (int) ( (double) (distance * yb) / sqrt( (double) (xb * xb + yb * yb) ) ); newPoly->AppendCorner( x1 + nx, y1 + ny ); } + newPoly->Close(); } @@ -991,114 +962,119 @@ CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments ) } int polycount = GetContoursCount(); + for( int contour = 0; contour < polycount; contour++ ) { - unsigned int startIndex = GetContourStart( contour ); - unsigned int endIndex = GetContourEnd( contour ); + unsigned int startIndex = GetContourStart( contour ); + unsigned int endIndex = GetContourEnd( contour ); for( unsigned int index = startIndex; index <= endIndex; index++ ) { + int x1, y1; // Current vertex + long long xa, ya; // Previous vertex + long long xb, yb; // Next vertex + double nx, ny; - int x1, y1; // Current vertex - long long xa, ya; // Previous vertex - long long xb, yb; // Next vertex - double nx, ny; - - x1 = m_CornersList[index].x; - y1 = m_CornersList[index].y; + x1 = m_CornersList[index].x; + y1 = m_CornersList[index].y; if( index == startIndex ) { - xa = m_CornersList[endIndex].x - x1; - ya = m_CornersList[endIndex].y - y1; + xa = m_CornersList[endIndex].x - x1; + ya = m_CornersList[endIndex].y - y1; } else { - xa = m_CornersList[index-1].x - x1; - ya = m_CornersList[index-1].y - y1; + xa = m_CornersList[index - 1].x - x1; + ya = m_CornersList[index - 1].y - y1; } if( index == endIndex ) { - xb = m_CornersList[startIndex].x - x1; - yb = m_CornersList[startIndex].y - y1; + xb = m_CornersList[startIndex].x - x1; + yb = m_CornersList[startIndex].y - y1; } else { - xb = m_CornersList[index+1].x - x1; - yb = m_CornersList[index+1].y - y1; + xb = m_CornersList[index + 1].x - x1; + yb = m_CornersList[index + 1].y - y1; } - double lena = sqrt( (double) (xa*xa + ya*ya) ); - double lenb = sqrt( (double) (xb*xb + yb*yb) ); - double cosine = ( xa*xb + ya*yb )/( lena*lenb ); + double lena = sqrt( (double) (xa * xa + ya * ya) ); + double lenb = sqrt( (double) (xb * xb + yb * yb) ); + double cosine = ( xa * xb + ya * yb ) / ( lena * lenb ); - unsigned int radius = aRadius; - double denom = sqrt( 2.0/( 1+cosine )-1 ); + unsigned int radius = aRadius; + double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 ); // Limit rounding distance to one half of an edge - if( 0.5*lena*denom < radius ) - radius = (unsigned int)(0.5*lena*denom); + if( 0.5 * lena * denom < radius ) + radius = (unsigned int) (0.5 * lena * denom); - if( 0.5*lenb*denom < radius ) - radius = (unsigned int)(0.5*lenb*denom); + if( 0.5 * lenb * denom < radius ) + radius = (unsigned int) (0.5 * lenb * denom); // Calculate fillet arc absolute center point (xc, yx) - double k = radius / sqrt( .5*( 1-cosine ) ); - double lenab = sqrt( ( xa/lena + xb/lenb )*( xa/lena + xb/lenb ) + - ( ya/lena + yb/lenb )*( ya/lena + yb/lenb ) ); - double xc = x1 + k*( xa/lena + xb/lenb )/lenab; - double yc = y1 + k*( ya/lena + yb/lenb )/lenab; + double k = radius / sqrt( .5 * ( 1 - cosine ) ); + double lenab = sqrt( ( xa / lena + xb / lenb ) * ( xa / lena + xb / lenb ) + + ( ya / lena + yb / lenb ) * ( ya / lena + yb / lenb ) ); + double xc = x1 + k * ( xa / lena + xb / lenb ) / lenab; + double yc = y1 + k * ( ya / lena + yb / lenb ) / lenab; // Calculate arc start and end vectors - k = radius / sqrt( 2/( 1+cosine )-1 ); - double xs = x1 + k*xa/lena - xc; - double ys = y1 + k*ya/lena - yc; - double xe = x1 + k*xb/lenb - xc; - double ye = y1 + k*yb/lenb - yc; + k = radius / sqrt( 2 / ( 1 + cosine ) - 1 ); + double xs = x1 + k * xa / lena - xc; + double ys = y1 + k * ya / lena - yc; + double xe = x1 + k * xb / lenb - xc; + double ye = y1 + k * yb / lenb - yc; // Cosine of arc angle - double argument = ( xs*xe + ys*ye ) / ( radius*radius ); + double argument = ( xs * xe + ys * ye ) / ( radius * radius ); if( argument < -1 ) // Just in case... argument = -1; else if( argument > 1 ) argument = 1; - double arcAngle = acos( argument ); + double arcAngle = acos( argument ); // Calculate the number of segments - double tempSegments = (double)aSegments * ( arcAngle / ( 2*M_PI ) ); + double tempSegments = (double) aSegments * ( arcAngle / ( 2 * M_PI ) ); - if( tempSegments - (int)tempSegments > 0 ) + if( tempSegments - (int) tempSegments > 0 ) tempSegments++; - unsigned int segments = (unsigned int) tempSegments; - double deltaAngle = arcAngle / segments; - double startAngle = atan2( -ys, xs ); + unsigned int segments = (unsigned int) tempSegments; + + double deltaAngle = arcAngle / segments; + double startAngle = atan2( -ys, xs ); // Flip arc for inner corners - if( xa*yb - ya*xb <= 0 ) + if( xa * yb - ya * xb <= 0 ) deltaAngle *= -1; - nx = xc + xs + 0.5; - ny = yc + ys + 0.5; + nx = xc + xs + 0.5; + ny = yc + ys + 0.5; + if( index == startIndex ) - newPoly->Start( GetLayer(), (int)nx, (int)ny, GetHatchStyle() ); + newPoly->Start( GetLayer(), (int) nx, (int) ny, GetHatchStyle() ); else - newPoly->AppendCorner( (int)nx, (int)ny ); + newPoly->AppendCorner( (int) nx, (int) ny ); unsigned int nVertices = 0; + for( unsigned int j = 0; j < segments; j++ ) { - nx = xc + cos( startAngle + (j+1)*deltaAngle )*radius + 0.5; - ny = yc - sin( startAngle + (j+1)*deltaAngle )*radius + 0.5; - newPoly->AppendCorner( (int)nx, (int)ny ); + nx = xc + cos( startAngle + (j + 1) * deltaAngle ) * radius + 0.5; + ny = yc - sin( startAngle + (j + 1) * deltaAngle ) * radius + 0.5; + newPoly->AppendCorner( (int) nx, (int) ny ); nVertices++; } } + newPoly->Close(); } + return newPoly; } @@ -1127,6 +1103,7 @@ void CPolyLine::RemoveAllContours( void ) void CPolyLine::InsertCorner( int ic, int x, int y ) { UnHatch(); + if( (unsigned) (ic) >= m_CornersList.size() ) { m_CornersList.push_back( CPolyPt( x, y ) ); @@ -1142,10 +1119,11 @@ void CPolyLine::InsertCorner( int ic, int x, int y ) { if( m_CornersList[ic].end_contour ) { - m_CornersList[ic + 1].end_contour = true; - m_CornersList[ic].end_contour = false; + m_CornersList[ic + 1].end_contour = true; + m_CornersList[ic].end_contour = false; } } + Hatch(); } @@ -1168,10 +1146,10 @@ CRect CPolyLine::GetBounds() { CRect r = GetCornerBounds(); - r.left -= m_width / 2; - r.right += m_width / 2; - r.bottom -= m_width / 2; - r.top += m_width / 2; + r.left -= m_width / 2; + r.right += m_width / 2; + r.bottom -= m_width / 2; + r.top += m_width / 2; return r; } @@ -1182,12 +1160,13 @@ CRect CPolyLine::GetCornerBounds() r.left = r.bottom = INT_MAX; r.right = r.top = INT_MIN; + for( unsigned i = 0; i max_x ) max_x = m_CornersList[ic].x; + if( m_CornersList[ic].y < min_y ) min_y = m_CornersList[ic].y; + if( m_CornersList[ic].y > max_y ) max_y = m_CornersList[ic].y; } // Calculate spacing betwwen 2 hatch lines - int spacing; + int spacing; + if( m_hatchStyle == DIAGONAL_EDGE ) spacing = m_hatchPitch; else spacing = m_hatchPitch * 2; // set the "lenght" of hatch lines (the lenght on horizontal axis) - double hatch_line_len = m_hatchPitch; + double hatch_line_len = m_hatchPitch; // To have a better look, give a slope depending on the layer - int layer = GetLayer(); - int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1 - double slope = 0.707106 * slope_flag; // 45 degrees slope - int max_a, min_a; + int layer = GetLayer(); + int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1 + double slope = 0.707106 * slope_flag; // 45 degrees slope + int max_a, min_a; + if( slope_flag == 1 ) { - max_a = (int) (max_y - slope * min_x); - min_a = (int) (min_y - slope * max_x); + max_a = (int) (max_y - slope * min_x); + min_a = (int) (min_y - slope * max_x); } else { - max_a = (int) (max_y - slope * max_x); - min_a = (int) (min_y - slope * min_x); + max_a = (int) (max_y - slope * max_x); + min_a = (int) (min_y - slope * min_x); } + min_a = (min_a / spacing) * spacing; // calculate an offset depending on layer number, @@ -1427,7 +1426,7 @@ void CPolyLine::Hatch() static std::vector pointbuffer; pointbuffer.clear(); - pointbuffer.reserve(MAXPTS+2); + pointbuffer.reserve( MAXPTS + 2 ); for( int a = min_a; a < max_a; a += spacing ) { @@ -1439,38 +1438,43 @@ void CPolyLine::Hatch() // we skip this line (should not occur) pointbuffer.clear(); int i_start_contour = 0; + for( int ic = 0; ic= MAXPTS ) // overflow { wxASSERT( 0 ); @@ -1495,6 +1499,7 @@ void CPolyLine::Hatch() for( unsigned ip = 0; ip < pointbuffer.size(); ip += 2 ) { double dx = pointbuffer[ip + 1].x - pointbuffer[ip].x; + // Push only one line for diagonal hatch, // or for small lines < twice the line len // else push 2 small lines @@ -1504,18 +1509,18 @@ void CPolyLine::Hatch() } else { - double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y; - double slope = dy / dx; + double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y; + double slope = dy / dx; if( dx > 0 ) dx = hatch_line_len; else dx = -hatch_line_len; - double x1 = pointbuffer[ip].x + dx; - double x2 = pointbuffer[ip + 1].x - dx; - double y1 = pointbuffer[ip].y + dx * slope; - double y2 = pointbuffer[ip + 1].y - dx * slope; + double x1 = pointbuffer[ip].x + dx; + double x2 = pointbuffer[ip + 1].x - dx; + double y1 = pointbuffer[ip].y + dx * slope; + double y2 = pointbuffer[ip + 1].y - dx * slope; m_HatchLines.push_back( CSegment( pointbuffer[ip].x, pointbuffer[ip].y, @@ -1544,28 +1549,30 @@ bool CPolyLine::TestPointInside( int px, int py ) // if the tested point is inside only one contour, it is inside the whole polygon // (in fact inside the main outline, and outside all holes). // if inside 2 contours (the main outline + an hole), it is outside the poly. - int polycount = GetContoursCount(); - bool inside = false; + int polycount = GetContoursCount(); + bool inside = false; + for( int icont = 0; icont < polycount; icont++ ) { - int istart = GetContourStart( icont ); - int iend = GetContourEnd( icont ); + int istart = GetContourStart( icont ); + int iend = GetContourEnd( icont ); // Test this polygon: - if( TestPointInsidePolygon( m_CornersList, istart, iend, px, py) ) // test point inside the current polygon + if( TestPointInsidePolygon( m_CornersList, istart, iend, px, py ) ) // test point inside the current polygon inside = not inside; } return inside; } + // copy data from another poly, but don't draw it // void CPolyLine::Copy( CPolyLine* src ) { UnHatch(); - m_hatchStyle = src->m_hatchStyle; - m_hatchPitch = src->m_hatchPitch; + m_hatchStyle = src->m_hatchStyle; + m_hatchPitch = src->m_hatchPitch; // copy corners, using vector copy m_CornersList = src->m_CornersList; // copy side styles, using vector copy @@ -1583,8 +1590,9 @@ bool CPolyLine::IsCutoutContour( int icont ) { int ncont = GetContour( icont ); - if( ncont == 0 ) // the first contour is the main outline, not an hole + if( ncont == 0 ) // the first contour is the main outline, not an hole return false; + return true; } @@ -1592,6 +1600,7 @@ bool CPolyLine::IsCutoutContour( int icont ) void CPolyLine::MoveOrigin( int x_off, int y_off ) { UnHatch(); + for( int ic = 0; ic < GetNumCorners(); ic++ ) { SetX( ic, GetX( ic ) + x_off ); @@ -1603,8 +1612,8 @@ void CPolyLine::MoveOrigin( int x_off, int y_off ) // Set various parameters: -// the calling function should UnHatch() before calling them, -// and Draw() after +// the calling function should UnHatch() before calling them, +// and Draw() after // void CPolyLine::SetX( int ic, int x ) { @@ -1627,19 +1636,19 @@ void CPolyLine::SetEndContour( int ic, bool end_contour ) 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 r = sqrt( (double) (xi - xc) * (xi - xc) + (double) (yi - yc) * (yi - yc) ); // get angles of start and finish - double th_i = atan2( (double) (yi - yc), (double) (xi - xc) ); - double th_f = atan2( (double) (yf - yc), (double) (xf - xc) ); - double th_d = (th_f - th_i) / (num - 1); - double theta = th_i; + double th_i = atan2( (double) (yi - yc), (double) (xi - xc) ); + double th_f = atan2( (double) (yf - yc), (double) (xf - xc) ); + double th_d = (th_f - th_i) / (num - 1); + double theta = th_i; // generate arc for( int ic = 0; ic bezier_points; - bezier_points = Bezier2Poly(x1,y1,x2,y2,x3,y3); - for( unsigned int i = 0; i < bezier_points.size() ; i++) - AppendCorner( bezier_points[i].x, bezier_points[i].y); + bezier_points = Bezier2Poly( x1, y1, x2, y2, x3, y3 ); + + for( unsigned int i = 0; i < bezier_points.size(); i++ ) + AppendCorner( bezier_points[i].x, bezier_points[i].y ); } -void CPolyLine::AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + +void CPolyLine::AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ) { std::vector bezier_points; - bezier_points = Bezier2Poly(x1,y1,x2,y2,x3,y3,x4,y4); - for( unsigned int i = 0; i < bezier_points.size() ; i++) - AppendCorner( bezier_points[i].x, bezier_points[i].y); + bezier_points = Bezier2Poly( x1, y1, x2, y2, x3, y3, x4, y4 ); + + for( unsigned int i = 0; i < bezier_points.size(); i++ ) + AppendCorner( bezier_points[i].x, bezier_points[i].y ); } @@ -1685,13 +1698,13 @@ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth ) if( TestPointInside( aStart.x, aStart.y ) ) return 0; - int distance = INT_MAX; - int polycount = GetContoursCount(); + int distance = INT_MAX; + int polycount = GetContoursCount(); for( int icont = 0; icont < polycount; icont++ ) { - int ic_start = GetContourStart( icont ); - int ic_end = GetContourEnd( icont ); + int ic_start = GetContourStart( icont ); + int ic_end = GetContourEnd( icont ); // now test spacing between area outline and segment for( int ic2 = ic_start; ic2 <= ic_end; ic2++ ) @@ -1715,10 +1728,12 @@ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth ) int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle, 0, aStart.x, aStart.y, aEnd.x, aEnd.y, CPolyLine::STRAIGHT, aWidth, - 1, // min clearance, should be > 0 + 1, // min clearance, should be > 0 NULL, NULL ); + if( distance > d ) distance = d; + if( distance <= 0 ) return 0; } @@ -1727,6 +1742,7 @@ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth ) return distance; } + /* * Function Distance * Calculates the distance between a point and polygon (with holes): @@ -1741,13 +1757,13 @@ int CPolyLine::Distance( const wxPoint& aPoint ) if( TestPointInside( aPoint.x, aPoint.y ) ) return 0; - int distance = INT_MAX; - int polycount = GetContoursCount(); + int distance = INT_MAX; + int polycount = GetContoursCount(); for( int icont = 0; icont < polycount; icont++ ) { - int ic_start = GetContourStart( icont ); - int ic_end = GetContourEnd( icont ); + int ic_start = GetContourStart( icont ); + int ic_end = GetContourEnd( icont ); // now test spacing between area outline and segment for( int ic2 = ic_start; ic2 <= ic_end; ic2++ ) @@ -1770,11 +1786,12 @@ int CPolyLine::Distance( const wxPoint& aPoint ) // Here we expect only straight lines for vertices // (no arcs, not yet supported in Pcbnew) int d = KiROUND( GetPointToLineSegmentDistance( aPoint.x, aPoint.y, - bx1, by1, bx2, by2 ) ); + bx1, by1, bx2, by2 ) ); if( distance > d ) distance = d; + if( distance <= 0 ) return 0; } @@ -1782,3 +1799,152 @@ int CPolyLine::Distance( const wxPoint& aPoint ) return distance; } + + +/** + * Function CopyPolysListToKiPolygonWithHole + * converts the outline contours aPolysList to a KI_POLYGON_WITH_HOLES + * + * @param aPolysList = the list of corners of contours + * @param aPolygoneWithHole = a KI_POLYGON_WITH_HOLES to populate + */ +void CopyPolysListToKiPolygonWithHole( const std::vector& aPolysList, + KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) +{ + unsigned corners_count = aPolysList.size(); + + std::vector cornerslist; + KI_POLYGON poly; + + // Enter main outline: this is the first contour + unsigned ic = 0; + + while( ic < corners_count ) + { + const CPolyPt& corner = aPolysList[ic++]; + cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) ); + + if( corner.end_contour ) + break; + } + + aPolygoneWithHole.set( cornerslist.begin(), cornerslist.end() ); + + // Enter holes: they are next contours (when exist) + if( ic < corners_count ) + { + KI_POLYGON_SET holePolyList; + + while( ic < corners_count ) + { + cornerslist.clear(); + + while( ic < corners_count ) + { + const CPolyPt& corner = aPolysList[ic++]; + cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) ); + + if( corner.end_contour ) + break; + } + + bpl::set_points( poly, cornerslist.begin(), cornerslist.end() ); + holePolyList.push_back( poly ); + } + + aPolygoneWithHole.set_holes( holePolyList.begin(), holePolyList.end() ); + } +} + +/** + * Function ConvertPolysListWithHolesToOnePolygon + * converts the outline contours aPolysListWithHoles with holes to one polygon + * with no holes (only one contour) + * holes are linked to main outlines by overlap segments, to give only one polygon + * + * @param aPolysListWithHoles = the list of corners of contours (haing holes + * @param aOnePolyList = a polygon with no holes + */ +void ConvertPolysListWithHolesToOnePolygon( const std::vector& aPolysListWithHoles, + std::vector& aOnePolyList ) +{ + unsigned corners_count = aPolysListWithHoles.size(); + int polycount = 0; + + for( unsigned ii = 0; ii < corners_count; ii++ ) + { + const CPolyPt& corner = aPolysListWithHoles[ii]; + + if( corner.end_contour ) + polycount++; + } + + // If polycount<= 1, there is no holes found. + if( polycount<= 1 ) + { + aOnePolyList = aPolysListWithHoles; + return; + } + + // Holes are found: convert them to only one polygon with overlap segments + KI_POLYGON_SET polysholes; + KI_POLYGON_SET mainpoly; + KI_POLYGON poly_tmp; + std::vector cornerslist; + corners_count = aPolysListWithHoles.size(); + + unsigned ic = 0; + // enter main outline + while( ic < corners_count ) + { + const CPolyPt& corner = aPolysListWithHoles[ic++]; + cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) ); + + if( corner.end_contour ) + break; + } + bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() ); + mainpoly.push_back( poly_tmp ); + + while( ic < corners_count ) + { + cornerslist.clear(); + { + while( ic < corners_count ) + { + const CPolyPt& corner = aPolysListWithHoles[ic++]; + cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) ); + + if( corner.end_contour ) + break; + } + + bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() ); + polysholes.push_back( poly_tmp ); + } + } + + mainpoly -= polysholes; + + // copy polygon with no holes to destination + // We should have only one polygon in list + wxASSERT( mainpoly.size() != 1 ); + + { + KI_POLYGON& poly_nohole = mainpoly[0]; + CPolyPt corner( 0, 0, false ); + + for( unsigned jj = 0; jj < poly_nohole.size(); jj++ ) + { + KI_POLY_POINT point = *(poly_nohole.begin() + jj); + corner.x = point.x(); + corner.y = point.y(); + corner.end_contour = false; + aOnePolyList.push_back( corner ); + } + + corner.end_contour = true; + aOnePolyList.pop_back(); + aOnePolyList.push_back( corner ); + } +} diff --git a/polygon/PolyLine.h b/polygon/PolyLine.h index 468bf09f78..4bf31a5213 100644 --- a/polygon/PolyLine.h +++ b/polygon/PolyLine.h @@ -19,11 +19,12 @@ #include #include -#include +#include // for wxPoint definition + +#include // inflection modes for DS_LINE and DS_LINE_VERTEX, used in math_for_graphics.cpp -enum -{ +enum { IM_NONE = 0, IM_90_45, IM_45_90, @@ -44,15 +45,16 @@ public: wxPoint m_End; CSegment() { }; - CSegment( const wxPoint & aStart, const wxPoint & aEnd ) + CSegment( const wxPoint& aStart, const wxPoint& aEnd ) { m_Start = aStart; - m_End = aEnd; + m_End = aEnd; } + CSegment( int x0, int y0, int x1, int y1 ) { - m_Start.x = x0; m_Start.y = y0; - m_End.x = x1; m_End.y = y1; + m_Start.x = x0; m_Start.y = y0; + m_End.x = x1; m_End.y = y1; } }; @@ -63,10 +65,10 @@ class CArc { public: enum { ARC_STEPS = 16 }; // arc approximation step is 16 segm / 90 degres - int style; - int xi, yi, xf, yf; - int n_steps; // number of straight-line segments in gpc_poly - bool bFound; + int style; + int xi, yi, xf, yf; + int n_steps; // number of straight-line segments in gpc_poly + bool bFound; }; @@ -77,8 +79,8 @@ public: wxPoint( aX, aY ), end_contour( aEnd ), m_utility( aUtility ) {} - /// Pure copy constructor is here to dis-ambiguate from the - /// specialized CPolyPt( const wxPoint& ) constructor version below. + // / Pure copy constructor is here to dis-ambiguate from the + // / specialized CPolyPt( const wxPoint& ) constructor version below. CPolyPt( const CPolyPt& aPt ) : wxPoint( aPt.x, aPt.y ), end_contour( aPt.end_contour ), m_utility( aPt.m_utility ) {} @@ -88,13 +90,13 @@ public: {} - bool end_contour; - int m_utility; + bool end_contour; + int m_utility; - bool operator == (const CPolyPt& cpt2 ) const + bool operator ==( const CPolyPt& cpt2 ) const { return (x == cpt2.x) && (y == cpt2.y) && (end_contour == cpt2.end_contour); } - bool operator != (CPolyPt& cpt2 ) const + bool operator !=( CPolyPt& cpt2 ) const { return (x != cpt2.x) || (y != cpt2.y) || (end_contour != cpt2.end_contour); } }; @@ -112,13 +114,13 @@ public: ~CPolyLine(); // functions for modifying polyline - void Start( int layer, int x, int y, int hatch ); - void AppendCorner( int x, int y, int style = STRAIGHT, bool bDraw = false ); - 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 RemoveContour( int icont ); + void Start( int layer, int x, int y, int hatch ); + void AppendCorner( int x, int y, int style = STRAIGHT, bool bDraw = false ); + 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 RemoveContour( int icont ); /** * Function Chamfer @@ -126,7 +128,7 @@ public: * @param aDistance is the chamfering distance. * @return CPolyLine* - Pointer to new polygon. */ - CPolyLine* Chamfer( unsigned int aDistance ); + CPolyLine* Chamfer( unsigned int aDistance ); /** * Function Fillet @@ -135,108 +137,88 @@ public: * @param aSegments is the number of segments / fillet. * @return CPolyLine* - Pointer to new polygon. */ - CPolyLine* Fillet( unsigned int aRadius, unsigned int aSegments ); + CPolyLine* Fillet( unsigned int aRadius, unsigned int aSegments ); - void RemoveAllContours( void ); + void RemoveAllContours( void ); // Remove or create hatch - void UnHatch(); - void Hatch(); + void UnHatch(); + void Hatch(); // Transform functions - void MoveOrigin( int x_off, int y_off ); + void MoveOrigin( int x_off, int y_off ); // misc. functions - CRect GetBounds(); - CRect GetCornerBounds(); - CRect GetCornerBounds( int icont ); - void Copy( CPolyLine* src ); - bool TestPointInside( int x, int y ); - bool IsCutoutContour( int icont ); - void AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ); + CRect GetBounds(); + CRect GetCornerBounds(); + CRect GetCornerBounds( int icont ); + void Copy( CPolyLine* src ); + bool TestPointInside( int x, int y ); + bool IsCutoutContour( int icont ); + void AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ); // access functions void SetLayer( int aLayer ) { m_layer = aLayer; } int GetLayer() { return m_layer; } - int GetNumCorners(); - int GetNumSides(); - int GetClosed(); - int GetContoursCount(); - int GetContour( int ic ); - int GetContourStart( int icont ); - int GetContourEnd( int icont ); - int GetContourSize( int icont ); + int GetNumCorners(); + int GetNumSides(); + int GetClosed(); + int GetContoursCount(); + int GetContour( int ic ); + int GetContourStart( int icont ); + int GetContourEnd( int icont ); + int GetContourSize( int icont ); int GetX( int ic ) const { return m_CornersList[ic].x; } int GetY( int ic ) const { return m_CornersList[ic].y; } const wxPoint& GetPos( int ic ) const { return m_CornersList[ic]; } - int GetEndContour( int ic ); + int GetEndContour( int ic ); int GetUtility( int ic ) { return m_CornersList[ic].m_utility; }; void SetUtility( int ic, int utility ) { m_CornersList[ic].m_utility = utility; }; - int GetSideStyle( int is ); + int GetSideStyle( int is ); + int GetHatchPitch() { return m_hatchPitch; } - int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils + int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils enum hatch_style GetHatchStyle() { return m_hatchStyle; } void SetHatch( int hatch, int pitch ) - { - SetHatchPitch( pitch ); - m_hatchStyle = (enum hatch_style ) hatch; - Hatch(); - } - void SetX( int ic, int x ); - void SetY( int ic, int y ); - void SetEndContour( int ic, bool end_contour ); - void SetSideStyle( int is, int style ); + { + SetHatchPitch( pitch ); + m_hatchStyle = (enum hatch_style) hatch; + Hatch(); + } + + void SetX( int ic, int x ); + void SetY( int ic, int y ); + void SetEndContour( int ic, bool end_contour ); + void SetSideStyle( int is, int style ); + void SetHatchStyle( enum hatch_style style ) - { - m_hatchStyle = style; - } + { + m_hatchStyle = style; + } + void SetHatchPitch( int pitch ) { m_hatchPitch = pitch; } - int RestoreArcs( std::vector * arc_array, std::vector * pa = NULL ); + int RestoreArcs( std::vector* arc_array, std::vector* pa = NULL ); - int NormalizeAreaOutlines( std::vector * pa = NULL, - bool bRetainArcs = false ); + int NormalizeAreaOutlines( std::vector* pa = NULL, + bool bRetainArcs = false ); // KBOOL functions - /** - * Function AddPolygonsToBoolEng - * and edges contours to a kbool engine, preparing a boolean op between polygons - * @param aStart_contour: starting contour number (-1 = all, 0 is the outlines of zone, > 1 = holes in zone - * @param aEnd_contour: ending contour number (-1 = all after aStart_contour) - * @param arc_array: arc connverted to poly (NULL if not exists) - * @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, - int aStart_contour = -1, - int aEnd_contour = -1, - std::vector * arc_array = NULL ); - /** * Function MakeKboolPoly * fill a kbool engine with a closed polyline contour * approximates arcs with multiple straight-line segments - * @param aStart_contour: starting contour number (-1 = all, 0 is the outlines of zone, > 1 = holes in zone - * @param aEnd_contour: ending contour number (-1 = all after aStart_contour) * combining intersecting contours if possible * @param arc_array : return data on arcs in arc_array - * @param aConvertHoles = mode for holes when a boolean operation is made - * true: holes are linked into outer contours by double overlapping segments - * false: holes are not linked: in this mode contours are added clockwise - * and polygons added counter clockwise are holes (default) * @return error: 0 if Ok, 1 if error */ - int MakeKboolPoly( int aStart_contour = -1, - int aEnd_contour = -1, - std::vector * arc_array = NULL, - bool aConvertHoles = false); + int MakeKboolPoly( std::vector* arc_array = NULL ); /** * Function NormalizeWithKbool @@ -250,22 +232,11 @@ public: * @param bRetainArcs == false, try to retain arcs in polys * @return number of external contours, or -1 if error */ - int NormalizeWithKbool( std::vector * aExtraPolyList, bool bRetainArcs ); - - /** - * Function GetKboolEngine - * @return the current used Kbool Engine (after normalization using kbool) - */ - Bool_Engine* GetKboolEngine( ) { return m_Kbool_Poly_Engine; } - /** - * Function FreeKboolEngine - * delete the current used Kbool Engine (free memory after normalization using kbool) - */ - void FreeKboolEngine( ) { delete m_Kbool_Poly_Engine; m_Kbool_Poly_Engine = NULL; } + int NormalizeWithKbool( std::vector* aExtraPolyList, bool bRetainArcs ); // Bezier Support - void AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3); - void AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); + void AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3 ); + void AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); /** * Function Distance @@ -274,7 +245,7 @@ public: * @return int = distance between the point and outline. * 0 if the point is inside */ - int Distance( const wxPoint& aPoint ); + int Distance( const wxPoint& aPoint ); /** * Function Distance @@ -285,22 +256,44 @@ public: * @return int = distance between the segment and outline. * 0 if segment intersects or is inside */ - int Distance( wxPoint aStart, wxPoint aEnd, int aWidth ); + int Distance( wxPoint aStart, wxPoint aEnd, int aWidth ); 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 - 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 - int m_utility; // a flag used in some calculations - Bool_Engine* m_Kbool_Poly_Engine; // polygons set in kbool engine data - + 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 + 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 + int m_utility; // a flag used in some calculations + Bool_Engine* m_Kbool_Poly_Engine; // polygons set in kbool engine data public: - std::vector m_CornersList; // array of points for corners - std::vector m_SideStyle; // array of styles for sides - std::vector m_HatchLines; // hatch lines showing the polygon area + std::vector m_CornersList; // array of points for corners + std::vector m_SideStyle; // array of styles for sides + std::vector m_HatchLines; // hatch lines showing the polygon area }; -#endif // #ifndef POLYLINE_H +/** + * Function CopyPolysListToKiPolygonWithHole + * converts the outline contours aPolysList to a KI_POLYGON_WITH_HOLES + * + * @param aPolysList = the list of corners of contours + * @param aPolygoneWithHole = a KI_POLYGON_WITH_HOLES to populate + */ +void CopyPolysListToKiPolygonWithHole( const std::vector& aPolysList, + KI_POLYGON_WITH_HOLES& aPolygoneWithHole ); + + +/** + * Function ConvertPolysListWithHolesToOnePolygon + * converts the outline contours aPolysListWithHoles with holes to one polygon + * with no holes (only one contour) + * holes are linked to main outlines by overlap segments, to give only one polygon + * + * @param aPolysListWithHoles = the list of corners of contours (haing holes + * @param aOnePolyList = a polygon with no holes + */ +void ConvertPolysListWithHolesToOnePolygon( const std::vector& aPolysListWithHoles, + std::vector& aOnePolyList ); + +#endif // #ifndef POLYLINE_H diff --git a/pcbnew/polygons_defs.h b/polygon/polygons_defs.h similarity index 100% rename from pcbnew/polygons_defs.h rename to polygon/polygons_defs.h