Commit e126042b authored by raburton's avatar raburton

set eol-style native on new files

parent 5eda8a52
// PolyLine.cpp ... implementation of CPolyLine class // PolyLine.cpp ... implementation of CPolyLine class
// from FreePCB. // from FreePCB.
// Adaptation for kicad // Adaptation for kicad
// //
using namespace std; using namespace std;
#include <math.h> #include <math.h>
#include <vector> #include <vector>
#include "PolyLine.h" #include "PolyLine.h"
#define to_int(x) (int)round((x)) #define to_int(x) (int)round((x))
/* Stuff to compile PolyLine.cpp, used in std::vector as CArray. does not work. must be redesigned, only for test */ /* Stuff to compile PolyLine.cpp, used in std::vector as CArray. does not work. must be redesigned, only for test */
#define SetSize reserve #define SetSize reserve
#define pi 3.14159265359 #define pi 3.14159265359
#define DENOM 10 // to use mils for php clipping #define DENOM 10 // to use mils for php clipping
//#define DENOM 1 // to use internal units for php clipping //#define DENOM 1 // to use internal units for php clipping
// dl is a pointer to CDisplayList for drawing graphic elements // dl is a pointer to CDisplayList for drawing graphic elements
// if dl = NULL, doesn't draw anything but can still hold data // if dl = NULL, doesn't draw anything but can still hold data
// //
CPolyLine::CPolyLine( CDisplayList * dl ) CPolyLine::CPolyLine( CDisplayList * dl )
{ {
m_dlist = dl; m_dlist = dl;
m_HatchStyle = 0; m_HatchStyle = 0;
m_sel_box = 0; m_sel_box = 0;
m_gpc_poly = new gpc_polygon; m_gpc_poly = new gpc_polygon;
m_gpc_poly->num_contours = 0; m_gpc_poly->num_contours = 0;
m_php_poly = new polygon; m_php_poly = new polygon;
} }
CPolyLine::CPolyLine() CPolyLine::CPolyLine()
{ {
m_dlist = NULL; m_dlist = NULL;
m_HatchStyle = 0; m_HatchStyle = 0;
m_sel_box = 0; m_sel_box = 0;
m_gpc_poly = new gpc_polygon; m_gpc_poly = new gpc_polygon;
m_gpc_poly->num_contours = 0; m_gpc_poly->num_contours = 0;
m_php_poly = new polygon; m_php_poly = new polygon;
} }
// destructor, removes display elements // destructor, removes display elements
// //
CPolyLine::~CPolyLine() CPolyLine::~CPolyLine()
{ {
Undraw(); Undraw();
FreeGpcPoly(); FreeGpcPoly();
delete m_gpc_poly; delete m_gpc_poly;
delete m_php_poly; delete m_php_poly;
} }
// Use the General Polygon Clipping Library to clip contours // Use the General Polygon Clipping Library to clip contours
// If this results in new polygons, return them as std::vector p // If this results in new polygons, return them as std::vector p
// If bRetainArcs == TRUE, try to retain arcs in polys // If bRetainArcs == TRUE, try to retain arcs in polys
// Returns number of external contours, or -1 if error // Returns number of external contours, or -1 if error
// //
int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, BOOL bRetainArcs ) int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, BOOL bRetainArcs )
{ {
std::vector<CArc> arc_array; std::vector<CArc> arc_array;
if( bRetainArcs ) if( bRetainArcs )
MakeGpcPoly( -1, &arc_array ); MakeGpcPoly( -1, &arc_array );
else else
MakeGpcPoly( -1, NULL ); MakeGpcPoly( -1, NULL );
Undraw(); Undraw();
// now, recreate poly // now, recreate poly
// first, find outside contours and create new CPolyLines if necessary // first, find outside contours and create new CPolyLines if necessary
int n_ext_cont = 0; int n_ext_cont = 0;
for( int ic=0; ic<m_gpc_poly->num_contours; ic++ ) for( int ic=0; ic<m_gpc_poly->num_contours; ic++ )
{ {
if( !(m_gpc_poly->hole)[ic] ) if( !(m_gpc_poly->hole)[ic] )
{ {
if( n_ext_cont == 0 ) if( n_ext_cont == 0 )
{ {
// first external contour, replace this poly // first external contour, replace this poly
corner.clear(); corner.clear();
side_style.clear(); side_style.clear();
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{ {
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
if( i==0 ) if( i==0 )
Start( m_layer, m_Width, m_sel_box, x, y, m_HatchStyle ); Start( m_layer, m_Width, m_sel_box, x, y, m_HatchStyle );
else else
AppendCorner( x, y, STRAIGHT, FALSE ); AppendCorner( x, y, STRAIGHT, FALSE );
} }
Close(); Close();
n_ext_cont++; n_ext_cont++;
} }
else if( pa ) else if( pa )
{ {
// next external contour, create new poly // next external contour, create new poly
CPolyLine * poly = new CPolyLine; CPolyLine * poly = new CPolyLine;
pa->SetSize(n_ext_cont); // put in array pa->SetSize(n_ext_cont); // put in array
(*pa)[n_ext_cont-1] = poly; (*pa)[n_ext_cont-1] = poly;
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{ {
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
if( i==0 ) if( i==0 )
poly->Start( m_layer, m_Width, m_sel_box, x, y, m_HatchStyle ); poly->Start( m_layer, m_Width, m_sel_box, x, y, m_HatchStyle );
else else
poly->AppendCorner( x, y, STRAIGHT, FALSE ); poly->AppendCorner( x, y, STRAIGHT, FALSE );
} }
poly->Close( STRAIGHT, FALSE ); poly->Close( STRAIGHT, FALSE );
n_ext_cont++; n_ext_cont++;
} }
} }
} }
// now add cutouts to the CPolyLine(s) // now add cutouts to the CPolyLine(s)
for( int ic=0; ic<m_gpc_poly->num_contours; ic++ ) for( int ic=0; ic<m_gpc_poly->num_contours; ic++ )
{ {
if( (m_gpc_poly->hole)[ic] ) if( (m_gpc_poly->hole)[ic] )
{ {
CPolyLine * ext_poly = NULL; CPolyLine * ext_poly = NULL;
if( n_ext_cont == 1 ) if( n_ext_cont == 1 )
{ {
ext_poly = this; ext_poly = this;
} }
else else
{ {
// find the polygon that contains this hole // find the polygon that contains this hole
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{ {
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
if( TestPointInside( x, y ) ) if( TestPointInside( x, y ) )
ext_poly = this; ext_poly = this;
else else
{ {
for( int ext_ic=0; ext_ic<n_ext_cont-1; ext_ic++ ) for( int ext_ic=0; ext_ic<n_ext_cont-1; ext_ic++ )
{ {
if( (*pa)[ext_ic]->TestPointInside( x, y ) ) if( (*pa)[ext_ic]->TestPointInside( x, y ) )
{ {
ext_poly = (*pa)[ext_ic]; ext_poly = (*pa)[ext_ic];
break; break;
} }
} }
} }
if( ext_poly ) if( ext_poly )
break; break;
} }
} }
if( !ext_poly ) if( !ext_poly )
ASSERT(0); ASSERT(0);
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{ {
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
ext_poly->AppendCorner( x, y, STRAIGHT, FALSE ); ext_poly->AppendCorner( x, y, STRAIGHT, FALSE );
} }
ext_poly->Close( STRAIGHT, FALSE ); ext_poly->Close( STRAIGHT, FALSE );
} }
} }
if( bRetainArcs ) if( bRetainArcs )
RestoreArcs( &arc_array, pa ); RestoreArcs( &arc_array, pa );
FreeGpcPoly(); FreeGpcPoly();
return n_ext_cont; return n_ext_cont;
} }
// make a php_polygon from first contour // make a php_polygon from first contour
int CPolyLine::MakePhpPoly() int CPolyLine::MakePhpPoly()
{ {
FreePhpPoly(); FreePhpPoly();
polygon test_poly; polygon test_poly;
int nv = GetContourEnd(0); int nv = GetContourEnd(0);
for( int iv=0; iv<=nv; iv++ ) for( int iv=0; iv<=nv; iv++ )
{ {
int x = GetX(iv)/DENOM; int x = GetX(iv)/DENOM;
int y = GetY(iv)/DENOM; int y = GetY(iv)/DENOM;
m_php_poly->addv( x, y ); m_php_poly->addv( x, y );
} }
return 0; return 0;
} }
void CPolyLine::FreePhpPoly() void CPolyLine::FreePhpPoly()
{ {
// delete all vertices // delete all vertices
while( m_php_poly->m_cnt > 1 ) while( m_php_poly->m_cnt > 1 )
{ {
vertex * fv = m_php_poly->getFirst(); vertex * fv = m_php_poly->getFirst();
m_php_poly->del( fv->m_nextV ); m_php_poly->del( fv->m_nextV );
} }
delete m_php_poly->m_first; delete m_php_poly->m_first;
m_php_poly->m_first = NULL; m_php_poly->m_first = NULL;
m_php_poly->m_cnt = 0; m_php_poly->m_cnt = 0;
} }
// Use the php clipping lib to clip this poly against poly // Use the php clipping lib to clip this poly against poly
// //
void CPolyLine::ClipPhpPolygon( int php_op, CPolyLine * poly ) void CPolyLine::ClipPhpPolygon( int php_op, CPolyLine * poly )
{ {
Undraw(); Undraw();
poly->MakePhpPoly(); poly->MakePhpPoly();
MakePhpPoly(); MakePhpPoly();
polygon * p = m_php_poly->boolean( poly->m_php_poly, php_op ); polygon * p = m_php_poly->boolean( poly->m_php_poly, php_op );
poly->FreePhpPoly(); poly->FreePhpPoly();
FreePhpPoly(); FreePhpPoly();
if( p ) if( p )
{ {
// now screw with the PolyLine // now screw with the PolyLine
corner.clear(); corner.clear();
side_style.clear(); side_style.clear();
do do
{ {
vertex * v = p->getFirst(); vertex * v = p->getFirst();
Start( m_layer, m_Width, m_sel_box, Start( m_layer, m_Width, m_sel_box,
to_int(v->X()*DENOM), to_int(v->X()*DENOM),
to_int(v->Y()*DENOM), to_int(v->Y()*DENOM),
m_HatchStyle ); m_HatchStyle );
do do
{ {
vertex * n = v->Next(); vertex * n = v->Next();
AppendCorner( to_int(v->X()*DENOM), to_int((v->Y()*DENOM )) ); AppendCorner( to_int(v->X()*DENOM), to_int((v->Y()*DENOM )) );
v = n; v = n;
} }
while( v->id() != p->getFirst()->id() ); while( v->id() != p->getFirst()->id() );
Close(); Close();
// p = p->NextPoly(); // p = p->NextPoly();
delete p; delete p;
p = NULL; p = NULL;
} }
while( p ); while( p );
} }
Draw(); Draw();
} }
// make a gpc_polygon for a closed polyline contour // make a gpc_polygon for a closed polyline contour
// approximates arcs with multiple straight-line segments // approximates arcs with multiple straight-line segments
// if icontour = -1, make polygon with all contours, // if icontour = -1, make polygon with all contours,
// combining intersecting contours if possible // combining intersecting contours if possible
// returns data on arcs in arc_array // returns data on arcs in arc_array
// //
int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array ) int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array )
{ {
if( m_gpc_poly->num_contours ) if( m_gpc_poly->num_contours )
FreeGpcPoly(); FreeGpcPoly();
if( !GetClosed() && (icontour == (GetNumContours()-1) || icontour == -1)) if( !GetClosed() && (icontour == (GetNumContours()-1) || icontour == -1))
return 1; // error return 1; // error
// initialize m_gpc_poly // initialize m_gpc_poly
m_gpc_poly->num_contours = 0; m_gpc_poly->num_contours = 0;
m_gpc_poly->hole = NULL; m_gpc_poly->hole = NULL;
m_gpc_poly->contour = NULL; m_gpc_poly->contour = NULL;
int n_arcs = 0; int n_arcs = 0;
int first_contour = icontour; int first_contour = icontour;
int last_contour = icontour; int last_contour = icontour;
if( icontour == -1 ) if( icontour == -1 )
{ {
first_contour = 0; first_contour = 0;
last_contour = GetNumContours() - 1; last_contour = GetNumContours() - 1;
} }
if( arc_array ) if( arc_array )
arc_array->SetSize(0); arc_array->SetSize(0);
int iarc = 0; int iarc = 0;
for( int icont=first_contour; icont<=last_contour; icont++ ) for( int icont=first_contour; icont<=last_contour; icont++ )
{ {
// make gpc_polygon for this contour // make gpc_polygon for this contour
gpc_polygon * gpc = new gpc_polygon; gpc_polygon * gpc = new gpc_polygon;
gpc->num_contours = 0; gpc->num_contours = 0;
gpc->hole = NULL; gpc->hole = NULL;
gpc->contour = NULL; gpc->contour = NULL;
// first, calculate number of vertices in contour // first, calculate number of vertices in contour
int n_vertices = 0; int n_vertices = 0;
int ic_st = GetContourStart(icont); int ic_st = GetContourStart(icont);
int ic_end = GetContourEnd(icont); int ic_end = GetContourEnd(icont);
for( int ic=ic_st; ic<=ic_end; ic++ ) for( int ic=ic_st; ic<=ic_end; ic++ )
{ {
int style = side_style[ic]; int style = side_style[ic];
int x1 = corner[ic].x; int x1 = corner[ic].x;
int y1 = corner[ic].y; int y1 = corner[ic].y;
int x2, y2; int x2, y2;
if( ic < ic_end ) if( ic < ic_end )
{ {
x2 = corner[ic+1].x; x2 = corner[ic+1].x;
y2 = corner[ic+1].y; y2 = corner[ic+1].y;
} }
else else
{ {
x2 = corner[ic_st].x; x2 = corner[ic_st].x;
y2 = corner[ic_st].y; y2 = corner[ic_st].y;
} }
if( style == STRAIGHT ) if( style == STRAIGHT )
n_vertices++; n_vertices++;
else else
{ {
// style is ARC_CW or ARC_CCW // style is ARC_CW or ARC_CCW
int n; // number of steps for arcs int n; // number of steps for arcs
n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP); n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP);
n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc
n_vertices += n; n_vertices += n;
n_arcs++; n_arcs++;
} }
} }
// now create gcp_vertex_list for this contour // now create gcp_vertex_list for this contour
gpc_vertex_list * g_v_list = new gpc_vertex_list; gpc_vertex_list * g_v_list = new gpc_vertex_list;
g_v_list->vertex = (gpc_vertex*)calloc( sizeof(gpc_vertex), n_vertices ); g_v_list->vertex = (gpc_vertex*)calloc( sizeof(gpc_vertex), n_vertices );
g_v_list->num_vertices = n_vertices; g_v_list->num_vertices = n_vertices;
int ivtx = 0; int ivtx = 0;
for( int ic=ic_st; ic<=ic_end; ic++ ) for( int ic=ic_st; ic<=ic_end; ic++ )
{ {
int style = side_style[ic]; int style = side_style[ic];
int x1 = corner[ic].x; int x1 = corner[ic].x;
int y1 = corner[ic].y; int y1 = corner[ic].y;
int x2, y2; int x2, y2;
if( ic < ic_end ) if( ic < ic_end )
{ {
x2 = corner[ic+1].x; x2 = corner[ic+1].x;
y2 = corner[ic+1].y; y2 = corner[ic+1].y;
} }
else else
{ {
x2 = corner[ic_st].x; x2 = corner[ic_st].x;
y2 = corner[ic_st].y; y2 = corner[ic_st].y;
} }
if( style == STRAIGHT ) if( style == STRAIGHT )
{ {
g_v_list->vertex[ivtx].x = x1; g_v_list->vertex[ivtx].x = x1;
g_v_list->vertex[ivtx].y = y1; g_v_list->vertex[ivtx].y = y1;
ivtx++; ivtx++;
} }
else else
{ {
// style is arc_cw or arc_ccw // style is arc_cw or arc_ccw
int n; // number of steps for arcs int n; // number of steps for arcs
n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP); n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP);
n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc
double xo, yo, theta1, theta2, a, b; double xo, yo, theta1, theta2, a, b;
a = fabs( (double)(x1 - x2) ); a = fabs( (double)(x1 - x2) );
b = fabs( (double)(y1 - y2) ); b = fabs( (double)(y1 - y2) );
if( style == CPolyLine::ARC_CW ) if( style == CPolyLine::ARC_CW )
{ {
// clockwise arc (ie.quadrant of ellipse) // clockwise arc (ie.quadrant of ellipse)
if( x2 > x1 && y2 > y1 ) if( x2 > x1 && y2 > y1 )
{ {
// first quadrant, draw second quadrant of ellipse // first quadrant, draw second quadrant of ellipse
xo = x2; xo = x2;
yo = y1; yo = y1;
theta1 = pi; theta1 = pi;
theta2 = pi/2.0; theta2 = pi/2.0;
} }
else if( x2 < x1 && y2 > y1 ) else if( x2 < x1 && y2 > y1 )
{ {
// second quadrant, draw third quadrant of ellipse // second quadrant, draw third quadrant of ellipse
xo = x1; xo = x1;
yo = y2; yo = y2;
theta1 = 3.0*pi/2.0; theta1 = 3.0*pi/2.0;
theta2 = pi; theta2 = pi;
} }
else if( x2 < x1 && y2 < y1 ) else if( x2 < x1 && y2 < y1 )
{ {
// third quadrant, draw fourth quadrant of ellipse // third quadrant, draw fourth quadrant of ellipse
xo = x2; xo = x2;
yo = y1; yo = y1;
theta1 = 2.0*pi; theta1 = 2.0*pi;
theta2 = 3.0*pi/2.0; theta2 = 3.0*pi/2.0;
} }
else else
{ {
xo = x1; // fourth quadrant, draw first quadrant of ellipse xo = x1; // fourth quadrant, draw first quadrant of ellipse
yo = y2; yo = y2;
theta1 = pi/2.0; theta1 = pi/2.0;
theta2 = 0.0; theta2 = 0.0;
} }
} }
else else
{ {
// counter-clockwise arc // counter-clockwise arc
if( x2 > x1 && y2 > y1 ) if( x2 > x1 && y2 > y1 )
{ {
xo = x1; // first quadrant, draw fourth quadrant of ellipse xo = x1; // first quadrant, draw fourth quadrant of ellipse
yo = y2; yo = y2;
theta1 = 3.0*pi/2.0; theta1 = 3.0*pi/2.0;
theta2 = 2.0*pi; theta2 = 2.0*pi;
} }
else if( x2 < x1 && y2 > y1 ) else if( x2 < x1 && y2 > y1 )
{ {
xo = x2; // second quadrant xo = x2; // second quadrant
yo = y1; yo = y1;
theta1 = 0.0; theta1 = 0.0;
theta2 = pi/2.0; theta2 = pi/2.0;
} }
else if( x2 < x1 && y2 < y1 ) else if( x2 < x1 && y2 < y1 )
{ {
xo = x1; // third quadrant xo = x1; // third quadrant
yo = y2; yo = y2;
theta1 = pi/2.0; theta1 = pi/2.0;
theta2 = pi; theta2 = pi;
} }
else else
{ {
xo = x2; // fourth quadrant xo = x2; // fourth quadrant
yo = y1; yo = y1;
theta1 = pi; theta1 = pi;
theta2 = 3.0*pi/2.0; theta2 = 3.0*pi/2.0;
} }
} }
// now write steps for arc // now write steps for arc
if( arc_array ) if( arc_array )
{ {
arc_array->SetSize(iarc+1); arc_array->SetSize(iarc+1);
(*arc_array)[iarc].style = style; (*arc_array)[iarc].style = style;
(*arc_array)[iarc].n_steps = n; (*arc_array)[iarc].n_steps = n;
(*arc_array)[iarc].xi = x1; (*arc_array)[iarc].xi = x1;
(*arc_array)[iarc].yi = y1; (*arc_array)[iarc].yi = y1;
(*arc_array)[iarc].xf = x2; (*arc_array)[iarc].xf = x2;
(*arc_array)[iarc].yf = y2; (*arc_array)[iarc].yf = y2;
iarc++; iarc++;
} }
for( int is=0; is<n; is++ ) for( int is=0; is<n; is++ )
{ {
double theta = theta1 + ((theta2-theta1)*(double)is)/n; double theta = theta1 + ((theta2-theta1)*(double)is)/n;
double x = xo + a*cos(theta); double x = xo + a*cos(theta);
double y = yo + b*sin(theta); double y = yo + b*sin(theta);
if( is == 0 ) if( is == 0 )
{ {
x = x1; x = x1;
y = y1; y = y1;
} }
g_v_list->vertex[ivtx].x = x; g_v_list->vertex[ivtx].x = x;
g_v_list->vertex[ivtx].y = y; g_v_list->vertex[ivtx].y = y;
ivtx++; ivtx++;
} }
} }
} }
if( n_vertices != ivtx ) if( n_vertices != ivtx )
ASSERT(0); ASSERT(0);
// add vertex_list to gpc // add vertex_list to gpc
gpc_add_contour( gpc, g_v_list, 0 ); gpc_add_contour( gpc, g_v_list, 0 );
// now clip m_gpc_poly with gpc, put new poly into result // now clip m_gpc_poly with gpc, put new poly into result
gpc_polygon * result = new gpc_polygon; gpc_polygon * result = new gpc_polygon;
if( icontour == -1 && icont != 0 ) if( icontour == -1 && icont != 0 )
gpc_polygon_clip( GPC_DIFF, m_gpc_poly, gpc, result ); // hole gpc_polygon_clip( GPC_DIFF, m_gpc_poly, gpc, result ); // hole
else else
gpc_polygon_clip( GPC_UNION, m_gpc_poly, gpc, result ); // outside gpc_polygon_clip( GPC_UNION, m_gpc_poly, gpc, result ); // outside
// now copy result to m_gpc_poly // now copy result to m_gpc_poly
gpc_free_polygon( m_gpc_poly ); gpc_free_polygon( m_gpc_poly );
delete m_gpc_poly; delete m_gpc_poly;
m_gpc_poly = result; m_gpc_poly = result;
gpc_free_polygon( gpc ); gpc_free_polygon( gpc );
delete gpc; delete gpc;
free( g_v_list->vertex ); free( g_v_list->vertex );
free( g_v_list ); free( g_v_list );
} }
return 0; return 0;
} }
int CPolyLine::FreeGpcPoly() int CPolyLine::FreeGpcPoly()
{ {
if( m_gpc_poly->num_contours ) if( m_gpc_poly->num_contours )
{ {
delete m_gpc_poly->contour->vertex; delete m_gpc_poly->contour->vertex;
delete m_gpc_poly->contour; delete m_gpc_poly->contour;
delete m_gpc_poly->hole; delete m_gpc_poly->hole;
} }
m_gpc_poly->num_contours = 0; m_gpc_poly->num_contours = 0;
return 0; return 0;
} }
// Restore arcs to a polygon where they were replaced with steps // Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array // If pa != NULL, also use polygons in pa array
// //
int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa ) int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa )
{ {
// get poly info // get poly info
int n_polys = 1; int n_polys = 1;
if( pa ) if( pa )
n_polys += pa->size(); n_polys += pa->size();
CPolyLine * poly; CPolyLine * poly;
// undraw polys and clear utility flag for all corners // undraw polys and clear utility flag for all corners
for( int ip=0; ip<n_polys; ip++ ) for( int ip=0; ip<n_polys; ip++ )
{ {
if( ip == 0 ) if( ip == 0 )
poly = this; poly = this;
else else
poly = (*pa)[ip-1]; poly = (*pa)[ip-1];
poly->Undraw(); poly->Undraw();
for( int ic=0; ic<poly->GetNumCorners(); ic++ ) for( int ic=0; ic<poly->GetNumCorners(); ic++ )
poly->SetUtility( ic, 0 ); // clear utility flag poly->SetUtility( ic, 0 ); // clear utility flag
} }
// find arcs and replace them // find arcs and replace them
BOOL bFound; BOOL bFound;
int arc_start; int arc_start;
int arc_end; int arc_end;
for( unsigned iarc=0; iarc<arc_array->size(); iarc++ ) for( unsigned iarc=0; iarc<arc_array->size(); iarc++ )
{ {
int arc_xi = (*arc_array)[iarc].xi; int arc_xi = (*arc_array)[iarc].xi;
int arc_yi = (*arc_array)[iarc].yi; int arc_yi = (*arc_array)[iarc].yi;
int arc_xf = (*arc_array)[iarc].xf; int arc_xf = (*arc_array)[iarc].xf;
int arc_yf = (*arc_array)[iarc].yf; int arc_yf = (*arc_array)[iarc].yf;
int n_steps = (*arc_array)[iarc].n_steps; int n_steps = (*arc_array)[iarc].n_steps;
int style = (*arc_array)[iarc].style; int style = (*arc_array)[iarc].style;
bFound = FALSE; bFound = FALSE;
// loop through polys // loop through polys
for( int ip=0; ip<n_polys; ip++ ) for( int ip=0; ip<n_polys; ip++ )
{ {
if( ip == 0 ) if( ip == 0 )
poly = this; poly = this;
else else
poly = (*pa)[ip-1]; poly = (*pa)[ip-1];
for( int icont=0; icont<poly->GetNumContours(); icont++ ) for( int icont=0; icont<poly->GetNumContours(); icont++ )
{ {
int ic_start = poly->GetContourStart(icont); int ic_start = poly->GetContourStart(icont);
int ic_end = poly->GetContourEnd(icont); int ic_end = poly->GetContourEnd(icont);
if( (ic_end-ic_start) > n_steps ) if( (ic_end-ic_start) > n_steps )
{ {
for( int ic=ic_start; ic<=ic_end; ic++ ) for( int ic=ic_start; ic<=ic_end; ic++ )
{ {
int ic_next = ic+1; int ic_next = ic+1;
if( ic_next > ic_end ) if( ic_next > ic_end )
ic_next = ic_start; ic_next = ic_start;
int xi = poly->GetX(ic); int xi = poly->GetX(ic);
int yi = poly->GetY(ic); int yi = poly->GetY(ic);
if( xi == arc_xi && yi == arc_yi ) if( xi == arc_xi && yi == arc_yi )
{ {
// test for forward arc // test for forward arc
int ic2 = ic + n_steps; int ic2 = ic + n_steps;
if( ic2 > ic_end ) if( ic2 > ic_end )
ic2 = ic2 - ic_end + ic_start - 1; ic2 = ic2 - ic_end + ic_start - 1;
int xf = poly->GetX(ic2); int xf = poly->GetX(ic2);
int yf = poly->GetY(ic2); int yf = poly->GetY(ic2);
if( xf == arc_xf && yf == arc_yf ) if( xf == arc_xf && yf == arc_yf )
{ {
// arc from ic to ic2 // arc from ic to ic2
bFound = TRUE; bFound = TRUE;
arc_start = ic; arc_start = ic;
arc_end = ic2; arc_end = ic2;
} }
else else
{ {
// try reverse arc // try reverse arc
ic2 = ic - n_steps; ic2 = ic - n_steps;
if( ic2 < ic_start ) if( ic2 < ic_start )
ic2 = ic2 - ic_start + ic_end + 1; ic2 = ic2 - ic_start + ic_end + 1;
xf = poly->GetX(ic2); xf = poly->GetX(ic2);
yf = poly->GetY(ic2); yf = poly->GetY(ic2);
if( xf == arc_xf && yf == arc_yf ) if( xf == arc_xf && yf == arc_yf )
{ {
// arc from ic2 to ic // arc from ic2 to ic
bFound = TRUE; bFound = TRUE;
arc_start = ic2; arc_start = ic2;
arc_end = ic; arc_end = ic;
style = 3 - style; style = 3 - style;
} }
} }
if( bFound ) if( bFound )
{ {
poly->side_style[arc_start] = style; poly->side_style[arc_start] = style;
// mark corners for deletion from arc_start+1 to arc_end-1 // mark corners for deletion from arc_start+1 to arc_end-1
for( int i=arc_start+1; i!=arc_end; ) for( int i=arc_start+1; i!=arc_end; )
{ {
if( i > ic_end ) if( i > ic_end )
i = ic_start; i = ic_start;
poly->SetUtility( i, 1 ); poly->SetUtility( i, 1 );
if( i == ic_end ) if( i == ic_end )
i = ic_start; i = ic_start;
else else
i++; i++;
} }
break; break;
} }
} }
if( bFound ) if( bFound )
break; break;
} }
} }
if( bFound ) if( bFound )
break; break;
} }
} }
if( bFound ) if( bFound )
(*arc_array)[iarc].bFound = TRUE; (*arc_array)[iarc].bFound = TRUE;
} }
// now delete all marked corners // now delete all marked corners
for( int ip=0; ip<n_polys; ip++ ) for( int ip=0; ip<n_polys; ip++ )
{ {
if( ip == 0 ) if( ip == 0 )
poly = this; poly = this;
else else
poly = (*pa)[ip-1]; poly = (*pa)[ip-1];
for( int ic=poly->GetNumCorners()-1; ic>=0; ic-- ) for( int ic=poly->GetNumCorners()-1; ic>=0; ic-- )
{ {
if( poly->GetUtility(ic) ) if( poly->GetUtility(ic) )
poly->DeleteCorner( ic, FALSE ); poly->DeleteCorner( ic, FALSE );
} }
} }
return 0; return 0;
} }
// initialize new polyline // initialize new polyline
// set layer, width, selection box size, starting point, id and pointer // set layer, width, selection box size, starting point, id and pointer
// //
// if sel_box = 0, don't create selection elements at all // if sel_box = 0, don't create selection elements at all
// //
// if polyline is board outline, enter with: // if polyline is board outline, enter with:
// id.type = ID_BOARD // id.type = ID_BOARD
// id.st = ID_BOARD_OUTLINE // id.st = ID_BOARD_OUTLINE
// id.i = 0 // id.i = 0
// ptr = NULL // ptr = NULL
// //
// if polyline is copper area, enter with: // if polyline is copper area, enter with:
// id.type = ID_NET; // id.type = ID_NET;
// id.st = ID_AREA // id.st = ID_AREA
// id.i = index to area // id.i = index to area
// ptr = pointer to net // ptr = pointer to net
// //
void CPolyLine::Start( int layer, int w, int sel_box, int x, int y, void CPolyLine::Start( int layer, int w, int sel_box, int x, int y,
int hatch ) int hatch )
{ {
m_layer = layer; m_layer = layer;
m_Width = w; m_Width = w;
m_sel_box = sel_box; m_sel_box = sel_box;
m_HatchStyle = hatch; m_HatchStyle = hatch;
CPolyPt poly_pt( x, y ); CPolyPt poly_pt( x, y );
poly_pt.end_contour = FALSE; poly_pt.end_contour = FALSE;
corner.push_back(poly_pt); corner.push_back(poly_pt);
side_style.push_back(0); side_style.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, int style, BOOL bDraw )
{ {
Undraw(); Undraw();
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 and side
corner.push_back(poly_pt); corner.push_back(poly_pt);
side_style.push_back(style); side_style.push_back(style);
if( corner.size() > 0 && !corner[corner.size()-1].end_contour ) if( corner.size() > 0 && !corner[corner.size()-1].end_contour )
side_style[corner.size()-1] = style; side_style[corner.size()-1] = style;
int dl_type; int dl_type;
if( style == CPolyLine::STRAIGHT ) if( style == CPolyLine::STRAIGHT )
dl_type = DL_LINE; dl_type = DL_LINE;
else if( style == CPolyLine::ARC_CW ) else if( style == CPolyLine::ARC_CW )
dl_type = DL_ARC_CW; dl_type = DL_ARC_CW;
else if( style == CPolyLine::ARC_CCW ) else if( style == CPolyLine::ARC_CCW )
dl_type = DL_ARC_CCW; dl_type = DL_ARC_CCW;
else else
ASSERT(0); ASSERT(0);
if( bDraw ) if( bDraw )
Draw(); Draw();
} }
// close last polyline contour // close last polyline contour
// //
void CPolyLine::Close( int style, BOOL bDraw ) void CPolyLine::Close( int style, BOOL bDraw )
{ {
if( GetClosed() ) if( GetClosed() )
ASSERT(0); ASSERT(0);
Undraw(); Undraw();
side_style[corner.size()-1] = style; side_style[corner.size()-1] = style;
corner[corner.size()-1].end_contour = TRUE; corner[corner.size()-1].end_contour = TRUE;
if( bDraw ) if( bDraw )
Draw(); Draw();
} }
// move corner of polyline // move corner of polyline
// //
void CPolyLine::MoveCorner( int ic, int x, int y ) void CPolyLine::MoveCorner( int ic, int x, int y )
{ {
Undraw(); Undraw();
corner[ic].x = x; corner[ic].x = x;
corner[ic].y = y; corner[ic].y = y;
Draw(); Draw();
} }
// delete corner and adjust arrays // delete corner and adjust arrays
// //
void CPolyLine::DeleteCorner( int ic, BOOL bDraw ) void CPolyLine::DeleteCorner( int ic, BOOL bDraw )
{ {
Undraw(); Undraw();
int icont = GetContour( ic ); int icont = GetContour( ic );
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
BOOL bClosed = icont < GetNumContours()-1 || GetClosed(); BOOL bClosed = icont < GetNumContours()-1 || GetClosed();
if( !bClosed ) if( !bClosed )
{ {
// open contour, must be last contour // open contour, must be last contour
corner.erase( corner.begin() + ic ); corner.erase( corner.begin() + ic );
if( ic != istart ) if( ic != istart )
side_style.erase( side_style.begin() + ic-1 ); side_style.erase( side_style.begin() + ic-1 );
} }
else else
{ {
// closed contour // closed contour
corner.erase( corner.begin() + ic ); corner.erase( corner.begin() + ic );
side_style.erase( side_style.begin() + ic ); side_style.erase( side_style.begin() + ic );
if( ic == iend ) if( ic == iend )
corner[ic-1].end_contour = TRUE; corner[ic-1].end_contour = TRUE;
} }
if( bClosed && GetContourSize(icont) < 3 ) if( bClosed && GetContourSize(icont) < 3 )
{ {
// delete the entire contour // delete the entire contour
RemoveContour( icont ); RemoveContour( icont );
} }
if( bDraw ) if( bDraw )
Draw(); Draw();
} }
void CPolyLine::RemoveContour( int icont ) void CPolyLine::RemoveContour( int icont )
{ {
Undraw(); Undraw();
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
if( icont == 0 && GetNumContours() == 1 ) if( icont == 0 && GetNumContours() == 1 )
{ {
// remove the only contour // remove the only contour
ASSERT(0); ASSERT(0);
} }
else if( icont == GetNumContours()-1 ) else if( icont == GetNumContours()-1 )
{ {
// remove last contour // remove last contour
corner.erase( corner.begin() + icont, corner.end() ); corner.erase( corner.begin() + icont, corner.end() );
side_style.erase( side_style.begin() + icont, side_style.end() ); side_style.erase( side_style.begin() + icont, side_style.end() );
} }
else else
{ {
// remove closed contour // remove closed contour
for( int ic=iend; ic>=istart; ic-- ) for( int ic=iend; ic>=istart; ic-- )
{ {
corner.erase( corner.begin() + ic ); corner.erase( corner.begin() + ic );
side_style.erase( side_style.begin() + ic ); side_style.erase( side_style.begin() + ic );
} }
} }
Draw(); Draw();
} }
/** Function InsertCorner /** Function InsertCorner
* insert a new corner between two existing corners * insert a new corner between two existing corners
* @param ic = index for the insertion point: the corner is inserted AFTER ic * @param ic = index for the insertion point: the corner is inserted AFTER ic
* @param x, y = coordinates corner to insert * @param x, y = coordinates corner to insert
*/ */
void CPolyLine::InsertCorner( int ic, int x, int y ) void CPolyLine::InsertCorner( int ic, int x, int y )
{ {
Undraw(); Undraw();
if ( (unsigned)(ic) >= corner.size() ) if ( (unsigned)(ic) >= corner.size() )
{ {
corner.push_back( CPolyPt(x,y) ); corner.push_back( CPolyPt(x,y) );
side_style.push_back( STRAIGHT ); side_style.push_back( STRAIGHT );
} }
else else
{ {
corner.insert( corner.begin() + ic + 1, CPolyPt(x,y) ); corner.insert( corner.begin() + ic + 1, CPolyPt(x,y) );
side_style.insert( side_style.begin() + ic + 1, STRAIGHT ); side_style.insert( side_style.begin() + ic + 1, STRAIGHT );
} }
if( (unsigned)(ic+1) < corner.size() ) if( (unsigned)(ic+1) < corner.size() )
{ {
if( corner[ic].end_contour ) if( corner[ic].end_contour )
{ {
corner[ic+1].end_contour = TRUE; corner[ic+1].end_contour = TRUE;
corner[ic].end_contour = FALSE; corner[ic].end_contour = FALSE;
} }
} }
Draw(); Draw();
} }
// undraw polyline by removing all graphic elements from display list // undraw polyline by removing all graphic elements from display list
// //
void CPolyLine::Undraw() void CPolyLine::Undraw()
{ {
if( m_dlist && bDrawn ) if( m_dlist && bDrawn )
{ {
// remove display elements, if present // remove display elements, if present
for( unsigned i=0; i<dl_side.size(); i++ ) for( unsigned i=0; i<dl_side.size(); i++ )
m_dlist->Remove( dl_side[i] ); m_dlist->Remove( dl_side[i] );
for( unsigned i=0; i<dl_side_sel.size(); i++ ) for( unsigned i=0; i<dl_side_sel.size(); i++ )
m_dlist->Remove( dl_side_sel[i] ); m_dlist->Remove( dl_side_sel[i] );
for( unsigned i=0; i<dl_corner_sel.size(); i++ ) for( unsigned i=0; i<dl_corner_sel.size(); i++ )
m_dlist->Remove( dl_corner_sel[i] ); m_dlist->Remove( dl_corner_sel[i] );
// remove pointers // remove pointers
dl_side.clear(); dl_side.clear();
dl_side_sel.clear(); dl_side_sel.clear();
dl_corner_sel.clear(); dl_corner_sel.clear();
} }
m_HatchLines.clear(); m_HatchLines.clear();
bDrawn = FALSE; bDrawn = FALSE;
} }
// draw polyline by adding all graphics to display list // draw polyline by adding all graphics to display list
// if side style is ARC_CW or ARC_CCW but endpoints are not angled, // if side style is ARC_CW or ARC_CCW but endpoints are not angled,
// convert to STRAIGHT // convert to STRAIGHT
// //
void CPolyLine::Draw( CDisplayList * dl ) void CPolyLine::Draw( CDisplayList * dl )
{ {
// first, undraw if necessary // first, undraw if necessary
if( bDrawn ) if( bDrawn )
Undraw(); Undraw();
// use new display list if provided // use new display list if provided
if( dl ) if( dl )
m_dlist = dl; m_dlist = dl;
#if 0 #if 0
int i_start_contour = 0; int i_start_contour = 0;
if( m_dlist ) if( m_dlist )
{ {
// set up std::vectors // set up std::vectors
dl_side.SetSize( corner.size() ); dl_side.SetSize( corner.size() );
if( m_sel_box ) if( m_sel_box )
{ {
dl_side_sel.SetSize( corner.size() ); dl_side_sel.SetSize( corner.size() );
dl_corner_sel.SetSize( corner.size() ); dl_corner_sel.SetSize( corner.size() );
} }
else else
{ {
dl_side_sel.clear(); dl_side_sel.clear();
dl_corner_sel.clear(); dl_corner_sel.clear();
} }
// now draw elements // now draw elements
for( int ic=0; ic<corner.size(); ic++ ) for( int ic=0; ic<corner.size(); ic++ )
{ {
m_id.ii = ic; m_id.ii = ic;
int xi = corner[ic].x; int xi = corner[ic].x;
int yi = corner[ic].y; int yi = corner[ic].y;
int xf, yf; int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size()-1 ) if( corner[ic].end_contour == FALSE && ic < corner.size()-1 )
{ {
xf = corner[ic+1].x; xf = corner[ic+1].x;
yf = corner[ic+1].y; yf = corner[ic+1].y;
} }
else else
{ {
xf = corner[i_start_contour].x; xf = corner[i_start_contour].x;
yf = corner[i_start_contour].y; yf = corner[i_start_contour].y;
i_start_contour = ic+1; i_start_contour = ic+1;
} }
// draw // draw
if( m_sel_box ) if( m_sel_box )
{ {
m_id.sst = ID_SEL_CORNER; m_id.sst = ID_SEL_CORNER;
dl_corner_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, DL_HOLLOW_RECT, dl_corner_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, DL_HOLLOW_RECT,
1, 0, 0, xi-m_sel_box, yi-m_sel_box, 1, 0, 0, xi-m_sel_box, yi-m_sel_box,
xi+m_sel_box, yi+m_sel_box, 0, 0 ); xi+m_sel_box, yi+m_sel_box, 0, 0 );
} }
if( ic<(corner.size()-1) || corner[ic].end_contour ) if( ic<(corner.size()-1) || corner[ic].end_contour )
{ {
// draw side // draw side
if( xi == xf || yi == yf ) if( xi == xf || yi == yf )
{ {
// if endpoints not angled, make side STRAIGHT // if endpoints not angled, make side STRAIGHT
side_style[ic] = STRAIGHT; side_style[ic] = STRAIGHT;
} }
int g_type = DL_LINE; int g_type = DL_LINE;
if( side_style[ic] == STRAIGHT ) if( side_style[ic] == STRAIGHT )
g_type = DL_LINE; g_type = DL_LINE;
else if( side_style[ic] == ARC_CW ) else if( side_style[ic] == ARC_CW )
g_type = DL_ARC_CW; g_type = DL_ARC_CW;
else if( side_style[ic] == ARC_CCW ) else if( side_style[ic] == ARC_CCW )
g_type = DL_ARC_CCW; g_type = DL_ARC_CCW;
m_id.sst = ID_SIDE; m_id.sst = ID_SIDE;
dl_side[ic] = m_dlist->Add( m_id, m_ptr, m_layer, g_type, dl_side[ic] = m_dlist->Add( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 ); 1, m_w, 0, xi, yi, xf, yf, 0, 0 );
if( m_sel_box ) if( m_sel_box )
{ {
m_id.sst = ID_SEL_SIDE; m_id.sst = ID_SEL_SIDE;
dl_side_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, g_type, dl_side_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 ); 1, m_w, 0, xi, yi, xf, yf, 0, 0 );
} }
} }
} }
// if( m_HatchStyle ) // if( m_HatchStyle )
// Hatch(); // Hatch();
} }
#endif #endif
Hatch(); Hatch();
bDrawn = TRUE; bDrawn = TRUE;
} }
// start dragging new corner to be inserted into side, make side and hatching invisible // start dragging new corner to be inserted into side, make side and hatching invisible
// //
void CPolyLine::StartDraggingToInsertCorner( CDC * pDC, int ic, int x, int y ) void CPolyLine::StartDraggingToInsertCorner( CDC * pDC, int ic, int x, int y )
{ {
if( !m_dlist ) if( !m_dlist )
ASSERT(0); ASSERT(0);
int icont = GetContour( ic ); int icont = GetContour( ic );
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
int post_c; int post_c;
if( ic == iend ) if( ic == iend )
post_c = istart; post_c = istart;
else else
post_c = ic + 1; post_c = ic + 1;
int xi = corner[ic].x; int xi = corner[ic].x;
int yi = corner[ic].y; int yi = corner[ic].y;
int xf = corner[post_c].x; int xf = corner[post_c].x;
int yf = corner[post_c].y; int yf = corner[post_c].y;
m_dlist->StartDraggingLineVertex( pDC, x, y, xi, yi, xf, yf, m_dlist->StartDraggingLineVertex( pDC, x, y, xi, yi, xf, yf,
LAY_SELECTION, LAY_SELECTION, 1, 1, DSS_STRAIGHT, DSS_STRAIGHT, LAY_SELECTION, LAY_SELECTION, 1, 1, DSS_STRAIGHT, DSS_STRAIGHT,
0, 0, 0, 0, 1 ); 0, 0, 0, 0, 1 );
m_dlist->CancelHighLight(); m_dlist->CancelHighLight();
m_dlist->Set_visible( dl_side[ic], 0 ); m_dlist->Set_visible( dl_side[ic], 0 );
/* for( int ih=0; ih<m_nhatch; ih++ ) /* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 ); m_dlist->Set_visible( dl_hatch[ih], 0 );
*/ */
} }
// cancel dragging inserted corner, make side and hatching visible again // cancel dragging inserted corner, make side and hatching visible again
// //
void CPolyLine::CancelDraggingToInsertCorner( int ic ) void CPolyLine::CancelDraggingToInsertCorner( int ic )
{ {
if( !m_dlist ) if( !m_dlist )
ASSERT(0); ASSERT(0);
int post_c; int post_c;
if( ic == (int)(corner.size()-1) ) if( ic == (int)(corner.size()-1) )
post_c = 0; post_c = 0;
else else
post_c = ic + 1; post_c = ic + 1;
m_dlist->StopDragging(); m_dlist->StopDragging();
/* m_dlist->Set_visible( dl_side[ic], 1 ); /* m_dlist->Set_visible( dl_side[ic], 1 );
for( int ih=0; ih<m_nhatch; ih++ ) for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 1 ); m_dlist->Set_visible( dl_hatch[ih], 1 );
*/ */
} }
// start dragging corner to new position, make adjacent sides and hatching invisible // start dragging corner to new position, make adjacent sides and hatching invisible
// //
void CPolyLine::StartDraggingToMoveCorner( CDC * pDC, int ic, int x, int y ) void CPolyLine::StartDraggingToMoveCorner( CDC * pDC, int ic, int x, int y )
{ {
if( !m_dlist ) if( !m_dlist )
ASSERT(0); ASSERT(0);
// see if corner is the first or last corner of an open contour // see if corner is the first or last corner of an open contour
int icont = GetContour( ic ); int icont = GetContour( ic );
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
if( !GetClosed() if( !GetClosed()
&& icont == GetNumContours() - 1 && icont == GetNumContours() - 1
&& (ic == istart || ic == iend) ) && (ic == istart || ic == iend) )
{ {
// yes // yes
int style, xi, yi, iside; int style, xi, yi, iside;
if( ic == istart ) if( ic == istart )
{ {
// first corner // first corner
iside = ic; iside = ic;
xi = GetX( ic+1 ); xi = GetX( ic+1 );
yi = GetY( ic+1 ); yi = GetY( ic+1 );
style = GetSideStyle( iside ); style = GetSideStyle( iside );
// reverse arc since we are drawing from corner 1 to 0 // reverse arc since we are drawing from corner 1 to 0
if( style == CPolyLine::ARC_CW ) if( style == CPolyLine::ARC_CW )
style = CPolyLine::ARC_CCW; style = CPolyLine::ARC_CCW;
else if( style == CPolyLine::ARC_CCW ) else if( style == CPolyLine::ARC_CCW )
style = CPolyLine::ARC_CW; style = CPolyLine::ARC_CW;
} }
else else
{ {
// last corner // last corner
iside = ic - 1; iside = ic - 1;
xi = GetX( ic-1 ); xi = GetX( ic-1 );
yi = GetY( ic-1); yi = GetY( ic-1);
style = GetSideStyle( iside ); style = GetSideStyle( iside );
} }
m_dlist->StartDraggingArc( pDC, style, GetX(ic), GetY(ic), xi, yi, LAY_SELECTION, 1, 1 ); m_dlist->StartDraggingArc( pDC, style, GetX(ic), GetY(ic), xi, yi, LAY_SELECTION, 1, 1 );
m_dlist->CancelHighLight(); m_dlist->CancelHighLight();
m_dlist->Set_visible( dl_side[iside], 0 ); m_dlist->Set_visible( dl_side[iside], 0 );
/* for( int ih=0; ih<m_nhatch; ih++ ) /* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 ); m_dlist->Set_visible( dl_hatch[ih], 0 );
*/ */
} }
else else
{ {
// no // no
// get indexes for preceding and following corners // get indexes for preceding and following corners
int pre_c, post_c; int pre_c, post_c;
int poly_side_style1, poly_side_style2; int poly_side_style1, poly_side_style2;
int style1, style2; int style1, style2;
if( ic == istart ) if( ic == istart )
{ {
pre_c = iend; pre_c = iend;
post_c = istart+1; post_c = istart+1;
poly_side_style1 = side_style[iend]; poly_side_style1 = side_style[iend];
poly_side_style2 = side_style[istart]; poly_side_style2 = side_style[istart];
} }
else if( ic == iend ) else if( ic == iend )
{ {
// last side // last side
pre_c = ic-1; pre_c = ic-1;
post_c = istart; post_c = istart;
poly_side_style1 = side_style[ic-1]; poly_side_style1 = side_style[ic-1];
poly_side_style2 = side_style[ic]; poly_side_style2 = side_style[ic];
} }
else else
{ {
pre_c = ic-1; pre_c = ic-1;
post_c = ic+1; post_c = ic+1;
poly_side_style1 = side_style[ic-1]; poly_side_style1 = side_style[ic-1];
poly_side_style2 = side_style[ic]; poly_side_style2 = side_style[ic];
} }
if( poly_side_style1 == STRAIGHT ) if( poly_side_style1 == STRAIGHT )
style1 = DSS_STRAIGHT; style1 = DSS_STRAIGHT;
else if( poly_side_style1 == ARC_CW ) else if( poly_side_style1 == ARC_CW )
style1 = DSS_ARC_CW; style1 = DSS_ARC_CW;
else if( poly_side_style1 == ARC_CCW ) else if( poly_side_style1 == ARC_CCW )
style1 = DSS_ARC_CCW; style1 = DSS_ARC_CCW;
if( poly_side_style2 == STRAIGHT ) if( poly_side_style2 == STRAIGHT )
style2 = DSS_STRAIGHT; style2 = DSS_STRAIGHT;
else if( poly_side_style2 == ARC_CW ) else if( poly_side_style2 == ARC_CW )
style2 = DSS_ARC_CW; style2 = DSS_ARC_CW;
else if( poly_side_style2 == ARC_CCW ) else if( poly_side_style2 == ARC_CCW )
style2 = DSS_ARC_CCW; style2 = DSS_ARC_CCW;
int xi = corner[pre_c].x; int xi = corner[pre_c].x;
int yi = corner[pre_c].y; int yi = corner[pre_c].y;
int xf = corner[post_c].x; int xf = corner[post_c].x;
int yf = corner[post_c].y; int yf = corner[post_c].y;
m_dlist->StartDraggingLineVertex( pDC, x, y, xi, yi, xf, yf, m_dlist->StartDraggingLineVertex( pDC, x, y, xi, yi, xf, yf,
LAY_SELECTION, LAY_SELECTION, 1, 1, style1, style2, LAY_SELECTION, LAY_SELECTION, 1, 1, style1, style2,
0, 0, 0, 0, 1 ); 0, 0, 0, 0, 1 );
m_dlist->CancelHighLight(); m_dlist->CancelHighLight();
m_dlist->Set_visible( dl_side[pre_c], 0 ); m_dlist->Set_visible( dl_side[pre_c], 0 );
m_dlist->Set_visible( dl_side[ic], 0 ); m_dlist->Set_visible( dl_side[ic], 0 );
/* for( int ih=0; ih<m_nhatch; ih++ ) /* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 ); m_dlist->Set_visible( dl_hatch[ih], 0 );
*/ } */ }
} }
// cancel dragging corner to new position, make sides and hatching visible again // cancel dragging corner to new position, make sides and hatching visible again
// //
// highlight side by drawing line over it // highlight side by drawing line over it
// //
void CPolyLine::HighlightSide( int is ) void CPolyLine::HighlightSide( int is )
{ {
if( !m_dlist ) if( !m_dlist )
ASSERT(0); ASSERT(0);
if( GetClosed() && is >= (int)corner.size() ) if( GetClosed() && is >= (int)corner.size() )
return; return;
if( !GetClosed() && is >= (int)(corner.size()-1) ) if( !GetClosed() && is >= (int)(corner.size()-1) )
return; return;
int style; int style;
if( side_style[is] == CPolyLine::STRAIGHT ) if( side_style[is] == CPolyLine::STRAIGHT )
style = DL_LINE; style = DL_LINE;
else if( side_style[is] == CPolyLine::ARC_CW ) else if( side_style[is] == CPolyLine::ARC_CW )
style = DL_ARC_CW; style = DL_ARC_CW;
else if( side_style[is] == CPolyLine::ARC_CCW ) else if( side_style[is] == CPolyLine::ARC_CCW )
style = DL_ARC_CCW; style = DL_ARC_CCW;
m_dlist->HighLight( style, m_dlist->HighLight( style,
m_dlist->Get_x( dl_side_sel[is] ), m_dlist->Get_x( dl_side_sel[is] ),
m_dlist->Get_y( dl_side_sel[is] ), m_dlist->Get_y( dl_side_sel[is] ),
m_dlist->Get_xf( dl_side_sel[is] ), m_dlist->Get_xf( dl_side_sel[is] ),
m_dlist->Get_yf( dl_side_sel[is] ), m_dlist->Get_yf( dl_side_sel[is] ),
m_dlist->Get_w( dl_side_sel[is]) ); m_dlist->Get_w( dl_side_sel[is]) );
} }
int CPolyLine::GetX( int ic ) int CPolyLine::GetX( int ic )
{ {
return corner[ic].x; return corner[ic].x;
} }
int CPolyLine::GetY( int ic ) int CPolyLine::GetY( int ic )
{ {
return corner[ic].y; return corner[ic].y;
} }
int CPolyLine::GetEndContour( int ic ) int CPolyLine::GetEndContour( int ic )
{ {
return corner[ic].end_contour; return corner[ic].end_contour;
} }
CRect CPolyLine::GetBounds() CRect CPolyLine::GetBounds()
{ {
CRect r = GetCornerBounds(); CRect r = GetCornerBounds();
r.left -= m_Width/2; r.left -= m_Width/2;
r.right += m_Width/2; r.right += m_Width/2;
r.bottom -= m_Width/2; r.bottom -= m_Width/2;
r.top += m_Width/2; r.top += m_Width/2;
return r; return r;
} }
CRect CPolyLine::GetCornerBounds() CRect CPolyLine::GetCornerBounds()
{ {
CRect r; CRect r;
r.left = r.bottom = INT_MAX; r.left = r.bottom = INT_MAX;
r.right = r.top = INT_MIN; r.right = r.top = INT_MIN;
for( unsigned i=0; i<corner.size(); i++ ) for( unsigned i=0; i<corner.size(); i++ )
{ {
r.left = min( r.left, corner[i].x ); r.left = min( r.left, corner[i].x );
r.right = max( r.right, corner[i].x ); r.right = max( r.right, corner[i].x );
r.bottom = min( r.bottom, corner[i].y ); r.bottom = min( r.bottom, corner[i].y );
r.top = max( r.top, corner[i].y ); r.top = max( r.top, corner[i].y );
} }
return r; return r;
} }
CRect CPolyLine::GetCornerBounds( int icont ) CRect CPolyLine::GetCornerBounds( int icont )
{ {
CRect r; CRect r;
r.left = r.bottom = INT_MAX; r.left = r.bottom = INT_MAX;
r.right = r.top = INT_MIN; r.right = r.top = INT_MIN;
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
for( int i=istart; i<=iend; i++ ) for( int i=istart; i<=iend; i++ )
{ {
r.left = min( r.left, corner[i].x ); r.left = min( r.left, corner[i].x );
r.right = max( r.right, corner[i].x ); r.right = max( r.right, corner[i].x );
r.bottom = min( r.bottom, corner[i].y ); r.bottom = min( r.bottom, corner[i].y );
r.top = max( r.top, corner[i].y ); r.top = max( r.top, corner[i].y );
} }
return r; return r;
} }
int CPolyLine::GetNumCorners() int CPolyLine::GetNumCorners()
{ {
return corner.size(); return corner.size();
} }
int CPolyLine::GetNumSides() int CPolyLine::GetNumSides()
{ {
if( GetClosed() ) if( GetClosed() )
return corner.size(); return corner.size();
else else
return corner.size()-1; return corner.size()-1;
} }
int CPolyLine::GetW() int CPolyLine::GetW()
{ {
return m_Width; return m_Width;
} }
int CPolyLine::GetSelBoxSize() int CPolyLine::GetSelBoxSize()
{ {
return m_sel_box; return m_sel_box;
} }
int CPolyLine::GetNumContours() int CPolyLine::GetNumContours()
{ {
int ncont = 0; int ncont = 0;
if( !corner.size() ) if( !corner.size() )
return 0; return 0;
for( unsigned ic=0; ic<corner.size(); ic++ ) for( unsigned ic=0; ic<corner.size(); ic++ )
if( corner[ic].end_contour ) if( corner[ic].end_contour )
ncont++; ncont++;
if( !corner[corner.size()-1].end_contour ) if( !corner[corner.size()-1].end_contour )
ncont++; ncont++;
return ncont; return ncont;
} }
int CPolyLine::GetContour( int ic ) int CPolyLine::GetContour( int ic )
{ {
int ncont = 0; int ncont = 0;
for( int i=0; i<ic; i++ ) for( int i=0; i<ic; i++ )
{ {
if( corner[i].end_contour ) if( corner[i].end_contour )
ncont++; ncont++;
} }
return ncont; return ncont;
} }
int CPolyLine::GetContourStart( int icont ) int CPolyLine::GetContourStart( int icont )
{ {
if( icont == 0 ) if( icont == 0 )
return 0; return 0;
int ncont = 0; int ncont = 0;
for( unsigned i=0; i<corner.size(); i++ ) for( unsigned i=0; i<corner.size(); i++ )
{ {
if( corner[i].end_contour ) if( corner[i].end_contour )
{ {
ncont++; ncont++;
if( ncont == icont ) if( ncont == icont )
return i+1; return i+1;
} }
} }
ASSERT(0); ASSERT(0);
return 0; return 0;
} }
int CPolyLine::GetContourEnd( int icont ) int CPolyLine::GetContourEnd( int icont )
{ {
if( icont < 0 ) if( icont < 0 )
return 0; return 0;
if( icont == GetNumContours()-1 ) if( icont == GetNumContours()-1 )
return corner.size()-1; return corner.size()-1;
int ncont = 0; int ncont = 0;
for( unsigned i=0; i<corner.size(); i++ ) for( unsigned i=0; i<corner.size(); i++ )
{ {
if( corner[i].end_contour ) if( corner[i].end_contour )
{ {
if( ncont == icont ) if( ncont == icont )
return i; return i;
ncont++; ncont++;
} }
} }
ASSERT(0); ASSERT(0);
return 0; return 0;
} }
int CPolyLine::GetContourSize( int icont ) int CPolyLine::GetContourSize( int icont )
{ {
return GetContourEnd(icont) - GetContourStart(icont) + 1; return GetContourEnd(icont) - GetContourStart(icont) + 1;
} }
void CPolyLine::SetSideStyle( int is, int style ) void CPolyLine::SetSideStyle( int is, int style )
{ {
Undraw(); Undraw();
CPoint p1, p2; CPoint p1, p2;
if( is == (int)(corner.size()-1) ) if( is == (int)(corner.size()-1) )
{ {
p1.x = corner[corner.size()-1].x; p1.x = corner[corner.size()-1].x;
p1.y = corner[corner.size()-1].y; p1.y = corner[corner.size()-1].y;
p2.x = corner[0].x; p2.x = corner[0].x;
p2.y = corner[0].y; p2.y = corner[0].y;
} }
else else
{ {
p1.x = corner[is].x; p1.x = corner[is].x;
p1.y = corner[is].y; p1.y = corner[is].y;
p2.x = corner[is+1].x; p2.x = corner[is+1].x;
p2.y = corner[is+1].y; p2.y = corner[is+1].y;
} }
if( p1.x == p2.x || p1.y == p2.y ) if( p1.x == p2.x || p1.y == p2.y )
side_style[is] = STRAIGHT; side_style[is] = STRAIGHT;
else else
side_style[is] = style; side_style[is] = style;
Draw(); Draw();
} }
int CPolyLine::GetSideStyle( int is ) int CPolyLine::GetSideStyle( int is )
{ {
return side_style[is]; return side_style[is];
} }
int CPolyLine::GetClosed() int CPolyLine::GetClosed()
{ {
if( corner.size() == 0 ) if( corner.size() == 0 )
return 0; return 0;
else else
return corner[corner.size()-1].end_contour; return corner[corner.size()-1].end_contour;
} }
// draw hatch lines // draw hatch lines
// //
void CPolyLine::Hatch() void CPolyLine::Hatch()
{ {
m_HatchLines.clear(); m_HatchLines.clear();
if( m_HatchStyle == NO_HATCH ) if( m_HatchStyle == NO_HATCH )
{ {
return; return;
} }
int layer = m_layer; int layer = m_layer;
// if( /*m_dlist && */GetClosed() ) // if( /*m_dlist && */GetClosed() )
{ {
enum { enum {
MAXPTS = 100, MAXPTS = 100,
MAXLINES = 1000 MAXLINES = 1000
}; };
int xx[MAXPTS], yy[MAXPTS]; int xx[MAXPTS], yy[MAXPTS];
// define range for hatch lines // define range for hatch lines
int min_x = corner[0].x; int min_x = corner[0].x;
int max_x = corner[0].x; int max_x = corner[0].x;
int min_y = corner[0].y; int min_y = corner[0].y;
int max_y = corner[0].y; int max_y = corner[0].y;
for( unsigned ic = 1; ic < corner.size(); ic++ ) for( unsigned ic = 1; ic < corner.size(); ic++ )
{ {
if( corner[ic].x < min_x ) if( corner[ic].x < min_x )
min_x = corner[ic].x; min_x = corner[ic].x;
if( corner[ic].x > max_x ) if( corner[ic].x > max_x )
max_x = corner[ic].x; max_x = corner[ic].x;
if( corner[ic].y < min_y ) if( corner[ic].y < min_y )
min_y = corner[ic].y; min_y = corner[ic].y;
if( corner[ic].y > max_y ) if( corner[ic].y > max_y )
max_y = corner[ic].y; max_y = corner[ic].y;
} }
int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1 int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1
double slope = 0.707106*slope_flag; double slope = 0.707106*slope_flag;
int spacing; int spacing;
if( m_HatchStyle == DIAGONAL_EDGE ) if( m_HatchStyle == DIAGONAL_EDGE )
spacing = 10*PCBU_PER_MIL; spacing = 10*PCBU_PER_MIL;
else else
spacing = 50*PCBU_PER_MIL; spacing = 50*PCBU_PER_MIL;
int max_a, min_a; int max_a, min_a;
if( slope_flag == 1 ) if( slope_flag == 1 )
{ {
max_a = (int)(max_y - slope*min_x); max_a = (int)(max_y - slope*min_x);
min_a = (int)(min_y - slope*max_x); min_a = (int)(min_y - slope*max_x);
} }
else else
{ {
max_a = (int)(max_y - slope*max_x); max_a = (int)(max_y - slope*max_x);
min_a = (int)(min_y - slope*min_x); min_a = (int)(min_y - slope*min_x);
} }
min_a = (min_a/spacing)*spacing; min_a = (min_a/spacing)*spacing;
int offset; int offset;
if( layer < (LAY_TOP_COPPER+2) ) if( layer < (LAY_TOP_COPPER+2) )
offset = 0; offset = 0;
else if( layer < (LAY_TOP_COPPER+4) ) else if( layer < (LAY_TOP_COPPER+4) )
offset = spacing/2; offset = spacing/2;
else if( layer < (LAY_TOP_COPPER+6) ) else if( layer < (LAY_TOP_COPPER+6) )
offset = spacing/4; offset = spacing/4;
else if( layer < (LAY_TOP_COPPER+8) ) else if( layer < (LAY_TOP_COPPER+8) )
offset = 3*spacing/4; offset = 3*spacing/4;
else if( layer < (LAY_TOP_COPPER+10) ) else if( layer < (LAY_TOP_COPPER+10) )
offset = 1*spacing/8; offset = 1*spacing/8;
else if( layer < (LAY_TOP_COPPER+12) ) else if( layer < (LAY_TOP_COPPER+12) )
offset = 3*spacing/8; offset = 3*spacing/8;
else if( layer < (LAY_TOP_COPPER+14) ) else if( layer < (LAY_TOP_COPPER+14) )
offset = 5*spacing/8; offset = 5*spacing/8;
else if( layer < (LAY_TOP_COPPER+16) ) else if( layer < (LAY_TOP_COPPER+16) )
offset = 7*spacing/8; offset = 7*spacing/8;
else else
ASSERT(0); ASSERT(0);
min_a += offset; min_a += offset;
// now calculate and draw hatch lines // now calculate and draw hatch lines
int nc = corner.size(); int nc = corner.size();
// loop through hatch lines // loop through hatch lines
for( int a=min_a; a<max_a; a+=spacing ) for( int a=min_a; a<max_a; a+=spacing )
{ {
// get intersection points for this hatch line // get intersection points for this hatch line
int nloops = 0; int nloops = 0;
int npts; int npts;
// make this a loop in case my homebrew hatching algorithm screws up // make this a loop in case my homebrew hatching algorithm screws up
do do
{ {
npts = 0; npts = 0;
int i_start_contour = 0; int i_start_contour = 0;
for( int ic=0; ic<nc; ic++ ) for( int ic=0; ic<nc; ic++ )
{ {
double x, y, x2, y2; double x, y, x2, y2;
int ok; int ok;
if( corner[ic].end_contour ) if( corner[ic].end_contour )
{ {
ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope,
corner[ic].x, corner[ic].y, corner[ic].x, corner[ic].y,
corner[i_start_contour].x, corner[i_start_contour].y, corner[i_start_contour].x, corner[i_start_contour].y,
side_style[ic], side_style[ic],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
i_start_contour = ic + 1; i_start_contour = ic + 1;
} }
else else
{ {
ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope,
corner[ic].x, corner[ic].y, corner[ic].x, corner[ic].y,
corner[ic+1].x, corner[ic+1].y, corner[ic+1].x, corner[ic+1].y,
side_style[ic], side_style[ic],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
} }
if( ok ) if( ok )
{ {
xx[npts] = (int)x; xx[npts] = (int)x;
yy[npts] = (int)y; yy[npts] = (int)y;
npts++; npts++;
ASSERT( npts<MAXPTS ); // overflow ASSERT( npts<MAXPTS ); // overflow
} }
if( ok == 2 ) if( ok == 2 )
{ {
xx[npts] = (int)x2; xx[npts] = (int)x2;
yy[npts] = (int)y2; yy[npts] = (int)y2;
npts++; npts++;
ASSERT( npts<MAXPTS ); // overflow ASSERT( npts<MAXPTS ); // overflow
} }
} }
nloops++; nloops++;
a += PCBU_PER_MIL/100; a += PCBU_PER_MIL/100;
} while( npts%2 != 0 && nloops < 3 ); } while( npts%2 != 0 && nloops < 3 );
ASSERT( npts%2==0 ); // odd number of intersection points, error ASSERT( npts%2==0 ); // odd number of intersection points, error
// sort points in order of descending x (if more than 2) // sort points in order of descending x (if more than 2)
if( npts>2 ) if( npts>2 )
{ {
for( int istart=0; istart<(npts-1); istart++ ) for( int istart=0; istart<(npts-1); istart++ )
{ {
int max_x = INT_MIN; int max_x = INT_MIN;
int imax; int imax;
for( int i=istart; i<npts; i++ ) for( int i=istart; i<npts; i++ )
{ {
if( xx[i] > max_x ) if( xx[i] > max_x )
{ {
max_x = xx[i]; max_x = xx[i];
imax = i; imax = i;
} }
} }
int temp = xx[istart]; int temp = xx[istart];
xx[istart] = xx[imax]; xx[istart] = xx[imax];
xx[imax] = temp; xx[imax] = temp;
temp = yy[istart]; temp = yy[istart];
yy[istart] = yy[imax]; yy[istart] = yy[imax];
yy[imax] = temp; yy[imax] = temp;
} }
} }
// draw lines // draw lines
for( int ip=0; ip<npts; ip+=2 ) for( int ip=0; ip<npts; ip+=2 )
{ {
double dx = xx[ip+1] - xx[ip]; double dx = xx[ip+1] - xx[ip];
if( m_HatchStyle == DIAGONAL_FULL || fabs(dx) < 40*NM_PER_MIL ) if( m_HatchStyle == DIAGONAL_FULL || fabs(dx) < 40*NM_PER_MIL )
{ {
m_HatchLines.push_back(CSegment(xx[ip], yy[ip], xx[ip+1], yy[ip+1]) ); m_HatchLines.push_back(CSegment(xx[ip], yy[ip], xx[ip+1], yy[ip+1]) );
} }
else else
{ {
double dy = yy[ip+1] - yy[ip]; double dy = yy[ip+1] - yy[ip];
double slope = dy/dx; double slope = dy/dx;
if( dx > 0 ) if( dx > 0 )
dx = 20*NM_PER_MIL; dx = 20*NM_PER_MIL;
else else
dx = -20*NM_PER_MIL; dx = -20*NM_PER_MIL;
double x1 = xx[ip] + dx; double x1 = xx[ip] + dx;
double x2 = xx[ip+1] - dx; double x2 = xx[ip+1] - dx;
double y1 = yy[ip] + dx*slope; double y1 = yy[ip] + dx*slope;
double y2 = yy[ip+1] - dx*slope; double y2 = yy[ip+1] - dx*slope;
m_HatchLines.push_back(CSegment(xx[ip], yy[ip], to_int(x1), to_int(y1)) ); m_HatchLines.push_back(CSegment(xx[ip], yy[ip], to_int(x1), to_int(y1)) );
m_HatchLines.push_back(CSegment(xx[ip+1], yy[ip+1], to_int(x2), to_int(y2)) ); m_HatchLines.push_back(CSegment(xx[ip+1], yy[ip+1], to_int(x2), to_int(y2)) );
} }
} }
} // end for } // end for
} }
} }
// test to see if a point is inside polyline // test to see if a point is inside polyline
// //
BOOL CPolyLine::TestPointInside( int x, int y ) BOOL CPolyLine::TestPointInside( int x, int y )
{ {
enum { MAXPTS = 100 }; enum { MAXPTS = 100 };
if( !GetClosed() ) if( !GetClosed() )
ASSERT(0); ASSERT(0);
// define line passing through (x,y), with slope = 2/3; // define line passing through (x,y), with slope = 2/3;
// get intersection points // get intersection points
double xx[MAXPTS], yy[MAXPTS]; double xx[MAXPTS], yy[MAXPTS];
double slope = (double)2.0/3.0; double slope = (double)2.0/3.0;
double a = y - slope*x; double a = y - slope*x;
int nloops = 0; int nloops = 0;
int npts; int npts;
// make this a loop so if my homebrew algorithm screws up, we try it again // make this a loop so if my homebrew algorithm screws up, we try it again
do do
{ {
// now find all intersection points of line with polyline sides // now find all intersection points of line with polyline sides
npts = 0; npts = 0;
for( int icont=0; icont<GetNumContours(); icont++ ) for( int icont=0; icont<GetNumContours(); icont++ )
{ {
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
for( int ic=istart; ic<=iend; ic++ ) for( int ic=istart; ic<=iend; ic++ )
{ {
double x, y, x2, y2; double x, y, x2, y2;
int ok; int ok;
if( ic == istart ) if( ic == istart )
ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope,
corner[iend].x, corner[iend].y, corner[iend].x, corner[iend].y,
corner[istart].x, corner[istart].y, corner[istart].x, corner[istart].y,
side_style[corner.size()-1], side_style[corner.size()-1],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
else else
ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope,
corner[ic-1].x, corner[ic-1].y, corner[ic-1].x, corner[ic-1].y,
corner[ic].x, corner[ic].y, corner[ic].x, corner[ic].y,
side_style[ic-1], side_style[ic-1],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
if( ok ) if( ok )
{ {
xx[npts] = (int)x; xx[npts] = (int)x;
yy[npts] = (int)y; yy[npts] = (int)y;
npts++; npts++;
ASSERT( npts<MAXPTS ); // overflow ASSERT( npts<MAXPTS ); // overflow
} }
if( ok == 2 ) if( ok == 2 )
{ {
xx[npts] = (int)x2; xx[npts] = (int)x2;
yy[npts] = (int)y2; yy[npts] = (int)y2;
npts++; npts++;
ASSERT( npts<MAXPTS ); // overflow ASSERT( npts<MAXPTS ); // overflow
} }
} }
} }
nloops++; nloops++;
a += PCBU_PER_MIL/100; a += PCBU_PER_MIL/100;
} while( npts%2 != 0 && nloops < 3 ); } while( npts%2 != 0 && nloops < 3 );
ASSERT( npts%2==0 ); // odd number of intersection points, error ASSERT( npts%2==0 ); // odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline // count intersection points to right of (x,y), if odd (x,y) is inside polyline
int ncount = 0; int ncount = 0;
for( int ip=0; ip<npts; ip++ ) for( int ip=0; ip<npts; ip++ )
{ {
if( xx[ip] == x && yy[ip] == y ) if( xx[ip] == x && yy[ip] == y )
return FALSE; // (x,y) is on a side, call it outside return FALSE; // (x,y) is on a side, call it outside
else if( xx[ip] > x ) else if( xx[ip] > x )
ncount++; ncount++;
} }
if( ncount%2 ) if( ncount%2 )
return TRUE; return TRUE;
else else
return FALSE; return FALSE;
} }
// test to see if a point is inside polyline contour // test to see if a point is inside polyline contour
// //
BOOL CPolyLine::TestPointInsideContour( int icont, int x, int y ) BOOL CPolyLine::TestPointInsideContour( int icont, int x, int y )
{ {
if( icont >= GetNumContours() ) if( icont >= GetNumContours() )
return FALSE; return FALSE;
enum { MAXPTS = 100 }; enum { MAXPTS = 100 };
if( !GetClosed() ) if( !GetClosed() )
ASSERT(0); ASSERT(0);
// define line passing through (x,y), with slope = 2/3; // define line passing through (x,y), with slope = 2/3;
// get intersection points // get intersection points
double xx[MAXPTS], yy[MAXPTS]; double xx[MAXPTS], yy[MAXPTS];
double slope = (double)2.0/3.0; double slope = (double)2.0/3.0;
double a = y - slope*x; double a = y - slope*x;
int nloops = 0; int nloops = 0;
int npts; int npts;
// make this a loop so if my homebrew algorithm screws up, we try it again // make this a loop so if my homebrew algorithm screws up, we try it again
do do
{ {
// now find all intersection points of line with polyline sides // now find all intersection points of line with polyline sides
npts = 0; npts = 0;
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
for( int ic=istart; ic<=iend; ic++ ) for( int ic=istart; ic<=iend; ic++ )
{ {
double x, y, x2, y2; double x, y, x2, y2;
int ok; int ok;
if( ic == istart ) if( ic == istart )
ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope,
corner[iend].x, corner[iend].y, corner[iend].x, corner[iend].y,
corner[istart].x, corner[istart].y, corner[istart].x, corner[istart].y,
side_style[corner.size()-1], side_style[corner.size()-1],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
else else
ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope,
corner[ic-1].x, corner[ic-1].y, corner[ic-1].x, corner[ic-1].y,
corner[ic].x, corner[ic].y, corner[ic].x, corner[ic].y,
side_style[ic-1], side_style[ic-1],
&x, &y, &x2, &y2 ); &x, &y, &x2, &y2 );
if( ok ) if( ok )
{ {
xx[npts] = (int)x; xx[npts] = (int)x;
yy[npts] = (int)y; yy[npts] = (int)y;
npts++; npts++;
ASSERT( npts<MAXPTS ); // overflow ASSERT( npts<MAXPTS ); // overflow
} }
if( ok == 2 ) if( ok == 2 )
{ {
xx[npts] = (int)x2; xx[npts] = (int)x2;
yy[npts] = (int)y2; yy[npts] = (int)y2;
npts++; npts++;
ASSERT( npts<MAXPTS ); // overflow ASSERT( npts<MAXPTS ); // overflow
} }
} }
nloops++; nloops++;
a += PCBU_PER_MIL/100; a += PCBU_PER_MIL/100;
} while( npts%2 != 0 && nloops < 3 ); } while( npts%2 != 0 && nloops < 3 );
ASSERT( npts%2==0 ); // odd number of intersection points, error ASSERT( npts%2==0 ); // odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline // count intersection points to right of (x,y), if odd (x,y) is inside polyline
int ncount = 0; int ncount = 0;
for( int ip=0; ip<npts; ip++ ) for( int ip=0; ip<npts; ip++ )
{ {
if( xx[ip] == x && yy[ip] == y ) if( xx[ip] == x && yy[ip] == y )
return FALSE; // (x,y) is on a side, call it outside return FALSE; // (x,y) is on a side, call it outside
else if( xx[ip] > x ) else if( xx[ip] > x )
ncount++; ncount++;
} }
if( ncount%2 ) if( ncount%2 )
return TRUE; return TRUE;
else else
return FALSE; return FALSE;
} }
// Test for intersection of sides // Test for intersection of sides
// //
int CPolyLine::TestIntersection( CPolyLine * poly ) int CPolyLine::TestIntersection( CPolyLine * poly )
{ {
if( !GetClosed() ) if( !GetClosed() )
ASSERT(0); ASSERT(0);
if( !poly->GetClosed() ) if( !poly->GetClosed() )
ASSERT(0); ASSERT(0);
for( int ic=0; ic<GetNumContours(); ic++ ) for( int ic=0; ic<GetNumContours(); ic++ )
{ {
int istart = GetContourStart(ic); int istart = GetContourStart(ic);
int iend = GetContourEnd(ic); int iend = GetContourEnd(ic);
for( int is=istart; is<=iend; is++ ) for( int is=istart; is<=iend; is++ )
{ {
int xf, yf; int xf, yf;
if( is < GetContourEnd(ic) ) if( is < GetContourEnd(ic) )
{ {
xf = GetX(is+1); xf = GetX(is+1);
yf = GetY(is+1); yf = GetY(is+1);
} }
else else
{ {
xf = GetX(istart); xf = GetX(istart);
yf = GetY(istart); yf = GetY(istart);
} }
for( int ic2=0; ic2<poly->GetNumContours(); ic2++ ) for( int ic2=0; ic2<poly->GetNumContours(); ic2++ )
{ {
int istart2 = poly->GetContourStart(ic2); int istart2 = poly->GetContourStart(ic2);
int iend2 = poly->GetContourEnd(ic2); int iend2 = poly->GetContourEnd(ic2);
for( int is2=istart2; is2<=iend2; is2++ ) for( int is2=istart2; is2<=iend2; is2++ )
{ {
int xf2, yf2; int xf2, yf2;
if( is2 < poly->GetContourEnd(ic2) ) if( is2 < poly->GetContourEnd(ic2) )
{ {
xf2 = poly->GetX(is2+1); xf2 = poly->GetX(is2+1);
yf2 = poly->GetY(is2+1); yf2 = poly->GetY(is2+1);
} }
else else
{ {
xf2 = poly->GetX(istart2); xf2 = poly->GetX(istart2);
yf2 = poly->GetY(istart2); yf2 = poly->GetY(istart2);
} }
// test for intersection between side and side2 // test for intersection between side and side2
} }
} }
} }
} }
return 0; return 0;
} }
// set selection box size // set selection box size
// //
void CPolyLine::SetSelBoxSize( int sel_box ) void CPolyLine::SetSelBoxSize( int sel_box )
{ {
// Undraw(); // Undraw();
m_sel_box = sel_box; m_sel_box = sel_box;
// Draw(); // Draw();
} }
// set pointer to display list, and draw into display list // set pointer to display list, and draw into display list
// //
void CPolyLine::SetDisplayList( CDisplayList * dl ) void CPolyLine::SetDisplayList( CDisplayList * dl )
{ {
if( m_dlist ) if( m_dlist )
Undraw(); Undraw();
m_dlist = dl; m_dlist = dl;
if( m_dlist ) if( m_dlist )
Draw(); Draw();
} }
// copy data from another poly, but don't draw it // copy data from another poly, but don't draw it
// //
void CPolyLine::Copy( CPolyLine * src ) void CPolyLine::Copy( CPolyLine * src )
{ {
Undraw(); Undraw();
m_dlist = src->m_dlist; m_dlist = src->m_dlist;
m_sel_box = src->m_sel_box; m_sel_box = src->m_sel_box;
// copy corners // copy corners
for( unsigned i=0; i< src->corner.size(); i++ ) for( unsigned i=0; i< src->corner.size(); i++ )
corner.push_back(src->corner[i]); corner.push_back(src->corner[i]);
// copy side styles // copy side styles
int nsides = src->GetNumSides(); int nsides = src->GetNumSides();
side_style.SetSize(nsides); side_style.SetSize(nsides);
for( int i=0; i<nsides; i++ ) for( int i=0; i<nsides; i++ )
side_style[i] = src->side_style[i]; side_style[i] = src->side_style[i];
// don't copy the Gpc_poly, just clear the old one // don't copy the Gpc_poly, just clear the old one
FreeGpcPoly(); FreeGpcPoly();
} }
void CPolyLine::MoveOrigin( int x_off, int y_off ) void CPolyLine::MoveOrigin( int x_off, int y_off )
{ {
Undraw(); Undraw();
for( int ic=0; ic < GetNumCorners(); ic++ ) for( int ic=0; ic < GetNumCorners(); ic++ )
{ {
SetX( ic, GetX(ic) + x_off ); SetX( ic, GetX(ic) + x_off );
SetY( ic, GetY(ic) + y_off ); SetY( ic, GetY(ic) + y_off );
} }
Draw(); Draw();
} }
// Set various parameters: // Set various parameters:
// the calling function should Undraw() before calling them, // the calling function should Undraw() before calling them,
// and Draw() after // and Draw() after
// //
void CPolyLine::SetX( int ic, int x ) { corner[ic].x = x; } void CPolyLine::SetX( int ic, int x ) { corner[ic].x = x; }
void CPolyLine::SetY( int ic, int y ) { corner[ic].y = y; } void CPolyLine::SetY( int ic, int y ) { corner[ic].y = y; }
void CPolyLine::SetEndContour( int ic, BOOL end_contour ) { corner[ic].end_contour = end_contour; } void CPolyLine::SetEndContour( int ic, BOOL end_contour ) { corner[ic].end_contour = end_contour; }
// Create CPolyLine for a pad // Create CPolyLine for a pad
// //
CPolyLine * CPolyLine::MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle ) CPolyLine * CPolyLine::MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle )
{ {
CPolyLine * poly = new CPolyLine; CPolyLine * poly = new CPolyLine;
int dx = l/2; int dx = l/2;
int dy = w/2; int dy = w/2;
if( angle%180 == 90 ) if( angle%180 == 90 )
{ {
dx = w/2; dx = w/2;
dy = l/2; dy = l/2;
} }
if( type == PAD_ROUND ) if( type == PAD_ROUND )
{ {
poly->Start( 0, 0, 0, x-dx, y, 0 ); poly->Start( 0, 0, 0, x-dx, y, 0 );
poly->AppendCorner( x, y+dy, ARC_CW, 0 ); poly->AppendCorner( x, y+dy, ARC_CW, 0 );
poly->AppendCorner( x+dx, y, ARC_CW, 0 ); poly->AppendCorner( x+dx, y, ARC_CW, 0 );
poly->AppendCorner( x, y-dy, ARC_CW, 0 ); poly->AppendCorner( x, y-dy, ARC_CW, 0 );
poly->Close( ARC_CW ); poly->Close( ARC_CW );
} }
return poly; return poly;
} }
// Add cutout for a pad // Add cutout for a pad
// Convert arcs to multiple straight lines // Convert arcs to multiple straight lines
// Do NOT draw or undraw // Do NOT draw or undraw
// //
void CPolyLine::AddContourForPadClearance( int type, int x, int y, int w, void CPolyLine::AddContourForPadClearance( int type, int x, int y, int w,
int l, int r, int angle, int fill_clearance, int l, int r, int angle, int fill_clearance,
int hole_w, int hole_clearance, BOOL bThermal, int spoke_w ) int hole_w, int hole_clearance, BOOL bThermal, int spoke_w )
{ {
int dx = l/2; int dx = l/2;
int dy = w/2; int dy = w/2;
if( angle%180 == 90 ) if( angle%180 == 90 )
{ {
dx = w/2; dx = w/2;
dy = l/2; dy = l/2;
} }
int x_clearance = max( fill_clearance, hole_clearance+hole_w/2-dx); int x_clearance = max( fill_clearance, hole_clearance+hole_w/2-dx);
int y_clearance = max( fill_clearance, hole_clearance+hole_w/2-dy); int y_clearance = max( fill_clearance, hole_clearance+hole_w/2-dy);
dx += x_clearance; dx += x_clearance;
dy += y_clearance; dy += y_clearance;
if( !bThermal ) if( !bThermal )
{ {
// normal clearance // normal clearance
if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) ) if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) )
{ {
AppendCorner( x-dx, y, ARC_CW, 0 ); AppendCorner( x-dx, y, ARC_CW, 0 );
AppendCorner( x, y+dy, ARC_CW, 0 ); AppendCorner( x, y+dy, ARC_CW, 0 );
AppendCorner( x+dx, y, ARC_CW, 0 ); AppendCorner( x+dx, y, ARC_CW, 0 );
AppendCorner( x, y-dy, ARC_CW, 0 ); AppendCorner( x, y-dy, ARC_CW, 0 );
Close( ARC_CW ); Close( ARC_CW );
} }
else if( type == PAD_SQUARE || type == PAD_RECT else if( type == PAD_SQUARE || type == PAD_RECT
|| type == PAD_RRECT || type == PAD_OVAL ) || type == PAD_RRECT || type == PAD_OVAL )
{ {
AppendCorner( x-dx, y-dy, STRAIGHT, 0 ); AppendCorner( x-dx, y-dy, STRAIGHT, 0 );
AppendCorner( x+dx, y-dy, STRAIGHT, 0 ); AppendCorner( x+dx, y-dy, STRAIGHT, 0 );
AppendCorner( x+dx, y+dy, STRAIGHT, 0 ); AppendCorner( x+dx, y+dy, STRAIGHT, 0 );
AppendCorner( x-dx, y+dy, STRAIGHT, 0 ); AppendCorner( x-dx, y+dy, STRAIGHT, 0 );
Close( STRAIGHT ); Close( STRAIGHT );
} }
} }
else else
{ {
// thermal relief // thermal relief
if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) ) if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) )
{ {
// draw 4 "wedges" // draw 4 "wedges"
double r = max(w/2 + fill_clearance, hole_w/2 + hole_clearance); double r = max(w/2 + fill_clearance, hole_w/2 + hole_clearance);
double start_angle = asin( spoke_w/(2.0*r) ); double start_angle = asin( spoke_w/(2.0*r) );
double th1, th2, corner_x, corner_y; double th1, th2, corner_x, corner_y;
for( int i=0; i<4; i++ ) for( int i=0; i<4; i++ )
{ {
if( i == 0 ) if( i == 0 )
{ {
corner_x = spoke_w/2; corner_x = spoke_w/2;
corner_y = spoke_w/2; corner_y = spoke_w/2;
th1 = start_angle; th1 = start_angle;
th2 = pi/2.0 - start_angle; th2 = pi/2.0 - start_angle;
} }
else if( i == 1 ) else if( i == 1 )
{ {
corner_x = -spoke_w/2; corner_x = -spoke_w/2;
corner_y = spoke_w/2; corner_y = spoke_w/2;
th1 = pi/2.0 + start_angle; th1 = pi/2.0 + start_angle;
th2 = pi - start_angle; th2 = pi - start_angle;
} }
else if( i == 2 ) else if( i == 2 )
{ {
corner_x = -spoke_w/2; corner_x = -spoke_w/2;
corner_y = -spoke_w/2; corner_y = -spoke_w/2;
th1 = -pi + start_angle; th1 = -pi + start_angle;
th2 = -pi/2.0 - start_angle; th2 = -pi/2.0 - start_angle;
} }
else if( i == 3 ) else if( i == 3 )
{ {
corner_x = spoke_w/2; corner_x = spoke_w/2;
corner_y = -spoke_w/2; corner_y = -spoke_w/2;
th1 = -pi/2.0 + start_angle; th1 = -pi/2.0 + start_angle;
th2 = -start_angle; th2 = -start_angle;
} }
AppendCorner( to_int(x+corner_x), to_int(y+corner_y), STRAIGHT, 0 ); AppendCorner( to_int(x+corner_x), to_int(y+corner_y), STRAIGHT, 0 );
AppendCorner( to_int(x+r*cos(th1)), to_int(y+r*sin(th1)), STRAIGHT, 0 ); AppendCorner( to_int(x+r*cos(th1)), to_int(y+r*sin(th1)), STRAIGHT, 0 );
AppendCorner( to_int(x+r*cos(th2)), to_int(y+r*sin(th2)), ARC_CCW, 0 ); AppendCorner( to_int(x+r*cos(th2)), to_int(y+r*sin(th2)), ARC_CCW, 0 );
Close( STRAIGHT ); Close( STRAIGHT );
} }
} }
else if( type == PAD_SQUARE || type == PAD_RECT else if( type == PAD_SQUARE || type == PAD_RECT
|| type == PAD_RRECT || type == PAD_OVAL ) || type == PAD_RRECT || type == PAD_OVAL )
{ {
// draw 4 rectangles // draw 4 rectangles
int xL = x - dx; int xL = x - dx;
int xR = x - spoke_w/2; int xR = x - spoke_w/2;
int yB = y - dy; int yB = y - dy;
int yT = y - spoke_w/2; int yT = y - spoke_w/2;
AppendCorner( xL, yB, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 ); AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 ); AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT ); Close( STRAIGHT );
xL = x + spoke_w/2; xL = x + spoke_w/2;
xR = x + dx; xR = x + dx;
AppendCorner( xL, yB, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 ); AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 ); AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT ); Close( STRAIGHT );
xL = x - dx; xL = x - dx;
xR = x - spoke_w/2; xR = x - spoke_w/2;
yB = y + spoke_w/2; yB = y + spoke_w/2;
yT = y + dy; yT = y + dy;
AppendCorner( xL, yB, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 ); AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 ); AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT ); Close( STRAIGHT );
xL = x + spoke_w/2; xL = x + spoke_w/2;
xR = x + dx; xR = x + dx;
AppendCorner( xL, yB, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 ); AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 ); AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT ); Close( STRAIGHT );
} }
} }
return; return;
} }
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 )
{ {
// get radius // get radius
double r = sqrt( (double)(xi-xc)*(xi-xc) + (double)(yi-yc)*(yi-yc) ); double r = sqrt( (double)(xi-xc)*(xi-xc) + (double)(yi-yc)*(yi-yc) );
// get angles of start and finish // get angles of start and finish
double th_i = atan2( (double)yi-yc, (double)xi-xc ); double th_i = atan2( (double)yi-yc, (double)xi-xc );
double th_f = atan2( (double)yf-yc, (double)xf-xc ); double th_f = atan2( (double)yf-yc, (double)xf-xc );
double th_d = (th_f - th_i)/(num-1); double th_d = (th_f - th_i)/(num-1);
double theta = th_i; double theta = th_i;
// generate arc // generate arc
for( int ic=0; ic<num; ic++ ) for( int ic=0; ic<num; ic++ )
{ {
int x = to_int(xc + r*cos(theta)); int x = to_int(xc + r*cos(theta));
int y = to_int(yc + r*sin(theta)); int y = to_int(yc + r*sin(theta));
AppendCorner( x, y, STRAIGHT, 0 ); AppendCorner( x, y, STRAIGHT, 0 );
theta += th_d; theta += th_d;
} }
Close( STRAIGHT ); Close( STRAIGHT );
} }
void CPolyLine::ClipGpcPolygon( gpc_op op, CPolyLine * clip_poly ) void CPolyLine::ClipGpcPolygon( gpc_op op, CPolyLine * clip_poly )
{ {
gpc_polygon * result = new gpc_polygon; gpc_polygon * result = new gpc_polygon;
gpc_polygon_clip( op, m_gpc_poly, clip_poly->GetGpcPoly(), result ); gpc_polygon_clip( op, m_gpc_poly, clip_poly->GetGpcPoly(), result );
gpc_free_polygon( m_gpc_poly ); gpc_free_polygon( m_gpc_poly );
delete m_gpc_poly; delete m_gpc_poly;
m_gpc_poly = result; m_gpc_poly = result;
} }
// PolyLine.h ... definition of CPolyLine class // PolyLine.h ... definition of CPolyLine class
// //
// A polyline contains one or more contours, where each contour // A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles // is defined by a list of corners and side-styles
// There may be multiple contours in a polyline. // There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed. // The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays, // All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of // separated by setting the end_contour flag of the last corner of
// each contour. // each contour.
// //
// When used for copper areas, the first contour is the outer edge // When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper. // of the area, subsequent ones are "holes" in the copper.
// //
// If a CDisplayList pointer is provided, the polyline can draw itself // If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE_H #ifndef POLYLINE_H
#define POLYLINE_H #define POLYLINE_H
#include <vector> #include <vector>
#include "defs-macros.h" #include "defs-macros.h"
#include "GenericPolygonClipperLibrary.h" #include "GenericPolygonClipperLibrary.h"
#include "php_polygon.h" #include "php_polygon.h"
#include "php_polygon_vertex.h" #include "php_polygon_vertex.h"
#include "PolyLine2Kicad.h" #include "PolyLine2Kicad.h"
#include "freepcb_ids.h" #include "freepcb_ids.h"
#include "freepcbDisplayList.h" #include "freepcbDisplayList.h"
#include "math_for_graphics.h" #include "math_for_graphics.h"
class CSegment { class CSegment {
public: public:
int xi, yi, xf, yf; int xi, yi, xf, yf;
CSegment() {}; CSegment() {};
CSegment(int x0, int y0, int x1, int y1) { CSegment(int x0, int y0, int x1, int y1) {
xi = x0; yi = y0; xf = x1; yf = y1; } xi = x0; yi = y0; xf = x1; yf = y1; }
}; };
class CArc { class CArc {
public: public:
enum{ MAX_STEP = 50*25400 }; // max step is 20 mils enum{ MAX_STEP = 50*25400 }; // max step is 20 mils
enum{ MIN_STEPS = 18 }; // min step is 5 degrees enum{ MIN_STEPS = 18 }; // min step is 5 degrees
int style; int style;
int xi, yi, xf, yf; int xi, yi, xf, yf;
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 class CPolyPt
{ {
public: public:
CPolyPt( int qx=0, int qy=0, BOOL qf=FALSE ) CPolyPt( int qx=0, int qy=0, BOOL qf=FALSE )
{ x=qx; y=qy; end_contour=qf; utility = 0; }; { x=qx; y=qy; end_contour=qf; utility = 0; };
int x; int x;
int y; int y;
BOOL end_contour; BOOL end_contour;
int utility; int utility;
}; };
class CPolyLine class CPolyLine
{ {
public: public:
enum { STRAIGHT, ARC_CW, ARC_CCW }; // side styles enum { STRAIGHT, ARC_CW, ARC_CCW }; // side styles
enum { NO_HATCH, DIAGONAL_FULL, DIAGONAL_EDGE }; // hatch styles enum { NO_HATCH, DIAGONAL_FULL, DIAGONAL_EDGE }; // hatch styles
enum { DEF_SIZE = 50, DEF_ADD = 50 }; // number of array elements to add at a time enum { DEF_SIZE = 50, DEF_ADD = 50 }; // number of array elements to add at a time
// constructors/destructor // constructors/destructor
CPolyLine( CDisplayList * dl ); CPolyLine( CDisplayList * dl );
CPolyLine(); CPolyLine();
~CPolyLine(); ~CPolyLine();
// functions for modifying polyline // functions for modifying polyline
void Start( int layer, int w, int sel_box, int x, int y, void Start( int layer, int w, int sel_box, int x, int y,
int hatch ); int hatch );
void AppendCorner( int x, int y, int style = STRAIGHT, BOOL bDraw=TRUE ); void AppendCorner( int x, int y, int style = STRAIGHT, BOOL bDraw=TRUE );
void InsertCorner( int ic, int x, int y ); void InsertCorner( int ic, int x, int y );
void DeleteCorner( int ic, BOOL bDraw=TRUE ); void DeleteCorner( int ic, BOOL bDraw=TRUE );
void MoveCorner( int ic, int x, int y ); void MoveCorner( int ic, int x, int y );
void Close( int style = STRAIGHT, BOOL bDraw=TRUE ); void Close( int style = STRAIGHT, BOOL bDraw=TRUE );
void RemoveContour( int icont ); void RemoveContour( int icont );
// drawing functions // drawing functions
void HighlightSide( int is ); void HighlightSide( int is );
void HighlightCorner( int ic ); void HighlightCorner( int ic );
void StartDraggingToInsertCorner( CDC * pDC, int ic, int x, int y); void StartDraggingToInsertCorner( CDC * pDC, int ic, int x, int y);
void StartDraggingToMoveCorner( CDC * pDC, int ic, int x, int y); void StartDraggingToMoveCorner( CDC * pDC, int ic, int x, int y);
void CancelDraggingToInsertCorner( int ic ); void CancelDraggingToInsertCorner( int ic );
void CancelDraggingToMoveCorner( int ic ); void CancelDraggingToMoveCorner( int ic );
void Undraw(); void Undraw();
void Draw( CDisplayList * dl = NULL ); void Draw( CDisplayList * dl = NULL );
void Hatch(); void Hatch();
void MakeVisible( BOOL visible = TRUE ); void MakeVisible( BOOL visible = TRUE );
void MoveOrigin( int x_off, int y_off ); void MoveOrigin( int x_off, int y_off );
// misc. functions // misc. functions
CRect GetBounds(); CRect GetBounds();
CRect GetCornerBounds(); CRect GetCornerBounds();
CRect GetCornerBounds( int icont ); CRect GetCornerBounds( int icont );
void Copy( CPolyLine * src ); void Copy( CPolyLine * src );
BOOL TestPointInside( int x, int y ); BOOL TestPointInside( int x, int y );
BOOL TestPointInsideContour( int icont, int x, int y ); BOOL TestPointInsideContour( int icont, int x, int y );
int TestIntersection( CPolyLine * poly ); int TestIntersection( CPolyLine * poly );
void AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ); void AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num );
// access functions // access functions
int GetNumCorners(); int GetNumCorners();
int GetNumSides(); int GetNumSides();
int GetClosed(); int GetClosed();
int GetNumContours(); int GetNumContours();
int GetContour( int ic ); int GetContour( int ic );
int GetContourStart( int icont ); int GetContourStart( int icont );
int GetContourEnd( int icont ); int GetContourEnd( int icont );
int GetContourSize( int icont ); int GetContourSize( int icont );
int GetX( int ic ); int GetX( int ic );
int GetY( int ic ); int GetY( int ic );
int GetEndContour( int ic ); int GetEndContour( int ic );
int GetUtility( int ic ){ return corner[ic].utility; }; int GetUtility( int ic ){ return corner[ic].utility; };
void SetUtility( int ic, int utility ){ corner[ic].utility = utility; }; void SetUtility( int ic, int utility ){ corner[ic].utility = utility; };
int GetW(); int GetW();
int GetSideStyle( int is ); int GetSideStyle( int is );
id GetId(); id GetId();
int GetSelBoxSize(); int GetSelBoxSize();
CDisplayList * GetDisplayList(){ return m_dlist; }; CDisplayList * GetDisplayList(){ return m_dlist; };
int GetHatch(){ return m_HatchStyle; } int GetHatch(){ return m_HatchStyle; }
void SetHatch( int hatch ){ Undraw(); m_HatchStyle = hatch; Draw(); }; void SetHatch( int hatch ){ Undraw(); m_HatchStyle = hatch; Draw(); };
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 SetLayer( int layer ); // void SetLayer( int layer );
void SetW( int w ); void SetW( int w );
void SetSideStyle( int is, int style ); void SetSideStyle( int is, int style );
void SetSelBoxSize( int sel_box ); void SetSelBoxSize( int sel_box );
void SetDisplayList( CDisplayList * dl ); void SetDisplayList( CDisplayList * dl );
// GPC functions // GPC functions
int MakeGpcPoly( int icontour=0, std::vector<CArc> * arc_array=NULL ); int MakeGpcPoly( int icontour=0, std::vector<CArc> * arc_array=NULL );
int FreeGpcPoly(); int FreeGpcPoly();
gpc_polygon * GetGpcPoly(){ return m_gpc_poly; }; gpc_polygon * GetGpcPoly(){ return m_gpc_poly; };
int NormalizeWithGpc( std::vector<CPolyLine*> * pa=NULL, BOOL bRetainArcs=FALSE ); int NormalizeWithGpc( std::vector<CPolyLine*> * pa=NULL, BOOL bRetainArcs=FALSE );
int RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa=NULL ); int RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa=NULL );
CPolyLine * MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle ); CPolyLine * MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle );
void AddContourForPadClearance( int type, int x, int y, int w, void AddContourForPadClearance( int type, int x, int y, int w,
int l, int r, int angle, int fill_clearance, int l, int r, int angle, int fill_clearance,
int hole_w, int hole_clearance, BOOL bThermal=FALSE, int spoke_w=0 ); int hole_w, int hole_clearance, BOOL bThermal=FALSE, int spoke_w=0 );
void ClipGpcPolygon( gpc_op op, CPolyLine * poly ); void ClipGpcPolygon( gpc_op op, CPolyLine * poly );
// PHP functions // PHP functions
int MakePhpPoly(); int MakePhpPoly();
void FreePhpPoly(); void FreePhpPoly();
void ClipPhpPolygon( int php_op, CPolyLine * poly ); void ClipPhpPolygon( int php_op, CPolyLine * poly );
private: private:
CDisplayList * m_dlist; // display list CDisplayList * m_dlist; // display list
int m_layer; // layer to draw on int m_layer; // layer to draw on
int m_Width; // line width int m_Width; // line width
int m_sel_box; // corner selection box width/2 int m_sel_box; // corner selection box width/2
public: public:
std::vector <CPolyPt> corner; // array of points for corners std::vector <CPolyPt> corner; // array of points for corners
std::vector <int> side_style; // array of styles for sides std::vector <int> side_style; // array of styles for sides
private: private:
std::vector <dl_element*> dl_side; // graphic elements std::vector <dl_element*> dl_side; // graphic elements
std::vector <dl_element*> dl_side_sel; std::vector <dl_element*> dl_side_sel;
std::vector <dl_element*> dl_corner_sel; std::vector <dl_element*> dl_corner_sel;
public: public:
int m_HatchStyle; // hatch style, see enum above int m_HatchStyle; // hatch style, see enum above
std::vector <CSegment> m_HatchLines; // hatch lines std::vector <CSegment> m_HatchLines; // hatch lines
private: private:
gpc_polygon * m_gpc_poly; // polygon in gpc format gpc_polygon * m_gpc_poly; // polygon in gpc format
polygon * m_php_poly; polygon * m_php_poly;
BOOL bDrawn; BOOL bDrawn;
}; };
#endif // #ifndef POLYLINE_H #endif // #ifndef POLYLINE_H
// PolyLine.h ... definition of CPolyLine class // PolyLine.h ... definition of CPolyLine class
// //
// A polyline contains one or more contours, where each contour // A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles // is defined by a list of corners and side-styles
// There may be multiple contours in a polyline. // There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed. // The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays, // All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of // separated by setting the end_contour flag of the last corner of
// each contour. // each contour.
// //
// When used for copper areas, the first contour is the outer edge // When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper. // of the area, subsequent ones are "holes" in the copper.
// //
// If a CDisplayList pointer is provided, the polyline can draw itself // If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE2KICAD_H #ifndef POLYLINE2KICAD_H
#define POLYLINE2KICAD_H #define POLYLINE2KICAD_H
#define PCBU_PER_MIL 10 #define PCBU_PER_MIL 10
#define MAX_LAYERS 32 #define MAX_LAYERS 32
#define NM_PER_MIL 10 // 25400 #define NM_PER_MIL 10 // 25400
// pad shapes // pad shapes
enum enum
{ {
PAD_NONE = 0, PAD_NONE = 0,
PAD_ROUND, PAD_ROUND,
PAD_SQUARE, PAD_SQUARE,
PAD_RECT, PAD_RECT,
PAD_RRECT, PAD_RRECT,
PAD_OVAL, PAD_OVAL,
PAD_OCTAGON PAD_OCTAGON
}; };
/* /*
enum enum
{ {
// visible layers // visible layers
LAY_SELECTION = 0, LAY_SELECTION = 0,
LAY_BACKGND, LAY_BACKGND,
LAY_VISIBLE_GRID, LAY_VISIBLE_GRID,
LAY_HILITE, LAY_HILITE,
LAY_DRC_ERROR, LAY_DRC_ERROR,
LAY_BOARD_OUTLINE, LAY_BOARD_OUTLINE,
LAY_RAT_LINE, LAY_RAT_LINE,
LAY_SILK_TOP, LAY_SILK_TOP,
LAY_SILK_BOTTOM, LAY_SILK_BOTTOM,
LAY_SM_TOP, LAY_SM_TOP,
LAY_SM_BOTTOM, LAY_SM_BOTTOM,
LAY_PAD_THRU, LAY_PAD_THRU,
LAY_TOP_COPPER, LAY_TOP_COPPER,
LAY_BOTTOM_COPPER, LAY_BOTTOM_COPPER,
// invisible layers // invisible layers
LAY_MASK_TOP = -100, LAY_MASK_TOP = -100,
LAY_MASK_BOTTOM = -101, LAY_MASK_BOTTOM = -101,
LAY_PASTE_TOP = -102, LAY_PASTE_TOP = -102,
LAY_PASTE_BOTTOM = -103 LAY_PASTE_BOTTOM = -103
}; };
*/ */
#define LAY_SELECTION 0 #define LAY_SELECTION 0
#define LAY_TOP_COPPER 0 #define LAY_TOP_COPPER 0
#define CDC wxDC #define CDC wxDC
class wxDC; class wxDC;
#if 0 #if 0
class dl_element; class dl_element;
class CDisplayList { class CDisplayList {
public: public:
void Set_visible(void*, int) {}; void Set_visible(void*, int) {};
int Get_x(void) { return 0;}; int Get_x(void) { return 0;};
int Get_y(void) { return 0;}; int Get_y(void) { return 0;};
void StopDragging(void) {}; void StopDragging(void) {};
void CancelHighLight(void) {}; void CancelHighLight(void) {};
void StartDraggingLineVertex(...) {}; void StartDraggingLineVertex(...) {};
void Add() {}; void Add() {};
}; };
#endif #endif
class CRect { class CRect {
public: public:
int left, right, top, bottom; int left, right, top, bottom;
}; };
class CPoint { class CPoint {
public: public:
int x, y; int x, y;
public: public:
CPoint(void) { x = y = 0;}; CPoint(void) { x = y = 0;};
CPoint(int i, int j) { x = i; y = j;}; CPoint(int i, int j) { x = i; y = j;};
}; };
#endif // #ifndef POLYLINE2KICAD_H #endif // #ifndef POLYLINE2KICAD_H
/* stuff for class CDisplayList */ /* stuff for class CDisplayList */
#include "PolyLine.h" #include "PolyLine.h"
dl_element * CDisplayList::Add( id id, void * ptr, int glayer, int gtype, int visible, dl_element * CDisplayList::Add( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int w, int holew, int x, int y, int xf, int yf, int xo, int yo,
int radius, int orig_layer ) int radius, int orig_layer )
{ {
return NULL; return NULL;
} }
dl_element * CDisplayList::AddSelector( id id, void * ptr, int glayer, int gtype, int visible, dl_element * CDisplayList::AddSelector( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int radius ) int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int radius )
{ {
return NULL; return NULL;
} }
void CDisplayList::Set_visible( dl_element * el, int visible ) void CDisplayList::Set_visible( dl_element * el, int visible )
{ {
} }
int CDisplayList::StopDragging() int CDisplayList::StopDragging()
{ {
return 0; return 0;
} }
int CDisplayList::CancelHighLight() int CDisplayList::CancelHighLight()
{ {
return 0; return 0;
} }
void CDisplayList::Set_id( dl_element * el, id * id ) void CDisplayList::Set_id( dl_element * el, id * id )
{ {
} }
id CDisplayList::Remove( dl_element * element ) id CDisplayList::Remove( dl_element * element )
{ {
return 0; return 0;
} }
int CDisplayList::Get_w( dl_element * el ) int CDisplayList::Get_w( dl_element * el )
{ {
return 0; return 0;
} }
int CDisplayList::Get_x( dl_element * el ) int CDisplayList::Get_x( dl_element * el )
{ {
return 0; return 0;
} }
int CDisplayList::Get_y( dl_element * el ) int CDisplayList::Get_y( dl_element * el )
{ {
return 0; return 0;
} }
int CDisplayList::Get_xf( dl_element * el ) int CDisplayList::Get_xf( dl_element * el )
{ {
return 0; return 0;
} }
int CDisplayList::Get_yf( dl_element * el ) int CDisplayList::Get_yf( dl_element * el )
{ {
return 0; return 0;
} }
int CDisplayList::HighLight( int gtype, int x, int y, int xf, int yf, int w, int orig_layer ) int CDisplayList::HighLight( int gtype, int x, int y, int xf, int yf, int w, int orig_layer )
{ {
return 0; return 0;
} }
int CDisplayList::StartDraggingLineVertex( CDC * pDC, int x, int y, int xi, int yi, int CDisplayList::StartDraggingLineVertex( CDC * pDC, int x, int y, int xi, int yi,
int xf, int yf, int xf, int yf,
int layer1, int layer2, int w1, int w2, int layer1, int layer2, int w1, int w2,
int style1, int style2, int style1, int style2,
int layer_no_via, int via_w, int via_holew, int dir, int layer_no_via, int via_w, int via_holew, int dir,
int crosshair ) int crosshair )
{ {
return 0; return 0;
} }
int CDisplayList::StartDraggingArc( CDC * pDC, int style, int x, int y, int xi, int yi, int CDisplayList::StartDraggingArc( CDC * pDC, int style, int x, int y, int xi, int yi,
int layer, int w, int crosshair ) int layer, int w, int crosshair )
{ {
return 0; return 0;
} }
// DisplayList.h : header file for CDisplayList class // DisplayList.h : header file for CDisplayList class
// //
#ifndef FP_DISPLAY_LIST_H #ifndef FP_DISPLAY_LIST_H
#define FP_DISPLAY_LIST_H #define FP_DISPLAY_LIST_H
//#define DL_MAX_LAYERS 32 //#define DL_MAX_LAYERS 32
#define DL_MAGIC 2674 #define DL_MAGIC 2674
#define PCBU_PER_WU 25400 // conversion from PCB units to world units #define PCBU_PER_WU 25400 // conversion from PCB units to world units
// graphics element types // graphics element types
enum enum
{ {
DL_NONE = 0, DL_NONE = 0,
DL_LINE, // line segment with round end-caps DL_LINE, // line segment with round end-caps
DL_CIRC, // filled circle DL_CIRC, // filled circle
DL_HOLLOW_CIRC, // circle outline DL_HOLLOW_CIRC, // circle outline
DL_DONUT, // annulus DL_DONUT, // annulus
DL_SQUARE, // filled square DL_SQUARE, // filled square
DL_RECT, // filled rectangle DL_RECT, // filled rectangle
DL_RRECT, // filled rounded rectangle DL_RRECT, // filled rounded rectangle
DL_OVAL, // filled oval DL_OVAL, // filled oval
DL_OCTAGON, // filled octagon DL_OCTAGON, // filled octagon
DL_HOLE, // hole, shown as circle DL_HOLE, // hole, shown as circle
DL_HOLLOW_RECT, // rectangle outline DL_HOLLOW_RECT, // rectangle outline
DL_RECT_X, // rectangle outline with X DL_RECT_X, // rectangle outline with X
DL_POINT, // shape to highlight a point DL_POINT, // shape to highlight a point
DL_ARC_CW, // arc with clockwise curve DL_ARC_CW, // arc with clockwise curve
DL_ARC_CCW, // arc with counter-clockwise curve DL_ARC_CCW, // arc with counter-clockwise curve
DL_X // X DL_X // X
}; };
// dragging line shapes // dragging line shapes
enum enum
{ {
DS_NONE = 0, DS_NONE = 0,
DS_LINE_VERTEX, // vertex between two lines DS_LINE_VERTEX, // vertex between two lines
DS_LINE, // line DS_LINE, // line
DS_ARC_STRAIGHT, // straight line (used when drawing polylines) DS_ARC_STRAIGHT, // straight line (used when drawing polylines)
DS_ARC_CW, // clockwise arc (used when drawing polylines) DS_ARC_CW, // clockwise arc (used when drawing polylines)
DS_ARC_CCW // counterclockwise arc (used when drawing polylines) DS_ARC_CCW // counterclockwise arc (used when drawing polylines)
}; };
// styles of line segment when dragging line or line vertex // styles of line segment when dragging line or line vertex
enum enum
{ {
DSS_STRAIGHT = 100, // straight line DSS_STRAIGHT = 100, // straight line
DSS_ARC_CW, // clockwise arc DSS_ARC_CW, // clockwise arc
DSS_ARC_CCW // counterclockwise arc DSS_ARC_CCW // counterclockwise arc
}; };
// inflection modes for DS_LINE and DS_LINE_VERTEX // inflection modes for DS_LINE and DS_LINE_VERTEX
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 CDisplayList; class CDisplayList;
// this structure contains an element of the display list // this structure contains an element of the display list
class dl_element class dl_element
{ {
friend class CDisplayList; friend class CDisplayList;
public: public:
CDisplayList * dlist; CDisplayList * dlist;
int magic; int magic;
dl_element * prev; dl_element * prev;
dl_element * next; dl_element * next;
id m_id; // identifier (see ids.h) id m_id; // identifier (see ids.h)
void * ptr; // pointer to object drawing this element void * ptr; // pointer to object drawing this element
int gtype; // type of primitive int gtype; // type of primitive
int visible; // 0 to hide int visible; // 0 to hide
//private: //private:
int sel_vert; // for selection rectangles, 1 if part is vertical int sel_vert; // for selection rectangles, 1 if part is vertical
int w; // width (for round or square shapes) int w; // width (for round or square shapes)
int holew; // hole width (for round holes) int holew; // hole width (for round holes)
int x_org, y_org; // x origin (for rotation, reflection, etc.) int x_org, y_org; // x origin (for rotation, reflection, etc.)
int x, y; // starting or center position of element int x, y; // starting or center position of element
int xf, yf; // opposite corner (for rectangle or line) int xf, yf; // opposite corner (for rectangle or line)
int radius; // radius of corners for DL_RRECT int radius; // radius of corners for DL_RRECT
int layer; // layer to draw on int layer; // layer to draw on
int orig_layer; // for elements on highlight layer, int orig_layer; // for elements on highlight layer,
// the original layer, the highlight will // the original layer, the highlight will
// only be drawn if this layer is visible // only be drawn if this layer is visible
}; };
class CDisplayList class CDisplayList
{ {
private: private:
// display-list parameters for each layer // display-list parameters for each layer
dl_element m_start[MAX_LAYERS], m_end[MAX_LAYERS]; dl_element m_start[MAX_LAYERS], m_end[MAX_LAYERS];
int m_rgb[MAX_LAYERS][3]; // layer colors int m_rgb[MAX_LAYERS][3]; // layer colors
BOOL m_vis[MAX_LAYERS]; // layer visibility flags BOOL m_vis[MAX_LAYERS]; // layer visibility flags
int m_layer_in_order[MAX_LAYERS]; // array of layers in draw order int m_layer_in_order[MAX_LAYERS]; // array of layers in draw order
int m_order_for_layer[MAX_LAYERS]; // draw order for each layer int m_order_for_layer[MAX_LAYERS]; // draw order for each layer
// window parameters // window parameters
int m_pcbu_per_wu; // i.e. nm per world unit int m_pcbu_per_wu; // i.e. nm per world unit
CRect m_client_r; // client rect (pixels) CRect m_client_r; // client rect (pixels)
CRect m_screen_r; // client rect (screen coords) CRect m_screen_r; // client rect (screen coords)
int m_pane_org_x; // left border of drawing pane (pixels) int m_pane_org_x; // left border of drawing pane (pixels)
int m_pane_org_y; // bottom border of drawing pane (pixels) int m_pane_org_y; // bottom border of drawing pane (pixels)
int m_bottom_pane_h; // height of bottom pane int m_bottom_pane_h; // height of bottom pane
CDC * memDC; // pointer to memory DC CDC * memDC; // pointer to memory DC
double m_scale; // world units per pixel double m_scale; // world units per pixel
int m_org_x; // world x-coord of left side of screen (world units) int m_org_x; // world x-coord of left side of screen (world units)
int m_org_y; // world y-coord of bottom of screen (world units) int m_org_y; // world y-coord of bottom of screen (world units)
int m_max_x; // world x_coord of right side of screen (world units) int m_max_x; // world x_coord of right side of screen (world units)
int m_max_y; // world y_coord of top of screen (world units) int m_max_y; // world y_coord of top of screen (world units)
int w_ext_x, w_ext_y; // window extents (world units) int w_ext_x, w_ext_y; // window extents (world units)
int v_ext_x, v_ext_y; // viewport extents (pixels) int v_ext_x, v_ext_y; // viewport extents (pixels)
double m_wu_per_pixel_x; // ratio w_ext_x/v_ext_x (world units per pixel) double m_wu_per_pixel_x; // ratio w_ext_x/v_ext_x (world units per pixel)
double m_wu_per_pixel_y; // ratio w_ext_y/v_ext_y (world units per pixel) double m_wu_per_pixel_y; // ratio w_ext_y/v_ext_y (world units per pixel)
double m_pcbu_per_pixel_x; double m_pcbu_per_pixel_x;
double m_pcbu_per_pixel_y; double m_pcbu_per_pixel_y;
// general dragging parameters // general dragging parameters
int m_drag_angle; // angle of rotation of selection rectangle (starts at 0) int m_drag_angle; // angle of rotation of selection rectangle (starts at 0)
int m_drag_side; // 0 = no change, 1 = switch to opposite int m_drag_side; // 0 = no change, 1 = switch to opposite
int m_drag_vert; // 1 if item being dragged is a vertical part int m_drag_vert; // 1 if item being dragged is a vertical part
// parameters for dragging polyline sides and trace segments // parameters for dragging polyline sides and trace segments
// that can be modified while dragging // that can be modified while dragging
int m_drag_flag; // 1 if dragging something int m_drag_flag; // 1 if dragging something
int m_drag_shape; // shape int m_drag_shape; // shape
int m_last_drag_shape; // last shape drawn int m_last_drag_shape; // last shape drawn
int m_drag_x; // last cursor position for dragged shape int m_drag_x; // last cursor position for dragged shape
int m_drag_y; int m_drag_y;
int m_drag_xi; // start of rubberband drag line int m_drag_xi; // start of rubberband drag line
int m_drag_yi; int m_drag_yi;
int m_drag_xf; // end of rubberband drag line int m_drag_xf; // end of rubberband drag line
int m_drag_yf; int m_drag_yf;
int m_drag_layer_1; // line layer int m_drag_layer_1; // line layer
int m_drag_w1; // line width int m_drag_w1; // line width
int m_drag_style1; // line style int m_drag_style1; // line style
int m_inflection_mode; // inflection mode int m_inflection_mode; // inflection mode
int m_last_inflection_mode; // last mode drawn int m_last_inflection_mode; // last mode drawn
// extra parameters when dragging vertex between 2 line segments // extra parameters when dragging vertex between 2 line segments
int m_drag_style2; int m_drag_style2;
int m_drag_layer_2; int m_drag_layer_2;
int m_drag_w2; int m_drag_w2;
// parameters used to draw leading via if necessary // parameters used to draw leading via if necessary
int m_drag_layer_no_via; int m_drag_layer_no_via;
int m_drag_via_w; int m_drag_via_w;
int m_drag_via_holew; int m_drag_via_holew;
int m_drag_via_drawn; int m_drag_via_drawn;
// arrays of lines and ratlines being dragged // arrays of lines and ratlines being dragged
// these can be rotated and flipped while being dragged // these can be rotated and flipped while being dragged
int m_drag_layer; // layer int m_drag_layer; // layer
int m_drag_max_lines; // max size of array for line segments int m_drag_max_lines; // max size of array for line segments
int m_drag_num_lines; // number of line segments to drag int m_drag_num_lines; // number of line segments to drag
CPoint * m_drag_line_pt; // array of relative coords for line endpoints CPoint * m_drag_line_pt; // array of relative coords for line endpoints
int m_drag_max_ratlines; // max size of ratline array int m_drag_max_ratlines; // max size of ratline array
int m_drag_num_ratlines; // number of ratlines to drag int m_drag_num_ratlines; // number of ratlines to drag
CPoint * m_drag_ratline_start_pt; // absolute coords for ratline start points CPoint * m_drag_ratline_start_pt; // absolute coords for ratline start points
CPoint * m_drag_ratline_end_pt; // relative coords for ratline endpoints CPoint * m_drag_ratline_end_pt; // relative coords for ratline endpoints
int m_drag_ratline_width; int m_drag_ratline_width;
// cursor parameters // cursor parameters
int m_cross_hairs; // 0 = none, 1 = cross-hairs, 2 = diagonals int m_cross_hairs; // 0 = none, 1 = cross-hairs, 2 = diagonals
CPoint m_cross_left, m_cross_right, m_cross_top, m_cross_bottom; // end-points CPoint m_cross_left, m_cross_right, m_cross_top, m_cross_bottom; // end-points
CPoint m_cross_topleft, m_cross_topright, m_cross_botleft, m_cross_botright; CPoint m_cross_topleft, m_cross_topright, m_cross_botleft, m_cross_botright;
// grid // grid
int m_visual_grid_on; int m_visual_grid_on;
double m_visual_grid_spacing; // in world units double m_visual_grid_spacing; // in world units
public: public:
CDisplayList( int pcbu_per_wu ); CDisplayList( int pcbu_per_wu );
~CDisplayList(); ~CDisplayList();
void SetVisibleGrid( BOOL on, double grid ); void SetVisibleGrid( BOOL on, double grid );
void SetMapping( CRect *client_r, CRect *screen_r, int pane_org_x, int pane_bottom_h, double scale, int org_x, int org_y ); void SetMapping( CRect *client_r, CRect *screen_r, int pane_org_x, int pane_bottom_h, double scale, int org_x, int org_y );
void SetDCToWorldCoords( CDC * pDC, CDC * mDC, int pcbu_org_x, int pcbu_org_y ); void SetDCToWorldCoords( CDC * pDC, CDC * mDC, int pcbu_org_x, int pcbu_org_y );
void SetLayerRGB( int layer, int r, int g, int b ); void SetLayerRGB( int layer, int r, int g, int b );
void SetLayerVisible( int layer, BOOL vis ); void SetLayerVisible( int layer, BOOL vis );
void SetLayerDrawOrder( int layer, int order ) void SetLayerDrawOrder( int layer, int order )
{ m_layer_in_order[order] = layer; m_order_for_layer[layer] = order; }; { m_layer_in_order[order] = layer; m_order_for_layer[layer] = order; };
dl_element * Add( id id, void * ptr, int glayer, int gtype, int visible, dl_element * Add( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int w, int holew, int x, int y, int xf, int yf, int xo, int yo,
int radius=0, int orig_layer=LAY_SELECTION ); int radius=0, int orig_layer=LAY_SELECTION );
dl_element * AddSelector( id id, void * ptr, int glayer, int gtype, int visible, dl_element * AddSelector( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int radius=0 ); int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int radius=0 );
void RemoveAll(); void RemoveAll();
void RemoveAllFromLayer( int layer ); void RemoveAllFromLayer( int layer );
id Remove( dl_element * element ); id Remove( dl_element * element );
void Draw( CDC * pDC ); void Draw( CDC * pDC );
int HighLight( int gtype, int x, int y, int xf, int yf, int w, int orig_layer=LAY_SELECTION ); int HighLight( int gtype, int x, int y, int xf, int yf, int w, int orig_layer=LAY_SELECTION );
int CancelHighLight(); int CancelHighLight();
void * TestSelect( int x, int y, id * sel_id, int * layer, void * TestSelect( int x, int y, id * sel_id, int * layer,
id * exclude_id = NULL, void * exclude_ptr = NULL, id * include_id = NULL, id * exclude_id = NULL, void * exclude_ptr = NULL, id * include_id = NULL,
int n_include_ids=1 ); int n_include_ids=1 );
int StartDraggingArray( CDC * pDC, int x, int y, int vert, int layer, int crosshair = 1 ); int StartDraggingArray( CDC * pDC, int x, int y, int vert, int layer, int crosshair = 1 );
int StartDraggingRatLine( CDC * pDC, int x, int y, int xf, int yf, int layer, int StartDraggingRatLine( CDC * pDC, int x, int y, int xf, int yf, int layer,
int w, int crosshair = 1 ); int w, int crosshair = 1 );
int StartDraggingRectangle( CDC * pDC, int x, int y, int xi, int yi, int StartDraggingRectangle( CDC * pDC, int x, int y, int xi, int yi,
int xf, int yf, int vert, int layer ); int xf, int yf, int vert, int layer );
int StartDraggingLineVertex( CDC * pDC, int x, int y, int xi, int yi, int StartDraggingLineVertex( CDC * pDC, int x, int y, int xi, int yi,
int xf, int yf, int xf, int yf,
int layer1, int layer2, int w1, int w2, int layer1, int layer2, int w1, int w2,
int style1, int style2, int style1, int style2,
int layer_no_via, int via_w, int via_holew, int dir, int layer_no_via, int via_w, int via_holew, int dir,
int crosshair ); int crosshair );
int StartDraggingLine( CDC * pDC, int x, int y, int xi, int yi, int layer1, int w, int StartDraggingLine( CDC * pDC, int x, int y, int xi, int yi, int layer1, int w,
int layer_no_via, int via_w, int via_holew, int layer_no_via, int via_w, int via_holew,
int crosshair, int style, int inflection_mode ); int crosshair, int style, int inflection_mode );
int StartDraggingArc( CDC * pDC, int style, int x, int y, int xi, int yi, int StartDraggingArc( CDC * pDC, int style, int x, int y, int xi, int yi,
int layer, int w, int crosshair ); int layer, int w, int crosshair );
void SetDragArcStyle( int style ); void SetDragArcStyle( int style );
void Drag( CDC * pDC, int x, int y ); void Drag( CDC * pDC, int x, int y );
int StopDragging(); int StopDragging();
void ChangeRoutingLayer( CDC * pDC, int layer1, int layer2, int w ); void ChangeRoutingLayer( CDC * pDC, int layer1, int layer2, int w );
void IncrementDragAngle( CDC * pDC ); void IncrementDragAngle( CDC * pDC );
int MakeDragLineArray( int num_lines ); int MakeDragLineArray( int num_lines );
int MakeDragRatlineArray( int num_ratlines, int width ); int MakeDragRatlineArray( int num_ratlines, int width );
int AddDragLine( CPoint pi, CPoint pf ); int AddDragLine( CPoint pi, CPoint pf );
int AddDragRatline( CPoint pi, CPoint pf ); int AddDragRatline( CPoint pi, CPoint pf );
int GetDragAngle(); int GetDragAngle();
void FlipDragSide( CDC * pDC ); void FlipDragSide( CDC * pDC );
int GetDragSide(); int GetDragSide();
void SetUpCrosshairs( int type, int x, int y ); void SetUpCrosshairs( int type, int x, int y );
void SetInflectionMode( int mode ){ m_inflection_mode = mode; }; void SetInflectionMode( int mode ){ m_inflection_mode = mode; };
CPoint ScreenToPCB( CPoint point ); CPoint ScreenToPCB( CPoint point );
CPoint PCBToScreen( CPoint point ); CPoint PCBToScreen( CPoint point );
CPoint WindowToPCB( CPoint point ); CPoint WindowToPCB( CPoint point );
// set element parameters // set element parameters
void Set_gtype( dl_element * el, int gtype ); void Set_gtype( dl_element * el, int gtype );
void Set_visible( dl_element * el, int visible ); void Set_visible( dl_element * el, int visible );
void Set_sel_vert( dl_element * el, int sel_vert ); void Set_sel_vert( dl_element * el, int sel_vert );
void Set_w( dl_element * el, int w ); void Set_w( dl_element * el, int w );
void Set_holew( dl_element * el, int holew ); void Set_holew( dl_element * el, int holew );
void Set_x_org( dl_element * el, int x_org ); void Set_x_org( dl_element * el, int x_org );
void Set_y_org( dl_element * el, int y_org ); void Set_y_org( dl_element * el, int y_org );
void Set_x( dl_element * el, int x ); void Set_x( dl_element * el, int x );
void Set_y( dl_element * el, int y ); void Set_y( dl_element * el, int y );
void Set_xf( dl_element * el, int xf ); void Set_xf( dl_element * el, int xf );
void Set_yf( dl_element * el, int yf ); void Set_yf( dl_element * el, int yf );
void Set_id( dl_element * el, id * id ); void Set_id( dl_element * el, id * id );
void Set_layer( dl_element * el, int layer ); void Set_layer( dl_element * el, int layer );
void Set_radius( dl_element * el, int radius ); void Set_radius( dl_element * el, int radius );
void Move( dl_element * el, int dx, int dy ); void Move( dl_element * el, int dx, int dy );
// get element parameters // get element parameters
void * Get_ptr( dl_element * el ); void * Get_ptr( dl_element * el );
int Get_gtype( dl_element * el ); int Get_gtype( dl_element * el );
int Get_visible( dl_element * el ); int Get_visible( dl_element * el );
int Get_sel_vert( dl_element * el ); int Get_sel_vert( dl_element * el );
int Get_w( dl_element * el ); int Get_w( dl_element * el );
int Get_holew( dl_element * el ); int Get_holew( dl_element * el );
int Get_x_org( dl_element * el ); int Get_x_org( dl_element * el );
int Get_y_org( dl_element * el ); int Get_y_org( dl_element * el );
int Get_x( dl_element * el ); int Get_x( dl_element * el );
int Get_y( dl_element * el ); int Get_y( dl_element * el );
int Get_xf( dl_element * el ); int Get_xf( dl_element * el );
int Get_yf( dl_element * el ); int Get_yf( dl_element * el );
int Get_radius( dl_element * el ); int Get_radius( dl_element * el );
int Get_layer( dl_element * el ); int Get_layer( dl_element * el );
id Get_id( dl_element * el ); id Get_id( dl_element * el );
}; };
#endif // #ifndef FP_DISPLAY_LIST_H #endif // #ifndef FP_DISPLAY_LIST_H
// definition of ID structure used by FreePCB // definition of ID structure used by FreePCB
// //
#pragma once #pragma once
// struct id : this structure is used to identify PCB design elements // struct id : this structure is used to identify PCB design elements
// such as instances of parts or nets, and their subelements // such as instances of parts or nets, and their subelements
// Each element will have its own id. // Each element will have its own id.
// An id is attached to each item of the Display List so that it can // An id is attached to each item of the Display List so that it can
// be linked back to the PCB design element which drew it. // be linked back to the PCB design element which drew it.
// These are mainly used to identify items selected by clicking the mouse // These are mainly used to identify items selected by clicking the mouse
// //
// In general: // In general:
// id.type = type of PCB element (e.g. part, net, text) // id.type = type of PCB element (e.g. part, net, text)
// id.st = subelement type (e.g. part pad, net connection) // id.st = subelement type (e.g. part pad, net connection)
// id.i = subelement index (zero-based) // id.i = subelement index (zero-based)
// id.sst = subelement of subelement (e.g. net connection segment) // id.sst = subelement of subelement (e.g. net connection segment)
// id.ii = subsubelement index (zero-based) // id.ii = subsubelement index (zero-based)
// //
// For example, the id for segment 0 of connection 4 of net 12 would be // For example, the id for segment 0 of connection 4 of net 12 would be
// id = { ID_NET, 12, ID_CONNECT, 4, ID_SEG, 0 }; // id = { ID_NET, 12, ID_CONNECT, 4, ID_SEG, 0 };
// //
// //
class id { class id {
public: public:
// constructor // constructor
id( int qt=0, int qst=0, int qis=0, int qsst=0, int qiis=0 ) id( int qt=0, int qst=0, int qis=0, int qsst=0, int qiis=0 )
{ type=qt; st=qst; i=qis; sst=qsst; ii=qiis; } { type=qt; st=qst; i=qis; sst=qsst; ii=qiis; }
// operators // operators
friend int operator ==(id id1, id id2) friend int operator ==(id id1, id id2)
{ return (id1.type==id2.type { return (id1.type==id2.type
&& id1.st==id2.st && id1.st==id2.st
&& id1.sst==id2.sst && id1.sst==id2.sst
&& id1.i==id2.i && id1.i==id2.i
&& id1.ii==id2.ii ); && id1.ii==id2.ii );
} }
// member functions // member functions
void Clear() void Clear()
{ type=0; st=0; i=0; sst=0; ii=0; } { type=0; st=0; i=0; sst=0; ii=0; }
void Set( int qt, int qst=0, int qis=0, int qsst=0, int qiis=0 ) void Set( int qt, int qst=0, int qis=0, int qsst=0, int qiis=0 )
{ type=qt; st=qst; i=qis; sst=qsst; ii=qiis; } { type=qt; st=qst; i=qis; sst=qsst; ii=qiis; }
// member variables // member variables
unsigned int type; // type of element unsigned int type; // type of element
unsigned int st; // type of subelement unsigned int st; // type of subelement
unsigned int i; // index of subelement unsigned int i; // index of subelement
unsigned int sst; // type of subsubelement unsigned int sst; // type of subsubelement
unsigned int ii; // index of subsubelement unsigned int ii; // index of subsubelement
}; };
// these are constants used in ids // these are constants used in ids
// root types // root types
enum { enum {
ID_NONE = 0, // an undefined type or st (or an error) ID_NONE = 0, // an undefined type or st (or an error)
ID_BOARD, // board outline ID_BOARD, // board outline
ID_PART, // part ID_PART, // part
ID_NET, // net ID_NET, // net
ID_TEXT, // free-standing text ID_TEXT, // free-standing text
ID_DRC, // DRC error ID_DRC, // DRC error
ID_SM_CUTOUT, // cutout for solder mask ID_SM_CUTOUT, // cutout for solder mask
ID_MULTI // if multiple selections ID_MULTI // if multiple selections
}; };
// subtypes of ID_PART // subtypes of ID_PART
enum { enum {
ID_PAD = 1, // pad_stack in a part ID_PAD = 1, // pad_stack in a part
ID_SEL_PAD, // selection rectangle for pad_stack in a part ID_SEL_PAD, // selection rectangle for pad_stack in a part
ID_OUTLINE, // part outline ID_OUTLINE, // part outline
ID_REF_TXT, // text showing ref num for part ID_REF_TXT, // text showing ref num for part
ID_ORIG, // part origin ID_ORIG, // part origin
ID_SEL_RECT, // selection rectangle for part ID_SEL_RECT, // selection rectangle for part
ID_SEL_REF_TXT // selection rectangle for ref text ID_SEL_REF_TXT // selection rectangle for ref text
}; };
// subtypes of ID_TEXT // subtypes of ID_TEXT
enum { enum {
ID_SEL_TXT = 1, // selection rectangle ID_SEL_TXT = 1, // selection rectangle
ID_STROKE // stroke for text ID_STROKE // stroke for text
}; };
// subtypes of ID_NET // subtypes of ID_NET
enum { enum {
ID_ENTIRE_NET = 0, ID_ENTIRE_NET = 0,
ID_CONNECT, // connection ID_CONNECT, // connection
ID_AREA // copper area ID_AREA // copper area
}; };
// subtypes of ID_BOARD // subtypes of ID_BOARD
enum { enum {
ID_BOARD_OUTLINE = 1, ID_BOARD_OUTLINE = 1,
}; };
// subsubtypes of ID_NET.ID_CONNECT // subsubtypes of ID_NET.ID_CONNECT
enum { enum {
ID_ENTIRE_CONNECT = 0, ID_ENTIRE_CONNECT = 0,
ID_SEG, ID_SEG,
ID_SEL_SEG, ID_SEL_SEG,
ID_VERTEX, ID_VERTEX,
ID_SEL_VERTEX, ID_SEL_VERTEX,
ID_VIA ID_VIA
}; };
// subsubtypes of ID_NET.ID_AREA, ID_BOARD.ID_BOARD_OUTLINE, ID_SM_CUTOUT // subsubtypes of ID_NET.ID_AREA, ID_BOARD.ID_BOARD_OUTLINE, ID_SM_CUTOUT
enum { enum {
ID_SIDE = 1, ID_SIDE = 1,
ID_SEL_SIDE, ID_SEL_SIDE,
ID_SEL_CORNER, ID_SEL_CORNER,
ID_HATCH, ID_HATCH,
ID_PIN_X, // only used by ID_AREA ID_PIN_X, // only used by ID_AREA
ID_STUB_X // only used by ID_AREA ID_STUB_X // only used by ID_AREA
}; };
// subtypes of ID_DRC // subtypes of ID_DRC
// for subsubtypes, use types in DesignRules.h // for subsubtypes, use types in DesignRules.h
enum { enum {
ID_DRE = 1, ID_DRE = 1,
ID_SEL_DRE ID_SEL_DRE
}; };
// math for graphics utility routines, from FreePCB // math for graphics utility routines, from FreePCB
using namespace std; using namespace std;
#include <vector> #include <vector>
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
#include <limits.h> #include <limits.h>
#include "defs-macros.h" #include "defs-macros.h"
#include "PolyLine2Kicad.h" #include "PolyLine2Kicad.h"
#include "freepcb_ids.h" #include "freepcb_ids.h"
#include "PolyLine.h" #include "PolyLine.h"
// function to find inflection-pont to create a "dogleg" of two straight-line segments // function to find inflection-pont to create a "dogleg" of two straight-line segments
// where one segment is vertical or horizontal and the other is at 45 degrees or 90 degrees // where one segment is vertical or horizontal and the other is at 45 degrees or 90 degrees
// enter with: // enter with:
// pi = start point // pi = start point
// pf = end point // pf = end point
// mode = IM_90_45 or IM_45_90 or IM_90 // mode = IM_90_45 or IM_45_90 or IM_90
// //
CPoint GetInflectionPoint( CPoint pi, CPoint pf, int mode ) CPoint GetInflectionPoint( CPoint pi, CPoint pf, int mode )
{ {
CPoint p = pi; CPoint p = pi;
if( mode == IM_NONE ) if( mode == IM_NONE )
return p; return p;
int dx = pf.x - pi.x; int dx = pf.x - pi.x;
int dy = pf.y - pi.y; int dy = pf.y - pi.y;
if( dx == 0 || dy == 0 || abs(dx) == abs(dy) ) if( dx == 0 || dy == 0 || abs(dx) == abs(dy) )
{ {
// only one segment needed // only one segment needed
} }
else else
{ {
if( abs(dy) > abs(dx) ) if( abs(dy) > abs(dx) )
{ {
// vertical > horizontal // vertical > horizontal
if( mode == IM_90 ) if( mode == IM_90 )
{ {
p.x = pi.x; p.x = pi.x;
p.y = pf.y; p.y = pf.y;
} }
else if( mode == IM_45_90 || mode == IM_90_45 ) else if( mode == IM_45_90 || mode == IM_90_45 )
{ {
int vert; // length of vertical line needed int vert; // length of vertical line needed
if( dy > 0 ) if( dy > 0 )
vert = dy - abs(dx); // positive vert = dy - abs(dx); // positive
else else
vert = dy + abs(dx); // negative vert = dy + abs(dx); // negative
if( mode == IM_90_45 ) if( mode == IM_90_45 )
p.y = pi.y + vert; p.y = pi.y + vert;
else if( mode == IM_45_90 ) else if( mode == IM_45_90 )
{ {
p.y = pf.y - vert; p.y = pf.y - vert;
p.x = pf.x; p.x = pf.x;
} }
} }
else else
ASSERT(0); ASSERT(0);
} }
else else
{ {
// horizontal > vertical // horizontal > vertical
if( mode == IM_90 ) if( mode == IM_90 )
{ {
p.x = pf.x; p.x = pf.x;
p.y = pi.y; p.y = pi.y;
} }
else if( mode == IM_45_90 || mode == IM_90_45 ) else if( mode == IM_45_90 || mode == IM_90_45 )
{ {
int hor; // length of horizontal line needed int hor; // length of horizontal line needed
if( dx > 0 ) if( dx > 0 )
hor = dx - abs(dy); // positive hor = dx - abs(dy); // positive
else else
hor = dx + abs(dy); // negative hor = dx + abs(dy); // negative
if( mode == IM_90_45 ) if( mode == IM_90_45 )
p.x = pi.x + hor; p.x = pi.x + hor;
else if( mode == IM_45_90 ) else if( mode == IM_45_90 )
{ {
p.x = pf.x - hor; p.x = pf.x - hor;
p.y = pf.y; p.y = pf.y;
} }
} }
else else
ASSERT(0); ASSERT(0);
} }
} }
return p; return p;
} }
// //
// function to rotate a point clockwise about another point // function to rotate a point clockwise about another point
// currently, angle must be 0, 90, 180 or 270 // currently, angle must be 0, 90, 180 or 270
// //
void RotatePoint( CPoint *p, int angle, CPoint org ) void RotatePoint( CPoint *p, int angle, CPoint org )
{ {
if( angle == 90 ) if( angle == 90 )
{ {
int tempy = org.y + (org.x - p->x); int tempy = org.y + (org.x - p->x);
p->x = org.x + (p->y - org.y); p->x = org.x + (p->y - org.y);
p->y = tempy; p->y = tempy;
} }
else if( angle > 90 ) else if( angle > 90 )
{ {
for( int i=0; i<(angle/90); i++ ) for( int i=0; i<(angle/90); i++ )
RotatePoint( p, 90, org ); RotatePoint( p, 90, org );
} }
} }
// function to rotate a rectangle clockwise about a point // function to rotate a rectangle clockwise about a point
// angle must be 0, 90, 180 or 270 // angle must be 0, 90, 180 or 270
// on exit, r->top > r.bottom, r.right > r.left // on exit, r->top > r.bottom, r.right > r.left
// //
void RotateRect( CRect *r, int angle, CPoint org ) void RotateRect( CRect *r, int angle, CPoint org )
{ {
CRect tr; CRect tr;
if( angle == 90 ) if( angle == 90 )
{ {
tr.left = org.x + (r->bottom - org.y); tr.left = org.x + (r->bottom - org.y);
tr.right = org.x + (r->top - org.y); tr.right = org.x + (r->top - org.y);
tr.top = org.y + (org.x - r->right); tr.top = org.y + (org.x - r->right);
tr.bottom = org.y + (org.x - r->left); tr.bottom = org.y + (org.x - r->left);
if( tr.left > tr.right ) if( tr.left > tr.right )
{ {
int temp = tr.right; int temp = tr.right;
tr.left = tr.right; tr.left = tr.right;
tr.left = temp; tr.left = temp;
} }
if( tr.left > tr.right ) if( tr.left > tr.right )
{ {
int temp = tr.right; int temp = tr.right;
tr.left = tr.right; tr.left = tr.right;
tr.left = temp; tr.left = temp;
} }
if( tr.bottom > tr.top ) if( tr.bottom > tr.top )
{ {
int temp = tr.bottom; int temp = tr.bottom;
tr.bottom = tr.top; tr.bottom = tr.top;
tr.top = temp; tr.top = temp;
} }
} }
else if( angle > 90 ) else if( angle > 90 )
{ {
tr = *r; tr = *r;
for( int i=0; i<(angle/90); i++ ) for( int i=0; i<(angle/90); i++ )
RotateRect( &tr, 90, org ); RotateRect( &tr, 90, org );
} }
*r = tr; *r = tr;
} }
// test for hit on line segment // test for hit on line segment
// i.e. cursor within a given distance from segment // i.e. cursor within a given distance from segment
// enter with: x,y = cursor coords // enter with: x,y = cursor coords
// (xi,yi) and (xf,yf) are the end-points of the line segment // (xi,yi) and (xf,yf) are the end-points of the line segment
// dist = maximum distance for hit // dist = maximum distance for hit
// //
int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist ) int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
{ {
double dd; double dd;
// test for vertical or horizontal segment // test for vertical or horizontal segment
if( xf==xi ) if( xf==xi )
{ {
// vertical segment // vertical segment
dd = fabs( (double)(x-xi) ); dd = fabs( (double)(x-xi) );
if( dd<dist && ( (yf>yi && y<yf && y>yi) || (yf<yi && y>yf && y<yi) ) ) if( dd<dist && ( (yf>yi && y<yf && y>yi) || (yf<yi && y>yf && y<yi) ) )
return 1; return 1;
} }
else if( yf==yi ) else if( yf==yi )
{ {
// horizontal segment // horizontal segment
dd = fabs( (double)(y-yi) ); dd = fabs( (double)(y-yi) );
if( dd<dist && ( (xf>xi && x<xf && x>xi) || (xf<xi && x>xf && x<xi) ) ) if( dd<dist && ( (xf>xi && x<xf && x>xi) || (xf<xi && x>xf && x<xi) ) )
return 1; return 1;
} }
else else
{ {
// oblique segment // oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx // find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double b = (double)(yf-yi)/(xf-xi); double b = (double)(yf-yi)/(xf-xi);
double a = (double)yi-b*xi; double a = (double)yi-b*xi;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b) // find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double d = -1.0/b; double d = -1.0/b;
double c = (double)y-d*x; double c = (double)y-d*x;
// find nearest point to (x,y) on line segment (xi,yi) to (xf,yf) // find nearest point to (x,y) on line segment (xi,yi) to (xf,yf)
double xp = (a-c)/(d-b); double xp = (a-c)/(d-b);
double yp = a + b*xp; double yp = a + b*xp;
// find distance // find distance
dd = sqrt((x-xp)*(x-xp)+(y-yp)*(y-yp)); dd = sqrt((x-xp)*(x-xp)+(y-yp)*(y-yp));
if( fabs(b)>0.7 ) if( fabs(b)>0.7 )
{ {
// line segment more vertical than horizontal // line segment more vertical than horizontal
if( dd<dist && ( (yf>yi && yp<yf && yp>yi) || (yf<yi && yp>yf && yp<yi) ) ) if( dd<dist && ( (yf>yi && yp<yf && yp>yi) || (yf<yi && yp>yf && yp<yi) ) )
return 1; return 1;
} }
else else
{ {
// line segment more horizontal than vertical // line segment more horizontal than vertical
if( dd<dist && ( (xf>xi && xp<xf && xp>xi) || (xf<xi && xp>xf && xp<xi) ) ) if( dd<dist && ( (xf>xi && xp<xf && xp>xi) || (xf<xi && xp>xf && xp<xi) ) )
return 1; return 1;
} }
} }
return 0; // no hit return 0; // no hit
} }
// find intersection between y = a + bx and y = c + dx; // find intersection between y = a + bx and y = c + dx;
// //
int FindLineIntersection( double a, double b, double c, double d, double * x, double * y ) int FindLineIntersection( double a, double b, double c, double d, double * x, double * y )
{ {
*x = (c-a)/(b-d); *x = (c-a)/(b-d);
*y = a + b*(*x); *y = a + b*(*x);
return 0; return 0;
} }
// set EllipseKH struct to describe the ellipse for an arc // set EllipseKH struct to describe the ellipse for an arc
// //
int MakeEllipseFromArc( int xi, int yi, int xf, int yf, int style, EllipseKH * el ) int MakeEllipseFromArc( int xi, int yi, int xf, int yf, int style, EllipseKH * el )
{ {
// arc (quadrant of ellipse) // arc (quadrant of ellipse)
// convert to clockwise arc // convert to clockwise arc
int xxi, xxf, yyi, yyf; int xxi, xxf, yyi, yyf;
if( style == CPolyLine::ARC_CCW ) if( style == CPolyLine::ARC_CCW )
{ {
xxi = xf; xxi = xf;
xxf = xi; xxf = xi;
yyi = yf; yyi = yf;
yyf = yi; yyf = yi;
} }
else else
{ {
xxi = xi; xxi = xi;
xxf = xf; xxf = xf;
yyi = yi; yyi = yi;
yyf = yf; yyf = yf;
} }
// find center and radii of ellipse // find center and radii of ellipse
double xo, yo; double xo, yo;
if( xxf > xxi && yyf > yyi ) if( xxf > xxi && yyf > yyi )
{ {
xo = xxf; xo = xxf;
yo = yyi; yo = yyi;
el->theta1 = M_PI; el->theta1 = M_PI;
el->theta2 = M_PI/2.0; el->theta2 = M_PI/2.0;
} }
else if( xxf < xxi && yyf > yyi ) else if( xxf < xxi && yyf > yyi )
{ {
xo = xxi; xo = xxi;
yo = yyf; yo = yyf;
el->theta1 = -M_PI/2.0; el->theta1 = -M_PI/2.0;
el->theta2 = -M_PI; el->theta2 = -M_PI;
} }
else if( xxf < xxi && yyf < yyi ) else if( xxf < xxi && yyf < yyi )
{ {
xo = xxf; xo = xxf;
yo = yyi; yo = yyi;
el->theta1 = 0.0; el->theta1 = 0.0;
el->theta2 = -M_PI/2.0; el->theta2 = -M_PI/2.0;
} }
else if( xxf > xxi && yyf < yyi ) else if( xxf > xxi && yyf < yyi )
{ {
xo = xxi; xo = xxi;
yo = yyf; yo = yyf;
el->theta1 = M_PI/2.0; el->theta1 = M_PI/2.0;
el->theta2 = 0.0; el->theta2 = 0.0;
} }
el->Center.X = xo; el->Center.X = xo;
el->Center.Y = yo; el->Center.Y = yo;
el->xrad = abs(xf-xi); el->xrad = abs(xf-xi);
el->yrad = abs(yf-yi); el->yrad = abs(yf-yi);
#if 0 #if 0
el->Phi = 0.0; el->Phi = 0.0;
el->MaxRad = el->xrad; el->MaxRad = el->xrad;
el->MinRad = el->yrad; el->MinRad = el->yrad;
if( el->MaxRad < el->MinRad ) if( el->MaxRad < el->MinRad )
{ {
el->MaxRad = el->yrad; el->MaxRad = el->yrad;
el->MinRad = el->xrad; el->MinRad = el->xrad;
el->Phi = M_PI/2.0; el->Phi = M_PI/2.0;
} }
#endif #endif
return 0; return 0;
} }
// find intersections between line segment (xi,yi) to (xf,yf) // find intersections between line segment (xi,yi) to (xf,yf)
// and line segment (xi2,yi2) to (xf2,yf2) // and line segment (xi2,yi2) to (xf2,yf2)
// the line segments may be arcs (i.e. quadrant of an ellipse) or straight // the line segments may be arcs (i.e. quadrant of an ellipse) or straight
// returns number of intersections found (max of 2) // returns number of intersections found (max of 2)
// returns coords of intersections in arrays x[2], y[2] // returns coords of intersections in arrays x[2], y[2]
// //
int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style, int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
int xi2, int yi2, int xf2, int yf2, int style2, int xi2, int yi2, int xf2, int yf2, int style2,
double x[], double y[] ) double x[], double y[] )
{ {
double xr[12], yr[12]; double xr[12], yr[12];
int iret = 0; 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 0;
if( style != CPolyLine::STRAIGHT && style2 != CPolyLine::STRAIGHT ) if( style != CPolyLine::STRAIGHT && style2 != CPolyLine::STRAIGHT )
{ {
// two identical arcs intersect // two identical arcs intersect
if( style == style2 && xi == xi2 && yi == yi2 && xf == xf2 && yf == yf2 ) if( style == style2 && xi == xi2 && yi == yi2 && xf == xf2 && yf == yf2 )
{ {
if( x && y ) if( x && y )
{ {
x[0] = xi; x[0] = xi;
y[0] = yi; y[0] = yi;
} }
return 1; return 1;
} }
else if( style != style2 && xi == xf2 && yi == yf2 && xf == xi2 && yf == yi2 ) else if( style != style2 && xi == xf2 && yi == yf2 && xf == xi2 && yf == yi2 )
{ {
if( x && y ) if( x && y )
{ {
x[0] = xi; x[0] = xi;
y[0] = yi; y[0] = yi;
} }
return 1; return 1;
} }
} }
if( style == CPolyLine::STRAIGHT && style2 == CPolyLine::STRAIGHT ) if( style == CPolyLine::STRAIGHT && style2 == CPolyLine::STRAIGHT )
{ {
// both straight-line segments // both straight-line segments
int x, y; int x, y;
bool bYes = TestForIntersectionOfStraightLineSegments( xi, yi, xf, yf, xi2, yi2, xf2, yf2, &x, &y ); bool bYes = TestForIntersectionOfStraightLineSegments( xi, yi, xf, yf, xi2, yi2, xf2, yf2, &x, &y );
if( !bYes ) if( !bYes )
return 0; return 0;
xr[0] = x; xr[0] = x;
yr[0] = y; yr[0] = y;
iret = 1; iret = 1;
} }
else if( style == CPolyLine::STRAIGHT ) else if( style == CPolyLine::STRAIGHT )
{ {
// first segment is straight, second segment is an arc // first segment is straight, second segment is an arc
int ret; int ret;
double x1r, y1r, x2r, y2r; double x1r, y1r, x2r, y2r;
if( xf == xi ) if( xf == xi )
{ {
// vertical first segment // vertical first segment
double a = xi; double a = xi;
double b = DBL_MAX/2.0; double b = DBL_MAX/2.0;
ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2, ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2,
&x1r, &y1r, &x2r, &y2r ); &x1r, &y1r, &x2r, &y2r );
} }
else else
{ {
double b = (double)(yf-yi)/(double)(xf-xi); double b = (double)(yf-yi)/(double)(xf-xi);
double a = yf - b*xf; double a = yf - b*xf;
ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2, ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2,
&x1r, &y1r, &x2r, &y2r ); &x1r, &y1r, &x2r, &y2r );
} }
if( ret == 0 ) if( ret == 0 )
return 0; return 0;
if( InRange( x1r, xi, xf ) && InRange( y1r, yi, yf ) ) if( InRange( x1r, xi, xf ) && InRange( y1r, yi, yf ) )
{ {
xr[iret] = x1r; xr[iret] = x1r;
yr[iret] = y1r; yr[iret] = y1r;
iret++; iret++;
} }
if( ret == 2 ) if( ret == 2 )
{ {
if( InRange( x2r, xi, xf ) && InRange( y2r, yi, yf ) ) if( InRange( x2r, xi, xf ) && InRange( y2r, yi, yf ) )
{ {
xr[iret] = x2r; xr[iret] = x2r;
yr[iret] = y2r; yr[iret] = y2r;
iret++; iret++;
} }
} }
} }
else if( style2 == CPolyLine::STRAIGHT ) else if( style2 == CPolyLine::STRAIGHT )
{ {
// first segment is an arc, second segment is straight // first segment is an arc, second segment is straight
int ret; int ret;
double x1r, y1r, x2r, y2r; double x1r, y1r, x2r, y2r;
if( xf2 == xi2 ) if( xf2 == xi2 )
{ {
// vertical second segment // vertical second segment
double a = xi2; double a = xi2;
double b = DBL_MAX/2.0; double b = DBL_MAX/2.0;
ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style, ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style,
&x1r, &y1r, &x2r, &y2r ); &x1r, &y1r, &x2r, &y2r );
} }
else else
{ {
double b = (double)(yf2-yi2)/(double)(xf2-xi2); double b = (double)(yf2-yi2)/(double)(xf2-xi2);
double a = yf2 - b*xf2; double a = yf2 - b*xf2;
ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style, ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style,
&x1r, &y1r, &x2r, &y2r ); &x1r, &y1r, &x2r, &y2r );
} }
if( ret == 0 ) if( ret == 0 )
return 0; return 0;
if( InRange( x1r, xi2, xf2 ) && InRange( y1r, yi2, yf2 ) ) if( InRange( x1r, xi2, xf2 ) && InRange( y1r, yi2, yf2 ) )
{ {
xr[iret] = x1r; xr[iret] = x1r;
yr[iret] = y1r; yr[iret] = y1r;
iret++; iret++;
} }
if( ret == 2 ) if( ret == 2 )
{ {
if( InRange( x2r, xi2, xf2 ) && InRange( y2r, yi2, yf2 ) ) if( InRange( x2r, xi2, xf2 ) && InRange( y2r, yi2, yf2 ) )
{ {
xr[iret] = x2r; xr[iret] = x2r;
yr[iret] = y2r; yr[iret] = y2r;
iret++; iret++;
} }
} }
} }
else else
{ {
// both segments are arcs // both segments are arcs
EllipseKH el1; EllipseKH el1;
EllipseKH el2; EllipseKH el2;
MakeEllipseFromArc( xi, yi, xf, yf, style, &el1 ); MakeEllipseFromArc( xi, yi, xf, yf, style, &el1 );
MakeEllipseFromArc( xi2, yi2, xf2, yf2, style2, &el2 ); MakeEllipseFromArc( xi2, yi2, xf2, yf2, style2, &el2 );
int n; int n;
if( el1.xrad+el1.yrad > el2.xrad+el2.yrad ) if( el1.xrad+el1.yrad > el2.xrad+el2.yrad )
n = GetArcIntersections( &el1, &el2 ); n = GetArcIntersections( &el1, &el2 );
else else
n = GetArcIntersections( &el2, &el1 ); n = GetArcIntersections( &el2, &el1 );
iret = n; iret = n;
} }
if( x && y ) if( x && y )
{ {
for( int i=0; i<iret; i++ ) for( int i=0; i<iret; i++ )
{ {
x[i] = xr[i]; x[i] = xr[i];
y[i] = yr[i]; y[i] = yr[i];
} }
} }
return iret; return iret;
} }
// find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf) // 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 // if b > DBL_MAX/10, assume vertical line at x = a
// the line segment may be an arc (i.e. quadrant of an ellipse) // the line segment may be an arc (i.e. quadrant of an ellipse)
// return 0 if no intersection // return 0 if no intersection
// returns 1 or 2 if intersections found // returns 1 or 2 if intersections found
// sets 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
// //
int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style, 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 )
{ {
double xx, yy; double xx, yy;
bool bVert = false; bool bVert = false;
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
if( style == CPolyLine::STRAIGHT || yf == yi ) if( style == CPolyLine::STRAIGHT || yf == yi )
{ {
// horizontal or oblique straight segment // horizontal or oblique straight segment
// put into form y = c + dx; // put into form y = c + dx;
double d = (double)(yf-yi)/(double)(xf-xi); double d = (double)(yf-yi)/(double)(xf-xi);
double c = yf - d*xf; double c = yf - d*xf;
if( bVert ) if( bVert )
{ {
// if vertical line, easy // if vertical line, easy
if( InRange( a, xi, xf ) ) if( InRange( a, xi, xf ) )
{ {
*x1 = a; *x1 = a;
*y1 = c + d*a; *y1 = c + d*a;
return 1; return 1;
} }
else else
{ {
if( dist ) if( dist )
*dist = min( abs(a-xi), abs(a-xf) ); *dist = min( abs(a-xi), abs(a-xf) );
return 0; return 0;
} }
} }
if( fabs(b-d) < 1E-12 ) if( fabs(b-d) < 1E-12 )
{ {
// parallel lines // parallel lines
if( dist ) if( dist )
{ {
*dist = GetPointToLineDistance( a, b, xi, xf ); *dist = GetPointToLineDistance( a, b, xi, xf );
} }
return 0; // lines parallel return 0; // lines parallel
} }
// calculate intersection // calculate intersection
xx = (c-a)/(b-d); xx = (c-a)/(b-d);
yy = a + b*(xx); yy = a + b*(xx);
// see if intersection is within the line segment // see if intersection is within the line segment
if( yf == yi ) if( yf == yi )
{ {
// horizontal line // horizontal line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf) ) if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf) )
return 0; return 0;
} }
else else
{ {
// oblique line // oblique line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf) if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf)
|| (yy>yi && yy>yf) || (yy<yi && yy<yf) ) || (yy>yi && yy>yf) || (yy<yi && yy<yf) )
return 0; return 0;
} }
} }
else if( style == CPolyLine::ARC_CW || style == CPolyLine::ARC_CCW ) else if( style == CPolyLine::ARC_CW || style == CPolyLine::ARC_CCW )
{ {
// arc (quadrant of ellipse) // arc (quadrant of ellipse)
// convert to clockwise arc // convert to clockwise arc
int xxi, xxf, yyi, yyf; int xxi, xxf, yyi, yyf;
if( style == CPolyLine::ARC_CCW ) if( style == CPolyLine::ARC_CCW )
{ {
xxi = xf; xxi = xf;
xxf = xi; xxf = xi;
yyi = yf; yyi = yf;
yyf = yi; yyf = yi;
} }
else else
{ {
xxi = xi; xxi = xi;
xxf = xf; xxf = xf;
yyi = yi; yyi = yi;
yyf = yf; yyf = yf;
} }
// find center and radii of ellipse // find center and radii of ellipse
double xo, yo, rx, ry; double xo, yo, rx, ry;
if( xxf > xxi && yyf > yyi ) if( xxf > xxi && yyf > yyi )
{ {
xo = xxf; xo = xxf;
yo = yyi; yo = yyi;
} }
else if( xxf < xxi && yyf > yyi ) else if( xxf < xxi && yyf > yyi )
{ {
xo = xxi; xo = xxi;
yo = yyf; yo = yyf;
} }
else if( xxf < xxi && yyf < yyi ) else if( xxf < xxi && yyf < yyi )
{ {
xo = xxf; xo = xxf;
yo = yyi; yo = yyi;
} }
else if( xxf > xxi && yyf < yyi ) else if( xxf > xxi && yyf < yyi )
{ {
xo = xxi; xo = xxi;
yo = yyf; yo = yyf;
} }
rx = fabs( (double)(xxi-xxf) ); rx = fabs( (double)(xxi-xxf) );
ry = fabs( (double)(yyi-yyf) ); ry = fabs( (double)(yyi-yyf) );
bool test; bool test;
double xx1, xx2, yy1, yy2, aa; double xx1, xx2, yy1, yy2, aa;
if( bVert ) if( bVert )
{ {
// shift vertical line to coordinate system of ellipse // shift vertical line to coordinate system of ellipse
aa = a - xo; aa = a - xo;
test = FindVerticalLineEllipseIntersections( rx, ry, aa, &yy1, &yy2 ); test = FindVerticalLineEllipseIntersections( rx, ry, aa, &yy1, &yy2 );
if( !test ) if( !test )
return 0; return 0;
// shift back to PCB coordinates // shift back to PCB coordinates
yy1 += yo; yy1 += yo;
yy2 += yo; yy2 += yo;
xx1 = a; xx1 = a;
xx2 = a; xx2 = a;
} }
else else
{ {
// shift line to coordinate system of ellipse // shift line to coordinate system of ellipse
aa = a + b*xo - yo; aa = a + b*xo - yo;
test = FindLineEllipseIntersections( rx, ry, aa, b, &xx1, &xx2 ); test = FindLineEllipseIntersections( rx, ry, aa, b, &xx1, &xx2 );
if( !test ) if( !test )
return 0; return 0;
// shift back to PCB coordinates // shift back to PCB coordinates
yy1 = aa + b*xx1; yy1 = aa + b*xx1;
xx1 += xo; xx1 += xo;
yy1 += yo; yy1 += yo;
yy2 = aa + b*xx2; yy2 = aa + b*xx2;
xx2 += xo; xx2 += xo;
yy2 += yo; yy2 += yo;
} }
int npts = 0; int npts = 0;
if( (xxf>xxi && xx1<xxf && xx1>xxi) || (xxf<xxi && xx1<xxi && xx1>xxf) ) 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) ) if( (yyf>yyi && yy1<yyf && yy1>yyi) || (yyf<yyi && yy1<yyi && yy1>yyf) )
{ {
*x1 = xx1; *x1 = xx1;
*y1 = yy1; *y1 = yy1;
npts = 1; npts = 1;
} }
} }
if( (xxf>xxi && xx2<xxf && xx2>xxi) || (xxf<xxi && xx2<xxi && xx2>xxf) ) 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( (yyf>yyi && yy2<yyf && yy2>yyi) || (yyf<yyi && yy2<yyi && yy2>yyf) )
{ {
if( npts == 0 ) if( npts == 0 )
{ {
*x1 = xx2; *x1 = xx2;
*y1 = yy2; *y1 = yy2;
npts = 1; npts = 1;
} }
else else
{ {
*x2 = xx2; *x2 = xx2;
*y2 = yy2; *y2 = yy2;
npts = 2; npts = 2;
} }
} }
} }
return npts; return npts;
} }
else else
ASSERT(0); ASSERT(0);
} }
else else
{ {
// vertical line segment // vertical line segment
if( bVert ) if( bVert )
return 0; return 0;
xx = xi; xx = xi;
yy = a + b*xx; yy = a + b*xx;
if( (yy>=yi && yy>yf) || (yy<=yi && yy<yf) ) if( (yy>=yi && yy>yf) || (yy<=yi && yy<yf) )
return 0; return 0;
} }
*x1 = xx; *x1 = xx;
*y1 = yy; *y1 = yy;
return 1; return 1;
} }
// Test for intersection of line segments // Test for intersection of line segments
// If lines are parallel, returns false // If lines are parallel, returns false
// If true, returns intersection coords in x, y // If true, returns intersection coords in x, y
// if false, returns min. distance in dist (may be 0.0 if parallel) // if false, returns min. distance in dist (may be 0.0 if parallel)
// and coords on nearest point in one of the segments in (x,y) // and coords on nearest point in one of the segments in (x,y)
// //
bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f, bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
int x2i, int y2i, int x2f, int y2f, int x2i, int y2i, int x2f, int y2f,
int * x, int * y, double * d ) int * x, int * y, double * d )
{ {
double a, b, dist; double a, b, dist;
// first, test for intersection // first, test for intersection
if( x1i == x1f && x2i == x2f ) if( x1i == x1f && x2i == x2f )
{ {
// both segments are vertical, can't intersect // both segments are vertical, can't intersect
} }
else if( y1i == y1f && y2i == y2f ) else if( y1i == y1f && y2i == y2f )
{ {
// both segments are horizontal, can't intersect // both segments are horizontal, can't intersect
} }
else if( x1i == x1f && y2i == y2f ) else if( x1i == x1f && y2i == y2f )
{ {
// first seg. vertical, second horizontal, see if they cross // first seg. vertical, second horizontal, see if they cross
if( InRange( x1i, x2i, x2f ) if( InRange( x1i, x2i, x2f )
&& InRange( y2i, y1i, y1f ) ) && InRange( y2i, y1i, y1f ) )
{ {
if( x ) if( x )
*x = x1i; *x = x1i;
if( y ) if( y )
*y = y2i; *y = y2i;
if( d ) if( d )
*d = 0.0; *d = 0.0;
return true; return true;
} }
} }
else if( y1i == y1f && x2i == x2f ) else if( y1i == y1f && x2i == x2f )
{ {
// first seg. horizontal, second vertical, see if they cross // first seg. horizontal, second vertical, see if they cross
if( InRange( y1i, y2i, y2f ) if( InRange( y1i, y2i, y2f )
&& InRange( x2i, x1i, x1f ) ) && InRange( x2i, x1i, x1f ) )
{ {
if( x ) if( x )
*x = x2i; *x = x2i;
if( y ) if( y )
*y = y1i; *y = y1i;
if( d ) if( d )
*d = 0.0; *d = 0.0;
return true; return true;
} }
} }
else if( x1i == x1f ) else if( x1i == x1f )
{ {
// first segment vertical, second oblique // first segment vertical, second oblique
// get a and b for second line segment, so that y = a + bx; // get a and b for second line segment, so that y = a + bx;
b = (double)(y2f-y2i)/(x2f-x2i); b = (double)(y2f-y2i)/(x2f-x2i);
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, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
{ {
if( InRange( y1, y1i, y1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) ) if( InRange( y1, y1i, y1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) )
{ {
if( x ) if( x )
*x = x1; *x = x1;
if( y ) if( y )
*y = y1; *y = y1;
if( d ) if( d )
*d = 0.0; *d = 0.0;
return true; return true;
} }
} }
} }
else if( y1i == y1f ) else if( y1i == y1f )
{ {
// first segment horizontal, second oblique // first segment horizontal, second oblique
// get a and b for second line segment, so that y = a + bx; // get a and b for second line segment, so that y = a + bx;
b = (double)(y2f-y2i)/(x2f-x2i); b = (double)(y2f-y2i)/(x2f-x2i);
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, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
{ {
if( InRange( x1, x1i, x1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) ) if( InRange( x1, x1i, x1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) )
{ {
if( x ) if( x )
*x = x1; *x = x1;
if( y ) if( y )
*y = y1; *y = y1;
if( d ) if( d )
*d = 0.0; *d = 0.0;
return true; return true;
} }
} }
} }
else if( x2i == x2f ) else if( x2i == x2f )
{ {
// second segment vertical, first oblique // second segment vertical, first oblique
// get a and b for first line segment, so that y = a + bx; // get a and b for first line segment, so that y = a + bx;
b = (double)(y1f-y1i)/(x1f-x1i); b = (double)(y1f-y1i)/(x1f-x1i);
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, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
{ {
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) && InRange( y1, y2i, y2f ) ) if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) && InRange( y1, y2i, y2f ) )
{ {
if( x ) if( x )
*x = x1; *x = x1;
if( y ) if( y )
*y = y1; *y = y1;
if( d ) if( d )
*d = 0.0; *d = 0.0;
return true; return true;
} }
} }
} }
else if( y2i == y2f ) else if( y2i == y2f )
{ {
// second segment horizontal, first oblique // second segment horizontal, first oblique
// get a and b for second line segment, so that y = a + bx; // get a and b for second line segment, so that y = a + bx;
b = (double)(y1f-y1i)/(x1f-x1i); b = (double)(y1f-y1i)/(x1f-x1i);
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, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
if( test ) if( test )
{ {
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) ) if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) )
{ {
if( x ) if( x )
*x = x1; *x = x1;
if( y ) if( y )
*y = y1; *y = y1;
if( d ) if( d )
*d = 0.0; *d = 0.0;
return true; return true;
} }
} }
} }
else else
{ {
// both segments oblique // both segments oblique
if( (long)(y1f-y1i)*(x2f-x2i) != (long)(y2f-y2i)*(x1f-x1i) ) if( (long)(y1f-y1i)*(x2f-x2i) != (long)(y2f-y2i)*(x1f-x1i) )
{ {
// not parallel, get a and b for first line segment, so that y = a + bx; // not parallel, get a and b for first line segment, so that y = a + bx;
b = (double)(y1f-y1i)/(x1f-x1i); b = (double)(y1f-y1i)/(x1f-x1i);
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, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 ); &x1, &y1, &x2, &y2 );
// both segments oblique // both segments oblique
if( test ) if( test )
{ {
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) ) if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) )
{ {
if( x ) if( x )
*x = x1; *x = x1;
if( y ) if( y )
*y = y1; *y = y1;
if( d ) if( d )
*d = 0.0; *d = 0.0;
return true; return true;
} }
} }
} }
} }
// don't intersect, get shortest distance between each endpoint and the other line segment // don't intersect, get shortest distance between each endpoint and the other line segment
dist = GetPointToLineSegmentDistance( x1i, y1i, x2i, y2i, x2f, y2f ); dist = GetPointToLineSegmentDistance( x1i, y1i, x2i, y2i, x2f, y2f );
double xx = x1i; double xx = x1i;
double yy = y1i; double yy = y1i;
double dd = GetPointToLineSegmentDistance( x1f, y1f, x2i, y2i, x2f, y2f ); double dd = GetPointToLineSegmentDistance( x1f, y1f, x2i, y2i, x2f, y2f );
if( dd < dist ) if( dd < dist )
{ {
dist = dd; dist = dd;
xx = x1f; xx = x1f;
yy = y1f; yy = y1f;
} }
dd = GetPointToLineSegmentDistance( x2i, y2i, x1i, y1i, x1f, y1f ); dd = GetPointToLineSegmentDistance( x2i, y2i, x1i, y1i, x1f, y1f );
if( dd < dist ) if( dd < dist )
{ {
dist = dd; dist = dd;
xx = x2i; xx = x2i;
yy = y2i; yy = y2i;
} }
dd = GetPointToLineSegmentDistance( x2f, y2f, x1i, y1i, x1f, y1f ); dd = GetPointToLineSegmentDistance( x2f, y2f, x1i, y1i, x1f, y1f );
if( dd < dist ) if( dd < dist )
{ {
dist = dd; dist = dd;
xx = x2f; xx = x2f;
yy = y2f; yy = y2f;
} }
if( x ) if( x )
*x = xx; *x = xx;
if( y ) if( y )
*y = yy; *y = yy;
if( d ) if( d )
*d = dist; *d = dist;
return false; return false;
} }
// quicksort algorithm // quicksort algorithm
// sorts array numbers[], also moves elements of another array index[] // sorts array numbers[], also moves elements of another array index[]
// //
#define Q3WAY #define Q3WAY
void quickSort(int numbers[], int index[], int array_size) void quickSort(int numbers[], int index[], int array_size)
{ {
#ifdef Q3WAY #ifdef Q3WAY
q_sort_3way(numbers, index, 0, array_size - 1); q_sort_3way(numbers, index, 0, array_size - 1);
#else #else
q_sort(numbers, index, 0, array_size - 1); q_sort(numbers, index, 0, array_size - 1);
#endif #endif
} }
// standard quicksort // standard quicksort
// //
void q_sort(int numbers[], int index[], int left, int right) void q_sort(int numbers[], int index[], int left, int right)
{ {
int pivot, pivot_index, l_hold, r_hold; int pivot, pivot_index, l_hold, r_hold;
l_hold = left; l_hold = left;
r_hold = right; r_hold = right;
pivot = numbers[left]; pivot = numbers[left];
pivot_index = index[left]; pivot_index = index[left];
while (left < right) while (left < right)
{ {
while ((numbers[right] >= pivot) && (left < right)) while ((numbers[right] >= pivot) && (left < right))
right--; right--;
if (left != right) if (left != right)
{ {
numbers[left] = numbers[right]; numbers[left] = numbers[right];
index[left] = index[right]; index[left] = index[right];
left++; left++;
} }
while ((numbers[left] <= pivot) && (left < right)) while ((numbers[left] <= pivot) && (left < right))
left++; left++;
if (left != right) if (left != right)
{ {
numbers[right] = numbers[left]; numbers[right] = numbers[left];
index[right] = index[left]; index[right] = index[left];
right--; right--;
} }
} }
numbers[left] = pivot; numbers[left] = pivot;
index[left] = pivot_index; index[left] = pivot_index;
pivot = left; pivot = left;
left = l_hold; left = l_hold;
right = r_hold; right = r_hold;
if (left < pivot) if (left < pivot)
q_sort(numbers, index, left, pivot-1); q_sort(numbers, index, left, pivot-1);
if (right > pivot) if (right > pivot)
q_sort(numbers, index, pivot+1, right); q_sort(numbers, index, pivot+1, right);
} }
// 3-way quicksort...useful where there are duplicate values // 3-way quicksort...useful where there are duplicate values
// //
void q_sort_3way( int a[], int b[], int l, int r ) void q_sort_3way( int a[], int b[], int l, int r )
{ {
#define EXCH(i,j) {int temp=a[i]; a[i]=a[j]; a[j]=temp; temp=b[i]; b[i]=b[j]; b[j]=temp;} #define EXCH(i,j) {int temp=a[i]; a[i]=a[j]; a[j]=temp; temp=b[i]; b[i]=b[j]; b[j]=temp;}
int i = l - 1; int i = l - 1;
int j = r; int j = r;
int p = l - 1; int p = l - 1;
int q = r; int q = r;
int v = a[r]; int v = a[r];
if( r <= l ) if( r <= l )
return; return;
for(;;) for(;;)
{ {
while( a[++i] < v ); while( a[++i] < v );
while( v < a[--j] ) while( v < a[--j] )
if( j == 1 ) if( j == 1 )
break; break;
if( i >= j ) if( i >= j )
break; break;
EXCH( i, j ); EXCH( i, j );
if( a[i] == v ) if( a[i] == v )
{ {
p++; p++;
EXCH( p, i ); EXCH( p, i );
} }
if( v == a[j] ) if( v == a[j] )
{ {
q--; q--;
EXCH( j, q ); EXCH( j, q );
} }
} }
EXCH( i, r ); EXCH( i, r );
j = i - 1; j = i - 1;
i = i + 1; i = i + 1;
for( int k=l; k<p; k++, j-- ) for( int k=l; k<p; k++, j-- )
EXCH( k, j ); EXCH( k, j );
for( int k=r-1; k>q; k--, i++ ) for( int k=r-1; k>q; k--, i++ )
EXCH( i, k ); EXCH( i, k );
q_sort_3way( a, b, l, j ); q_sort_3way( a, b, l, j );
q_sort_3way( a, b, i, r ); q_sort_3way( a, b, i, r );
} }
// solves quadratic equation // solves quadratic equation
// i.e. ax**2 + bx + c = 0 // i.e. ax**2 + bx + c = 0
// returns true if solution exist, with solutions in x1 and x2 // returns true if solution exist, with solutions in x1 and x2
// else returns false // else returns false
// //
bool Quadratic( double a, double b, double c, double *x1, double *x2 ) bool Quadratic( double a, double b, double c, double *x1, double *x2 )
{ {
double root = b*b - 4.0*a*c; double root = b*b - 4.0*a*c;
if( root < 0.0 ) if( root < 0.0 )
return false; return false;
root = sqrt( root ); root = sqrt( root );
*x1 = (-b+root)/(2.0*a); *x1 = (-b+root)/(2.0*a);
*x2 = (-b-root)/(2.0*a); *x2 = (-b-root)/(2.0*a);
return true; return true;
} }
// finds intersections of vertical line at x // finds intersections of vertical line at x
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1; // with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in y1 and y2 // returns true if solution exist, with solutions in y1 and y2
// else returns false // else returns false
// //
bool FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 ) bool FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 )
{ {
double y_sqr = (1.0-(x*x)/(a*a))*b*b; double y_sqr = (1.0-(x*x)/(a*a))*b*b;
if( y_sqr < 0.0 ) if( y_sqr < 0.0 )
return false; return false;
*y1 = sqrt(y_sqr); *y1 = sqrt(y_sqr);
*y2 = -*y1; *y2 = -*y1;
return true; return true;
} }
// finds intersections of straight line y = c + dx // finds intersections of straight line y = c + dx
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1; // with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in x1 and x2 // returns true if solution exist, with solutions in x1 and x2
// else returns false // else returns false
// //
bool FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 ) bool FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 )
{ {
// quadratic terms // quadratic terms
double A = d*d+b*b/(a*a); double A = d*d+b*b/(a*a);
double B = 2.0*c*d; double B = 2.0*c*d;
double C = c*c-b*b; double C = c*c-b*b;
return Quadratic( A, B, C, x1, x2 ); return Quadratic( A, B, C, x1, x2 );
} }
#if 0 #if 0
// draw a straight line or an arc between xi,yi and xf,yf // draw a straight line or an arc between xi,yi and xf,yf
// //
void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, bool bMeta ) void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, bool bMeta )
{ {
int xi, yi, xf, yf; int xi, yi, xf, yf;
if( shape == DL_LINE || xxi == xxf || yyi == yyf ) if( shape == DL_LINE || xxi == xxf || yyi == yyf )
{ {
// draw straight line // draw straight line
pDC->MoveTo( xxi, yyi ); pDC->MoveTo( xxi, yyi );
pDC->LineTo( xxf, yyf ); pDC->LineTo( xxf, yyf );
} }
else if( shape == DL_ARC_CCW || shape == DL_ARC_CW ) else if( shape == DL_ARC_CCW || shape == DL_ARC_CW )
{ {
// set endpoints so we can always draw counter-clockwise arc // set endpoints so we can always draw counter-clockwise arc
if( shape == DL_ARC_CW ) if( shape == DL_ARC_CW )
{ {
xi = xxf; xi = xxf;
yi = yyf; yi = yyf;
xf = xxi; xf = xxi;
yf = yyi; yf = yyi;
} }
else else
{ {
xi = xxi; xi = xxi;
yi = yyi; yi = yyi;
xf = xxf; xf = xxf;
yf = yyf; yf = yyf;
} }
pDC->MoveTo( xi, yi ); pDC->MoveTo( xi, yi );
if( xf > xi && yf > yi ) if( xf > xi && yf > yi )
{ {
// quadrant 1 // quadrant 1
int w = (xf-xi)*2; int w = (xf-xi)*2;
int h = (yf-yi)*2; int h = (yf-yi)*2;
if( !bMeta ) if( !bMeta )
pDC->Arc( xf-w, yi+h, xf, yi, pDC->Arc( xf-w, yi+h, xf, yi,
xi, yi, xf, yf ); xi, yi, xf, yf );
else else
pDC->Arc( xf-w, yi, xf, yi+h, pDC->Arc( xf-w, yi, xf, yi+h,
xf, yf, xi, yi ); xf, yf, xi, yi );
} }
else if( xf < xi && yf > yi ) else if( xf < xi && yf > yi )
{ {
// quadrant 2 // quadrant 2
int w = -(xf-xi)*2; int w = -(xf-xi)*2;
int h = (yf-yi)*2; int h = (yf-yi)*2;
if( !bMeta ) if( !bMeta )
pDC->Arc( xi-w, yf, xi, yf-h, pDC->Arc( xi-w, yf, xi, yf-h,
xi, yi, xf, yf ); xi, yi, xf, yf );
else else
pDC->Arc( xi-w, yf-h, xi, yf, pDC->Arc( xi-w, yf-h, xi, yf,
xf, yf, xi, yi ); xf, yf, xi, yi );
} }
else if( xf < xi && yf < yi ) else if( xf < xi && yf < yi )
{ {
// quadrant 3 // quadrant 3
int w = -(xf-xi)*2; int w = -(xf-xi)*2;
int h = -(yf-yi)*2; int h = -(yf-yi)*2;
if( !bMeta ) if( !bMeta )
pDC->Arc( xf, yi, xf+w, yi-h, pDC->Arc( xf, yi, xf+w, yi-h,
xi, yi, xf, yf ); xi, yi, xf, yf );
else else
pDC->Arc( xf, yi-h, xf+w, yi, pDC->Arc( xf, yi-h, xf+w, yi,
xf, yf, xi, yi ); xf, yf, xi, yi );
} }
else if( xf > xi && yf < yi ) else if( xf > xi && yf < yi )
{ {
// quadrant 4 // quadrant 4
int w = (xf-xi)*2; int w = (xf-xi)*2;
int h = -(yf-yi)*2; int h = -(yf-yi)*2;
if( !bMeta ) if( !bMeta )
pDC->Arc( xi, yf+h, xi+w, yf, pDC->Arc( xi, yf+h, xi+w, yf,
xi, yi, xf, yf ); xi, yi, xf, yf );
else else
pDC->Arc( xi, yf, xi+w, yf+h, pDC->Arc( xi, yf, xi+w, yf+h,
xf, yf, xi, yi ); xf, yf, xi, yi );
} }
pDC->MoveTo( xxf, yyf ); pDC->MoveTo( xxf, yyf );
} }
else else
ASSERT(0); // oops ASSERT(0); // oops
} }
#endif #endif
// Get arrays of circles, rects and line segments to represent pad // Get arrays of circles, rects and line segments to represent pad
// for purposes of drawing pad or calculating clearances // for purposes of drawing pad or calculating clearances
// margins of circles and line segments represent pad outline // margins of circles and line segments represent pad outline
// circles and rects are used to find points inside pad // circles and rects are used to find points inside pad
// //
void GetPadElements( int type, int x, int y, int wid, int len, int radius, int angle, void GetPadElements( int type, int x, int y, int wid, int len, int radius, int angle,
int * nr, my_rect r[], int * nc, my_circle c[], int * ns, my_seg s[] ) int * nr, my_rect r[], int * nc, my_circle c[], int * ns, my_seg s[] )
{ {
*nc = 0; *nc = 0;
*nr = 0; *nr = 0;
*ns = 0; *ns = 0;
if( type == PAD_ROUND ) if( type == PAD_ROUND )
{ {
*nc = 1; *nc = 1;
c[0] = my_circle(x,y,wid/2); c[0] = my_circle(x,y,wid/2);
return; return;
} }
if( type == PAD_SQUARE ) if( type == PAD_SQUARE )
{ {
*nr = 1; *nr = 1;
r[0] = my_rect(x-wid/2, y-wid/2,x+wid/2, y+wid/2); r[0] = my_rect(x-wid/2, y-wid/2,x+wid/2, y+wid/2);
*ns = 4; *ns = 4;
s[0] = my_seg(x-wid/2, y+wid/2,x+wid/2, y+wid/2); // top s[0] = my_seg(x-wid/2, y+wid/2,x+wid/2, y+wid/2); // top
s[1] = my_seg(x-wid/2, y-wid/2,x+wid/2, y-wid/2); // bottom s[1] = my_seg(x-wid/2, y-wid/2,x+wid/2, y-wid/2); // bottom
s[2] = my_seg(x-wid/2, y-wid/2,x-wid/2, y+wid/2); // left s[2] = my_seg(x-wid/2, y-wid/2,x-wid/2, y+wid/2); // left
s[3] = my_seg(x+wid/2, y-wid/2,x+wid/2, y+wid/2); // right s[3] = my_seg(x+wid/2, y-wid/2,x+wid/2, y+wid/2); // right
return; return;
} }
if( type == PAD_OCTAGON ) if( type == PAD_OCTAGON )
{ {
const double pi = 3.14159265359; const double pi = 3.14159265359;
*nc = 1; // circle represents inside of polygon *nc = 1; // circle represents inside of polygon
c[0] = my_circle(x, y, wid/2); c[0] = my_circle(x, y, wid/2);
*ns = 8; // now create sides of polygon *ns = 8; // now create sides of polygon
double theta = pi/8.0; double theta = pi/8.0;
double radius = 0.5*(double)wid/cos(theta); double radius = 0.5*(double)wid/cos(theta);
double last_x = x + radius*cos(theta); double last_x = x + radius*cos(theta);
double last_y = y + radius*sin(theta); double last_y = y + radius*sin(theta);
for( int is=0; is<8; is++ ) for( int is=0; is<8; is++ )
{ {
theta += pi/4.0; theta += pi/4.0;
double dx = x + radius*cos(theta); double dx = x + radius*cos(theta);
double dy = y + radius*sin(theta); double dy = y + radius*sin(theta);
s[is] = my_seg(last_x, last_y, x, y); s[is] = my_seg(last_x, last_y, x, y);
last_x = dx; last_x = dx;
last_y = dy; last_y = dy;
} }
return; return;
} }
// //
int h; int h;
int v; int v;
if( angle == 90 || angle == 270 ) if( angle == 90 || angle == 270 )
{ {
h = wid; h = wid;
v = len; v = len;
} }
else else
{ {
v = wid; v = wid;
h = len; h = len;
} }
if( type == PAD_RECT ) if( type == PAD_RECT )
{ {
*nr = 1; *nr = 1;
r[0] = my_rect(x-h/2, y-v/2, x+h/2, y+v/2); r[0] = my_rect(x-h/2, y-v/2, x+h/2, y+v/2);
*ns = 4; *ns = 4;
s[0] = my_seg(x-h/2, y+v/2,x+h/2, y+v/2); // top s[0] = my_seg(x-h/2, y+v/2,x+h/2, y+v/2); // top
s[1] = my_seg(x-h/2, y-v/2,x+h/2, y-v/2); // bottom s[1] = my_seg(x-h/2, y-v/2,x+h/2, y-v/2); // bottom
s[2] = my_seg(x-h/2, y-v/2,x-h/2, y+v/2); // left s[2] = my_seg(x-h/2, y-v/2,x-h/2, y+v/2); // left
s[3] = my_seg(x+h/2, y-v/2,x+h/2, y+v/2); // right s[3] = my_seg(x+h/2, y-v/2,x+h/2, y+v/2); // right
return; return;
} }
if( type == PAD_RRECT ) if( type == PAD_RRECT )
{ {
*nc = 4; *nc = 4;
c[0] = my_circle(x-h/2+radius, y-v/2+radius, radius); // bottom left circle c[0] = my_circle(x-h/2+radius, y-v/2+radius, radius); // bottom left circle
c[1] = my_circle(x+h/2-radius, y-v/2+radius, radius); // bottom right circle c[1] = my_circle(x+h/2-radius, y-v/2+radius, radius); // bottom right circle
c[2] = my_circle(x-h/2+radius, y+v/2-radius, radius); // top left circle c[2] = my_circle(x-h/2+radius, y+v/2-radius, radius); // top left circle
c[3] = my_circle(x+h/2-radius, y+v/2-radius, radius); // top right circle c[3] = my_circle(x+h/2-radius, y+v/2-radius, radius); // top right circle
*ns = 4; *ns = 4;
s[0] = my_seg(x-h/2+radius, y+v/2, x+h/2-radius, y+v/2); // top s[0] = my_seg(x-h/2+radius, y+v/2, x+h/2-radius, y+v/2); // top
s[1] = my_seg(x-h/2+radius, y-v/2, x+h/2-radius, y+v/2); // bottom s[1] = my_seg(x-h/2+radius, y-v/2, x+h/2-radius, y+v/2); // bottom
s[2] = my_seg(x-h/2, y-v/2+radius, x-h/2, y+v/2-radius); // left s[2] = my_seg(x-h/2, y-v/2+radius, x-h/2, y+v/2-radius); // left
s[3] = my_seg(x+h/2, y-v/2+radius, x+h/2, y+v/2-radius); // right s[3] = my_seg(x+h/2, y-v/2+radius, x+h/2, y+v/2-radius); // right
return; return;
} }
if( type == PAD_OVAL ) if( type == PAD_OVAL )
{ {
if( h > v ) if( h > v )
{ {
// horizontal // horizontal
*nc = 2; *nc = 2;
c[0] = my_circle(x-h/2+v/2, y, v/2); // left circle c[0] = my_circle(x-h/2+v/2, y, v/2); // left circle
c[1] = my_circle(x+h/2-v/2, y, v/2); // right circle c[1] = my_circle(x+h/2-v/2, y, v/2); // right circle
*nr = 1; *nr = 1;
r[0] = my_rect(x-h/2+v/2, y-v/2, x+h/2-v/2, y+v/2); r[0] = my_rect(x-h/2+v/2, y-v/2, x+h/2-v/2, y+v/2);
*ns = 2; *ns = 2;
s[0] = my_seg(x-h/2+v/2, y+v/2, x+h/2-v/2, y+v/2); // top s[0] = my_seg(x-h/2+v/2, y+v/2, x+h/2-v/2, y+v/2); // top
s[1] = my_seg(x-h/2+v/2, y-v/2, x+h/2-v/2, y-v/2); // bottom s[1] = my_seg(x-h/2+v/2, y-v/2, x+h/2-v/2, y-v/2); // bottom
} }
else else
{ {
// vertical // vertical
*nc = 2; *nc = 2;
c[0] = my_circle(x, y+v/2-h/2, h/2); // top circle c[0] = my_circle(x, y+v/2-h/2, h/2); // top circle
c[1] = my_circle(x, y-v/2+h/2, h/2); // bottom circle c[1] = my_circle(x, y-v/2+h/2, h/2); // bottom circle
*nr = 1; *nr = 1;
r[0] = my_rect(x-h/2, y-v/2+h/2, x+h/2, y+v/2-h/2); r[0] = my_rect(x-h/2, y-v/2+h/2, x+h/2, y+v/2-h/2);
*ns = 2; *ns = 2;
s[0] = my_seg(x-h/2, y-v/2+h/2, x-h/2, y+v/2-h/2); // left s[0] = my_seg(x-h/2, y-v/2+h/2, x-h/2, y+v/2-h/2); // left
s[1] = my_seg(x+h/2, y-v/2+h/2, x+h/2, y+v/2-h/2); // left s[1] = my_seg(x+h/2, y-v/2+h/2, x+h/2, y+v/2-h/2); // left
} }
return; return;
} }
ASSERT(0); ASSERT(0);
} }
// Find distance from a staright line segment to a pad // Find distance from a staright line segment to a pad
// //
int GetClearanceBetweenSegmentAndPad( int x1, int y1, int x2, int y2, int w, int GetClearanceBetweenSegmentAndPad( int x1, int y1, int x2, int y2, int w,
int type, int x, int y, int wid, int len, int radius, int angle ) int type, int x, int y, int wid, int len, int radius, int angle )
{ {
if( type == PAD_NONE ) if( type == PAD_NONE )
return INT_MAX; return INT_MAX;
else else
{ {
int nc, nr, ns; int nc, nr, ns;
my_circle c[4]; my_circle c[4];
my_rect r[2]; my_rect r[2];
my_seg s[8]; my_seg s[8];
GetPadElements( type, x, y, wid, len, radius, angle, GetPadElements( type, x, y, wid, len, radius, angle,
&nr, r, &nc, c, &ns, s ); &nr, r, &nc, c, &ns, s );
// first test for endpoints of line segment in rectangle // first test for endpoints of line segment in rectangle
for( int ir=0; ir<nr; ir++ ) for( int ir=0; ir<nr; ir++ )
{ {
if( x1 >= r[ir].xlo && x1 <= r[ir].xhi && y1 >= r[ir].ylo && y1 <= r[ir].yhi ) if( x1 >= r[ir].xlo && x1 <= r[ir].xhi && y1 >= r[ir].ylo && y1 <= r[ir].yhi )
return 0; return 0;
if( x2 >= r[ir].xlo && x2 <= r[ir].xhi && y2 >= r[ir].ylo && y2 <= r[ir].yhi ) if( x2 >= r[ir].xlo && x2 <= r[ir].xhi && y2 >= r[ir].ylo && y2 <= r[ir].yhi )
return 0; return 0;
} }
// now get distance from elements of pad outline // now get distance from elements of pad outline
int dist = INT_MAX; int dist = INT_MAX;
for( int ic=0; ic<nc; ic++ ) for( int ic=0; ic<nc; ic++ )
{ {
int d = GetPointToLineSegmentDistance( c[ic].x, c[ic].y, x1, y1, x2, y2 ) - c[ic].r - w/2; int d = GetPointToLineSegmentDistance( c[ic].x, c[ic].y, x1, y1, x2, y2 ) - c[ic].r - w/2;
dist = min(dist,d); dist = min(dist,d);
} }
for( int is=0; is<ns; is++ ) for( int is=0; is<ns; is++ )
{ {
double d; double d;
TestForIntersectionOfStraightLineSegments( s[is].xi, s[is].yi, s[is].xf, s[is].yf, TestForIntersectionOfStraightLineSegments( s[is].xi, s[is].yi, s[is].xf, s[is].yf,
x1, y1, x2, y2, NULL, NULL, &d ); x1, y1, x2, y2, NULL, NULL, &d );
d -= w/2; d -= w/2;
dist = min(dist,d); dist = min(dist,d);
} }
return max(0,dist); return max(0,dist);
} }
} }
// Get clearance between 2 segments // Get clearance between 2 segments
// Returns point in segment closest to other segment in x, y // Returns point in segment closest to other segment in x, y
// in clearance > max_cl, just returns max_cl and doesn't return x,y // in clearance > max_cl, just returns max_cl and doesn't return x,y
// //
int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1, 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 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
int test = max_cl + w1/2 + w2/2; int test = max_cl + w1/2 + w2/2;
if( min(x1i,x1f)-max(x2i,x2f) > test ) if( min(x1i,x1f)-max(x2i,x2f) > test )
return max_cl; return max_cl;
if( min(x2i,x2f)-max(x1i,x1f) > test ) if( min(x2i,x2f)-max(x1i,x1f) > test )
return max_cl; return max_cl;
if( min(y1i,y1f)-max(y2i,y2f) > test ) if( min(y1i,y1f)-max(y2i,y2f) > test )
return max_cl; return max_cl;
if( min(y2i,y2f)-max(y1i,y1f) > test ) if( min(y2i,y2f)-max(y1i,y1f) > test )
return max_cl; return max_cl;
if( style1 == CPolyLine::STRAIGHT && style1 == CPolyLine::STRAIGHT ) if( style1 == CPolyLine::STRAIGHT && style1 == CPolyLine::STRAIGHT )
{ {
// both segments are straight lines // both segments are straight lines
int xx, yy; int xx, yy;
double dd; double dd;
TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f, TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f,
x2i, y2i, x2f, y2f, &xx, &yy, &dd ); x2i, y2i, x2f, y2f, &xx, &yy, &dd );
int d = max( 0, dd - w1/2 - w2/2 ); int d = max( 0, dd - w1/2 - w2/2 );
if( x ) if( x )
*x = xx; *x = xx;
if( y ) if( y )
*y = yy; *y = yy;
return d; return d;
} }
// not both straight-line segments // not both straight-line segments
// see if segments intersect // see if segments intersect
double xr[2]; double xr[2];
double yr[2]; double yr[2];
test = FindSegmentIntersections( x1i, y1i, x1f, y1f, style1, x2i, y2i, x2f, y2f, style2, xr, yr ); test = FindSegmentIntersections( x1i, y1i, x1f, y1f, style1, x2i, y2i, x2f, y2f, style2, xr, yr );
if( test ) if( test )
{ {
if( x ) if( x )
*x = xr[0]; *x = xr[0];
if( y ) if( y )
*y = yr[0]; *y = yr[0];
return 0.0; return 0.0;
} }
// at least one segment is an arc // at least one segment is an arc
EllipseKH el1; EllipseKH el1;
EllipseKH el2; EllipseKH el2;
bool bArcs; bool bArcs;
int xi, yi, xf, yf; int xi, yi, xf, yf;
if( style2 == CPolyLine::STRAIGHT ) if( style2 == CPolyLine::STRAIGHT )
{ {
// style1 = arc, style2 = straight // style1 = arc, style2 = straight
MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 ); MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 );
xi = x2i; xi = x2i;
yi = y2i; yi = y2i;
xf = x2f; xf = x2f;
yf = y2f; yf = y2f;
bArcs = false; bArcs = false;
} }
else if( style1 == CPolyLine::STRAIGHT ) else if( style1 == CPolyLine::STRAIGHT )
{ {
// style2 = arc, style1 = straight // style2 = arc, style1 = straight
xi = x1i; xi = x1i;
yi = y1i; yi = y1i;
xf = x1f; xf = x1f;
yf = y1f; yf = y1f;
MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el1 ); MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el1 );
bArcs = false; bArcs = false;
} }
else else
{ {
// style1 = arc, style2 = arc // style1 = arc, style2 = arc
MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 ); MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 );
MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el2 ); MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el2 );
bArcs = true; bArcs = true;
} }
const int NSTEPS = 32; const int NSTEPS = 32;
if( el1.theta2 > el1.theta1 ) if( el1.theta2 > el1.theta1 )
ASSERT(0); ASSERT(0);
if( bArcs && el2.theta2 > el2.theta1 ) if( bArcs && el2.theta2 > el2.theta1 )
ASSERT(0); ASSERT(0);
// test multiple points in both segments // test multiple points in both segments
double th1; double th1;
double th2; double th2;
double len2; double len2;
if( bArcs ) if( bArcs )
{ {
th1 = el2.theta1; th1 = el2.theta1;
th2 = el2.theta2; th2 = el2.theta2;
len2 = max(el2.xrad, el2.yrad); len2 = max(el2.xrad, el2.yrad);
} }
else else
{ {
th1 = 1.0; th1 = 1.0;
th2 = 0.0; th2 = 0.0;
len2 = abs(xf-xi)+abs(yf-yi); len2 = abs(xf-xi)+abs(yf-yi);
} }
double s_start = el1.theta1; double s_start = el1.theta1;
double s_end = el1.theta2; double s_end = el1.theta2;
double s_start2 = th1; double s_start2 = th1;
double s_end2 = th2; double s_end2 = th2;
double dmin = DBL_MAX; double dmin = DBL_MAX;
double xmin, ymin, smin, smin2; double xmin, ymin, smin, smin2;
int nsteps = NSTEPS; int nsteps = NSTEPS;
int nsteps2 = NSTEPS; int nsteps2 = NSTEPS;
double step = (s_start-s_end)/(nsteps-1); double step = (s_start-s_end)/(nsteps-1);
double step2 = (s_start2-s_end2)/(nsteps2-1); double step2 = (s_start2-s_end2)/(nsteps2-1);
while( (step * max(el1.xrad, el1.yrad)) > 0.1*NM_PER_MIL while( (step * max(el1.xrad, el1.yrad)) > 0.1*NM_PER_MIL
&& (step2 * len2) > 0.1*NM_PER_MIL ) && (step2 * len2) > 0.1*NM_PER_MIL )
{ {
step = (s_start-s_end)/(nsteps-1); step = (s_start-s_end)/(nsteps-1);
for( int i=0; i<nsteps; i++ ) for( int i=0; i<nsteps; i++ )
{ {
double s; double s;
if( i < nsteps-1 ) if( i < nsteps-1 )
s = s_start - i*step; s = s_start - i*step;
else else
s = s_end; s = s_end;
double x = el1.Center.X + el1.xrad*cos(s); double x = el1.Center.X + el1.xrad*cos(s);
double y = el1.Center.Y + el1.yrad*sin(s); double y = el1.Center.Y + el1.yrad*sin(s);
// if not an arc, use s2 as fractional distance along line // if not an arc, use s2 as fractional distance along line
step2 = (s_start2-s_end2)/(nsteps2-1); step2 = (s_start2-s_end2)/(nsteps2-1);
for( int i2=0; i2<nsteps2; i2++ ) for( int i2=0; i2<nsteps2; i2++ )
{ {
double s2; double s2;
if( i2 < nsteps2-1 ) if( i2 < nsteps2-1 )
s2 = s_start2 - i2*step2; s2 = s_start2 - i2*step2;
else else
s2 = s_end2; s2 = s_end2;
double x2, y2; double x2, y2;
if( !bArcs ) if( !bArcs )
{ {
x2 = xi + (xf-xi)*s2; x2 = xi + (xf-xi)*s2;
y2 = yi + (yf-yi)*s2; y2 = yi + (yf-yi)*s2;
} }
else else
{ {
x2 = el2.Center.X + el2.xrad*cos(s2); x2 = el2.Center.X + el2.xrad*cos(s2);
y2 = el2.Center.Y + el2.yrad*sin(s2); y2 = el2.Center.Y + el2.yrad*sin(s2);
} }
double d = Distance( x, y, x2, y2 ); double d = Distance( x, y, x2, y2 );
if( d < dmin ) if( d < dmin )
{ {
dmin = d; dmin = d;
xmin = x; xmin = x;
ymin = y; ymin = y;
smin = s; smin = s;
smin2 = s2; smin2 = s2;
} }
} }
} }
if( step > step2 ) if( step > step2 )
{ {
s_start = min(el1.theta1, smin + step); s_start = min(el1.theta1, smin + step);
s_end = max(el1.theta2, smin - step); s_end = max(el1.theta2, smin - step);
step = (s_start - s_end)/nsteps; step = (s_start - s_end)/nsteps;
} }
else else
{ {
s_start2 = min(th1, smin2 + step2); s_start2 = min(th1, smin2 + step2);
s_end2 = max(th2, smin2 - step2); s_end2 = max(th2, smin2 - step2);
step2 = (s_start2 - s_end2)/nsteps2; step2 = (s_start2 - s_end2)/nsteps2;
} }
} }
if( x ) if( x )
*x = xmin; *x = xmin;
if( y ) if( y )
*y = ymin; *y = ymin;
return max(0,dmin-w1/2-w2/2); // allow for widths return max(0,dmin-w1/2-w2/2); // allow for widths
} }
// Find clearance between pads // Find clearance between pads
// For each pad: // For each pad:
// type = PAD_ROUND, PAD_SQUARE, etc. // type = PAD_ROUND, PAD_SQUARE, etc.
// x, y = center position // x, y = center position
// w, l = width and length // w, l = width and length
// r = corner radius // r = corner radius
// angle = 0 or 90 (if 0, pad length is along x-axis) // angle = 0 or 90 (if 0, pad length is along x-axis)
// //
int GetClearanceBetweenPads( int type1, int x1, int y1, int w1, int l1, int r1, int angle1, int GetClearanceBetweenPads( int type1, int x1, int y1, int w1, int l1, int r1, int angle1,
int type2, int x2, int y2, int w2, int l2, int r2, int angle2 ) int type2, int x2, int y2, int w2, int l2, int r2, int angle2 )
{ {
if( type1 == PAD_NONE ) if( type1 == PAD_NONE )
return INT_MAX; return INT_MAX;
if( type2 == PAD_NONE ) if( type2 == PAD_NONE )
return INT_MAX; return INT_MAX;
int dist = INT_MAX; int dist = INT_MAX;
int nr, nc, ns, nrr, ncc, nss; int nr, nc, ns, nrr, ncc, nss;
my_rect r[2], rr[2]; my_rect r[2], rr[2];
my_circle c[4], cc[4]; my_circle c[4], cc[4];
my_seg s[8], ss[8]; my_seg s[8], ss[8];
GetPadElements( type1, x1, y1, w1, l1, r1, angle1, GetPadElements( type1, x1, y1, w1, l1, r1, angle1,
&nr, r, &nc, c, &ns, s ); &nr, r, &nc, c, &ns, s );
GetPadElements( type2, x2, y2, w2, l2, r2, angle2, GetPadElements( type2, x2, y2, w2, l2, r2, angle2,
&nrr, rr, &ncc, cc, &nss, ss ); &nrr, rr, &ncc, cc, &nss, ss );
// now find distance from every element of pad1 to every element of pad2 // now find distance from every element of pad1 to every element of pad2
for( int ic=0; ic<nc; ic++ ) for( int ic=0; ic<nc; ic++ )
{ {
for( int icc=0; icc<ncc; icc++ ) for( int icc=0; icc<ncc; icc++ )
{ {
int d = Distance( c[ic].x, c[ic].y, cc[icc].x, cc[icc].y ) int d = Distance( c[ic].x, c[ic].y, cc[icc].x, cc[icc].y )
- c[ic].r - cc[icc].r; - c[ic].r - cc[icc].r;
dist = min(dist,d); dist = min(dist,d);
} }
for( int iss=0; iss<nss; iss++ ) for( int iss=0; iss<nss; iss++ )
{ {
int d = GetPointToLineSegmentDistance( c[ic].x, c[ic].y, int d = GetPointToLineSegmentDistance( c[ic].x, c[ic].y,
ss[iss].xi, ss[iss].yi, ss[iss].xf, ss[iss].yf ) - c[ic].r; ss[iss].xi, ss[iss].yi, ss[iss].xf, ss[iss].yf ) - c[ic].r;
dist = min(dist,d); dist = min(dist,d);
} }
} }
for( int is=0; is<ns; is++ ) for( int is=0; is<ns; is++ )
{ {
for( int icc=0; icc<ncc; icc++ ) for( int icc=0; icc<ncc; icc++ )
{ {
int d = GetPointToLineSegmentDistance( cc[icc].x, cc[icc].y, int d = GetPointToLineSegmentDistance( cc[icc].x, cc[icc].y,
s[is].xi, s[is].yi, s[is].xf, s[is].yf ) - cc[icc].r; s[is].xi, s[is].yi, s[is].xf, s[is].yf ) - cc[icc].r;
dist = min(dist,d); dist = min(dist,d);
} }
for( int iss=0; iss<nss; iss++ ) for( int iss=0; iss<nss; iss++ )
{ {
double d; double d;
TestForIntersectionOfStraightLineSegments( s[is].xi, s[is].yi, s[is].xf, s[is].yf, TestForIntersectionOfStraightLineSegments( s[is].xi, s[is].yi, s[is].xf, s[is].yf,
ss[iss].xi, ss[iss].yi, ss[iss].xf, ss[iss].yf, NULL, NULL, &d ); ss[iss].xi, ss[iss].yi, ss[iss].xf, ss[iss].yf, NULL, NULL, &d );
dist = min(dist,d); dist = min(dist,d);
} }
} }
return max(dist,0); return max(dist,0);
} }
// Get min. distance from (x,y) to line y = a + bx // Get min. distance from (x,y) to line y = a + bx
// if b > DBL_MAX/10, assume vertical line at x = a // if b > DBL_MAX/10, assume vertical line at x = a
// returns closest point on line in xp, yp // returns closest point on line in xp, yp
// //
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 )
{ {
// vertical line // vertical line
if( xpp && ypp ) if( xpp && ypp )
{ {
*xpp = a; *xpp = a;
*ypp = y; *ypp = y;
} }
return abs(a-x); return abs(a-x);
} }
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b) // find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double d = -1.0/b; double d = -1.0/b;
double c = (double)y-d*x; double c = (double)y-d*x;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf) // find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double xp = (a-c)/(d-b); double xp = (a-c)/(d-b);
double yp = a + b*xp; double yp = a + b*xp;
if( xpp && ypp ) if( xpp && ypp )
{ {
*xpp = xp; *xpp = xp;
*ypp = yp; *ypp = yp;
} }
// find distance // find distance
return Distance( x, y, xp, yp ); return Distance( x, y, xp, yp );
} }
/***********************************************************************************/ /***********************************************************************************/
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 GetPointToLineSegmentDistance /** Function GetPointToLineSegmentDistance
* Get distance between line segment and point * Get distance between line segment and point
* @param x,y = point * @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment * @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance * @return the distance
*/ */
{ {
// test for vertical or horizontal segment // test for vertical or horizontal segment
if( xf==xi ) if( xf==xi )
{ {
// vertical line segment // vertical line segment
if( InRange( y, yi, yf ) ) if( InRange( y, yi, yf ) )
return abs( x - xi ); return abs( x - xi );
else else
return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) );
} }
else if( yf==yi ) else if( yf==yi )
{ {
// horizontal line segment // horizontal line segment
if( InRange( x, xi, xf ) ) if( InRange( x, xi, xf ) )
return abs( y - yi ); return abs( y - yi );
else else
return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) );
} }
else else
{ {
// oblique segment // oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx // find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double b = (double)(yf-yi)/(xf-xi); double b = (double)(yf-yi)/(xf-xi);
double a = (double)yi-b*xi; double a = (double)yi-b*xi;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b) // find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double d = -1.0/b; double d = -1.0/b;
double c = (double)y-d*x; double c = (double)y-d*x;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf) // find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double xp = (a-c)/(d-b); double xp = (a-c)/(d-b);
double yp = a + b*xp; double yp = a + b*xp;
// find distance // find distance
if( InRange( xp, xi, xf ) && InRange( yp, yi, yf ) ) if( InRange( xp, xi, xf ) && InRange( yp, yi, yf ) )
return Distance( x, y, xp, yp ); return Distance( x, y, xp, yp );
else else
return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) );
} }
} }
// 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 )
{ {
if( x >= xi && x <= xf ) if( x >= xi && x <= xf )
return true; return true;
} }
else else
{ {
if( x >= xf && x <= xi ) if( x >= xf && x <= xi )
return true; return true;
} }
return false; return false;
} }
// Get distance between 2 points // Get distance between 2 points
// //
double Distance( int x1, int y1, int x2, int y2 ) double Distance( int x1, int y1, int x2, int y2 )
{ {
double d; double d;
d = sqrt( (double)(x1-x2)*(x1-x2) + (double)(y1-y2)*(y1-y2) ); d = sqrt( (double)(x1-x2)*(x1-x2) + (double)(y1-y2)*(y1-y2) );
if( d > INT_MAX || d < INT_MIN ) if( d > INT_MAX || d < INT_MIN )
ASSERT(0); ASSERT(0);
return (int)d; return (int)d;
} }
// this finds approximate solutions // this finds approximate solutions
// note: this works best if el2 is smaller than el1 // note: this works best if el2 is smaller than el1
// //
int GetArcIntersections( EllipseKH * el1, EllipseKH * el2, int GetArcIntersections( EllipseKH * el1, EllipseKH * el2,
double * x1, double * y1, double * x2, double * y2 ) double * x1, double * y1, double * x2, double * y2 )
{ {
if( el1->theta2 > el1->theta1 ) if( el1->theta2 > el1->theta1 )
ASSERT(0); ASSERT(0);
if( el2->theta2 > el2->theta1 ) if( el2->theta2 > el2->theta1 )
ASSERT(0); ASSERT(0);
const int NSTEPS = 32; const int NSTEPS = 32;
double xret[2], yret[2]; double xret[2], yret[2];
double xscale = 1.0/el1->xrad; double xscale = 1.0/el1->xrad;
double yscale = 1.0/el1->yrad; double yscale = 1.0/el1->yrad;
// now transform params of second ellipse into reference frame // now transform params of second ellipse into reference frame
// with origin at center if first ellipse, // with origin at center if first ellipse,
// scaled so the first ellipse is a circle of radius = 1.0 // scaled so the first ellipse is a circle of radius = 1.0
double xo = (el2->Center.X - el1->Center.X)*xscale; double xo = (el2->Center.X - el1->Center.X)*xscale;
double yo = (el2->Center.Y - el1->Center.Y)*yscale; double yo = (el2->Center.Y - el1->Center.Y)*yscale;
double xr = el2->xrad*xscale; double xr = el2->xrad*xscale;
double yr = el2->yrad*yscale; double yr = el2->yrad*yscale;
// now test NSTEPS positions in arc, moving clockwise (ie. decreasing theta) // now test NSTEPS positions in arc, moving clockwise (ie. decreasing theta)
double step = M_PI/((NSTEPS-1)*2.0); double step = M_PI/((NSTEPS-1)*2.0);
double d_prev, th_prev; double d_prev, th_prev;
double th_interp; double th_interp;
double th1; double th1;
int n = 0; int n = 0;
for( int i=0; i<NSTEPS; i++ ) for( int i=0; i<NSTEPS; i++ )
{ {
double theta; double theta;
if( i < NSTEPS-1 ) if( i < NSTEPS-1 )
theta = el2->theta1 - i*step; theta = el2->theta1 - i*step;
else else
theta = el2->theta2; theta = el2->theta2;
double x = xo + xr*cos(theta); double x = xo + xr*cos(theta);
double y = yo + yr*sin(theta); double y = yo + yr*sin(theta);
double d = 1.0 - sqrt(x*x + y*y); double d = 1.0 - sqrt(x*x + y*y);
if( i>0 ) if( i>0 )
{ {
bool bInt = false; bool bInt = false;
if( d >= 0.0 && d_prev <= 0.0 ) if( d >= 0.0 && d_prev <= 0.0 )
{ {
th_interp = theta + (step*(-d_prev))/(d-d_prev); th_interp = theta + (step*(-d_prev))/(d-d_prev);
bInt = true; bInt = true;
} }
else if( d <= 0.0 && d_prev >= 0.0 ) else if( d <= 0.0 && d_prev >= 0.0 )
{ {
th_interp = theta + (step*d_prev)/(d_prev-d); th_interp = theta + (step*d_prev)/(d_prev-d);
bInt = true; bInt = true;
} }
if( bInt ) if( bInt )
{ {
x = xo + xr*cos(th_interp); x = xo + xr*cos(th_interp);
y = yo + yr*sin(th_interp); y = yo + yr*sin(th_interp);
th1 = atan2( y, x ); th1 = atan2( y, x );
if( th1 <= el1->theta1 && th1 >= el1->theta2 ) if( th1 <= el1->theta1 && th1 >= el1->theta2 )
{ {
xret[n] = x*el1->xrad + el1->Center.X; xret[n] = x*el1->xrad + el1->Center.X;
yret[n] = y*el1->yrad + el1->Center.Y; yret[n] = y*el1->yrad + el1->Center.Y;
n++; n++;
if( n > 2 ) if( n > 2 )
ASSERT(0); ASSERT(0);
} }
} }
} }
d_prev = d; d_prev = d;
th_prev = theta; th_prev = theta;
} }
if( x1 ) if( x1 )
*x1 = xret[0]; *x1 = xret[0];
if( y1 ) if( y1 )
*y1 = yret[0]; *y1 = yret[0];
if( x2 ) if( x2 )
*x2 = xret[1]; *x2 = xret[1];
if( y2 ) if( y2 )
*y2 = yret[1]; *y2 = yret[1];
return n; return n;
} }
// this finds approximate solution // this finds approximate solution
// //
//double GetSegmentClearance( EllipseKH * el1, EllipseKH * el2, //double GetSegmentClearance( EllipseKH * el1, EllipseKH * el2,
double GetArcClearance( EllipseKH * el1, EllipseKH * el2, double GetArcClearance( EllipseKH * el1, EllipseKH * el2,
double * x1, double * y1 ) double * x1, double * y1 )
{ {
const int NSTEPS = 32; const int NSTEPS = 32;
if( el1->theta2 > el1->theta1 ) if( el1->theta2 > el1->theta1 )
ASSERT(0); ASSERT(0);
if( el2->theta2 > el2->theta1 ) if( el2->theta2 > el2->theta1 )
ASSERT(0); ASSERT(0);
// test multiple positions in both arcs, moving clockwise (ie. decreasing theta) // test multiple positions in both arcs, moving clockwise (ie. decreasing theta)
double th_start = el1->theta1; double th_start = el1->theta1;
double th_end = el1->theta2; double th_end = el1->theta2;
double th_start2 = el2->theta1; double th_start2 = el2->theta1;
double th_end2 = el2->theta2; double th_end2 = el2->theta2;
double dmin = DBL_MAX; double dmin = DBL_MAX;
double xmin, ymin, thmin, thmin2; double xmin, ymin, thmin, thmin2;
int nsteps = NSTEPS; int nsteps = NSTEPS;
int nsteps2 = NSTEPS; int nsteps2 = NSTEPS;
double step = (th_start-th_end)/(nsteps-1); double step = (th_start-th_end)/(nsteps-1);
double step2 = (th_start2-th_end2)/(nsteps2-1); double step2 = (th_start2-th_end2)/(nsteps2-1);
while( (step * max(el1->xrad, el1->yrad)) > 1.0*NM_PER_MIL while( (step * max(el1->xrad, el1->yrad)) > 1.0*NM_PER_MIL
&& (step2 * max(el2->xrad, el2->yrad)) > 1.0*NM_PER_MIL ) && (step2 * max(el2->xrad, el2->yrad)) > 1.0*NM_PER_MIL )
{ {
step = (th_start-th_end)/(nsteps-1); step = (th_start-th_end)/(nsteps-1);
for( int i=0; i<nsteps; i++ ) for( int i=0; i<nsteps; i++ )
{ {
double theta; double theta;
if( i < nsteps-1 ) if( i < nsteps-1 )
theta = th_start - i*step; theta = th_start - i*step;
else else
theta = th_end; theta = th_end;
double x = el1->Center.X + el1->xrad*cos(theta); double x = el1->Center.X + el1->xrad*cos(theta);
double y = el1->Center.Y + el1->yrad*sin(theta); double y = el1->Center.Y + el1->yrad*sin(theta);
step2 = (th_start2-th_end2)/(nsteps2-1); step2 = (th_start2-th_end2)/(nsteps2-1);
for( int i2=0; i2<nsteps2; i2++ ) for( int i2=0; i2<nsteps2; i2++ )
{ {
double theta2; double theta2;
if( i2 < nsteps2-1 ) if( i2 < nsteps2-1 )
theta2 = th_start2 - i2*step2; theta2 = th_start2 - i2*step2;
else else
theta2 = th_end2; theta2 = th_end2;
double x2 = el2->Center.X + el2->xrad*cos(theta2); double x2 = el2->Center.X + el2->xrad*cos(theta2);
double y2 = el2->Center.Y + el2->yrad*sin(theta2); double y2 = el2->Center.Y + el2->yrad*sin(theta2);
double d = Distance( x, y, x2, y2 ); double d = Distance( x, y, x2, y2 );
if( d < dmin ) if( d < dmin )
{ {
dmin = d; dmin = d;
xmin = x; xmin = x;
ymin = y; ymin = y;
thmin = theta; thmin = theta;
thmin2 = theta2; thmin2 = theta2;
} }
} }
} }
if( step > step2 ) if( step > step2 )
{ {
th_start = min(el1->theta1, thmin + step); th_start = min(el1->theta1, thmin + step);
th_end = max(el1->theta2, thmin - step); th_end = max(el1->theta2, thmin - step);
step = (th_start - th_end)/nsteps; step = (th_start - th_end)/nsteps;
} }
else else
{ {
th_start2 = min(el2->theta1, thmin2 + step2); th_start2 = min(el2->theta1, thmin2 + step2);
th_end2 = max(el2->theta2, thmin2 - step2); th_end2 = max(el2->theta2, thmin2 - step2);
step2 = (th_start2 - th_end2)/nsteps2; step2 = (th_start2 - th_end2)/nsteps2;
} }
} }
if( x1 ) if( x1 )
*x1 = xmin; *x1 = xmin;
if( y1 ) if( y1 )
*y1 = ymin; *y1 = ymin;
return dmin; return dmin;
} }
// math stuff for graphics, from FreePCB // math stuff for graphics, from FreePCB
typedef struct PointTag typedef struct PointTag
{ {
double X,Y; double X,Y;
} Point; } Point;
typedef struct EllipseTag typedef struct EllipseTag
{ {
Point Center; /* ellipse center */ Point Center; /* ellipse center */
// double MaxRad,MinRad; /* major and minor axis */ // double MaxRad,MinRad; /* major and minor axis */
// double Phi; /* major axis rotation */ // double Phi; /* major axis rotation */
double xrad, yrad; // radii on x and y double xrad, yrad; // radii on x and y
double theta1, theta2; // start and end angle for arc double theta1, theta2; // start and end angle for arc
} EllipseKH; } EllipseKH;
const CPoint zero(0,0); const CPoint zero(0,0);
class my_circle { class my_circle {
public: public:
my_circle(){}; my_circle(){};
my_circle( int xx, int yy, int rr ) my_circle( int xx, int yy, int rr )
{ {
x = xx; x = xx;
y = yy; y = yy;
r = rr; r = rr;
}; };
int x, y, r; int x, y, r;
}; };
class my_rect { class my_rect {
public: public:
my_rect(){}; my_rect(){};
my_rect( int xi, int yi, int xf, int yf ) my_rect( int xi, int yi, int xf, int yf )
{ {
xlo = min(xi,xf); xlo = min(xi,xf);
xhi = max(xi,xf); xhi = max(xi,xf);
ylo = min(yi,yf); ylo = min(yi,yf);
yhi = max(yi,yf); yhi = max(yi,yf);
}; };
int xlo, ylo, xhi, yhi; int xlo, ylo, xhi, yhi;
}; };
class my_seg { class my_seg {
public: public:
my_seg(){}; my_seg(){};
my_seg( int xxi, int yyi, int xxf, int yyf ) my_seg( int xxi, int yyi, int xxf, int yyf )
{ {
xi = xxi; xi = xxi;
yi = yyi; yi = yyi;
xf = xxf; xf = xxf;
yf = yyf; yf = yyf;
}; };
int xi, yi, xf, yf; int xi, yi, xf, yf;
}; };
// math stuff for graphics // math stuff for graphics
BOOL Quadratic( double a, double b, double c, double *x1, double *x2 ); BOOL Quadratic( double a, double b, double c, double *x1, double *x2 );
void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, BOOL bMeta=FALSE ); void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, BOOL bMeta=FALSE );
void RotatePoint( CPoint *p, int angle, CPoint org ); void RotatePoint( CPoint *p, int angle, CPoint org );
void RotateRect( CRect *r, int angle, CPoint org ); void RotateRect( CRect *r, int angle, CPoint org );
int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist ); int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist );
int FindLineIntersection( double a, double b, double c, double d, double * x, double * y ); int FindLineIntersection( double a, double b, double c, double d, double * x, double * y );
int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style, 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 * 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 FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
int xi2, int yi2, int xf2, int yf2, int style2, int xi2, int yi2, int xf2, int yf2, int style2,
double x[]=NULL, double y[]=NULL ); double x[]=NULL, double y[]=NULL );
BOOL FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 ); 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 ); BOOL FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 );
BOOL TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f, BOOL TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
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 );
void GetPadElements( int type, int x, int y, int wid, int len, int radius, int angle, void GetPadElements( int type, int x, int y, int wid, int len, int radius, int angle,
int * nr, my_rect r[], int * nc, my_circle c[], int * ns, my_seg s[] ); int * nr, my_rect r[], int * nc, my_circle c[], int * ns, my_seg s[] );
int GetClearanceBetweenPads( int type1, int x1, int y1, int w1, int l1, int r1, int angle1, int GetClearanceBetweenPads( int type1, int x1, int y1, int w1, int l1, int r1, int angle1,
int type2, int x2, int y2, int w2, int l2, int r2, int angle2 ); int type2, int x2, int y2, int w2, int l2, int r2, int angle2 );
int GetClearanceBetweenSegmentAndPad( int x1, int y1, int x2, int y2, int w, int GetClearanceBetweenSegmentAndPad( int x1, int y1, int x2, int y2, int w,
int type, int x, int y, int wid, int len, int type, int x, int y, int wid, int len,
int radius, int angle ); int radius, int angle );
int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1, 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 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 );
/** Function GetPointToLineSegmentDistance /** Function GetPointToLineSegmentDistance
* Get distance between line segment and point * Get distance between line segment and point
* @param x,y = point * @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment * @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance * @return the distance
*/ */
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 );
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 );
BOOL InRange( double x, double xi, double xf ); BOOL InRange( double x, double xi, double xf );
double Distance( int x1, int y1, int x2, int y2 ); double Distance( int x1, int y1, int x2, int y2 );
int GetArcIntersections( EllipseKH * el1, EllipseKH * el2, int GetArcIntersections( EllipseKH * el1, EllipseKH * el2,
double * x1=NULL, double * y1=NULL, double * x1=NULL, double * y1=NULL,
double * x2=NULL, double * y2=NULL ); double * x2=NULL, double * y2=NULL );
CPoint GetInflectionPoint( CPoint pi, CPoint pf, int mode ); CPoint GetInflectionPoint( CPoint pi, CPoint pf, int mode );
// quicksort (2-way or 3-way) // quicksort (2-way or 3-way)
void quickSort(int numbers[], int index[], int array_size); void quickSort(int numbers[], int index[], int array_size);
void q_sort(int numbers[], int index[], int left, int right); void q_sort(int numbers[], int index[], int left, int right);
void q_sort_3way( int a[], int b[], int left, int right ); void q_sort_3way( int a[], int b[], int left, int right );
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