Mercurial > hg > digilib-old
changeset 606:8204615dad77 jquery
geometry classes as extra file
author | robcast |
---|---|
date | Thu, 13 Jan 2011 14:52:13 +0100 |
parents | aee94e4a8c48 |
children | f5d5cae64828 |
files | client/digitallibrary/jquery/dlGeometry.js |
diffstat | 1 files changed, 306 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/digitallibrary/jquery/dlGeometry.js Thu Jan 13 14:52:13 2011 +0100 @@ -0,0 +1,306 @@ +/* digilib geometry classes + * should be integrated into jquery.digilib.js + */ + +var dlGeometry = function() { +/* + * Size class + */ + var size = function (w, h) { + var that = { + width : parseFloat(w), + height : parseFloat(h) + }; + that.equals = function(other) { + return (this.width === other.width && this.height === other.height); + }; + that.toString = function() { + return (this.width + "x" + this.height); + }; + return that; + }; + +/* + * Position class + */ + var position = function (x, y) { + var that = { + x : parseFloat(x), + y : parseFloat(y) + }; + that.equals = function(other) { + return (this.x === other.x && this.y === other.y); + }; + that.toString = function() { + return (this.x + "," + this.y); + }; + return that; + }; +/* + * Rectangle class + */ + var rectangle = function (x, y, w, h) { + var that = {}; + if (typeof x === "object") { + // assume x and y are Position + that = { + x : x.x, + y : x.y, + width : y.x - x.x, + height : y.y - x.y + }; + } else { + that = { + x : parseFloat(x), + y : parseFloat(y), + width : parseFloat(w), + height : parseFloat(h) + }; + } + // returns a copy of this Rectangle + that.copy = function() { + return rectangle(this.x, this.y, this.width, this.height); + }; + // returns the position of this Rectangle + that.getPosition = function() { + return position(this.x, this.y); + }; + // returns the upper left corner position + that.getPt1 = that.getPosition; + // returns the lower right corner position of this Rectangle + that.getPt2 = function() { + return position(this.x + this.width, this.y + this.height); + }; + // sets the upper left corner to position pos + that.setPt1 = function(pos) { + this.x = pos.x; + this.y = pos.y; + return this; + }; + that.setPt2 = function(pos) { + // sets the lower right corner to position pos + this.width = pos.x - this.x; + this.height = pos.y - this.y; + return this; + }; + that.getCenter = function() { + // returns the center position of this Rectangle + return position(this.x + this.width / 2, this.y + this.height / 2); + }; + that.setCenter = function(pos) { + // moves this Rectangle's center to position pos + this.x = pos.x - this.width / 2; + this.y = pos.y - this.height / 2; + return this; + }; + that.getSize = function() { + // returns the size of this Rectangle + return size(this.width, this.height); + }; + that.equals = function(other) { + // equal props + var eq = (this.x === other.x && this.y === other.y && + this.width === other.width); + return eq; + }; + that.getArea = function() { + // returns the area of this Rectangle + return (this.width * this.height); + }; + that.normalize = function() { + // eliminates negative width and height + var p = this.getPt2(); + this.x = Math.min(this.x, p.x); + this.y = Math.min(this.y, p.y); + this.width = Math.abs(this.width); + this.height = Math.abs(this.height); + return this; + }; + that.containsPosition = function(pos) { + // returns if Position "pos" lies inside of this rectangle + var ct = ((pos.x >= this.x) && (pos.y >= this.y) && + (pos.x <= this.x + this.width) && (pos.y <= this.y + this.width)); + return ct; + }; + that.containsRect = function(rect) { + // returns if rectangle "rect" is contained in this rectangle + return (this.containsPosition(rect.getPt1()) && this.containsPosition(rect.getPt2())); + }; + that.stayInside = function(rect) { + // changes this rectangle's x/y values so it stays inside of rectangle rect + // keeping the proportions + if (this.x < rect.x) { + this.x = rect.x; + } + if (this.y < rect.y) { + this.y = rect.y; + } + if (this.x + this.width > rect.x + rect.width) { + this.x = rect.x + rect.width - this.width; + } + if (this.y + this.height > rect.y + rect.height) { + this.y = rect.y + rect.height - this.height; + } + return this; + }; + that.clipTo = function(rect) { + // clips this rectangle so it stays inside of rectangle rect + var p1 = rect.getPt1(); + var p2 = rect.getPt2(); + var this2 = this.getPt2(); + this.setPt1(position(Math.max(this.x, p1.x), Math.max(this.y, p1.y))); + this.setPt2(position(Math.min(this2.x, p2.x), Math.min(this2.y, p2.y))); + return this; + }; + that.intersect = function(rect) { + // returns the intersection of the given Rectangle and this one + // FIX ME: not really, it should return null if there is no overlap + var sec = rect.copy(); + if (sec.x < this.x) { + sec.width = sec.width - (this.x - sec.x); + sec.x = this.x; + } + if (sec.y < this.y) { + sec.height = sec.height - (this.y - sec.y); + sec.y = this.y; + } + if (sec.x + sec.width > this.x + this.width) { + sec.width = (this.x + this.width) - sec.x; + } + if (sec.y + sec.height > this.y + this.height) { + sec.height = (this.y + this.height) - sec.y; + } + return sec; + }; + that.fit = function(rect) { + // returns a Rectangle that fits into this one (by moving first) + var sec = rect.copy(); + sec.x = Math.max(sec.x, this.x); + sec.y = Math.max(sec.y, this.x); + if (sec.x + sec.width > this.x + this.width) { + sec.x = this.x + this.width - sec.width; + } + if (sec.y + sec.height > this.y + this.height) { + sec.y = this.y + this.height - sec.height; + } + return sec.intersect(this); + }; + that.toString = function() { + return this.width+"x"+this.height+"@"+this.x+","+this.y; + }; + return that; + }; + +/* + * Transform class + * + * defines a class of affine transformations + */ + var transform = function (spec) { + var that = { + m00 : spec.m00 || 1.0, + m01 : spec.m01 || 0.0, + m02 : spec.m02 || 0.0, + m10 : spec.m10 || 0.0, + m11 : spec.m11 || 1.0, + m12 : spec.m12 || 0.0, + m20 : spec.m20 || 0.0, + m21 : spec.m21 || 0.0, + m22 : spec.m22 || 1.0 + }; + that.concat = function(traf) { + // add Transform traf to this Transform + for (var i = 0; i < 3; i++) { + for (var j = 0; j < 3; j++) { + var c = 0.0; + for (var k = 0; k < 3; k++) { + c += traf["m"+i+k] * this["m"+k+j]; + } + this["m"+i+j] = c; + } + } + return this; + }; + that.transform = function(rect) { + // returns transformed Rectangle or Position with this Transform applied + var x = this.m00 * rect.x + this.m01 * rect.y + this.m02; + var y = this.m10 * rect.x + this.m11 * rect.y + this.m12; + if (rect.width) { + // transform the other corner points + var pt2 = rect.getPt2(); + var x2 = this.m00 * pt2.x + this.m01 * pt2.y + this.m02; + var y2 = this.m10 * pt2.x + this.m11 * pt2.y + this.m12; + var width = x2 - x; + var height = y2 - y; + return rectangle(x, y, width, height); + } + return position(x, y); + }; + that.invtransform = function(rect) { + // returns transformed Rectangle or Position with the inverse of this Transform applied + var det = this.m00 * this.m11 - this.m01 * this.m10; + var x = (this.m11 * rect.x - this.m01 * rect.y - this.m11 * this.m02 + this.m01 * this.m12) / det; + var y = (- this.m10 * rect.x + this.m00 * rect.y + this.m10 * this.m02 - this.m00 * this.m12) / det; + if (rect.width) { + // transform the other corner points + var pt2 = rect.getPt2(); + var x2 = (this.m11 * pt2.x - this.m01 * pt2.y - this.m11 * this.m02 + this.m01 * this.m12) / det; + var y2 = (- this.m10 * pt2.x + this.m00 * pt2.y + this.m10 * this.m02 - this.m00 * this.m12) / det; + var width = x2 - x; + var height = y2 - y; + return rectangle(x, y, width, height); + } + return position(x, y); + }; + that.getRotation = getRotation; + that.getTranslation = getTranslation; + that.getScale = getScale; + + return that; + }; + + transform.getRotation = function (angle, pos) { + // returns a Transform that is a rotation by angle degrees around [pos.x, pos.y] + if (angle !== 0) { + var t = 2.0 * Math.PI * parseFloat(angle) / 360.0; + var traf = { + m00 : Math.cos(t), + m01 : - Math.sin(t), + m10 : Math.sin(t), + m11 : Math.cos(t), + m02 : pos.x - pos.x * Math.cos(t) + pos.y * Math.sin(t), + m12 : pos.y - pos.x * Math.sin(t) - pos.y * Math.cos(t) + }; + return transform(traf); + } + return transform(); + }; + + transform.getTranslation = function (pos) { + // returns a Transform that is a translation by [pos.x, pos,y] + var traf = { + m02 : pos.x, + m12 : pos.y + }; + return transform(traf); + }; + + transform.getScale = function (size) { + // returns a Transform that is a scale by [size.width, size.height] + var traf = { + m00 : size.width, + m11 : size.height + }; + return transform(traf); + }; + + // export functions + var that = { + size : size, + position : position, + rectangle : rectangle, + transform : transform + }; + + return that; + };