// 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 = DSS_STRAIGHT, style2 = DSS_STRAIGHT; 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 = DL_LINE; 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 = 0; 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 = INT_MIN; 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; }