1 /* 2 Copyright 2008-2023 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 dual licensed under the GNU LGPL or MIT License. 13 14 You can redistribute it and/or modify it under the terms of the 15 16 * GNU Lesser General Public License as published by 17 the Free Software Foundation, either version 3 of the License, or 18 (at your option) any later version 19 OR 20 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 21 22 JSXGraph is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 GNU Lesser General Public License for more details. 26 27 You should have received a copy of the GNU Lesser General Public License and 28 the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/> 29 and <https://opensource.org/licenses/MIT/>. 30 */ 31 32 /*global JXG: true, define: true*/ 33 /*jslint nomen: true, plusplus: true*/ 34 35 /** 36 * @fileoverview In this file the geometry object Arc is defined. Arc stores all 37 * style and functional properties that are required to draw an arc on a board. 38 */ 39 40 import JXG from "../jxg"; 41 import Geometry from "../math/geometry"; 42 import Mat from "../math/math"; 43 import Coords from "../base/coords"; 44 import Circle from "../base/circle"; 45 import Type from "../utils/type"; 46 import Const from "../base/constants"; 47 48 /** 49 * @class An arc is a segment of the circumference of a circle. It is defined by a center, one point that 50 * defines the radius, and a third point that defines the angle of the arc. 51 * 52 * @pseudo 53 * @name Arc 54 * @augments Curve 55 * @constructor 56 * @type JXG.Curve 57 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. 58 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be an arc of a circle around p1 through p2. The arc is drawn 59 * counter-clockwise from p2 to p3. 60 * @example 61 * // Create an arc out of three free points 62 * var p1 = board.create('point', [2.0, 2.0]); 63 * var p2 = board.create('point', [1.0, 0.5]); 64 * var p3 = board.create('point', [3.5, 1.0]); 65 * 66 * var a = board.create('arc', [p1, p2, p3]); 67 * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}]) 68 * </pre><div class="jxgbox" id="JXG114ef584-4a5e-4686-8392-c97501befb5b" style="width: 300px; height: 300px;"></div> 69 * <script type="text/javascript"> 70 * (function () { 71 * var board = JXG.JSXGraph.initBoard('JXG114ef584-4a5e-4686-8392-c97501befb5b', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), 72 * p1 = board.create('point', [2.0, 2.0]), 73 * p2 = board.create('point', [1.0, 0.5]), 74 * p3 = board.create('point', [3.5, 1.0]), 75 * 76 * a = board.create('arc', [p1, p2, p3]); 77 * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}]) 78 * })(); 79 * </script><pre> 80 * 81 * @example 82 * var t = board.create('transform', [2, 1.5], {type: 'scale'}); 83 * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); 84 * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'}); 85 * 86 * </pre><div id="JXG1949da46-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> 87 * <script type="text/javascript"> 88 * (function() { 89 * var board = JXG.JSXGraph.initBoard('JXG1949da46-6339-11e8-9fb9-901b0e1b8723', 90 * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); 91 * var t = board.create('transform', [2, 1.5], {type: 'scale'}); 92 * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); 93 * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'}); 94 * 95 * })(); 96 * 97 * </script><pre> 98 * 99 */ 100 JXG.createArc = function (board, parents, attributes) { 101 var el, attr, points; 102 103 points = Type.providePoints(board, parents, attributes, "arc", [ 104 "center", 105 "radiusPoint", 106 "anglePoint" 107 ]); 108 if (points === false || points.length < 3) { 109 throw new Error( 110 "JSXGraph: Can't create Arc with parent types '" + 111 typeof parents[0] + 112 "' and '" + 113 typeof parents[1] + 114 "' and '" + 115 typeof parents[2] + 116 "'." + 117 "\nPossible parent types: [point,point,point], [arc, transformation]" 118 ); 119 } 120 121 attr = Type.copyAttributes(attributes, board.options, "arc"); 122 el = board.create("curve", [[0], [0]], attr); 123 124 el.elType = "arc"; 125 el.setParents(points); 126 127 /** 128 * documented in JXG.GeometryElement 129 * @ignore 130 */ 131 el.type = Const.OBJECT_TYPE_ARC; 132 133 /** 134 * Center of the arc. 135 * @memberOf Arc.prototype 136 * @name center 137 * @type JXG.Point 138 */ 139 el.center = points[0]; 140 141 /** 142 * Point defining the arc's radius. 143 * @memberOf Arc.prototype 144 * @name radiuspoint 145 * @type JXG.Point 146 */ 147 el.radiuspoint = points[1]; 148 el.point2 = el.radiuspoint; 149 150 /** 151 * The point defining the arc's angle. 152 * @memberOf Arc.prototype 153 * @name anglepoint 154 * @type JXG.Point 155 */ 156 el.anglepoint = points[2]; 157 el.point3 = el.anglepoint; 158 159 // Add arc as child to defining points 160 // or vice versa if the points are provided as coordinates 161 if (Type.exists(el.center._is_new)) { 162 el.addChild(el.center); 163 delete el.center._is_new; 164 } else { 165 el.center.addChild(el); 166 } 167 if (Type.exists(el.radiuspoint._is_new)) { 168 el.addChild(el.radiuspoint); 169 delete el.radiuspoint._is_new; 170 } else { 171 el.radiuspoint.addChild(el); 172 } 173 if (Type.exists(el.anglepoint._is_new)) { 174 el.addChild(el.anglepoint); 175 delete el.anglepoint._is_new; 176 } else { 177 el.anglepoint.addChild(el); 178 } 179 180 // should be documented in options 181 el.useDirection = attr.usedirection; 182 183 // documented in JXG.Curve 184 el.updateDataArray = function () { 185 var ar, 186 phi, 187 det, 188 p0c, 189 p1c, 190 p2c, 191 sgn = 1, 192 A = this.radiuspoint, 193 B = this.center, 194 C = this.anglepoint, 195 ev_s = Type.evaluate(this.visProp.selection); 196 197 phi = Geometry.rad(A, B, C); 198 if ((ev_s === "minor" && phi > Math.PI) || (ev_s === "major" && phi < Math.PI)) { 199 sgn = -1; 200 } 201 202 // This is true for circumCircleArcs. In that case there is 203 // a fourth parent element: [center, point1, point3, point2] 204 if (this.useDirection) { 205 p0c = points[1].coords.usrCoords; 206 p1c = points[3].coords.usrCoords; 207 p2c = points[2].coords.usrCoords; 208 det = (p0c[1] - p2c[1]) * (p0c[2] - p1c[2]) - (p0c[2] - p2c[2]) * (p0c[1] - p1c[1]); 209 210 if (det < 0) { 211 this.radiuspoint = points[1]; 212 this.anglepoint = points[2]; 213 } else { 214 this.radiuspoint = points[2]; 215 this.anglepoint = points[1]; 216 } 217 } 218 219 A = A.coords.usrCoords; 220 B = B.coords.usrCoords; 221 C = C.coords.usrCoords; 222 223 ar = Geometry.bezierArc(A, B, C, false, sgn); 224 225 this.dataX = ar[0]; 226 this.dataY = ar[1]; 227 228 this.bezierDegree = 3; 229 230 this.updateStdform(); 231 this.updateQuadraticform(); 232 }; 233 234 /** 235 * Determines the arc's current radius. I.e. the distance between {@link Arc#center} and {@link Arc#radiuspoint}. 236 * @memberOf Arc.prototype 237 * @name Radius 238 * @function 239 * @returns {Number} The arc's radius 240 */ 241 el.Radius = function () { 242 return this.radiuspoint.Dist(this.center); 243 }; 244 245 /** 246 * @deprecated Use {@link Arc#Radius} 247 * @memberOf Arc.prototype 248 * @name getRadius 249 * @function 250 * @returns {Number} 251 */ 252 el.getRadius = function () { 253 JXG.deprecated("Arc.getRadius()", "Arc.Radius()"); 254 return this.Radius(); 255 }; 256 257 /** 258 * Returns the length of the arc. 259 * @memberOf Arc.prototype 260 * @name Value 261 * @function 262 * @returns {Number} The arc length 263 */ 264 el.Value = function () { 265 return this.Radius() * Geometry.rad(this.radiuspoint, this.center, this.anglepoint); 266 }; 267 268 // documented in geometry element 269 el.hasPoint = function (x, y) { 270 var dist, 271 checkPoint, 272 has, 273 invMat, 274 c, 275 prec, 276 type, 277 r = this.Radius(); 278 279 if (Type.evaluate(this.visProp.hasinnerpoints)) { 280 return this.hasPointSector(x, y); 281 } 282 283 if (Type.isObject(Type.evaluate(this.visProp.precision))) { 284 type = this.board._inputDevice; 285 prec = Type.evaluate(this.visProp.precision[type]); 286 } else { 287 // 'inherit' 288 prec = this.board.options.precision.hasPoint; 289 } 290 prec /= Math.min(Math.abs(this.board.unitX), Math.abs(this.board.unitY)); 291 checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); 292 293 if (this.transformations.length > 0) { 294 // Transform the mouse/touch coordinates 295 // back to the original position of the curve. 296 this.updateTransformMatrix(); 297 invMat = Mat.inverse(this.transformMat); 298 c = Mat.matVecMult(invMat, checkPoint.usrCoords); 299 checkPoint = new Coords(Const.COORDS_BY_USER, c, this.board); 300 } 301 302 dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint); 303 has = Math.abs(dist - r) < prec; 304 305 /** 306 * At that point we know that the user has touched the circle line. 307 * Now, we have to check, if the user has hit the arc path. 308 */ 309 if (has) { 310 has = Geometry.coordsOnArc(this, checkPoint); 311 } 312 return has; 313 }; 314 315 /** 316 * Checks whether (x,y) is within the sector defined by the arc. 317 * @memberOf Arc.prototype 318 * @name hasPointSector 319 * @function 320 * @param {Number} x Coordinate in x direction, screen coordinates. 321 * @param {Number} y Coordinate in y direction, screen coordinates. 322 * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise. 323 */ 324 el.hasPointSector = function (x, y) { 325 var checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), 326 r = this.Radius(), 327 dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint), 328 has = dist < r; 329 330 if (has) { 331 has = Geometry.coordsOnArc(this, checkPoint); 332 } 333 return has; 334 }; 335 336 // documented in geometry element 337 el.getTextAnchor = function () { 338 return this.center.coords; 339 }; 340 341 // documented in geometry element 342 el.getLabelAnchor = function () { 343 var coords, 344 vec, 345 vecx, 346 vecy, 347 len, 348 angle = Geometry.rad(this.radiuspoint, this.center, this.anglepoint), 349 dx = 10 / this.board.unitX, 350 dy = 10 / this.board.unitY, 351 p2c = this.point2.coords.usrCoords, 352 pmc = this.center.coords.usrCoords, 353 bxminusax = p2c[1] - pmc[1], 354 byminusay = p2c[2] - pmc[2], 355 ev_s = Type.evaluate(this.visProp.selection), 356 l_vp = this.label ? this.label.visProp : this.visProp.label; 357 358 // If this is uncommented, the angle label can not be dragged 359 //if (Type.exists(this.label)) { 360 // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); 361 //} 362 363 if ((ev_s === "minor" && angle > Math.PI) || (ev_s === "major" && angle < Math.PI)) { 364 angle = -(2 * Math.PI - angle); 365 } 366 367 coords = new Coords( 368 Const.COORDS_BY_USER, 369 [ 370 pmc[1] + Math.cos(angle * 0.5) * bxminusax - Math.sin(angle * 0.5) * byminusay, 371 pmc[2] + Math.sin(angle * 0.5) * bxminusax + Math.cos(angle * 0.5) * byminusay 372 ], 373 this.board 374 ); 375 376 vecx = coords.usrCoords[1] - pmc[1]; 377 vecy = coords.usrCoords[2] - pmc[2]; 378 379 len = Math.sqrt(vecx * vecx + vecy * vecy); 380 vecx = (vecx * (len + dx)) / len; 381 vecy = (vecy * (len + dy)) / len; 382 vec = [pmc[1] + vecx, pmc[2] + vecy]; 383 384 l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1, 0], [0, 0], vec)); 385 386 return new Coords(Const.COORDS_BY_USER, vec, this.board); 387 }; 388 389 // documentation in jxg.circle 390 el.updateQuadraticform = Circle.prototype.updateQuadraticform; 391 392 // documentation in jxg.circle 393 el.updateStdform = Circle.prototype.updateStdform; 394 395 el.methodMap = JXG.deepCopy(el.methodMap, { 396 getRadius: "getRadius", 397 radius: "Radius", 398 center: "center", 399 radiuspoint: "radiuspoint", 400 anglepoint: "anglepoint", 401 Value: "Value" 402 }); 403 404 el.prepareUpdate().update(); 405 return el; 406 }; 407 408 JXG.registerElement("arc", JXG.createArc); 409 410 /** 411 * @class A semicircle is a special arc defined by two points. The arc hits both points. 412 * @pseudo 413 * @name Semicircle 414 * @augments Arc 415 * @constructor 416 * @type Arc 417 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. 418 * @param {JXG.Point_JXG.Point} p1,p2 The result will be a composition of an arc drawn clockwise from <tt>p1</tt> and 419 * <tt>p2</tt> and the midpoint of <tt>p1</tt> and <tt>p2</tt>. 420 * @example 421 * // Create an arc out of three free points 422 * var p1 = board.create('point', [4.5, 2.0]); 423 * var p2 = board.create('point', [1.0, 0.5]); 424 * 425 * var a = board.create('semicircle', [p1, p2]); 426 * </pre><div class="jxgbox" id="JXG5385d349-75d7-4078-b732-9ae808db1b0e" style="width: 300px; height: 300px;"></div> 427 * <script type="text/javascript"> 428 * (function () { 429 * var board = JXG.JSXGraph.initBoard('JXG5385d349-75d7-4078-b732-9ae808db1b0e', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), 430 * p1 = board.create('point', [4.5, 2.0]), 431 * p2 = board.create('point', [1.0, 0.5]), 432 * 433 * sc = board.create('semicircle', [p1, p2]); 434 * })(); 435 * </script><pre> 436 */ 437 JXG.createSemicircle = function (board, parents, attributes) { 438 var el, mp, attr, points; 439 440 // we need 2 points 441 points = Type.providePoints(board, parents, attributes, "point"); 442 if (points === false || points.length !== 2) { 443 throw new Error( 444 "JSXGraph: Can't create Semicircle with parent types '" + 445 typeof parents[0] + 446 "' and '" + 447 typeof parents[1] + 448 "'." + 449 "\nPossible parent types: [point,point]" 450 ); 451 } 452 453 attr = Type.copyAttributes(attributes, board.options, "semicircle", "center"); 454 mp = board.create("midpoint", points, attr); 455 mp.dump = false; 456 457 attr = Type.copyAttributes(attributes, board.options, "semicircle"); 458 el = board.create("arc", [mp, points[1], points[0]], attr); 459 el.elType = "semicircle"; 460 el.setParents([points[0].id, points[1].id]); 461 el.subs = { 462 midpoint: mp 463 }; 464 el.inherits.push(mp); 465 466 /** 467 * The midpoint of the two defining points. 468 * @memberOf Semicircle.prototype 469 * @name midpoint 470 * @type Midpoint 471 */ 472 el.midpoint = el.center = mp; 473 474 return el; 475 }; 476 477 JXG.registerElement("semicircle", JXG.createSemicircle); 478 479 /** 480 * @class A circumcircle arc is an {@link Arc} defined by three points. All three points lie on the arc. 481 * @pseudo 482 * @name CircumcircleArc 483 * @augments Arc 484 * @constructor 485 * @type Arc 486 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. 487 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be a composition of an arc of the circumcircle of 488 * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt> and the midpoint of the circumcircle of the three points. The arc is drawn 489 * counter-clockwise from <tt>p1</tt> over <tt>p2</tt> to <tt>p3</tt>. 490 * @example 491 * // Create a circum circle arc out of three free points 492 * var p1 = board.create('point', [2.0, 2.0]); 493 * var p2 = board.create('point', [1.0, 0.5]); 494 * var p3 = board.create('point', [3.5, 1.0]); 495 * 496 * var a = board.create('circumcirclearc', [p1, p2, p3]); 497 * </pre><div class="jxgbox" id="JXG87125fd4-823a-41c1-88ef-d1a1369504e3" style="width: 300px; height: 300px;"></div> 498 * <script type="text/javascript"> 499 * (function () { 500 * var board = JXG.JSXGraph.initBoard('JXG87125fd4-823a-41c1-88ef-d1a1369504e3', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), 501 * p1 = board.create('point', [2.0, 2.0]), 502 * p2 = board.create('point', [1.0, 0.5]), 503 * p3 = board.create('point', [3.5, 1.0]), 504 * 505 * cca = board.create('circumcirclearc', [p1, p2, p3]); 506 * })(); 507 * </script><pre> 508 */ 509 JXG.createCircumcircleArc = function (board, parents, attributes) { 510 var el, mp, attr, points; 511 512 // We need three points 513 points = Type.providePoints(board, parents, attributes, "point"); 514 if (points === false || points.length !== 3) { 515 throw new Error( 516 "JSXGraph: create Circumcircle Arc with parent types '" + 517 typeof parents[0] + 518 "' and '" + 519 typeof parents[1] + 520 "' and '" + 521 typeof parents[2] + 522 "'." + 523 "\nPossible parent types: [point,point,point]" 524 ); 525 } 526 527 attr = Type.copyAttributes(attributes, board.options, "circumcirclearc", "center"); 528 mp = board.create("circumcenter", points, attr); 529 mp.dump = false; 530 531 attr = Type.copyAttributes(attributes, board.options, "circumcirclearc"); 532 attr.usedirection = true; 533 el = board.create("arc", [mp, points[0], points[2], points[1]], attr); 534 535 el.elType = "circumcirclearc"; 536 el.setParents([points[0].id, points[1].id, points[2].id]); 537 el.subs = { 538 center: mp 539 }; 540 el.inherits.push(mp); 541 542 /** 543 * The midpoint of the circumcircle of the three points defining the circumcircle arc. 544 * @memberOf CircumcircleArc.prototype 545 * @name center 546 * @type Circumcenter 547 */ 548 el.center = mp; 549 550 return el; 551 }; 552 553 JXG.registerElement("circumcirclearc", JXG.createCircumcircleArc); 554 555 /** 556 * @class A minor arc is a segment of the circumference of a circle having measure less than or equal to 557 * 180 degrees (pi radians). It is defined by a center, one point that 558 * defines the radius, and a third point that defines the angle of the arc. 559 * @pseudo 560 * @name MinorArc 561 * @augments Curve 562 * @constructor 563 * @type JXG.Curve 564 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. 565 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor arc is an arc of a circle around p1 having measure less than or equal to 566 * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. 567 * @example 568 * // Create an arc out of three free points 569 * var p1 = board.create('point', [2.0, 2.0]); 570 * var p2 = board.create('point', [1.0, 0.5]); 571 * var p3 = board.create('point', [3.5, 1.0]); 572 * 573 * var a = board.create('arc', [p1, p2, p3]); 574 * </pre><div class="jxgbox" id="JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f" style="width: 300px; height: 300px;"></div> 575 * <script type="text/javascript"> 576 * (function () { 577 * var board = JXG.JSXGraph.initBoard('JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), 578 * p1 = board.create('point', [2.0, 2.0]), 579 * p2 = board.create('point', [1.0, 0.5]), 580 * p3 = board.create('point', [3.5, 1.0]), 581 * 582 * a = board.create('minorarc', [p1, p2, p3]); 583 * })(); 584 * </script><pre> 585 */ 586 587 JXG.createMinorArc = function (board, parents, attributes) { 588 attributes.selection = "minor"; 589 return JXG.createArc(board, parents, attributes); 590 }; 591 592 JXG.registerElement("minorarc", JXG.createMinorArc); 593 594 /** 595 * @class A major arc is a segment of the circumference of a circle having measure greater than or equal to 596 * 180 degrees (pi radians). It is defined by a center, one point that 597 * defines the radius, and a third point that defines the angle of the arc. 598 * @pseudo 599 * @name MajorArc 600 * @augments Curve 601 * @constructor 602 * @type JXG.Curve 603 * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. 604 * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major arc is an arc of a circle around p1 having measure greater than or equal to 605 * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. 606 * @example 607 * // Create an arc out of three free points 608 * var p1 = board.create('point', [2.0, 2.0]); 609 * var p2 = board.create('point', [1.0, 0.5]); 610 * var p3 = board.create('point', [3.5, 1.0]); 611 * 612 * var a = board.create('majorarc', [p1, p2, p3]); 613 * </pre><div class="jxgbox" id="JXG17a10d38-5629-40a4-b150-f41806edee9f" style="width: 300px; height: 300px;"></div> 614 * <script type="text/javascript"> 615 * (function () { 616 * var board = JXG.JSXGraph.initBoard('JXG17a10d38-5629-40a4-b150-f41806edee9f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), 617 * p1 = board.create('point', [2.0, 2.0]), 618 * p2 = board.create('point', [1.0, 0.5]), 619 * p3 = board.create('point', [3.5, 1.0]), 620 * 621 * a = board.create('majorarc', [p1, p2, p3]); 622 * })(); 623 * </script><pre> 624 */ 625 JXG.createMajorArc = function (board, parents, attributes) { 626 attributes.selection = "major"; 627 return JXG.createArc(board, parents, attributes); 628 }; 629 630 JXG.registerElement("majorarc", JXG.createMajorArc); 631 632 // export default { 633 // createArc: JXG.createArc, 634 // createSemicircle: JXG.createSemicircle, 635 // createCircumcircleArc: JXG.createCircumcircleArc, 636 // createMinorArc: JXG.createMinorArc, 637 // createMajorArc: JXG.createMajorArc 638 // }; 639