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:
* @param aLayer = the layer of area
* @param aStartPointPosition = position of the first point of the polygon outline of this area
* @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,
int aLayer, wxPoint aStartPointPosition, int aHatch );
......@@ -1054,58 +1054,30 @@ public:
ZONE_CONTAINER* InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch );
/**
* Function TestAreaPolygon
* Test an area for self-intersection.
*
* @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.
* Function NormalizeAreaPolygon
* 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)
* 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 undo commands) can be NULL
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new created areas pickers
* @param aCurrArea = the zone to process
* @param bMessageBoxInt == true, shows message when clipping occurs.
* @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
* @return true if changes are made
* Also sets areas->utility1 flags if areas are modified
*/
int ClipAreaPolygon( PICKED_ITEMS_LIST* aNewZonesList,
ZONE_CONTAINER* aCurrArea,
bool bMessageBoxArc,
bool bMessageBoxInt,
bool bRetainArcs = true );
bool NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
ZONE_CONTAINER* aCurrArea );
/**
* Process an area that has been modified, by clipping its polygon against
* itself and the polygons for any other areas on the same net.
* Function OnAreaPolygonModified
* 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.
* @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 bMessageBoxInt : if true, shows message boxes when clipping occurs.
* @param bMessageBoxArc if true, shows message when clipping can't be done due to arcs.
* @return :
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides, polygon clipped
* @return true if some areas modified
*/
int AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area,
bool bMessageBoxArc,
bool bMessageBoxInt );
bool OnAreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area );
/**
* Function CombineAllAreasInNet
......@@ -1113,15 +1085,13 @@ public:
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful
* in undo commands can be NULL
* @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* @param aUseUtility : if true, don't check areas if both utility flags are 0
* 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,
bool bMessageBox,
bool bUseUtility );
bool aUseUtility );
/**
* Function RemoveArea
......@@ -1154,17 +1124,15 @@ public:
/**
* Function CombineAreas
* If possible, combine 2 copper areas
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful
* in undo commands can be NULL
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas
* (useful for undo).
* @param area_ref = the main area (zone)
* @param area_to_combine = the zone that can be merged with area_ref
* area_ref must be BEFORE area_to_combine
* area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
* @return : true if area_to_combine is combined with area_ref (and therefore be deleted)
*/
int CombineAreas( PICKED_ITEMS_LIST* aDeletedList,
bool CombineAreas( PICKED_ITEMS_LIST* aDeletedList,
ZONE_CONTAINER* area_ref,
ZONE_CONTAINER* area_to_combine );
......
......@@ -44,6 +44,7 @@
#include <class_board.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
......
......@@ -47,6 +47,7 @@
#include <pcbnew.h>
#include <zones.h>
#include <math_for_graphics.h>
#include <polygon_test_point_inside.h>
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
m_cornerRadius = 0;
utility = 0; // flags used in polygon calculations
utility2 = 0; // flags used in polygon calculations
m_Poly = new CPolyLine(); // Outlines
aBoard->GetZoneSettings().ExportSetting( *this );
}
......@@ -102,7 +102,6 @@ ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone ) :
utility = aZone.utility;
utility2 = aZone.utility;
}
......
......@@ -573,7 +573,7 @@ public:
// thickness of the copper bridge in thermal reliefs
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
bool m_IsFilled;
......
......@@ -45,6 +45,7 @@
#include <class_zone.h>
#include <class_marker_pcb.h>
#include <math_for_graphics.h>
#include <polygon_test_point_inside.h>
/* compare 2 trapezoids (can be rectangle) and return true if distance > aDist
......
......@@ -44,8 +44,6 @@
#include <zones_functions_for_undo_redo.h>
#include <drc_stuff.h>
bool s_Verbose = false; // false if zone outline diags must not be shown
// Outline creation:
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,
......@@ -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
// Combine zones if possible
GetBoard()->AreaPolygonModified( &_AuxiliaryList, newZone, true, s_Verbose );
GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, newZone );
// Redraw zones
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*
// Combine zones if possible
wxBusyCursor dummy;
GetBoard()->AreaPolygonModified( &_AuxiliaryList, aZone, true, s_Verbose );
GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone );
m_canvas->Refresh();
......@@ -389,7 +387,7 @@ void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone )
aZone->m_Poly->DeleteCorner( aZone->m_CornerSelection );
// modify zones outlines according to the new aZone shape
GetBoard()->AreaPolygonModified( &_AuxiliaryList, aZone, true, s_Verbose );
GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone );
if( DC )
{
......@@ -768,7 +766,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC )
GetScreen()->SetCurItem( NULL ); // This outline can be deleted when merging outlines
// Combine zones if possible :
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone, true, s_Verbose );
GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, zone );
// Redraw the real edge zone :
GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
......@@ -898,7 +896,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone )
aZone->SetNetName( net->GetNetname() );
// Combine zones if possible
GetBoard()->AreaPolygonModified( &_AuxiliaryList, aZone, true, s_Verbose );
GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone );
// Redraw the real new zone outlines
GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, -1 );
......
......@@ -35,6 +35,7 @@
#include <pcbnew.h>
#include <zones.h>
#include <polygon_test_point_inside.h>
/**
......
......@@ -28,7 +28,6 @@
#include <algorithm> // sort
#include <fctsys.h>
#include <common.h>
#include <macros.h>
......@@ -40,6 +39,7 @@
#include <pcbnew.h>
#include <zones.h>
#include <polygon_test_point_inside.h>
static bool CmpZoneSubnetValue( const BOARD_CONNECTED_ITEM* a, const BOARD_CONNECTED_ITEM* b );
void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode );
......
......@@ -43,11 +43,7 @@
#include <drc_stuff.h>
#include <math_for_graphics.h>
static bool bDontShowSelfIntersectionArcsWarning;
static bool bDontShowSelfIntersectionWarning;
static bool bDontShowIntersectionArcsWarning;
#define STRAIGHT 0 // To be remove after math_for_graphics code cleanup
/**
* Function AddArea
......@@ -126,199 +122,31 @@ ZONE_CONTAINER* BOARD::InsertArea( int netcode, int iarea, int layer, int x, int
/**
* Function TestAreaPolygon
* Test an area for self-intersection.
*
* @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.
* Function NormalizeAreaPolygon
* 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)
* 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
* undo commands) can be NULL
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new created areas
* @param aCurrArea = the zone to process
* @param bMessageBoxInt == true, shows message when clipping occurs.
* @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
* @return true if changes are made
* Also sets areas->utility1 flags if areas are modified
*/
int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
ZONE_CONTAINER* aCurrArea,
bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs )
bool BOARD::NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
ZONE_CONTAINER* aCurrArea )
{
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++ )
m_ZoneDescriptorList[ia]->utility = 0;
aCurrArea->utility = 1;
if( test == 1 )
{
// 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 );
}
}
if( curr_polygon->IsPolygonSelfIntersecting() )
{
std::vector<CPolyLine*>* pa = new std::vector<CPolyLine*>;
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( n_poly > 1 )
......@@ -340,61 +168,46 @@ int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
NewArea->utility = 1;
}
}
curr_polygon->Hatch();
delete pa;
}
return test;
curr_polygon->Hatch();
return true;
}
/**
* Process an area that has been modified, by clipping its polygon against
* 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.
* @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas
* (useful in undo commands can be NULL
* @param modified_area = area to test
* @param bMessageBoxArc if true, shows message when clipping can't be done due to arcs.
* @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
* @return true if some areas modified
*/
int BOARD::AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area,
bool bMessageBoxArc,
bool bMessageBoxInt )
bool BOARD::OnAreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area )
{
// clip polygon against itself
int test = ClipAreaPolygon( aModifiedZonesList, modified_area, bMessageBoxArc, bMessageBoxInt );
if( test == -1 )
return test;
bool modified = NormalizeAreaPolygon( aModifiedZonesList, modified_area );
// now see if we need to clip against other areas
int layer = modified_area->GetLayer();
bool bCheckAllAreas = false;
if( test == 1 )
bCheckAllAreas = true;
else
bCheckAllAreas = TestAreaIntersections( modified_area );
bool bCheckAllAreas = TestAreaIntersections( modified_area );
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( m_ZoneDescriptorList.size() > 0 )
{
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
m_ZoneDescriptorList[ia]->BuildFilledPolysListData( this );
}
}
// Test for bad areas: all zones must have more than 2 corners:
// Note: should not happen, but just in case.
......@@ -408,33 +221,29 @@ int BOARD::AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
RemoveArea( aModifiedZonesList, zone );
}
return test;
return modified;
}
/**
* Function CombineAllAreasInNet
* 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
* undo commands can be NULL
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful
* in undo commands can be NULL
* @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* @param aUseUtility : if true, don't check areas if both utility flags are 0
* 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 bMessageBox, bool bUseUtility )
bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
bool aUseUtility )
{
if( m_ZoneDescriptorList.size() <= 1 )
return 0;
return false;
// start by testing all area polygons to set utility2 flags
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
if( m_ZoneDescriptorList[ia]->GetNet() == aNetCode )
TestAreaPolygon( m_ZoneDescriptorList[ia] );
bool modified = false;
// now loop through all combinations
//Loop through all combinations
for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ia1++ )
{
ZONE_CONTAINER* curr_area = m_ZoneDescriptorList[ia1];
......@@ -458,15 +267,14 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
if( curr_area->GetIsKeepout() != area2->GetIsKeepout() )
continue;
if( curr_area->GetLayer() == area2->GetLayer()
&& curr_area->utility2 != -1 && area2->utility2 != -1 )
if( curr_area->GetLayer() == area2->GetLayer() )
{
CRect b2 = area2->m_Poly->GetCornerBounds();
if( !( b1.left > b2.right || b1.right < b2.left
|| b1.bottom > b2.top || b1.top < b2.bottom ) )
{
// 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 );
......@@ -476,19 +284,7 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
if( ret == 1 )
{
mod_ia1 = 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 );
}
modified = true;
}
}
}
......@@ -499,7 +295,7 @@ int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode,
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 )
{
int xi1 = poly1->GetX( ic1 );
int yi1 = poly1->GetY( ic1 );
int xf1, yf1, style1;
int xf1, yf1;
if( ic1 < ie1 )
{
......@@ -569,8 +365,6 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
yf1 = poly1->GetY( is1 );
}
style1 = poly1->GetSideStyle( ic1 );
for( int icont2 = 0; icont2 < poly2->GetContoursCount(); icont2++ )
{
int is2 = poly2->GetContourStart( icont2 );
......@@ -580,7 +374,7 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
{
int xi2 = poly2->GetX( ic2 );
int yi2 = poly2->GetY( ic2 );
int xf2, yf2, style2;
int xf2, yf2;
if( ic2 < ie2 )
{
......@@ -593,9 +387,8 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
yf2 = poly2->GetY( is2 );
}
style2 = poly2->GetSideStyle( ic2 );
int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1,
xi2, yi2, xf2, yf2, style2 );
int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1,
xi2, yi2, xf2, yf2 );
if( n_int )
return true;
}
......@@ -640,7 +433,6 @@ bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test )
* @param area_to_test = area to compare for intersection calculations
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
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_
CRect b1 = poly1->GetCornerBounds();
CRect b2 = poly2->GetCornerBounds();
if( b1.bottom > b2.top
|| b1.top < b2.bottom
|| b1.left > b2.right
|| b1.right < b2.left )
if( b1.bottom > b2.top || b1.top < b2.bottom ||
b1.left > b2.right || b1.right < b2.left )
return 0;
// now test for intersecting segments
bool bInt = false;
bool bArcInt = false;
for( int icont1 = 0; icont1<poly1->GetContoursCount(); icont1++ )
{
......@@ -674,7 +463,7 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
{
int xi1 = poly1->GetX( ic1 );
int yi1 = poly1->GetY( ic1 );
int xf1, yf1, style1;
int xf1, yf1;
if( ic1 < ie1 )
{
......@@ -687,8 +476,6 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
yf1 = poly1->GetY( is1 );
}
style1 = poly1->GetSideStyle( ic1 );
for( int icont2 = 0; icont2<poly2->GetContoursCount(); icont2++ )
{
int is2 = poly2->GetContourStart( icont2 );
......@@ -698,7 +485,7 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
{
int xi2 = poly2->GetX( ic2 );
int yi2 = poly2->GetY( ic2 );
int xf2, yf2, style2;
int xf2, yf2;
if( ic2 < ie2 )
{
......@@ -711,37 +498,20 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
yf2 = poly2->GetY( is2 );
}
style2 = poly2->GetSideStyle( ic2 );
int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1,
xi2, yi2, xf2, yf2, style2 );
int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1,
xi2, yi2, xf2, yf2 );
if( n_int )
{
bInt = true;
if( style1 != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT )
bArcInt = true;
break;
}
}
if( bArcInt )
break;
}
if( bArcInt )
break;
}
if( bArcInt )
break;
}
if( !bInt )
{
if( bArcInt )
return 0;
// 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)
for( int ic2 = 0; ic2 < poly2->GetNumCorners(); ic2++ )
......@@ -769,9 +539,6 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
return 0;
}
if( bArcInt )
return 2;
return 1;
}
......@@ -779,24 +546,22 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
/**
* Function CombineAreas
* Merge 2 copper areas (which are expected intersecting)
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo
* commands can be NULL
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas
* (useful for undo command)
* @param area_ref = the main area (zone)
* @param area_to_combine = the zone that can be merged with area_ref
* area_ref must be BEFORE area_to_combine
* area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect (Currently not supported)
* @return : true if area_to_combine is combined with area_ref (and therefore be deleted)
*/
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 )
{
if( area_ref == area_to_combine )
{
wxASSERT( 0 );
return 0;
return false;
}
// polygons intersect, combine them
......@@ -920,7 +685,7 @@ int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_r
area_ref->utility = 1;
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
ay2 = refSmoothedPoly->GetY( ic + 1 );
}
int astyle = refSmoothedPoly->GetSideStyle( ic );
for( int icont2 = 0; icont2 < testSmoothedPoly->GetContoursCount(); 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
by2 = testSmoothedPoly->GetY( ic2 + 1 );
}
int bstyle = testSmoothedPoly->GetSideStyle( ic2 );
int x, y;
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle,
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
0,
ax1, ay1, ax2,
ay2, astyle,
ax1, ay1, ax2, ay2,
0,
zone2zoneClearance,
&x, &y );
......@@ -1196,7 +957,6 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex )
}
// now test spacing between areas
int astyle = CPolyLine::STRAIGHT;
int ax1 = start.x;
int ay1 = start.y;
int ax2 = end.x;
......@@ -1224,11 +984,10 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex )
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 d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle,
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
0,
ax1, ay1, ax2, ay2, astyle,
ax1, ay1, ax2, ay2,
0,
zone_clearance,
&x, &y );
......
......@@ -14,6 +14,10 @@
#include <bezier_curves.h>
#include <polygon_test_point_inside.h>
#include <math_for_graphics.h>
#include <polygon_test_point_inside.h>
enum m_SideStyle { STRAIGHT }; // side styles
CPolyLine::CPolyLine()
{
......@@ -57,12 +61,11 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false );
* because copper areas have only one outside contour
* 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 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
*/
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<int>* hole; // used to store corners for a given hole
CPolyLine* polyline;
......@@ -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
* True holes are combined if possible
*/
if( bRetainArcs )
MakeKboolPoly( &arc_array );
else
MakeKboolPoly( NULL );
MakeKboolPoly();
UnHatch();
......@@ -111,7 +111,6 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool
{
// first external contour, replace this poly
m_CornersList.clear();
m_SideStyle.clear();
bool first = true;
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
......@@ -203,16 +202,13 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool
{
int x = (*hole)[ii]; ii++;
int y = (*hole)[ii];
polyline->AppendCorner( x, y, STRAIGHT, false );
polyline->AppendCorner( x, y );
}
polyline->CloseLastContour();
}
}
if( bRetainArcs )
RestoreArcs( &arc_array, aExtraPolyList );
delete m_Kbool_Poly_Engine;
m_Kbool_Poly_Engine = NULL;
......@@ -263,12 +259,10 @@ int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng, GroupType aGroup )
/**
* Function MakeKboolPoly
* 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 corners computed from arcs approximations in arc_array
* normalize self-intersecting contours
* @return error: 0 if Ok, 1 if error
*/
int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array )
int CPolyLine::MakeKboolPoly()
{
if( m_Kbool_Poly_Engine )
{
......@@ -279,15 +273,9 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array )
if( !GetClosed() )
return 1; // error
int n_arcs = 0;
int polycount = GetContoursCount();
int last_contour = polycount - 1;
if( arc_array )
arc_array->clear();
int iarc = 0;
for( int icont = 0; icont <= last_contour; icont++ )
{
// Fill a kbool engine for this contour,
......@@ -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_end = GetContourEnd( icont );
......@@ -325,159 +311,12 @@ int CPolyLine::MakeKboolPoly( std::vector<CArc>* arc_array )
return 1; // error
}
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++ )
// Enter this contour to booleng
for( int ic = ic_st; ic <= ic_end; ic++ )
{
int style = m_SideStyle[ic];
int x1 = m_CornersList[ic].x;
int y1 = m_CornersList[ic].y;
int x2, y2;
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
......@@ -604,194 +443,23 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles )
}
int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* pa, bool bRetainArcs )
{
return NormalizeWithKbool( pa, bRetainArcs );
}
// Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array
//
int CPolyLine::RestoreArcs( std::vector<CArc>* arc_array, std::vector<CPolyLine*>* pa )
/**
* Function NormalizeAreaOutlines
* Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
* @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
* needed by the normalization
* @return the polygon count (always >= 1, becuse there is at lesat one polygon)
* There are new polygons only if the polygon count is > 1
*/
int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
{
// get poly info
int n_polys = 1;
if( pa )
n_polys += pa->size();
CPolyLine* poly;
// undraw polys and clear m_utility flag for all corners
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;
return NormalizeWithKbool( aNewPolygonList );
}
// initialize new polyline
// set layer, width, selection box size, starting point, id and pointer
//
// 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
//
/* initialize a contour
* set layer, hatch style, and starting point
*/
void CPolyLine::Start( int layer, int x, int y, int hatch )
{
m_layer = layer;
......@@ -800,27 +468,19 @@ void CPolyLine::Start( int layer, int x, int y, int hatch )
poly_pt.end_contour = false;
m_CornersList.push_back( poly_pt );
m_SideStyle.push_back( 0 );
}
// 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();
CPolyPt poly_pt( x, y );
poly_pt.end_contour = false;
// add entries for new corner and side
// add entries for new corner
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 )
// delete corner and adjust arrays
//
void CPolyLine::DeleteCorner( int ic, bool bDraw )
void CPolyLine::DeleteCorner( int ic )
{
UnHatch();
int icont = GetContour( ic );
int istart = GetContourStart( 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
m_CornersList.erase( m_CornersList.begin() + ic );
if( ic != istart )
m_SideStyle.erase( m_SideStyle.begin() + ic - 1 );
}
else
{
// closed contour
m_CornersList.erase( m_CornersList.begin() + ic );
m_SideStyle.erase( m_SideStyle.begin() + ic );
if( ic == iend )
m_CornersList[ic - 1].end_contour = true;
}
if( bClosed && GetContourSize( icont ) < 3 )
if( closed && GetContourSize( icont ) < 3 )
{
// delete the entire contour
RemoveContour( icont );
}
if( bDraw )
Hatch();
}
......@@ -907,7 +559,6 @@ void CPolyLine::RemoveContour( int icont )
{
// remove last contour
m_CornersList.erase( m_CornersList.begin() + istart, m_CornersList.end() );
m_SideStyle.erase( m_SideStyle.begin() + istart, m_SideStyle.end() );
}
else
{
......@@ -915,7 +566,6 @@ void CPolyLine::RemoveContour( int icont )
for( int ic = iend; ic>=istart; ic-- )
{
m_CornersList.erase( m_CornersList.begin() + ic );
m_SideStyle.erase( m_SideStyle.begin() + ic );
}
}
......@@ -1140,7 +790,6 @@ void CPolyLine::RemoveAllContours( void )
*/
{
m_CornersList.clear();
m_SideStyle.clear();
}
......@@ -1157,12 +806,10 @@ void CPolyLine::InsertCorner( int ic, int x, int y )
if( (unsigned) (ic) >= m_CornersList.size() )
{
m_CornersList.push_back( CPolyPt( x, y ) );
m_SideStyle.push_back( STRAIGHT );
}
else
{
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() )
......@@ -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()
{
if( m_CornersList.size() == 0 )
......@@ -1500,7 +1112,6 @@ void CPolyLine::Hatch()
m_CornersList[ic].x, m_CornersList[ic].y,
m_CornersList[i_start_contour].x,
m_CornersList[i_start_contour].y,
m_SideStyle[ic],
&x, &y, &x2, &y2 );
i_start_contour = ic + 1;
}
......@@ -1509,7 +1120,6 @@ void CPolyLine::Hatch()
ok = FindLineSegmentIntersection( a, slope,
m_CornersList[ic].x, m_CornersList[ic].y,
m_CornersList[ic + 1].x, m_CornersList[ic + 1].y,
m_SideStyle[ic],
&x, &y, &x2, &y2 );
}
......@@ -1625,8 +1235,6 @@ void CPolyLine::Copy( CPolyLine* src )
m_hatchPitch = src->m_hatchPitch;
// copy corners, using vector copy
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 )
}
/*
* 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 )
{
......@@ -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 y = KiROUND( yc + radius * sin( theta ) );
AppendCorner( x, y, STRAIGHT, 0 );
AppendCorner( x, y );
theta += th_d;
}
......@@ -1776,10 +1385,9 @@ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth )
by2 = GetY( ic2 + 1 );
}
int bstyle = GetSideStyle( ic2 );
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle, 0,
int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
aStart.x, aStart.y, aEnd.x, aEnd.y,
CPolyLine::STRAIGHT, aWidth,
aWidth,
1, // min clearance, should be > 0
NULL, NULL );
......@@ -1835,12 +1443,9 @@ int CPolyLine::Distance( const wxPoint& aPoint )
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,
bx1, by1, bx2, by2 ) );
if( distance > d )
distance = d;
......@@ -2000,3 +1605,100 @@ void ConvertPolysListWithHolesToOnePolygon( const std::vector<CPolyPt>& aPolysL
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 @@
#include <polygons_defs.h>
// inflection modes for DS_LINE and DS_LINE_VERTEX, used in math_for_graphics.cpp
enum {
/*enum {
IM_NONE = 0,
IM_90_45,
IM_45_90,
IM_90
};
*/
class CRect
{
......@@ -58,6 +58,7 @@ public:
}
};
/*
class CArc
{
public:
......@@ -67,7 +68,7 @@ public:
int n_steps; // number of straight-line segments in gpc_poly
bool bFound;
};
*/
class CPolyPt : public wxPoint
{
......@@ -98,27 +99,41 @@ public:
};
#include <polygon_test_point_inside.h>
class CPolyLine
{
public:
enum m_SideStyle { STRAIGHT, ARC_CW, ARC_CCW }; // side styles
enum HATCH_STYLE { NO_HATCH, DIAGONAL_FULL, DIAGONAL_EDGE }; // hatch styles
// constructors/destructor
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 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 DeleteCorner( int ic, bool bDraw = false );
void DeleteCorner( int ic );
void MoveCorner( int ic, int x, int y );
void CloseLastContour();
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
* returns a chamfered version of a polygon.
......@@ -180,7 +195,6 @@ public:
int GetUtility( int ic ) { return m_CornersList[ic].m_utility; };
void SetUtility( int ic, int utility ) { m_CornersList[ic].m_utility = utility; };
int GetSideStyle( int is );
int GetHatchPitch() { return m_hatchPitch; }
static int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils
......@@ -197,7 +211,6 @@ public:
void SetX( int ic, int x );
void SetY( int ic, int y );
void SetEndContour( int ic, bool end_contour );
void SetSideStyle( int is, int style );
void SetHatchStyle( enum HATCH_STYLE style )
{
......@@ -206,10 +219,15 @@ public:
void SetHatchPitch( int pitch ) { m_hatchPitch = pitch; }
int RestoreArcs( std::vector<CArc>* arc_array, std::vector<CPolyLine*>* pa = NULL );
int NormalizeAreaOutlines( std::vector<CPolyLine*>* pa = NULL,
bool bRetainArcs = false );
/**
* Function NormalizeAreaOutlines
* Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
* @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
* needed by the normalization
* @return the polygon count (always >= 1, 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
......@@ -224,12 +242,9 @@ public:
/**
* Function MakeKboolPoly
* 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
*/
int MakeKboolPoly( std::vector<CArc>* arc_array = NULL );
int MakeKboolPoly();
/**
* Function NormalizeWithKbool
......@@ -240,10 +255,10 @@ public:
* because copper areas have only one outside contour
* 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 bRetainArcs == false, try to retain arcs in polys
* @return number of external contours, or -1 if error
* (when after normalization, there is more than one polygon with holes)
* @return number of contours, or -1 if error
*/
int NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList, bool bRetainArcs );
int NormalizeWithKbool( std::vector<CPolyLine*>* aExtraPolyList );
// Bezier Support
void AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3 );
......@@ -280,7 +295,6 @@ private:
Bool_Engine* m_Kbool_Poly_Engine; // polygons set in kbool engine data
public:
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
};
......
......@@ -11,37 +11,13 @@
#include <PolyLine.h>
#include <math_for_graphics.h>
#define NM_PER_MIL 25400
typedef struct PointTag
{
double X,Y;
} PointT;
typedef struct EllipseTag
{
PointT Center; /* ellipse center */
double xrad, yrad; // radii on x and y
double theta1, theta2; // start and end angle for arc
} EllipseKH;
static bool InRange( double x, double xi, double xf );
double Distance( double x1, double y1, double x2, double y2 )
{
double dx = x1 - x2;
double dy = y1 - y2;
double d = sqrt( dx * dx + dy * dy );
return d;
return hypot( x1 - x2, y1 - y2 );
}
static int GetArcIntersections( EllipseKH * el1, EllipseKH * el2,
double * x1=NULL, double * y1=NULL,
double * x2=NULL, double * y2=NULL );
static bool InRange( double x, double xi, double xf );
/**
* Function TestLineHit
* test for hit on line segment i.e. a point within a given distance from segment
......@@ -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
//
int MakeEllipseFromArc( int xi, int yi, int xf, int yf, int style, EllipseKH* el )
{
// arc (quadrant of ellipse)
// convert to clockwise arc
int xxi, xxf, yyi, yyf;
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[] )
/* Function FindSegmentIntersections
* find intersections between line segment (xi,yi) to (xf,yf)
* and line segment (xi2,yi2) to (xf2,yf2)
* returns true if intersection found
*/
bool FindSegmentIntersections( int xi, int yi, int xf, int yf,
int xi2, int yi2, int xf2, int yf2 )
{
double xr[12], yr[12];
int iret = 0;
if( max( xi, xf ) < min( xi2, xf2 )
|| min( xi, xf ) > max( xi2, xf2 )
|| max( yi, yf ) < min( yi2, yf2 )
|| min( yi, yf ) > max( yi2, yf2 ) )
return 0;
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 false;
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)
// if b > DBL_MAX/10, assume vertical line at x = a
// the line segment may be an arc (i.e. quadrant of an ellipse)
// return 0 if no intersection
// returns 1 or 2 if intersections found
// sets coords of intersections in *x1, *y1, *x2, *y2
// if no intersection, returns min distance in 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 )
{
......@@ -378,10 +116,7 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
if( b > DBL_MAX / 10.0 )
bVert = true;
if( xf != xi )
{
// non-vertical segment, get intersection
if( style == CPolyLine::STRAIGHT || yf == yi )
if( xf != xi ) // non-vertical segment, get intersection
{
// horizontal or oblique straight segment
// put into form y = c + dx;
......@@ -402,7 +137,7 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
if( dist )
*dist = min( abs( a - xi ), abs( a - xf ) );
return 0;
return false;
}
}
......@@ -414,7 +149,7 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
*dist = GetPointToLineDistance( a, b, xi, xf );
}
return 0; // lines parallel
return false; // lines parallel
}
// calculate intersection
......@@ -426,140 +161,21 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
{
// horizontal line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf) )
return 0;
return false;
}
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)
// convert to clockwise arc
int xxi, xxf, yyi, yyf;
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 = xxf, yo = yyi, rx, ry; // Init made to avoid C compil warnings
if( xxf > xxi && yyf > yyi )
{
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 )
{
// shift vertical line to coordinate system of ellipse
aa = a - xo;
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
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;
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) )
{
if( (yyf>yyi && yy2<yyf && yy2>yyi) || (yyf<yyi && yy2<yyi && yy2>yyf) )
{
if( npts == 0 )
{
*x1 = xx2;
*y1 = yy2;
npts = 1;
}
else
{
*x2 = xx2;
*y2 = yy2;
npts = 2;
}
}
return false;
}
return npts;
}
else
wxASSERT( 0 );
}
else
{
// vertical line segment
if( bVert )
return 0;
return false;
xx = xi;
yy = a + b * xx;
......@@ -570,7 +186,7 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
*x1 = xx;
*y1 = yy;
return 1;
return true;
}
......@@ -640,7 +256,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y2i - b * x2i;
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 );
if( test )
......@@ -668,7 +284,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y2i - b * x2i;
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 );
if( test )
......@@ -696,7 +312,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y1i - b * x1i;
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 );
if( test )
......@@ -724,7 +340,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y1i - b * x1i;
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 );
if( test )
......@@ -754,17 +370,8 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
a = (double) y1i - b * x1i;
double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a,
b,
x2i,
y2i,
x2f,
y2f,
CPolyLine::STRAIGHT,
&x1,
&y1,
&x2,
&y2 );
int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f,
&x1, &y1, &x2, &y2 );
// both segments oblique
if( test )
......@@ -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 )
{
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 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 )
{
// check clearance between bounding rectangles
......@@ -904,14 +462,11 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1,
if( min( y2i, y2f ) - max( y1i, y1f ) > min_dist )
return max_cl+1;
if( style1 == CPolyLine::STRAIGHT && style1 == CPolyLine::STRAIGHT )
{
// both segments are straight lines
int xx, yy;
double dd;
double dist;
TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f,
x2i, y2i, x2f, y2f, &xx, &yy, &dd );
int d = (int) dd - ( (w1 + w2) / 2 );
x2i, y2i, x2f, y2f, &xx, &yy, &dist );
int d = (int) dist - ( (w1 + w2) / 2 );
if( d < 0 )
d = 0;
......@@ -922,187 +477,14 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1,
*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 )
*x = (int) xmin;
if( y )
*y = (int) ymin;
return max( 0, (int) dmin - w1 / 2 - w2 / 2 ); // allow for widths
}
// 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 xp, yp
//
/* 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* xpp, double* ypp )
{
if( b > DBL_MAX / 10 )
......@@ -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
* Get distance between line segment and point
......@@ -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
* @return the distance
*/
double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf )
{
// test for vertical or horizontal segment
if( xf==xi )
......@@ -1190,7 +570,6 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int
// test for value within range
//
bool InRange( double x, double xi, double xf )
{
if( xf > xi )
......@@ -1206,211 +585,3 @@ bool InRange( double x, double xi, double xf )
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
bool Quadratic( double a, double b, double c, double *x1, double *x2 );
/**
* Function TestLineHit
* 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 );
*/
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 );
int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
int xi2, int yi2, int xf2, int yf2, int style2,
double x[]=NULL, double y[]=NULL );
bool FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 );
bool FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 );
/* Function FindSegmentIntersections
* find intersections between line segment (xi,yi) to (xf,yf)
* and line segment (xi2,yi2) to (xf2,yf2)
* 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
......@@ -39,8 +45,13 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
int x2i, int y2i, int x2f, int y2f,
int * x=NULL, int * y=NULL, double * dist=NULL );
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,
/* 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
*/
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 );
/**
......@@ -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 );
/* 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 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