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