00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #pragma once
00024
00025 #include "cinder/Vector.h"
00026 #include "cinder/BSpline.h"
00027 #include "cinder/Rect.h"
00028 #include "cinder/Exception.h"
00029 #include "cinder/MatrixAffine2.h"
00030
00031 #include <vector>
00032
00033 namespace cinder {
00034
00035 class Path2d {
00036 public:
00037 Path2d() {}
00038 explicit Path2d( const BSpline<Vec2f> &spline, float subdivisionStep = 0.01f );
00039
00041 void moveTo( const Vec2f &p );
00043 void moveTo( float x, float y ) { moveTo( Vec2f( x, y ) ); }
00044 void lineTo( const Vec2f &p );
00045 void lineTo( float x, float y ) { lineTo( Vec2f( x, y ) ); }
00046 void quadTo( const Vec2f &p1, const Vec2f &p2 );
00047 void quadTo( float x1, float y1, float x2, float y2 ) { quadTo( Vec2f( x1, y1 ), Vec2f( x2, y2 ) ); }
00048 void curveTo( const Vec2f &p1, const Vec2f &p2, const Vec2f &p3 );
00049 void curveTo( float x1, float y1, float x2, float y2, float x3, float y3 ) { curveTo( Vec2f( x1, y1 ), Vec2f( x2, y2 ), Vec2f( x3, y3 ) ); }
00050 void arc( const Vec2f ¢er, float radius, float startRadians, float endRadians, bool forward = true );
00051 void arc( float centerX, float centerY, float radius, float startRadians, float endRadians, bool forward = true ) { arc( Vec2f( centerX, centerY ), radius, startRadians, endRadians, forward ); }
00052 void arcTo( const Vec2f &p, const Vec2f &t, float radius );
00053 void arcTo( float x, float y, float tanX, float tanY, float radius) { arcTo( Vec2f( x, y ), Vec2f( tanX, tanY ), radius ); }
00054
00056 void close() { mSegments.push_back( CLOSE ); }
00057 bool isClosed() const { return ( mSegments.size() > 1 ) && mSegments.back() == CLOSE; }
00058
00060 void reverse();
00061
00062 bool empty() const { return mPoints.empty(); }
00063 void clear() { mSegments.clear(); mPoints.clear(); }
00064 size_t getNumSegments() const { return mSegments.size(); }
00065 size_t getNumPoints() const { return mPoints.size(); }
00066
00068 Vec2f getPosition( float t ) const;
00070 Vec2f getSegmentPosition( size_t segment, float t ) const;
00071
00072 std::vector<Vec2f> subdivide( float approximationScale = 1.0f ) const;
00073
00075 void scale( const Vec2f &amount, Vec2f scaleCenter = Vec2f::zero() );
00077 void transform( const MatrixAffine2f &matrix );
00079 Path2d transformCopy( const MatrixAffine2f &matrix ) const;
00080
00081
00082 const std::vector<Vec2f>& getPoints() const { return mPoints; }
00083 std::vector<Vec2f>& getPoints() { return mPoints; }
00084 const Vec2f& getPoint( size_t point ) const { return mPoints[point]; }
00085 Vec2f& getPoint( size_t point ) { return mPoints[point]; }
00086 const Vec2f& getCurrentPoint() const { return mPoints.back(); }
00087 void setPoint( size_t index, const Vec2f &p ) { mPoints[index] = p; }
00088
00089 enum SegmentType { MOVETO, LINETO, QUADTO, CUBICTO, CLOSE };
00090 static const int sSegmentTypePointCounts[];
00091 SegmentType getSegmentType( size_t segment ) const { return mSegments[segment]; }
00092
00093 const std::vector<SegmentType>& getSegments() const { return mSegments; }
00094 std::vector<SegmentType>& getSegments() { return mSegments; }
00095
00096 void removeSegment( size_t segment );
00097
00099 Rectf calcBoundingBox() const;
00101 Rectf calcPreciseBoundingBox() const;
00102
00104 bool contains( const Vec2f &pt ) const;
00105
00106 friend class Shape2d;
00107 friend std::ostream& operator<<( std::ostream &out, const Path2d &p );
00108 private:
00109 void arcHelper( const Vec2f ¢er, float radius, float startRadians, float endRadians, bool forward );
00110 void arcSegmentAsCubicBezier( const Vec2f ¢er, float radius, float startRadians, float endRadians );
00111 void subdivideQuadratic( float distanceToleranceSqr, const Vec2f &p1, const Vec2f &p2, const Vec2f &p3, int level, std::vector<Vec2f> *result ) const;
00112 void subdivideCubic( float distanceToleranceSqr, const Vec2f &p1, const Vec2f &p2, const Vec2f &p3, const Vec2f &p4, int level, std::vector<Vec2f> *result ) const;
00113
00114 std::vector<Vec2f> mPoints;
00115 std::vector<SegmentType> mSegments;
00116 };
00117
00118 inline std::ostream& operator<<( std::ostream &out, const Path2d &p )
00119 {
00120 size_t pt = 0;
00121 for( size_t s = 0; s < p.mSegments.size(); ++s ) {
00122 if( p.mSegments[s] == Path2d::MOVETO ) {
00123 out << "M " << p.mPoints[pt].x << " " << p.mPoints[pt].y << " ";
00124 pt++;
00125 }
00126 if( p.mSegments[s] == Path2d::LINETO ) {
00127 out << "L " << p.mPoints[pt].x << " " << p.mPoints[pt].y << " ";
00128 pt++;
00129 }
00130 else if( p.mSegments[s] == Path2d::QUADTO ) {
00131 out << "Q " << p.mPoints[pt].x << " " << p.mPoints[pt].y << " " << p.mPoints[pt+1].x << " " << p.mPoints[pt+1].y << " ";
00132 pt += 2;
00133 }
00134 else if( p.mSegments[s] == Path2d::CUBICTO ) {
00135 out << "C " << p.mPoints[pt].x << " " << p.mPoints[pt].y << " " << p.mPoints[pt+1].x << " " << p.mPoints[pt+1].y << " " << p.mPoints[pt+2].x << " " << p.mPoints[pt+2].y << " ";
00136 pt += 3;
00137 }
00138 else {
00139 out << "Z ";
00140 }
00141
00142 }
00143
00144 return out;
00145 }
00146
00147 class Path2dExc : public Exception {
00148 };
00149
00150 }