Mercurial > hg > digilib
comparison client/digitallibrary/jquery/dlGeometry.js @ 599:0d6fa11f7f98 jquery
geometry classes as extra file
| author | robcast |
|---|---|
| date | Thu, 13 Jan 2011 14:52:13 +0100 |
| parents | |
| children | b930fa64c684 |
comparison
equal
deleted
inserted
replaced
| 598:81723e7efe82 | 599:0d6fa11f7f98 |
|---|---|
| 1 /* digilib geometry classes | |
| 2 * should be integrated into jquery.digilib.js | |
| 3 */ | |
| 4 | |
| 5 var dlGeometry = function() { | |
| 6 /* | |
| 7 * Size class | |
| 8 */ | |
| 9 var size = function (w, h) { | |
| 10 var that = { | |
| 11 width : parseFloat(w), | |
| 12 height : parseFloat(h) | |
| 13 }; | |
| 14 that.equals = function(other) { | |
| 15 return (this.width === other.width && this.height === other.height); | |
| 16 }; | |
| 17 that.toString = function() { | |
| 18 return (this.width + "x" + this.height); | |
| 19 }; | |
| 20 return that; | |
| 21 }; | |
| 22 | |
| 23 /* | |
| 24 * Position class | |
| 25 */ | |
| 26 var position = function (x, y) { | |
| 27 var that = { | |
| 28 x : parseFloat(x), | |
| 29 y : parseFloat(y) | |
| 30 }; | |
| 31 that.equals = function(other) { | |
| 32 return (this.x === other.x && this.y === other.y); | |
| 33 }; | |
| 34 that.toString = function() { | |
| 35 return (this.x + "," + this.y); | |
| 36 }; | |
| 37 return that; | |
| 38 }; | |
| 39 /* | |
| 40 * Rectangle class | |
| 41 */ | |
| 42 var rectangle = function (x, y, w, h) { | |
| 43 var that = {}; | |
| 44 if (typeof x === "object") { | |
| 45 // assume x and y are Position | |
| 46 that = { | |
| 47 x : x.x, | |
| 48 y : x.y, | |
| 49 width : y.x - x.x, | |
| 50 height : y.y - x.y | |
| 51 }; | |
| 52 } else { | |
| 53 that = { | |
| 54 x : parseFloat(x), | |
| 55 y : parseFloat(y), | |
| 56 width : parseFloat(w), | |
| 57 height : parseFloat(h) | |
| 58 }; | |
| 59 } | |
| 60 // returns a copy of this Rectangle | |
| 61 that.copy = function() { | |
| 62 return rectangle(this.x, this.y, this.width, this.height); | |
| 63 }; | |
| 64 // returns the position of this Rectangle | |
| 65 that.getPosition = function() { | |
| 66 return position(this.x, this.y); | |
| 67 }; | |
| 68 // returns the upper left corner position | |
| 69 that.getPt1 = that.getPosition; | |
| 70 // returns the lower right corner position of this Rectangle | |
| 71 that.getPt2 = function() { | |
| 72 return position(this.x + this.width, this.y + this.height); | |
| 73 }; | |
| 74 // sets the upper left corner to position pos | |
| 75 that.setPt1 = function(pos) { | |
| 76 this.x = pos.x; | |
| 77 this.y = pos.y; | |
| 78 return this; | |
| 79 }; | |
| 80 that.setPt2 = function(pos) { | |
| 81 // sets the lower right corner to position pos | |
| 82 this.width = pos.x - this.x; | |
| 83 this.height = pos.y - this.y; | |
| 84 return this; | |
| 85 }; | |
| 86 that.getCenter = function() { | |
| 87 // returns the center position of this Rectangle | |
| 88 return position(this.x + this.width / 2, this.y + this.height / 2); | |
| 89 }; | |
| 90 that.setCenter = function(pos) { | |
| 91 // moves this Rectangle's center to position pos | |
| 92 this.x = pos.x - this.width / 2; | |
| 93 this.y = pos.y - this.height / 2; | |
| 94 return this; | |
| 95 }; | |
| 96 that.getSize = function() { | |
| 97 // returns the size of this Rectangle | |
| 98 return size(this.width, this.height); | |
| 99 }; | |
| 100 that.equals = function(other) { | |
| 101 // equal props | |
| 102 var eq = (this.x === other.x && this.y === other.y && | |
| 103 this.width === other.width); | |
| 104 return eq; | |
| 105 }; | |
| 106 that.getArea = function() { | |
| 107 // returns the area of this Rectangle | |
| 108 return (this.width * this.height); | |
| 109 }; | |
| 110 that.normalize = function() { | |
| 111 // eliminates negative width and height | |
| 112 var p = this.getPt2(); | |
| 113 this.x = Math.min(this.x, p.x); | |
| 114 this.y = Math.min(this.y, p.y); | |
| 115 this.width = Math.abs(this.width); | |
| 116 this.height = Math.abs(this.height); | |
| 117 return this; | |
| 118 }; | |
| 119 that.containsPosition = function(pos) { | |
| 120 // returns if Position "pos" lies inside of this rectangle | |
| 121 var ct = ((pos.x >= this.x) && (pos.y >= this.y) && | |
| 122 (pos.x <= this.x + this.width) && (pos.y <= this.y + this.width)); | |
| 123 return ct; | |
| 124 }; | |
| 125 that.containsRect = function(rect) { | |
| 126 // returns if rectangle "rect" is contained in this rectangle | |
| 127 return (this.containsPosition(rect.getPt1()) && this.containsPosition(rect.getPt2())); | |
| 128 }; | |
| 129 that.stayInside = function(rect) { | |
| 130 // changes this rectangle's x/y values so it stays inside of rectangle rect | |
| 131 // keeping the proportions | |
| 132 if (this.x < rect.x) { | |
| 133 this.x = rect.x; | |
| 134 } | |
| 135 if (this.y < rect.y) { | |
| 136 this.y = rect.y; | |
| 137 } | |
| 138 if (this.x + this.width > rect.x + rect.width) { | |
| 139 this.x = rect.x + rect.width - this.width; | |
| 140 } | |
| 141 if (this.y + this.height > rect.y + rect.height) { | |
| 142 this.y = rect.y + rect.height - this.height; | |
| 143 } | |
| 144 return this; | |
| 145 }; | |
| 146 that.clipTo = function(rect) { | |
| 147 // clips this rectangle so it stays inside of rectangle rect | |
| 148 var p1 = rect.getPt1(); | |
| 149 var p2 = rect.getPt2(); | |
| 150 var this2 = this.getPt2(); | |
| 151 this.setPt1(position(Math.max(this.x, p1.x), Math.max(this.y, p1.y))); | |
| 152 this.setPt2(position(Math.min(this2.x, p2.x), Math.min(this2.y, p2.y))); | |
| 153 return this; | |
| 154 }; | |
| 155 that.intersect = function(rect) { | |
| 156 // returns the intersection of the given Rectangle and this one | |
| 157 // FIX ME: not really, it should return null if there is no overlap | |
| 158 var sec = rect.copy(); | |
| 159 if (sec.x < this.x) { | |
| 160 sec.width = sec.width - (this.x - sec.x); | |
| 161 sec.x = this.x; | |
| 162 } | |
| 163 if (sec.y < this.y) { | |
| 164 sec.height = sec.height - (this.y - sec.y); | |
| 165 sec.y = this.y; | |
| 166 } | |
| 167 if (sec.x + sec.width > this.x + this.width) { | |
| 168 sec.width = (this.x + this.width) - sec.x; | |
| 169 } | |
| 170 if (sec.y + sec.height > this.y + this.height) { | |
| 171 sec.height = (this.y + this.height) - sec.y; | |
| 172 } | |
| 173 return sec; | |
| 174 }; | |
| 175 that.fit = function(rect) { | |
| 176 // returns a Rectangle that fits into this one (by moving first) | |
| 177 var sec = rect.copy(); | |
| 178 sec.x = Math.max(sec.x, this.x); | |
| 179 sec.y = Math.max(sec.y, this.x); | |
| 180 if (sec.x + sec.width > this.x + this.width) { | |
| 181 sec.x = this.x + this.width - sec.width; | |
| 182 } | |
| 183 if (sec.y + sec.height > this.y + this.height) { | |
| 184 sec.y = this.y + this.height - sec.height; | |
| 185 } | |
| 186 return sec.intersect(this); | |
| 187 }; | |
| 188 that.toString = function() { | |
| 189 return this.width+"x"+this.height+"@"+this.x+","+this.y; | |
| 190 }; | |
| 191 return that; | |
| 192 }; | |
| 193 | |
| 194 /* | |
| 195 * Transform class | |
| 196 * | |
| 197 * defines a class of affine transformations | |
| 198 */ | |
| 199 var transform = function (spec) { | |
| 200 var that = { | |
| 201 m00 : spec.m00 || 1.0, | |
| 202 m01 : spec.m01 || 0.0, | |
| 203 m02 : spec.m02 || 0.0, | |
| 204 m10 : spec.m10 || 0.0, | |
| 205 m11 : spec.m11 || 1.0, | |
| 206 m12 : spec.m12 || 0.0, | |
| 207 m20 : spec.m20 || 0.0, | |
| 208 m21 : spec.m21 || 0.0, | |
| 209 m22 : spec.m22 || 1.0 | |
| 210 }; | |
| 211 that.concat = function(traf) { | |
| 212 // add Transform traf to this Transform | |
| 213 for (var i = 0; i < 3; i++) { | |
| 214 for (var j = 0; j < 3; j++) { | |
| 215 var c = 0.0; | |
| 216 for (var k = 0; k < 3; k++) { | |
| 217 c += traf["m"+i+k] * this["m"+k+j]; | |
| 218 } | |
| 219 this["m"+i+j] = c; | |
| 220 } | |
| 221 } | |
| 222 return this; | |
| 223 }; | |
| 224 that.transform = function(rect) { | |
| 225 // returns transformed Rectangle or Position with this Transform applied | |
| 226 var x = this.m00 * rect.x + this.m01 * rect.y + this.m02; | |
| 227 var y = this.m10 * rect.x + this.m11 * rect.y + this.m12; | |
| 228 if (rect.width) { | |
| 229 // transform the other corner points | |
| 230 var pt2 = rect.getPt2(); | |
| 231 var x2 = this.m00 * pt2.x + this.m01 * pt2.y + this.m02; | |
| 232 var y2 = this.m10 * pt2.x + this.m11 * pt2.y + this.m12; | |
| 233 var width = x2 - x; | |
| 234 var height = y2 - y; | |
| 235 return rectangle(x, y, width, height); | |
| 236 } | |
| 237 return position(x, y); | |
| 238 }; | |
| 239 that.invtransform = function(rect) { | |
| 240 // returns transformed Rectangle or Position with the inverse of this Transform applied | |
| 241 var det = this.m00 * this.m11 - this.m01 * this.m10; | |
| 242 var x = (this.m11 * rect.x - this.m01 * rect.y - this.m11 * this.m02 + this.m01 * this.m12) / det; | |
| 243 var y = (- this.m10 * rect.x + this.m00 * rect.y + this.m10 * this.m02 - this.m00 * this.m12) / det; | |
| 244 if (rect.width) { | |
| 245 // transform the other corner points | |
| 246 var pt2 = rect.getPt2(); | |
| 247 var x2 = (this.m11 * pt2.x - this.m01 * pt2.y - this.m11 * this.m02 + this.m01 * this.m12) / det; | |
| 248 var y2 = (- this.m10 * pt2.x + this.m00 * pt2.y + this.m10 * this.m02 - this.m00 * this.m12) / det; | |
| 249 var width = x2 - x; | |
| 250 var height = y2 - y; | |
| 251 return rectangle(x, y, width, height); | |
| 252 } | |
| 253 return position(x, y); | |
| 254 }; | |
| 255 that.getRotation = getRotation; | |
| 256 that.getTranslation = getTranslation; | |
| 257 that.getScale = getScale; | |
| 258 | |
| 259 return that; | |
| 260 }; | |
| 261 | |
| 262 transform.getRotation = function (angle, pos) { | |
| 263 // returns a Transform that is a rotation by angle degrees around [pos.x, pos.y] | |
| 264 if (angle !== 0) { | |
| 265 var t = 2.0 * Math.PI * parseFloat(angle) / 360.0; | |
| 266 var traf = { | |
| 267 m00 : Math.cos(t), | |
| 268 m01 : - Math.sin(t), | |
| 269 m10 : Math.sin(t), | |
| 270 m11 : Math.cos(t), | |
| 271 m02 : pos.x - pos.x * Math.cos(t) + pos.y * Math.sin(t), | |
| 272 m12 : pos.y - pos.x * Math.sin(t) - pos.y * Math.cos(t) | |
| 273 }; | |
| 274 return transform(traf); | |
| 275 } | |
| 276 return transform(); | |
| 277 }; | |
| 278 | |
| 279 transform.getTranslation = function (pos) { | |
| 280 // returns a Transform that is a translation by [pos.x, pos,y] | |
| 281 var traf = { | |
| 282 m02 : pos.x, | |
| 283 m12 : pos.y | |
| 284 }; | |
| 285 return transform(traf); | |
| 286 }; | |
| 287 | |
| 288 transform.getScale = function (size) { | |
| 289 // returns a Transform that is a scale by [size.width, size.height] | |
| 290 var traf = { | |
| 291 m00 : size.width, | |
| 292 m11 : size.height | |
| 293 }; | |
| 294 return transform(traf); | |
| 295 }; | |
| 296 | |
| 297 // export functions | |
| 298 var that = { | |
| 299 size : size, | |
| 300 position : position, | |
| 301 rectangle : rectangle, | |
| 302 transform : transform | |
| 303 }; | |
| 304 | |
| 305 return that; | |
| 306 }; |
