// 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; }
/* * Function TestForIntersectionOfStraightLineSegments * Test for intersection of line segments * If lines are parallel, returns false * If true, returns also intersection coords in x, y * if false, returns min. distance in dist (may be 0.0 if parallel) */ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f, int x2i, int y2i, int x2f, int y2f, int* x, int* y, double* d ) { double a, b, dist; // first, test for intersection if( x1i == x1f && x2i == x2f ) { // both segments are vertical, can't intersect } else if( y1i == y1f && y2i == y2f ) { // both segments are horizontal, can't intersect } else if( x1i == x1f && y2i == y2f ) { // first seg. vertical, second horizontal, see if they cross if( InRange( x1i, x2i, x2f ) && InRange( y2i, y1i, y1f ) ) { if( x ) *x = x1i; if( y ) *y = y2i; if( d ) *d = 0.0; return true; } } else if( y1i == y1f && x2i == x2f ) { // first seg. horizontal, second vertical, see if they cross if( InRange( y1i, y2i, y2f ) && InRange( x2i, x1i, x1f ) ) { if( x ) *x = x2i; if( y ) *y = y1i; if( d ) *d = 0.0; return true; } } else if( x1i == x1f ) { // first segment vertical, second oblique // get a and b for second line segment, so that y = a + bx; b = double( y2f - y2i ) / (x2f - x2i); a = (double) y2i - b * x2i; double x1, y1, x2, y2; int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f, &x1, &y1, &x2, &y2 ); if( test ) { if( InRange( y1, y1i, y1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) ) { if( x ) *x = KiROUND( x1 ); if( y ) *y = KiROUND( y1 ); if( d ) *d = 0.0; return true; } } } else if( y1i == y1f ) { // first segment horizontal, second oblique // get a and b for second line segment, so that y = a + bx; b = double( y2f - y2i ) / (x2f - x2i); a = (double) y2i - b * x2i; double x1, y1, x2, y2; int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f, &x1, &y1, &x2, &y2 ); if( test ) { if( InRange( x1, x1i, x1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) ) { if( x ) *x = KiROUND( x1 ); if( y ) *y = KiROUND( y1 ); if( d ) *d = 0.0; return true; } } } else if( x2i == x2f ) { // second segment vertical, first oblique // get a and b for first line segment, so that y = a + bx; b = double( y1f - y1i ) / (x1f - x1i); a = (double) y1i - b * x1i; double x1, y1, x2, y2; int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, &x1, &y1, &x2, &y2 ); if( test ) { if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) && InRange( y1, y2i, y2f ) ) { if( x ) *x = KiROUND( x1 ); if( y ) *y = KiROUND( y1 ); if( d ) *d = 0.0; return true; } } } else if( y2i == y2f ) { // second segment horizontal, first oblique // get a and b for second line segment, so that y = a + bx; b = double( y1f - y1i ) / (x1f - x1i); a = (double) y1i - b * x1i; double x1, y1, x2, y2; int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, &x1, &y1, &x2, &y2 ); if( test ) { if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) ) { if( x ) *x = KiROUND( x1 ); if( y ) *y = KiROUND( y1 ); if( d ) *d = 0.0; return true; } } } else { // both segments oblique if( long( y1f - y1i ) * (x2f - x2i) != long( y2f - y2i ) * (x1f - x1i) ) { // not parallel, get a and b for first line segment, so that y = a + bx; b = double( y1f - y1i ) / (x1f - x1i); a = (double) y1i - b * x1i; double x1, y1, x2, y2; int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, &x1, &y1, &x2, &y2 ); // both segments oblique if( test ) { if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) ) { if( x ) *x = KiROUND( x1 ); if( y ) *y = KiROUND( y1 ); if( d ) *d = 0.0; return true; } } } } // don't intersect, get shortest distance between each endpoint and the other line segment dist = GetPointToLineSegmentDistance( x1i, y1i, x2i, y2i, x2f, y2f ); double xx = x1i; double yy = y1i; double dd = GetPointToLineSegmentDistance( x1f, y1f, x2i, y2i, x2f, y2f ); if( dd < dist ) { dist = dd; xx = x1f; yy = y1f; } dd = GetPointToLineSegmentDistance( x2i, y2i, x1i, y1i, x1f, y1f ); if( dd < dist ) { dist = dd; xx = x2i; yy = y2i; } dd = GetPointToLineSegmentDistance( x2f, y2f, x1i, y1i, x1f, y1f ); if( dd < dist ) { dist = dd; xx = x2f; yy = y2f; } if( x ) *x = KiROUND( xx ); if( y ) *y = KiROUND( yy ); if( d ) *d = dist; return false; }
// draw hatch lines // void CPolyLine::Hatch(CDL_job *pDL_job) { if( m_hatch == NO_HATCH ) { m_nhatch = 0; return; } if( m_dlist && GetClosed() ) { enum { MAXPTS = 100, MAXLINES = 1000 }; dl_hatch.SetSize( MAXLINES, MAXLINES ); int xx[MAXPTS], yy[MAXPTS]; // define range for hatch lines int min_x = corner[0].x; int max_x = corner[0].x; int min_y = corner[0].y; int max_y = corner[0].y; for( int ic=1; ic<m_ncorners; ic++ ) { if( corner[ic].x < min_x ) min_x = corner[ic].x; if( corner[ic].x > 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 = 1 - 2*(m_layer%2); // 1 or -1 double slope = 0.707106*slope_flag; //slope=0; int spacing; if( m_hatch == DIAGONAL_EDGE ) spacing = 10*PCBU_PER_MIL; else spacing = 6*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( m_layer < (LAY_TOP_COPPER+2) ) offset = 0; else if( m_layer < (LAY_TOP_COPPER+4) ) offset = spacing/2; else if( m_layer < (LAY_TOP_COPPER+6) ) offset = spacing/4; else if( m_layer < (LAY_TOP_COPPER+8) ) offset = 3*spacing/4; else if( m_layer < (LAY_TOP_COPPER+10) ) offset = 1*spacing/8; else if( m_layer < (LAY_TOP_COPPER+12) ) offset = 3*spacing/8; else if( m_layer < (LAY_TOP_COPPER+14) ) offset = 5*spacing/8; else if( m_layer < (LAY_TOP_COPPER+16) ) offset = 7*spacing/8; else ASSERT(0); min_a += offset; // now calculate and draw hatch lines int nc = m_ncorners; int nhatch = 0; // loop through hatch lines for( int a=min_a; a<max_a; a+=spacing ) { // get intersection points for this hatch line int nloops = 0; int npts; // make this a loop in case my homebrew hatching algorithm screws up do { npts = 0; int i_start_contour = 0; for( int ic=0; ic<nc; ic++ ) { double x, y, x2, y2; int ok; if( corner[ic].end_contour ) { ok = FindLineSegmentIntersection( a, slope, corner[ic].x, corner[ic].y, corner[i_start_contour].x, corner[i_start_contour].y, side_style[ic], &x, &y, &x2, &y2 ); i_start_contour = ic + 1; } else { ok = FindLineSegmentIntersection( a, slope, corner[ic].x, corner[ic].y, corner[ic+1].x, corner[ic+1].y, side_style[ic], &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 // sort points in order of descending x (if more than 2) if( npts>2 ) { for( int istart=0; istart<(npts-1); istart++ ) { int max_x = INT_MIN; int imax; for( int i=istart; i<npts; i++ ) { if( xx[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 int width = spacing/3; for( int ip=0; ip<npts; ip+=2 ) { id hatch_id = m_id; hatch_id.sst = ID_HATCH; hatch_id.ii = nhatch; int dx = xx[ip+1] - xx[ip]; const int edge_width = 20; if( m_hatch == DIAGONAL_FULL || abs(dx) < edge_width*2*NM_PER_MIL ) { dl_element * dl = m_dlist->Add( pDL_job, hatch_id, 0, m_layer, DL_LINE, 1, width, 0, 0, xx[ip], yy[ip], xx[ip+1], yy[ip+1], 0, 0 ); dl_hatch.SetAtGrow(nhatch, dl); nhatch++; } else { int dy = yy[ip+1] - yy[ip]; double slope = double(dy)/dx; if( dx > 0 ) dx = edge_width*NM_PER_MIL; else dx = -edge_width*NM_PER_MIL; int x1 = xx[ip] + dx; int x2 = xx[ip+1] - dx; int y1 = yy[ip] + dx*slope; int y2 = yy[ip+1] - dx*slope; dl_element * dl; dl = m_dlist->Add( pDL_job, hatch_id, 0, m_layer, DL_LINE, 1, width, 0, 0, xx[ip], yy[ip], x1, y1, 0, 0 ); dl_hatch.SetAtGrow(nhatch, dl); dl = m_dlist->Add( pDL_job, hatch_id, 0, m_layer, DL_LINE, 1, width, 0, 0, xx[ip+1], yy[ip+1], x2, y2, 0, 0 ); dl_hatch.SetAtGrow(nhatch+1, dl); nhatch += 2; } } } // end for m_nhatch = nhatch; dl_hatch.SetSize( m_nhatch ); } }
void CPolyLine::Hatch() { m_HatchLines.clear(); if( m_hatchStyle == NO_HATCH || m_hatchPitch == 0 ) return; if( !GetClosed() ) // If not closed, the poly is beeing created and not finalised. Not not hatch return; // define range for hatch lines int min_x = m_CornersList[0].x; int max_x = m_CornersList[0].x; int min_y = m_CornersList[0].y; int max_y = m_CornersList[0].y; for( unsigned ic = 1; ic < m_CornersList.GetCornersCount(); ic++ ) { if( m_CornersList[ic].x < min_x ) min_x = m_CornersList[ic].x; if( m_CornersList[ic].x > max_x ) max_x = m_CornersList[ic].x; if( m_CornersList[ic].y < min_y ) min_y = m_CornersList[ic].y; if( m_CornersList[ic].y > max_y ) max_y = m_CornersList[ic].y; } // Calculate spacing between 2 hatch lines int spacing; if( m_hatchStyle == DIAGONAL_EDGE ) spacing = m_hatchPitch; else spacing = m_hatchPitch * 2; // set the "length" of hatch lines (the lenght on horizontal axis) double hatch_line_len = m_hatchPitch; // To have a better look, give a slope depending on the layer LAYER_NUM layer = GetLayer(); int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1 double slope = 0.707106 * slope_flag; // 45 degrees slope int max_a, min_a; if( slope_flag == 1 ) { max_a = KiROUND( max_y - slope * min_x ); min_a = KiROUND( min_y - slope * max_x ); } else { max_a = KiROUND( max_y - slope * max_x ); min_a = KiROUND( min_y - slope * min_x ); } min_a = (min_a / spacing) * spacing; // calculate an offset depending on layer number, // for a better look of hatches on a multilayer board int offset = (layer * 7) / 8; min_a += offset; // now calculate and draw hatch lines int nc = m_CornersList.GetCornersCount(); // loop through hatch lines #define MAXPTS 200 // Usually we store only few values per one hatch line // depending on the compexity of the zone outline static std::vector <wxPoint> pointbuffer; pointbuffer.clear(); pointbuffer.reserve( MAXPTS + 2 ); for( int a = min_a; a < max_a; a += spacing ) { // get intersection points for this hatch line // Note: because we should have an even number of intersections with the // current hatch line and the zone outline (a closed polygon, // or a set of closed polygons), if an odd count is found // we skip this line (should not occur) pointbuffer.clear(); int i_start_contour = 0; for( int ic = 0; ic<nc; ic++ ) { double x, y, x2, y2; int ok; if( m_CornersList[ic].end_contour || ( ic == (int) (m_CornersList.GetCornersCount() - 1) ) ) { ok = FindLineSegmentIntersection( a, slope, m_CornersList[ic].x, m_CornersList[ic].y, m_CornersList[i_start_contour].x, m_CornersList[i_start_contour].y, &x, &y, &x2, &y2 ); i_start_contour = ic + 1; } else { ok = FindLineSegmentIntersection( a, slope, m_CornersList[ic].x, m_CornersList[ic].y, m_CornersList[ic + 1].x, m_CornersList[ic + 1].y, &x, &y, &x2, &y2 ); } if( ok ) { wxPoint point( KiROUND( x ), KiROUND( y ) ); pointbuffer.push_back( point ); } if( ok == 2 ) { wxPoint point( KiROUND( x2 ), KiROUND( y2 ) ); pointbuffer.push_back( point ); } if( pointbuffer.size() >= MAXPTS ) // overflow { wxASSERT( 0 ); break; } } // ensure we have found an even intersection points count // because intersections are the ends of segments // inside the polygon(s) and a segment has 2 ends. // if not, this is a strange case (a bug ?) so skip this hatch if( pointbuffer.size() % 2 != 0 ) continue; // sort points in order of descending x (if more than 2) to // ensure the starting point and the ending point of the same segment // are stored one just after the other. if( pointbuffer.size() > 2 ) sort( pointbuffer.begin(), pointbuffer.end(), sort_ends_by_descending_X ); // creates lines or short segments inside the complex polygon for( unsigned ip = 0; ip < pointbuffer.size(); ip += 2 ) { double dx = pointbuffer[ip + 1].x - pointbuffer[ip].x; // Push only one line for diagonal hatch, // or for small lines < twice the line len // else push 2 small lines if( m_hatchStyle == DIAGONAL_FULL || fabs( dx ) < 2 * hatch_line_len ) { m_HatchLines.push_back( CSegment( pointbuffer[ip], pointbuffer[ip + 1] ) ); } else { double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y; double slope = dy / dx; if( dx > 0 ) dx = hatch_line_len; else dx = -hatch_line_len; double x1 = pointbuffer[ip].x + dx; double x2 = pointbuffer[ip + 1].x - dx; double y1 = pointbuffer[ip].y + dx * slope; double y2 = pointbuffer[ip + 1].y - dx * slope; m_HatchLines.push_back( CSegment( pointbuffer[ip].x, pointbuffer[ip].y, KiROUND( x1 ), KiROUND( y1 ) ) ); m_HatchLines.push_back( CSegment( pointbuffer[ip + 1].x, pointbuffer[ip + 1].y, KiROUND( x2 ), KiROUND( y2 ) ) ); } } } }