|
|
@ -13,143 +13,6 @@ using namespace std; |
|
|
|
#include "PolyLine.h"
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// enter with:
|
|
|
|
// pi = start point
|
|
|
|
// pf = end point
|
|
|
|
// mode = IM_90_45 or IM_45_90 or IM_90
|
|
|
|
//
|
|
|
|
CPoint GetInflectionPoint( CPoint pi, CPoint pf, int mode ) |
|
|
|
{ |
|
|
|
CPoint p = pi; |
|
|
|
if( mode == IM_NONE ) |
|
|
|
return p; |
|
|
|
|
|
|
|
int dx = pf.x - pi.x; |
|
|
|
int dy = pf.y - pi.y; |
|
|
|
if( dx == 0 || dy == 0 || abs(dx) == abs(dy) ) |
|
|
|
{ |
|
|
|
// only one segment needed
|
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if( abs(dy) > abs(dx) ) |
|
|
|
{ |
|
|
|
// vertical > horizontal
|
|
|
|
if( mode == IM_90 ) |
|
|
|
{ |
|
|
|
p.x = pi.x; |
|
|
|
p.y = pf.y; |
|
|
|
} |
|
|
|
else if( mode == IM_45_90 || mode == IM_90_45 ) |
|
|
|
{ |
|
|
|
int vert; // length of vertical line needed
|
|
|
|
if( dy > 0 ) |
|
|
|
vert = dy - abs(dx); // positive
|
|
|
|
else |
|
|
|
vert = dy + abs(dx); // negative
|
|
|
|
if( mode == IM_90_45 ) |
|
|
|
p.y = pi.y + vert; |
|
|
|
else if( mode == IM_45_90 ) |
|
|
|
{ |
|
|
|
p.y = pf.y - vert; |
|
|
|
p.x = pf.x; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
wxASSERT(0); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// horizontal > vertical
|
|
|
|
if( mode == IM_90 ) |
|
|
|
{ |
|
|
|
p.x = pf.x; |
|
|
|
p.y = pi.y; |
|
|
|
} |
|
|
|
else if( mode == IM_45_90 || mode == IM_90_45 ) |
|
|
|
{ |
|
|
|
int hor; // length of horizontal line needed
|
|
|
|
if( dx > 0 ) |
|
|
|
hor = dx - abs(dy); // positive
|
|
|
|
else |
|
|
|
hor = dx + abs(dy); // negative
|
|
|
|
if( mode == IM_90_45 ) |
|
|
|
p.x = pi.x + hor; |
|
|
|
else if( mode == IM_45_90 ) |
|
|
|
{ |
|
|
|
p.x = pf.x - hor; |
|
|
|
p.y = pf.y; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
wxASSERT(0); |
|
|
|
} |
|
|
|
} |
|
|
|
return p; |
|
|
|
} |
|
|
|
|
|
|
|
//
|
|
|
|
// function to rotate a point clockwise about another point
|
|
|
|
// currently, angle must be 0, 90, 180 or 270
|
|
|
|
//
|
|
|
|
void RotatePoint( CPoint *p, int angle, CPoint org ) |
|
|
|
{ |
|
|
|
if( angle == 90 ) |
|
|
|
{ |
|
|
|
int tempy = org.y + (org.x - p->x); |
|
|
|
p->x = org.x + (p->y - org.y); |
|
|
|
p->y = tempy; |
|
|
|
} |
|
|
|
else if( angle > 90 ) |
|
|
|
{ |
|
|
|
for( int i=0; i<(angle/90); i++ ) |
|
|
|
RotatePoint( p, 90, org ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// function to rotate a rectangle clockwise about a point
|
|
|
|
// angle must be 0, 90, 180 or 270
|
|
|
|
// on exit, r->top > r.bottom, r.right > r.left
|
|
|
|
//
|
|
|
|
void RotateRect( CRect *r, int angle, CPoint org ) |
|
|
|
{ |
|
|
|
CRect tr; |
|
|
|
if( angle == 90 ) |
|
|
|
{ |
|
|
|
tr.left = org.x + (r->bottom - org.y); |
|
|
|
tr.right = org.x + (r->top - org.y); |
|
|
|
tr.top = org.y + (org.x - r->right); |
|
|
|
tr.bottom = org.y + (org.x - r->left); |
|
|
|
if( tr.left > tr.right ) |
|
|
|
{ |
|
|
|
int temp = tr.right; |
|
|
|
tr.left = tr.right; |
|
|
|
tr.left = temp; |
|
|
|
} |
|
|
|
if( tr.left > tr.right ) |
|
|
|
{ |
|
|
|
int temp = tr.right; |
|
|
|
tr.left = tr.right; |
|
|
|
tr.left = temp; |
|
|
|
} |
|
|
|
if( tr.bottom > tr.top ) |
|
|
|
{ |
|
|
|
int temp = tr.bottom; |
|
|
|
tr.bottom = tr.top; |
|
|
|
tr.top = temp; |
|
|
|
} |
|
|
|
} |
|
|
|
else if( angle > 90 ) |
|
|
|
{ |
|
|
|
tr = *r; |
|
|
|
for( int i=0; i<(angle/90); i++ ) |
|
|
|
RotateRect( &tr, 90, org ); |
|
|
|
} |
|
|
|
*r = tr; |
|
|
|
} |
|
|
|
|
|
|
|
// test for hit on line segment
|
|
|
|
// i.e. cursor within a given distance from segment
|
|
|
|
// enter with: x,y = cursor coords
|
|
|
@ -206,15 +69,6 @@ int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist ) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// find intersection between y = a + bx and y = c + dx;
|
|
|
|
//
|
|
|
|
int FindLineIntersection( double a, double b, double c, double d, double * x, double * y ) |
|
|
|
{ |
|
|
|
*x = (c-a)/(b-d); |
|
|
|
*y = a + b*(*x); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
// set EllipseKH struct to describe the ellipse for an arc
|
|
|
|
//
|
|
|
|
int MakeEllipseFromArc( int xi, int yi, int xf, int yf, int style, EllipseKH * el ) |
|
|
@ -875,250 +729,6 @@ bool FindLineEllipseIntersections( double a, double b, double c, double d, doubl |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// 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 ) |
|
|
|
{ |
|
|
|
int xi, yi, xf, yf; |
|
|
|
if( shape == DL_LINE || xxi == xxf || yyi == yyf ) |
|
|
|
{ |
|
|
|
// draw straight line
|
|
|
|
pDC->MoveTo( xxi, yyi ); |
|
|
|
pDC->LineTo( xxf, yyf ); |
|
|
|
} |
|
|
|
else if( shape == DL_ARC_CCW || shape == DL_ARC_CW ) |
|
|
|
{ |
|
|
|
// set endpoints so we can always draw counter-clockwise arc
|
|
|
|
if( shape == DL_ARC_CW ) |
|
|
|
{ |
|
|
|
xi = xxf; |
|
|
|
yi = yyf; |
|
|
|
xf = xxi; |
|
|
|
yf = yyi; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
xi = xxi; |
|
|
|
yi = yyi; |
|
|
|
xf = xxf; |
|
|
|
yf = yyf; |
|
|
|
} |
|
|
|
pDC->MoveTo( xi, yi ); |
|
|
|
if( xf > xi && yf > yi ) |
|
|
|
{ |
|
|
|
// quadrant 1
|
|
|
|
int w = (xf-xi)*2; |
|
|
|
int h = (yf-yi)*2; |
|
|
|
if( !bMeta ) |
|
|
|
pDC->Arc( xf-w, yi+h, xf, yi, |
|
|
|
xi, yi, xf, yf ); |
|
|
|
else |
|
|
|
pDC->Arc( xf-w, yi, xf, yi+h, |
|
|
|
xf, yf, xi, yi ); |
|
|
|
} |
|
|
|
else if( xf < xi && yf > yi ) |
|
|
|
{ |
|
|
|
// quadrant 2
|
|
|
|
int w = -(xf-xi)*2; |
|
|
|
int h = (yf-yi)*2; |
|
|
|
if( !bMeta ) |
|
|
|
pDC->Arc( xi-w, yf, xi, yf-h, |
|
|
|
xi, yi, xf, yf ); |
|
|
|
else |
|
|
|
pDC->Arc( xi-w, yf-h, xi, yf, |
|
|
|
xf, yf, xi, yi ); |
|
|
|
} |
|
|
|
else if( xf < xi && yf < yi ) |
|
|
|
{ |
|
|
|
// quadrant 3
|
|
|
|
int w = -(xf-xi)*2; |
|
|
|
int h = -(yf-yi)*2; |
|
|
|
if( !bMeta ) |
|
|
|
pDC->Arc( xf, yi, xf+w, yi-h, |
|
|
|
xi, yi, xf, yf ); |
|
|
|
else |
|
|
|
pDC->Arc( xf, yi-h, xf+w, yi, |
|
|
|
xf, yf, xi, yi ); |
|
|
|
} |
|
|
|
else if( xf > xi && yf < yi ) |
|
|
|
{ |
|
|
|
// quadrant 4
|
|
|
|
int w = (xf-xi)*2; |
|
|
|
int h = -(yf-yi)*2; |
|
|
|
if( !bMeta ) |
|
|
|
pDC->Arc( xi, yf+h, xi+w, yf, |
|
|
|
xi, yi, xf, yf ); |
|
|
|
else |
|
|
|
pDC->Arc( xi, yf, xi+w, yf+h, |
|
|
|
xf, yf, xi, yi ); |
|
|
|
} |
|
|
|
pDC->MoveTo( xxf, yyf ); |
|
|
|
} |
|
|
|
else |
|
|
|
wxASSERT(0); // oops
|
|
|
|
} |
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Get arrays of circles, rects and line segments to represent pad
|
|
|
|
// for purposes of drawing pad or calculating clearances
|
|
|
|
// margins of circles and line segments represent pad outline
|
|
|
|
// 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, |
|
|
|
int * nr, my_rect r[], int * nc, my_circle c[], int * ns, my_seg s[] ) |
|
|
|
{ |
|
|
|
*nc = 0; |
|
|
|
*nr = 0; |
|
|
|
*ns = 0; |
|
|
|
if( type == PAD_ROUND ) |
|
|
|
{ |
|
|
|
*nc = 1; |
|
|
|
c[0] = my_circle(x,y,wid/2); |
|
|
|
return; |
|
|
|
} |
|
|
|
if( type == PAD_SQUARE ) |
|
|
|
{ |
|
|
|
*nr = 1; |
|
|
|
r[0] = my_rect(x-wid/2, y-wid/2,x+wid/2, y+wid/2); |
|
|
|
*ns = 4; |
|
|
|
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[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
|
|
|
|
return; |
|
|
|
} |
|
|
|
if( type == PAD_OCTAGON ) |
|
|
|
{ |
|
|
|
const double pi = 3.14159265359; |
|
|
|
*nc = 1; // circle represents inside of polygon
|
|
|
|
c[0] = my_circle(x, y, wid/2); |
|
|
|
*ns = 8; // now create sides of polygon
|
|
|
|
double theta = pi/8.0; |
|
|
|
double radius = 0.5*(double)wid/cos(theta); |
|
|
|
double last_x = x + radius*cos(theta); |
|
|
|
double last_y = y + radius*sin(theta); |
|
|
|
for( int is=0; is<8; is++ ) |
|
|
|
{ |
|
|
|
theta += pi/4.0; |
|
|
|
double dx = x + radius*cos(theta); |
|
|
|
double dy = y + radius*sin(theta); |
|
|
|
s[is] = my_seg((int) last_x, (int) last_y, x, y); |
|
|
|
last_x = dx; |
|
|
|
last_y = dy; |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
//
|
|
|
|
int h; |
|
|
|
int v; |
|
|
|
if( angle == 90 || angle == 270 ) |
|
|
|
{ |
|
|
|
h = wid; |
|
|
|
v = len; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
v = wid; |
|
|
|
h = len; |
|
|
|
} |
|
|
|
if( type == PAD_RECT ) |
|
|
|
{ |
|
|
|
*nr = 1; |
|
|
|
r[0] = my_rect(x-h/2, y-v/2, x+h/2, y+v/2); |
|
|
|
*ns = 4; |
|
|
|
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[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
|
|
|
|
return; |
|
|
|
} |
|
|
|
if( type == PAD_RRECT ) |
|
|
|
{ |
|
|
|
*nc = 4; |
|
|
|
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[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
|
|
|
|
*ns = 4; |
|
|
|
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[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
|
|
|
|
return; |
|
|
|
} |
|
|
|
if( type == PAD_OVAL ) |
|
|
|
{ |
|
|
|
if( h > v ) |
|
|
|
{ |
|
|
|
// horizontal
|
|
|
|
*nc = 2; |
|
|
|
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
|
|
|
|
*nr = 1; |
|
|
|
r[0] = my_rect(x-h/2+v/2, y-v/2, x+h/2-v/2, y+v/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[1] = my_seg(x-h/2+v/2, y-v/2, x+h/2-v/2, y-v/2); // bottom
|
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// vertical
|
|
|
|
*nc = 2; |
|
|
|
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
|
|
|
|
*nr = 1; |
|
|
|
r[0] = my_rect(x-h/2, y-v/2+h/2, x+h/2, y+v/2-h/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[1] = my_seg(x+h/2, y-v/2+h/2, x+h/2, y+v/2-h/2); // left
|
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
wxASSERT(0); |
|
|
|
} |
|
|
|
|
|
|
|
// Find distance from a staright line segment to a pad
|
|
|
|
//
|
|
|
|
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 ) |
|
|
|
{ |
|
|
|
if( type == PAD_NONE ) |
|
|
|
return INT_MAX; |
|
|
|
else |
|
|
|
{ |
|
|
|
int nc, nr, ns; |
|
|
|
my_circle c[4]; |
|
|
|
my_rect r[2]; |
|
|
|
my_seg s[8]; |
|
|
|
GetPadElements( type, x, y, wid, len, radius, angle, |
|
|
|
&nr, r, &nc, c, &ns, s ); |
|
|
|
// first test for endpoints of line segment in rectangle
|
|
|
|
for( int ir=0; ir<nr; ir++ ) |
|
|
|
{ |
|
|
|
if( x1 >= r[ir].xlo && x1 <= r[ir].xhi && y1 >= r[ir].ylo && y1 <= r[ir].yhi ) |
|
|
|
return 0; |
|
|
|
if( x2 >= r[ir].xlo && x2 <= r[ir].xhi && y2 >= r[ir].ylo && y2 <= r[ir].yhi ) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
// now get distance from elements of pad outline
|
|
|
|
int dist = INT_MAX; |
|
|
|
for( int ic=0; ic<nc; ic++ ) |
|
|
|
{ |
|
|
|
int d = (int)GetPointToLineSegmentDistance( c[ic].x, c[ic].y, x1, y1, x2, y2 ) - c[ic].r - w/2; |
|
|
|
dist = min(dist,d); |
|
|
|
} |
|
|
|
for( int is=0; is<ns; is++ ) |
|
|
|
{ |
|
|
|
double d; |
|
|
|
TestForIntersectionOfStraightLineSegments( s[is].xi, s[is].yi, s[is].xf, s[is].yf, |
|
|
|
x1, y1, x2, y2, NULL, NULL, &d ); |
|
|
|
dist = min(dist, (int)d - w/2); |
|
|
|
} |
|
|
|
return max(0,dist); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Get clearance between 2 segments
|
|
|
|
// Returns point in segment closest to other segment in x, y
|
|
|
@ -1300,67 +910,6 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Find clearance between pads
|
|
|
|
// For each pad:
|
|
|
|
// type = PAD_ROUND, PAD_SQUARE, etc.
|
|
|
|
// x, y = center position
|
|
|
|
// w, l = width and length
|
|
|
|
// r = corner radius
|
|
|
|
// 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 type2, int x2, int y2, int w2, int l2, int r2, int angle2 ) |
|
|
|
{ |
|
|
|
if( type1 == PAD_NONE ) |
|
|
|
return INT_MAX; |
|
|
|
if( type2 == PAD_NONE ) |
|
|
|
return INT_MAX; |
|
|
|
|
|
|
|
int dist = INT_MAX; |
|
|
|
int nr, nc, ns, nrr, ncc, nss; |
|
|
|
my_rect r[2], rr[2]; |
|
|
|
my_circle c[4], cc[4]; |
|
|
|
my_seg s[8], ss[8]; |
|
|
|
|
|
|
|
GetPadElements( type1, x1, y1, w1, l1, r1, angle1, |
|
|
|
&nr, r, &nc, c, &ns, s ); |
|
|
|
GetPadElements( type2, x2, y2, w2, l2, r2, angle2, |
|
|
|
&nrr, rr, &ncc, cc, &nss, ss ); |
|
|
|
// now find distance from every element of pad1 to every element of pad2
|
|
|
|
for( int ic=0; ic<nc; ic++ ) |
|
|
|
{ |
|
|
|
for( int icc=0; icc<ncc; icc++ ) |
|
|
|
{ |
|
|
|
int d = (int) Distance( c[ic].x, c[ic].y, cc[icc].x, cc[icc].y ) |
|
|
|
- c[ic].r - cc[icc].r; |
|
|
|
dist = min(dist,d); |
|
|
|
} |
|
|
|
for( int iss=0; iss<nss; iss++ ) |
|
|
|
{ |
|
|
|
int d = (int) GetPointToLineSegmentDistance( c[ic].x, c[ic].y, |
|
|
|
ss[iss].xi, ss[iss].yi, ss[iss].xf, ss[iss].yf ) - c[ic].r; |
|
|
|
dist = min(dist,d); |
|
|
|
} |
|
|
|
} |
|
|
|
for( int is=0; is<ns; is++ ) |
|
|
|
{ |
|
|
|
for( int icc=0; icc<ncc; icc++ ) |
|
|
|
{ |
|
|
|
int d = (int) GetPointToLineSegmentDistance( cc[icc].x, cc[icc].y, |
|
|
|
s[is].xi, s[is].yi, s[is].xf, s[is].yf ) - cc[icc].r; |
|
|
|
dist = min(dist,d); |
|
|
|
} |
|
|
|
for( int iss=0; iss<nss; iss++ ) |
|
|
|
{ |
|
|
|
double d; |
|
|
|
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 ); |
|
|
|
dist = min(dist, (int)d); |
|
|
|
} |
|
|
|
} |
|
|
|
return max(dist,0); |
|
|
|
} |
|
|
|
|
|
|
|
// Get min. distance from (x,y) to line y = a + bx
|
|
|
|
// if b > DBL_MAX/10, assume vertical line at x = a
|
|
|
|
// returns closest point on line in xp, yp
|
|
|
|