Move private createPoint() to Point.create().

This commit is contained in:
Jürg Lehni 2011-02-21 00:23:36 +01:00
parent 245c1e9b90
commit 04d2ed29c6

View file

@ -1,320 +1,321 @@
var Point = Base.extend(new function() { var Point = Base.extend({
beans: true,
/** initialize: function() {
* Provide a faster internal creator for Points out of two coordinates that if (arguments.length == 2) {
* does not rely on Point#initialize at all. This speeds up all math this.x = arguments[0];
* operations a lot. this.y = arguments[1];
*/ } else if (arguments.length == 1) {
function createPoint(x, y) { var arg = arguments[0];
var point = new Point(Point.dont); if (arg == null) {
point.x = x; this.x = this.y = 0;
point.y = y; } else if (arg.x !== undefined) {
return point; this.x = arg.x;
} this.y = arg.y;
} else if (arg.width !== undefined) {
return { this.x = arg.width;
beans: true, this.y = arg.height;
} else if (Array.isArray(arg)) {
initialize: function() { this.x = arg[0];
if (arguments.length == 2) { this.y = arg.length > 1 ? arg[1] : arg[0];
this.x = arguments[0]; } else if (typeof arg === 'number') {
this.y = arguments[1]; this.x = this.y = arg;
} else if (arguments.length == 1) {
var arg = arguments[0];
if (arg == null) {
this.x = this.y = 0;
} else if (arg.x !== undefined) {
this.x = arg.x;
this.y = arg.y;
} else if (arg.width !== undefined) {
this.x = arg.width;
this.y = arg.height;
} else if (Array.isArray(arg)) {
this.x = arg[0];
this.y = arg.length > 1 ? arg[1] : arg[0];
} else if (typeof arg === 'number') {
this.x = this.y = arg;
} else {
this.x = this.y = 0;
}
} else { } else {
this.x = this.y = 0; this.x = this.y = 0;
} }
}, } else {
this.x = this.y = 0;
}
},
clone: function() { clone: function() {
return createPoint(this.x, this.y); return Point.create(this.x, this.y);
}, },
add: function() { add: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
return createPoint(this.x + point.x, this.y + point.y); return Point.create(this.x + point.x, this.y + point.y);
}, },
subtract: function() { subtract: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
return createPoint(this.x - point.x, this.y - point.y); return Point.create(this.x - point.x, this.y - point.y);
}, },
multiply: function() { multiply: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
return createPoint(this.x * point.x, this.y * point.y); return Point.create(this.x * point.x, this.y * point.y);
}, },
divide: function() { divide: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
return createPoint(this.x / point.x, this.y / point.y); return Point.create(this.x / point.x, this.y / point.y);
}, },
modulo: function() { modulo: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
return createPoint(this.x % point.x, this.y % point.y); return Point.create(this.x % point.x, this.y % point.y);
}, },
negate: function() { negate: function() {
return createPoint(-this.x, -this.y); return Point.create(-this.x, -this.y);
}, },
equals: function() { equals: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
return this.x == point.x && this.y == point.y; return this.x == point.x && this.y == point.y;
}, },
getDistance: function() { getDistance: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
var px = point.x - this.x; var px = point.x - this.x;
var py = point.y - this.y; var py = point.y - this.y;
return Math.sqrt(px * px + py * py); return Math.sqrt(px * px + py * py);
}, },
getDistanceSquared: function() { getDistanceSquared: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
var px = point.x - this.x; var px = point.x - this.x;
var py = point.y - this.y; var py = point.y - this.y;
return px * px + py * py; return px * px + py * py;
}, },
getLength: function() { getLength: function() {
var point = Point.read(arguments); var point = Point.read(arguments);
return Math.sqrt(this.x * this.x + this.y * this.y); return Math.sqrt(this.x * this.x + this.y * this.y);
}, },
setLength: function(length) { setLength: function(length) {
if (this.isZero()) { if (this.isZero()) {
if (this._angle != null) { if (this._angle != null) {
var a = this._angle; var a = this._angle;
this.x = Math.cos(a) * length; this.x = Math.cos(a) * length;
this.y = Math.sin(a) * length; this.y = Math.sin(a) * length;
} else {
// Assume angle = 0
this.x = length;
// y is already 0
}
} else { } else {
var scale = length / this.length; // Assume angle = 0
if (scale == 0.0) { this.x = length;
// Calculate angle now, so it will be preserved even when // y is already 0
// x and y are 0
this.getAngle();
}
this.x *= scale;
this.y *= scale;
} }
}, } else {
var scale = length / this.length;
if (scale == 0.0) {
// Calculate angle now, so it will be preserved even when
// x and y are 0
this.getAngle();
}
this.x *= scale;
this.y *= scale;
}
},
normalize: function(length) { normalize: function(length) {
if (length === null) if (length === null)
length = 1; length = 1;
var len = this.length; var len = this.length;
var scale = len != 0 ? length / len : 0; var scale = len != 0 ? length / len : 0;
var res = createPoint(this.x * scale, this.y * scale); var res = Point.create(this.x * scale, this.y * scale);
// Preserve angle. // Preserve angle.
res._angle = this._angle; res._angle = this._angle;
return res; return res;
}, },
getAngleInRadians: function() { getAngleInRadians: function() {
return Math.atan2(this.y, this.x); // TODO: Not sur we want this one, but if so, just rely on
}, // this.getAngle(), which caches values internally?
return Math.atan2(this.y, this.x);
},
getAngleInDegrees: function() { getAngleInDegrees: function() {
return Math.atan2(this.y, this.x) * 180 / Math.PI; // TODO: Not sur we want this one, but if so, just rely on
}, // this.getAngle(), which caches values internally?
return Math.atan2(this.y, this.x) * 180 / Math.PI;
},
getQuadrant: function() { getQuadrant: function() {
if (this.x >= 0) { if (this.x >= 0) {
if (this.y >= 0) { if (this.y >= 0) {
return 1; return 1;
} else {
return 4;
}
} else { } else {
if (this.y >= 0) { return 4;
return 2;
} else {
return 3;
}
} }
}, } else {
if (this.y >= 0) {
setAngle: function(angle) { return 2;
angle = this._angle = angle * Math.PI / 180;
if (!this.isZero()) {
var length = this.length;
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
}
},
getAngle: function() {
var angle;
if (arguments.length) {
var point = Point.read(arguments);
var div = this.length * point.length;
if (div == 0) {
return NaN;
} else {
angle = Math.acos(this.dot(point) / div);
}
} else { } else {
if (this._angle == null) return 3;
this._angle = Math.atan2(this.y, this.x);
angle = this._angle;
}
return angle * 180 / Math.PI;
},
getDirectedAngle: function() {
var point = Point.read(arguments);
var angle = this.angle - point.angle;
var bounds = 180;
if (angle < - bounds) {
return angle + bounds * 2;
} else if (angle > bounds) {
return angle - bounds * 2;
} else {
return angle;
}
},
rotate: function(angle) {
angle = angle * Math.PI / 180;
var s = Math.sin(angle);
var c = Math.cos(angle);
return createPoint(
this.x * c - this.y * s,
this.y * c + this.x * s
);
},
// TODO: Shouldn't center just be the optional 2nd argument to rotate()?
rotateAround: function(angle, center) {
center = new Point(center);
return this.subtract(center).rotate(angle).add(this);
},
interpolate: function(point, t) {
return createPoint(
this.x * (1 - t) + point.x * t,
this.y * (1 - t) + point.y * t
);
},
// TODO: Need to adapt Rectangle.java first
// isInside: function(rect) {
// return rect.contains(this);
// },
isClose: function(point, tolerance) {
point = new Point(point);
return this.getDistance(point) < tolerance;
},
isParallel: function(point) {
return Math.abs(this.x / point.x - this.y / point.y) < 0.00001;
},
isZero: function() {
return this.x == 0 && this.y == 0;
},
isNaN: function() {
return isNaN(this.x) || isNaN(this.y);
},
round: function() {
return createPoint(Math.round(this.x), Math.round(this.y));
},
ceil: function() {
return createPoint(Math.ceil(this.x), Math.ceil(this.y));
},
floor: function() {
return createPoint(Math.floor(this.x), Math.floor(this.y));
},
abs: function() {
return createPoint(Math.abs(this.x), Math.abs(this.y));
},
dot: function() {
var point = Point.read(arguments);
return this.x * point.x + this.y * point.y;
},
cross: function() {
var point = Point.read(arguments);
return this.x * point.y - this.y - point.x;
},
project: function() {
var point = Point.read(arguments);
if (point.isZero()) {
return createPoint(0, 0);
} else {
var scale = this.dot(point) / point.dot(point);
return createPoint(
point.x * scale,
point.y * scale
);
}
},
toString: function() {
return '{ x: ' + this.x + ', y: ' + this.y + ' }';
},
statics: {
read: function(args, index) {
var index = index || 0, length = args.length - index;
if (length == 1 && args[index] instanceof Point) {
return args[index];
} else if (length != 0) {
var point = new Point(Point.dont);
point.initialize.apply(point, index > 0
? Array.prototype.slice.call(args, index) : args);
return point;
}
return null;
},
min: function(point1, point2) {
return createPoint(
Math.min(point1.x, point2.x),
Math.min(point1.y, point2.y));
},
max: function(point1, point2) {
return createPoint(
Math.max(point1.x, point2.x),
Math.max(point1.y, point2.y));
},
random: function() {
return createPoint(Math.random(), Math.random());
} }
} }
}; },
setAngle: function(angle) {
angle = this._angle = angle * Math.PI / 180;
if (!this.isZero()) {
var length = this.length;
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
}
},
getAngle: function() {
var angle;
if (arguments.length) {
var point = Point.read(arguments);
var div = this.length * point.length;
if (div == 0) {
return NaN;
} else {
angle = Math.acos(this.dot(point) / div);
}
} else {
if (this._angle == null)
this._angle = Math.atan2(this.y, this.x);
angle = this._angle;
}
return angle * 180 / Math.PI;
},
getDirectedAngle: function() {
var point = Point.read(arguments);
var angle = this.angle - point.angle;
var bounds = 180;
if (angle < - bounds) {
return angle + bounds * 2;
} else if (angle > bounds) {
return angle - bounds * 2;
} else {
return angle;
}
},
rotate: function(angle) {
angle = angle * Math.PI / 180;
var s = Math.sin(angle);
var c = Math.cos(angle);
return Point.create(
this.x * c - this.y * s,
this.y * c + this.x * s
);
},
// TODO: Shouldn't center just be the optional 2nd argument to rotate()?
rotateAround: function(angle, center) {
center = new Point(center);
return this.subtract(center).rotate(angle).add(this);
},
interpolate: function(point, t) {
return Point.create(
this.x * (1 - t) + point.x * t,
this.y * (1 - t) + point.y * t
);
},
// TODO: Need to adapt Rectangle.java first
// isInside: function(rect) {
// return rect.contains(this);
// },
isClose: function(point, tolerance) {
point = new Point(point);
return this.getDistance(point) < tolerance;
},
isParallel: function(point) {
return Math.abs(this.x / point.x - this.y / point.y) < 0.00001;
},
isZero: function() {
return this.x == 0 && this.y == 0;
},
isNaN: function() {
return isNaN(this.x) || isNaN(this.y);
},
round: function() {
return Point.create(Math.round(this.x), Math.round(this.y));
},
ceil: function() {
return Point.create(Math.ceil(this.x), Math.ceil(this.y));
},
floor: function() {
return Point.create(Math.floor(this.x), Math.floor(this.y));
},
abs: function() {
return Point.create(Math.abs(this.x), Math.abs(this.y));
},
dot: function() {
var point = Point.read(arguments);
return this.x * point.x + this.y * point.y;
},
cross: function() {
var point = Point.read(arguments);
return this.x * point.y - this.y - point.x;
},
project: function() {
var point = Point.read(arguments);
if (point.isZero()) {
return Point.create(0, 0);
} else {
var scale = this.dot(point) / point.dot(point);
return Point.create(
point.x * scale,
point.y * scale
);
}
},
toString: function() {
return '{ x: ' + this.x + ', y: ' + this.y + ' }';
},
statics: {
/**
* Provide a faster creator for Points out of two coordinates that
* does not rely on Point#initialize at all. This speeds up all math
* operations a lot.
*/
create: function(x, y) {
var point = new Point(Point.dont);
point.x = x;
point.y = y;
return point;
},
read: function(args, index) {
var index = index || 0, length = args.length - index;
if (length == 1 && args[index] instanceof Point) {
return args[index];
} else if (length != 0) {
var point = new Point(Point.dont);
point.initialize.apply(point, index > 0
? Array.prototype.slice.call(args, index) : args);
return point;
}
return null;
},
min: function(point1, point2) {
return Point.create(
Math.min(point1.x, point2.x),
Math.min(point1.y, point2.y));
},
max: function(point1, point2) {
return Point.create(
Math.max(point1.x, point2.x),
Math.max(point1.y, point2.y));
},
random: function() {
return Point.create(Math.random(), Math.random());
}
}
}); });