Implement proper index independent argument list reading of basic types.

Implemented for Point, Size, Rectangle and Color.
This commit is contained in:
Jürg Lehni 2012-10-18 14:24:15 -07:00
parent 6f2ff18fa1
commit 30374ae3b4
13 changed files with 260 additions and 190 deletions

View file

@ -34,8 +34,8 @@ var Line = this.Line = Base.extend(/** @lends Line# */{
// intersection outside the line segment are allowed. // intersection outside the line segment are allowed.
// With two parameters, the 2nd parameter is a direction, and infinite // With two parameters, the 2nd parameter is a direction, and infinite
// is automatially true, since we're describing an infinite line. // is automatially true, since we're describing an infinite line.
point1 = Point.read(arguments, 0, 1); point1 = Point.read(arguments);
point2 = Point.read(arguments, 1, 1); point2 = Point.read(arguments);
if (arguments.length == 3) { if (arguments.length == 3) {
this.point = point1; this.point = point1;
this.vector = point2.subtract(point1); this.vector = point2.subtract(point1);

View file

@ -128,24 +128,20 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
* @param {Point} [center] The center for the scaling transformation * @param {Point} [center] The center for the scaling transformation
* @return {Matrix} This affine transform * @return {Matrix} This affine transform
*/ */
scale: function(/* scale | */ hor, ver, center) { scale: function(scale, center) {
if (arguments.length < 2 || typeof ver === 'object') { // Do not modify scale, center, since that would arguments of which
// hor is the single scale parameter, representing both hor and ver // we're reading from!
// Read center first from argument 1, then set ver = hor (thus var _scale = Point.read(arguments),
// modifing the content of argument 1!) _center = Point.read(arguments);
center = Point.read(arguments, 1); // TODO: Isn't center always set this way??
ver = hor; if (_center)
} else { this.translate(_center);
center = Point.read(arguments, 2); this._a *= _scale.x;
} this._c *= _scale.x;
if (center) this._b *= _scale.y;
this.translate(center); this._d *= _scale.y;
this._a *= hor; if (_center)
this._c *= hor; this.translate(_center.negate());
this._b *= ver;
this._d *= ver;
if (center)
this.translate(center.negate());
return this; return this;
}, },
@ -168,7 +164,8 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
*/ */
translate: function(point) { translate: function(point) {
point = Point.read(arguments); point = Point.read(arguments);
var x = point.x, y = point.y; var x = point.x,
y = point.y;
this._tx += x * this._a + y * this._b; this._tx += x * this._a + y * this._b;
this._ty += x * this._c + y * this._d; this._ty += x * this._c + y * this._d;
return this; return this;
@ -219,24 +216,21 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
* @param {Point} [center] The center for the shear transformation * @param {Point} [center] The center for the shear transformation
* @return {Matrix} This affine transform * @return {Matrix} This affine transform
*/ */
shear: function(/* point | */ hor, ver, center) { shear: function(point, center) {
// See #scale() for explanation of this: // Do not modify point, center, since that would arguments of which
if (arguments.length < 2 || typeof ver === 'object') { // we're reading from!
center = Point.read(arguments, 1); var _point = Point.read(arguments),
ver = hor; _center = Point.read(arguments);
} else { if (_center)
center = Point.read(arguments, 2); this.translate(_center);
}
if (center)
this.translate(center);
var a = this._a, var a = this._a,
c = this._c; c = this._c;
this._a += ver * this._b; this._a += _point.y * this._b;
this._c += ver * this._d; this._c += _point.y * this._d;
this._b += hor * a; this._b += _point.x * a;
this._d += hor * c; this._d += _point.x * c;
if (center) if (_center)
this.translate(center.negate()); this.translate(_center.negate());
return this; return this;
}, },

View file

@ -28,6 +28,9 @@
* console.log(point.y); // 5 * console.log(point.y); // 5
*/ */
var Point = this.Point = Base.extend(/** @lends Point# */{ var Point = this.Point = Base.extend(/** @lends Point# */{
// Tell Base.read that the Point constructor supporst reading with index
_readIndex: true,
/** /**
* Creates a Point object with the given x and y coordinates. * Creates a Point object with the given x and y coordinates.
* *
@ -132,25 +135,36 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
initialize: function(arg0, arg1) { initialize: function(arg0, arg1) {
var type = typeof arg0; var type = typeof arg0;
if (type === 'number') { if (type === 'number') {
var hasY = typeof arg1 === 'number';
this.x = arg0; this.x = arg0;
this.y = typeof arg1 === 'number' ? arg1 : arg0; this.y = hasY ? arg1 : arg0;
if (this._read)
this._read = hasY ? 2 : 1;
} else if (type === 'undefined' || arg0 === null) { } else if (type === 'undefined' || arg0 === null) {
this.x = this.y = 0; this.x = this.y = 0;
} else if (typeof arg0.x !== 'undefined') { if (this._read)
this.x = arg0.x; this._read = arg0 === null ? 1 : 0;
this.y = arg0.y;
} else if (Array.isArray(arg0)) {
this.x = arg0[0];
this.y = arg0.length > 1 ? arg0[1] : arg0[0];
} else if (typeof arg0.width !== 'undefined') {
this.x = arg0.width;
this.y = arg0.height;
} else if (typeof arg0.angle !== 'undefined') {
this.x = arg0.length;
this.y = 0;
this.setAngle(arg0.angle);
} else { } else {
this.x = this.y = 0; if (typeof arg0.x !== 'undefined') {
this.x = arg0.x;
this.y = arg0.y;
} else if (Array.isArray(arg0)) {
this.x = arg0[0];
this.y = arg0.length > 1 ? arg0[1] : arg0[0];
} else if (typeof arg0.width !== 'undefined') {
this.x = arg0.width;
this.y = arg0.height;
} else if (typeof arg0.angle !== 'undefined') {
this.x = arg0.length;
this.y = 0;
this.setAngle(arg0.angle);
} else {
this.x = this.y = 0;
if (this._read)
this._read = 0;
}
if (this._read)
this._read = 1;
} }
}, },
@ -787,11 +801,11 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
* console.log(minPoint); // {x: 10, y: 5} * console.log(minPoint); // {x: 10, y: 5}
*/ */
min: function(point1, point2) { min: function(point1, point2) {
point1 = Point.read(arguments, 0, 1); var _point1 = Point.read(arguments);
point2 = Point.read(arguments, 1, 1); _point2 = Point.read(arguments);
return Point.create( return Point.create(
Math.min(point1.x, point2.x), Math.min(_point1.x, _point2.x),
Math.min(point1.y, point2.y) Math.min(_point1.y, _point2.y)
); );
}, },
@ -811,11 +825,11 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
* console.log(maxPoint); // {x: 200, y: 100} * console.log(maxPoint); // {x: 200, y: 100}
*/ */
max: function(point1, point2) { max: function(point1, point2) {
point1 = Point.read(arguments, 0, 1); var _point1 = Point.read(arguments);
point2 = Point.read(arguments, 1, 1); _point2 = Point.read(arguments);
return Point.create( return Point.create(
Math.max(point1.x, point2.x), Math.max(_point1.x, _point2.x),
Math.max(point1.y, point2.y) Math.max(_point1.y, _point2.y)
); );
}, },

View file

@ -22,6 +22,9 @@
* rectangular path, it is not an item. * rectangular path, it is not an item.
*/ */
var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
// Tell Base.read that the Rectangle constructor supporst reading with index
_readIndex: true,
/** /**
* Creates a Rectangle object. * Creates a Rectangle object.
* *
@ -54,21 +57,34 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
* @param {Rectangle} rt * @param {Rectangle} rt
*/ */
initialize: function(arg0, arg1, arg2, arg3) { initialize: function(arg0, arg1, arg2, arg3) {
if (arguments.length == 4) { var type = typeof arg0;
if (type === 'number') {
// new Rectangle(x, y, width, height) // new Rectangle(x, y, width, height)
this.x = arg0; this.x = arg0;
this.y = arg1; this.y = arg1;
this.width = arg2; this.width = arg2;
this.height = arg3; this.height = arg3;
} else if (arguments.length == 2) { if (this._read)
if (arg1 && arg1.x !== undefined) { this._read = 4;
} else if (type === 'undefined' || arg0 === null) {
// new Rectangle(), new Rectangle(null)
this.x = this.y = this.width = this.height = 0;
if (this._read)
this._read = arg0 === null ? 1 : 0;
} else if (arguments.length > 1 && typeof arg0.width === 'undefined') {
// We're checking arg0.width to rule out Rectangles, which are
// handled separately below.
// Read a point argument and look at the next value to see wether
// it's a size or a point, then read accordingly
var point = Point.read(arguments),
next = Base.peekValue(arguments);
this.x = point.x;
this.y = point.y;
if (next && next.x !== undefined) {
// new Rectangle(point1, point2) // new Rectangle(point1, point2)
var point1 = Point.read(arguments, 0, 1); var point2 = Point.read(arguments);
var point2 = Point.read(arguments, 1, 1); this.width = point2.x - point.x;
this.x = point1.x; this.height = point2.y - point.y;
this.y = point1.y;
this.width = point2.x - point1.x;
this.height = point2.y - point1.y;
if (this.width < 0) { if (this.width < 0) {
this.x = point2.x; this.x = point2.x;
this.width = -this.width; this.width = -this.width;
@ -79,22 +95,22 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
} }
} else { } else {
// new Rectangle(point, size) // new Rectangle(point, size)
var point = Point.read(arguments, 0, 1); var size = Size.read(arguments);
var size = Size.read(arguments, 1, 1);
this.x = point.x;
this.y = point.y;
this.width = size.width; this.width = size.width;
this.height = size.height; this.height = size.height;
} }
if (this._read)
this._read = arguments._index;
} else if (arg0) { } else if (arg0) {
// Use 0 as defaults, in case we're reading from a Point or Size // new Rectangle(rect)
// Use 0 as defaults, in case we're not reading from a Rectangle,
// but a Point or Size instead
this.x = arg0.x || 0; this.x = arg0.x || 0;
this.y = arg0.y || 0; this.y = arg0.y || 0;
this.width = arg0.width || 0; this.width = arg0.width || 0;
this.height = arg0.height || 0; this.height = arg0.height || 0;
} else { if (this._read)
// new Rectangle() this._read = 1;
this.x = this.y = this.width = this.height = 0;
} }
}, },

View file

@ -27,6 +27,9 @@
* console.log(size.height); // 5 * console.log(size.height); // 5
*/ */
var Size = this.Size = Base.extend(/** @lends Size# */{ var Size = this.Size = Base.extend(/** @lends Size# */{
// Tell Base.read that the Point constructor supporst reading with index
_readIndex: true,
// DOCS: improve Size class description // DOCS: improve Size class description
/** /**
* Creates a Size object with the given width and height values. * Creates a Size object with the given width and height values.
@ -91,28 +94,34 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
* console.log(size.height); // 50 * console.log(size.height); // 50
*/ */
initialize: function(arg0, arg1) { initialize: function(arg0, arg1) {
if (arg1 !== undefined) { var type = typeof arg0;
if (type === 'number') {
var hasHeight = typeof arg1 === 'number';
this.width = arg0; this.width = arg0;
this.height = arg1; this.height = hasHeight ? arg1 : arg0;
} else if (arg0 !== undefined) { if (this._read)
if (arg0 == null) { this._read = hasHeight ? 2 : 1;
this.width = this.height = 0; } else if (type === 'undefined' || arg0 === null) {
} else if (arg0.width !== undefined) { this.width = this.height = 0;
if (this._read)
this._read = arg0 === null ? 1 : 0;
} else {
if (typeof arg0.width !== 'undefined') {
this.width = arg0.width; this.width = arg0.width;
this.height = arg0.height; this.height = arg0.height;
} else if (arg0.x !== undefined) {
this.width = arg0.x;
this.height = arg0.y;
} else if (Array.isArray(arg0)) { } else if (Array.isArray(arg0)) {
this.width = arg0[0]; this.width = arg0[0];
this.height = arg0.length > 1 ? arg0[1] : arg0[0]; this.height = arg0.length > 1 ? arg0[1] : arg0[0];
} else if (typeof arg0 === 'number') { } else if (typeof arg0.x !== 'undefined') {
this.width = this.height = arg0; this.width = arg0.x;
this.height = arg0.y;
} else { } else {
this.width = this.height = 0; this.width = this.height = 0;
if (this._read)
this._read = 0;
} }
} else { if (this._read)
this.width = this.height = 0; this._read = 1;
} }
}, },

View file

@ -207,16 +207,20 @@ var Color = this.Color = Base.extend(new function() {
}; };
var fields = /** @lends Color# */{ var fields = /** @lends Color# */{
// Tell Base.read that we do not want null to be converted to a color.
_readNull: true, _readNull: true,
// Tell Base.read that the Point constructor supporst reading with index
_readIndex: true,
initialize: function(arg) { initialize: function(arg) {
var isArray = Array.isArray(arg), var isArray = Array.isArray(arg),
type = this._colorType; type = this._colorType,
res;
if (typeof arg === 'object' && !isArray) { if (typeof arg === 'object' && !isArray) {
if (!type) { if (!type) {
// Called on the abstract Color class. Guess color type // Called on the abstract Color class. Guess color type
// from arg // from arg
return arg.red !== undefined res = arg.red !== undefined
? new RgbColor(arg.red, arg.green, arg.blue, arg.alpha) ? new RgbColor(arg.red, arg.green, arg.blue, arg.alpha)
: arg.gray !== undefined : arg.gray !== undefined
? new GrayColor(arg.gray, arg.alpha) ? new GrayColor(arg.gray, arg.alpha)
@ -227,33 +231,41 @@ var Color = this.Color = Base.extend(new function() {
? new HsbColor(arg.hue, arg.saturation, arg.brightness, ? new HsbColor(arg.hue, arg.saturation, arg.brightness,
arg.alpha) arg.alpha)
: new RgbColor(); // Fallback : new RgbColor(); // Fallback
if (this._read)
res._read = 1;
} else { } else {
// Called on a subclass instance. Return the converted // Called on a subclass instance. Return the converted
// color. // color.
return Color.read(arguments).convert(type); res = Color.read(arguments).convert(type);
if (this._read)
res._read = arguments._read;
} }
} else if (typeof arg === 'string') { } else if (typeof arg === 'string') {
var rgbColor = arg.match(/^#[0-9a-f]{3,6}$/i) var rgbColor = arg.match(/^#[0-9a-f]{3,6}$/i)
? hexToRgbColor(arg) ? hexToRgbColor(arg)
: nameToRgbColor(arg); : nameToRgbColor(arg);
return type res = type
? rgbColor.convert(type) ? rgbColor.convert(type)
: rgbColor; : rgbColor;
if (this._read)
res._read = 1;
} else { } else {
var components = isArray ? arg var components = isArray ? arg
: Array.prototype.slice.call(arguments); : Array.prototype.slice.call(arguments);
if (!type) { if (!type) {
// Called on the abstract Color class. Guess color type // Called on the abstract Color class. Guess color type
// from arg // from arg
//if (components.length >= 4) // var ctor = components.length >= 4
// return new CmykColor(components); // ? CmykColor
if (components.length >= 3) // : components.length >= 3
return new RgbColor(components); var ctor = components.length >= 3
return new GrayColor(components); ? RgbColor
: GrayColor;
res = new ctor(components);
} else { } else {
// Called on a subclass instance. Just copy over // Called on a subclass instance. Just copy over
// components. // components.
Base.each(this._components, res = Base.each(this._components,
function(name, i) { function(name, i) {
var value = components[i]; var value = components[i];
// Set internal propery directly // Set internal propery directly
@ -262,7 +274,10 @@ var Color = this.Color = Base.extend(new function() {
}, },
this); this);
} }
if (this._read)
res._read = res._components.length;
} }
return res;
}, },
/** /**

View file

@ -63,18 +63,45 @@ this.Base = Base.inject(/** @lends Base# */{
* cloned if they are already provided in the required type * cloned if they are already provided in the required type
*/ */
read: function(list, start, length, clone) { read: function(list, start, length, clone) {
var start = start || 0, var proto = this.prototype,
length = length || list.length - start; readIndex = proto._readIndex,
var obj = list[start]; index = start || readIndex && list._index || 0;
if (!length)
length = list.length - index;
var obj = list[index];
if (obj instanceof this if (obj instanceof this
// If the class defines _readNull, return null when nothing // If the class defines _readNull, return null when nothing
// was provided // was provided
|| this.prototype._readNull && obj == null && length <= 1) || proto._readNull && obj == null && length <= 1) {
if (readIndex)
list._index = index + 1;
return obj && clone ? obj.clone() : obj; return obj && clone ? obj.clone() : obj;
}
obj = new this(this.dont); obj = new this(this.dont);
return obj.initialize.apply(obj, start > 0 || length < list.length if (readIndex)
? Array.prototype.slice.call(list, start, start + length) obj._read = true;
obj = obj.initialize.apply(obj, index > 0 || length < list.length
? Array.prototype.slice.call(list, index, index + length)
: list) || obj; : list) || obj;
if (readIndex) {
list._index = index + obj._read;
// Have arguments._read point to the amount of args read in the
// last read() call
list._read = obj._read;
delete obj._read;
}
return obj;
},
peekValue: function(list, start) {
return list[list._index = start || list._index || 0];
},
readValue: function(list, start) {
var value = this.peekValue(list, start);
list._index++;
list._read = 1;
return value;
}, },
/** /**

View file

@ -107,10 +107,9 @@ HitResult = Base.extend(/** @lends HitResult# */{
* @private * @private
*/ */
getOptions: function(point, options) { getOptions: function(point, options) {
// Use _merged property to not repeatetly call merge in recursion.
return options && options._merged ? options : Base.merge({ return options && options._merged ? options : Base.merge({
// Use the converted options object to perform point conversion point: Point.read([point]),
// only once.
point: Point.read(arguments, 0, 1),
// Type of item, for instanceof check: PathItem, TexItem, etc // Type of item, for instanceof check: PathItem, TexItem, etc
type: null, type: null,
// Tolerance // Tolerance

View file

@ -115,7 +115,7 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
this._matrix = pointOrMatrix !== undefined this._matrix = pointOrMatrix !== undefined
? pointOrMatrix instanceof Matrix ? pointOrMatrix instanceof Matrix
? pointOrMatrix.clone() ? pointOrMatrix.clone()
: new Matrix().translate(Point.read(arguments, 0)) : new Matrix().translate(Point.read(arguments))
: new Matrix(); : new Matrix();
}, },

View file

@ -338,17 +338,16 @@ var Raster = this.Raster = PlacedItem.extend(/** @lends Raster# */{
* @param color the color that the pixel will be set to * @param color the color that the pixel will be set to
*/ */
setPixel: function(point, color) { setPixel: function(point, color) {
var hasPoint = arguments.length == 2; var _point = Point.read(arguments),
point = Point.read(arguments, 0, hasPoint ? 1 : 2); _color = Color.read(arguments);
color = Color.read(arguments, hasPoint ? 1 : 2);
var ctx = this.getContext(true), var ctx = this.getContext(true),
imageData = ctx.createImageData(1, 1), imageData = ctx.createImageData(1, 1),
alpha = color.getAlpha(); alpha = color.getAlpha();
imageData.data[0] = color.getRed() * 255; imageData.data[0] = _color.getRed() * 255;
imageData.data[1] = color.getGreen() * 255; imageData.data[1] = _color.getGreen() * 255;
imageData.data[2] = color.getBlue() * 255; imageData.data[2] = _color.getBlue() * 255;
imageData.data[3] = alpha != null ? alpha * 255 : 255; imageData.data[3] = alpha != null ? alpha * 255 : 255;
ctx.putImageData(imageData, point.x, point.y); ctx.putImageData(imageData, _point.x, _point.y);
}, },
// DOCS: document Raster#createData // DOCS: document Raster#createData

View file

@ -41,10 +41,9 @@ Path.inject({ statics: new function() {
* path.strokeColor = 'black'; * path.strokeColor = 'black';
*/ */
Line: function() { Line: function() {
var step = Math.floor(arguments.length / 2);
return new Path( return new Path(
Segment.read(arguments, 0, step), Point.read(arguments),
Segment.read(arguments, step, step) Point.read(arguments)
); );
}, },
@ -125,32 +124,27 @@ Path.inject({ statics: new function() {
* var path = new Path.RoundRectangle(rectangle, cornerSize); * var path = new Path.RoundRectangle(rectangle, cornerSize);
*/ */
RoundRectangle: function(rect, size) { RoundRectangle: function(rect, size) {
if (arguments.length == 2) { var _rect = Rectangle.read(arguments),
rect = Rectangle.read(arguments, 0, 1); _size = Size.min(Size.read(arguments),
size = Size.read(arguments, 1, 1); _rect.getSize(true).divide(2)),
} else if (arguments.length == 6) { path = new Path(),
rect = Rectangle.read(arguments, 0, 4); uSize = _size.multiply(kappa * 2),
size = Size.read(arguments, 4, 2); bl = _rect.getBottomLeft(true),
} tl = _rect.getTopLeft(true),
size = Size.min(size, rect.getSize(true).divide(2)); tr = _rect.getTopRight(true),
var path = new Path(), br = _rect.getBottomRight(true);
uSize = size.multiply(kappa * 2),
bl = rect.getBottomLeft(true),
tl = rect.getTopLeft(true),
tr = rect.getTopRight(true),
br = rect.getBottomRight(true);
path._add([ path._add([
new Segment(bl.add(size.width, 0), null, [-uSize.width, 0]), new Segment(bl.add(_size.width, 0), null, [-uSize.width, 0]),
new Segment(bl.subtract(0, size.height), [0, uSize.height], null), new Segment(bl.subtract(0, _size.height), [0, uSize.height], null),
new Segment(tl.add(0, size.height), null, [0, -uSize.height]), new Segment(tl.add(0, _size.height), null, [0, -uSize.height]),
new Segment(tl.add(size.width, 0), [-uSize.width, 0], null), new Segment(tl.add(_size.width, 0), [-uSize.width, 0], null),
new Segment(tr.subtract(size.width, 0), null, [uSize.width, 0]), new Segment(tr.subtract(_size.width, 0), null, [uSize.width, 0]),
new Segment(tr.add(0, size.height), [0, -uSize.height], null), new Segment(tr.add(0, _size.height), [0, -uSize.height], null),
new Segment(br.subtract(0, size.height), null, [0, uSize.height]), new Segment(br.subtract(0, _size.height), null, [0, uSize.height]),
new Segment(br.subtract(size.width, 0), [uSize.width, 0], null) new Segment(br.subtract(_size.width, 0), [uSize.width, 0], null)
]); ]);
path._closed = true; path._closed = true;
return path; return path;
@ -204,14 +198,10 @@ Path.inject({ statics: new function() {
* var path = new Path.Circle(new Point(100, 100), 50); * var path = new Path.Circle(new Point(100, 100), 50);
*/ */
Circle: function(center, radius) { Circle: function(center, radius) {
if (arguments.length == 3) { var _center = Point.read(arguments),
center = Point.read(arguments, 0, 2); _radius = Base.readValue(arguments);
radius = arguments[2]; return Path.Oval(new Rectangle(_center.subtract(_radius),
} else { Size.create(_radius * 2, _radius * 2)));
center = Point.read(arguments, 0, 1);
}
return Path.Oval(new Rectangle(center.subtract(radius),
Size.create(radius * 2, radius * 2)));
}, },
/** /**
@ -261,15 +251,17 @@ Path.inject({ statics: new function() {
* decahedron.fillColor = 'black'; * decahedron.fillColor = 'black';
*/ */
RegularPolygon: function(center, numSides, radius) { RegularPolygon: function(center, numSides, radius) {
center = Point.read(arguments, 0, 1); var _center = Point.read(arguments),
var path = new Path(), _numSides = Base.readValue(arguments),
step = 360 / numSides, _radius = Base.readValue(arguments),
three = !(numSides % 3), path = new Path(),
vector = new Point(0, three ? -radius : radius), step = 360 / _numSides,
three = !(_numSides % 3),
vector = new Point(0, three ? -_radius : _radius),
offset = three ? -1 : 0.5, offset = three ? -1 : 0.5,
segments = new Array(numSides); segments = new Array(_numSides);
for (var i = 0; i < numSides; i++) { for (var i = 0; i < _numSides; i++) {
segments[i] = new Segment(center.add( segments[i] = new Segment(_center.add(
vector.rotate((i + offset) * step))); vector.rotate((i + offset) * step)));
} }
path._add(segments); path._add(segments);
@ -299,15 +291,17 @@ Path.inject({ statics: new function() {
* path.fillColor = 'black'; * path.fillColor = 'black';
*/ */
Star: function(center, numPoints, radius1, radius2) { Star: function(center, numPoints, radius1, radius2) {
center = Point.read(arguments, 0, 1); var _center = Point.read(arguments),
numPoints *= 2; _numPoints = Base.readValue(arguments) * 2,
var path = new Path(), _radius1 = Base.readValue(arguments),
step = 360 / numPoints, _radius2 = Base.readValue(arguments),
path = new Path(),
step = 360 / _numPoints,
vector = new Point(0, -1), vector = new Point(0, -1),
segments = new Array(numPoints); segments = new Array(_numPoints);
for (var i = 0; i < numPoints; i++) { for (var i = 0; i < _numPoints; i++) {
segments[i] = new Segment(center.add( segments[i] = new Segment(_center.add(
vector.rotate(step * i).multiply(i % 2 ? radius2 : radius1))); vector.rotate(step * i).multiply(i % 2 ? _radius2 : _radius1)));
} }
path._add(segments); path._add(segments);
path._closed = true; path._closed = true;

View file

@ -1667,20 +1667,20 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
}, },
cubicCurveTo: function(handle1, handle2, to) { cubicCurveTo: function(handle1, handle2, to) {
handle1 = Point.read(arguments, 0, 1); var _handle1 = Point.read(arguments);
handle2 = Point.read(arguments, 1, 1); _handle2 = Point.read(arguments);
to = Point.read(arguments, 2, 1); _to = Point.read(arguments);
// First modify the current segment: // First modify the current segment:
var current = getCurrentSegment(this); var current = getCurrentSegment(this);
// Convert to relative values: // Convert to relative values:
current.setHandleOut(handle1.subtract(current._point)); current.setHandleOut(_handle1.subtract(current._point));
// And add the new segment, with handleIn set to c2 // And add the new segment, with handleIn set to c2
this._add([ new Segment(to, handle2.subtract(to)) ]); this._add([ new Segment(_to, _handle2.subtract(to)) ]);
}, },
quadraticCurveTo: function(handle, to) { quadraticCurveTo: function(handle, to) {
handle = Point.read(arguments, 0, 1); var _handle = Point.read(arguments),
to = Point.read(arguments, 1, 1); to = Point.read(arguments);
// This is exact: // This is exact:
// If we have the three quad points: A E D, // If we have the three quad points: A E D,
// and the cubic is A B C D, // and the cubic is A B C D,
@ -1688,26 +1688,26 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
// C = E + 1/3 (D - E) // C = E + 1/3 (D - E)
var current = getCurrentSegment(this)._point; var current = getCurrentSegment(this)._point;
this.cubicCurveTo( this.cubicCurveTo(
handle.add(current.subtract(handle).multiply(1/3)), _handle.add(current.subtract(_handle).multiply(1 / 3)),
handle.add(to.subtract(handle).multiply(1/3)), _handle.add(to.subtract(_handle).multiply(1 / 3)),
to _to
); );
}, },
curveTo: function(through, to, parameter) { curveTo: function(through, to, parameter) {
through = Point.read(arguments, 0, 1); var _through = Point.read(arguments),
to = Point.read(arguments, 1, 1); _to = Point.read(arguments),
var t = Base.pick(parameter, 0.5), t = Base.pick(Base.readValue(arguments), 0.5),
t1 = 1 - t, t1 = 1 - t,
current = getCurrentSegment(this)._point, current = getCurrentSegment(this)._point,
// handle = (through - (1 - t)^2 * current - t^2 * to) / // handle = (through - (1 - t)^2 * current - t^2 * to) /
// (2 * (1 - t) * t) // (2 * (1 - t) * t)
handle = through.subtract(current.multiply(t1 * t1)) handle = _through.subtract(current.multiply(t1 * t1))
.subtract(to.multiply(t * t)).divide(2 * t * t1); .subtract(_to.multiply(t * t)).divide(2 * t * t1);
if (handle.isNaN()) if (handle.isNaN())
throw new Error( throw new Error(
'Cannot put a curve through points with parameter = ' + t); 'Cannot put a curve through points with parameter = ' + t);
this.quadraticCurveTo(handle, to); this.quadraticCurveTo(handle, _to);
}, },
// PORT: New implementation back to Scriptographer // PORT: New implementation back to Scriptographer
@ -1715,17 +1715,20 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
// Get the start point: // Get the start point:
var current = getCurrentSegment(this), var current = getCurrentSegment(this),
from = current._point, from = current._point,
through; through,
if (clockwise === undefined) point = Point.read(arguments),
clockwise = true; next = Base.peekValue(arguments);
if (typeof clockwise === 'boolean') { if (/boolean|undefined/.test(typeof next)) {
to = Point.read(arguments, 0, 1); // arcTo(to, clockwise)
to = point;
clockwise = next;
var middle = from.add(to).divide(2), var middle = from.add(to).divide(2),
through = middle.add(middle.subtract(from).rotate( through = middle.add(middle.subtract(from).rotate(
clockwise ? -90 : 90)); clockwise ? -90 : 90));
} else { } else {
through = Point.read(arguments, 0, 1); // arcTo(through, to)
to = Point.read(arguments, 1, 1); through = point;
to = Point.read(arguments);
} }
// Construct the two perpendicular middle lines to (from, through) // Construct the two perpendicular middle lines to (from, through)
// and (through, to), and intersect them to get the center // and (through, to), and intersect them to get the center

View file

@ -73,7 +73,7 @@ var SegmentPoint = Point.extend({
} else { } else {
// If not Point-like already, read Point from pt = 3rd argument // If not Point-like already, read Point from pt = 3rd argument
if ((x = pt.x) === undefined) { if ((x = pt.x) === undefined) {
pt = Point.read(arguments, 2, 1); pt = Point.read(arguments, 2);
x = pt.x; x = pt.x;
} }
y = pt.y; y = pt.y;