Path class
class Path extends CurvePath { var useSpacedPoints = false; List _points; List<PathAction> actions; Path( [List points] ) : actions = [], super(){ if (points != null) { _fromPoints(points); } } // Create path using straight lines to connect all points // - vectors: array of Vector2 factory Path.fromPoints( vectors ) => new Path(vectors); _fromPoints( vectors ){ moveTo( vectors[0].x, vectors[0].y ); for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { this.lineTo( vectors[ v ].x, vectors[ v ].y ); } } addAction(String action, [var args]) => actions.add(new PathAction(action, args)); // startPath() endPath()? moveTo( x, y ) => addAction( PathAction.MOVE_TO, [x, y] ); lineTo( x, y ) { var args = [x, y]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new LineCurve( new Vector2( x0, y0 ), new Vector2( x, y ) ); curves.add( curve ); addAction( PathAction.LINE_TO, args); } quadraticCurveTo( aCPx, aCPy, aX, aY ) { var args = [aCPx, aCPy, aX, aY]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ].toDouble(); var y0 = lastargs[ lastargs.length - 1 ].toDouble(); var curve = new QuadraticBezierCurve( new Vector2( x0, y0 ), new Vector2( aCPx.toDouble(), aCPy.toDouble() ), new Vector2( aX.toDouble(), aY.toDouble() ) ); curves.add( curve ); addAction( PathAction.QUADRATIC_CURVE_TO, args ); } bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { var args = [aCP1x, aCP1y, aCP2x, aCP2y, aX, aY]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ].toDouble(); var y0 = lastargs[ lastargs.length - 1 ].toDouble(); var curve = new CubicBezierCurve( new Vector2( x0, y0 ), new Vector2( aCP1x.toDouble(), aCP1y.toDouble() ), new Vector2( aCP2x.toDouble(), aCP2y.toDouble() ), new Vector2( aX.toDouble(), aY.toDouble() ) ); curves.add( curve ); addAction( PathAction.BEZIER_CURVE_TO, args ); } splineThru( List<Vector2> pts) { var args = [pts]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; //--- var npts = [ new Vector2( x0, y0 ) ]; npts.addAll(pts); //Array.prototype.push.apply( npts, pts ); var curve = new SplineCurve( npts ); curves.add( curve ); addAction( PathAction.CSPLINE_THRU, args); } // FUTURE: Change the API or follow canvas API? // TODO ARC ( x, y, x - radius, y - radius, startAngle, endAngle ) arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { var lastargs = actions[ actions.length - 1].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; absarc(aX + x0, aY + y0, aRadius, aStartAngle, aEndAngle, aClockwise ); } absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); } ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; absellipse(aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ); } absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { var args = [aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise]; var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ); curves.add( curve ); var lastPoint = curve.getPoint(aClockwise ? 1 : 0); args.add(lastPoint.x); args.add(lastPoint.y); addAction(PathAction.ELLIPSE, args); } getSpacedPoints( [int divisions = 5, bool closedPath = false] ) { if ( divisions == null ) divisions = 40; var points = []; for ( var i = 0; i < divisions; i ++ ) { points.add( this.getPoint( i / divisions ) ); //if( !this.getPoint( i / divisions ) ) throw "DIE"; } // if ( closedPath ) { // // points.push( points[ 0 ] ); // // } return points; } /* Return an array of vectors based on contour of the path */ getPoints( [int divisions = null, closedPath = false] ) { if (useSpacedPoints) { return getSpacedPoints( divisions, closedPath ); } if (divisions == null) divisions = 12; List<Vector2> points = []; var i, il, item, action, args; var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, laste, j, t, tx, ty; for ( i = 0; i < actions.length; i ++ ) { item = actions[ i ]; action = item.action; args = item.args; switch( action ) { case PathAction.MOVE_TO: points.add( new Vector2( args[ 0 ], args[ 1 ] ) ); break; case PathAction.LINE_TO: points.add( new Vector2( args[ 0 ], args[ 1 ] ) ); break; case PathAction.QUADRATIC_CURVE_TO: cpx = args[ 2 ]; cpy = args[ 3 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( j = 1; j <= divisions; j ++ ) { t = j / divisions; tx = ShapeUtils.b2( t, cpx0, cpx1, cpx ); ty = ShapeUtils.b2( t, cpy0, cpy1, cpy ); points.add( new Vector2( tx, ty ) ); } break; case PathAction.BEZIER_CURVE_TO: cpx = args[ 4 ]; cpy = args[ 5 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; cpx2 = args[ 2 ]; cpy2 = args[ 3 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( j = 1; j <= divisions; j ++ ) { t = j / divisions; tx = ShapeUtils.b3( t, cpx0, cpx1, cpx2, cpx ); ty = ShapeUtils.b3( t, cpy0, cpy1, cpy2, cpy ); points.add( new Vector2( tx, ty ) ); } break; case PathAction.CSPLINE_THRU: laste = actions[ i - 1 ].args; var last = new Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); var spts = [ last ]; var n = divisions * args[ 0 ].length; spts.addAll( args[ 0 ] ); var spline = new SplineCurve( spts ); for ( j = 1; j <= n; j ++ ) { points.add( spline.getPointAt( j / n ) ) ; } break; case PathAction.ARC: laste = actions[ i - 1 ].args; var aX = args[ 0 ], aY = args[ 1 ], aRadius = args[ 2 ], aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], aClockwise = !!args[ 5 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; for ( j = 1; j <= tdivisions; j ++ ) { t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + aRadius * Math.cos( angle ); ty = aY + aRadius * Math.sin( angle ); //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.add( new Vector2( tx, ty ) ); } //console.log(points); break; case PathAction.ELLIPSE: var aX = args[ 0 ], aY = args[ 1 ], xRadius = args[ 2 ], yRadius = args[ 3 ], aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], aClockwise = !!args[ 6 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; for ( j = 1; j <= tdivisions; j ++ ) { t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + xRadius * Math.cos( angle ); ty = aY + yRadius * Math.sin( angle ); //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.add( new Vector2( tx, ty ) ); } //console.log(points); break; } // end switch } // Normalize to remove the closing point by default. var lastPoint = points[ points.length - 1]; var EPSILON = 0.0000000001; if ( (lastPoint.x - points[ 0 ].x).abs() < EPSILON && (lastPoint.y - points[ 0 ].y).abs() < EPSILON) { points.removeLast(); } if ( closedPath ) { points.add( points[ 0 ] ); } return points; } // This was used for testing purposes. Should be removed soon. transform ( path, segments ) { var bounds = getBoundingBox(); var oldPts = getPoints( segments ); // getPoints getSpacedPoints //console.log( path.cacheArcLengths() ); //path.getLengths(400); //segments = 40; return getWrapPoints( oldPts, path ); } // Breaks path into shapes toShapes() { var i, il, item, action, args; List<Path> subPaths = []; var lastPath = new Path(); for ( i = 0; i < actions.length; i ++ ) { item = actions[ i ]; args = item.args; action = item.action; if ( action == PathAction.MOVE_TO ) { if ( lastPath.actions.length != 0 ) { subPaths.add( lastPath ); lastPath = new Path(); } } lastPath._applyAction( action, args); } if ( lastPath.actions.length != 0 ) { subPaths.add( lastPath ); } // console.log(subPaths); if ( subPaths.length == 0 ) return []; var tmpPath; Shape tmpShape; List<Shape> shapes = []; var holesFirst = !ShapeUtils.isClockWise( subPaths[ 0 ].getPoints() ); // console.log("Holes first", holesFirst); if ( subPaths.length == 1) { tmpPath = subPaths[0]; tmpShape = new Shape(); tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; shapes.add( tmpShape ); return shapes; }; if ( holesFirst ) { tmpShape = new Shape(); for ( i = 0; i < subPaths.length; i ++ ) { tmpPath = subPaths[ i ]; if ( ShapeUtils.isClockWise( tmpPath.getPoints() ) ) { tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; shapes.add( tmpShape ); tmpShape = new Shape(); //console.log('cw', i); } else { tmpShape.holes.add( tmpPath ); //console.log('ccw', i); } } } else { // Shapes first for ( i = 0; i < subPaths.length; i ++ ) { tmpPath = subPaths[ i ]; if ( ShapeUtils.isClockWise( tmpPath.getPoints() ) ) { if (tmpShape != null) shapes.add( tmpShape ); tmpShape = new Shape(); tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; } else { tmpShape.holes.add( tmpPath ); } } shapes.add( tmpShape ); } //console.log("shape", shapes); return shapes; } // TODO(nelsonsilva) - Come up with a better way to invoke the action _applyAction( action, args) { switch (action) { case PathAction.MOVE_TO: moveTo(args[0], args[1]); break; case PathAction.LINE_TO: lineTo(args[0], args[1]); break; case PathAction.QUADRATIC_CURVE_TO: quadraticCurveTo(args[0], args[1], args[2], args[3]); break; case PathAction.BEZIER_CURVE_TO: bezierCurveTo(args[0], args[1], args[2], args[3], args[4], args[5]); break; case PathAction.CSPLINE_THRU: splineThru(args[0]); break; case PathAction.ARC: arc(args[0], args[1], args[2], args[3], args[4], args[5]); break; case PathAction.ELLIPSE: ellipse(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break; } } }
Extends
Subclasses
Constructors
factory Path.fromPoints(vectors) #
factory Path.fromPoints( vectors ) => new Path(vectors);
Properties
List<PathAction> actions #
List<PathAction> actions
var useSpacedPoints #
var useSpacedPoints = false
Methods
dynamic absarc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) #
absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); }
dynamic absellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise) #
absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { var args = [aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise]; var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ); curves.add( curve ); var lastPoint = curve.getPoint(aClockwise ? 1 : 0); args.add(lastPoint.x); args.add(lastPoint.y); addAction(PathAction.ELLIPSE, args); }
dynamic addAction(String action, [args]) #
addAction(String action, [var args]) => actions.add(new PathAction(action, args));
dynamic addWrapPath(bendpath) #
inherited from CurvePath
Bend / Wrap Helper Methods
addWrapPath( bendpath ) => _bends.add( bendpath );
dynamic arc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) #
arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { var lastargs = actions[ actions.length - 1].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; absarc(aX + x0, aY + y0, aRadius, aStartAngle, aEndAngle, aClockwise ); }
dynamic bezierCurveTo(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) #
bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { var args = [aCP1x, aCP1y, aCP2x, aCP2y, aX, aY]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ].toDouble(); var y0 = lastargs[ lastargs.length - 1 ].toDouble(); var curve = new CubicBezierCurve( new Vector2( x0, y0 ), new Vector2( aCP1x.toDouble(), aCP1y.toDouble() ), new Vector2( aCP2x.toDouble(), aCP2y.toDouble() ), new Vector2( aX.toDouble(), aY.toDouble() ) ); curves.add( curve ); addAction( PathAction.BEZIER_CURVE_TO, args ); }
dynamic checkConnection() #
inherited from CurvePath
checkConnection() { // TODO // If the ending of curve is not connected to the starting // or the next curve, then, this is not a real path }
dynamic closePath() #
inherited from CurvePath
closePath() { // TODO Test // and verify for vector3 (needs to implement equals) // Add a line curve if start and end of lines are not connected var startPoint = curves[0].getPoint(0); var endPoint = curves[curves.length-1].getPoint(1); if (!startPoint.equals(endPoint)) { this.curves.add( new LineCurve(endPoint, startPoint) ); } }
dynamic createGeometry(points) #
inherited from CurvePath
createGeometry( points ) { var geometry = new Geometry(); for ( var i = 0; i < points.length; i ++ ) { var z = (points[i] is Vector3) ? points[ i ].z : 0.0; geometry.vertices.add( new Vector3( points[ i ].x, points[ i ].y, z) ); } return geometry; }
dynamic createPointsGeometry({divisions}) #
inherited from CurvePath
Create Geometries Helpers
Generate geometry from path points (for Line or ParticleSystem objects)
createPointsGeometry( {divisions} ) { var pts = this.getPoints( divisions, true ); return this.createGeometry( pts ); }
dynamic createSpacedPointsGeometry([divisions]) #
inherited from CurvePath
createSpacedPointsGeometry( [divisions] ) { var pts = this.getSpacedPoints( divisions, true ); return this.createGeometry( pts ); }
dynamic ellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise) #
ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; absellipse(aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ); }
dynamic getBoundingBox() #
inherited from CurvePath
getBoundingBox() { var points = getPoints(); var maxX, maxY, maxZ; var minX, minY, minZ; maxX = maxY = double.NEGATIVE_INFINITY; minX = minY = double.INFINITY; var p, i, sum; var v3 = points[0] is Vector3; sum = (v3) ? new Vector3.zero() : new Vector2.zero(); int il = points.length; for ( i = 0; i < il; i ++ ) { p = points[ i ]; if ( p.x > maxX ) { maxX = p.x; } else if ( p.x < minX ) minX = p.x; if ( p.y > maxY ) { maxY = p.y; } else if ( p.y < minY ) minY = p.y; if (v3) { p = p as Vector3; if ( p.z > maxZ ) { maxZ = p.z; } else if ( p.z < minZ ) minZ = p.z; (sum as Vector3).add( p ); } else { (sum as Vector2).add( p ); } } var ret = { "minX": minX, "minY": minY, "maxX": maxX, "maxY": maxY, "centroid": (sum as dynamic).scale( 1.0 / il ) }; if (v3) { ret["maxZ"] = maxZ; ret["minZ"] = minZ; } return ret; }
List<num> getCurveLengths() #
inherited from CurvePath
List<num> getCurveLengths() { // We use cache values if curves and cache array are same length if ( this.cacheLengths != null && this.cacheLengths.length == this.curves.length ) { return this.cacheLengths; } // Get length of subsurve // Push sums into cached array var lengths = [], sums = 0; var i, il = this.curves.length; for ( i = 0; i < il; i ++ ) { sums += this.curves[ i ].length; lengths.add( sums ); } this.cacheLengths = lengths; return lengths; }
List getLengths({num divisions: null}) #
inherited from Curve
List getLengths( {num divisions: null} ) { if (divisions == null) divisions = (_arcLengthDivisions != null) ? (_arcLengthDivisions): 200; if ( cacheArcLengths != null && ( cacheArcLengths.length == divisions + 1 ) && !needsUpdate) { //console.log( "cached", this.cacheArcLengths ); return cacheArcLengths; } needsUpdate = false; var cache = []; var current; var last = getPoint( 0.0 ); var sum = 0; cache.add( 0 ); for ( var p = 1; p <= divisions; p ++ ) { current = getPoint ( p / divisions ); var distance; // TODO(nelsonsilva) - Must move distanceTo to IVector interface os create a new IHasDistance if (current is Vector3) { distance = (current as Vector3).absoluteError( last as Vector3 ); } else { distance = (current as Vector2).absoluteError( last as Vector2); } sum += distance; cache.add( sum ); last = current; } cacheArcLengths = cache; return cache; // { sums: cache, sum:sum }; Sum is in the last element. }
dynamic getPoint(num t) #
inherited from CurvePath
getPoint( num t ) { var d = t * this.length; var curveLengths = this.getCurveLengths(); var i = 0, diff; Curve curve; // To think about boundaries points. while ( i < curveLengths.length ) { if ( curveLengths[ i ] >= d ) { diff = curveLengths[ i ] - d; curve = this.curves[ i ]; var u = 1 - diff / curve.length; return curve.getPointAt( u ); } i ++; } return null; // loop where sum != 0, sum > d , sum+1 <d }
V getPointAt(u) #
inherited from Curve
V getPointAt( u ) { var t = getUtoTmapping( u ); return getPoint( t ); }
dynamic getPoints([int divisions = null, closedPath = false]) #
getPoints( [int divisions = null, closedPath = false] ) { if (useSpacedPoints) { return getSpacedPoints( divisions, closedPath ); } if (divisions == null) divisions = 12; List<Vector2> points = []; var i, il, item, action, args; var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, laste, j, t, tx, ty; for ( i = 0; i < actions.length; i ++ ) { item = actions[ i ]; action = item.action; args = item.args; switch( action ) { case PathAction.MOVE_TO: points.add( new Vector2( args[ 0 ], args[ 1 ] ) ); break; case PathAction.LINE_TO: points.add( new Vector2( args[ 0 ], args[ 1 ] ) ); break; case PathAction.QUADRATIC_CURVE_TO: cpx = args[ 2 ]; cpy = args[ 3 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( j = 1; j <= divisions; j ++ ) { t = j / divisions; tx = ShapeUtils.b2( t, cpx0, cpx1, cpx ); ty = ShapeUtils.b2( t, cpy0, cpy1, cpy ); points.add( new Vector2( tx, ty ) ); } break; case PathAction.BEZIER_CURVE_TO: cpx = args[ 4 ]; cpy = args[ 5 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; cpx2 = args[ 2 ]; cpy2 = args[ 3 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( j = 1; j <= divisions; j ++ ) { t = j / divisions; tx = ShapeUtils.b3( t, cpx0, cpx1, cpx2, cpx ); ty = ShapeUtils.b3( t, cpy0, cpy1, cpy2, cpy ); points.add( new Vector2( tx, ty ) ); } break; case PathAction.CSPLINE_THRU: laste = actions[ i - 1 ].args; var last = new Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); var spts = [ last ]; var n = divisions * args[ 0 ].length; spts.addAll( args[ 0 ] ); var spline = new SplineCurve( spts ); for ( j = 1; j <= n; j ++ ) { points.add( spline.getPointAt( j / n ) ) ; } break; case PathAction.ARC: laste = actions[ i - 1 ].args; var aX = args[ 0 ], aY = args[ 1 ], aRadius = args[ 2 ], aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], aClockwise = !!args[ 5 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; for ( j = 1; j <= tdivisions; j ++ ) { t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + aRadius * Math.cos( angle ); ty = aY + aRadius * Math.sin( angle ); //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.add( new Vector2( tx, ty ) ); } //console.log(points); break; case PathAction.ELLIPSE: var aX = args[ 0 ], aY = args[ 1 ], xRadius = args[ 2 ], yRadius = args[ 3 ], aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], aClockwise = !!args[ 6 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; for ( j = 1; j <= tdivisions; j ++ ) { t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + xRadius * Math.cos( angle ); ty = aY + yRadius * Math.sin( angle ); //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.add( new Vector2( tx, ty ) ); } //console.log(points); break; } // end switch } // Normalize to remove the closing point by default. var lastPoint = points[ points.length - 1]; var EPSILON = 0.0000000001; if ( (lastPoint.x - points[ 0 ].x).abs() < EPSILON && (lastPoint.y - points[ 0 ].y).abs() < EPSILON) { points.removeLast(); } if ( closedPath ) { points.add( points[ 0 ] ); } return points; }
dynamic getSpacedPoints([int divisions = 5, bool closedPath = false]) #
getSpacedPoints( [int divisions = 5, bool closedPath = false] ) { if ( divisions == null ) divisions = 40; var points = []; for ( var i = 0; i < divisions; i ++ ) { points.add( this.getPoint( i / divisions ) ); //if( !this.getPoint( i / divisions ) ) throw "DIE"; } // if ( closedPath ) { // // points.push( points[ 0 ] ); // // } return points; }
V getTangent(t) #
inherited from Curve
V getTangent( t ) { var delta = 0.0001; var t1 = t - delta; var t2 = t + delta; // Capping in case of danger if ( t1 < 0 ) t1 = 0; if ( t2 > 1 ) t2 = 1; var pt1 = getPoint( t1 ); var pt2 = getPoint( t2 ); var vec = pt2 - pt1; return vec.normalize(); }
V getTangentAt(u) #
inherited from Curve
V getTangentAt( u ) { var t = getUtoTmapping( u ); return getTangent( t ); }
dynamic getTransformedPoints(segments, {List bends: null}) #
inherited from CurvePath
getTransformedPoints( segments, {List bends: null} ) { var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints var i, il; if (bends == null) { bends = _bends; } for ( i = 0; i < bends.length; i ++ ) { oldPts = this.getWrapPoints( oldPts, bends[ i ] ); } return oldPts; }
dynamic getTransformedSpacedPoints([num segments, List bends = null]) #
inherited from CurvePath
getTransformedSpacedPoints( [num segments, List bends = null] ) { var oldPts = getSpacedPoints( segments ); var i, il; if (bends == null) { bends = _bends; } for ( i = 0; i < bends.length; i ++ ) { oldPts = this.getWrapPoints( oldPts, bends[ i ] ); } return oldPts; }
List<V> getUPoints([List uList, closedPath = false]) #
inherited from Curve
List<V> getUPoints( [List uList , closedPath = false] ) { var pts = []; for ( var u in uList ) { pts.add( this.getPointAt( u ) ); } return pts; }
dynamic getUtoTmapping(u, {distance: null}) #
inherited from Curve
getUtoTmapping( u, {distance: null} ) { var arcLengths = getLengths(); int i = 0, il = arcLengths.length; var targetArcLength; // The targeted u distance value to get if (distance != null) { targetArcLength = distance; } else { targetArcLength = u * arcLengths[ il - 1 ]; } //var time = Date.now(); // binary search for the index with largest value smaller than target u distance var low = 0, high = il - 1, comparison; while ( low <= high ) { i = ( low + ( high - low ) / 2 ).floor().toInt(); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats comparison = arcLengths[ i ] - targetArcLength; if ( comparison < 0 ) { low = i + 1; continue; } else if ( comparison > 0 ) { high = i - 1; continue; } else { high = i; break; // DONE } } i = high; //console.log('b' , i, low, high, Date.now()- time); if ( arcLengths[ i ] == targetArcLength ) { var t = i / ( il - 1 ); return t; } // we could get finer grain at lengths, or use simple interpolatation between two points var lengthBefore = arcLengths[ i ]; var lengthAfter = arcLengths[ i + 1 ]; var segmentLength = lengthAfter - lengthBefore; // determine where we are between the 'before' and 'after' points var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; // add that fractional amount to t var t = ( i + segmentFraction ) / ( il -1 ); return t; }
dynamic getWrapPoints(oldPts, path) #
inherited from CurvePath
getWrapPoints( oldPts, path ) { var bounds = getBoundingBox(); var i, il, p, oldX, oldY, xNorm; for ( i = 0; i < oldPts.length; i ++ ) { p = oldPts[ i ]; oldX = p.x; oldY = p.y; xNorm = oldX / bounds.maxX; // If using actual distance, for length > path, requires line extrusions //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance xNorm = path.getUtoTmapping( xNorm, oldX ); // check for out of bounds? var pathPt = path.getPoint( xNorm ); var normal = path.getNormalVector( xNorm ).scale( oldY ); p.x = pathPt.x + normal.x; p.y = pathPt.y + normal.y; } return oldPts; }
dynamic lineTo(x, y) #
lineTo( x, y ) { var args = [x, y]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new LineCurve( new Vector2( x0, y0 ), new Vector2( x, y ) ); curves.add( curve ); addAction( PathAction.LINE_TO, args); }
dynamic moveTo(x, y) #
moveTo( x, y ) => addAction( PathAction.MOVE_TO, [x, y] );
dynamic quadraticCurveTo(aCPx, aCPy, aX, aY) #
quadraticCurveTo( aCPx, aCPy, aX, aY ) { var args = [aCPx, aCPy, aX, aY]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ].toDouble(); var y0 = lastargs[ lastargs.length - 1 ].toDouble(); var curve = new QuadraticBezierCurve( new Vector2( x0, y0 ), new Vector2( aCPx.toDouble(), aCPy.toDouble() ), new Vector2( aX.toDouble(), aY.toDouble() ) ); curves.add( curve ); addAction( PathAction.QUADRATIC_CURVE_TO, args ); }
dynamic splineThru(List<Vector2> pts) #
splineThru( List<Vector2> pts) { var args = [pts]; var lastargs = actions.last.args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; //--- var npts = [ new Vector2( x0, y0 ) ]; npts.addAll(pts); //Array.prototype.push.apply( npts, pts ); var curve = new SplineCurve( npts ); curves.add( curve ); addAction( PathAction.CSPLINE_THRU, args); }
dynamic toShapes() #
toShapes() { var i, il, item, action, args; List<Path> subPaths = []; var lastPath = new Path(); for ( i = 0; i < actions.length; i ++ ) { item = actions[ i ]; args = item.args; action = item.action; if ( action == PathAction.MOVE_TO ) { if ( lastPath.actions.length != 0 ) { subPaths.add( lastPath ); lastPath = new Path(); } } lastPath._applyAction( action, args); } if ( lastPath.actions.length != 0 ) { subPaths.add( lastPath ); } // console.log(subPaths); if ( subPaths.length == 0 ) return []; var tmpPath; Shape tmpShape; List<Shape> shapes = []; var holesFirst = !ShapeUtils.isClockWise( subPaths[ 0 ].getPoints() ); // console.log("Holes first", holesFirst); if ( subPaths.length == 1) { tmpPath = subPaths[0]; tmpShape = new Shape(); tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; shapes.add( tmpShape ); return shapes; }; if ( holesFirst ) { tmpShape = new Shape(); for ( i = 0; i < subPaths.length; i ++ ) { tmpPath = subPaths[ i ]; if ( ShapeUtils.isClockWise( tmpPath.getPoints() ) ) { tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; shapes.add( tmpShape ); tmpShape = new Shape(); //console.log('cw', i); } else { tmpShape.holes.add( tmpPath ); //console.log('ccw', i); } } } else { // Shapes first for ( i = 0; i < subPaths.length; i ++ ) { tmpPath = subPaths[ i ]; if ( ShapeUtils.isClockWise( tmpPath.getPoints() ) ) { if (tmpShape != null) shapes.add( tmpShape ); tmpShape = new Shape(); tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; } else { tmpShape.holes.add( tmpPath ); } } shapes.add( tmpShape ); } //console.log("shape", shapes); return shapes; }
dynamic transform(path, segments) #
transform ( path, segments ) { var bounds = getBoundingBox(); var oldPts = getPoints( segments ); // getPoints getSpacedPoints //console.log( path.cacheArcLengths() ); //path.getLengths(400); //segments = 40; return getWrapPoints( oldPts, path ); }