1 /*
  2     Copyright 2008-2011
  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  * @fileoverview In this file the geometry object Arc is defined. Arc stores all
 28  * style and functional properties that are required to draw an arc on a board.
 29  */
 30 
 31 /**
 32  * @class An arc is a segment of the circumference of a circle. It is defined by a center, one point that
 33  * defines the radius, and a third point that defines the angle of the arc.
 34  * @pseudo
 35  * @name Arc
 36  * @augments Curve
 37  * @constructor
 38  * @type JXG.Curve
 39  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 40  * @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
 41  * counter-clockwise from p2 to p3.
 42  * @example
 43  * // Create an arc out of three free points
 44  * var p1 = board.create('point', [2.0, 2.0]);
 45  * var p2 = board.create('point', [1.0, 0.5]);
 46  * var p3 = board.create('point', [3.5, 1.0]);
 47  *
 48  * var a = board.create('arc', [p1, p2, p3]);
 49  * </pre><div id="114ef584-4a5e-4686-8392-c97501befb5b" style="width: 300px; height: 300px;"></div>
 50  * <script type="text/javascript">
 51  * (function () {
 52  *   var board = JXG.JSXGraph.initBoard('114ef584-4a5e-4686-8392-c97501befb5b', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
 53  *       p1 = board.create('point', [2.0, 2.0]),
 54  *       p2 = board.create('point', [1.0, 0.5]),
 55  *       p3 = board.create('point', [3.5, 1.0]),
 56  *
 57  *       a = board.create('arc', [p1, p2, p3]);
 58  * })();
 59  * </script><pre>
 60  */
 61 JXG.createArc = function(board, parents, attributes) {
 62     var el, attr, i;
 63 
 64 
 65     // this method is used to create circumccirclearcs, too. if a circumcirclearc is created we get a fourth
 66     // point, that's why we need to check that case, too.
 67     if(!(parents = JXG.checkParents('arc', parents, [
 68             [JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT],
 69             [JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT, JXG.OBJECT_CLASS_POINT]]))) {
 70         throw new Error("JSXGraph: Can't create Arc with parent types '" +
 71                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" +
 72                         (typeof parents[2]) + "'." +
 73                         "\nPossible parent types: [point,point,point]");
 74     }
 75 
 76     attr = JXG.copyAttributes(attributes, board.options, 'arc');
 77     el = board.create('curve', [[0],[0]], attr);
 78 
 79     el.elType = 'arc';
 80 
 81     el.parents = [];
 82     for (i = 0; i < parents.length; i++) {
 83         if (parents[i].id) {
 84             el.parents.push(parents[i].id);
 85         }
 86     }
 87 
 88     /**
 89      * documented in JXG.GeometryElement
 90      * @ignore
 91      */
 92     el.type = JXG.OBJECT_TYPE_ARC;
 93 
 94     /**
 95      * Center of the arc.
 96      * @memberOf Arc.prototype
 97      * @name center
 98      * @type JXG.Point
 99      */
100     el.center = JXG.getReference(board, parents[0]);
101 
102     /**
103      * Point defining the arc's radius.
104      * @memberOf Arc.prototype
105      * @name radiuspoint
106      * @type JXG.Point
107      */
108     el.radiuspoint = JXG.getReference(board, parents[1]);
109     el.point2 = el.radiuspoint;
110 
111     /**
112      * The point defining the arc's angle.
113      * @memberOf Arc.prototype
114      * @name anglepoint
115      * @type JXG.Point
116      */
117     el.anglepoint = JXG.getReference(board, parents[2]);
118     el.point3 = el.anglepoint;
119 
120     // Add arc as child to defining points
121     el.center.addChild(el);
122     el.radiuspoint.addChild(el);
123     el.anglepoint.addChild(el);
124     
125     /**
126      * TODO
127      */
128     el.useDirection = attr['usedirection'];      // useDirection is necessary for circumCircleArcs
129 
130     // documented in JXG.Curve
131     el.updateDataArray = function() {
132         var A = this.radiuspoint,
133             B = this.center,
134             C = this.anglepoint,
135             beta, co, si, matrix, phi, i,
136             x = B.X(),
137             y = B.Y(),
138             z = B.Z(),
139             v, det, p0c, p1c, p2c,
140             p1, p2, p3, p4,
141             k, ax, ay, bx, by, d, r, sgn = 1.0,
142             PI2 = Math.PI*0.5;
143             
144         phi = JXG.Math.Geometry.rad(A,B,C);
145         
146         if ((this.visProp.type=='minor' && phi>Math.PI) 
147             || (this.visProp.type=='major' && phi<Math.PI)) { 
148             phi = 2*Math.PI - phi; 
149             sgn = -1.0;
150         }
151 
152         if (this.useDirection) { // This is true for circumCircleArcs. In that case there is
153                                   // a fourth parent element: [center, point1, point3, point2]
154             p0c = parents[1].coords.usrCoords;
155             p1c = parents[3].coords.usrCoords;
156             p2c = parents[2].coords.usrCoords;
157             det = (p0c[1]-p2c[1])*(p0c[2]-p1c[2]) - (p0c[2]-p2c[2])*(p0c[1]-p1c[1]);
158             if (det < 0) {
159                 this.radiuspoint = parents[1];
160                 this.anglepoint = parents[2];
161             } else {
162                 this.radiuspoint = parents[2];
163                 this.anglepoint = parents[1];
164             }
165         }
166 
167         p1 = [A.Z(), A.X(), A.Y()];
168         p4 = p1.slice(0);
169         r = B.Dist(A);
170         x /= z;
171         y /= z;
172         this.dataX = [p1[1]/p1[0]];
173         this.dataY = [p1[2]/p1[0]];
174         while (phi>JXG.Math.eps) {
175             if (phi>=PI2) {
176                 beta = PI2;
177                 phi -= PI2;
178             } else {
179                 beta = phi;
180                 phi = 0.0;
181             }
182 
183             co = Math.cos(sgn*beta);
184             si = Math.sin(sgn*beta);
185             matrix = [[1,        0,   0],  // z missing
186                     [x*(1-co)+y*si,co,-si],
187                     [y*(1-co)-x*si,si, co]];
188             v = JXG.Math.matVecMult(matrix, p1);
189             p4 = [v[0]/v[0], v[1]/v[0], v[2]/v[0]];
190 
191             ax = p1[1]-x;
192             ay = p1[2]-y;
193             bx = p4[1]-x;
194             by = p4[2]-y;
195 
196             d = Math.sqrt((ax+bx)*(ax+bx) + (ay+by)*(ay+by));
197             //if (beta>Math.PI) { d *= -1; }
198  
199             if (Math.abs(by-ay)>JXG.Math.eps) {
200                 k = (ax+bx)*(r/d-0.5)/(by-ay)*8.0/3.0;
201             } else {
202                 k = (ay+by)*(r/d-0.5)/(ax-bx)*8.0/3.0;
203             }
204 
205             p2 = [1, p1[1]-k*ay, p1[2]+k*ax ];
206             p3 = [1, p4[1]+k*by, p4[2]-k*bx ];
207         
208             this.dataX = this.dataX.concat([p2[1], p3[1], p4[1]]);
209             this.dataY = this.dataY.concat([p2[2], p3[2], p4[2]]);
210             p1 = p4.slice(0);
211         }
212         this.bezierDegree = 3;
213 
214         this.updateStdform();
215         this.updateQuadraticform();
216     };
217 
218     /**
219      * Determines the arc's current radius. I.e. the distance between {@link Arc#center} and {@link Arc#radiuspoint}.
220      * @memberOf Arc.prototype
221      * @name Radius
222      * @function
223      * @returns {Number} The arc's radius
224      */
225     el.Radius = function() {
226         return this.radiuspoint.Dist(this.center);
227     };
228 
229     /**
230      * @deprecated Use {@link Arc#Radius}
231      * @memberOf Arc.prototype
232      * @name getRadius
233      * @function
234      * @returns {Number}
235      */
236     el.getRadius = function() {
237         return this.Radius();
238     };
239 
240     // documented in geometry element
241     el.hasPoint = function (x, y) {
242         var prec = this.board.options.precision.hasPoint/(this.board.unitX),
243             r = this.Radius(),
244             dist, checkPoint,
245             has, angle, alpha, beta,
246             invMat, c;
247             
248         checkPoint = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board);
249         
250         if (this.transformations.length>0) {
251             /** 
252              * Transform the mouse/touch coordinates 
253              * back to the original position of the curve.
254              */
255             this.updateTransformMatrix();
256             invMat = JXG.Math.inverse(this.transformMat);
257             c = JXG.Math.matVecMult(invMat, checkPoint.usrCoords);
258             checkPoint = new JXG.Coords(JXG.COORDS_BY_USER, c, this.board);
259         }
260             
261         dist = this.center.coords.distance(JXG.COORDS_BY_USER, checkPoint);
262         has = (Math.abs(dist-r) < prec);
263 
264         /**
265          * At that point we know that the user has touched the circle line.
266          */
267         if (has) {
268             angle = JXG.Math.Geometry.rad(this.radiuspoint,this.center,checkPoint.usrCoords.slice(1));
269             alpha = 0.0;
270             beta = JXG.Math.Geometry.rad(this.radiuspoint,this.center,this.anglepoint);
271             if ((this.visProp.type=='minor' && beta>Math.PI)
272                 || (this.visProp.type=='major' && beta<Math.PI)) { 
273                 alpha = beta; 
274                 beta = 2*Math.PI;
275             } 
276             if (angle<alpha || angle>beta) { 
277                 has = false; 
278             }
279         }
280         return has;    
281     };
282 
283     /**
284      * Checks whether (x,y) is within the sector defined by the arc.
285      * @memberOf Arc.prototype
286      * @name hasPointSector
287      * @function
288      * @param {Number} x Coordinate in x direction, screen coordinates.
289      * @param {Number} y Coordinate in y direction, screen coordinates.
290      * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise.
291      */
292     el.hasPointSector = function (x, y) { 
293         var checkPoint = new JXG.Coords(JXG.COORDS_BY_SCREEN, [x,y], this.board),
294             r = this.Radius(),
295             dist = this.center.coords.distance(JXG.COORDS_BY_USER,checkPoint),
296             has = (dist<r),
297             angle, alpha, beta;
298         
299         if (has) {
300             angle = JXG.Math.Geometry.rad(this.radiuspoint,this.center,checkPoint.usrCoords.slice(1));
301             alpha = 0.0;
302             beta = JXG.Math.Geometry.rad(this.radiuspoint,this.center,this.anglepoint);
303             if ((this.visProp.type=='minor' && beta>Math.PI) 
304                 || (this.visProp.type=='major' && beta<Math.PI)) { 
305                 alpha = beta; 
306                 beta = 2*Math.PI;
307             } 
308             if (angle<alpha || angle>beta) { 
309                 has = false; 
310             }
311         }
312         return has;    
313     };
314 
315     // documented in geometry element
316     el.getTextAnchor = function() {
317         return this.center.coords;
318     };
319 
320     // documented in geometry element
321     el.getLabelAnchor = function() {
322         var angle,
323             dx = 10/(this.board.unitX),
324             dy = 10/(this.board.unitY),
325             p2c = this.point2.coords.usrCoords,
326             pmc = this.center.coords.usrCoords,
327             bxminusax = p2c[1] - pmc[1],
328             byminusay = p2c[2] - pmc[2],
329             coords, vecx, vecy, len;
330 
331         if(this.label.content != null) {                          
332             this.label.content.relativeCoords = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0,0],this.board);                      
333         }  
334 
335         angle = JXG.Math.Geometry.rad(this.radiuspoint, this.center, this.anglepoint);
336         if ((this.visProp.type=='minor' && angle>Math.PI)
337             || (this.visProp.type=='major' && angle<Math.PI)) { 
338             angle = -(2*Math.PI - angle); 
339         } 
340         
341         coords = new JXG.Coords(JXG.COORDS_BY_USER, 
342                         [pmc[1]+ Math.cos(angle*0.5)*bxminusax - Math.sin(angle*0.5)*byminusay, 
343                         pmc[2]+ Math.sin(angle*0.5)*bxminusax + Math.cos(angle*0.5)*byminusay], 
344                         this.board);
345 
346         vecx = coords.usrCoords[1] - pmc[1];
347         vecy = coords.usrCoords[2] - pmc[2];
348     
349         len = Math.sqrt(vecx*vecx+vecy*vecy);
350         vecx = vecx*(len+dx)/len;
351         vecy = vecy*(len+dy)/len;
352 
353         return new JXG.Coords(JXG.COORDS_BY_USER, [pmc[1]+vecx,pmc[2]+vecy], this.board);
354     };
355     
356     /**
357      * TODO description
358      */
359     el.updateQuadraticform = function () {
360         var m = this.center,
361             mX = m.X(), mY = m.Y(), r = this.Radius();
362         this.quadraticform = [[mX*mX+mY*mY-r*r,-mX,-mY],
363             [-mX,1,0],
364             [-mY,0,1]
365         ];
366     };
367 
368     /**
369      * TODO description
370      */
371     el.updateStdform = function () {
372         this.stdform[3] = 0.5;
373         this.stdform[4] = this.Radius();
374         this.stdform[1] = -this.center.coords.usrCoords[1];
375         this.stdform[2] = -this.center.coords.usrCoords[2];
376         this.normalize();
377     };
378 
379     el.prepareUpdate().update();
380     return el;
381 };
382 
383 JXG.JSXGraph.registerElement('arc', JXG.createArc);
384 
385 /**
386  * @class A semicircle is a special arc defined by two points. The arc hits both points.
387  * @pseudo
388  * @name Semicircle
389  * @augments Arc
390  * @constructor
391  * @type Arc
392  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
393  * @param {JXG.Point_JXG.Point} p1,p2 The result will be a composition of an arc drawn clockwise from <tt>p1</tt> and
394  * <tt>p2</tt> and the midpoint of <tt>p1</tt> and <tt>p2</tt>.
395  * @example
396  * // Create an arc out of three free points
397  * var p1 = board.create('point', [4.5, 2.0]);
398  * var p2 = board.create('point', [1.0, 0.5]);
399  *
400  * var a = board.create('semicircle', [p1, p2]);
401  * </pre><div id="5385d349-75d7-4078-b732-9ae808db1b0e" style="width: 300px; height: 300px;"></div>
402  * <script type="text/javascript">
403  * (function () {
404  *   var board = JXG.JSXGraph.initBoard('5385d349-75d7-4078-b732-9ae808db1b0e', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
405  *       p1 = board.create('point', [4.5, 2.0]),
406  *       p2 = board.create('point', [1.0, 0.5]),
407  *
408  *       sc = board.create('semicircle', [p1, p2]);
409  * })();
410  * </script><pre>
411  */
412 JXG.createSemicircle = function(board, parents, attributes) {
413     var el, mp, attr;
414     
415 
416     // we need 2 points
417     if ( (JXG.isPoint(parents[0])) && (JXG.isPoint(parents[1])) ) {
418 
419         attr = JXG.copyAttributes(attributes, board.options, 'semicircle', 'midpoint');
420         mp = board.create('midpoint', [parents[0], parents[1]], attr);
421 
422         mp.dump = false;
423 
424         attr = JXG.copyAttributes(attributes, board.options, 'semicircle');
425         el = board.create('arc', [mp, parents[1], parents[0]], attr);
426 
427         el.elType = 'semicircle';
428         el.parents = [parents[0].id, parents[1].id];
429         el.subs = {
430             midpoint: mp
431         };
432 
433         /**
434          * The midpoint of the two defining points.
435          * @memberOf Semicircle.prototype
436          * @name midpoint
437          * @type Midpoint
438          */
439         el.midpoint = el.center = mp;
440     } else
441         throw new Error("JSXGraph: Can't create Semicircle with parent types '" + 
442                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
443                         "\nPossible parent types: [point,point]");
444 
445     return el;
446 };
447 
448 JXG.JSXGraph.registerElement('semicircle', JXG.createSemicircle);
449 
450 /**
451  * @class A circumcircle arc is an {@link Arc} defined by three points. All three points lie on the arc.
452  * @pseudo
453  * @name CircumcircleArc
454  * @augments Arc
455  * @constructor
456  * @type Arc
457  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
458  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be a composition of an arc of the circumcircle of
459  * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt> and the midpoint of the circumcircle of the three points. The arc is drawn
460  * counter-clockwise from <tt>p1</tt> over <tt>p2</tt> to <tt>p3</tt>.
461  * @example
462  * // Create a circum circle arc out of three free points
463  * var p1 = board.create('point', [2.0, 2.0]);
464  * var p2 = board.create('point', [1.0, 0.5]);
465  * var p3 = board.create('point', [3.5, 1.0]);
466  *
467  * var a = board.create('arc', [p1, p2, p3]);
468  * </pre><div id="87125fd4-823a-41c1-88ef-d1a1369504e3" style="width: 300px; height: 300px;"></div>
469  * <script type="text/javascript">
470  * (function () {
471  *   var board = JXG.JSXGraph.initBoard('87125fd4-823a-41c1-88ef-d1a1369504e3', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
472  *       p1 = board.create('point', [2.0, 2.0]),
473  *       p2 = board.create('point', [1.0, 0.5]),
474  *       p3 = board.create('point', [3.5, 1.0]),
475  *
476  *       cca = board.create('circumcirclearc', [p1, p2, p3]);
477  * })();
478  * </script><pre>
479  */
480 JXG.createCircumcircleArc = function(board, parents, attributes) {
481     var el, mp, attr;
482     
483     // We need three points
484     if ( (JXG.isPoint(parents[0])) && (JXG.isPoint(parents[1])) && (JXG.isPoint(parents[2]))) {
485 
486         attr = JXG.copyAttributes(attributes, board.options, 'circumcirclearc', 'center');
487         mp = board.create('circumcenter',[parents[0], parents[1], parents[2]], attr);
488 
489         mp.dump = false;
490 
491         attr = JXG.copyAttributes(attributes, board.options, 'circumcirclearc');
492         attr.usedirection = true;
493         el = board.create('arc', [mp, parents[0], parents[2], parents[1]], attr);
494 
495         el.elType = 'circumcirclearc';
496         el.parents = [parents[0].id, parents[1].id, parents[2].id];
497         el.subs = {
498             center: mp
499         };
500 
501         /**
502          * The midpoint of the circumcircle of the three points defining the circumcircle arc.
503          * @memberOf CircumcircleArc.prototype
504          * @name center
505          * @type Circumcenter
506          */
507         el.center = mp;
508     } else
509         throw new Error("JSXGraph: create Circumcircle Arc with parent types '" + 
510                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
511                         "\nPossible parent types: [point,point,point]");
512 
513     return el;
514 };
515 
516 JXG.JSXGraph.registerElement('circumcirclearc', JXG.createCircumcircleArc);
517 
518 /**
519  * @class A minor arc is a segment of the circumference of a circle having measure less than or equal to 
520  * 180 degrees (pi radians). It is defined by a center, one point that
521  * defines the radius, and a third point that defines the angle of the arc.
522  * @pseudo
523  * @name MinorArc
524  * @augments Curve
525  * @constructor
526  * @type JXG.Curve
527  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
528  * @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 
529  * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. 
530  * @example
531  * // Create an arc out of three free points
532  * var p1 = board.create('point', [2.0, 2.0]);
533  * var p2 = board.create('point', [1.0, 0.5]);
534  * var p3 = board.create('point', [3.5, 1.0]);
535  *
536  * var a = board.create('arc', [p1, p2, p3]);
537  * </pre><div id="af27ddcc-265f-428f-90dd-d31ace945800" style="width: 300px; height: 300px;"></div>
538  * <script type="text/javascript">
539  * (function () {
540  *   var board = JXG.JSXGraph.initBoard('af27ddcc-265f-428f-90dd-d31ace945800', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
541  *       p1 = board.create('point', [2.0, 2.0]),
542  *       p2 = board.create('point', [1.0, 0.5]),
543  *       p3 = board.create('point', [3.5, 1.0]),
544  *
545  *       a = board.create('minorarc', [p1, p2, p3]);
546  * })();
547  * </script><pre>
548  */
549 
550 JXG.createMinorArc = function(board, parents, attributes) {
551     attributes.type = 'minor';
552     return JXG.createArc(board, parents, attributes);
553 };
554 
555 JXG.JSXGraph.registerElement('minorarc', JXG.createMinorArc);
556 
557 /**
558  * @class A major arc is a segment of the circumference of a circle having measure greater than or equal to 
559  * 180 degrees (pi radians). It is defined by a center, one point that
560  * defines the radius, and a third point that defines the angle of the arc.
561  * @pseudo
562  * @name MinorArc
563  * @augments Curve
564  * @constructor
565  * @type JXG.Curve
566  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
567  * @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 
568  * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. 
569  * @example
570  * // Create an arc out of three free points
571  * var p1 = board.create('point', [2.0, 2.0]);
572  * var p2 = board.create('point', [1.0, 0.5]);
573  * var p3 = board.create('point', [3.5, 1.0]);
574  *
575  * var a = board.create('arc', [p1, p2, p3]);
576  * </pre><div id="83c6561f-7561-4047-b98d-036248a00932" style="width: 300px; height: 300px;"></div>
577  * <script type="text/javascript">
578  * (function () {
579  *   var board = JXG.JSXGraph.initBoard('83c6561f-7561-4047-b98d-036248a00932', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),
580  *       p1 = board.create('point', [2.0, 2.0]),
581  *       p2 = board.create('point', [1.0, 0.5]),
582  *       p3 = board.create('point', [3.5, 1.0]),
583  *
584  *       a = board.create('majorarc', [p1, p2, p3]);
585  * })();
586  * </script><pre>
587  */
588 JXG.createMajorArc = function(board, parents, attributes) {
589     attributes.type = 'major';
590     return JXG.createArc(board, parents, attributes);
591 };
592 
593 JXG.JSXGraph.registerElement('majorarc', JXG.createMajorArc);
594