      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  * Creates a new instance of JXG.Polygon.
     28  * @class Polygon stores all style and functional properties that are required
     29  * to draw and to interactact with a polygon.
     30  * @param {JXG.Board} board Reference to the board the polygon is to be drawn on.
     31  * @param {Array} vertices Unique identifiers for the points defining the polygon.
     32  * Last point must be first point. Otherwise, the first point will be added at the list.
     33  * @param {Object} attributes An object which contains properties as given in {@link JXG.Options.elements}
     34  * and {@link JXG.Options.polygon}.
     35  * @constructor
     36  * @extends JXG.GeometryElement
     37  */
     38
     39 JXG.Polygon = function (board, vertices, attributes) {
     40     this.constructor(board, attributes, JXG.OBJECT_TYPE_POLYGON, JXG.OBJECT_CLASS_AREA);
     41
     42     var i, vertex, l,
     43         attr_line = JXG.copyAttributes(attributes, board.options, 'polygon', 'borders');
     44
     45     this.withLines = attributes.withlines;
     46     this.attr_line = attr_line;
     47
     48     /**
     49      * References to the points defining the polygon. The last vertex is the same as the first vertex.
     50      * @type Array
     51      */
     52     this.vertices = [];
     53     for(i=0; i<vertices.length; i++) {
     54        vertex = JXG.getRef(this.board, vertices[i]);
     55        this.vertices[i] = vertex;
     56     }
     57
     58     if(this.vertices[this.vertices.length-1] != this.vertices[0]) {
     59         this.vertices.push(this.vertices[0]);
     60     }
     61
     62     /**
     63      * References to the border lines of the polygon.
     64      * @type Array
     65      */
     66     this.borders = [];
     67     if (this.withLines) {
     68         for(i = 0; i < this.vertices.length - 1; i++) {
     69             attr_line.id = attr_line.ids && attr_line.ids[i];
     70             attr_line.strokecolor = JXG.isArray(attr_line.colors) && attr_line.colors[i % attr_line.colors.length] || attr_line.strokecolor;
     71             if (attr_line.strokecolor===false) attr_line.strokecolor = 'none';
     72             l = JXG.createSegment(board, [this.vertices[i], this.vertices[i+1]], attr_line);
     73             l.dump = false;
     74             this.borders[i] = l;
     75             l.parentPolygon = this;
     76         }
     77     }
     78
     79     // Add polygon as child to defining points
     80     for(i=0; i<this.vertices.length-1; i++) { // last vertex is first vertex
     81         vertex = JXG.getReference(this.board, this.vertices[i]);
     82         vertex.addChild(this);
     83     }
     84
     85     // create label
     86     this.createLabel();
     87
     88     /* Register polygon at board */
     89     this.id = this.board.setId(this, 'Py');
     90     this.board.renderer.drawPolygon(this);
     91     this.board.finalizeAdding(this);
     92
     93     this.methodMap.borders = 'borders';
     94     this.methodMap.vertices = 'vertices';
     95
     96     this.elType = 'polygon';
     97 };
     98 JXG.Polygon.prototype = new JXG.GeometryElement;
     99
    100
    101 JXG.extend(JXG.Polygon.prototype, /** @lends JXG.Polygon.prototype */ {
    102     /**
    103      * Checks whether (x,y) is near the polygon.
    104      * @param {Number} x Coordinate in x direction, screen coordinates.
    105      * @param {Number} y Coordinate in y direction, screen coordinates.
    106      * @return {Boolean} Returns true, if (x,y) is inside or at the boundary the polygon, otherwise false.
    107      */
    108     hasPoint: function (x,y) {
    109
    110         var i, j, len, c = false;
    111
    112         if (this.visProp.hasinnerpoints) {
    113             // All points of the polygon trigger hasPoint: inner and boundary points
    114             len = this.vertices.length;
    115             // See http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for a reference
    116             for (i=0, j=len-2; i<len-1; j=i++) { // last vertex is first vertex
    117                 if (((this.vertices[i].coords.scrCoords[2] > y) != (this.vertices[j].coords.scrCoords[2] > y))
    118                     && (x < (this.vertices[j].coords.scrCoords[1] - this.vertices[i].coords.scrCoords[1]) * (y - this.vertices[i].coords.scrCoords[2])
    119                         / (this.vertices[j].coords.scrCoords[2] - this.vertices[i].coords.scrCoords[2]) + this.vertices[i].coords.scrCoords[1])) {
    120                     c = !c;
    121                 }
    122             }
    123         } else {
    124             // Only boundary points trigger hasPoint
    125             len = this.borders.length;
    126             for (i=0; i<len; i++) {
    127                 if (this.borders[i].hasPoint(x,y)) {
    128                     c = true;
    129                     break;
    130                 }
    131             }
    132         }
    133
    134         return c;
    135     },
    136
    137     /**
    138      * Uses the boards renderer to update the polygon.
    139      */
    140     updateRenderer: function () {
    141         if (this.needsUpdate) {
    142             this.board.renderer.updatePolygon(this);
    143             this.needsUpdate = false;
    144         }
    145         if(this.hasLabel && this.label.content.visProp.visible) {
    146             //this.label.setCoordinates(this.coords);
    147             this.label.content.update();
    148             //this.board.renderer.updateLabel(this.label);
    149             this.board.renderer.updateText(this.label.content);
    150         }
    151     },
    152
    153     /**
    154      * return TextAnchor
    155      */
    156     getTextAnchor: function() {
    157         var a = this.vertices[0].X(),
    158             b = this.vertices[0].Y(),
    159             x = a,
    160             y = b,
    161             i;
    162
    163         for (i = 0; i < this.vertices.length; i++) {
    164             if (this.vertices[i].X() < a)
    165                 a = this.vertices[i].X();
    166             if (this.vertices[i].X() > x)
    167                 x = this.vertices[i].X();
    168             if (this.vertices[i].Y() > b)
    169                 b = this.vertices[i].Y();
    170             if (this.vertices[i].Y() < y)
    171                 y = this.vertices[i].Y();
    172         }
    173
    174         return new JXG.Coords(JXG.COORDS_BY_USER, [(a + x)*0.5, (b + y)*0.5], this.board);
    175     },
    176
    177     getLabelAnchor: JXG.shortcut(JXG.Polygon.prototype, 'getTextAnchor'),
    178
    179     // documented in geometry element
    180     cloneToBackground: function() {
    181         var copy = {}, er;
    182
    183         copy.id = this.id + 'T' + this.numTraces;
    184         this.numTraces++;
    185         copy.vertices = this.vertices;
    186         copy.visProp = JXG.deepCopy(this.visProp, this.visProp.traceattributes, true);
    187         copy.visProp.layer = this.board.options.layer.trace;
    188         copy.board = this.board;
    189         JXG.clearVisPropOld(copy);
    190
    191         er = this.board.renderer.enhancedRendering;
    192         this.board.renderer.enhancedRendering = true;
    193         this.board.renderer.drawPolygon(copy);
    194         this.board.renderer.enhancedRendering = er;
    195         this.traces[copy.id] = copy.rendNode;
    196
    197         return this;
    198     },
    199
    200     /**
    201      * Hide the polygon including its border lines. It will still exist but not visible on the board.
    202      */
    203     hideElement: function() {
    204         var i;
    205
    206         this.visProp.visible = false;
    207         this.board.renderer.hide(this);
    208
    209         for(i = 0; i < this.borders.length; i++) {
    210             this.borders[i].hideElement();
    211         }
    212
    213         if (this.hasLabel && JXG.exists(this.label)) {
    214             this.label.hiddenByParent = true;
    215             if(this.label.content.visProp.visible) {
    216                 this.board.renderer.hide(this.label.content);
    217             }
    218         }
    219     },
    220
    221     /**
    222      * Make the element visible.
    223      */
    224     showElement: function() {
    225         var i;
    226
    227         this.visProp.visible = true;
    228         this.board.renderer.show(this);
    229
    230         for(i = 0; i < this.borders.length; i++) {
    231             this.borders[i].showElement();
    232         }
    233
    234         if (this.hasLabel && JXG.exists(this.label)) {
    235             if(this.label.content.visProp.visible) {
    236                 this.board.renderer.show(this.label.content);
    237             }
    238         }
    239     },
    240
    241     /**
    242      * returns the area of the polygon
    243      */
    244     Area: function() {
    245         //Surveyor's Formula
    246         var area = 0, i;
    247
    248         for (i = 0; i < this.vertices.length - 1; i++) {
    249             area += (this.vertices[i].X()*this.vertices[i+1].Y()-this.vertices[i+1].X()*this.vertices[i].Y()); // last vertex is first vertex
    250         }
    251         area /= 2.0;
    252         return Math.abs(area);
    253     },
    254
    255     /**
    256      * This method removes the SVG or VML nodes of the lines and the filled area from the renderer, to remove
    257      * the object completely you should use {@link JXG.Board#removeObject}.
    258      */
    259     remove: function () {
    260         var i;
    261
    262         for (i = 0; i < this.borders.length; i++) {
    263             this.board.removeObject(this.borders[i]);
    264         }
    265         this.board.renderer.remove(this.rendNode);
    266     },
    267
    268     /**
    269      * Finds the index to a given point reference.
    270      * @param {JXG.Point} p Reference to an element of type {@link JXG.Point}
    271      */
    272     findPoint: function (p) {
    273         var i;
    274
    275         if (!JXG.isPoint(p)) {
    276             return -1;
    277         }
    278
    279         for (i = 0; i < this.vertices.length; i++) {
    280             if (this.vertices[i].id === p.id) {
    281                 return i;
    282             }
    283         }
    284
    285         return -1;
    286     },
    287
    288     /**
    289      * Add more points to the polygon. The new points will be inserted at the end.
    290      * @param {%} % Arbitrary number of points
    291      * @returns {JXG.Polygon} Reference to the polygon
    292      */
    293     addPoints: function () {
    294         var args = Array.prototype.slice.call(arguments);
    295
    296         return this.insertPoints.apply(this, [this.vertices.length-2].concat(args));
    297     },
    298
    299     /**
    300      * Adds more points to the vertex list of the polygon, starting with index <tt><i</tt>
    301      * @param {Number} i The position where the new vertices are inserted, starting with 0.
    302      * @param {%} % Arbitrary number of points to insert.
    303      * @returns {JXG.Polygon} Reference to the polygon object
    304      */
    305     insertPoints: function () {
    306         var idx, i, npoints = [], tmp;
    307
    308         if (arguments.length === 0) {
    309             return this;
    310         }
    311
    312         idx = arguments[0];
    313
    314         if (idx < 0 || idx > this.vertices.length-2) {
    315             return this;
    316         }
    317
    318         for (i = 1; i < arguments.length; i++) {
    319             if (JXG.isPoint(arguments[i])) {
    320                 npoints.push(arguments[i]);
    321             }
    322         }
    323
    324         tmp = this.vertices.slice(0, idx+1).concat(npoints);
    325         this.vertices = tmp.concat(this.vertices.slice(idx+1));
    326
    327         if (this.withLines) {
    328             tmp = this.borders.slice(0, idx);
    329             this.board.removeObject(this.borders[idx]);
    330
    331             for (i = 0; i < npoints.length; i++) {
    332                 tmp.push(JXG.createSegment(this.board, [this.vertices[idx+i], this.vertices[idx+i+1]], this.attr_line));
    333             }
    334             tmp.push(JXG.createSegment(this.board, [this.vertices[idx+npoints.length], this.vertices[idx+npoints.length+1]], this.attr_line));
    335
    336             this.borders = tmp.concat(this.borders.slice(idx));
    337         }
    338
    339         this.board.update();
    340
    341         return this;
    342     },
    343
    344     /**
    345      * Removes given set of vertices from the polygon
    346      * @param {%} % Arbitrary number of vertices as {@link JXG.Point} elements or index numbers
    347      * @returns {JXG.Polygon} Reference to the polygon
    348      */
    349     removePoints: function () {
    350         var i, j, idx, nvertices = [], nborders = [],
    351             nidx = [], partition = [];
    352
    353         // partition:
    354         // in order to keep the borders which could be recycled, we have to partition
    355         // the set of removed points. I.e. if the points 1, 2, 5, 6, 7, 10 are removed,
    356         // the partition is
    357         //       1-2, 5-7, 10-10
    358         // this gives us the borders, that can be removed and the borders we have to create.
    359
    360
    361         // remove the last vertex which is identical to the first
    362         this.vertices = this.vertices.slice(0, this.vertices.length-1);
    363
    364         // collect all valid parameters as indices in nidx
    365         for (i = 0; i < arguments.length; i++) {
    366             if (JXG.isPoint(arguments[i])) {
    367                 idx = this.findPoint(arguments[i]);
    368             }
    369
    370             if (JXG.isNumber(idx) && idx > -1 && idx < this.vertices.length && JXG.indexOf(nidx, idx) === -1) {
    371                 nidx.push(idx);
    372             }
    373         }
    374
    375         // sort the elements to be eliminated
    376         nidx = nidx.sort();
    377         nvertices = this.vertices.slice();
    378         nborders = this.borders.slice();
    379
    380         // initialize the partition
    381         if (this.withLines) {
    382             partition.push([nidx[nidx.length-1]]);
    383         }
    384
    385         // run through all existing vertices and copy all remaining ones to nvertices
    386         // compute the partition
    387         for (i = nidx.length-1; i > -1; i--) {
    388             nvertices[nidx[i]] = -1;
    389
    390             if (this.withLines && (nidx[i] - 1 > nidx[i-1])) {
    391                 partition[partition.length-1][1] = nidx[i];
    392                 partition.push([nidx[i-1]]);
    393             }
    394         }
    395
    396         // finalize the partition computation
    397         if (this.withLines) {
    398             partition[partition.length-1][1] = nidx[0];
    399         }
    400
    401         // update vertices
    402         this.vertices = [];
    403         for (i = 0; i < nvertices.length; i++) {
    404             if (JXG.isPoint(nvertices[i])) {
    405                 this.vertices.push(nvertices[i]);
    406             }
    407         }
    408         if (this.vertices[this.vertices.length-1].id !== this.vertices[0].id) {
    409             this.vertices.push(this.vertices[0]);
    410         }
    411
    412         // delete obsolete and create missing borders
    413         if (this.withLines) {
    414             for (i = 0; i < partition.length; i++) {
    415                 for (j = partition[i][1] - 1; j < partition[i][0] + 1; j++) {
    416                     // special cases
    417                     if (j < 0) {
    418                         // first vertex is removed, so the last border has to be removed, too
    419                         j = 0;
    420                         this.board.removeObject(this.borders[nborders.length-1]);
    421                         nborders[nborders.length-1] = -1;
    422                     } else if (j > nborders.length-1) {
    423                         j = nborders.length-1;
    424                     }
    425
    426                     this.board.removeObject(this.borders[j]);
    427                     nborders[j] = -1;
    428                 }
    429
    430                 // only create the new segment if it's not the closing border. the closing border is getting a special treatment at the end
    431                 // the if clause is newer than the min/max calls inside createSegment; i'm sure this makes the min/max calls obsolete, but
    432                 // just to be sure...
    433                 if (partition[i][1] !== 0 && partition[i][0] !== nvertices.length-1) {
    434                     nborders[partition[i][0] - 1] = JXG.createSegment(this.board, [nvertices[Math.max(partition[i][1]-1, 0)], nvertices[Math.min(partition[i][0]+1, this.vertices.length-1)]], this.attr_line);
    435                 }
    436             }
    437
    438             this.borders = [];
    439             for (i = 0; i < nborders.length; i++) {
    440                 if (nborders[i] !== -1) {
    441                     this.borders.push(nborders[i]);
    442                 }
    443             }
    444
    445             // if the first and/or the last vertex is removed, the closing border is created at the end.
    446             if (partition[0][1] === 5 || partition[partition.length-1][1] === 0) {
    447                 this.borders.push(JXG.createSegment(this.board, [this.vertices[0], this.vertices[this.vertices.length-2]], this.attr_line));
    448             }
    449         }
    450
    451         this.board.update();
    452
    453         return this;
    454     },
    455
    456     getParents: function () {
    457         var p = [], i;
    458
    459         for (i = 0; i < this.vertices.length; i++) {
    460             p.push(this.vertices[i].id);
    461         }
    462         return p;
    463     },
    464
    465     getAttributes: function () {
    466         var attr = JXG.GeometryElement.prototype.getAttributes.call(this), i;
    467
    468         if (this.withLines) {
    469             attr.lines = attr.lines || {};
    470             attr.lines.ids = [];
    471             attr.lines.colors = [];
    472
    473             for (i = 0; i < this.borders.length; i++) {
    474                 attr.lines.ids.push(this.borders[i].id);
    475                 attr.lines.colors.push(this.borders[i].visProp.strokecolor);
    476             }
    477         }
    478
    479         return attr;
    480     }
    481 });
    482
    483
    484 /**
    485  * @class A polygon is an area enclosed by a set of border lines which are determined by a list of points. Each two
    486  * consecutive points of the list define a line.
    487  * @pseudo
    488  * @constructor
    489  * @name Polygon
    490  * @type Polygon
    491  * @augments JXG.Polygon
    492  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
    493  * @param {Array} vertices The polygon's vertices. If the first and the last vertex don't match the first one will be
    494  * added to the array by the creator.
    495  * @example
    496  * var p1 = board.create('point', [0.0, 2.0]);
    497  * var p2 = board.create('point', [2.0, 1.0]);
    498  * var p3 = board.create('point', [4.0, 6.0]);
    499  * var p4 = board.create('point', [1.0, 3.0]);
    500  *
    501  * var pol = board.create('polygon', [p1, p2, p3, p4]);
    502  * </pre><div id="682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div>
    503  * <script type="text/javascript">
    504  *  (function () {
    505  *   var board = JXG.JSXGraph.initBoard('682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),
    506  *       p1 = board.create('point', [0.0, 2.0]),
    507  *       p2 = board.create('point', [2.0, 1.0]),
    508  *       p3 = board.create('point', [4.0, 6.0]),
    509  *       p4 = board.create('point', [1.0, 3.0]),
    510  *       cc1 = board.create('polygon', [p1, p2, p3, p4]);
    511  *  })();
    512  * </script><pre>
    513  */
    514 JXG.createPolygon = function(board, parents, attributes) {
    515     var el, i, attr = JXG.copyAttributes(attributes, board.options, 'polygon');
    516
    517     // Sind alles Punkte?
    518     for(i = 0; i < parents.length; i++) {
    519         parents[i] = JXG.getReference(board, parents[i]);
    520         if(!JXG.isPoint(parents[i]))
    521             throw new Error("JSXGraph: Can't create polygon with parent types other than 'point'.");
    522     }
    523
    524     el = new JXG.Polygon(board, parents, attr);
    525
    526     return el;
    527 };
    528
    529
    530 /**
    531  * @class Constructs a regular polygon. It needs two points which define the base line and the number of vertices.
    532  * @pseudo
    533  * @description Constructs a regular polygon. It needs two points which define the base line and the number of vertices, or a set of points.
    534  * @constructor
    535  * @name RegularPolygon
    536  * @type Polygon
    537  * @augments Polygon
    538  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
    539  * @param {JXG.Point_JXG.Point_Number} p1,p2,n The constructed regular polygon has n vertices and the base line defined by p1 and p2.
    540  * @example
    541  * var p1 = board.create('point', [0.0, 2.0]);
    542  * var p2 = board.create('point', [2.0, 1.0]);
    543  *
    544  * var pol = board.create('regularpolygon', [p1, p2, 5]);
    545  * </pre><div id="682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div>
    546  * <script type="text/javascript">
    547  *  (function () {
    548  *   var board = JXG.JSXGraph.initBoard('682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),
    549  *       p1 = board.create('point', [0.0, 2.0]),
    550  *       p2 = board.create('point', [2.0, 1.0]),
    551  *       cc1 = board.create('regularpolygon', [p1, p2, 5]);
    552  *  })();
    553  * </script><pre>
    554  * @example
    555  * var p1 = board.create('point', [0.0, 2.0]);
    556  * var p2 = board.create('point', [4.0,4.0]);
    557  * var p3 = board.create('point', [2.0,0.0]);
    558  *
    559  * var pol = board.create('regularpolygon', [p1, p2, p3]);
    560  * </pre><div id="096a78b3-bd50-4bac-b958-3be5e7df17ed" style="width: 400px; height: 400px;"></div>
    561  * <script type="text/javascript">
    562  * (function () {
    563  *   var board = JXG.JSXGraph.initBoard('096a78b3-bd50-4bac-b958-3be5e7df17ed', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),
    564  *       p1 = board.create('point', [0.0, 2.0]),
    565  *       p2 = board.create('point', [4.0, 4.0]),
    566  *       p3 = board.create('point', [2.0,0.0]),
    567  *       cc1 = board.create('regularpolygon', [p1, p2, p3]);
    568  * })();
    569  * </script><pre>
    570  */
    571 JXG.createRegularPolygon = function(board, parents, attributes) {
    572     var el, i, n, p = [], rot, c, len, pointsExist, attr;
    573
    574     if (JXG.isNumber(parents[parents.length-1]) && parents.length!=3) {
    575         throw new Error("JSXGraph: A regular polygon needs two points and a number as input.");
    576     }
    577
    578     len = parents.length;
    579     n = parents[len-1];
    580     if ((!JXG.isNumber(n) && !JXG.isPoint(JXG.getReference(board, n))) || n<3) {
    581         throw new Error("JSXGraph: The third parameter has to be number greater than 2 or a point.");
    582     }
    583
    584     if (JXG.isPoint(JXG.getReference(board, n))) {  // Regular polygon given by n points
    585         n = len;
    586         pointsExist = true;
    587     } else {
    588         len--;
    589         pointsExist = false;
    590     }
    591
    592     // The first two parent elements have to be points
    593     for(i=0; i<len; i++) {
    594         parents[i] = JXG.getReference(board, parents[i]);
    595         if(!JXG.isPoint(parents[i]))
    596             throw new Error("JSXGraph: Can't create regular polygon if the first two parameters aren't points.");
    597     }
    598
    599     p[0] = parents[0];
    600     p[1] = parents[1];
    601     attr = JXG.copyAttributes(attributes, board.options, 'polygon', 'vertices');
    602     for (i=2;i<n;i++) {
    603         rot = board.create('transform', [Math.PI*(2.0-(n-2)/n),p[i-1]], {type:'rotate'});
    604         if (pointsExist) {
    605             p[i] = parents[i];
    606             p[i].addTransform(parents[i-2],rot);
    607         } else {
    608             if (JXG.isArray(attr.ids) && attr.ids.length >= n-2) {
    609                 attr.id = attr.ids[i-2];
    610             }
    611             p[i] = board.create('point',[p[i-2],rot], attr);
    612 			p[i].type = JXG.OBJECT_TYPE_CAS;
    613         }
    614     }
    615     attr = JXG.copyAttributes(attributes, board.options, 'polygon');
    616     el = board.create('polygon', p, attr);
    617
    618     el.elType = 'regularpolygon';
    619
    620     return el;
    621 };
    622
    623 JXG.JSXGraph.registerElement('polygon', JXG.createPolygon);
    624 JXG.JSXGraph.registerElement('regularpolygon', JXG.createRegularPolygon);
    625