// Test for intersection of sides // int CPolyLine::TestIntersection( CPolyLine * poly ) { if( !GetClosed() ) ASSERT(0); if( !poly->GetClosed() ) ASSERT(0); for( int ic=0; ic<GetNumContours(); ic++ ) { int istart = GetContourStart(ic); int iend = GetContourEnd(ic); for( int is=istart; is<=iend; is++ ) { int xi = GetX(is); int yi = GetY(is); int xf, yf; if( is < GetContourEnd(ic) ) { xf = GetX(is+1); yf = GetY(is+1); } else { xf = GetX(istart); yf = GetY(istart); } int style = GetSideStyle(is); for( int ic2=0; ic2<poly->GetNumContours(); ic2++ ) { int istart2 = poly->GetContourStart(ic2); int iend2 = poly->GetContourEnd(ic2); for( int is2=istart2; is2<=iend2; is2++ ) { int xi2 = poly->GetX(is2); int yi2 = poly->GetY(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); } int style2 = poly->GetSideStyle(is2); // test for intersection between side and side2 } } } } return 0; }
// 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.RemoveAt( ic ); if( ic != istart ) side_style.RemoveAt( ic-1 ); m_ncorners--; } else { // closed contour corner.RemoveAt( ic ); side_style.RemoveAt( ic ); if( ic == iend ) corner[ic-1].end_contour = TRUE; m_ncorners--; } if( bClosed && GetContourSize(icont) < 3 ) { // delete the entire contour RemoveContour( icont ); } if( bDraw ) Draw(); }
void CPolyLine::RemoveContour( int icont ) /******************************************/ /** * Function RemoveContour * @param icont = contour number to remove * remove a contour only if there is more than 1 contour */ { UnHatch(); int istart = GetContourStart( icont ); int iend = GetContourEnd( icont ); int polycount = GetContoursCount(); if( icont == 0 && polycount == 1 ) { // remove the only contour wxASSERT( 0 ); } else { // remove closed contour for( int ic = iend; ic>=istart; ic-- ) { m_CornersList.DeleteCorner( ic ); } } Hatch(); }
// delete corner and adjust arrays // void CPolyLine::DeleteCorner( int ic ) { UnHatch(); int icont = GetContour( ic ); int iend = GetContourEnd( icont ); bool closed = icont < GetContoursCount() - 1 || GetClosed(); if( !closed ) { // open contour, must be last contour m_CornersList.DeleteCorner( ic ); } else { // closed contour m_CornersList.DeleteCorner( ic ); if( ic == iend ) m_CornersList[ic - 1].end_contour = true; } if( closed && GetContourSize( icont ) < 3 ) { // delete the entire contour RemoveContour( icont ); } }
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.SetSize( GetContourStart(icont) ); side_style.SetSize( GetContourStart(icont) ); m_ncorners -= iend - istart + 1; } else { // remove closed contour for( int ic=iend; ic>=istart; ic-- ) { corner.RemoveAt( ic ); side_style.RemoveAt( ic ); m_ncorners--; } } Draw(); }
// test to see if a point is inside polyline // bool CPolyLine::TestPointInside( int px, int py ) { if( !GetClosed() ) { wxASSERT( 0 ); } // Test all polygons. // Since the first is the main outline, and other are holes, // if the tested point is inside only one contour, it is inside the whole polygon // (in fact inside the main outline, and outside all holes). // if inside 2 contours (the main outline + an hole), it is outside the poly. int polycount = GetContoursCount(); bool inside = false; for( int icont = 0; icont < polycount; icont++ ) { int istart = GetContourStart( icont ); int iend = GetContourEnd( icont ); // test point inside the current polygon if( TestPointInsidePolygon( m_CornersList, istart, iend, px, py ) ) inside = not inside; } return inside; }
// 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, int crosshair ) { 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, crosshair ); m_dlist->CancelHighLight(); m_dlist->Set_visible( dl_side[ic], 0 ); for( int ih=0; ih<m_nhatch; ih++ ) m_dlist->Set_visible( dl_hatch[ih], 0 ); }
// 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; }
/* * Function Distance * Calculates the distance between a segment and a polygon (with holes): * param aStart is the starting point of the segment. * param aEnd is the ending point of the segment. * param aWidth is the width of the segment. * return distance between the segment and outline. * 0 if segment intersects or is inside */ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth ) { // We calculate the min dist between the segment and each outline segment // However, if the segment to test is inside the outline, and does not cross // any edge, it can be seen outside the polygon. // Therefore test if a segment end is inside ( testing only one end is enough ) if( TestPointInside( aStart.x, aStart.y ) ) return 0; int distance = INT_MAX; int polycount = GetContoursCount(); for( int icont = 0; icont < polycount; icont++ ) { int ic_start = GetContourStart( icont ); int ic_end = GetContourEnd( icont ); // now test spacing between area outline and segment for( int ic2 = ic_start; ic2 <= ic_end; ic2++ ) { int bx1 = GetX( ic2 ); int by1 = GetY( ic2 ); int bx2, by2; if( ic2 == ic_end ) { bx2 = GetX( ic_start ); by2 = GetY( ic_start ); } else { bx2 = GetX( ic2 + 1 ); by2 = GetY( ic2 + 1 ); } int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, 1, // min clearance, should be > 0 NULL, NULL ); if( distance > d ) distance = d; if( distance <= 0 ) return 0; } } return distance; }
CRect CPolyLine::GetCornerBounds( int icont ) { CRect r; r.left = r.bottom = INT_MAX; r.right = r.top = INT_MIN; int istart = GetContourStart( icont ); int iend = GetContourEnd( icont ); for( int i=istart; i<=iend; i++ ) { r.left = min( r.left, corner[i].x ); r.right = max( r.right, corner[i].x ); r.bottom = min( r.bottom, corner[i].y ); r.top = max( r.top, corner[i].y ); } return r; }
/* * Function Distance * Calculates the distance between a point and polygon (with holes): * param aPoint is the coordinate of the point. * return distance between the point and outline. * 0 if the point is inside */ int CPolyLine::Distance( const wxPoint& aPoint ) { // We calculate the dist between the point and each outline segment // If the point is inside the outline, the dist is 0. if( TestPointInside( aPoint.x, aPoint.y ) ) return 0; int distance = INT_MAX; int polycount = GetContoursCount(); for( int icont = 0; icont < polycount; icont++ ) { int ic_start = GetContourStart( icont ); int ic_end = GetContourEnd( icont ); // now test spacing between area outline and segment for( int ic2 = ic_start; ic2 <= ic_end; ic2++ ) { int bx1 = GetX( ic2 ); int by1 = GetY( ic2 ); int bx2, by2; if( ic2 == ic_end ) { bx2 = GetX( ic_start ); by2 = GetY( ic_start ); } else { bx2 = GetX( ic2 + 1 ); by2 = GetY( ic2 + 1 ); } int d = KiROUND( GetPointToLineSegmentDistance( aPoint.x, aPoint.y, bx1, by1, bx2, by2 ) ); if( distance > d ) distance = d; if( distance <= 0 ) return 0; } } return distance; }
const EDA_RECT CPolyLine::GetBoundingBox( int icont ) { int xmin = INT_MAX; int ymin = INT_MAX; int xmax = INT_MIN; int ymax = INT_MIN; int istart = GetContourStart( icont ); int iend = GetContourEnd( icont ); for( int i = istart; i<=iend; i++ ) { xmin = std::min( xmin, m_CornersList[i].x ); xmax = std::max( xmax, m_CornersList[i].x ); ymin = std::min( ymin, m_CornersList[i].y ); ymax = std::max( ymax, m_CornersList[i].y ); } EDA_RECT r; r.SetOrigin( wxPoint( xmin, ymin ) ); r.SetEnd( wxPoint( xmax, ymax ) ); return r; }
// start dragging corner to new position, make adjacent sides and hatching invisible // void CPolyLine::StartDraggingToMoveCorner( CDC * pDC, int ic, int x, int y, int crosshair ) { 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, crosshair ); m_dlist->CancelHighLight(); m_dlist->Set_visible( dl_side[iside], 0 ); for( int ih=0; ih<m_nhatch; ih++ ) m_dlist->Set_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, crosshair ); m_dlist->CancelHighLight(); m_dlist->Set_visible( dl_side[pre_c], 0 ); m_dlist->Set_visible( dl_side[ic], 0 ); for( int ih=0; ih<m_nhatch; ih++ ) m_dlist->Set_visible( dl_hatch[ih], 0 ); } }
/** * Function IsPolygonSelfIntersecting * Test a CPolyLine for self-intersection of vertex (all contours). * * @return : * false if no intersecting sides * true if intersecting sides * When a CPolyLine is self intersectic, it need to be normalized. * (converted to non intersecting polygons) */ bool CPolyLine::IsPolygonSelfIntersecting() { // first, check for sides intersecting other sides int n_cont = GetContoursCount(); // make bounding rect for each contour std::vector<EDA_RECT> cr; cr.reserve( n_cont ); for( int icont = 0; icont<n_cont; icont++ ) cr.push_back( GetBoundingBox( icont ) ); for( int icont = 0; icont<n_cont; icont++ ) { int is_start = GetContourStart( icont ); int is_end = GetContourEnd( icont ); for( int is = is_start; is<=is_end; is++ ) { int is_prev = is - 1; if( is_prev < is_start ) is_prev = is_end; int is_next = is + 1; if( is_next > is_end ) is_next = is_start; int x1i = GetX( is ); int y1i = GetY( is ); int x1f = GetX( is_next ); int y1f = GetY( is_next ); // check for intersection with any other sides for( int icont2 = icont; icont2 < n_cont; icont2++ ) { if( !cr[icont].Intersects( cr[icont2] ) ) { // rectangles don't overlap, do nothing } else { int is2_start = GetContourStart( icont2 ); int is2_end = GetContourEnd( icont2 ); for( int is2 = is2_start; is2<=is2_end; is2++ ) { int is2_prev = is2 - 1; if( is2_prev < is2_start ) is2_prev = is2_end; int is2_next = is2 + 1; if( is2_next > is2_end ) is2_next = is2_start; if( icont != icont2 || ( is2 != is && is2 != is_prev && is2 != is_next && is != is2_prev && is != is2_next ) ) { int x2i = GetX( is2 ); int y2i = GetY( is2 ); int x2f = GetX( is2_next ); int y2f = GetY( is2_next ); int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f, x2i, y2i, x2f, y2f ); if( ret ) { // intersection between non-adjacent sides return true; } } } } } } } return false; }
CPolyLine* CPolyLine::Chamfer( unsigned int aDistance ) { CPolyLine* newPoly = new CPolyLine; if( !aDistance ) { newPoly->Copy( this ); return newPoly; } int polycount = GetContoursCount(); for( int contour = 0; contour < polycount; contour++ ) { unsigned int startIndex = GetContourStart( contour ); unsigned int endIndex = GetContourEnd( contour ); for( unsigned int index = startIndex; index <= endIndex; index++ ) { int x1, y1, nx, ny; long long xa, ya, xb, yb; x1 = m_CornersList[index].x; y1 = m_CornersList[index].y; if( index == startIndex ) { xa = m_CornersList[endIndex].x - x1; ya = m_CornersList[endIndex].y - y1; } else { xa = m_CornersList[index - 1].x - x1; ya = m_CornersList[index - 1].y - y1; } if( index == endIndex ) { xb = m_CornersList[startIndex].x - x1; yb = m_CornersList[startIndex].y - y1; } else { xb = m_CornersList[index + 1].x - x1; yb = m_CornersList[index + 1].y - y1; } unsigned int lena = KiROUND( hypot( xa, ya ) ); unsigned int lenb = KiROUND( hypot( xb, yb ) ); unsigned int distance = aDistance; // Chamfer one half of an edge at most if( 0.5 * lena < distance ) distance = int( 0.5 * lena ); if( 0.5 * lenb < distance ) distance = int( 0.5 * lenb ); nx = KiROUND( (distance * xa) / hypot( xa, ya ) ); ny = KiROUND( (distance * ya) / hypot( xa, ya ) ); if( index == startIndex ) newPoly->Start( GetLayer(), x1 + nx, y1 + ny, GetHatchStyle() ); else newPoly->AppendCorner( x1 + nx, y1 + ny ); nx = KiROUND( (distance * xb) / hypot( xb, yb ) ); ny = KiROUND( (distance * yb) / hypot( xb, yb ) ); newPoly->AppendCorner( x1 + nx, y1 + ny ); } newPoly->CloseLastContour(); } return newPoly; }
// 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, CArray<CArc> * 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) int i=0, j=0; 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 int i=0, j=0; 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; is<n; is++ ) { double theta = theta1 + ((theta2-theta1)*(double)is)/n; double x = xo + a*cos(theta); double y = yo + b*sin(theta); if( is == 0 ) { x = x1; y = y1; } g_v_list->vertex[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; }
CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments ) { CPolyLine* newPoly = new CPolyLine; if( !aRadius ) { newPoly->Copy( this ); return newPoly; } int polycount = GetContoursCount(); for( int contour = 0; contour < polycount; contour++ ) { unsigned int startIndex = GetContourStart( contour ); unsigned int endIndex = GetContourEnd( contour ); for( unsigned int index = startIndex; index <= endIndex; index++ ) { int x1, y1; // Current vertex long long xa, ya; // Previous vertex long long xb, yb; // Next vertex double nx, ny; x1 = m_CornersList[index].x; y1 = m_CornersList[index].y; if( index == startIndex ) { xa = m_CornersList[endIndex].x - x1; ya = m_CornersList[endIndex].y - y1; } else { xa = m_CornersList[index - 1].x - x1; ya = m_CornersList[index - 1].y - y1; } if( index == endIndex ) { xb = m_CornersList[startIndex].x - x1; yb = m_CornersList[startIndex].y - y1; } else { xb = m_CornersList[index + 1].x - x1; yb = m_CornersList[index + 1].y - y1; } double lena = hypot( xa, ya ); double lenb = hypot( xb, yb ); double cosine = ( xa * xb + ya * yb ) / ( lena * lenb ); double radius = aRadius; double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 ); // Do nothing in case of parallel edges if( std::isinf( denom ) ) continue; // Limit rounding distance to one half of an edge if( 0.5 * lena * denom < radius ) radius = 0.5 * lena * denom; if( 0.5 * lenb * denom < radius ) radius = 0.5 * lenb * denom; // Calculate fillet arc absolute center point (xc, yx) double k = radius / sqrt( .5 * ( 1 - cosine ) ); double lenab = sqrt( ( xa / lena + xb / lenb ) * ( xa / lena + xb / lenb ) + ( ya / lena + yb / lenb ) * ( ya / lena + yb / lenb ) ); double xc = x1 + k * ( xa / lena + xb / lenb ) / lenab; double yc = y1 + k * ( ya / lena + yb / lenb ) / lenab; // Calculate arc start and end vectors k = radius / sqrt( 2 / ( 1 + cosine ) - 1 ); double xs = x1 + k * xa / lena - xc; double ys = y1 + k * ya / lena - yc; double xe = x1 + k * xb / lenb - xc; double ye = y1 + k * yb / lenb - yc; // Cosine of arc angle double argument = ( xs * xe + ys * ye ) / ( radius * radius ); if( argument < -1 ) // Just in case... argument = -1; else if( argument > 1 ) argument = 1; double arcAngle = acos( argument ); // Calculate the number of segments double tempSegments = (double) aSegments * ( arcAngle / ( 2 * M_PI ) ); if( tempSegments - (int) tempSegments > 0 ) tempSegments++; unsigned int segments = (unsigned int) tempSegments; double deltaAngle = arcAngle / segments; double startAngle = atan2( -ys, xs ); // Flip arc for inner corners if( xa * yb - ya * xb <= 0 ) deltaAngle *= -1; nx = xc + xs; ny = yc + ys; if( index == startIndex ) newPoly->Start( GetLayer(), KiROUND( nx ), KiROUND( ny ), GetHatchStyle() ); else newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) ); for( unsigned int j = 0; j < segments; j++ ) { nx = xc + cos( startAngle + (j + 1) * deltaAngle ) * radius; ny = yc - sin( startAngle + (j + 1) * deltaAngle ) * radius; newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) ); } } newPoly->CloseLastContour(); } return newPoly; }
// 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[m_ncorners-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<MAXPTS ); // overflow } if( ok == 2 ) { xx[npts] = (int)x2; yy[npts] = (int)y2; npts++; ASSERT( npts<MAXPTS ); // overflow } } nloops++; a += PCBU_PER_MIL/100; } while( npts%2 != 0 && nloops < 3 ); ASSERT( npts%2==0 ); // odd number of intersection points, error // count intersection points to right of (x,y), if odd (x,y) is inside polyline int ncount = 0; for( int ip=0; ip<npts; ip++ ) { if( xx[ip] == x && yy[ip] == y ) return FALSE; // (x,y) is on a side, call it outside else if( xx[ip] > x ) ncount++; } if( ncount%2 ) return TRUE; else return FALSE; }
int CPolyLine::GetContourSize( int icont ) { return GetContourEnd(icont) - GetContourStart(icont) + 1; }