1 /** 2 * @fileOverview Raphael (svg javascript library) extension by 'macros' for civil engineering 3 * mechanics drawings (supports, deflections etc.). 4 * @author (c) 2011 <a href="mailto:jan.stransky.1@fsv.cvut.cz">Jan Stransky</a> 5 * @version Version 0.2 (2011-05-16) 6 * @requires raphael.js (see <a href="http://raphaeljs.com">Raphael library</a> loaded before loading this file 7 * @example 8 * var a = new Arrow(100,50,100,30); 9 * a.obj.strokeRed(); a.attr({...:...}); 10 * a.obj.update = functions(dx,dz) { ...; } 11 * a.obj.drag(move,reset);*/ 12 13 14 /** Generic function used for draging ojects. For each dragable object should be defined function update(dx,dz): e.g. moving only in x direction etc. 15 * @param {float} dx x increment of dragging 16 * @param {float} dz z increment of dragging 17 * @example 18 * a = new Arrow(100,59,199,30); 19 * a.update = function(dx,dz) { a.translate(dx,dz); } 20 * a.drag(move,init,reset) // make an object draggable using a.update() function when moving*/ 21 function move(dx,dz) { 22 this.update(dx - (this.deltax || 0), dz - (this.deltaz || 0)); 23 this.deltax = dx; 24 this.deltaz = dz; 25 } 26 27 /** Generic function used for draging ojects, see {@link move}*/ 28 function init() { this.deltax = this.deltaz = 0; } 29 30 /** Generic function used for draging ojects, see {@link move}*/ 31 function reset() { this.reset(); } 32 33 34 /* *********************************************************** 35 * other generic functions 36 ************************************************************/ 37 /** */ 38 Raphael = Raphael 39 /** */ 40 Raphael.el = Raphael.el; 41 42 // color setting 43 Raphael.el.fillRed = function() { this.attr({"fill":"#f00"}); } 44 Raphael.el.fillGreen = function() { this.attr({"fill":"#0f0"}); } 45 Raphael.el.fillBlue = function() { this.attr({"fill":"#00f"}); } 46 Raphael.el.fillYellow = function() { this.attr({"fill":"#ff0"}); } 47 Raphael.el.fillCyan = function() { this.attr({"fill":"#0ff"}); } 48 Raphael.el.fillMagenta = function() { this.attr({"fill":"#f0f"}); } 49 Raphael.el.fillOrange = function() { this.attr({"fill":"#f50"}); } 50 Raphael.el.fillBlack = function() { this.attr({"fill":"#000"}); } 51 Raphael.el.fillWhite = function() { this.attr({"fill":"#fff"}); } 52 Raphael.el.fillGray = function() { this.attr({"fill":"#777"}); } 53 Raphael.el.strokeRed = function() { this.attr({"stroke":"#f00"}); } 54 Raphael.el.strokeGreen = function() { this.attr({"stroke":"#0f0"}); } 55 Raphael.el.strokeBlue = function() { this.attr({"stroke":"#00f"}); } 56 Raphael.el.strokeYellow = function() { this.attr({"stroke":"#ff0"}); } 57 Raphael.el.strokeCyan = function() { this.attr({"stroke":"#0ff"}); } 58 Raphael.el.strokeMagenta = function() { this.attr({"stroke":"#f0f"}); } 59 Raphael.el.strokeOrange = function() { this.attr({"stroke":"#f50"}); } 60 Raphael.el.strokeBlack = function() { this.attr({"stroke":"#000"}); } 61 Raphael.el.strokeWhite = function() { this.attr({"stroke":"#fff"}); } 62 Raphael.el.strokeGray = function() { this.attr({"stroke":"#777"}); } 63 Raphael.el.red = function() { this.fillRed(); this.strokeRed(); } 64 Raphael.el.green = function() { this.fillGreen(); this.strokeGreen(); } 65 Raphael.el.blue = function() { this.fillBlue(); this.strokeBlue(); } 66 Raphael.el.yellow = function() { this.fillYellow(); this.strokeYellow(); } 67 Raphael.el.cyan = function() { this.fillCyan(); this.strokeCyan(); } 68 Raphael.el.magenta = function() { this.fillMagenta(); this.strokeMagenta(); } 69 Raphael.el.orange = function() { this.fillOrange(); this.strokeOrange(); } 70 Raphael.el.black = function() { this.fillBlack(); this.strokeBlack(); } 71 Raphael.el.white = function() { this.fillWhite(); this.strokeWhite(); } 72 Raphael.el.gray = function() { this.fillGreen(); this.strokeGray(); } 73 /** Set width of raphael object * @param w new width*/ 74 Raphael.el.setWidth = function(w) { this.attr({"stroke-width":w}); } 75 /** Returns [x,z] components of transformated vector 76 * @param {float} x x component of original vector 77 * @param {float} z z component of original vector 78 * @param {float} sin sin of angle of rotation 79 * @param {float} cos cos of angle of rotation 80 * @returns {[float,float]} coordinates of transformated vector*/ 81 vecTrans = function(x,z,sin,cos) { return [x*cos-z*sin,x*sin+z*cos]; } 82 83 84 /** Abstract class for simple geometrical objects 85 * @class Abstract class for geometrical object 86 */ 87 GeomObj = function() { 88 89 /** Sets basic parameters to created object 90 * @param {Raphael} raphael raphael instance 91 * @param {float} x x coordinate [pixel] 92 * @param {float} z z coordinate [pixel] 93 * @param {float} size size [pixel] 94 * @param {float} angle rotation angle from initial position 95 */ 96 this.init = function(raphael,x,z,size,angle) { 97 /** @property {Raphael} rapheal raphael instance connected to the object*/ 98 this.raphael = raphael 99 /** @property {float} x x coordinate of the object*/ 100 this.x = x; 101 /** @property {float} z z coordinate of the object*/ 102 this.z = z; 103 /** @property {float} size size of the object*/ 104 this.size = size; 105 /** @property {float} angle angle of the object*/ 106 this.angle = angle; 107 /** @property {Array} pathList svg array (list) of the object*/ 108 this.pathList = null; 109 /** @property {Raphael.el} obj pointer to actual raphael object*/ 110 this.obj = null; 111 /** @property {float} sin sin of this.angle*/ 112 this.sin = 0.; 113 /** @property {float} cos cos of this.angle*/ 114 this.cos = 0.; 115 116 this.setSinCos(); 117 this.setPathList(); 118 this.makeObj(this.raphael); 119 this.copies = []; 120 this.copiesShifts = []; 121 } 122 123 /** Compute sin and cos from stored angle*/ 124 this.setSinCos = function() { 125 this.sin = Math.sin(-this.angle*Math.PI/180); 126 this.cos = Math.cos(-this.angle*Math.PI/180); 127 } 128 /** Set new this.pathList of receiver (each derived class have to define its own setPathList method) 129 * @private 130 */ 131 this.setPathList = function() {} 132 /** Create a raphael object and assign it to this.obj 133 * @private 134 */ 135 this.makeObj = function() { this.obj = this.raphael.path(this.pathList); } 136 /** Set this.pathList to this.obj raphael object 137 * @private 138 */ 139 this.attrObjPath = function() { this.obj.attr({"path":this.pathList}); } 140 /** Sets new x position of receiver (this.x = x) 141 * @param {float} x new x coordinate [pixel] 142 */ 143 this.setX = function(x) { this.x = x; this.up(); } 144 /** Sets new z position of receiver (this.z = z) 145 * @param {float} z new z coordinate [pixel] 146 */ 147 this.setZ = function(z) { this.z = z; this.up(); } 148 /** Sets new x and z position of receiver (this.x = x; this.z = z) 149 * @param {float} x new x coordinate [pixel] 150 * @param {float} z new z coordinate [pixel] 151 */ 152 this.setXZ = function(x,z) { this.x = x; this.z = z; this.up(); } 153 /** Translate receiver in x direction (this.x += x) 154 * @param {float} dx distance to be translated [pixel] 155 */ 156 this.translateX = function(dx) { this.x += dx; this.up(); } 157 /** Translate receiver in x direction (this.z += dz) 158 * @param {float} dz distance to be translated [pixel] 159 */ 160 this.translateZ = function(dz) { this.z += dz; this.up(); } 161 /** Translate receiver in x and z direction (this.x += dx; this.z += dz) 162 * @param {float} dx distance to be translated in x direction [pixel] 163 * @param {float} dz distance to be translated in z direction [pixel] 164 */ 165 this.translate = function(dx,dz) { this.x += dx; this.z += dz; this.up(); } 166 /** Rotate receiver by given angle (this.angle += phi) 167 * @param {float} phi angle of rotation 168 */ 169 this.rotate = function(phi) { this.angle += phi; this.setSinCos(); this.up(); } 170 /** Set angle of receiver (this.angle = phi) 171 * @param {float} phi angle of rotation 172 */ 173 this.setAngle = function(phi) { this.angle = phi; this.setSinCos(); this.up(); } 174 this.copy = function(shifts) { for (var i in shifts) { this.copiesShifts.push(shifts[i]); this.copies.push(this.makeCopy()); this.up();} } 175 /** Make a copy of itself (each derived class to be copied have to define its own makeCopy method)*/ 176 this.makeCopy = function() { return; } 177 178 /** Update receiver (set this.pathList for given internal variables - x,z,angle... - as well as its copies) 179 * @public 180 */ 181 this.up = function() { 182 this.setPathList(); this.attrObjPath(); 183 for (var c in this.copies) { this.copies[c].setXZ(this.x+this.copiesShifts[c][0],this.z+this.copiesShifts[c][1]); } 184 } 185 } 186 187 188 /** Arrow 189 * @class represents arrow 190 * @borrows GeomObj#setX as this.setX 191 * @param {Raphael} raphael raphael instance 192 * @param {float} [x=0.] x coordinate of arrow tip [pixel] 193 * @param {float} [z=0.] z coordinate of arrow tip [pixel] 194 * @param {float} [size=100.] length of the whole arrow (its size) [pixel] 195 * @param {float} [angle=0.] the arrow will be rotated by this angle [deg] 196 * @param {float} [headLen=size/4.] length of the arrow head [pixel] 197 * @param {float} [headWidth=size/16.] width of the arrow head [pixel]*/ 198 Arrow = function(raphael,x,z,size,angle,headLen,headWidth) { 199 this.inheritFrom = GeomObj; this.inheritFrom(); 200 this.headLen = headLen || size/4. 201 this.headWidth = headWidth || size/16. 202 203 this.setPathList = function() { 204 this.pathList = [ 205 ["M",this.x,this.z], 206 ["L",this.x+this.cos*this.size,this.z+this.sin*this.size], 207 ["M",this.x+this.cos*this.headLen-this.sin*this.headWidth,this.z+this.sin*this.headLen+this.cos*this.headWidth], 208 ["L",this.x,this.z], 209 ["L",this.x+this.cos*this.headLen+this.sin*this.headWidth,this.z+this.sin*this.headLen-this.cos*this.headWidth]]; 210 } 211 /** Resize receiver in both direction 212 * @param {float} newSize new size of receiver*/ 213 this.resize = function(newSize) { 214 if (newSize>1) { this.headLen *= newSize/this.size; this.headWidth *= newSize/this.size; this.size=newSize; this.up(); } 215 } 216 this.makeCopy = function() { 217 var ret = new Arrow(this.raphael,this.x,this.z,this.size,this.angle,this.headLen,this.headWidth); 218 ret.obj.remove(); 219 ret.obj = this.obj.clone(); 220 return ret; 221 } 222 223 this.init(raphael,x||0,z||0,size||100,angle||0); 224 }; 225 226 /** Creates new arrrow object, for parameters meaning see {@link Arrow} 227 * @param {Raphael} raphael raphael instance 228 * @param {float} [x=0.] x coordinate of arrow tip [pixel] 229 * @param {float} [z=0.] z coordinate of arrow tip [pixel] 230 * @param {float} [size=100.] length of the whole arrow (its size) [pixel] 231 * @param {float} [angle=0.] the arrow will be rotated by this angle [deg] 232 * @param {float} [headLen=size/4.] length of the arrow head [pixel] 233 * @param {float} [headWidth=size/16.] width of the arrow head [pixel] 234 * returns {Arrow} new arrow object*/ 235 Arrow.create = function(raphael,x,z,size,angle,headLen,headWidth) { 236 return new Arrow(raphael,x,z,size,angle,headLen,headWidth); 237 } 238 239 240 /** Pin support 241 * @class represents pin support 242 * @param {Raphael} raphael raphael instance 243 * @param {float} [x=0.] x coordinate of supprt tip [pixel] 244 * @param {float} [z=0.] z coordinate of supprt tip [pixel] 245 * @param {float} [size=20.] height of the support [pixel] 246 * @param {float} [angle=0.] the support will be rotated by angle [deg] 247 * @param {bool|int} [sliding=true] if the support is sliding or not 248 * @param {float} [gap=5.] gap between triangle and line (sliding symbol) [pixel] 249 * @param {float} [ratio=0.7] width/height of the triangle [-]*/ 250 PinSupport = function(raphael,x,z,size,angle,sliding,gap,ratio) { 251 this.inheritFrom = GeomObj; this.inheritFrom(); 252 this.sliding = sliding || 0 253 this.ratio = ratio || .7; 254 this.gap = gap || 5; 255 this.setPathList = function() { 256 if (this.sliding) { 257 this.pathList = [ 258 ["M",this.x,this.z], 259 ["L", this.x - this.cos*this.ratio*this.size - this.sin*this.size, this.z - this.sin*this.ratio*this.size + this.cos*this.size], 260 ["L", this.x + this.cos*this.ratio*this.size - this.sin*this.size, this.z + this.sin*this.ratio*this.size + this.cos*this.size], 261 ["Z"], 262 ["M", this.x - this.cos*this.ratio*this.size - this.sin*(this.size+this.gap),this.z - this.sin*this.ratio*this.size + this.cos*(this.size+this.gap)], 263 ["L", this.x + this.cos*this.ratio*this.size - this.sin*(this.size+this.gap),this.z + this.sin*this.ratio*this.size + this.cos*(this.size+this.gap)]]; 264 } 265 else { 266 this.pathList = [ 267 ["M",this.x,this.z], 268 ["L", this.x - this.cos*this.ratio*this.size - this.sin*this.size, this.z - this.sin*this.ratio*this.size + this.cos*this.size], 269 ["L", this.x + this.cos*this.ratio*this.size - this.sin*this.size, this.z + this.sin*this.ratio*this.size + this.cos*this.size], 270 ["Z"]]; 271 } 272 } 273 this.makeCopy = function() { 274 var ret = new PinSupport(this.raphael,this.x,this.z,this.size,this.angle,this.sliding,this.gap,this.ratio); 275 ret.obj.remove(); 276 ret.obj = this.obj.clone(); 277 return ret; 278 } 279 280 this.init(raphael,x||0,z||0,size||20,angle||0); 281 } 282 283 284 /** Fixed support 285 * @class represents fixed support 286 * @param {Raphael} raphael raphael instance 287 * @param {float} [x=0.] x coordinate of the support center [pixel] 288 * @param {float} [z=0.] z coordinate of the support center [pixel] 289 * @param {float} [size=30.] size (height) of the support [pixel] 290 * @param {float} [angle=0.] the support will be rotated by angle [deg] 291 * @param {float} [ratio=2.] height/width (width of the 'flags') 292 * @param {int} [num=5] number of 'flags' 293 * @param {bool|int} [reversed=false] reversed direction of 'flags' 294 */ 295 FixedSupport = function(raphael,x,z,size,angle,ratio,num,reversed) { 296 this.inheritFrom = GeomObj; this.inheritFrom(); 297 this.ratio = ratio || .2; 298 this.num = num || 5; 299 this.reversed = reversed || 0; 300 301 this.setPathList = function() { 302 this.pathList = [ 303 ["M", this.x - this.sin*this.size*.5, this.z + this.cos*this.size*.5], 304 ["L", this.x + this.sin*this.size*.5, this.z - this.cos*this.size*.5]]; 305 if (this.reversed) { 306 for (var i=0; i<this.num; i++) { 307 var pt0 = vecTrans(0,this.size*(-.5+(i+1)/this.num),this.sin,this.cos); 308 var pt1 = vecTrans(-this.size*this.ratio,this.size*(-.5+i/this.num),this.sin,this.cos); 309 this.pathList.push(["M",this.x+pt0[0],this.z+pt0[1]]); 310 this.pathList.push(["L",this.x+pt1[0],this.z+pt1[1]]); 311 } 312 } 313 else { 314 for (var i=0; i<this.num; i++) { 315 var pt0 = vecTrans(0,this.size*(-.5+i/this.num),this.sin,this.cos); 316 var pt1 = vecTrans(-this.size*this.ratio,this.size*(-.5+(i+1)/this.num),this.sin,this.cos); 317 this.pathList.push(["M",this.x+pt0[0],this.z+pt0[1]]); 318 this.pathList.push(["L",this.x+pt1[0],this.z+pt1[1]]); 319 } 320 } 321 } 322 this.makeCopy = function() { 323 var ret = new FixedSupport(this.raphael,this.x,this.z,this.size,this.angle,this.ratio,this.num,this.reversed); 324 ret.obj.remove(); 325 ret.obj = this.obj.clone(); 326 return ret; 327 } 328 329 this.init(raphael,x||0,z||0,size||20,angle||0); 330 } 331 332 333 /************************************************************ 334 * 335 * Line 336 * input: 337 * raphael ... raphael instance 338 * nodeA ... 1st Node2d 339 * nodeB ... 2nd Node2d 340 * 341 ************************************************************/ 342 Line = function(raphael,nodeA,nodeB) { 343 this.raphael = raphael; 344 this.nodeA = nodeA; 345 this.nodeB = nodeB; 346 this.copies = []; 347 this.copiesNodes = [[],[]]; 348 349 this.setPathList = function() { this.pathList = [["M",this.nodeA.x,this.nodeA.z],["L",this.nodeB.x,this.nodeB.z]]; } 350 this.makeObj = function() { this.obj = this.raphael.path(this.pathList); } 351 this.setPathList(); 352 this.makeObj(); 353 this.attrObjPath = function() { this.obj.attr({"path":this.pathList}); } 354 this.up = function() { 355 this.setPathList(); this.attrObjPath(); 356 for (var c in this.copies) { this.copies[c].up(); } 357 } 358 this.copy = function(nodes) { // nodes=[[node1,node2,node3],[node4,node5,node6]] wll make lines 14,25,36 359 for (var n in nodes[0]) { 360 this.copiesNodes[0].push(nodes[0][n]); 361 this.copiesNodes[1].push(nodes[1][n]); 362 this.copies.push(this.makeCopy(this.copiesNodes[0][n],this.copiesNodes[1][n])); 363 } 364 } 365 this.makeCopy = function(nodeA,nodeB) { 366 var ret = new Line(this.raphael,nodeA,nodeB); 367 ret.obj.remove(); 368 ret.obj = this.obj.clone(); 369 return ret; 370 } 371 } 372 373 374 /************************************************************ 375 * 376 * Path (for easier modifying) 377 * input: 378 * raphael ... raphael instance 379 * pathList ... path list for raphael path 380 * 381 ************************************************************/ 382 Path = function(raphael,pathList) { 383 this.pathList = pathList || []; 384 this.obj = raphael.path(this.pathList); 385 // methods 386 this.attrObjPath = function() { this.obj.attr({"path":this.pathList}); } 387 this.setItem = function(i,j,val) { this.pathList[i][j] = val; this.attrObjPath(); } 388 this.iaddItem = function(i,j,val) { this.pathList[i][j] += val; this.attrObjPath(); } 389 this.setNewPath = function(newPathList) { this.pathList = newPathList; this.attrObjPath(); } 390 } 391 392 393 /************************************************************ 394 * 395 * Circle (for easier modifying) 396 * input: 397 * raphael ... raphael instance 398 * cx ... x coordinate of circles center (default 0.) 399 * cz ... z coordinate of circles center (default 0.) 400 * r ... circle radius (default 10.) 401 * 402 ************************************************************/ 403 Circle = function(raphael,x,z,r) { 404 this.x = x || 0; 405 this.z = z || 0; 406 this.r = r || 10; 407 this.copies = []; 408 this.copiesShifts = []; 409 this.raphael = raphael 410 this.obj = this.raphael.circle(this.x,this.z,this.r); 411 412 this.setR = function(r) { this.r = r; this.obj.attr({"r":r}); } 413 this.setX = function(x) { this.x = x; this.obj.attr({"cx":x}); } 414 this.setZ = function(z) { this.z = z; this.obj.attr({"cy":z}); } 415 this.setXZ = function(x,z) { this.x = x; this.z = z; this.obj.attr({"cx":x,"cy":z}); } 416 this.translateX = function(dx) { this.x += dx; this.obj.attr({"cx":this.x}); } 417 this.translateZ = function(dz) { this.z += dz; this.obj.attr({"cy":this.z}); } 418 this.translate = function(dx,dz) { this.x += dx; this.z += dz; this.obj.attr({"cx":this.x,"cy":this.z}); } 419 this.copy = function(shifts) { for (var i in shifts) { this.copiesShifts.push(shifts[i]); this.copies.push(this.makeCopy()); } } 420 this.makeCopy = function() { 421 var ret = new Circle(this.raphael,this.x,this.z,this.r) 422 ret.obj.remove(); 423 ret.obj = this.obj.clone(); 424 return ret; 425 } 426 this.up = function() { for (var c in this.copies) { this.copies[c].setXZ(this.x+this.copiesShifts[c][0],this.z+this.copiesShifts[c][1]); } } 427 } 428 429 /************************************************************ 430 * 431 * Slider (for easier modifying) 432 * input: 433 * raphael ... raphael instance 434 * nodeA ... 1st node 435 * nodeB ... 2nd node 436 * rcirc ... radius of slider's circle (default 5.) 437 * val1 ... value when the slider is at the very beginning (default 0.) 438 * val2 ... value when the slider is at the very end (default 1.) 439 * initVal ... initial value (default .5*(val1+val2)) 440 * gap ... gap between end of the slider's line and the 441 * slider's circle when the circle is at extreme position (default 3.) 442 * 443 ************************************************************/ 444 Slider = function(raphael,nodeA,nodeB,rcirc,val1,val2,initVal,gap) { 445 this.nodeA = nodeA; 446 this.nodeB = nodeB; 447 this.rcirc = rcirc || 5.; 448 this.gap = gap || 3.; 449 this.x1 = this.nodeA.x 450 this.z1 = this.nodeA.z 451 this.x2 = this.nodeB.x 452 this.z2 = this.nodeB.z 453 this.dx = this.x2 - this.x1; 454 this.dz = this.z2 - this.z1; 455 this.len = Math.sqrt(this.dx*this.dx+this.dz*this.dz); 456 this.cos = this.dx/this.len; 457 this.sin = this.dz/this.len; 458 this.start = this.gap+this.rcirc; 459 this.stop = this.len - this.start; 460 this.val1 = val1 || 0.; 461 this.val2 = val2 || 1.; 462 this.lenVals = this.len - 2*this.start; 463 if (this.lenVals<0) { 464 var initPos = this.len*.5; 465 this.xLeft = (this.x2+this.x1)*.5; 466 this.xRight = (this.x2+this.x1)*.5; 467 this.zLeft = (this.z2+this.z1)*.5; 468 this.zRight = (this.z2+this.z1)*.5; 469 } 470 else { 471 var initPos = this.start+this.lenVals/(this.val2-this.val1)*(initVal-this.val1); 472 if (initPos < this.start) { initPos = this.start; } 473 if (initPos > this.stop) { initPos = this.stop; } 474 this.xLeft = this.x1+this.start*this.cos; 475 this.xRight = this.x2-this.start*this.cos; 476 this.zLeft = this.z1+this.start*this.sin; 477 this.zRight = this.z2-this.start*this.sin; 478 } 479 this.line = new Line(raphael,this.nodeA,this.nodeB); 480 this.circ = new Circle(raphael,this.x1+this.cos*initPos,this.z1+this.sin*initPos,this.rcirc); 481 482 this.getVal = function() { 483 var dx = this.circ.x-this.x1-this.start*this.cos; 484 var dz = this.circ.z-this.z1-this.start*this.sin; 485 var len = Math.sqrt(dx*dx+dz*dz); 486 return this.val1+len*(this.val2-this.val1)/this.lenVals; 487 } 488 } 489 490 /************************************************************ 491 * 492 * Linear load 493 * input: 494 * raphael ... raphael instance 495 * nodeA ... 1st node 496 * nodeB ... 2nd node 497 * valx ... value of load in x direction (global) (default 0.) 498 * valz ... value of load in z direction (global) (default 0.) 499 * num ... numer of arrows (default 4) 500 * 501 ************************************************************/ 502 LinearLoad = function(raphael,nodeA,nodeB,valx,valz,num) { 503 this.nodeA = nodeA; 504 this.nodeB = nodeB; 505 this.valx = valx || 0; 506 this.valz = valz || 0; 507 this.num = num || 4; 508 509 this.setVals = function(valx,valz) { 510 this.valx = valx || 0; 511 this.valz = valz || 0; 512 this.up(); 513 } 514 this.geom = function() { 515 this.x1 = this.nodeA.x; 516 this.z1 = this.nodeA.z; 517 this.x2 = this.nodeB.x; 518 this.z2 = this.nodeB.z; 519 this.dx = this.x2-this.x1; 520 this.dz = this.z2-this.z1; 521 this.len = Math.sqrt(this.dx*this.dx+this.dz*this.dz); 522 this.cos = this.dx/this.len; 523 this.sin = this.dz/this.len; 524 this.lenVals = Math.sqrt(this.valx*this.valx+this.valz*this.valz); 525 this.cosVal = this.valx/this.lenVals; 526 this.sinVal = this.valz/this.lenVals; 527 } 528 this.setPathList = function() { 529 this.pathList = [["M",this.x1,this.z1],["L",this.x2,this.z2], 530 ["L",this.x2-this.valx,this.z2-this.valz],["L",this.x1-this.valx,this.z1-this.valz],["Z"]]; 531 var segLen = this.len/(this.num+1); 532 for (var i=1; i<=this.num; i++) { 533 this.pathList.push(["M",this.x1-this.valx+i*segLen*this.cos,this.z1-this.valz+i*segLen*this.sin]); 534 this.pathList.push(["L",this.x1+i*segLen*this.cos,this.z1+i*segLen*this.sin]); 535 this.pathList.push(["M", 536 this.x1+i*segLen*this.cos-this.cosVal*this.lenVals/4+this.sinVal*this.lenVals/16, 537 this.z1+i*segLen*this.sin-this.sinVal*this.lenVals/4-this.cosVal*this.lenVals/16]); 538 this.pathList.push(["L",this.x1+i*segLen*this.cos,this.z1+i*segLen*this.sin]); 539 this.pathList.push(["L", 540 this.x1+i*segLen*this.cos-this.cosVal*this.lenVals/4-this.sinVal*this.lenVals/16, 541 this.z1+i*segLen*this.sin-this.sinVal*this.lenVals/4+this.cosVal*this.lenVals/16]); 542 } 543 } 544 this.attrObjPath = function() { this.obj.attr({"path":this.pathList}); } 545 this.up = function() { this.geom(); this.setPathList(); this.attrObjPath(); } 546 547 this.obj = raphael.path(this.pathList); 548 549 this.up(); 550 } 551 552 553 /************************************************************ 554 * 555 * Text in rectangular frame 556 * input: 557 * x ... x coordinate of left lower corner [pixel] (default 100.) 558 * z ... z coordinate of left lower corner [pixel] (default 100.) 559 * width ... width [pixel] (default 100.) 560 * height ... height [pixel] (default 100.) 561 * str ... string to be shown (default "string") 562 * fontSize ... font size (default 20) 563 * 564 ************************************************************/ 565 TextRect = function(raphael,x,z,width,height,str,fontSize) { 566 this.x = x || 100.; 567 this.z = z || 100.; 568 this.width = width || 100.; 569 this.height = height || 100.; 570 this.str = str || "string"; 571 this.fontSize = fontSize || 20; 572 this.rect = raphael.rect(this.x,this.z-this.height,this.width,this.height); 573 this.text = raphael.text(this.x+.5*this.width,this.z-.5*this.height,this.str).attr({"font-size":this.fontSize}); 574 575 this.up = function() { 576 this.rect.attr({"x":this.x,"y":(this.z-this.height)}); 577 this.text.attr({"x":(this.x+.5*this.width),"y":(this.z-.5*this.height)}); 578 } 579 this.setX = function(x) { this.x = x; this.up(); } 580 this.setZ = function(z) { this.z = z; this.up(); } 581 this.setXZ = function(x,z) { this.x = x; this.z = z; this.up(); } 582 } 583 584 /************************************************************ 585 * 586 * Abstract class for curves (applied as internal forces, 587 * deflection etc.) 588 * 589 ************************************************************/ 590 CurveObj = function() { 591 this.init = function(raphael,nodeA,nodeB,scale,notClosedBegin,notClosedEnd,notClosedBase) { 592 this.raphael = raphael; 593 this.nodeA = nodeA; 594 this.nodeB = nodeB; 595 this.scale = scale || 1.; 596 this.notClosedBegin = notClosedBegin || 0; 597 this.notClosedEnd = notClosedEnd || 0; 598 this.notClosedBase = notClosedBase || 0; 599 600 this.geom() 601 this.consts(); 602 this.setPathList(); 603 this.makeObj(); 604 } 605 606 this.consts = function() {} 607 this.setPathList = function() {} 608 this.geom = function() { 609 this.x1 = this.nodeA.x; 610 this.z1 = this.nodeA.z; 611 this.x2 = this.nodeB.x; 612 this.z2 = this.nodeB.z; 613 this.dx = this.x2-this.x1; 614 this.dz = this.z2-this.z1; 615 this.len = Math.sqrt(this.dx*this.dx+this.dz*this.dz); 616 this.segLen = this.len/(this.num) || 1 617 this.cos = this.dx/this.len; 618 this.sin = this.dz/this.len; 619 } 620 this.makeObj = function() { this.obj = this.raphael.path(this.pathList); } 621 this.attrObjPath = function() { this.obj.attr({"path":this.pathList}); } 622 this.up= function() { this.geom(); this.consts(); this.setPathList(); this.attrObjPath(); } 623 this.notClosedPartsHandle = function(val1) { 624 if (this.notClosedEnd) { this.pathList.push(["M",this.x2,this.z2]); } 625 else { this.pathList.push(["L",this.x2,this.z2]); } 626 if (this.notClosedBase) { this.pathList.push(["M",this.x1,this.z1]); } 627 else { this.pathList.push(["L",this.x1,this.z1]); } 628 if (this.notClosedBegin) {} else { this.pathList.push(["L",this.x1-this.scale*this.sin*val1,this.z1+this.scale*this.cos*val1]); } 629 } 630 this.setXZ = function() { 631 this.x1 = x1; 632 this.z1 = z1; 633 this.x2 = x2; 634 this.z2 = z2; 635 this.up(); 636 } 637 } 638 639 640 /************************************************************ 641 * 642 * Linear curve (e.g. shear force line) 643 * input: 644 * raphael ... raphael instance 645 * nodeA ... 1st node 646 * nodeB ... 2nd node 647 * val1 ... value in 1st point (default 0.) 648 * val2 ... value in 2nd point (default 0.) 649 * sclale ... scale factor (default 1.) 650 * notClosedBegin ... the line conecting 1st node with 1st nodal value (default 0) 651 * notClosedEnd ... the line conecting 2nd node with 2nd nodal value (default 0) 652 * notClosedBase ... the line conecting 1st and 2nd node (default 0) 653 * 654 ************************************************************/ 655 LinearCurve = function(raphael,nodeA,nodeB,val1,val2,scale,notClosedBegin,notClosedEnd,notClosedBase) { 656 this.inheritFrom = CurveObj; this.inheritFrom(); 657 this.val1 = val1 || 0; 658 this.val2 = val2 || 0; 659 this.notClosedBegin = notClosedBegin || 0; 660 this.notClosedEnd = notClosedEnd || 0; 661 this.notClosedBase = notClosedBase || 0; 662 663 this.setPathList = function() { 664 this.pathList = [["M",this.x1-this.scale*this.sin*this.val1,this.z1+this.scale*this.cos*this.val1]]; 665 this.pathList.push(["L",this.x2-this.scale*this.sin*this.val2,this.z2+this.scale*this.cos*this.val2]); 666 this.notClosedPartsHandle(this.val1); 667 } 668 this.setVals = function(val1,val2) { 669 this.val1 = val1; 670 this.val2 = val2; 671 this.up(); 672 } 673 this.init(raphael,nodeA,nodeB,scale||1,notClosedBegin||0,notClosedEnd||0,notClosedBase||0); 674 } 675 676 /************************************************************ 677 * 678 * Parabolic curve (e.g. bending moment line) 679 * input: 680 * raphael ... raphael instance 681 * nodeA ... 1st node 682 * nodeB ... 2nd node 683 * val1 ... value in 1st point (default 0.) 684 * valMid ... value in the middle of 1st and 2nd node (default 0.) 685 * val2 ... value in 2nd point (default 0.) 686 * sclale ... scale factor (default 1.) 687 * notClosedBegin ... the line conecting 1st node with 1st nodal value (default 0) 688 * notClosedEnd ... the line conecting 2nd node with 2nd nodal value (default 0) 689 * notClosedBase ... the line conecting 1st and 2nd node (default 0) 690 * num ... number of interpolating points (default 5) 691 * 692 ************************************************************/ 693 ParabolicCurve = function(raphael,nodeA,nodeB,val1,valMid,val2,scale,notClosedBegin,notClosedEnd,notClosedBase,num) { 694 this.inheritFrom = CurveObj; this.inheritFrom(); 695 this.val1 = val1 || 0; 696 this.valMid = valMid || 0.; 697 this.val2 = val2 || 0; 698 this.notClosedBegin = notClosedBegin || 0; 699 this.notClosedEnd = notClosedEnd || 0; 700 this.notClosedBase = notClosedBase || 0; 701 this.num = num || 5; 702 703 this.consts = function() { 704 this.c0 = this.val1; 705 this.c1 = (-3*this.val1 - this.val2 + 4*this.valMid)/this.len; 706 this.c2 = (2*this.val1 + 2*this.val2 - 4*this.valMid)/this.len/this.len; 707 } 708 this.v = function(s) { return this.c0 + this.c1*s + this.c2*s*s; } 709 this.dv = function(s) { return this.c1 + 2*this.c2*s; } 710 this.setPathList = function() { 711 this.pathList = [["M",this.x1-this.scale*this.sin*this.v(0),this.z1+this.scale*this.cos*this.v(0)]]; 712 var t = .3; 713 for (var i=0; i<this.num; i++) { 714 var v1 = this.v(i*this.segLen); 715 var v2 = this.v((i+1)*this.segLen); 716 var dv1 = this.dv(i*this.segLen); 717 var dv2 = this.dv((i+1)*this.segLen); 718 var vec1 = vecTrans((i+t)*this.segLen,this.scale*(v1+dv1*t*this.segLen),this.sin,this.cos); 719 var vec2 = vecTrans((i+1-t)*this.segLen,this.scale*(v2-dv2*t*this.segLen),this.sin,this.cos); 720 var vec3 = vecTrans((i+1)*this.segLen,this.scale*v2,this.sin,this.cos); 721 var ll = ["C",this.x1+vec1[0],this.z1+vec1[1],this.x1+vec2[0],this.z1+vec2[1],this.x1+vec3[0],this.z1+vec3[1]]; 722 this.pathList.push(ll); 723 } 724 this.notClosedPartsHandle(this.v(0)); 725 } 726 this.setVals = function(val1,val2,valMid) { 727 this.val1 = val1; 728 this.val2 = val2; 729 this.valMid = valMid; 730 this.up(); 731 } 732 this.init(raphael,nodeA,nodeB,scale||1,notClosedBegin||0,notClosedEnd||0,notClosedBase||0); 733 } 734 735 /************************************************************ 736 * 737 * Generic class for 3rd and 4th order curves (used for deflection) 738 * input: 739 * raphael ... raphael instance 740 * nodeA ... 1st node 741 * nodeB ... 2nd node 742 * u1 ... local x deflection in the 1st nod (default 0.) 743 * w1 ... local z deflection in the 1st nod (default 0.) 744 * phi1 ... rotation of the 1st point (default 0.) 745 * u2 ... local x deflection in the 2nd nod (default 0.) 746 * w2 ... local z deflection in the 2nd nod (default 0.) 747 * phi2 ... rotation of the 2nd point (default 0.) 748 * wMid ... local z deflection from continuous load 749 * in the middle of the beam (default 0.) 750 * scale ... scale parameter for the deflection line (default 1.) 751 * notClosedBegin ... the line conecting 1st node with 1st nodal value (default 0) 752 * notClosedEnd ... the line conecting 2nd node with 2nd nodal value (default 0) 753 * notClosedBase ... the line conecting 1st and 2nd node (default 0) 754 * num ... number of interpolation points (default 5) 755 * 756 ************************************************************/ 757 DeflCurve = function(raphael,nodeA,nodeB,u1,w1,phi1,u2,w2,phi2,wMid,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num) { 758 this.inheritFrom = CurveObj; this.inheritFrom(); 759 760 this.consts = function() { 761 this.c0 = this.w1; 762 this.c1 = -this.phi1*this.lenScale; 763 this.c2 = (2*this.phi1+this.phi2)*this.lenScale/this.len + 3/this.len/this.len*(this.w2-this.w1) + 16/this.len/this.len*this.wMid; 764 this.c3 = 2/this.len/this.len/this.len*(this.w1-this.w2) - 1/this.len/this.len*this.lenScale*(this.phi1+this.phi2) - 32/this.len/this.len/this.len*this.wMid; 765 this.c4 = 16/this.len/this.len/this.len/this.len*this.wMid; 766 } 767 this.w = function(s) { return this.c0 + this.c1*s + this.c2*s*s + this.c3*s*s*s + this.c4*s*s*s*s; } 768 this.dw = function(s) { return this.c1 + 2*this.c2*s + 3*this.c3*s*s + 4*this.c4*s*s*s; } 769 this.setPathList = function() { 770 this.pathList = [["M",this.x1+this.scale*(this.u1*this.cos-this.sin*this.w(0)),this.z1+this.scale*(this.u1*this.sin+this.cos*this.w(0))]]; 771 var t = .3; 772 for (var i=0; i<this.num; i++) { 773 var w1 = this.w(i*this.segLen); 774 var w2 = this.w((i+1)*this.segLen); 775 var dw1 = this.dw(i*this.segLen); 776 var dw2 = this.dw((i+1)*this.segLen); 777 var vec1 = vecTrans(this.scale*this.u1+(i+t)*(this.segLen+this.scale*(this.u2-this.u1)/this.num),this.scale*(w1+dw1*t*this.segLen),this.sin,this.cos); 778 var vec2 = vecTrans(this.scale*this.u1+(i+1-t)*(this.segLen+this.scale*(this.u2-this.u1)/this.num),this.scale*(w2-dw2*t*this.segLen),this.sin,this.cos); 779 var vec3 = vecTrans(this.scale*this.u1+(i+1)*(this.segLen+this.scale*(this.u2-this.u1)/this.num),this.scale*w2,this.sin,this.cos); 780 var ll = ["C",this.x1+vec1[0],this.z1+vec1[1],this.x1+vec2[0],this.z1+vec2[1],this.x1+vec3[0],this.z1+vec3[1]]; 781 this.pathList.push(ll); 782 } 783 this.notClosedPartsHandle(this.w(0)); 784 } 785 this.setDsplFull = function(u1,w1,phi1,u2,w2,phi2,wMid) { 786 this.u1 = u1; 787 this.w1 = w1; 788 this.phi1 = phi1; 789 this.u2 = u2; 790 this.w2 = w2; 791 this.phi2 = phi2; 792 this.wMid = wMid || 0.; 793 this.up(); 794 } 795 this.init = function(raphael,nodeA,nodeB,u1,w1,phi1,u2,w2,phi2,wMid,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num) { 796 this.raphael = raphael; 797 this.nodeA = nodeA; 798 this.nodeB = nodeB; 799 this.u1 = u1 || 0.; 800 this.w1 = w1 || 0.; 801 this.phi1 = phi1 || 0.; 802 this.u2 = u2 || 0.; 803 this.w2 = w2 || 0.; 804 this.phi2 = phi2 || 0.; 805 this.wMid = wMid || 0.; 806 this.realLen = realLen || 1.; 807 this.scale = scale || 1.; 808 this.notClosedBegin = notClosedBegin || 0; 809 this.notClosedEnd = notClosedEnd || 0; 810 this.notClosedBase = notClosedBase || 0; 811 this.num = num || 5; 812 813 this.geom() 814 this.lenScale = this.realLen/this.len; 815 this.consts(); 816 this.setPathList(); 817 this.makeObj(); 818 } 819 } 820 821 /************************************************************ 822 * specific higher order curves 823 ************************************************************/ 824 // cubic deflection (all 6 deflections can be set) 825 DeflCubic = function(raphael,nodeA,nodeB,u1,w1,phi1,u2,w2,phi2,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num) { 826 this.inheritFrom = DeflCurve; this.inheritFrom(); 827 this.init(raphael,nodeA,nodeB,u1,w1,phi1,u2,w2,phi2,0,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num); 828 this.setDspl = function(u1,w1,phi1,u2,w2,phi2) { this.setDsplFull(u1,w1,phi1,u2,w2,phi2,0); } 829 } 830 // 4th order deflection (all 6 deflections can be set) 831 Defl4thOrder = function(raphael,nodeA,nodeB,u1,w1,phi1,u2,w2,phi2,wMid,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num) { 832 this.inheritFrom = DeflCurve; this.inheritFrom(); 833 this.init(raphael,nodeA,nodeB,u1,w1,phi1,u2,w2,phi2,wMid,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num); 834 this.setDspl = function(u1,w1,phi1,u2,w2,phi2,wMid) { this.setDsplFull(u1,w1,phi1,u2,w2,phi2,wMid); } 835 } 836 837 // cubic deflection (only w1,phi1,w2,phi2 can be set) 838 DeflCubicNoU = function(raphael,nodeA,nodeB,w1,phi1,w2,phi2,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num) { 839 this.inheritFrom = DeflCurve; this.inheritFrom(); 840 this.init(raphael,nodeA,nodeB,0,w1,phi1,0,w2,phi2,0,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num); 841 this.setDspl = function(w1,phi1,w2,phi2) { this.setDsplFull(0,w1,phi1,0,w2,phi2,0); } 842 } 843 // 4th order deflection (only w1,phi1,w2,phi2 can be set) 844 Defl4thOrderNoU = function(raphael,nodeA,nodeB,w1,phi1,w2,phi2,wMid,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num) { 845 this.inheritFrom = DeflCurve; this.inheritFrom(); 846 this.init(raphael,nodeA,nodeB,0,w1,phi1,0,w2,phi2,wMid,realLen,scale,notClosedBegin,notClosedEnd,notClosedBase,num); 847 this.setDspl = function(w1,phi1,w2,phi2,wMid) { this.setDsplFull(0,w1,phi1,0,w2,phi2,wMid); } 848 } 849