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 geometry object Circle is defined in this file. Circle stores all 29 * style and functional properties that are required to draw and move a circle on 30 * a board. 31 * @author graphjs 32 * @version 0.1 33 */ 34 35 /** 36 * A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius. 37 * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function, 38 * line, or circle). 39 * @class Creates a new circle object. Do not use this constructor to create a circle. Use {@link JXG.Board#create} with 40 * type {@link Circle} instead. 41 * @constructor 42 * @augments JXG.GeometryElement 43 * @param {String,JXG.Board} board The board the new circle is drawn on. 44 * @param {String} method Can be 45 * <ul><li> <b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li> 46 * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius in user units</li> 47 * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line</li> 48 * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle</li></ul> 49 * The parameters p1, p2 and radius must be set according to this method parameter. 50 * @param {JXG.Point} p1 center of the circle. 51 * @param {JXG.Point,JXG.Line,JXG.Circle} p2 Can be 52 *<ul><li>a point on the circle if method is 'twoPoints'</li> 53 <li>a line if the method is 'pointLine'</li> 54 <li>a circle if the method is 'pointCircle'</li></ul> 55 * @param {float} radius Only used when method is set to 'pointRadius'. Must be a given radius in user units. 56 * @param {String} id Unique identifier for this object. If null or an empty string is given, 57 * an unique id will be generated by Board 58 * @param {String} name Not necessarily unique name. If null or an 59 * empty string is given, an unique name will be generated. 60 * @see JXG.Board#generateName 61 */ 62 63 JXG.Circle = function (board, method, par1, par2, attributes) { 64 /* Call the constructor of GeometryElement */ 65 this.constructor(board, attributes, JXG.OBJECT_TYPE_CIRCLE, JXG.OBJECT_CLASS_CIRCLE); 66 67 68 //this.type = JXG.OBJECT_TYPE_CIRCLE; 69 //this.elementClass = JXG.OBJECT_CLASS_CIRCLE; 70 71 //this.init(board, attributes); 72 73 /** 74 * Stores the given method. 75 * Can be 76 * <ul><li><b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li> 77 * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius given in user units or as term.</li> 78 * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line.</li> 79 * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle.</li></ul> 80 * @type string 81 * @see #center 82 * @see #point2 83 * @see #radius 84 * @see #line 85 * @see #circle 86 */ 87 this.method = method; 88 89 // this is kept so existing code won't ne broken 90 this.midpoint = JXG.getReference(this.board, par1); 91 92 /** 93 * The circles center. Do not set this parameter directly as it will break JSXGraph's update system. 94 * @type JXG.Point 95 */ 96 this.center = JXG.getReference(this.board, par1); 97 98 /** Point on the circle only set if method equals 'twoPoints'. Do not set this parameter directly as it will break JSXGraph's update system. 99 * @type JXG.Point 100 * @see #method 101 */ 102 this.point2 = null; 103 104 /** Radius of the circle 105 * only set if method equals 'pointRadius' 106 * @type Number 107 * @default null 108 * @see #method 109 */ 110 this.radius = 0; 111 112 /** Line defining the radius of the circle given by the distance from the startpoint and the endpoint of the line 113 * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system. 114 * @type JXG.Line 115 * @default null 116 * @see #method 117 */ 118 this.line = null; 119 120 /** Circle defining the radius of the circle given by the radius of the other circle 121 * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system. 122 * @type JXG.Circle 123 * @default null 124 * @see #method 125 */ 126 this.circle = null; 127 128 if(method == 'twoPoints') { 129 this.point2 = JXG.getReference(board,par2); 130 // this.point2.addChild(this); // See below. Here, the id of this is not determined. 131 this.radius = this.Radius(); 132 } 133 else if(method == 'pointRadius') { 134 this.gxtterm = par2; 135 this.updateRadius = JXG.createFunction(par2, this.board, null, true); // Converts GEONExT syntax into JavaScript syntax 136 this.updateRadius(); // First evaluation of the graph 137 } 138 else if(method == 'pointLine') { 139 // dann ist p2 die Id eines Objekts vom Typ Line! 140 this.line = JXG.getReference(board, par2); 141 this.radius = this.line.point1.coords.distance(JXG.COORDS_BY_USER, this.line.point2.coords); 142 } 143 else if(method == 'pointCircle') { 144 // dann ist p2 die Id eines Objekts vom Typ Circle! 145 this.circle = JXG.getReference(board, par2); 146 this.radius = this.circle.Radius(); 147 } 148 149 // create Label 150 this.id = this.board.setId(this, 'C'); 151 this.board.renderer.drawEllipse(this); 152 this.board.finalizeAdding(this); 153 154 this.createGradient(); 155 this.elType = 'circle'; 156 this.createLabel(); 157 158 this.center.addChild(this); 159 160 if(method == 'pointRadius') { 161 this.notifyParents(par2); 162 } else if(method == 'pointLine') { 163 this.line.addChild(this); 164 } else if(method == 'pointCircle') { 165 this.circle.addChild(this); 166 } else if(method == 'twoPoints') { 167 this.point2.addChild(this); 168 } 169 170 this.methodMap = JXG.deepCopy(this.methodMap, { 171 setRadius: 'setRadius', 172 getRadius: 'getRadius', 173 radius: 'Radius' 174 }); 175 }; 176 JXG.Circle.prototype = new JXG.GeometryElement; 177 178 JXG.extend(JXG.Circle.prototype, /** @lends JXG.Circle.prototype */ { 179 180 /** 181 * Checks whether (x,y) is near the circle. 182 * @param {Number} x Coordinate in x direction, screen coordinates. 183 * @param {Number} y Coordinate in y direction, screen coordinates. 184 * @returns {Boolean} True if (x,y) is near the circle, False otherwise. 185 * @private 186 */ 187 hasPoint: function (x, y) { 188 var prec = this.board.options.precision.hasPoint/(this.board.unitX), 189 mp = this.center.coords.usrCoords, 190 p = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board), 191 r = this.Radius(); 192 193 var dist = Math.sqrt((mp[1]-p.usrCoords[1])*(mp[1]-p.usrCoords[1]) + (mp[2]-p.usrCoords[2])*(mp[2]-p.usrCoords[2])); 194 if (this.visProp.hasinnerpoints) { 195 return (dist < r + prec); 196 } else { 197 return (Math.abs(dist-r) < prec); 198 } 199 //return (dist <= r + prec); 200 }, 201 202 /** 203 * Used to generate a polynomial for a point p that lies on this circle. 204 * @param p The point for that the polynomial is generated. 205 * @returns {Array} An array containing the generated polynomial. 206 * @private 207 */ 208 generatePolynomial: function (p) { 209 /* 210 * We have four methods to construct a circle: 211 * (a) Two points 212 * (b) center and radius 213 * (c) center and radius given by length of a segment 214 * (d) center and radius given by another circle 215 * 216 * In case (b) we have to distinguish two cases: 217 * (i) radius is given as a number 218 * (ii) radius is given as a function 219 * In the latter case there's no guarantee the radius depends on other geometry elements 220 * in a polynomial way so this case has to be omitted. 221 * 222 * Another tricky case is case (d): 223 * The radius depends on another circle so we have to cycle through the ancestors of each circle 224 * until we reach one that's radius does not depend on another circles radius. 225 * 226 * 227 * All cases (a) to (d) vary only in calculation of the radius. So the basic formulae for 228 * a glider G (g1,g2) on a circle with center M (m1,m2) and radius r is just: 229 * 230 * (g1-m1)^2 + (g2-m2)^2 - r^2 = 0 231 * 232 * So the easiest case is (b) with a fixed radius given as a number. The other two cases (a) 233 * and (c) are quite the same: Euclidean distance between two points A (a1,a2) and B (b1,b2), 234 * squared: 235 * 236 * r^2 = (a1-b1)^2 + (a2-b2)^2 237 * 238 * For case (d) we have to cycle recursively through all defining circles and finally return the 239 * formulae for calculating r^2. For that we use JXG.Circle.symbolic.generateRadiusSquared(). 240 */ 241 242 var m1 = this.center.symbolic.x; 243 var m2 = this.center.symbolic.y; 244 var g1 = p.symbolic.x; 245 var g2 = p.symbolic.y; 246 247 var rsq = this.generateRadiusSquared(); 248 249 /* No radius can be calculated (Case b.ii) */ 250 if (rsq == '') 251 return []; 252 253 var poly = '((' + g1 + ')-(' + m1 + '))^2 + ((' + g2 + ')-(' + m2 + '))^2 - (' + rsq + ')'; 254 return [poly]; 255 }, 256 257 /** 258 * Generate symbolic radius calculation for loci determination with Groebner-Basis algorithm. 259 * @returns {String} String containing symbolic calculation of the circle's radius or an empty string 260 * if the radius can't be expressed in a polynomial equation. 261 * @private 262 */ 263 generateRadiusSquared: function () { 264 /* 265 * Four cases: 266 * 267 * (a) Two points 268 * (b) center and radius 269 * (c) center and radius given by length of a segment 270 * (d) center and radius given by another circle 271 */ 272 273 var rsq = '', 274 m1, m2, p1, p2, q1, q2; 275 276 if (this.method == "twoPoints") { 277 m1 = this.center.symbolic.x; 278 m2 = this.center.symbolic.y; 279 p1 = this.point2.symbolic.x; 280 p2 = this.point2.symbolic.y; 281 282 rsq = '((' + p1 + ')-(' + m1 + '))^2 + ((' + p2 + ')-(' + m2 + '))^2'; 283 } else if (this.method == "pointRadius") { 284 if (typeof(this.radius) == 'number') 285 rsq = '' + this.radius*this.radius; 286 } else if (this.method == "pointLine") { 287 p1 = this.line.point1.symbolic.x; 288 p2 = this.line.point1.symbolic.y; 289 290 q1 = this.line.point2.symbolic.x; 291 q2 = this.line.point2.symbolic.y; 292 293 rsq = '((' + p1 + ')-(' + q1 + '))^2 + ((' + p2 + ')-(' + q2 + '))^2'; 294 } else if (this.method == "pointCircle") { 295 rsq = this.circle.Radius(); 296 } 297 298 return rsq; 299 }, 300 301 /** 302 * Uses the boards renderer to update the circle. 303 */ 304 update: function () { 305 if (this.needsUpdate) { 306 if(this.visProp.trace) { 307 this.cloneToBackground(true); 308 } 309 310 if(this.method == 'pointLine') { 311 this.radius = this.line.point1.coords.distance(JXG.COORDS_BY_USER, this.line.point2.coords); 312 } 313 else if(this.method == 'pointCircle') { 314 this.radius = this.circle.Radius(); 315 } 316 else if(this.method == 'pointRadius') { 317 this.radius = this.updateRadius(); 318 } 319 //if (true||!this.board.geonextCompatibilityMode) { 320 this.updateStdform(); 321 this.updateQuadraticform(); 322 //} 323 } 324 return this; 325 }, 326 327 /** 328 * TODO description 329 * @private 330 */ 331 updateQuadraticform: function () { 332 var m = this.center, 333 mX = m.X(), mY = m.Y(), r = this.Radius(); 334 this.quadraticform = [[mX*mX+mY*mY-r*r,-mX,-mY], 335 [-mX,1,0], 336 [-mY,0,1] 337 ]; 338 }, 339 340 /** 341 * TODO description 342 * @private 343 */ 344 updateStdform: function () { 345 this.stdform[3] = 0.5; 346 this.stdform[4] = this.Radius(); 347 this.stdform[1] = -this.center.coords.usrCoords[1]; 348 this.stdform[2] = -this.center.coords.usrCoords[2]; 349 this.normalize(); 350 }, 351 352 /** 353 * Uses the boards renderer to update the circle. 354 * @private 355 */ 356 updateRenderer: function () { 357 if (this.needsUpdate && this.visProp.visible) { 358 var wasReal = this.isReal; 359 this.isReal = (!isNaN(this.center.coords.usrCoords[1] + this.center.coords.usrCoords[2] + this.Radius())) && this.center.isReal; 360 if (this.isReal) { 361 if (wasReal!=this.isReal) { 362 this.board.renderer.show(this); 363 if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.show(this.label.content); 364 } 365 this.board.renderer.updateEllipse(this); 366 } else { 367 if (wasReal!=this.isReal) { 368 this.board.renderer.hide(this); 369 if(this.hasLabel && this.label.content.visProp.visible) this.board.renderer.hide(this.label.content); 370 } 371 } 372 this.needsUpdate = false; 373 } 374 375 /* Update the label if visible. */ 376 if(this.hasLabel && this.label.content.visProp.visible && this.isReal) { 377 //this.label.setCoordinates(this.coords); 378 this.label.content.update(); 379 //this.board.renderer.updateLabel(this.label); 380 this.board.renderer.updateText(this.label.content); 381 } 382 }, 383 384 /** 385 * TODO description 386 * @param contentStr TODO type&description 387 * @private 388 */ 389 notifyParents: function (contentStr) { 390 if (typeof contentStr == 'string') 391 JXG.GeonextParser.findDependencies(this,contentStr+'',this.board); 392 }, 393 394 /** 395 * Set a new radius, then update the board. 396 * @param {String|Number|function} r A string, function or number describing the new radius. 397 * @returns {JXG.Circle} Reference to this circle 398 */ 399 setRadius: function (r) { 400 this.updateRadius = JXG.createFunction(r, this.board, null, true); 401 this.board.update(); 402 403 return this; 404 }, 405 406 /** 407 * Calculates the radius of the circle. 408 * @param {String|Number|function} [value] Set new radius 409 * @returns {Number} The radius of the circle 410 */ 411 Radius: function (value) { 412 if (JXG.exists(value)) { 413 this.setRadius(value); 414 return this.Radius(); 415 } 416 417 if(this.method == 'twoPoints') { 418 if (JXG.Math.Geometry.distance(this.point2.coords.usrCoords,[0,0,0])==0.0 || 419 JXG.Math.Geometry.distance(this.center.coords.usrCoords,[0,0,0])==0.0) { 420 return NaN; 421 } else { 422 return this.center.Dist(this.point2); 423 } 424 } 425 else if(this.method == 'pointLine' || this.method == 'pointCircle') { 426 return this.radius; 427 } 428 else if(this.method == 'pointRadius') { 429 return this.updateRadius(); 430 } 431 }, 432 433 /** 434 * @deprecated 435 */ 436 getRadius: function () { 437 return this.Radius(); 438 }, 439 440 // documented in geometry element 441 getTextAnchor: function () { 442 return this.center.coords; 443 }, 444 445 // documented in geometry element 446 getLabelAnchor: function () { 447 var r = this.Radius(), 448 c = this.center.coords.usrCoords, 449 x, y; 450 451 switch (this.visProp.label.position) { 452 case 'lft': 453 x = c[1] - r; y = c[2]; break; 454 case 'llft': 455 x = c[1] - Math.sqrt(0.5)*r; y = c[2] - Math.sqrt(0.5)*r; break; 456 case 'rt': 457 x = c[1] + r; y = c[2]; break; 458 case 'lrt': 459 x = c[1] + Math.sqrt(0.5)*r; y = c[2] - Math.sqrt(0.5)*r; break; 460 case 'urt': 461 x = c[1] + Math.sqrt(0.5)*r; y = c[2] + Math.sqrt(0.5)*r; break; 462 case 'top': 463 x = c[1]; y = c[2] + r; break; 464 case 'bot': 465 x = c[1]; y = c[2] - r; break; 466 case 'ulft': 467 default: 468 x = c[1] - Math.sqrt(0.5)*r; y = c[2] + Math.sqrt(0.5)*r; break; 469 } 470 return new JXG.Coords(JXG.COORDS_BY_USER, [x, y], this.board); 471 }, 472 473 474 // documented in geometry element 475 cloneToBackground: function () { 476 var copy = {}, r, er; 477 copy.id = this.id + 'T' + this.numTraces; 478 copy.elementClass = JXG.OBJECT_CLASS_CIRCLE; 479 this.numTraces++; 480 copy.center = {}; 481 copy.center.coords = this.center.coords; 482 r = this.Radius(); 483 copy.Radius = function () { return r; }; 484 copy.getRadius = function () { return r; }; // deprecated 485 486 copy.board = this.board; 487 488 copy.visProp = JXG.deepCopy(this.visProp, this.visProp.traceattributes, true); 489 copy.visProp.layer = this.board.options.layer.trace; 490 JXG.clearVisPropOld(copy); 491 492 er = this.board.renderer.enhancedRendering; 493 this.board.renderer.enhancedRendering = true; 494 this.board.renderer.drawEllipse(copy); 495 this.board.renderer.enhancedRendering = er; 496 this.traces[copy.id] = copy.rendNode; 497 498 return this; 499 }, 500 501 /** 502 * Add transformations to this circle. 503 * @param {JXG.Transform|Array} transform Either one {@link JXG.Transform} or an array of {@link JXG.Transform}s. 504 * @returns {JXG.Circle} Reference to this circle object. 505 */ 506 addTransform: function (transform) { 507 var i, 508 list = JXG.isArray(transform) ? transform : [transform], 509 len = list.length; 510 511 for (i = 0; i < len; i++) { 512 this.center.transformations.push(list[i]); 513 if (this.method === 'twoPoints') { 514 this.point2.transformations.push(list[i]); 515 } 516 } 517 518 return this; 519 }, 520 521 // see geometryelement.js 522 snapToGrid: function () { 523 if (this.visProp.snaptogrid) { 524 this.center.snapToGrid(); 525 526 if (this.method === 'twoPoints') { 527 this.point2.snapToGrid(); 528 } 529 } 530 531 return this; 532 }, 533 534 /** 535 * TODO description 536 * @param method TODO 537 * @param coords TODO 538 * @private 539 */ 540 setPosition: function (method, coords) { 541 var t; 542 543 coords = new JXG.Coords(method, coords, this.board); 544 t = this.board.create('transform', coords.usrCoords.slice(1), {type:'translate'}); 545 this.addTransform(t); 546 547 return this; 548 }, 549 550 /** 551 * Sets x and y coordinate and calls the circle's update() method. 552 * @param {number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. 553 * @param {Array} coords coordinate in screen/user units 554 * @param {Array} oldcoords previous coordinate in screen/user units 555 * @returns {JXG.Circle} Reference to this circle. 556 */ 557 setPositionDirectly: function (method, coords, oldcoords) { 558 coords = new JXG.Coords(method, coords, this.board); 559 oldcoords = new JXG.Coords(method, oldcoords, this.board); 560 561 var diffc = JXG.Math.Statistics.subtract(coords.usrCoords, oldcoords.usrCoords), 562 len = this.parents.length, i, p; 563 564 for (i = 0; i < len; i++) { 565 if (!JXG.getRef(this.board, this.parents[i]).draggable()) { 566 return this; 567 } 568 } 569 570 for (i = 0; i < len; i++) { 571 p = JXG.getRef(this.board, this.parents[i]); 572 p.coords.setCoordinates(JXG.COORDS_BY_USER, JXG.Math.Statistics.add(p.coords.usrCoords, diffc)); 573 } 574 575 this.update(); 576 return this; 577 }, 578 579 /** 580 * Treats the circle as parametric curve and calculates its X coordinate. 581 * @param {Number} t Number between 0 and 1. 582 * @returns {Number} <tt>X(t)= radius*cos(t)+centerX</tt>. 583 */ 584 X: function (t) { 585 return this.Radius()*Math.cos(t*2.0*Math.PI)+this.center.coords.usrCoords[1]; 586 }, 587 588 /** 589 * Treats the circle as parametric curve and calculates its Y coordinate. 590 * @param {Number} t Number between 0 and 1. 591 * @returns {Number} <tt>X(t)= radius*sin(t)+centerY</tt>. 592 */ 593 Y: function (t) { 594 return this.Radius()*Math.sin(t*2.0*Math.PI)+this.center.coords.usrCoords[2]; 595 }, 596 597 /** 598 * Treat the circle as parametric curve and calculates its Z coordinate. 599 * @param {Number} t ignored 600 * @return {Number} 1.0 601 */ 602 Z: function (t) { 603 return 1.0; 604 }, 605 606 /** 607 * TODO description 608 * @private 609 */ 610 minX: function () { 611 return 0.0; 612 }, 613 614 /** 615 * TODO description 616 * @private 617 */ 618 maxX: function () { 619 return 1.0; 620 }, 621 622 Area: function () { 623 var r = this.Radius(); 624 return r*r*Math.PI; 625 }, 626 627 bounds: function () { 628 var uc = this.center.coords.usrCoords, 629 r = this.Radius(); 630 631 return [uc[1] - r, uc[2] + r, uc[1] + r, uc[2] - r]; 632 } 633 }); 634 635 /** 636 * @class This element is used to provide a constructor for a circle. 637 * @pseudo 638 * @description A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius. 639 * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function, 640 * line, or circle). 641 * @name Circle 642 * @augments JXG.Circle 643 * @constructor 644 * @type JXG.Circle 645 * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. 646 * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, but the radius can be given 647 * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the 648 * line will determine the radius), or another {@link JXG.Circle}. 649 * @example 650 * // Create a circle providing two points 651 * var p1 = board.create('point', [2.0, 2.0]); 652 * var p2 = board.create('point', [2.0, 0.0]); 653 * var c1 = board.create('circle', [p1, p2]); 654 * 655 * // Create another circle using the above circle 656 * var p3 = board.create('point', [3.0, 2.0]); 657 * var c2 = board.create('circle', [p3, c1]); 658 * </pre><div id="5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0" style="width: 400px; height: 400px;"></div> 659 * <script type="text/javascript"> 660 * var cex1_board = JXG.JSXGraph.initBoard('5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); 661 * var cex1_p1 = cex1_board.create('point', [2.0, 2.0]); 662 * var cex1_p2 = cex1_board.create('point', [2.0, 0.0]); 663 * var cex1_c1 = cex1_board.create('circle', [cex1_p1, cex1_p2]); 664 * var cex1_p3 = cex1_board.create('point', [3.0, 2.0]); 665 * var cex1_c2 = cex1_board.create('circle', [cex1_p3, cex1_c1]); 666 * </script><pre> 667 */ 668 JXG.createCircle = function (board, parents, attributes) { 669 var el, p, i, attr, isDraggable = true; 670 671 p = []; 672 for (i=0;i<parents.length;i++) { 673 if (JXG.isPoint(parents[i])) { 674 p[i] = parents[i]; // Point 675 } else if (JXG.isArray(parents[i]) && parents[i].length>1) { 676 attr = JXG.copyAttributes(attributes, board.options, 'circle', 'center'); 677 p[i] = board.create('point', parents[i], attr); // Coordinates 678 } else { 679 p[i] = parents[i]; // Something else (number, function, string) 680 } 681 } 682 683 attr = JXG.copyAttributes(attributes, board.options, 'circle'); 684 685 if( parents.length==2 && JXG.isPoint(p[0]) && JXG.isPoint(p[1]) ) { 686 // Point/Point 687 el = new JXG.Circle(board, 'twoPoints', p[0], p[1], attr); 688 } else if( ( JXG.isNumber(p[0]) || JXG.isFunction(p[0]) || JXG.isString(p[0])) && JXG.isPoint(p[1]) ) { 689 // Number/Point 690 el = new JXG.Circle(board, 'pointRadius', p[1], p[0], attr); 691 } else if( ( JXG.isNumber(p[1]) || JXG.isFunction(p[1]) || JXG.isString(p[1])) && JXG.isPoint(p[0]) ) { 692 // Point/Number 693 el = new JXG.Circle(board, 'pointRadius', p[0], p[1], attr); 694 } else if( (p[0].elementClass == JXG.OBJECT_CLASS_CIRCLE) && JXG.isPoint(p[1]) ) { 695 // Circle/Point 696 el = new JXG.Circle(board, 'pointCircle', p[1], p[0], attr); 697 } else if( (p[1].elementClass == JXG.OBJECT_CLASS_CIRCLE) && JXG.isPoint(p[0])) { 698 // Point/Circle 699 el = new JXG.Circle(board, 'pointCircle', p[0], p[1], attr); 700 } else if( (p[0].elementClass == JXG.OBJECT_CLASS_LINE) && JXG.isPoint(p[1])) { 701 // Line/Point 702 el = new JXG.Circle(board, 'pointLine', p[1], p[0], attr); 703 } else if( (p[1].elementClass == JXG.OBJECT_CLASS_LINE) && JXG.isPoint(p[0])) { 704 // Point/Line 705 el = new JXG.Circle(board, 'pointLine', p[0], p[1], attr); 706 } else if( parents.length==3 && JXG.isPoint(p[0]) && JXG.isPoint(p[1]) && JXG.isPoint(p[2])) { 707 // Circle through three points 708 el = JXG.createCircumcircle(board, p, attributes); 709 //el.center.setProperty({visible:false}); 710 //isDraggable = false; 711 } else 712 throw new Error("JSXGraph: Can't create circle with parent types '" + 713 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 714 "\nPossible parent types: [point,point], [point,number], [point,function], [point,circle], [point,point,point]"); 715 716 el.isDraggable = isDraggable; 717 718 el.parents = []; 719 for (i = 0; i < parents.length; i++) { 720 if (parents[i].id) { 721 el.parents.push(parents[i].id); 722 } 723 } 724 725 el.elType = 'circle'; 726 return el; 727 }; 728 729 JXG.JSXGraph.registerElement('circle', JXG.createCircle); 730