1 /* 2 Copyright 2008,2009 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Alfred Wassermann, 8 Peter Wilfahrt 9 10 This file is part of JSXGraph. 11 12 JSXGraph is free software: you can redistribute it and/or modify 13 it under the terms of the GNU Lesser General Public License as published by 14 the Free Software Foundation, either version 3 of the License, or 15 (at your option) any later version. 16 17 JSXGraph is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public License 23 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>. 24 25 */ 26 27 /** 28 * @fileoverview The object Intersection is defined in this file. Intersection 29 * manages all properties and actiones required to cut circles and lines with 30 * each other and draws the intersection points. 31 * @author graphjs 32 * @version 0.1 33 */ 34 35 /** 36 * Constructs a new Intersection object. 37 * @class This is the Intersection class. 38 * It manages all properties and actiones required to cut circles and lines with 39 * each other and draws the intersection points. 40 * @constructor 41 * @param {String,Board} board The board the new point is drawn on. 42 * @param {Array} coordinates An array with the affine user coordinates of the point. 43 * @param {String} id Unique identifier for the point. If null or an empty string is given, 44 * an unique id will be generated by Board 45 * @see JXG.Board#addPoint 46 * @param {String} name Not necessarily unique name for the point. If null or an 47 * empty string is given, an unique name will be generated 48 * @see JXG.Board#generateName 49 * @param {bool} show False if the point is invisible, True otherwise 50 */ 51 JXG.Intersection = function(Board, Id, Intersect1, Intersect2, InterId1, InterId2, InterName1, InterName2) { 52 this.constructor(); 53 /** 54 * Reference to board where the intersected elements are drawn. 55 * @type JXG.Board 56 * @see JXG.Board 57 */ 58 this.board = Board; 59 60 /** 61 * Unique identifier for the element. Equivalent to id-attribute of renderer element. 62 * @type String 63 */ 64 this.id = Id; 65 this.name = this.id; 66 67 /** 68 * True when this object is visible, false otherwise. 69 * @type bool 70 */ 71 this.visProp = {}; 72 this.visProp['visible'] = true; 73 this.show = true; // noch noetig? BV 74 75 /** 76 * True when the intersection points have real coordinates, false otherwise. 77 * @type bool 78 */ 79 this.real = true; 80 81 /** 82 * Stores all Intersection Objects which in this moment are not real and 83 * hide this element. 84 */ 85 this.notExistingParents = {}; 86 87 /** 88 * Geometry element that is intersected with intersect2. 89 * @type JXG.GeometryElement 90 * @see #intersect2 91 */ 92 this.intersect1 = JXG.getReference(this.board, Intersect1); 93 94 /** 95 * Geometry element that is intersected with intersect1. 96 * @type JXG.GeometryElement 97 * @see #intersect1 98 */ 99 this.intersect2 = JXG.getReference(this.board, Intersect2); 100 101 /** 102 * Type of this object. For internal use only. 103 * @private 104 */ 105 this.type = JXG.OBJECT_TYPE_INTERSECTION; 106 107 /* 108 * Only intersect existing geometry elements. 109 */ 110 if( ((this.intersect1 == '') || (!JXG.exists(this.intersect1))) && ((this.intersect2 == '') || (!JXG.exists(this.intersect2)))) { 111 return; 112 } 113 114 /* 115 * Do not intersect elements which aren't of type line, arrow, circle or arc. 116 */ 117 if( ((this.intersect1.type == this.intersect2.type) && (this.intersect1.type == JXG.OBJECT_TYPE_LINE || this.intersect1.type == JXG.OBJECT_TYPE_ARROW)) 118 || ((this.intersect1.type == JXG.OBJECT_TYPE_LINE) && (this.intersect2.type == JXG.OBJECT_TYPE_ARROW)) 119 || ((this.intersect2.type == JXG.OBJECT_TYPE_LINE) && (this.intersect1.type == JXG.OBJECT_TYPE_ARROW)) ) { 120 /* Intersect two elements of type line or arrow */ 121 122 var coords = JXG.Math.Geometry.intersectLineLine(this.intersect1, this.intersect2, this.board).usrCoords.slice(1); 123 124 /* Create intersection point */ 125 this.p = new JXG.Point(this.board, coords, InterId1, InterName1, true); 126 /* A point constructed by an intersection can't be moved, so it is fixed */ 127 this.p.fixed = true; 128 this.addChild(this.p); 129 this.real = true; 130 131 /* 132 * Because the update function depends on the types of the intersected elements 133 * the update method has to be defined dynamically in dependence of the intersected 134 * elements. 135 */ 136 this.update = function () { 137 /* Calculate the coordinates of the intersection point in dependance of the intersected elements */ 138 if (this.needsUpdate) { 139 this.p.coords = JXG.Math.Geometry.intersectLineLine(this.intersect1, this.intersect2, this.board); 140 /* Update the point */ 141 //this.p.update(); 142 this.needsUpdate = false; 143 } 144 }; 145 146 /* 147 * Hides the element, generated dynamically. 148 */ 149 this.hideElement = function() { 150 this.visProp['visible'] = false; 151 this.p.hideElement(); 152 }; 153 154 /* 155 * Shows the element, generated dynamically. 156 */ 157 this.showElement = function() { 158 this.visProp['visible'] = true; 159 this.p.showElement(); 160 }; 161 162 /* 163 * Hides the element and his children. This is called from parents which became invisible or unreal 164 * and so this element isn't real anymore. The not existing parent is stored in the notExistingParents 165 * array. 166 */ 167 this.hideChild = function(id) { 168 this.notExistingParents[id] = this.board.objects[id]; 169 170 for(var el in this.descendants) { 171 if(this.descendants[el].visProp['visible'] && this.descendants[el].type != JXG.OBJECT_TYPE_INTERSECTION) { 172 if(this.descendants[el].type != JXG.OBJECT_TYPE_TEXT) { 173 this.descendants[el].hideElement(); 174 this.descendants[el].visProp['visible'] = true; 175 } 176 else { 177 if(!this.descendants[el].isLabel) { 178 this.descendants[el].hideElement(); 179 this.descendants[el].visProp['visible'] = true; 180 } 181 } 182 } 183 this.descendants[el].notExistingParents[id] = this.board.objects[id]; 184 } 185 }; 186 187 /* 188 * Shows the element and his children. This is called from parents which became visible or real 189 * and so this element is now real. The formerly not existing parent is deleted from the 190 * notExistingParents array. 191 */ 192 this.showChild = function(id) { 193 for(var el in this.board.objects) { 194 delete(this.board.objects[el].notExistingParents[id]); 195 if(this.board.objects[el].visProp['visible'] && JXG.keys(this.board.objects[el].notExistingParents).length == 0) { 196 if(this.board.objects[el].type != JXG.OBJECT_TYPE_INTERSECTION) { 197 this.board.objects[el].showElement(); 198 } 199 } 200 } 201 }; 202 } 203 else if( ((Intersect1.type == Intersect2.type) && (Intersect1.type == JXG.OBJECT_TYPE_CIRCLE || Intersect1.type == JXG.OBJECT_TYPE_ARC)) || 204 (Intersect1.type == JXG.OBJECT_TYPE_CIRCLE && Intersect2.type == JXG.OBJECT_TYPE_ARC) || 205 (Intersect2.type == JXG.OBJECT_TYPE_CIRCLE && Intersect1.type == JXG.OBJECT_TYPE_ARC) ) { // Circle <-> Circle, Arc <-> Arc, Arc <-> Circle, 206 this.p1 = new JXG.Point(this.board, [0, 0], InterId1, InterName1, false); 207 this.p1.fixed = true; 208 this.p1.label.content.visProp['visible'] = true; 209 this.p2 = new JXG.Point(this.board, [0, 0], InterId2, InterName2, false); 210 this.p2.fixed = true; 211 this.p2.label.content.visProp['visible'] = true; 212 this.addChild(this.p1); 213 this.addChild(this.p2); 214 215 var coordinates = JXG.Math.Geometry.intersectCircleCircle(this.intersect1, this.intersect2, this.board); 216 if(coordinates[0] == 1) { 217 this.p1.coords = coordinates[1]; 218 this.p1.showElement(); 219 this.p1.updateRenderer(); 220 221 this.p2.coords = coordinates[2]; 222 this.p2.showElement(); 223 this.p2.updateRenderer(); 224 225 this.real = true; 226 } 227 else { 228 this.real = false; 229 } 230 231 this.update = function () { 232 if (!this.needsUpdate) { return; } 233 var coordinates = JXG.Math.Geometry.intersectCircleCircle(this.intersect1, this.intersect2, this.board); 234 var p1show = this.p1.visProp['visible']; 235 var p2show = this.p2.visProp['visible']; 236 if(coordinates[0] == 0) { 237 if(this.real) { 238 this.hideChild(this.id); 239 this.p1.visProp['visible'] = p1show; 240 this.p2.visProp['visible'] = p2show; 241 this.real = false; 242 } 243 } else { 244 this.p1.coords = coordinates[1]; 245 this.p2.coords = coordinates[2]; 246 if(!this.real) { 247 this.showChild(this.id); 248 this.real = true; 249 } 250 } 251 this.needsUpdate = false; 252 }; 253 254 this.hideElement = function() { 255 this.visProp['visible'] = false; 256 this.p1.hideElement(); 257 this.p2.hideElement(); 258 }; 259 260 this.showElement = function() { 261 this.visProp['visible'] = true; 262 this.p1.showElement(); 263 this.p2.showElement(); 264 }; 265 266 this.hideChild = function(id) { 267 this.notExistingParents[id] = this.board.objects[id]; 268 269 for(var el in this.descendants) { 270 if(this.descendants[el].visProp['visible'] && this.descendants[el].type != JXG.OBJECT_TYPE_INTERSECTION) { 271 if(this.descendants[el].type != JXG.OBJECT_TYPE_TEXT) { 272 this.descendants[el].hideElement(); 273 this.descendants[el].visProp['visible'] = true; 274 } 275 else { 276 if(!this.descendants[el].isLabel) { 277 this.descendants[el].hideElement(); 278 this.descendants[el].visProp['visible'] = true; 279 } 280 } 281 } 282 this.descendants[el].notExistingParents[id] = this.board.objects[id]; 283 } 284 }; 285 286 this.showChild = function(id) { 287 var el; 288 for(el in this.board.objects) { 289 delete(this.board.objects[el].notExistingParents[id]); 290 if(this.board.objects[el].visProp['visible'] && JXG.keys(this.board.objects[el].notExistingParents).length == 0) { 291 if(this.board.objects[el].type != JXG.OBJECT_TYPE_INTERSECTION) { 292 this.board.objects[el].showElement(); 293 } 294 } 295 } 296 }; 297 } 298 else { // Circle <-> Line, Arc <-> Line, Circle <-> Arrow, Arc <-> Arrow 299 this.p1 = new JXG.Point(this.board, [0, 0], InterId1, InterName1, false); 300 this.p1.fixed = true; 301 this.p1.label.content.visProp['visible'] = true; 302 this.p2 = new JXG.Point(this.board, [0, 0], InterId2, InterName2, false); 303 this.p2.fixed = true; 304 this.p2.label.content.visProp['visible'] = true; 305 this.addChild(this.p1); 306 this.addChild(this.p2); 307 308 if(this.intersect1.type == JXG.OBJECT_TYPE_LINE || this.intersect1.type == JXG.OBJECT_TYPE_ARROW) { 309 var swap = this.intersect1; 310 this.intersect1 = this.intersect2; 311 this.intersect2 = swap; 312 } 313 314 var coordinates = JXG.Math.Geometry.intersectCircleLine(this.intersect1, this.intersect2, this.board); 315 if(coordinates[0] == 1) { // not really implemented 316 this.p1.coords = coordinates[1]; 317 this.p1.showElement(); 318 this.p1.update(); 319 } 320 else if(coordinates[0] == 2) { 321 this.p1.coords = coordinates[1]; 322 this.p1.showElement(); 323 324 this.p2.coords = coordinates[2]; 325 this.p2.showElement(); 326 327 //this.p1.update(); 328 this.p1.updateRenderer(); 329 //this.p2.update(); 330 this.p2.updateRenderer(); 331 332 this.real = true; 333 } 334 else { 335 this.real = false; 336 } 337 338 this.update = function () { 339 if (!this.needsUpdate) { return; } 340 var coordinates = JXG.Math.Geometry.intersectCircleLine(this.intersect1, this.intersect2, this.board); 341 var show1 = this.p1.visProp['visible']; 342 var show2 = this.p2.visProp['visible']; 343 344 if(coordinates[0] == 0) { 345 if(this.real) { 346 this.hideChild(this.id); 347 this.p1.visProp['visible'] = show1; 348 this.p2.visProp['visible'] = show2; 349 this.real = false; 350 } 351 } else if(coordinates[0] == 2) { 352 this.p1.coords = coordinates[1]; 353 this.p2.coords = coordinates[2]; 354 if(!this.real) { 355 this.showChild(this.id); 356 this.real = true; 357 } 358 } 359 this.needsUpdate = false; 360 }; 361 362 this.hideElement = function() { 363 this.visProp['visible'] = false; 364 this.p1.hideElement(); 365 this.p2.hideElement(); 366 }; 367 368 this.showElement = function() { 369 this.visProp['visible'] = true; 370 this.p1.showElement(); 371 this.p2.showElement(); 372 }; 373 374 this.hideChild = function(id) { 375 this.notExistingParents[id] = this.board.objects[id]; 376 377 for(var el in this.descendants) { 378 if(this.descendants[el].visProp['visible'] && this.descendants[el].type != JXG.OBJECT_TYPE_INTERSECTION) { 379 if(this.descendants[el].type != JXG.OBJECT_TYPE_TEXT) { 380 this.descendants[el].hideElement(); 381 this.descendants[el].visProp['visible'] = true; 382 } 383 else { 384 if(!this.descendants[el].isLabel) { 385 this.descendants[el].hideElement(); 386 this.descendants[el].visProp['visible'] = true; 387 } 388 } 389 } 390 this.descendants[el].notExistingParents[id] = this.board.objects[id]; 391 } 392 }; 393 394 this.showChild = function(id) { 395 var el; 396 for(el in this.board.objects) { 397 delete(this.board.objects[el].notExistingParents[id]); 398 if(this.board.objects[el].visProp['visible'] && JXG.keys(this.board.objects[el].notExistingParents).length == 0) { 399 if(this.board.objects[el].type != JXG.OBJECT_TYPE_INTERSECTION) { 400 this.board.objects[el].showElement(); 401 } 402 } 403 } 404 }; 405 } 406 407 this.id = this.board.setId(this, 'I'); 408 409 this.intersect1.addChild(this); 410 this.intersect2.addChild(this); 411 }; 412 JXG.Intersection.prototype = new JXG.GeometryElement(); 413 414 /** 415 * Calls the renderer to update the drawing. This method is defined dynamically 416 * as it highly depends on the types of the intersected elements. 417 */ 418 JXG.Intersection.prototype.update = function() { 419 }; 420 421 /** 422 * Checks whether (x,y) is near the point. 423 * @param {int} x Coordinate in x direction, screen coordinates. 424 * @param {int} y Coordinate in y direction, screen coordinates. 425 * @return {bool} Always returns false 426 */ 427 JXG.Intersection.prototype.hasPoint = function(x, y) { 428 }; 429 430 /** 431 * Hides the element and his children. This is called from parents which became invisible or unreal 432 * and so this element isn't real anymore. The not existing parent is stored in the notExistingParents 433 * array. 434 * @param {String} id The identifier of the element causing this element to be hidden. 435 */ 436 JXG.Intersection.prototype.hideChild = function(id) { 437 }; 438 439 /** 440 * Shows the element and his children. This is called from parents which became visible or real 441 * and so this element is now real. The formerly not existing parent is deleted from the 442 * notExistingParents array. 443 * @param {String} id The identifier of the element causing this element to be shown. 444 */ 445 JXG.Intersection.prototype.showChild = function(id) { 446 }; 447 448 /** 449 * Remove intersection points from drawing. 450 */ 451 JXG.Intersection.prototype.remove = function() { 452 if(JXG.exists(this.p)) 453 this.board.removeObject(this.p); 454 if(JXG.exists(this.p1)) 455 this.board.removeObject(this.p1); 456 if(JXG.exists(this.p2)) 457 this.board.removeObject(this.p2); 458 }; 459 460 /** 461 * Dummy method 462 */ 463 JXG.Intersection.prototype.updateRenderer = function() { 464 }; 465