mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Merge remote branch 'origin/master'
This commit is contained in:
commit
5dcf416a7a
1 changed files with 292 additions and 291 deletions
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue