bool CStaticObject::canWalk(const Vector2& from, const Vector2& to, Vector2& norm) { if( to.x > m_max.x && from.x > m_max.x ) return true; if( to.x < m_min.x && from.x < m_min.x ) return true; if( to.y > m_max.y && from.y > m_max.y ) return true; if( to.y < m_min.y && from.y < m_min.y ) return true; Vector2 dir = to - from; std::vector<CSegment>::iterator it; Real t; for( it = m_segments.begin(); it != m_segments.end(); ++it ) { if( (*it).intersects(CSegment(from,to)) ) break; if( (*it).squareDist(to,&t) < (CHAR_SIZE * CHAR_SIZE / 10) && t < 1.0f && t > 0.0f ) break; } if( it != m_segments.end() ) { if( dir.dotProduct((*it).getNormal()) > 0 ) norm = (*it).getNormal(); else norm = -(*it).getNormal(); return false; } return true; };
int SHAPE_LINE_CHAIN::FindSegment( const VECTOR2I& aP ) const { for( int s = 0; s < SegmentCount(); s++ ) if( CSegment( s ).Distance( aP ) <= 1 ) return s; return -1; }
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const { int min_d = INT_MAX; int nearest = 0; for( int i = 0; i < SegmentCount(); i++ ) { int d = CSegment( i ).Distance( aP ); if( d < min_d ) { min_d = d; nearest = i; } } return CSegment( nearest ).NearestPoint( aP ); }
int SHAPE_LINE_CHAIN::Length() const { int l = 0; for( int i = 0; i < SegmentCount(); i++ ) l += CSegment( i ).Length(); return l; }
int SHAPE_LINE_CHAIN::Intersect( const SEG& aSeg, INTERSECTIONS& aIp ) const { for( int s = 0; s < SegmentCount(); s++ ) { OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg ); if( p ) { INTERSECTION is; is.our = CSegment( s ); is.their = aSeg; is.p = *p; aIp.push_back( is ); } } compareOriginDistance comp( aSeg.A ); sort( aIp.begin(), aIp.end(), comp ); return aIp.size(); }
int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP, bool aOutlineOnly ) const { int d = INT_MAX; if( IsClosed() && PointInside( aP ) && !aOutlineOnly ) return 0; for( int s = 0; s < SegmentCount(); s++ ) d = std::min( d, CSegment( s ).Distance( aP ) ); return d; }
int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, INTERSECTIONS& aIp ) const { BOX2I bb_other = aChain.BBox(); for( int s1 = 0; s1 < SegmentCount(); s1++ ) { const SEG& a = CSegment( s1 ); const BOX2I bb_cur( a.A, a.B - a.A ); if( !bb_other.Intersects( bb_cur ) ) continue; for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ ) { const SEG& b = aChain.CSegment( s2 ); INTERSECTION is; if( a.Collinear( b ) ) { is.our = a; is.their = b; if( a.Contains( b.A ) ) { is.p = b.A; aIp.push_back( is ); } if( a.Contains( b.B ) ) { is.p = b.B; aIp.push_back( is ); } if( b.Contains( a.A ) ) { is.p = a.A; aIp.push_back( is ); } if( b.Contains( a.B ) ) { is.p = a.B; aIp.push_back( is ); } } else { OPT_VECTOR2I p = a.Intersect( b ); if( p ) { is.p = *p; is.our = a; is.their = b; aIp.push_back( is ); } } } } return aIp.size(); }
int SHAPE_LINE_CHAIN::PathLength( const VECTOR2I& aP ) const { int sum = 0; for( int i = 0; i < SegmentCount(); i++ ) { const SEG seg = CSegment( i ); int d = seg.Distance( aP ); if( d <= 1 ) { sum += ( aP - seg.A ).EuclideanNorm(); return sum; } else sum += seg.Length(); } return -1; }
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const { BOX2I box_a( aSeg.A, aSeg.B - aSeg.A ); BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance; for( int i = 0; i < SegmentCount(); i++ ) { const SEG& s = CSegment( i ); BOX2I box_b( s.A, s.B - s.A ); BOX2I::ecoord_type d = box_a.SquaredDistance( box_b ); if( d < dist_sq ) { if( s.Collide( aSeg, aClearance ) ) return true; } } return false; }
bool SHAPE_LINE_CHAIN::CheckClearance( const VECTOR2I& aP, const int aDist) const { if( !PointCount() ) return false; else if( PointCount() == 1 ) return m_points[0] == aP; for( int i = 0; i < SegmentCount(); i++ ) { const SEG s = CSegment( i ); if( s.A == aP || s.B == aP ) return true; if( s.Distance( aP ) <= aDist ) return true; } return false; }
const VECTOR2I SHAPE_LINE_CHAIN::PointAlong( int aPathLength ) const { int total = 0; if( aPathLength == 0 ) return CPoint( 0 ); for( int i = 0; i < SegmentCount(); i++ ) { const SEG& s = CSegment( i ); int l = s.Length(); if( total + l >= aPathLength ) { VECTOR2I d( s.B - s.A ); return s.A + d.Resize( aPathLength - total ); } total += l; } return CPoint( -1 ); }
int SHAPE_LINE_CHAIN::EdgeContainingPoint( const VECTOR2I& aPt, int aAccuracy ) const { if( !PointCount() ) return -1; else if( PointCount() == 1 ) { VECTOR2I dist = m_points[0] - aPt; return ( hypot( dist.x, dist.y ) <= aAccuracy + 1 ) ? 0 : -1; } for( int i = 0; i < SegmentCount(); i++ ) { const SEG s = CSegment( i ); if( s.A == aPt || s.B == aPt ) return i; if( s.Distance( aPt ) <= aAccuracy + 1 ) return i; } return -1; }
int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP ) { int ii = -1; int min_dist = 2; int found_index = Find( aP ); for( int s = 0; s < SegmentCount(); s++ ) { const SEG seg = CSegment( s ); int dist = seg.Distance( aP ); // make sure we are not producing a 'slightly concave' primitive. This might happen // if aP lies very close to one of already existing points. if( dist < min_dist && seg.A != aP && seg.B != aP ) { min_dist = dist; if( found_index < 0 ) ii = s; else if( s < found_index ) ii = s; } } if( ii < 0 ) ii = found_index; if( ii >= 0 ) { m_points.insert( m_points.begin() + ii + 1, aP ); return ii + 1; } return -1; }
void CPolygon::orderPoints() { std::vector<CSegment> segList; std::vector<CSegment> nonIntersecting; for (size_t x=0; x< m_vPointList.size(); x++) { for (size_t y=x+1; y< m_vPointList.size(); y++) { segList.push_back(CSegment(m_vPointList[x], m_vPointList[y])); } } for (size_t x=0; x< segList.size(); x++) { bool ni = true; for (size_t y=0; y< segList.size(); y++) { Vector point; if (segList[x].findIntersection(segList[y], point)) { //ignore point intersections if (!(point == segList[x].getPointOne()) && !(point == segList[x].getPointTwo())) { ni = false; break; } } } if (ni) nonIntersecting.push_back(segList[x]); } std::vector<Vector> points; size_t c=0; size_t pos=0; while ( c < nonIntersecting.size() ) { points.push_back(nonIntersecting[pos].getPointOne()); for (size_t y=0; y< nonIntersecting.size(); y++) { if (y==pos) continue; bool o = nonIntersecting[y].getPointOne() == nonIntersecting[pos].getPointTwo(); bool t = nonIntersecting[y].getPointTwo() == nonIntersecting[pos].getPointTwo(); bool tDone = false; for (size_t z=0; z<points.size(); z++) { if (points[z] == nonIntersecting[y].getPointTwo()) { tDone = true; break; } } if (o || (t && !tDone)) { if (t) nonIntersecting[y].swapPoints(); pos = y; break; } } c++; } m_vPointList.clear(); for (size_t z=0; z<points.size(); z++) { m_vPointList.push_back(points[z]); } }
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 ) ) ); } } } }
const OPT<SHAPE_LINE_CHAIN::INTERSECTION> SHAPE_LINE_CHAIN::SelfIntersecting() const { for( int s1 = 0; s1 < SegmentCount(); s1++ ) { for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ ) { const VECTOR2I s2a = CSegment( s2 ).A, s2b = CSegment( s2 ).B; if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) ) { INTERSECTION is; is.our = CSegment( s1 ); is.their = CSegment( s2 ); is.p = s2a; return is; } else if( CSegment( s1 ).Contains( s2b ) && // for closed polylines, the ending point of the // last segment == starting point of the first segment // this is a normal case, not self intersecting case !( IsClosed() && s1 == 0 && s2 == SegmentCount()-1 ) ) { INTERSECTION is; is.our = CSegment( s1 ); is.their = CSegment( s2 ); is.p = s2b; return is; } else { OPT_VECTOR2I p = CSegment( s1 ).Intersect( CSegment( s2 ), true ); if( p ) { INTERSECTION is; is.our = CSegment( s1 ); is.their = CSegment( s2 ); is.p = *p; return is; } } } } return OPT<SHAPE_LINE_CHAIN::INTERSECTION>(); }