bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aPt, int aAccuracy ) const { BOX2I bbox = BBox(); bbox.Inflate( aAccuracy ); if( !m_closed || PointCount() < 3 || !BBox().Contains( aPt ) ) return false; bool inside = false; /** * To check for interior points, we draw a line in the positive x direction from * the point. If it intersects an even number of segments, the point is outside the * line chain (it had to first enter and then exit). Otherwise, it is inside the chain. * * Note: slope might be denormal here in the case of a horizontal line but we require our * y to move from above to below the point (or vice versa) */ for( int i = 0; i < PointCount(); i++ ) { const auto p1 = CPoint( i ); const auto p2 = CPoint( i + 1 ); // CPoint wraps, so ignore counts const auto diff = p2 - p1; if( diff.y != 0 ) { const int d = rescale( diff.x, ( aPt.y - p1.y ), diff.y ); if( ( ( p1.y > aPt.y ) != ( p2.y > aPt.y ) ) && ( aPt.x - p1.x < d ) ) inside = !inside; } } return inside && !PointOnEdge( aPt, aAccuracy ); }
void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex ) { if( aEndIndex < 0 ) aEndIndex += PointCount(); if( aStartIndex < 0 ) aStartIndex += PointCount(); m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 ); }
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine ) { if( aEndIndex < 0 ) aEndIndex += PointCount(); if( aStartIndex < 0 ) aStartIndex += PointCount(); m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 ); m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() ); }
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const { SHAPE_LINE_CHAIN rv; if( aEndIndex < 0 ) aEndIndex += PointCount(); if( aStartIndex < 0 ) aStartIndex += PointCount(); for( int i = aStartIndex; i <= aEndIndex; i++ ) rv.Append( m_points[i] ); return rv; }
void FTContour::buildBackOutset(float outset) { for(size_t i = 0; i < PointCount(); ++i) { AddBackPoint(Point(i) + Outset(i) * outset); } }
void FTContour::SetParity(int parity) { size_t size = PointCount(); FTPoint vOutset; if(((parity & 1) && clockwise) || (!(parity & 1) && !clockwise)) { // Contour orientation is wrong! We must reverse all points. // FIXME: could it be worth writing FTVector::reverse() for this? for(size_t i = 0; i < size / 2; i++) { FTPoint tmp = pointList[i]; pointList[i] = pointList[size - 1 - i]; pointList[size - 1 -i] = tmp; } clockwise = !clockwise; } for(size_t i = 0; i < size; i++) { size_t prev, cur, next; prev = (i + size - 1) % size; cur = i; next = (i + size + 1) % size; vOutset = ComputeOutsetPoint(Point(prev), Point(cur), Point(next)); AddOutsetPoint(vOutset); } }
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP ) { if( aEndIndex < 0 ) aEndIndex += PointCount(); if( aStartIndex < 0 ) aStartIndex += PointCount(); if( aStartIndex == aEndIndex ) m_points[aStartIndex] = aP; else { m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 ); m_points[aStartIndex] = aP; } }
int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const { for( int s = 0; s < PointCount(); s++ ) if( CPoint( s ) == aP ) return s; return -1; }
const std::string SHAPE_LINE_CHAIN::Format() const { std::stringstream ss; ss << m_points.size() << " " << ( m_closed ? 1 : 0 ) << " "; for( int i = 0; i < PointCount(); i++ ) ss << m_points[i].x << " " << m_points[i].y << " "; // Format() << " "; return ss.str(); }
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; }
ON_PointGrid& ON_PointGrid::operator=( const ON_PointGrid& src ) { if ( this != &src ) { ON_Geometry::operator=(src); m_point_count[0] = src.m_point_count[0]; m_point_count[1] = src.m_point_count[1]; m_point_stride0 = m_point_count[1]; m_point.Reserve(PointCount()); m_point.SetCount(PointCount()); if ( PointCount() > 0 ) { // copy cv array if ( m_point_stride0 == src.m_point_stride0 ) { memcpy( m_point.Array(), src.m_point.Array(), PointCount()*sizeof(ON_3dPoint) ); } else { int i, j; for ( i = 0; i < m_point_count[0]; i++ ) for ( j = 0; j < m_point_count[1]; j++ ) { m_point[i*m_point_stride0+j] = src[i][j]; } } } } return *this; }
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; }
ClipperLib::Path SHAPE_LINE_CHAIN::convertToClipper( bool aRequiredOrientation ) const { ClipperLib::Path c_path; for( int i = 0; i < PointCount(); i++ ) { const VECTOR2I& vertex = CPoint( i ); c_path.push_back( ClipperLib::IntPoint( vertex.x, vertex.y ) ); } if( Orientation( c_path ) != aRequiredOrientation ) ReversePath( c_path ); return c_path; }
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const SEG& aSeg, int& dist ) const { int nearest = 0; dist = INT_MAX; for( int i = 0; i < PointCount(); i++ ) { int d = aSeg.LineDistance( CPoint( i ) ); if( d < dist ) { dist = d; nearest = i; } } return CPoint( nearest ); }
static void VaryGlyphs(struct ttfinfo *info,int tupleIndex,int gnum, int *points, FILE *ttf ) { /* one annoying thing about gvar, is that the variations do not describe */ /* designs. well variations for [0,1] describes that design, but the */ /* design for [1,1] includes the variations [0,1], [1,0], and [1,1] */ int pcnt, tc; int *xdeltas, *ydeltas; struct variations *v = info->variations; if ( info->chars[gnum]==NULL ) /* Apple doesn't support ttc so this */ return; /* can't happen */ if ( points==NULL ) { LogError( _("Mismatched local and shared tuple flags.\n") ); return; } if ( points[0]==ALL_POINTS ) pcnt = PointCount(info->chars[gnum])+4; else { for ( pcnt=0; points[pcnt]!=END_OF_POINTS; ++pcnt ); } xdeltas = readpackeddeltas(ttf,pcnt); ydeltas = readpackeddeltas(ttf,pcnt); if ( xdeltas[0]!=BAD_DELTA && ydeltas[0]!=BAD_DELTA ) for ( tc = 0; tc<v->tuple_count; ++tc ) { if ( TuplesMatch(v,tc,tupleIndex)) VaryGlyph(v->tuples[tc].chars[gnum],points,xdeltas,ydeltas,pcnt); } else { static int warned = false; if ( !warned ) LogError( _("Incorrect number of deltas in glyph %d (%s)\n"), gnum, info->chars[gnum]->name!=NULL?info->chars[gnum]->name:"<Nameless>" ); warned = true; } free(xdeltas); free(ydeltas); }
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify() { std::vector<VECTOR2I> pts_unique; if( PointCount() < 2 ) { return *this; } else if( PointCount() == 2 ) { if( m_points[0] == m_points[1] ) m_points.pop_back(); return *this; } int i = 0; int np = PointCount(); // stage 1: eliminate duplicate vertices while( i < np ) { int j = i + 1; while( j < np && CPoint( i ) == CPoint( j ) ) j++; pts_unique.push_back( CPoint( i ) ); i = j; } m_points.clear(); np = pts_unique.size(); i = 0; // stage 1: eliminate collinear segments while( i < np - 2 ) { const VECTOR2I p0 = pts_unique[i]; const VECTOR2I p1 = pts_unique[i + 1]; int n = i; while( n < np - 2 && SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 ) n++; m_points.push_back( p0 ); if( n > i ) i = n; if( n == np ) { m_points.push_back( pts_unique[n - 1] ); return *this; } i++; } if( np > 1 ) m_points.push_back( pts_unique[np - 2] ); m_points.push_back( pts_unique[np - 1] ); return *this; }