Commit ef39c5f3 authored by jean-pierre charras's avatar jean-pierre charras

PolyLine and math_for_graphics code cleanup: remove arc support in CPolyLine class:

This is an obscure legacy code from FreePCB, never used, never tested, never maintained.
parents 474128a4 90a6daa7
...@@ -1041,7 +1041,7 @@ public: ...@@ -1041,7 +1041,7 @@ public:
* @param aLayer = the layer of area * @param aLayer = the layer of area
* @param aStartPointPosition = position of the first point of the polygon outline of this area * @param aStartPointPosition = position of the first point of the polygon outline of this area
* @param aHatch = hatch option * @param aHatch = hatch option
* @return pointer to the new area * @return a reference to the new area
*/ */
ZONE_CONTAINER* AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, ZONE_CONTAINER* AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode,
int aLayer, wxPoint aStartPointPosition, int aHatch ); int aLayer, wxPoint aStartPointPosition, int aHatch );
...@@ -1054,58 +1054,30 @@ public: ...@@ -1054,58 +1054,30 @@ public:
ZONE_CONTAINER* InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch ); ZONE_CONTAINER* InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch );
/** /**
* Function TestAreaPolygon * Function NormalizeAreaPolygon
* Test an area for self-intersection. * Process an area that has been modified, by normalizing its polygon against itself.
* * i.e. convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
* @param CurrArea = copper area to test
* @return :
* -1 if arcs intersect other sides
* 0 if no intersecting sides
* 1 if intersecting sides, but no intersecting arcs
* Also sets utility2 flag of area with return value
*/
int TestAreaPolygon( ZONE_CONTAINER* CurrArea );
/**
* Function ClipAreaPolygon
* Process an area that has been modified, by clipping its polygon against itself.
* This may change the number and order of copper areas in the net. * This may change the number and order of copper areas in the net.
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful * @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new created areas pickers
* in undo commands) can be NULL
* @param aCurrArea = the zone to process * @param aCurrArea = the zone to process
* @param bMessageBoxInt == true, shows message when clipping occurs. * @return true if changes are made
* @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs.
* @param bRetainArcs = true to handle arcs (not really used in KiCad)
* @return :
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides
* Also sets areas->utility1 flags if areas are modified * Also sets areas->utility1 flags if areas are modified
*/ */
int ClipAreaPolygon( PICKED_ITEMS_LIST* aNewZonesList, bool NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
ZONE_CONTAINER* aCurrArea, ZONE_CONTAINER* aCurrArea );
bool bMessageBoxArc,
bool bMessageBoxInt,
bool bRetainArcs = true );
/** /**
* Process an area that has been modified, by clipping its polygon against * Function OnAreaPolygonModified
* itself and the polygons for any other areas on the same net. * Process an area that has been modified, by normalizing its polygon
* and merging the intersecting polygons for any other areas on the same net.
* This may change the number and order of copper areas in the net. * This may change the number and order of copper areas in the net.
* @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas * @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas
* (useful in undo commands. Can be NULL * (useful in undo commands can be NULL
* @param modified_area = area to test * @param modified_area = area to test
* @param bMessageBoxInt : if true, shows message boxes when clipping occurs. * @return true if some areas modified
* @param bMessageBoxArc if true, shows message when clipping can't be done due to arcs. */
* @return : bool OnAreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
* -1 if arcs intersect other sides, so polygon can't be clipped ZONE_CONTAINER* modified_area );
* 0 if no intersecting sides
* 1 if intersecting sides, polygon clipped
*/
int AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area,
bool bMessageBoxArc,
bool bMessageBoxInt );
/** /**
* Function CombineAllAreasInNet * Function CombineAllAreasInNet
...@@ -1113,15 +1085,13 @@ public: ...@@ -1113,15 +1085,13 @@ public:
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful
* in undo commands can be NULL * in undo commands can be NULL
* @param aNetCode = net to consider * @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box * @param aUseUtility : if true, don't check areas if both utility flags are 0
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* Sets utility flag = 1 for any areas modified * Sets utility flag = 1 for any areas modified
* If an area has self-intersecting arcs, doesn't try to combine it * @return true if some areas modified
*/ */
int CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, bool CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList,
int aNetCode, int aNetCode,
bool bMessageBox, bool aUseUtility );
bool bUseUtility );
/** /**
* Function RemoveArea * Function RemoveArea
...@@ -1154,19 +1124,17 @@ public: ...@@ -1154,19 +1124,17 @@ public:
/** /**
* Function CombineAreas * Function CombineAreas
* If possible, combine 2 copper areas * If possible, combine 2 copper areas
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas
* in undo commands can be NULL * (useful for undo).
* @param area_ref = the main area (zone) * @param area_ref = the main area (zone)
* @param area_to_combine = the zone that can be merged with area_ref * @param area_to_combine = the zone that can be merged with area_ref
* area_ref must be BEFORE area_to_combine * area_ref must be BEFORE area_to_combine
* area_to_combine will be deleted, if areas are combined * area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection * @return : true if area_to_combine is combined with area_ref (and therefore be deleted)
* 1 if intersection
* 2 if arcs intersect
*/ */
int CombineAreas( PICKED_ITEMS_LIST* aDeletedList, bool CombineAreas( PICKED_ITEMS_LIST* aDeletedList,
ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ref,
ZONE_CONTAINER* area_to_combine ); ZONE_CONTAINER* area_to_combine );
/** /**
* Function Test_Drc_Areas_Outlines_To_Areas_Outlines * Function Test_Drc_Areas_Outlines_To_Areas_Outlines
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <class_board.h> #include <class_board.h>
#include <class_module.h> #include <class_module.h>
#include <polygon_test_point_inside.h>
int D_PAD::m_PadSketchModePenSize = 0; // Pen size used to draw pads in sketch mode int D_PAD::m_PadSketchModePenSize = 0; // Pen size used to draw pads in sketch mode
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <pcbnew.h> #include <pcbnew.h>
#include <zones.h> #include <zones.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
#include <polygon_test_point_inside.h>
ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) : ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) :
...@@ -65,7 +66,6 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) : ...@@ -65,7 +66,6 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) :
SetDoNotAllowTracks( true ); // has meaning only if m_isKeepout == true SetDoNotAllowTracks( true ); // has meaning only if m_isKeepout == true
m_cornerRadius = 0; m_cornerRadius = 0;
utility = 0; // flags used in polygon calculations utility = 0; // flags used in polygon calculations
utility2 = 0; // flags used in polygon calculations
m_Poly = new CPolyLine(); // Outlines m_Poly = new CPolyLine(); // Outlines
aBoard->GetZoneSettings().ExportSetting( *this ); aBoard->GetZoneSettings().ExportSetting( *this );
} }
...@@ -102,7 +102,6 @@ ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone ) : ...@@ -102,7 +102,6 @@ ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone ) :
utility = aZone.utility; utility = aZone.utility;
utility2 = aZone.utility;
} }
......
...@@ -573,7 +573,7 @@ public: ...@@ -573,7 +573,7 @@ public:
// thickness of the copper bridge in thermal reliefs // thickness of the copper bridge in thermal reliefs
int m_ThermalReliefCopperBridge; int m_ThermalReliefCopperBridge;
int utility, utility2; // flags used in polygon calculations int utility; // flags used in polygon calculations
// true when a zone was filled, false after deleting the filled areas // true when a zone was filled, false after deleting the filled areas
bool m_IsFilled; bool m_IsFilled;
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <class_zone.h> #include <class_zone.h>
#include <class_marker_pcb.h> #include <class_marker_pcb.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
#include <polygon_test_point_inside.h>
/* compare 2 trapezoids (can be rectangle) and return true if distance > aDist /* compare 2 trapezoids (can be rectangle) and return true if distance > aDist
......
...@@ -44,8 +44,6 @@ ...@@ -44,8 +44,6 @@
#include <zones_functions_for_undo_redo.h> #include <zones_functions_for_undo_redo.h>
#include <drc_stuff.h> #include <drc_stuff.h>
bool s_Verbose = false; // false if zone outline diags must not be shown
// Outline creation: // Outline creation:
static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC ); static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC );
static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC, static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
...@@ -141,7 +139,7 @@ void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ) ...@@ -141,7 +139,7 @@ void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone )
GetScreen()->SetCurItem( NULL ); // This outline may be deleted when merging outlines GetScreen()->SetCurItem( NULL ); // This outline may be deleted when merging outlines
// Combine zones if possible // Combine zones if possible
GetBoard()->AreaPolygonModified( &_AuxiliaryList, newZone, true, s_Verbose ); GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, newZone );
// Redraw zones // Redraw zones
GetBoard()->RedrawAreasOutlines( m_canvas, aDC, GR_OR, newZone->GetLayer() ); GetBoard()->RedrawAreasOutlines( m_canvas, aDC, GR_OR, newZone->GetLayer() );
...@@ -334,7 +332,7 @@ void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* ...@@ -334,7 +332,7 @@ void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER*
// Combine zones if possible // Combine zones if possible
wxBusyCursor dummy; wxBusyCursor dummy;
GetBoard()->AreaPolygonModified( &_AuxiliaryList, aZone, true, s_Verbose ); GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone );
m_canvas->Refresh(); m_canvas->Refresh();
...@@ -389,7 +387,7 @@ void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone ) ...@@ -389,7 +387,7 @@ void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone )
aZone->m_Poly->DeleteCorner( aZone->m_CornerSelection ); aZone->m_Poly->DeleteCorner( aZone->m_CornerSelection );
// modify zones outlines according to the new aZone shape // modify zones outlines according to the new aZone shape
GetBoard()->AreaPolygonModified( &_AuxiliaryList, aZone, true, s_Verbose ); GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone );
if( DC ) if( DC )
{ {
...@@ -768,7 +766,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC ) ...@@ -768,7 +766,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC )
GetScreen()->SetCurItem( NULL ); // This outline can be deleted when merging outlines GetScreen()->SetCurItem( NULL ); // This outline can be deleted when merging outlines
// Combine zones if possible : // Combine zones if possible :
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone, true, s_Verbose ); GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, zone );
// Redraw the real edge zone : // Redraw the real edge zone :
GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer ); GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
...@@ -898,7 +896,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) ...@@ -898,7 +896,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone )
aZone->SetNetName( net->GetNetname() ); aZone->SetNetName( net->GetNetname() );
// Combine zones if possible // Combine zones if possible
GetBoard()->AreaPolygonModified( &_AuxiliaryList, aZone, true, s_Verbose ); GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone );
// Redraw the real new zone outlines // Redraw the real new zone outlines
GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, -1 ); GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, -1 );
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <pcbnew.h> #include <pcbnew.h>
#include <zones.h> #include <zones.h>
#include <polygon_test_point_inside.h>
/** /**
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <algorithm> // sort #include <algorithm> // sort
#include <fctsys.h> #include <fctsys.h>
#include <common.h> #include <common.h>
#include <macros.h> #include <macros.h>
...@@ -40,6 +39,7 @@ ...@@ -40,6 +39,7 @@
#include <pcbnew.h> #include <pcbnew.h>
#include <zones.h> #include <zones.h>
#include <polygon_test_point_inside.h>
static bool CmpZoneSubnetValue( const BOARD_CONNECTED_ITEM* a, const BOARD_CONNECTED_ITEM* b ); static bool CmpZoneSubnetValue( const BOARD_CONNECTED_ITEM* a, const BOARD_CONNECTED_ITEM* b );
void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode ); void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode );
......
...@@ -43,11 +43,7 @@ ...@@ -43,11 +43,7 @@
#include <drc_stuff.h> #include <drc_stuff.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
#define STRAIGHT 0 // To be remove after math_for_graphics code cleanup
static bool bDontShowSelfIntersectionArcsWarning;
static bool bDontShowSelfIntersectionWarning;
static bool bDontShowIntersectionArcsWarning;
/** /**
* Function AddArea * Function AddArea
...@@ -126,199 +122,31 @@ ZONE_CONTAINER* BOARD::InsertArea( int netcode, int iarea, int layer, int x, int ...@@ -126,199 +122,31 @@ ZONE_CONTAINER* BOARD::InsertArea( int netcode, int iarea, int layer, int x, int
/** /**
* Function TestAreaPolygon * Function NormalizeAreaPolygon
* Test an area for self-intersection. * Process an area that has been modified, by normalizing its polygon against itself.
* * i.e. convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
* @param CurrArea = copper area to test
* @return :
* -1 if arcs intersect other sides
* 0 if no intersecting sides
* 1 if intersecting sides, but no intersecting arcs
* Also sets utility2 flag of area with return value
*/
int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea )
{
CPolyLine* p = CurrArea->m_Poly;
// first, check for sides intersecting other sides, especially arcs
bool bInt = false;
bool bArcInt = false;
int n_cont = p->GetContoursCount();
// make bounding rect for each contour
std::vector<CRect> cr;
cr.reserve( n_cont );
for( int icont = 0; icont<n_cont; icont++ )
cr.push_back( p->GetCornerBounds( icont ) );
for( int icont = 0; icont<n_cont; icont++ )
{
int is_start = p->GetContourStart( icont );
int is_end = p->GetContourEnd( icont );
for( int is = is_start; is<=is_end; is++ )
{
int is_prev = is - 1;
if( is_prev < is_start )
is_prev = is_end;
int is_next = is + 1;
if( is_next > is_end )
is_next = is_start;
int style = p->GetSideStyle( is );
int x1i = p->GetX( is );
int y1i = p->GetY( is );
int x1f = p->GetX( is_next );
int y1f = p->GetY( is_next );
// check for intersection with any other sides
for( int icont2 = icont; icont2<n_cont; icont2++ )
{
if( cr[icont].left > cr[icont2].right
|| cr[icont].bottom > cr[icont2].top
|| cr[icont2].left > cr[icont].right
|| cr[icont2].bottom > cr[icont].top )
{
// rectangles don't overlap, do nothing
}
else
{
int is2_start = p->GetContourStart( icont2 );
int is2_end = p->GetContourEnd( icont2 );
for( int is2 = is2_start; is2<=is2_end; is2++ )
{
int is2_prev = is2 - 1;
if( is2_prev < is2_start )
is2_prev = is2_end;
int is2_next = is2 + 1;
if( is2_next > is2_end )
is2_next = is2_start;
if( icont != icont2
|| (is2 != is && is2 != is_prev && is2 != is_next && is != is2_prev
&& is !=
is2_next ) )
{
int style2 = p->GetSideStyle( is2 );
int x2i = p->GetX( is2 );
int y2i = p->GetY( is2 );
int x2f = p->GetX( is2_next );
int y2f = p->GetY( is2_next );
int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f, style,
x2i, y2i, x2f, y2f, style2 );
if( ret )
{
// intersection between non-adjacent sides
bInt = true;
if( style != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT )
{
bArcInt = true;
break;
}
}
}
}
}
if( bArcInt )
break;
}
if( bArcInt )
break;
}
if( bArcInt )
break;
}
if( bArcInt )
CurrArea->utility2 = -1;
else if( bInt )
CurrArea->utility2 = 1;
else
CurrArea->utility2 = 0;
return CurrArea->utility2;
}
/**
* Function ClipAreaPolygon
* Process an area that has been modified, by clipping its polygon against itself.
* This may change the number and order of copper areas in the net. * This may change the number and order of copper areas in the net.
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in * @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new created areas
* undo commands) can be NULL
* @param aCurrArea = the zone to process * @param aCurrArea = the zone to process
* @param bMessageBoxInt == true, shows message when clipping occurs. * @return true if changes are made
* @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs.
* @param bRetainArcs = true to handle arcs (not really used in KiCad)
* @return
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides
* Also sets areas->utility1 flags if areas are modified * Also sets areas->utility1 flags if areas are modified
*/ */
int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, bool BOARD::NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
ZONE_CONTAINER* aCurrArea, ZONE_CONTAINER* aCurrArea )
bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs )
{ {
CPolyLine* curr_polygon = aCurrArea->m_Poly; CPolyLine* curr_polygon = aCurrArea->m_Poly;
int test = TestAreaPolygon( aCurrArea ); // this sets utility2 flag
if( test == -1 && !bRetainArcs )
test = 1;
if( test == -1 )
{
// arc intersections, don't clip unless bRetainArcs == false
if( bMessageBoxArc && bDontShowSelfIntersectionArcsWarning == false )
{
wxString str;
str.Printf( wxT( "Area %08lX of net \"%s\" has arcs intersecting other sides.\n" ),
aCurrArea->GetTimeStamp(), GetChars( aCurrArea->GetNetName() ) );
str += wxT( "This may cause problems with other editing operations,\n" );
str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" );
str += wxT( "Manual correction is recommended." );
wxMessageBox( str );
}
return -1; // arcs intersect with other sides, error
}
// mark all areas as unmodified except this one // mark all areas as unmodified except this one, if modified
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
m_ZoneDescriptorList[ia]->utility = 0; m_ZoneDescriptorList[ia]->utility = 0;
aCurrArea->utility = 1; aCurrArea->utility = 1;
if( test == 1 ) if( curr_polygon->IsPolygonSelfIntersecting() )
{
// non-arc intersections, clip the polygon
if( bMessageBoxInt && bDontShowSelfIntersectionWarning == false )
{
wxString str;
str.Printf( wxT( "Area %08lX of net \"%s\" is self-intersecting and will be clipped.\n" ),
aCurrArea->GetTimeStamp(), GetChars( aCurrArea->GetNetName() ) );
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 );
}
}
{ {
std::vector<CPolyLine*>* pa = new std::vector<CPolyLine*>; std::vector<CPolyLine*>* pa = new std::vector<CPolyLine*>;
curr_polygon->UnHatch(); curr_polygon->UnHatch();
int n_poly = aCurrArea->m_Poly->NormalizeAreaOutlines( pa, bRetainArcs ); int n_poly = aCurrArea->m_Poly->NormalizeAreaOutlines( pa );
// 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 ) if( n_poly > 1 )
...@@ -340,60 +168,45 @@ int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, ...@@ -340,60 +168,45 @@ int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
NewArea->utility = 1; NewArea->utility = 1;
} }
} }
curr_polygon->Hatch();
delete pa; delete pa;
} }
return test; curr_polygon->Hatch();
return true;
} }
/** /**
* Process an area that has been modified, by clipping its polygon against * Process an area that has been modified, by normalizing its polygon
* itself and the polygons for any other areas on the same net. * and merging the intersecting polygons for any other areas on the same net.
* This may change the number and order of copper areas in the net. * This may change the number and order of copper areas in the net.
* @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas * @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas
* (useful in undo commands can be NULL * (useful in undo commands can be NULL
* @param modified_area = area to test * @param modified_area = area to test
* @param bMessageBoxArc if true, shows message when clipping can't be done due to arcs. * @return true if some areas modified
* @param bMessageBoxInt == true, shows message when clipping occurs.
* @return :
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides, polygon clipped
*/ */
int BOARD::AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList, bool BOARD::OnAreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area, ZONE_CONTAINER* modified_area )
bool bMessageBoxArc,
bool bMessageBoxInt )
{ {
// clip polygon against itself // clip polygon against itself
int test = ClipAreaPolygon( aModifiedZonesList, modified_area, bMessageBoxArc, bMessageBoxInt ); bool modified = NormalizeAreaPolygon( aModifiedZonesList, modified_area );
if( test == -1 )
return test;
// now see if we need to clip against other areas // now see if we need to clip against other areas
int layer = modified_area->GetLayer(); int layer = modified_area->GetLayer();
bool bCheckAllAreas = false; bool bCheckAllAreas = TestAreaIntersections( modified_area );
if( test == 1 )
bCheckAllAreas = true;
else
bCheckAllAreas = TestAreaIntersections( modified_area );
if( bCheckAllAreas ) if( bCheckAllAreas )
CombineAllAreasInNet( aModifiedZonesList, modified_area->GetNet(), bMessageBoxInt, true ); {
modified = true;
CombineAllAreasInNet( aModifiedZonesList, modified_area->GetNet(), true );
}
if( layer >= FIRST_NO_COPPER_LAYER ) // Refill non copper zones on this layer if( layer >= FIRST_NO_COPPER_LAYER ) // Refill non copper zones on this layer
{ {
if( m_ZoneDescriptorList.size() > 0 ) for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
{ if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) m_ZoneDescriptorList[ia]->BuildFilledPolysListData( this );
if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
m_ZoneDescriptorList[ia]->BuildFilledPolysListData( this );
}
} }
// Test for bad areas: all zones must have more than 2 corners: // Test for bad areas: all zones must have more than 2 corners:
...@@ -408,33 +221,29 @@ int BOARD::AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList, ...@@ -408,33 +221,29 @@ int BOARD::AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
RemoveArea( aModifiedZonesList, zone ); RemoveArea( aModifiedZonesList, zone );
} }
return test; return modified;
} }
/** /**
* Function CombineAllAreasInNet * Function CombineAllAreasInNet
* Checks all copper areas in net for intersections, combining them if found * Checks all copper areas in net for intersections, combining them if found
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful
* undo commands can be NULL * in undo commands can be NULL
* @param aNetCode = net to consider * @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box * @param aUseUtility : if true, don't check areas if both utility flags are 0
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* Sets utility flag = 1 for any areas modified * Sets utility flag = 1 for any areas modified
* If an area has self-intersecting arcs, doesn't try to combine it * @return true if some areas modified
*/ */
int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
bool bMessageBox, bool bUseUtility ) bool aUseUtility )
{ {
if( m_ZoneDescriptorList.size() <= 1 ) if( m_ZoneDescriptorList.size() <= 1 )
return 0; return false;
// start by testing all area polygons to set utility2 flags bool modified = false;
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
if( m_ZoneDescriptorList[ia]->GetNet() == aNetCode )
TestAreaPolygon( m_ZoneDescriptorList[ia] );
// now loop through all combinations //Loop through all combinations
for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ia1++ ) for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ia1++ )
{ {
ZONE_CONTAINER* curr_area = m_ZoneDescriptorList[ia1]; ZONE_CONTAINER* curr_area = m_ZoneDescriptorList[ia1];
...@@ -458,15 +267,14 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, ...@@ -458,15 +267,14 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
if( curr_area->GetIsKeepout() != area2->GetIsKeepout() ) if( curr_area->GetIsKeepout() != area2->GetIsKeepout() )
continue; continue;
if( curr_area->GetLayer() == area2->GetLayer() if( curr_area->GetLayer() == area2->GetLayer() )
&& curr_area->utility2 != -1 && area2->utility2 != -1 )
{ {
CRect b2 = area2->m_Poly->GetCornerBounds(); CRect b2 = area2->m_Poly->GetCornerBounds();
if( !( b1.left > b2.right || b1.right < b2.left if( !( b1.left > b2.right || b1.right < b2.left
|| b1.bottom > b2.top || b1.top < b2.bottom ) ) || b1.bottom > b2.top || b1.top < b2.bottom ) )
{ {
// check area2 against curr_area // check area2 against curr_area
if( curr_area->utility || area2->utility || bUseUtility == false ) if( curr_area->utility || area2->utility || aUseUtility == false )
{ {
int ret = TestAreaIntersection( curr_area, area2 ); int ret = TestAreaIntersection( curr_area, area2 );
...@@ -476,19 +284,7 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, ...@@ -476,19 +284,7 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
if( ret == 1 ) if( ret == 1 )
{ {
mod_ia1 = true; mod_ia1 = true;
} modified = true;
else if( ret == 2 )
{
if( bMessageBox && bDontShowIntersectionArcsWarning == false )
{
wxString str;
str.Printf( wxT( "Areas %d and %d of net \"%s\" intersect, but some of the intersecting sides are arcs.\n" ),
ia1 + 1,
ia2 + 1,
GetChars( curr_area->GetNetName() ) );
str += wxT( "Therefore, these areas can't be combined." );
wxMessageBox( str );
}
} }
} }
} }
...@@ -499,7 +295,7 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, ...@@ -499,7 +295,7 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
ia1--; // if modified, we need to check it again ia1--; // if modified, we need to check it again
} }
return 0; return modified;
} }
...@@ -556,7 +352,7 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) ...@@ -556,7 +352,7 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
{ {
int xi1 = poly1->GetX( ic1 ); int xi1 = poly1->GetX( ic1 );
int yi1 = poly1->GetY( ic1 ); int yi1 = poly1->GetY( ic1 );
int xf1, yf1, style1; int xf1, yf1;
if( ic1 < ie1 ) if( ic1 < ie1 )
{ {
...@@ -569,8 +365,6 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) ...@@ -569,8 +365,6 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
yf1 = poly1->GetY( is1 ); yf1 = poly1->GetY( is1 );
} }
style1 = poly1->GetSideStyle( ic1 );
for( int icont2 = 0; icont2 < poly2->GetContoursCount(); icont2++ ) for( int icont2 = 0; icont2 < poly2->GetContoursCount(); icont2++ )
{ {
int is2 = poly2->GetContourStart( icont2 ); int is2 = poly2->GetContourStart( icont2 );
...@@ -580,7 +374,7 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) ...@@ -580,7 +374,7 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
{ {
int xi2 = poly2->GetX( ic2 ); int xi2 = poly2->GetX( ic2 );
int yi2 = poly2->GetY( ic2 ); int yi2 = poly2->GetY( ic2 );
int xf2, yf2, style2; int xf2, yf2;
if( ic2 < ie2 ) if( ic2 < ie2 )
{ {
...@@ -593,9 +387,8 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) ...@@ -593,9 +387,8 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
yf2 = poly2->GetY( is2 ); yf2 = poly2->GetY( is2 );
} }
style2 = poly2->GetSideStyle( ic2 ); int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1,
int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, xi2, yi2, xf2, yf2 );
xi2, yi2, xf2, yf2, style2 );
if( n_int ) if( n_int )
return true; return true;
} }
...@@ -640,7 +433,6 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) ...@@ -640,7 +433,6 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
* @param area_to_test = area to compare for intersection calculations * @param area_to_test = area to compare for intersection calculations
* @return : 0 if no intersection * @return : 0 if no intersection
* 1 if intersection * 1 if intersection
* 2 if arcs intersect
*/ */
int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_test ) int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_test )
{ {
...@@ -655,15 +447,12 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ ...@@ -655,15 +447,12 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
CRect b1 = poly1->GetCornerBounds(); CRect b1 = poly1->GetCornerBounds();
CRect b2 = poly2->GetCornerBounds(); CRect b2 = poly2->GetCornerBounds();
if( b1.bottom > b2.top if( b1.bottom > b2.top || b1.top < b2.bottom ||
|| b1.top < b2.bottom b1.left > b2.right || b1.right < b2.left )
|| b1.left > b2.right
|| b1.right < b2.left )
return 0; return 0;
// now test for intersecting segments // now test for intersecting segments
bool bInt = false; bool bInt = false;
bool bArcInt = false;
for( int icont1 = 0; icont1<poly1->GetContoursCount(); icont1++ ) for( int icont1 = 0; icont1<poly1->GetContoursCount(); icont1++ )
{ {
...@@ -674,7 +463,7 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ ...@@ -674,7 +463,7 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
{ {
int xi1 = poly1->GetX( ic1 ); int xi1 = poly1->GetX( ic1 );
int yi1 = poly1->GetY( ic1 ); int yi1 = poly1->GetY( ic1 );
int xf1, yf1, style1; int xf1, yf1;
if( ic1 < ie1 ) if( ic1 < ie1 )
{ {
...@@ -687,8 +476,6 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ ...@@ -687,8 +476,6 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
yf1 = poly1->GetY( is1 ); yf1 = poly1->GetY( is1 );
} }
style1 = poly1->GetSideStyle( ic1 );
for( int icont2 = 0; icont2<poly2->GetContoursCount(); icont2++ ) for( int icont2 = 0; icont2<poly2->GetContoursCount(); icont2++ )
{ {
int is2 = poly2->GetContourStart( icont2 ); int is2 = poly2->GetContourStart( icont2 );
...@@ -698,7 +485,7 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ ...@@ -698,7 +485,7 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
{ {
int xi2 = poly2->GetX( ic2 ); int xi2 = poly2->GetX( ic2 );
int yi2 = poly2->GetY( ic2 ); int yi2 = poly2->GetY( ic2 );
int xf2, yf2, style2; int xf2, yf2;
if( ic2 < ie2 ) if( ic2 < ie2 )
{ {
...@@ -711,37 +498,20 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ ...@@ -711,37 +498,20 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
yf2 = poly2->GetY( is2 ); yf2 = poly2->GetY( is2 );
} }
style2 = poly2->GetSideStyle( ic2 ); int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1,
int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, xi2, yi2, xf2, yf2 );
xi2, yi2, xf2, yf2, style2 );
if( n_int ) if( n_int )
{ {
bInt = true; bInt = true;
if( style1 != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT )
bArcInt = true;
break; break;
} }
} }
if( bArcInt )
break;
} }
if( bArcInt )
break;
} }
if( bArcInt )
break;
} }
if( !bInt ) if( !bInt )
{ {
if( bArcInt )
return 0;
// If a contour is inside an other contour, no segments intersects, but the zones // If a contour is inside an other contour, no segments intersects, but the zones
// can be combined test a corner inside an outline (only one corner is enought) // can be combined test a corner inside an outline (only one corner is enought)
for( int ic2 = 0; ic2 < poly2->GetNumCorners(); ic2++ ) for( int ic2 = 0; ic2 < poly2->GetNumCorners(); ic2++ )
...@@ -769,9 +539,6 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ ...@@ -769,9 +539,6 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
return 0; return 0;
} }
if( bArcInt )
return 2;
return 1; return 1;
} }
...@@ -779,24 +546,22 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ ...@@ -779,24 +546,22 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
/** /**
* Function CombineAreas * Function CombineAreas
* Merge 2 copper areas (which are expected intersecting) * Merge 2 copper areas (which are expected intersecting)
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas
* commands can be NULL * (useful for undo command)
* @param area_ref = the main area (zone) * @param area_ref = the main area (zone)
* @param area_to_combine = the zone that can be merged with area_ref * @param area_to_combine = the zone that can be merged with area_ref
* area_ref must be BEFORE area_to_combine * area_ref must be BEFORE area_to_combine
* area_to_combine will be deleted, if areas are combined * area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection * @return : true if area_to_combine is combined with area_ref (and therefore be deleted)
* 1 if intersection
* 2 if arcs intersect (Currently not supported)
*/ */
int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref, bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref,
ZONE_CONTAINER* area_to_combine ) ZONE_CONTAINER* area_to_combine )
{ {
if( area_ref == area_to_combine ) if( area_ref == area_to_combine )
{ {
wxASSERT( 0 ); wxASSERT( 0 );
return 0; return false;
} }
// polygons intersect, combine them // polygons intersect, combine them
...@@ -920,7 +685,7 @@ int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_r ...@@ -920,7 +685,7 @@ int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_r
area_ref->utility = 1; area_ref->utility = 1;
area_ref->m_Poly->Hatch(); area_ref->m_Poly->Hatch();
return 1; return true;
} }
...@@ -1054,8 +819,6 @@ int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_E ...@@ -1054,8 +819,6 @@ int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_E
ay2 = refSmoothedPoly->GetY( ic + 1 ); ay2 = refSmoothedPoly->GetY( ic + 1 );
} }
int astyle = refSmoothedPoly->GetSideStyle( ic );
for( int icont2 = 0; icont2 < testSmoothedPoly->GetContoursCount(); icont2++ ) for( int icont2 = 0; icont2 < testSmoothedPoly->GetContoursCount(); icont2++ )
{ {
int ic_start2 = testSmoothedPoly->GetContourStart( icont2 ); int ic_start2 = testSmoothedPoly->GetContourStart( icont2 );
...@@ -1078,13 +841,11 @@ int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_E ...@@ -1078,13 +841,11 @@ int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_E
by2 = testSmoothedPoly->GetY( ic2 + 1 ); by2 = testSmoothedPoly->GetY( ic2 + 1 );
} }
int bstyle = testSmoothedPoly->GetSideStyle( ic2 );
int x, y; int x, y;
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle, int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
0, 0,
ax1, ay1, ax2, ax1, ay1, ax2, ay2,
ay2, astyle,
0, 0,
zone2zoneClearance, zone2zoneClearance,
&x, &y ); &x, &y );
...@@ -1196,7 +957,6 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) ...@@ -1196,7 +957,6 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex )
} }
// now test spacing between areas // now test spacing between areas
int astyle = CPolyLine::STRAIGHT;
int ax1 = start.x; int ax1 = start.x;
int ay1 = start.y; int ay1 = start.y;
int ax2 = end.x; int ax2 = end.x;
...@@ -1224,11 +984,10 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) ...@@ -1224,11 +984,10 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex )
by2 = area_to_test->m_Poly->GetY( ic2 + 1 ); by2 = area_to_test->m_Poly->GetY( ic2 + 1 );
} }
int bstyle = area_to_test->m_Poly->GetSideStyle( ic2 );
int x, y; // variables containing the intersecting point coordinates int x, y; // variables containing the intersecting point coordinates
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle, int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
0, 0,
ax1, ay1, ax2, ay2, astyle, ax1, ay1, ax2, ay2,
0, 0,
zone_clearance, zone_clearance,
&x, &y ); &x, &y );
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include <bezier_curves.h> #include <bezier_curves.h>
#include <polygon_test_point_inside.h> #include <polygon_test_point_inside.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
#include <polygon_test_point_inside.h>
enum m_SideStyle { STRAIGHT }; // side styles
CPolyLine::CPolyLine() CPolyLine::CPolyLine()
{ {
...@@ -57,12 +61,11 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); ...@@ -57,12 +61,11 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false );
* because copper areas have only one outside contour * because copper areas have only one outside contour
* Therefore, if this results in new CPolyLines, return them as std::vector pa * Therefore, if this results in new CPolyLines, return them as std::vector pa
* @param aExtraPolyList: pointer on a std::vector<CPolyLine*> to store extra CPolyLines * @param aExtraPolyList: pointer on a std::vector<CPolyLine*> to store extra CPolyLines
* @param bRetainArcs == true, try to retain arcs in polys * (when after normalization, there is more than one polygon with holes)
* @return number of external contours, or -1 if error * @return number of external contours, or -1 if error
*/ */
int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool bRetainArcs ) int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList )
{ {
std::vector<CArc> arc_array;
std::vector <void*> hole_array; // list of holes std::vector <void*> hole_array; // list of holes
std::vector<int>* hole; // used to store corners for a given hole std::vector<int>* hole; // used to store corners for a given hole
CPolyLine* polyline; CPolyLine* polyline;
...@@ -74,10 +77,7 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool ...@@ -74,10 +77,7 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool
* will be converted in non self crossing polygons by inserting extra points at the crossing locations * will be converted in non self crossing polygons by inserting extra points at the crossing locations
* True holes are combined if possible * True holes are combined if possible
*/ */
if( bRetainArcs ) MakeKboolPoly();
MakeKboolPoly( &arc_array );
else
MakeKboolPoly( NULL );
UnHatch(); UnHatch();
...@@ -111,7 +111,6 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool ...@@ -111,7 +111,6 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool
{ {
// first external contour, replace this poly // first external contour, replace this poly
m_CornersList.clear(); m_CornersList.clear();
m_SideStyle.clear();
bool first = true; bool first = true;
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
...@@ -203,16 +202,13 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool ...@@ -203,16 +202,13 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool
{ {
int x = (*hole)[ii]; ii++; int x = (*hole)[ii]; ii++;
int y = (*hole)[ii]; int y = (*hole)[ii];
polyline->AppendCorner( x, y, STRAIGHT, false ); polyline->AppendCorner( x, y );
} }
polyline->CloseLastContour(); polyline->CloseLastContour();
} }
} }
if( bRetainArcs )
RestoreArcs( &arc_array, aExtraPolyList );
delete m_Kbool_Poly_Engine; delete m_Kbool_Poly_Engine;
m_Kbool_Poly_Engine = NULL; m_Kbool_Poly_Engine = NULL;
...@@ -263,12 +259,10 @@ int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng, GroupType aGroup ) ...@@ -263,12 +259,10 @@ int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng, GroupType aGroup )
/** /**
* Function MakeKboolPoly * Function MakeKboolPoly
* fill a kbool engine with a closed polyline contour * fill a kbool engine with a closed polyline contour
* approximates arcs with multiple straight-line segments * normalize self-intersecting contours
* combining intersecting contours if possible
* @param arc_array : return corners computed from arcs approximations in arc_array
* @return error: 0 if Ok, 1 if error * @return error: 0 if Ok, 1 if error
*/ */
int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array ) int CPolyLine::MakeKboolPoly()
{ {
if( m_Kbool_Poly_Engine ) if( m_Kbool_Poly_Engine )
{ {
...@@ -279,15 +273,9 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array ) ...@@ -279,15 +273,9 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array )
if( !GetClosed() ) if( !GetClosed() )
return 1; // error return 1; // error
int n_arcs = 0;
int polycount = GetContoursCount(); int polycount = GetContoursCount();
int last_contour = polycount - 1; int last_contour = polycount - 1;
if( arc_array )
arc_array->clear();
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, // Fill a kbool engine for this contour,
...@@ -314,8 +302,6 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array ) ...@@ -314,8 +302,6 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array )
} }
} }
// first, calculate number of vertices in contour
int n_vertices = 0;
int ic_st = GetContourStart( icont ); int ic_st = GetContourStart( icont );
int ic_end = GetContourEnd( icont ); int ic_end = GetContourEnd( icont );
...@@ -325,159 +311,12 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array ) ...@@ -325,159 +311,12 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array )
return 1; // error return 1; // error
} }
for( int ic = ic_st; ic<=ic_end; ic++ ) // Enter this contour to booleng
for( int ic = ic_st; ic <= ic_end; ic++ )
{ {
int style = m_SideStyle[ic];
if( style == STRAIGHT )
n_vertices++;
else
{
// style is ARC_CW or ARC_CCW
int n = CArc::ARC_STEPS;
n_vertices += n;
n_arcs++;
}
}
// 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 x1 = m_CornersList[ic].x;
int y1 = m_CornersList[ic].y; int y1 = m_CornersList[ic].y;
int x2, y2; booleng->AddPoint( x1, y1 );
if( ic < ic_end )
{
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;
}
if( style == STRAIGHT )
{
booleng->AddPoint( x1, y1 );
ivtx++;
}
else
{
// style is arc_cw or arc_ccw
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) );
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;
}
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;
}
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;
}
else
{
xo = x1; // fourth quadrant, draw first quadrant of ellipse
yo = y2;
theta1 = M_PI / 2.0;
theta2 = 0.0;
}
}
else
{
// 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;
}
else if( x2 < x1 && y2 > y1 )
{
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;
}
else
{
xo = x2; // fourth quadrant
yo = y1;
theta1 = M_PI;
theta2 = 3.0 * M_PI / 2.0;
}
}
// now write steps for arc
if( arc_array )
{
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;
arc_array->push_back( new_arc );
iarc++;
}
for( int is = 0; is<n; is++ )
{
double theta = theta1 + ( (theta2 - theta1) * (double) is ) / n;
double x = xo + a* cos( theta );
double y = yo + b* sin( theta );
if( is == 0 )
{
x = x1;
y = y1;
}
booleng->AddPoint( x, y );
ivtx++;
}
}
}
if( n_vertices != ivtx )
{
wxASSERT( 0 );
} }
// close list added to the bool engine // close list added to the bool engine
...@@ -604,194 +443,23 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) ...@@ -604,194 +443,23 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles )
} }
int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* pa, bool bRetainArcs ) /**
{ * Function NormalizeAreaOutlines
return NormalizeWithKbool( pa, bRetainArcs ); * Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
} * @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
* needed by the normalization
* @return the polygon count (always >= 1, becuse there is at lesat one polygon)
// Restore arcs to a polygon where they were replaced with steps * There are new polygons only if the polygon count is > 1
// If pa != NULL, also use polygons in pa array */
// int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
int CPolyLine::RestoreArcs( std::vector<CArc>* arc_array, std::vector<CPolyLine*>* pa )
{ {
// get poly info return NormalizeWithKbool( aNewPolygonList );
int n_polys = 1;
if( pa )
n_polys += pa->size();
CPolyLine* poly;
// undraw polys and clear m_utility flag for all corners
for( int ip = 0; ip<n_polys; ip++ )
{
if( ip == 0 )
poly = this;
else
poly = (*pa)[ip - 1];
poly->UnHatch();
for( int ic = 0; ic<poly->GetNumCorners(); ic++ )
poly->SetUtility( ic, 0 );
// clear m_utility flag
}
// find arcs and replace them
bool bFound;
int arc_start = 0;
int arc_end = 0;
for( unsigned iarc = 0; iarc<arc_array->size(); iarc++ )
{
int arc_xi = (*arc_array)[iarc].xi;
int arc_yi = (*arc_array)[iarc].yi;
int arc_xf = (*arc_array)[iarc].xf;
int arc_yf = (*arc_array)[iarc].yf;
int n_steps = (*arc_array)[iarc].n_steps;
int style = (*arc_array)[iarc].style;
bFound = false;
// loop through polys
for( int ip = 0; ip<n_polys; ip++ )
{
if( ip == 0 )
poly = this;
else
poly = (*pa)[ip - 1];
int polycount = poly->GetContoursCount();
for( int icont = 0; icont < polycount; 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 );
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 );
if( xf == arc_xf && yf == arc_yf )
{
// arc from ic to 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 );
if( xf == arc_xf && yf == arc_yf )
{
// arc from ic2 to ic
bFound = true;
arc_start = ic2;
arc_end = ic;
style = 3 - style;
}
}
if( bFound )
{
poly->m_SideStyle[arc_start] = style;
// mark corners for deletion from arc_start+1 to arc_end-1
for( int i = arc_start + 1; i!=arc_end; )
{
if( i > ic_end )
i = ic_start;
poly->SetUtility( i, 1 );
if( i == ic_end )
i = ic_start;
else
i++;
}
break;
}
}
if( bFound )
break;
}
}
if( bFound )
break;
}
}
if( bFound )
(*arc_array)[iarc].bFound = true;
}
// now delete all marked corners
for( int ip = 0; ip<n_polys; ip++ )
{
if( ip == 0 )
poly = this;
else
poly = (*pa)[ip - 1];
for( int ic = poly->GetNumCorners() - 1; ic>=0; ic-- )
{
if( poly->GetUtility( ic ) )
poly->DeleteCorner( ic, false );
}
}
return 0;
} }
// initialize new polyline /* initialize a contour
// set layer, width, selection box size, starting point, id and pointer * set layer, hatch style, and starting point
// */
// if sel_box = 0, don't create selection elements at all
//
// if polyline is board outline, enter with:
// id.type = ID_BOARD
// id.st = ID_BOARD_OUTLINE
// id.i = 0
// ptr = NULL
//
// if polyline is copper area, enter with:
// id.type = ID_NET;
// id.st = ID_AREA
// id.i = index to area
// ptr = pointer to net
//
void CPolyLine::Start( int layer, int x, int y, int hatch ) void CPolyLine::Start( int layer, int x, int y, int hatch )
{ {
m_layer = layer; m_layer = layer;
...@@ -800,27 +468,19 @@ void CPolyLine::Start( int layer, int x, int y, int hatch ) ...@@ -800,27 +468,19 @@ void CPolyLine::Start( int layer, int x, int y, int hatch )
poly_pt.end_contour = false; poly_pt.end_contour = false;
m_CornersList.push_back( poly_pt ); m_CornersList.push_back( poly_pt );
m_SideStyle.push_back( 0 );
} }
// add a corner to unclosed polyline // add a corner to unclosed polyline
// //
void CPolyLine::AppendCorner( int x, int y, int style, bool bDraw ) void CPolyLine::AppendCorner( int x, int y )
{ {
UnHatch(); UnHatch();
CPolyPt poly_pt( x, y ); CPolyPt poly_pt( x, y );
poly_pt.end_contour = false; poly_pt.end_contour = false;
// add entries for new corner and side // add entries for new corner
m_CornersList.push_back( poly_pt ); m_CornersList.push_back( poly_pt );
m_SideStyle.push_back( style );
if( m_CornersList.size() > 0 && !m_CornersList[m_CornersList.size() - 1].end_contour )
m_SideStyle[m_CornersList.size() - 1] = style;
if( bDraw )
Hatch();
} }
...@@ -845,40 +505,32 @@ void CPolyLine::MoveCorner( int ic, int x, int y ) ...@@ -845,40 +505,32 @@ void CPolyLine::MoveCorner( int ic, int x, int y )
// delete corner and adjust arrays // delete corner and adjust arrays
// //
void CPolyLine::DeleteCorner( int ic, bool bDraw ) void CPolyLine::DeleteCorner( int ic )
{ {
UnHatch(); UnHatch();
int icont = GetContour( ic ); int icont = GetContour( ic );
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
bool bClosed = icont < GetContoursCount() - 1 || GetClosed(); bool closed = icont < GetContoursCount() - 1 || GetClosed();
if( !bClosed ) if( !closed )
{ {
// open contour, must be last contour // open contour, must be last contour
m_CornersList.erase( m_CornersList.begin() + ic ); m_CornersList.erase( m_CornersList.begin() + ic );
if( ic != istart )
m_SideStyle.erase( m_SideStyle.begin() + ic - 1 );
} }
else else
{ {
// closed contour // closed contour
m_CornersList.erase( m_CornersList.begin() + ic ); m_CornersList.erase( m_CornersList.begin() + ic );
m_SideStyle.erase( m_SideStyle.begin() + ic );
if( ic == iend ) if( ic == iend )
m_CornersList[ic - 1].end_contour = true; m_CornersList[ic - 1].end_contour = true;
} }
if( bClosed && GetContourSize( icont ) < 3 ) if( closed && GetContourSize( icont ) < 3 )
{ {
// delete the entire contour // delete the entire contour
RemoveContour( icont ); RemoveContour( icont );
} }
if( bDraw )
Hatch();
} }
...@@ -907,7 +559,6 @@ void CPolyLine::RemoveContour( int icont ) ...@@ -907,7 +559,6 @@ void CPolyLine::RemoveContour( int icont )
{ {
// remove last contour // remove last contour
m_CornersList.erase( m_CornersList.begin() + istart, m_CornersList.end() ); m_CornersList.erase( m_CornersList.begin() + istart, m_CornersList.end() );
m_SideStyle.erase( m_SideStyle.begin() + istart, m_SideStyle.end() );
} }
else else
{ {
...@@ -915,7 +566,6 @@ void CPolyLine::RemoveContour( int icont ) ...@@ -915,7 +566,6 @@ void CPolyLine::RemoveContour( int icont )
for( int ic = iend; ic>=istart; ic-- ) for( int ic = iend; ic>=istart; ic-- )
{ {
m_CornersList.erase( m_CornersList.begin() + ic ); m_CornersList.erase( m_CornersList.begin() + ic );
m_SideStyle.erase( m_SideStyle.begin() + ic );
} }
} }
...@@ -1140,7 +790,6 @@ void CPolyLine::RemoveAllContours( void ) ...@@ -1140,7 +790,6 @@ void CPolyLine::RemoveAllContours( void )
*/ */
{ {
m_CornersList.clear(); m_CornersList.clear();
m_SideStyle.clear();
} }
...@@ -1157,12 +806,10 @@ void CPolyLine::InsertCorner( int ic, int x, int y ) ...@@ -1157,12 +806,10 @@ void CPolyLine::InsertCorner( int ic, int x, int y )
if( (unsigned) (ic) >= m_CornersList.size() ) if( (unsigned) (ic) >= m_CornersList.size() )
{ {
m_CornersList.push_back( CPolyPt( x, y ) ); m_CornersList.push_back( CPolyPt( x, y ) );
m_SideStyle.push_back( STRAIGHT );
} }
else else
{ {
m_CornersList.insert( m_CornersList.begin() + ic + 1, CPolyPt( x, y ) ); m_CornersList.insert( m_CornersList.begin() + ic + 1, CPolyPt( x, y ) );
m_SideStyle.insert( m_SideStyle.begin() + ic + 1, STRAIGHT );
} }
if( (unsigned) (ic + 1) < m_CornersList.size() ) if( (unsigned) (ic + 1) < m_CornersList.size() )
...@@ -1348,41 +995,6 @@ int CPolyLine::GetContourSize( int icont ) ...@@ -1348,41 +995,6 @@ int CPolyLine::GetContourSize( int icont )
} }
void CPolyLine::SetSideStyle( int is, int style )
{
UnHatch();
wxPoint p1, p2;
if( is == (int) (m_CornersList.size() - 1) )
{
p1.x = m_CornersList[m_CornersList.size() - 1].x;
p1.y = m_CornersList[m_CornersList.size() - 1].y;
p2.x = m_CornersList[0].x;
p2.y = m_CornersList[0].y;
}
else
{
p1.x = m_CornersList[is].x;
p1.y = m_CornersList[is].y;
p2.x = m_CornersList[is + 1].x;
p2.y = m_CornersList[is + 1].y;
}
if( p1.x == p2.x || p1.y == p2.y )
m_SideStyle[is] = STRAIGHT;
else
m_SideStyle[is] = style;
Hatch();
}
int CPolyLine::GetSideStyle( int is )
{
return m_SideStyle[is];
}
int CPolyLine::GetClosed() int CPolyLine::GetClosed()
{ {
if( m_CornersList.size() == 0 ) if( m_CornersList.size() == 0 )
...@@ -1500,7 +1112,6 @@ void CPolyLine::Hatch() ...@@ -1500,7 +1112,6 @@ void CPolyLine::Hatch()
m_CornersList[ic].x, m_CornersList[ic].y, m_CornersList[ic].x, m_CornersList[ic].y,
m_CornersList[i_start_contour].x, m_CornersList[i_start_contour].x,
m_CornersList[i_start_contour].y, m_CornersList[i_start_contour].y,
m_SideStyle[ic],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
i_start_contour = ic + 1; i_start_contour = ic + 1;
} }
...@@ -1509,7 +1120,6 @@ void CPolyLine::Hatch() ...@@ -1509,7 +1120,6 @@ void CPolyLine::Hatch()
ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope,
m_CornersList[ic].x, m_CornersList[ic].y, m_CornersList[ic].x, m_CornersList[ic].y,
m_CornersList[ic + 1].x, m_CornersList[ic + 1].y, m_CornersList[ic + 1].x, m_CornersList[ic + 1].y,
m_SideStyle[ic],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
} }
...@@ -1625,8 +1235,6 @@ void CPolyLine::Copy( CPolyLine* src ) ...@@ -1625,8 +1235,6 @@ void CPolyLine::Copy( CPolyLine* src )
m_hatchPitch = src->m_hatchPitch; m_hatchPitch = src->m_hatchPitch;
// copy corners, using vector copy // copy corners, using vector copy
m_CornersList = src->m_CornersList; m_CornersList = src->m_CornersList;
// copy side styles, using vector copy
m_SideStyle = src->m_SideStyle;
} }
...@@ -1683,7 +1291,8 @@ void CPolyLine::SetEndContour( int ic, bool end_contour ) ...@@ -1683,7 +1291,8 @@ void CPolyLine::SetEndContour( int ic, bool end_contour )
} }
/* /*
* AppendArc adds segments to current contour to approximate the given arc * 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 ) void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num )
{ {
...@@ -1701,7 +1310,7 @@ void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int n ...@@ -1701,7 +1310,7 @@ void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int n
{ {
int x = KiROUND( xc + radius * cos( theta ) ); int x = KiROUND( xc + radius * cos( theta ) );
int y = KiROUND( yc + radius * sin( theta ) ); int y = KiROUND( yc + radius * sin( theta ) );
AppendCorner( x, y, STRAIGHT, 0 ); AppendCorner( x, y );
theta += th_d; theta += th_d;
} }
...@@ -1776,10 +1385,9 @@ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth ) ...@@ -1776,10 +1385,9 @@ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth )
by2 = GetY( ic2 + 1 ); by2 = GetY( ic2 + 1 );
} }
int bstyle = GetSideStyle( ic2 ); int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle, 0,
aStart.x, aStart.y, aEnd.x, aEnd.y, aStart.x, aStart.y, aEnd.x, aEnd.y,
CPolyLine::STRAIGHT, aWidth, aWidth,
1, // min clearance, should be > 0 1, // min clearance, should be > 0
NULL, NULL ); NULL, NULL );
...@@ -1835,12 +1443,9 @@ int CPolyLine::Distance( const wxPoint& aPoint ) ...@@ -1835,12 +1443,9 @@ int CPolyLine::Distance( const wxPoint& aPoint )
by2 = GetY( ic2 + 1 ); by2 = GetY( ic2 + 1 );
} }
// Here we expect only straight lines for vertices
// (no arcs, not yet supported in Pcbnew)
int d = KiROUND( GetPointToLineSegmentDistance( aPoint.x, aPoint.y, int d = KiROUND( GetPointToLineSegmentDistance( aPoint.x, aPoint.y,
bx1, by1, bx2, by2 ) ); bx1, by1, bx2, by2 ) );
if( distance > d ) if( distance > d )
distance = d; distance = d;
...@@ -2000,3 +1605,100 @@ void ConvertPolysListWithHolesToOnePolygon( const std::vector<CPolyPt>& aPolysL ...@@ -2000,3 +1605,100 @@ void ConvertPolysListWithHolesToOnePolygon( const std::vector<CPolyPt>& aPolysL
aOnePolyList.push_back( corner ); aOnePolyList.push_back( corner );
} }
} }
/**
* Function IsPolygonSelfIntersecting
* Test a CPolyLine for self-intersection of vertex (all contours).
*
* @return :
* false if no intersecting sides
* true if intersecting sides
* When a CPolyLine is self intersectic, it need to be normalized.
* (converted to non intersecting polygons)
*/
bool CPolyLine::IsPolygonSelfIntersecting()
{
// first, check for sides intersecting other sides
int n_cont = GetContoursCount();
// make bounding rect for each contour
std::vector<CRect> cr;
cr.reserve( n_cont );
for( int icont = 0; icont<n_cont; icont++ )
cr.push_back( GetCornerBounds( icont ) );
for( int icont = 0; icont<n_cont; icont++ )
{
int is_start = GetContourStart( icont );
int is_end = GetContourEnd( icont );
for( int is = is_start; is<=is_end; is++ )
{
int is_prev = is - 1;
if( is_prev < is_start )
is_prev = is_end;
int is_next = is + 1;
if( is_next > is_end )
is_next = is_start;
int x1i = GetX( is );
int y1i = GetY( is );
int x1f = GetX( is_next );
int y1f = GetY( is_next );
// check for intersection with any other sides
for( int icont2 = icont; icont2<n_cont; icont2++ )
{
if( cr[icont].left > cr[icont2].right
|| cr[icont].bottom > cr[icont2].top
|| cr[icont2].left > cr[icont].right
|| cr[icont2].bottom > cr[icont].top )
{
// rectangles don't overlap, do nothing
}
else
{
int is2_start = GetContourStart( icont2 );
int is2_end = GetContourEnd( icont2 );
for( int is2 = is2_start; is2<=is2_end; is2++ )
{
int is2_prev = is2 - 1;
if( is2_prev < is2_start )
is2_prev = is2_end;
int is2_next = is2 + 1;
if( is2_next > is2_end )
is2_next = is2_start;
if( icont != icont2
|| ( is2 != is && is2 != is_prev && is2 != is_next &&
is != is2_prev && is != is2_next )
)
{
int x2i = GetX( is2 );
int y2i = GetY( is2 );
int x2f = GetX( is2_next );
int y2f = GetY( is2_next );
int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f,
x2i, y2i, x2f, y2f );
if( ret )
{
// intersection between non-adjacent sides
return true;
}
}
}
}
}
}
}
return false;
}
...@@ -24,13 +24,13 @@ ...@@ -24,13 +24,13 @@
#include <polygons_defs.h> #include <polygons_defs.h>
// inflection modes for DS_LINE and DS_LINE_VERTEX, used in math_for_graphics.cpp // inflection modes for DS_LINE and DS_LINE_VERTEX, used in math_for_graphics.cpp
enum { /*enum {
IM_NONE = 0, IM_NONE = 0,
IM_90_45, IM_90_45,
IM_45_90, IM_45_90,
IM_90 IM_90
}; };
*/
class CRect class CRect
{ {
...@@ -58,6 +58,7 @@ public: ...@@ -58,6 +58,7 @@ public:
} }
}; };
/*
class CArc class CArc
{ {
public: public:
...@@ -67,7 +68,7 @@ public: ...@@ -67,7 +68,7 @@ public:
int n_steps; // number of straight-line segments in gpc_poly int n_steps; // number of straight-line segments in gpc_poly
bool bFound; bool bFound;
}; };
*/
class CPolyPt : public wxPoint class CPolyPt : public wxPoint
{ {
...@@ -98,27 +99,41 @@ public: ...@@ -98,27 +99,41 @@ public:
}; };
#include <polygon_test_point_inside.h>
class CPolyLine class CPolyLine
{ {
public: 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 // constructors/destructor
CPolyLine(); CPolyLine();
~CPolyLine(); ~CPolyLine();
// functions for modifying polyline // functions for modifying the CPolyLine contours
/* initialize a contour
* set layer, hatch style, and starting point
*/
void Start( int layer, int x, int y, int hatch ); void Start( int layer, int x, int y, int hatch );
void AppendCorner( int x, int y, int style = STRAIGHT, bool bDraw = false );
void AppendCorner( int x, int y );
void InsertCorner( int ic, int x, int y ); void InsertCorner( int ic, int x, int y );
void DeleteCorner( int ic, bool bDraw = false ); void DeleteCorner( int ic );
void MoveCorner( int ic, int x, int y ); void MoveCorner( int ic, int x, int y );
void CloseLastContour(); void CloseLastContour();
void RemoveContour( int icont ); void RemoveContour( int icont );
/**
* Function IsPolygonSelfIntersecting
* Test a CPolyLine for self-intersection of vertex (all contours).
*
* @return :
* false if no intersecting sides
* true if intersecting sides
* When a CPolyLine is self intersectic, it need to be normalized.
* (converted to non intersecting polygons)
*/
bool IsPolygonSelfIntersecting();
/** /**
* Function Chamfer * Function Chamfer
* returns a chamfered version of a polygon. * returns a chamfered version of a polygon.
...@@ -180,7 +195,6 @@ public: ...@@ -180,7 +195,6 @@ public:
int GetUtility( int ic ) { return m_CornersList[ic].m_utility; }; int GetUtility( int ic ) { return m_CornersList[ic].m_utility; };
void SetUtility( int ic, int utility ) { m_CornersList[ic].m_utility = utility; }; void SetUtility( int ic, int utility ) { m_CornersList[ic].m_utility = utility; };
int GetSideStyle( int is );
int GetHatchPitch() { return m_hatchPitch; } int GetHatchPitch() { return m_hatchPitch; }
static int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils static int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils
...@@ -197,7 +211,6 @@ public: ...@@ -197,7 +211,6 @@ public:
void SetX( int ic, int x ); void SetX( int ic, int x );
void SetY( int ic, int y ); void SetY( int ic, int y );
void SetEndContour( int ic, bool end_contour ); 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 )
{ {
...@@ -206,10 +219,15 @@ public: ...@@ -206,10 +219,15 @@ public:
void SetHatchPitch( int pitch ) { m_hatchPitch = pitch; } void SetHatchPitch( int pitch ) { m_hatchPitch = pitch; }
int RestoreArcs( std::vector<CArc>* arc_array, std::vector<CPolyLine*>* pa = NULL ); /**
* Function NormalizeAreaOutlines
int NormalizeAreaOutlines( std::vector<CPolyLine*>* pa = NULL, * Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
bool bRetainArcs = false ); * @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
* needed by the normalization
* @return the polygon count (always >= 1, becuse there is at lesat one polygon)
* There are new polygons only if the polygon count is > 1
*/
int NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList );
// KBOOL functions // KBOOL functions
...@@ -224,12 +242,9 @@ public: ...@@ -224,12 +242,9 @@ public:
/** /**
* Function MakeKboolPoly * Function MakeKboolPoly
* fill a kbool engine with a closed polyline contour * fill a kbool engine with a closed polyline contour
* approximates arcs with multiple straight-line segments
* combining intersecting contours if possible
* @param arc_array : return data on arcs in arc_array
* @return error: 0 if Ok, 1 if error * @return error: 0 if Ok, 1 if error
*/ */
int MakeKboolPoly( std::vector<CArc>* arc_array = NULL ); int MakeKboolPoly();
/** /**
* Function NormalizeWithKbool * Function NormalizeWithKbool
...@@ -240,10 +255,10 @@ public: ...@@ -240,10 +255,10 @@ public:
* because copper areas have only one outside contour * because copper areas have only one outside contour
* Therefore, if this results in new CPolyLines, return them as std::vector pa * Therefore, if this results in new CPolyLines, return them as std::vector pa
* @param aExtraPolyList: pointer on a std::vector<CPolyLine*> to store extra CPolyLines * @param aExtraPolyList: pointer on a std::vector<CPolyLine*> to store extra CPolyLines
* @param bRetainArcs == false, try to retain arcs in polys * (when after normalization, there is more than one polygon with holes)
* @return number of external contours, or -1 if error * @return number of contours, or -1 if error
*/ */
int NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool bRetainArcs ); int NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList );
// Bezier Support // 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 );
...@@ -280,7 +295,6 @@ private: ...@@ -280,7 +295,6 @@ private:
Bool_Engine* m_Kbool_Poly_Engine; // polygons set in kbool engine data Bool_Engine* m_Kbool_Poly_Engine; // polygons set in kbool engine data
public: public:
std::vector <CPolyPt> m_CornersList; // array of points for corners std::vector <CPolyPt> m_CornersList; // array of points for corners
std::vector <int> m_SideStyle; // array of styles for sides
std::vector <CSegment> m_HatchLines; // hatch lines showing the polygon area std::vector <CSegment> m_HatchLines; // hatch lines showing the polygon area
}; };
......
...@@ -11,37 +11,13 @@ ...@@ -11,37 +11,13 @@
#include <PolyLine.h> #include <PolyLine.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
#define NM_PER_MIL 25400 static bool InRange( double x, double xi, double xf );
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 Distance( double x1, double y1, double x2, double y2 )
{ {
double dx = x1 - x2; return hypot( x1 - x2, y1 - y2 );
double dy = y1 - y2;
double d = sqrt( dx * dx + dy * dy );
return d;
} }
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 * Function TestLineHit
* test for hit on line segment i.e. a point within a given distance from segment * test for hit on line segment i.e. a point within a given distance from segment
...@@ -104,271 +80,33 @@ bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist ) ...@@ -104,271 +80,33 @@ bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
} }
// set EllipseKH struct to describe the ellipse for an arc /* Function FindSegmentIntersections
// * find intersections between line segment (xi,yi) to (xf,yf)
int MakeEllipseFromArc( int xi, int yi, int xf, int yf, int style, EllipseKH* el ) * and line segment (xi2,yi2) to (xf2,yf2)
{ * returns true if intersection found
// arc (quadrant of ellipse) */
// convert to clockwise arc bool FindSegmentIntersections( int xi, int yi, int xf, int yf,
int xxi, xxf, yyi, yyf; int xi2, int yi2, int xf2, int yf2 )
if( style == CPolyLine::ARC_CCW )
{
xxi = xf;
xxf = xi;
yyi = yf;
yyf = yi;
}
else
{
xxi = xi;
xxf = xf;
yyi = yi;
yyf = yf;
}
// find center and radii of ellipse
double xo = 0, yo = 0;
if( xxf > xxi && yyf > yyi )
{
xo = xxf;
yo = yyi;
el->theta1 = M_PI;
el->theta2 = M_PI / 2.0;
}
else if( xxf < xxi && yyf > yyi )
{
xo = xxi;
yo = yyf;
el->theta1 = -M_PI / 2.0;
el->theta2 = -M_PI;
}
else if( xxf < xxi && yyf < yyi )
{
xo = xxf;
yo = yyi;
el->theta1 = 0.0;
el->theta2 = -M_PI / 2.0;
}
else if( xxf > xxi && yyf < yyi )
{
xo = xxi;
yo = yyf;
el->theta1 = M_PI / 2.0;
el->theta2 = 0.0;
}
el->Center.X = xo;
el->Center.Y = yo;
el->xrad = abs( xf - xi );
el->yrad = abs( yf - yi );
#if 0
el->Phi = 0.0;
el->MaxRad = el->xrad;
el->MinRad = el->yrad;
if( el->MaxRad < el->MinRad )
{
el->MaxRad = el->yrad;
el->MinRad = el->xrad;
el->Phi = M_PI / 2.0;
}
#endif
return 0;
}
// find intersections between line segment (xi,yi) to (xf,yf)
// and line segment (xi2,yi2) to (xf2,yf2)
// the line segments may be arcs (i.e. quadrant of an ellipse) or straight
// returns number of intersections found (max of 2)
// returns coords of intersections in arrays x[2], y[2]
//
int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
int xi2, int yi2, int xf2, int yf2, int style2,
double x[], double y[] )
{ {
double xr[12], yr[12];
int iret = 0;
if( max( xi, xf ) < min( xi2, xf2 ) if( max( xi, xf ) < min( xi2, xf2 )
|| min( xi, xf ) > max( xi2, xf2 ) || min( xi, xf ) > max( xi2, xf2 )
|| max( yi, yf ) < min( yi2, yf2 ) || max( yi, yf ) < min( yi2, yf2 )
|| min( yi, yf ) > max( yi2, yf2 ) ) || min( yi, yf ) > max( yi2, yf2 ) )
return 0; return false;
if( style != CPolyLine::STRAIGHT && style2 != CPolyLine::STRAIGHT )
{
// two identical arcs intersect
if( style == style2 && xi == xi2 && yi == yi2 && xf == xf2 && yf == yf2 )
{
if( x && y )
{
x[0] = xi;
y[0] = yi;
}
return 1;
}
else if( style != style2 && xi == xf2 && yi == yf2 && xf == xi2 && yf == yi2 )
{
if( x && y )
{
x[0] = xi;
y[0] = yi;
}
return 1;
}
}
if( style == CPolyLine::STRAIGHT && style2 == CPolyLine::STRAIGHT )
{
// both straight-line segments
int x, y;
bool bYes = TestForIntersectionOfStraightLineSegments( xi,
yi,
xf,
yf,
xi2,
yi2,
xf2,
yf2,
&x,
&y );
if( !bYes )
return 0;
xr[0] = x;
yr[0] = y;
iret = 1;
}
else if( style == CPolyLine::STRAIGHT )
{
// first segment is straight, second segment is an arc
int ret;
double x1r, y1r, x2r, y2r;
if( xf == xi )
{
// vertical first segment
double a = xi;
double b = DBL_MAX / 2.0;
ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2,
&x1r, &y1r, &x2r, &y2r );
}
else
{
double b = (double) (yf - yi) / (double) (xf - xi);
double a = yf - b * xf;
ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2,
&x1r, &y1r, &x2r, &y2r );
}
if( ret == 0 )
return 0;
if( InRange( x1r, xi, xf ) && InRange( y1r, yi, yf ) )
{
xr[iret] = x1r;
yr[iret] = y1r;
iret++;
}
if( ret == 2 )
{
if( InRange( x2r, xi, xf ) && InRange( y2r, yi, yf ) )
{
xr[iret] = x2r;
yr[iret] = y2r;
iret++;
}
}
}
else if( style2 == CPolyLine::STRAIGHT )
{
// first segment is an arc, second segment is straight
int ret;
double x1r, y1r, x2r, y2r;
if( xf2 == xi2 )
{
// vertical second segment
double a = xi2;
double b = DBL_MAX / 2.0;
ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style,
&x1r, &y1r, &x2r, &y2r );
}
else
{
double b = (double) (yf2 - yi2) / (double) (xf2 - xi2);
double a = yf2 - b * xf2;
ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style,
&x1r, &y1r, &x2r, &y2r );
}
if( ret == 0 )
return 0;
if( InRange( x1r, xi2, xf2 ) && InRange( y1r, yi2, yf2 ) )
{
xr[iret] = x1r;
yr[iret] = y1r;
iret++;
}
if( ret == 2 )
{
if( InRange( x2r, xi2, xf2 ) && InRange( y2r, yi2, yf2 ) )
{
xr[iret] = x2r;
yr[iret] = y2r;
iret++;
}
}
}
else
{
// both segments are arcs
EllipseKH el1;
EllipseKH el2;
MakeEllipseFromArc( xi, yi, xf, yf, style, &el1 );
MakeEllipseFromArc( xi2, yi2, xf2, yf2, style2, &el2 );
int n;
if( el1.xrad + el1.yrad > el2.xrad + el2.yrad )
n = GetArcIntersections( &el1, &el2 );
else
n = GetArcIntersections( &el2, &el1 );
iret = n;
}
if( x && y )
{
for( int i = 0; i<iret; i++ )
{
x[i] = xr[i];
y[i] = yr[i];
}
}
return iret; return TestForIntersectionOfStraightLineSegments( xi, yi, xf, yf,
xi2, yi2, xf2, yf2 );
} }
// find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf) /* Function FindLineSegmentIntersection
// if b > DBL_MAX/10, assume vertical line at x = a * find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf)
// the line segment may be an arc (i.e. quadrant of an ellipse) * if b > DBL_MAX/10, assume vertical line at x = a
// return 0 if no intersection * return false if no intersection or true if intersect
// returns 1 or 2 if intersections found * return coords of intersections in *x1, *y1, *x2, *y2
// sets coords of intersections in *x1, *y1, *x2, *y2 * if no intersection, returns min distance in dist
// if no intersection, returns min distance in dist */
// bool FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf,
int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style,
double* x1, double* y1, double* x2, double* y2, double* x1, double* y1, double* x2, double* y2,
double* dist ) double* dist )
{ {
...@@ -378,188 +116,66 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int ...@@ -378,188 +116,66 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
if( b > DBL_MAX / 10.0 ) if( b > DBL_MAX / 10.0 )
bVert = true; bVert = true;
if( xf != xi ) if( xf != xi ) // non-vertical segment, get intersection
{ {
// non-vertical segment, get intersection // horizontal or oblique straight segment
if( style == CPolyLine::STRAIGHT || yf == yi ) // put into form y = c + dx;
{ double d = (double) (yf - yi) / (double) (xf - xi);
// horizontal or oblique straight segment double c = yf - d * xf;
// put into form y = c + dx;
double d = (double) (yf - yi) / (double) (xf - xi);
double c = yf - d * xf;
if( bVert )
{
// if vertical line, easy
if( InRange( a, xi, xf ) )
{
*x1 = a;
*y1 = c + d * a;
return 1;
}
else
{
if( dist )
*dist = min( abs( a - xi ), abs( a - xf ) );
return 0; if( bVert )
}
}
if( fabs( b - d ) < 1E-12 )
{
// parallel lines
if( dist )
{
*dist = GetPointToLineDistance( a, b, xi, xf );
}
return 0; // lines parallel
}
// calculate intersection
xx = (c - a) / (b - d);
yy = a + b * (xx);
// see if intersection is within the line segment
if( yf == yi )
{
// horizontal line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf) )
return 0;
}
else
{
// oblique line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf)
|| (yy>yi && yy>yf) || (yy<yi && yy<yf) )
return 0;
}
}
else if( style == CPolyLine::ARC_CW || style == CPolyLine::ARC_CCW )
{ {
// arc (quadrant of ellipse) // if vertical line, easy
// convert to clockwise arc if( InRange( a, xi, xf ) )
int xxi, xxf, yyi, yyf;
if( style == CPolyLine::ARC_CCW )
{ {
xxi = xf; *x1 = a;
xxf = xi; *y1 = c + d * a;
yyi = yf; return 1;
yyf = yi;
} }
else else
{ {
xxi = xi; if( dist )
xxf = xf; *dist = min( abs( a - xi ), abs( a - xf ) );
yyi = yi;
yyf = yf;
}
// find center and radii of ellipse
double xo = xxf, yo = yyi, rx, ry; // Init made to avoid C compil warnings
if( xxf > xxi && yyf > yyi ) return false;
{
xo = xxf;
yo = yyi;
}
else if( xxf < xxi && yyf > yyi )
{
xo = xxi;
yo = yyf;
} }
else if( xxf < xxi && yyf < yyi ) }
{
xo = xxf;
yo = yyi;
}
else if( xxf > xxi && yyf < yyi )
{
xo = xxi;
yo = yyf;
}
rx = fabs( (double) (xxi - xxf) );
ry = fabs( (double) (yyi - yyf) );
bool test;
double xx1, xx2, yy1, yy2, aa;
if( bVert ) if( fabs( b - d ) < 1E-12 )
{ {
// shift vertical line to coordinate system of ellipse // parallel lines
aa = a - xo; if( dist )
test = FindVerticalLineEllipseIntersections( rx, ry, aa, &yy1, &yy2 );
if( !test )
return 0;
// shift back to PCB coordinates
yy1 += yo;
yy2 += yo;
xx1 = a;
xx2 = a;
}
else
{ {
// shift line to coordinate system of ellipse *dist = GetPointToLineDistance( a, b, xi, xf );
aa = a + b * xo - yo;
test = FindLineEllipseIntersections( rx, ry, aa, b, &xx1, &xx2 );
if( !test )
return 0;
// shift back to PCB coordinates
yy1 = aa + b * xx1;
xx1 += xo;
yy1 += yo;
yy2 = aa + b * xx2;
xx2 += xo;
yy2 += yo;
} }
int npts = 0; return false; // lines parallel
}
if( (xxf>xxi && xx1<xxf && xx1>xxi) || (xxf<xxi && xx1<xxi && xx1>xxf) )
{
if( (yyf>yyi && yy1<yyf && yy1>yyi) || (yyf<yyi && yy1<yyi && yy1>yyf) )
{
*x1 = xx1;
*y1 = yy1;
npts = 1;
}
}
if( (xxf>xxi && xx2<xxf && xx2>xxi) || (xxf<xxi && xx2<xxi && xx2>xxf) ) // calculate intersection
{ xx = (c - a) / (b - d);
if( (yyf>yyi && yy2<yyf && yy2>yyi) || (yyf<yyi && yy2<yyi && yy2>yyf) ) yy = a + b * (xx);
{
if( npts == 0 )
{
*x1 = xx2;
*y1 = yy2;
npts = 1;
}
else
{
*x2 = xx2;
*y2 = yy2;
npts = 2;
}
}
}
return npts; // see if intersection is within the line segment
if( yf == yi )
{
// horizontal line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf) )
return false;
} }
else else
wxASSERT( 0 ); {
// oblique line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf)
|| (yy>yi && yy>yf) || (yy<yi && yy<yf) )
return false;
}
} }
else else
{ {
// vertical line segment // vertical line segment
if( bVert ) if( bVert )
return 0; return false;
xx = xi; xx = xi;
yy = a + b * xx; yy = a + b * xx;
...@@ -570,7 +186,7 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int ...@@ -570,7 +186,7 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
*x1 = xx; *x1 = xx;
*y1 = yy; *y1 = yy;
return 1; return true;
} }
...@@ -640,7 +256,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y ...@@ -640,7 +256,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y2i - b * x2i; a = (double) y2i - b * x2i;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f, CPolyLine::STRAIGHT, int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
...@@ -668,7 +284,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y ...@@ -668,7 +284,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y2i - b * x2i; a = (double) y2i - b * x2i;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f, CPolyLine::STRAIGHT, int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
...@@ -696,7 +312,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y ...@@ -696,7 +312,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y1i - b * x1i; a = (double) y1i - b * x1i;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, CPolyLine::STRAIGHT, int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
...@@ -724,7 +340,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y ...@@ -724,7 +340,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y1i - b * x1i; a = (double) y1i - b * x1i;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, CPolyLine::STRAIGHT, int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
...@@ -754,17 +370,8 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y ...@@ -754,17 +370,8 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y1i - b * x1i; a = (double) y1i - b * x1i;
double x1, y1, x2, y2; double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f,
b, &x1, &y1, &x2, &y2 );
x2i,
y2i,
x2f,
y2f,
CPolyLine::STRAIGHT,
&x1,
&y1,
&x2,
&y2 );
// both segments oblique // both segments oblique
if( test ) if( test )
...@@ -831,62 +438,13 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y ...@@ -831,62 +438,13 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
} }
/*solves the Quadratic equation = a*x*x + b*x + c /* Function GetClearanceBetweenSegments
* Get clearance between 2 segments
* Returns coordinates of the closest point between these 2 segments in x, y
* If clearance > max_cl, just returns max_cl+1 and doesn't return x,y
*/ */
bool Quadratic( double a, double b, double c, double* x1, double* x2 ) int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int w1,
{ int x2i, int y2i, int x2f, int y2f, int w2,
double root = b * b - 4.0 * a * c;
if( root < 0.0 )
return false;
root = sqrt( root );
*x1 = (-b + root) / (2.0 * a);
*x2 = (-b - root) / (2.0 * a);
return true;
}
// finds intersections of vertical line at x
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in y1 and y2
// else returns false
//
bool FindVerticalLineEllipseIntersections( double a, double b, double x, double* y1, double* y2 )
{
double y_sqr = ( 1.0 - (x * x) / (a * a) ) * b * b;
if( y_sqr < 0.0 )
return false;
*y1 = sqrt( y_sqr );
*y2 = -*y1;
return true;
}
// finds intersections of straight line y = c + dx
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in x1 and x2
// else returns false
//
bool FindLineEllipseIntersections( double a, double b, double c, double d, double* x1, double* x2 )
{
// quadratic terms
double A = d * d + b * b / (a * a);
double B = 2.0 * c * d;
double C = c * c - b * b;
return Quadratic( A, B, C, x1, x2 );
}
// Get clearance between 2 segments
// Returns point in segment closest to other segment in 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 ) int max_cl, int* x, int* y )
{ {
// check clearance between bounding rectangles // check clearance between bounding rectangles
...@@ -904,205 +462,29 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, ...@@ -904,205 +462,29 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1,
if( min( y2i, y2f ) - max( y1i, y1f ) > min_dist ) if( min( y2i, y2f ) - max( y1i, y1f ) > min_dist )
return max_cl+1; return max_cl+1;
if( style1 == CPolyLine::STRAIGHT && style1 == CPolyLine::STRAIGHT ) int xx, yy;
{ double dist;
// both segments are straight lines TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f,
int xx, yy; x2i, y2i, x2f, y2f, &xx, &yy, &dist );
double dd; int d = (int) dist - ( (w1 + w2) / 2 );
TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f, if( d < 0 )
x2i, y2i, x2f, y2f, &xx, &yy, &dd ); d = 0;
int d = (int) dd - ( (w1 + w2) / 2 );
if( d < 0 )
d = 0;
if( x )
*x = xx;
if( y )
*y = yy;
return d;
}
// not both straight-line segments
// see if segments intersect
double xr[2];
double yr[2];
int count =
FindSegmentIntersections( x1i, y1i, x1f, y1f, style1, x2i, y2i, x2f, y2f, style2, xr, yr );
if( count )
{
if( x )
*x = (int) xr[0];
if( y )
*y = (int) yr[0];
return 0;
}
// at least one segment is an arc
EllipseKH el1;
EllipseKH el2;
bool bArcs;
int xi = 0, yi = 0, xf = 0, yf = 0;
if( style2 == CPolyLine::STRAIGHT )
{
// style1 = arc, style2 = straight
MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 );
xi = x2i;
yi = y2i;
xf = x2f;
yf = y2f;
bArcs = false;
}
else if( style1 == CPolyLine::STRAIGHT )
{
// style2 = arc, style1 = straight
xi = x1i;
yi = y1i;
xf = x1f;
yf = y1f;
MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el1 );
bArcs = false;
}
else
{
// style1 = arc, style2 = arc
MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 );
MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el2 );
bArcs = true;
}
const int NSTEPS = 32;
if( el1.theta2 > el1.theta1 )
{
wxASSERT( 0 );
}
if( bArcs && el2.theta2 > el2.theta1 )
{
wxASSERT( 0 );
}
// test multiple points in both segments
double th1;
double th2;
double len2;
if( bArcs )
{
th1 = el2.theta1;
th2 = el2.theta2;
len2 = max( el2.xrad, el2.yrad );
}
else
{
th1 = 1.0;
th2 = 0.0;
len2 = abs( xf - xi ) + abs( yf - yi );
}
double s_start = el1.theta1;
double s_end = el1.theta2;
double s_start2 = th1;
double s_end2 = th2;
double dmin = DBL_MAX;
double xmin = 0, ymin = 0, smin = 0, smin2 = 0; // Init made to avoid C compil warnings
int nsteps = NSTEPS;
int nsteps2 = NSTEPS;
double step = (s_start - s_end) / (nsteps - 1);
double step2 = (s_start2 - s_end2) / (nsteps2 - 1);
while( ( step * max( el1.xrad, el1.yrad ) ) > 0.1 * NM_PER_MIL
&& (step2 * len2) > 0.1 * NM_PER_MIL )
{
step = (s_start - s_end) / (nsteps - 1);
for( int i = 0; i<nsteps; i++ )
{
double s;
if( i < nsteps - 1 )
s = s_start - i * step;
else
s = s_end;
double x = el1.Center.X + el1.xrad * cos( s );
double y = el1.Center.Y + el1.yrad * sin( s );
// if not an arc, use s2 as fractional distance along line
step2 = (s_start2 - s_end2) / (nsteps2 - 1);
for( int i2 = 0; i2<nsteps2; i2++ )
{
double s2;
if( i2 < nsteps2 - 1 )
s2 = s_start2 - i2 * step2;
else
s2 = s_end2;
double x2, y2;
if( !bArcs )
{
x2 = xi + (xf - xi) * s2;
y2 = yi + (yf - yi) * s2;
}
else
{
x2 = el2.Center.X + el2.xrad* cos( s2 );
y2 = el2.Center.Y + el2.yrad* sin( s2 );
}
double d = Distance( x, y, x2, y2 );
if( d < dmin )
{
dmin = d;
xmin = x;
ymin = y;
smin = s;
smin2 = s2;
}
}
}
if( step > step2 )
{
s_start = min( el1.theta1, smin + step );
s_end = max( el1.theta2, smin - step );
step = (s_start - s_end) / nsteps;
}
else
{
s_start2 = min( th1, smin2 + step2 );
s_end2 = max( th2, smin2 - step2 );
step2 = (s_start2 - s_end2) / nsteps2;
}
}
if( x ) if( x )
*x = (int) xmin; *x = xx;
if( y ) if( y )
*y = (int) ymin; *y = yy;
return max( 0, (int) dmin - w1 / 2 - w2 / 2 ); // allow for widths return d;
} }
// Get min. distance from (x,y) to line y = a + bx /* Function GetPointToLineDistance
// if b > DBL_MAX/10, assume vertical line at x = a * Get min. distance from (x,y) to line y = a + bx
// returns closest point on line in xp, yp * if b > DBL_MAX/10, assume vertical line at x = a
// * returns closest point on line in xpp, ypp
*/
double GetPointToLineDistance( double a, double b, int x, int y, double* xpp, double* ypp ) double GetPointToLineDistance( double a, double b, int x, int y, double* xpp, double* ypp )
{ {
if( b > DBL_MAX / 10 ) if( b > DBL_MAX / 10 )
...@@ -1136,9 +518,6 @@ double GetPointToLineDistance( double a, double b, int x, int y, double* xpp, do ...@@ -1136,9 +518,6 @@ double GetPointToLineDistance( double a, double b, int x, int y, double* xpp, do
} }
/***********************************************************************************/
double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf )
/***********************************************************************************/
/** /**
* Function GetPointToLineSegmentDistance * Function GetPointToLineSegmentDistance
* Get distance between line segment and point * Get distance between line segment and point
...@@ -1147,6 +526,7 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int ...@@ -1147,6 +526,7 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int
* @param xf,yf End point of the line segment * @param xf,yf End point of the line segment
* @return the distance * @return the distance
*/ */
double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf )
{ {
// test for vertical or horizontal segment // test for vertical or horizontal segment
if( xf==xi ) if( xf==xi )
...@@ -1190,7 +570,6 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int ...@@ -1190,7 +570,6 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int
// test for value within range // test for value within range
//
bool InRange( double x, double xi, double xf ) bool InRange( double x, double xi, double xf )
{ {
if( xf > xi ) if( xf > xi )
...@@ -1206,211 +585,3 @@ bool InRange( double x, double xi, double xf ) ...@@ -1206,211 +585,3 @@ bool InRange( double x, double xi, double xf )
return false; return false;
} }
// this finds approximate solutions
// note: this works best if el2 is smaller than el1
//
int GetArcIntersections( EllipseKH* el1, EllipseKH* el2,
double* x1, double* y1, double* x2, double* y2 )
{
if( el1->theta2 > el1->theta1 )
{
wxASSERT( 0 );
}
if( el2->theta2 > el2->theta1 )
{
wxASSERT( 0 );
}
const int NSTEPS = 32;
double xret[2], yret[2];
double xscale = 1.0 / el1->xrad;
double yscale = 1.0 / el1->yrad;
// now transform params of second ellipse into reference frame
// with origin at center if first ellipse,
// scaled so the first ellipse is a circle of radius = 1.0
double xo = (el2->Center.X - el1->Center.X) * xscale;
double yo = (el2->Center.Y - el1->Center.Y) * yscale;
double xr = el2->xrad * xscale;
double yr = el2->yrad * yscale;
// now test NSTEPS positions in arc, moving clockwise (ie. decreasing theta)
double step = M_PI / ( (NSTEPS - 1) * 2.0 );
double d_prev = 0;
double th_interp;
double th1;
int n = 0;
for( int i = 0; i<NSTEPS; i++ )
{
double theta;
if( i < NSTEPS - 1 )
theta = el2->theta1 - i * step;
else
theta = el2->theta2;
double x = xo + xr * cos( theta );
double y = yo + yr * sin( theta );
double d = 1.0 - sqrt( x * x + y * y );
if( i>0 )
{
bool bInt = false;
if( d >= 0.0 && d_prev <= 0.0 )
{
th_interp = theta + ( step * (-d_prev) ) / (d - d_prev);
bInt = true;
}
else if( d <= 0.0 && d_prev >= 0.0 )
{
th_interp = theta + (step * d_prev) / (d_prev - d);
bInt = true;
}
if( bInt )
{
x = xo + xr * cos( th_interp );
y = yo + yr * sin( th_interp );
th1 = atan2( y, x );
if( th1 <= el1->theta1 && th1 >= el1->theta2 )
{
xret[n] = x * el1->xrad + el1->Center.X;
yret[n] = y * el1->yrad + el1->Center.Y;
n++;
if( n > 2 )
{
wxASSERT( 0 );
}
}
}
}
d_prev = d;
}
if( x1 )
*x1 = xret[0];
if( y1 )
*y1 = yret[0];
if( x2 )
*x2 = xret[1];
if( y2 )
*y2 = yret[1];
return n;
}
// this finds approximate solution
//
// double GetSegmentClearance( EllipseKH * el1, EllipseKH * el2,
double GetArcClearance( EllipseKH* el1, EllipseKH* el2,
double* x1, double* y1 )
{
const int NSTEPS = 32;
if( el1->theta2 > el1->theta1 )
{
wxASSERT( 0 );
}
if( el2->theta2 > el2->theta1 )
{
wxASSERT( 0 );
}
// test multiple positions in both arcs, moving clockwise (ie. decreasing theta)
double th_start = el1->theta1;
double th_end = el1->theta2;
double th_start2 = el2->theta1;
double th_end2 = el2->theta2;
double dmin = DBL_MAX;
double xmin = 0, ymin = 0, thmin = 0, thmin2 = 0;
int nsteps = NSTEPS;
int nsteps2 = NSTEPS;
double step = (th_start - th_end) / (nsteps - 1);
double step2 = (th_start2 - th_end2) / (nsteps2 - 1);
while( ( step * max( el1->xrad, el1->yrad ) ) > 1.0 * NM_PER_MIL
&& ( step2 * max( el2->xrad, el2->yrad ) ) > 1.0 * NM_PER_MIL )
{
step = (th_start - th_end) / (nsteps - 1);
for( int i = 0; i<nsteps; i++ )
{
double theta;
if( i < nsteps - 1 )
theta = th_start - i * step;
else
theta = th_end;
double x = el1->Center.X + el1->xrad * cos( theta );
double y = el1->Center.Y + el1->yrad * sin( theta );
step2 = (th_start2 - th_end2) / (nsteps2 - 1);
for( int i2 = 0; i2<nsteps2; i2++ )
{
double theta2;
if( i2 < nsteps2 - 1 )
theta2 = th_start2 - i2 * step2;
else
theta2 = th_end2;
double x2 = el2->Center.X + el2->xrad * cos( theta2 );
double y2 = el2->Center.Y + el2->yrad * sin( theta2 );
double d = Distance( x, y, x2, y2 );
if( d < dmin )
{
dmin = d;
xmin = x;
ymin = y;
thmin = theta;
thmin2 = theta2;
}
}
}
if( step > step2 )
{
th_start = min( el1->theta1, thmin + step );
th_end = max( el1->theta2, thmin - step );
step = (th_start - th_end) / nsteps;
}
else
{
th_start2 = min( el2->theta1, thmin2 + step2 );
th_end2 = max( el2->theta2, thmin2 - step2 );
step2 = (th_start2 - th_end2) / nsteps2;
}
}
if( x1 )
*x1 = xmin;
if( y1 )
*y1 = ymin;
return dmin;
}
// math stuff for graphics, from FreePCB // math stuff for graphics, from FreePCB
// math stuff for graphics
bool Quadratic( double a, double b, double c, double *x1, double *x2 );
/** /**
* Function TestLineHit * Function TestLineHit
* test for hit on line segment i.e. a point within a given distance from segment * test for hit on line segment i.e. a point within a given distance from segment
...@@ -14,13 +10,23 @@ bool Quadratic( double a, double b, double c, double *x1, double *x2 ); ...@@ -14,13 +10,23 @@ bool Quadratic( double a, double b, double c, double *x1, double *x2 );
*/ */
bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist ); bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist );
int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style, /* Function FindLineSegmentIntersection
* find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf)
* if b > DBL_MAX/10, assume vertical line at x = a
* return false if no intersection or true if intersect
* return coords of intersections in *x1, *y1, *x2, *y2
* if no intersection, returns min distance in dist
*/
bool FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf,
double * x1, double * y1, double * x2, double * y2, double * dist=NULL ); double * x1, double * y1, double * x2, double * y2, double * dist=NULL );
int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
int xi2, int yi2, int xf2, int yf2, int style2, /* Function FindSegmentIntersections
double x[]=NULL, double y[]=NULL ); * find intersections between line segment (xi,yi) to (xf,yf)
bool FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 ); * and line segment (xi2,yi2) to (xf2,yf2)
bool FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 ); * returns true if intersection found
*/
bool FindSegmentIntersections( int xi, int yi, int xf, int yf,
int xi2, int yi2, int xf2, int yf2 );
/** /**
* Function TestForIntersectionOfStraightLineSegments * Function TestForIntersectionOfStraightLineSegments
...@@ -39,8 +45,13 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y ...@@ -39,8 +45,13 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
int x2i, int y2i, int x2f, int y2f, int x2i, int y2i, int x2f, int y2f,
int * x=NULL, int * y=NULL, double * dist=NULL ); int * x=NULL, int * y=NULL, double * dist=NULL );
int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1, /* Function GetClearanceBetweenSegments
int x2i, int y2i, int x2f, int y2f, int style2, int w2, * Get clearance between 2 segments
* Returns coordinates of the closest point between these 2 segments in x, y
* If 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 w1,
int x2i, int y2i, int x2f, int y2f, int w2,
int max_cl, int * x, int * y ); int max_cl, int * x, int * y );
/** /**
...@@ -52,6 +63,11 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, ...@@ -52,6 +63,11 @@ 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 GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf );
/* Function GetPointToLineDistance
* Get min. distance from (x,y) to line y = a + bx
* if b > DBL_MAX/10, assume vertical line at x = a
* returns closest point on line in xpp, ypp
*/
double GetPointToLineDistance( double a, double b, int x, int y, double * xp=NULL, double * yp=NULL ); double GetPointToLineDistance( double a, double b, int x, int y, double * xp=NULL, double * yp=NULL );
double Distance( double x1, double y1, double x2, double y2 ); double Distance( double x1, double y1, double x2, double y2 );
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment