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