      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  * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together
     28  * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here
     29  * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the
     30  * following compositions can be found: <ul>
     31  *   <li>{@link Arrowparallel} (currently private)</li>
     32  *   <li>{@link Bisector}</li>
     33  *   <li>{@link Circumcircle}</li>
     34  *   <li>{@link Circumcirclemidpoint}</li>
     35  *   <li>{@link Integral}</li>
     36  *   <li>{@link Midpoint}</li>
     37  *   <li>{@link Mirrorpoint}</li>
     38  *   <li>{@link Normal}</li>
     39  *   <li>{@link Orthogonalprojection}</li>
     40  *   <li>{@link Parallel}</li>
     41  *   <li>{@link Perpendicular}</li>
     42  *   <li>{@link Perpendicularpoint}</li>
     43  *   <li>{@link Perpendicularsegment}</li>
     44  *   <li>{@link Reflection}</li></ul>
     45  */
     46
     47
     48 /**
     49  * A composition is a simple container that manages none or more {@link JXG.GeometryElement}s.
     50  * @param {Object} elements A list of elements with a descriptive name for the element as the key and a reference
     51  * to the element as the value of every list entry. The name is used to access the element later on.
     52  * @example
     53  * var p1 = board.create('point', [1, 2]),
     54  *     p2 = board.create('point', [2, 3]),
     55  *     c = new JXG.Composition({
     56  *         start: p1,
     57  *         end: p2
     58  *     });
     59  *
     60  * // moves p1 to [3, 3]
     61  * c.start.moveTo([3, 3]);
     62  * @class JXG.Composition
     63  */
     64 JXG.Composition = function (elements) {
     65     var genericMethods = [
     66             /**
     67              * Invokes setProperty for every stored element with a setProperty method and hands over the given arguments.
     68              * See {@link JXG.GeometryElement#setProperty} for further description, valid parameters and return values.
     69              * @name setProperty
     70              * @memberOf JXG.Composition.prototype
     71              * @function
     72              */
     73             'setProperty',
     74
     75             /**
     76              * Invokes prepareUpdate for every stored element with a prepareUpdate method and hands over the given arguments.
     77              * See {@link JXG.GeometryElement#prepareUpdate} for further description, valid parameters and return values.
     78              * @name prepareUpdate
     79              * @memberOf JXG.Composition.prototype
     80              * @function
     81              */
     82             'prepareUpdate',
     83
     84             /**
     85              * Invokes updateRenderer for every stored element with a updateRenderer method and hands over the given arguments.
     86              * See {@link JXG.GeometryElement#updateRenderer} for further description, valid parameters and return values.
     87              * @name updateRenderer
     88              * @memberOf JXG.Composition.prototype
     89              * @function
     90              */
     91             'updateRenderer',
     92
     93             /**
     94              * Invokes update for every stored element with a update method and hands over the given arguments.
     95              * See {@link JXG.GeometryElement#update} for further description, valid parameters and return values.
     96              * @name update
     97              * @memberOf JXG.Composition.prototype
     98              * @function
     99              */
    100             'update',
    101
    102             /**
    103              * Invokes highlight for every stored element with a highlight method and hands over the given arguments.
    104              * See {@link JXG.GeometryElement#highlight} for further description, valid parameters and return values.
    105              * @name highlight
    106              * @memberOf JXG.Composition.prototype
    107              * @function
    108              */
    109             'highlight',
    110
    111             /**
    112              * Invokes noHighlight for every stored element with a noHighlight method and hands over the given arguments.
    113              * See {@link JXG.GeometryElement#noHighlight} for further description, valid parameters and return values.
    114              * @name noHighlight
    115              * @memberOf JXG.Composition.prototype
    116              * @function
    117              */
    118             'noHighlight'
    119         ],
    120         generateMethod = function (what) {
    121             return function () {
    122                 var i;
    123
    124                 for (i in that.elements) {
    125                     if (JXG.exists(that.elements[i][what])) {
    126                         that.elements[i][what].apply(that.elements[i], arguments);
    127                     }
    128                 }
    129                 return that;
    130             };
    131         },
    132         that = this,
    133         e;
    134
    135     for (e = 0; e < genericMethods.length; e++) {
    136         this[genericMethods[e]] = generateMethod(genericMethods[e]);
    137     }
    138
    139     this.elements = {};
    140     for (e in elements) {
    141         if (elements.hasOwnProperty(e)) {
    142             this.add(e, elements[e]);
    143         }
    144     }
    145
    146     this.dump = true;
    147     this.subs = {};
    148 };
    149
    150 JXG.extend(JXG.Composition.prototype, /** @lends JXG.Composition.prototype */ {
    151
    152     /**
    153      * Adds an element to the composition container.
    154      * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to
    155      * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate,
    156      * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in
    157      * JavaScript.
    158      * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be
    159      * another composition, too.
    160      * @returns {Boolean} True, if the element was added successfully. Reasons why adding the element failed include
    161      * using a reserved name and providing an invalid element.
    162      */
    163     add: function (what, element) {
    164         if (!JXG.exists(this[what]) && JXG.exists(element)) {
    165             if (JXG.exists(element.id)) {
    166                 this.elements[element.id] = element;
    167             } else {
    168                 this.elements[what] = element;
    169             }
    170             this[what] = element;
    171
    172             return true
    173         }
    174
    175         return false;
    176     },
    177
    178     /**
    179      * Remove an element from the composition container.
    180      * @param {String} what The name used to access the element.
    181      * @returns {Boolean} True, if the element has been removed successfully.
    182      */
    183     remove: function (what) {
    184         var found = false,
    185             e;
    186
    187         for (e in this.elements) {
    188             if (this.elements[e].id === this[what].id) {
    189                 found = true;
    190                 break;
    191             }
    192         }
    193
    194         if (found) {
    195             delete this.elements[this[what].id];
    196             delete this[what];
    197         }
    198
    199         return found;
    200     },
    201
    202     getParents: function () {
    203         return this.parents;
    204     },
    205
    206     getType: function () {
    207         return this.elType;
    208     },
    209
    210     getAttributes: function () {
    211         var attr = {},
    212             e;
    213
    214         for (e in this.subs) {
    215             attr[e] = this.subs[e].visProp;
    216         }
    217
    218         return this.attr;
    219     }
    220 });
    221
    222 /**
    223  * @class This is used to construct a point that is the orthogonal projection of a point to a line.
    224  * @pseudo
    225  * @description An orthogonal projection is given by a point and a line. It is determined by projecting the given point
    226  * orthogonal onto the given line.
    227  * @constructor
    228  * @name Orthogonalprojection
    229  * @type JXG.Point
    230  * @augments JXG.Point
    231  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    232  * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
    233  * @example
    234  * var p1 = board.create('point', [0.0, 4.0]);
    235  * var p2 = board.create('point', [6.0, 1.0]);
    236  * var l1 = board.create('line', [p1, p2]);
    237  * var p3 = board.create('point', [3.0, 3.0]);
    238  *
    239  * var pp1 = board.create('orthogonalprojection', [p3, l1]);
    240  * </pre><div id="7708b215-39fa-41b6-b972-19d73d77d791" style="width: 400px; height: 400px;"></div>
    241  * <script type="text/javascript">
    242  *   var ppex1_board = JXG.JSXGraph.initBoard('7708b215-39fa-41b6-b972-19d73d77d791', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    243  *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
    244  *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
    245  *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
    246  *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
    247  *   var ppex1_pp1 = ppex1_board.create('orthogonalprojection', [ppex1_p3, ppex1_l1]);
    248  * </script><pre>
    249  */
    250 JXG.createOrthogonalProjection = function(board, parents, attributes) {
    251     var l, p, t, atts;
    252
    253     if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
    254         p = parents[0];
    255         l = parents[1];
    256     }
    257     else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
    258         p = parents[1];
    259         l = parents[0];
    260     }
    261     else {
    262         throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
    263                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    264                         "\nPossible parent types: [point,line]");
    265     }
    266
    267     attr = JXG.copyAttributes(attributes, board.options, 'orthogonalprojection');
    268     t = board.create('point', [function () { return JXG.Math.Geometry.projectPointToLine(p, l, board); }], attributes);
    269     //t.type = JXG.OBJECT_TYPE_OPROJECT;
    270     p.addChild(t);
    271     l.addChild(t);
    272
    273     t.elType = 'orthogonalprojection';
    274     t.parents = [p.id, t.id];
    275
    276     t.update();
    277
    278     t.generatePolynomial = function() {
    279         /*
    280          *  Perpendicular takes point P and line L and creates point T and line M:
    281          *
    282          *                          | M
    283          *                          |
    284          *                          x P (p1,p2)
    285          *                          |
    286          *                          |
    287          *  L                       |
    288          *  ----------x-------------x------------------------x--------
    289          *            A (a1,a2)     |T (t1,t2)               B (b1,b2)
    290          *                          |
    291          *                          |
    292          *
    293          * So we have two conditions:
    294          *
    295          *   (a)  AT  || TB          (collinearity condition)
    296          *   (b)  PT _|_ AB          (orthogonality condition)
    297          *
    298          *      a2-t2       t2-b2
    299          *     -------  =  -------           (1)
    300          *      a1-t1       t1-b1
    301          *
    302          *      p2-t2         a1-b1
    303          *     -------  =  - -------         (2)
    304          *      p1-t1         a2-b2
    305          *
    306          * Multiplying (1) and (2) with denominators and simplifying gives
    307          *
    308          *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                  (1')
    309          *
    310          *    p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0    (2')
    311          *
    312          */
    313
    314         var a1 = l.point1.symbolic.x;
    315         var a2 = l.point1.symbolic.y;
    316         var b1 = l.point2.symbolic.x;
    317         var b2 = l.point2.symbolic.y;
    318
    319         var p1 = p.symbolic.x;
    320         var p2 = p.symbolic.y;
    321         var t1 = t.symbolic.x;
    322         var t2 = t.symbolic.y;
    323
    324         var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
    325         var poly2 = '('+p2+')*('+a2+')-('+p2+')*('+b2+')-('+t2+')*('+a2+')+('+t2+')*('+b2+')+('+p1+')*('+a1+')-('+p1+')*('+b1+')-('+t1+')*('+a1+')+('+t1+')*('+b1+')';
    326
    327         return [poly1, poly2];
    328     };
    329
    330     return t;
    331 };
    332
    333
    334 /**
    335
    336  * @class This element is used to provide a constructor for a perpendicular.
    337  * @pseudo
    338  * @description  A perpendicular is a composition of two elements: a line and a point. The line is orthogonal
    339  * to a given line and contains a given point.
    340  * @name Perpendicular
    341  * @constructor
    342  * @type JXG.Line
    343  * @augments Segment
    344  * @return A {@link JXG.Line} object through the given point that is orthogonal to the given line.
    345  * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.
    346  * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and
    347  * will contain p.
    348  * @example
    349  * // Create a perpendicular
    350  * var p1 = board.create('point', [0.0, 2.0]);
    351  * var p2 = board.create('point', [2.0, 1.0]);
    352  * var l1 = board.create('line', [p1, p2]);
    353  *
    354  * var p3 = board.create('point', [3.0, 3.0]);
    355  * var perp1 = board.create('perpendicular', [l1, p3]);
    356  * </pre><div id="d5b78842-7b27-4d37-b608-d02519e6cd03" style="width: 400px; height: 400px;"></div>
    357  * <script type="text/javascript">
    358  *   var pex1_board = JXG.JSXGraph.initBoard('d5b78842-7b27-4d37-b608-d02519e6cd03', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    359  *   var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);
    360  *   var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);
    361  *   var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);
    362  *   var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);
    363  *   var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]);
    364  * </script><pre>
    365  */
    366 JXG.createPerpendicular = function(board, parents, attributes) {
    367     var p, l, pd, attr;
    368
    369     parents[0] = JXG.getReference(board, parents[0]);
    370     parents[1] = JXG.getReference(board, parents[1]);
    371
    372     if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
    373         l = parents[1];
    374         p = parents[0];
    375     }
    376     else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
    377         l = parents[0];
    378         p = parents[1];
    379     } else {
    380         throw new Error("JSXGraph: Can't create perpendicular with parent types '" +
    381                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    382                         "\nPossible parent types: [line,point]");
    383     }
    384
    385     attr = JXG.copyAttributes(attributes, board.options, 'perpendicular');
    386     pd = JXG.createLine(board, [
    387                     function(){ return  l.stdform[2]*p.X()-l.stdform[1]*p.Y();},
    388                     function(){ return -l.stdform[2]*p.Z();},
    389                     function(){ return  l.stdform[1]*p.Z();}
    390                 ],
    391                 attr);
    392
    393     pd.elType = 'perpendicular';
    394     pd.parents = [l.id, p.id];
    395
    396     return pd;
    397 };
    398
    399 /**
    400  * @class This is used to construct a perpendicular point.
    401  * @pseudo
    402  * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point
    403  * orthogonal onto the given line. This used in GEONExTReader only. All other applications should use
    404  * orthogonal projection.
    405  * @constructor
    406  * @name Perpendicularpoint
    407  * @type JXG.Point
    408  * @augments JXG.Point
    409  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    410  * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
    411  * @example
    412  * var p1 = board.create('point', [0.0, 4.0]);
    413  * var p2 = board.create('point', [6.0, 1.0]);
    414  * var l1 = board.create('line', [p1, p2]);
    415  * var p3 = board.create('point', [3.0, 3.0]);
    416  *
    417  * var pp1 = board.create('perpendicularpoint', [p3, l1]);
    418  * </pre><div id="ded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div>
    419  * <script type="text/javascript">
    420  *   var ppex1_board = JXG.JSXGraph.initBoard('ded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    421  *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
    422  *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
    423  *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
    424  *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
    425  *   var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]);
    426  * </script><pre>
    427  */
    428 JXG.createPerpendicularPoint = function(board, parents, attributes) {
    429     var l, p, t;
    430
    431     if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
    432         p = parents[0];
    433         l = parents[1];
    434     }
    435     else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
    436         p = parents[1];
    437         l = parents[0];
    438     }
    439     else {
    440         throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
    441                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    442                         "\nPossible parent types: [point,line]");
    443     }
    444
    445     t = board.create('point', [function () { return JXG.Math.Geometry.perpendicular(l, p, board)[0]; }], attributes);
    446     p.addChild(t);
    447     l.addChild(t);
    448
    449     t.elType = 'perpendicularpoint';
    450     t.parents = [p.id, l.id];
    451
    452     t.update();
    453
    454     t.generatePolynomial = function() {
    455         /*
    456          *  Perpendicular takes point P and line L and creates point T and line M:
    457          *
    458          *                          | M
    459          *                          |
    460          *                          x P (p1,p2)
    461          *                          |
    462          *                          |
    463          *  L                       |
    464          *  ----------x-------------x------------------------x--------
    465          *            A (a1,a2)     |T (t1,t2)               B (b1,b2)
    466          *                          |
    467          *                          |
    468          *
    469          * So we have two conditions:
    470          *
    471          *   (a)  AT  || TB          (collinearity condition)
    472          *   (b)  PT _|_ AB          (orthogonality condition)
    473          *
    474          *      a2-t2       t2-b2
    475          *     -------  =  -------           (1)
    476          *      a1-t1       t1-b1
    477          *
    478          *      p2-t2         a1-b1
    479          *     -------  =  - -------         (2)
    480          *      p1-t1         a2-b2
    481          *
    482          * Multiplying (1) and (2) with denominators and simplifying gives
    483          *
    484          *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                  (1')
    485          *
    486          *    p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0    (2')
    487          *
    488          */
    489
    490         var a1 = l.point1.symbolic.x;
    491         var a2 = l.point1.symbolic.y;
    492         var b1 = l.point2.symbolic.x;
    493         var b2 = l.point2.symbolic.y;
    494         var p1 = p.symbolic.x;
    495         var p2 = p.symbolic.y;
    496         var t1 = t.symbolic.x;
    497         var t2 = t.symbolic.y;
    498
    499         var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
    500         var poly2 = '('+p2+')*('+a2+')-('+p2+')*('+b2+')-('+t2+')*('+a2+')+('+t2+')*('+b2+')+('+p1+')*('+a1+')-('+p1+')*('+b1+')-('+t1+')*('+a1+')+('+t1+')*('+b1+')';
    501
    502         return [poly1, poly2];
    503     };
    504
    505     return t;
    506 };
    507
    508
    509 /**
    510  * @class This element is used to provide a constructor for a perpendicular segment.
    511  * @pseudo
    512  * @description  A perpendicular is a composition of two elements: a line segment and a point. The line segment is orthogonal
    513  * to a given line and contains a given point and meets the given line in the perpendicular point.
    514  * @name Perpendicular
    515  * @constructor
    516  * @type JXG.Line
    517  * @augments Segment
    518  * @return An array containing two elements: A {@link JXG.Line} object in the first component and a
    519  * {@link JXG.Point} element in the second component. The line segment is orthogonal to the given line and meets it
    520  * in the returned point.
    521  * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.
    522  * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and
    523  * will contain p. The perpendicular point is the intersection point of the two lines.
    524  * @example
    525  * // Create a perpendicular
    526  * var p1 = board.create('point', [0.0, 2.0]);
    527  * var p2 = board.create('point', [2.0, 1.0]);
    528  * var l1 = board.create('line', [p1, p2]);
    529  *
    530  * var p3 = board.create('point', [3.0, 3.0]);
    531  * var perp1 = board.create('perpendicularsegment', [l1, p3]);
    532  * </pre><div id="037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div>
    533  * <script type="text/javascript">
    534  *   var pex1_board = JXG.JSXGraph.initBoard('037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    535  *   var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);
    536  *   var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);
    537  *   var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);
    538  *   var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);
    539  *   var pex1_perp1 = pex1_board.create('perpendicularsegment', [pex1_l1, pex1_p3]);
    540  * </script><pre>
    541  */
    542 JXG.createPerpendicularSegment = function(board, parents, attributes) {
    543     var p, l, pd, t, attr;
    544
    545     parents[0] = JXG.getReference(board, parents[0]);
    546     parents[1] = JXG.getReference(board, parents[1]);
    547
    548     if(JXG.isPoint(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
    549         l = parents[1];
    550         p = parents[0];
    551     }
    552     else if(JXG.isPoint(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
    553         l = parents[0];
    554         p = parents[1];
    555     } else {
    556         throw new Error("JSXGraph: Can't create perpendicular with parent types '" +
    557                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    558                         "\nPossible parent types: [line,point]");
    559     }
    560     attr = JXG.copyAttributes(attributes, board.options, 'perpendicularsegment', 'point');
    561     t = JXG.createPerpendicularPoint(board, [l, p], attr);
    562
    563     t.dump = false;
    564
    565     if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
    566     attr = JXG.copyAttributes(attributes, board.options, 'perpendicularsegment');
    567     pd = JXG.createLine(board, [function () { return (JXG.Math.Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]); }], attr);
    568
    569     /**
    570      * Helper point
    571      * @memberOf PerpendicularSegment.prototype
    572      * @type PerpendicularPoint
    573      * @name point
    574      */
    575     pd.point = t;
    576
    577     pd.elType = 'perpendicularsegment';
    578     pd.parents = [p.id, l.id];
    579     pd.subs = {
    580         point: t
    581     };
    582
    583     return pd;
    584 };
    585
    586 /**
    587  * @class The midpoint element constructs a point in the middle of two given points.
    588  * @pseudo
    589  * @description A midpoint is given by two points. It is collinear to the given points and the distance
    590  * is the same to each of the given points, i.e. it is in the middle of the given points.
    591  * @constructor
    592  * @name Midpoint
    593  * @type JXG.Point
    594  * @augments JXG.Point
    595  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    596  * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2.
    597  * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of
    598  * the given line l.
    599  * @example
    600  * // Create base elements: 2 points and 1 line
    601  * var p1 = board.create('point', [0.0, 2.0]);
    602  * var p2 = board.create('point', [2.0, 1.0]);
    603  * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
    604  *
    605  * var mp1 = board.create('midpoint', [p1, p2]);
    606  * var mp2 = board.create('midpoint', [l1]);
    607  * </pre><div id="7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div>
    608  * <script type="text/javascript">
    609  *   var mpex1_board = JXG.JSXGraph.initBoard('7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    610  *   var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]);
    611  *   var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]);
    612  *   var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
    613  *   var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]);
    614  *   var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]);
    615  * </script><pre>
    616  */
    617 JXG.createMidpoint = function(board, parents, attributes) {
    618     var a, b, t;
    619
    620     if(parents.length == 2 && JXG.isPoint(parents[0]) && JXG.isPoint(parents[1])) {
    621         a = parents[0];
    622         b = parents[1];
    623     }
    624     else if(parents.length == 1 && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
    625         a = parents[0].point1;
    626         b = parents[0].point2;
    627     }
    628     else {
    629         throw new Error("JSXGraph: Can't create midpoint." +
    630                         "\nPossible parent types: [point,point], [line]");
    631     }
    632
    633     t = board.create('point', [
    634                                function () {
    635                                 var x = a.coords.usrCoords[1] + b.coords.usrCoords[1];
    636                                 if (isNaN(x) || Math.abs(a.coords.usrCoords[0])<JXG.Math.eps || Math.abs(b.coords.usrCoords[0])<JXG.Math.eps) {
    637                                     return NaN;
    638                                 } else {
    639                                     return x*0.5;
    640                                 }
    641                                },
    642                                function () {
    643                                 var y = a.coords.usrCoords[2] + b.coords.usrCoords[2];
    644                                 if (isNaN(y) || Math.abs(a.coords.usrCoords[0])<JXG.Math.eps || Math.abs(b.coords.usrCoords[0])<JXG.Math.eps) {
    645                                     return NaN;
    646                                 } else {
    647                                     return y*0.5;
    648                                 }
    649                               }], attributes);
    650     a.addChild(t);
    651     b.addChild(t);
    652
    653     t.elType = 'midpoint';
    654     t.parents = [a.id, b.id];
    655
    656     t.prepareUpdate().update();
    657
    658     t.generatePolynomial = function() {
    659         /*
    660          *  Midpoint takes two point A and B or line L (with points P and Q) and creates point T:
    661          *
    662          *  L (not necessarily)
    663          *  ----------x------------------x------------------x--------
    664          *            A (a1,a2)          T (t1,t2)          B (b1,b2)
    665          *
    666          * So we have two conditions:
    667          *
    668          *   (a)   AT  ||  TB           (collinearity condition)
    669          *   (b)  [AT] == [TB]          (equidistant condition)
    670          *
    671          *      a2-t2       t2-b2
    672          *     -------  =  -------                                         (1)
    673          *      a1-t1       t1-b1
    674          *
    675          *     (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2       (2)
    676          *
    677          *
    678          * Multiplying (1) with denominators and simplifying (1) and (2) gives
    679          *
    680          *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                      (1')
    681          *
    682          *    a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0    (2')
    683          *
    684          */
    685
    686         var a1 = a.symbolic.x;
    687         var a2 = a.symbolic.y;
    688         var b1 = b.symbolic.x;
    689         var b2 = b.symbolic.y;
    690         var t1 = t.symbolic.x;
    691         var t2 = t.symbolic.y;
    692
    693         var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
    694         var poly2 = '('+a1+')^2 - 2*('+a1+')*('+t1+')+('+a2+')^2-2*('+a2+')*('+t2+')-('+b1+')^2+2*('+b1+')*('+t1+')-('+b2+')^2+2*('+b2+')*('+t2+')';
    695
    696         return [poly1, poly2];
    697     };
    698
    699     return t;
    700 };
    701
    702 /**
    703  * @class This element is used to construct a parallel point.
    704  * @pseudo
    705  * @description A parallel point is given by three points. Taking the euclidean vector from the first to the
    706  * second point, the parallel point is determined by adding that vector to the third point.
    707  * The line determined by the first two points is parallel to the line determined by the third point and the constructed point.
    708  * @constructor
    709  * @name Parallelpoint
    710  * @type JXG.Point
    711  * @augments JXG.Point
    712  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    713  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 Taking the euclidean vector <tt>v=p2-p1</tt> the parallel point is determined by
    714  * <tt>p4 = p3+v</tt>
    715  * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l.
    716  * @example
    717  * var p1 = board.create('point', [0.0, 2.0]);
    718  * var p2 = board.create('point', [2.0, 1.0]);
    719  * var p3 = board.create('point', [3.0, 3.0]);
    720  *
    721  * var pp1 = board.create('parallelpoint', [p1, p2, p3]);
    722  * </pre><div id="488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div>
    723  * <script type="text/javascript">
    724  *   var ppex1_board = JXG.JSXGraph.initBoard('488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    725  *   var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]);
    726  *   var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]);
    727  *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
    728  *   var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]);
    729  * </script><pre>
    730  */
    731 JXG.createParallelPoint = function(board, parents, attributes) {
    732     var a, b, c, p;
    733
    734     if(parents.length == 3 && parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) {
    735         a = parents[0];
    736         b = parents[1];
    737         c = parents[2];
    738     } else if (parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
    739         c = parents[0];
    740         a = parents[1].point1;
    741         b = parents[1].point2;
    742     } else if (parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
    743         c = parents[1];
    744         a = parents[0].point1;
    745         b = parents[0].point2;
    746     }
    747     else {
    748         throw new Error("JSXGraph: Can't create parallel point with parent types '" +
    749                         (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    750                         "\nPossible parent types: [line,point], [point,point,point]");
    751     }
    752
    753     p = board.create('point', [function () { return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1]; },
    754                                function () { return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2]; }],
    755                                attributes);
    756 	// required for algorithms requiring dependencies between elements
    757 	a.addChild(p);
    758 	b.addChild(p);
    759     c.addChild(p);
    760
    761     p.elType = 'parallelpoint';
    762     p.parents = [a.id, b.id, c.id];
    763
    764     // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update.
    765     // can be removed if the above issue is resolved.
    766     p.prepareUpdate().update();
    767
    768     p.generatePolynomial = function() {
    769         /*
    770          *  Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T:
    771          *
    772          *
    773          *                     C (c1,c2)                             T (t1,t2)
    774          *                      x                                     x
    775          *                     /                                     /
    776          *                    /                                     /
    777          *                   /                                     /
    778          *                  /                                     /
    779          *                 /                                     /
    780          *                /                                     /
    781          *               /                                     /
    782          *              /                                     /
    783          *  L (opt)    /                                     /
    784          *  ----------x-------------------------------------x--------
    785          *            A (a1,a2)                             B (b1,b2)
    786          *
    787          * So we have two conditions:
    788          *
    789          *   (a)   CT  ||  AB           (collinearity condition I)
    790          *   (b)   BT  ||  AC           (collinearity condition II)
    791          *
    792          * The corresponding equations are
    793          *
    794          *    (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0         (1)
    795          *    (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0         (2)
    796          *
    797          * Simplifying (1) and (2) gives
    798          *
    799          *    b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0      (1')
    800          *    t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0      (2')
    801          *
    802          */
    803
    804         var a1 = a.symbolic.x;
    805         var a2 = a.symbolic.y;
    806         var b1 = b.symbolic.x;
    807         var b2 = b.symbolic.y;
    808         var c1 = c.symbolic.x;
    809         var c2 = c.symbolic.y;
    810         var t1 = p.symbolic.x;
    811         var t2 = p.symbolic.y;
    812
    813         var poly1 =  '('+b2+')*('+t1+')-('+b2+')*('+c1+')-('+a2+')*('+t1+')+('+a2+')*('+c1+')-('+t2+')*('+b1+')+('+t2+')*('+a1+')+('+c2+')*('+b1+')-('+c2+')*('+a1+')';
    814         var poly2 =  '('+t2+')*('+a1+')-('+t2+')*('+c1+')-('+b2+')*('+a1+')+('+b2+')*('+c1+')-('+t1+')*('+a2+')+('+t1+')*('+c2+')+('+b1+')*('+a2+')-('+b1+')*('+c2+')';
    815
    816         return [poly1, poly2];
    817     };
    818
    819     return p;
    820 };
    821
    822
    823 /**
    824  * @class A parallel is a line through a given point with the same slope as a given line.
    825  * @pseudo
    826  * @name Parallel
    827  * @augments Line
    828  * @constructor
    829  * @type JXG.Line
    830  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    831  * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l.
    832  * @example
    833  * // Create a parallel
    834  * var p1 = board.create('point', [0.0, 2.0]);
    835  * var p2 = board.create('point', [2.0, 1.0]);
    836  * var l1 = board.create('line', [p1, p2]);
    837  *
    838  * var p3 = board.create('point', [3.0, 3.0]);
    839  * var pl1 = board.create('parallel', [l1, p3]);
    840  * </pre><div id="24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div>
    841  * <script type="text/javascript">
    842  *   var plex1_board = JXG.JSXGraph.initBoard('24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    843  *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
    844  *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
    845  *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
    846  *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
    847  *   var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);
    848  * </script><pre>
    849  */
    850 JXG.createParallel = function(board, parents, attributes) {
    851     var p, pp, pl, li, attr;
    852
    853     /* parallel point polynomials are done in createParallelPoint */
    854     /*
    855     try {
    856         attr = JXG.copyAttributes(attributes, board.options, 'parallel', 'point');
    857         pp = JXG.createParallelPoint(board, parents, attr);     // non-visible point
    858     } catch (e) {
    859         throw new Error("JSXGraph: Can't create parallel with parent types '" +
    860                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    861                         "\nPossible parent types: [line,point], [point,point,point]");
    862     }
    863     */
    864
    865     p = null;
    866     if(parents.length == 3) {
    867         // line through point parents[2] which is parallel to line through parents[0] and parents[1]
    868         p = parents[2];
    869         li = function() { return JXG.Math.crossProduct(parents[0].coords.usrCoords, parents[1].coords.usrCoords); };
    870
    871         //pp = [parents[0].id, parents[1].id, p.id];
    872     } else if (parents[0].elementClass == JXG.OBJECT_CLASS_POINT) {
    873         // Parallel to line parents[1] through point parents[0]
    874         p = parents[0];
    875         li = function() { return parents[1].stdform; };
    876         //pp = [parents[1].id, p.id];
    877     } else if (parents[1].elementClass == JXG.OBJECT_CLASS_POINT) {
    878         // Parallel to line parents[0] through point parents[1]
    879         p = parents[1];
    880         li = function() { return parents[0].stdform; };
    881         //pp = [parents[0].id, p.id];
    882     }
    883
    884     if (!JXG.exists(attributes.layer)) {
    885         attributes.layer = board.options.layer.line;
    886     }
    887
    888     attr = JXG.copyAttributes(attributes, board.options, 'parallel', 'point');
    889 	pp = board.create('point', [function() {
    890             return JXG.Math.crossProduct([1,0,0], li());
    891         }], attr);
    892
    893     pp.isDraggable = true;
    894
    895     attr = JXG.copyAttributes(attributes, board.options, 'parallel');
    896     pl = board.create('line', [p, pp], attr);
    897     /*
    898     pl = board.create('line', [function() {
    899             var l = li();
    900             return [ -(p.X()*l[1]+p.Y()*l[2]), p.Z()*l[1], p.Z()*l[2]];
    901         }], attr);
    902     */
    903
    904     pl.elType = 'parallel';
    905     pl.parents = [parents[0].id, parents[1].id];
    906     if (parents.length === 3) {
    907         pl.parents.push(parents[2].id);
    908     }
    909
    910     /**
    911      * Helper point used to create the parallel line. This point lies on the line at infinity, hence it's not visible,
    912      * not even with visible set to <tt>true</tt>. Creating another line through this point would make that other line
    913      * parallel to the create parallel.
    914      * @memberOf Parallel.prototype
    915      * @name point
    916      * @type JXG.Point
    917      */
    918     pl.point = pp;
    919
    920     return pl;
    921 };
    922
    923 /**
    924  * @class An arrow parallel is a parallel segment with an arrow attached.
    925  * @pseudo
    926  * @constructor
    927  * @name Arrowparallel
    928  * @type Parallel
    929  * @augments Parallel
    930  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    931  * @param {JXG.Line_JXG.Point} l,p The constructed arrow contains p and has the same slope as l.
    932  * @example
    933  * // Create a parallel
    934  * var p1 = board.create('point', [0.0, 2.0]);
    935  * var p2 = board.create('point', [2.0, 1.0]);
    936  * var l1 = board.create('line', [p1, p2]);
    937  *
    938  * var p3 = board.create('point', [3.0, 3.0]);
    939  * var pl1 = board.create('arrowparallel', [l1, p3]);
    940  * </pre><div id="eeacdf99-036f-4e83-aeb6-f7388423e369" style="width: 400px; height: 400px;"></div>
    941  * <script type="text/javascript">
    942  * (function () {
    943  *   var plex1_board = JXG.JSXGraph.initBoard('eeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    944  *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
    945  *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
    946  *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
    947  *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
    948  *   var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_l1, plex1_p3]);
    949  * })();
    950  * </script><pre>
    951  */
    952 JXG.createArrowParallel = function(board, parents, attributes) {
    953     var p;
    954
    955     /* parallel arrow point polynomials are done in createParallelPoint */
    956     try {
    957         p = JXG.createParallel(board, parents, attributes).setStraight(false, false).setArrow(false,true);
    958         p.elType = 'arrowparallel';
    959
    960         // parents are set in createParallel
    961
    962         return p;
    963     } catch (e) {
    964         throw new Error("JSXGraph: Can't create arrowparallel with parent types '" +
    965                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    966                         "\nPossible parent types: [line,point], [point,point,point]");
    967     }
    968 };
    969
    970 /**
    971  * @class Constructs a normal.
    972  * @pseudo
    973  * @description A normal is a line through a given point on a element of type line, circle, curve, or turtle and orthogonal to that object.
    974  * @constructor
    975  * @name Normal
    976  * @type JXG.Line
    977  * @augments JXG.Line
    978  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    979  * @param {JXG.Line,JXG.Circle,JXG.Curve,JXG.Turtle_JXG.Point} o,p The constructed line contains p which lies on the object and is orthogonal
    980  * to the tangent to the object in the given point.
    981  * @param {Glider} p Works like above, however the object is given by {@link Glider#slideObject}.
    982  * @example
    983  * // Create a normal to a circle.
    984  * var p1 = board.create('point', [2.0, 2.0]);
    985  * var p2 = board.create('point', [3.0, 2.0]);
    986  * var c1 = board.create('circle', [p1, p2]);
    987  *
    988  * var norm1 = board.create('normal', [c1, p2]);
    989  * </pre><div id="4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div>
    990  * <script type="text/javascript">
    991  *   var nlex1_board = JXG.JSXGraph.initBoard('4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    992  *   var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]);
    993  *   var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]);
    994  *   var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]);
    995  *
    996  *   // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]);
    997  *   var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]);
    998  * </script><pre>
    999  */
    1000 JXG.createNormal = function(board, parents, attributes) {
    1001     /* TODO normal polynomials */
    1002     var p, c, l, i, attr, pp, attrp;
    1003
    1004     if (parents.length==1) { // One arguments: glider on line, circle or curve
    1005         p = parents[0];
    1006         c = p.slideObject;
    1007     } else if (parents.length==2) { // Two arguments: (point,line), (point,circle), (line,point) or (circle,point)
    1008         if (JXG.isPoint(parents[0])) {
    1009             p = parents[0];
    1010             c = parents[1];
    1011         } else if (JXG.isPoint(parents[1])) {
    1012             c = parents[0];
    1013             p = parents[1];
    1014         } else {
    1015             throw new Error("JSXGraph: Can't create normal with parent types '" +
    1016                             (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1017                             "\nPossible parent types: [point,line], [point,circle], [glider]");
    1018         }
    1019     } else {
    1020         throw new Error("JSXGraph: Can't create normal with parent types '" +
    1021                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1022                         "\nPossible parent types: [point,line], [point,circle], [glider]");
    1023     }
    1024
    1025     attr = JXG.copyAttributes(attributes, board.options, 'normal');
    1026     if(c.elementClass==JXG.OBJECT_CLASS_LINE) {
    1027         // Homogeneous version:
    1028         // orthogonal(l,p) = (F^\delta\cdot l)\times p
    1029         /*
    1030         l = board.create('line', [
    1031                     function(){ return c.stdform[1]*p.Y()-c.stdform[2]*p.X();},
    1032                     function(){ return c.stdform[2]*p.Z();},
    1033                     function(){ return -c.stdform[1]*p.Z();}
    1034                     ], attributes );
    1035         */
    1036         // Private point
    1037         attrp = JXG.copyAttributes(attributes, board.options, 'normal', 'point');
    1038         pp = board.create('point', [function() {
    1039                 var p = JXG.Math.crossProduct([1,0,0], c.stdform);
    1040                 return [p[0], -p[2], p[1]];
    1041             }], attrp);
    1042         pp.isDraggable = true;
    1043
    1044         l = board.create('line', [p, pp], attr);
    1045
    1046         /**
    1047          * A helper point used to create a normal to a {@link JXG.Line} object. For normals to circles or curves this
    1048          * element is <tt>undefined</tt>.
    1049          * @type JXG.Point
    1050          * @name point
    1051          * @memberOf Normal.prototype
    1052          */
    1053         l.point = pp;
    1054     } else if(c.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
    1055         l = board.create('line', [c.midpoint,p], attr);
    1056     } else if (c.elementClass == JXG.OBJECT_CLASS_CURVE) {
    1057         if (c.visProp.curvetype!='plot') {
    1058             var g = c.X;
    1059             var f = c.Y;
    1060             l = board.create('line', [
    1061                     function(){ return -p.X()*board.D(g)(p.position)-p.Y()*board.D(f)(p.position);},
    1062                     function(){ return board.D(g)(p.position);},
    1063                     function(){ return board.D(f)(p.position);}
    1064                     ], attr);
    1065         } else {                         // curveType 'plot'
    1066             l = board.create('line', [
    1067                     function(){ var i=Math.floor(p.position);
    1068                                 var lbda = p.position-i;
    1069                                 if (i==c.numberPoints-1) {i--; lbda=1; }
    1070                                 if (i<0) return 1.0;
    1071                                 return (c.Y(i)+lbda*(c.Y(i+1)-c.Y(i)))*(c.Y(i)-c.Y(i+1))-(c.X(i)+lbda*(c.X(i+1)-c.X(i)))*(c.X(i+1)-c.X(i));},
    1072                     function(){ var i=Math.floor(p.position);
    1073                                 if (i==c.numberPoints-1) i--;
    1074                                 if (i<0) return 0.0;
    1075                                 return c.X(i+1)-c.X(i);},
    1076                     function(){ var i=Math.floor(p.position);
    1077                                 if (i==c.numberPoints-1) i--;
    1078                                 if (i<0) return 0.0;
    1079                                 return c.Y(i+1)-c.Y(i);}
    1080                     ], attr );
    1081         }
    1082     } else if (c.type == JXG.OBJECT_TYPE_TURTLE) {
    1083             l = board.create('line', [
    1084                     function(){ var i=Math.floor(p.position);
    1085                                 var lbda = p.position-i;
    1086                                 var el,j;
    1087                                 for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
    1088                                     el = c.objects[j];
    1089                                     if (el.type==JXG.OBJECT_TYPE_CURVE) {
    1090                                         if (i<el.numberPoints) break;
    1091                                         i-=el.numberPoints;
    1092                                     }
    1093                                 }
    1094                                 if (i==el.numberPoints-1) { i--; lbda=1.0; }
    1095                                 if (i<0) return 1.0;
    1096                                 return (el.Y(i)+lbda*(el.Y(i+1)-el.Y(i)))*(el.Y(i)-el.Y(i+1))-(el.X(i)+lbda*(el.X(i+1)-el.X(i)))*(el.X(i+1)-el.X(i));},
    1097                     function(){ var i=Math.floor(p.position);
    1098                                 var el,j;
    1099                                 for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
    1100                                     el = c.objects[j];
    1101                                     if (el.type==JXG.OBJECT_TYPE_CURVE) {
    1102                                         if (i<el.numberPoints) break;
    1103                                         i-=el.numberPoints;
    1104                                     }
    1105                                 }
    1106                                 if (i==el.numberPoints-1) i--;
    1107                                 if (i<0) return 0.0;
    1108                                 return el.X(i+1)-el.X(i);},
    1109                     function(){ var i=Math.floor(p.position);
    1110                                 var el,j;
    1111                                 for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
    1112                                     el = c.objects[j];
    1113                                     if (el.type==JXG.OBJECT_TYPE_CURVE) {
    1114                                         if (i<el.numberPoints) break;
    1115                                         i-=el.numberPoints;
    1116                                     }
    1117                                 }
    1118                                 if (i==el.numberPoints-1) i--;
    1119                                 if (i<0) return 0.0;
    1120                                 return el.Y(i+1)-el.Y(i);}
    1121                     ], attr );
    1122     }
    1123     else {
    1124         throw new Error("JSXGraph: Can't create normal with parent types '" +
    1125                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1126                         "\nPossible parent types: [point,line], [point,circle], [glider]");
    1127     }
    1128
    1129     l.parents = [];
    1130     for (i = 0; i < parents.length; i++) {
    1131         l.parents.push(parents[i].id);
    1132     }
    1133     l.elType = 'normal';
    1134
    1135     return l;
    1136 };
    1137
    1138 /**
    1139  * @class A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and
    1140  * C and divides the angle ABC into two equal sized parts.
    1141  * @pseudo
    1142  * @constructor
    1143  * @name Bisector
    1144  * @type JXG.Line
    1145  * @augments JXG.Line
    1146  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1147  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will
    1148  * be divided into two equal angles.
    1149  * @example
    1150  * var p1 = board.create('point', [6.0, 4.0]);
    1151  * var p2 = board.create('point', [3.0, 2.0]);
    1152  * var p3 = board.create('point', [1.0, 7.0]);
    1153  *
    1154  * var bi1 = board.create('bisector', [p1, p2, p3]);
    1155  * </pre><div id="0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div>
    1156  * <script type="text/javascript">
    1157  * (function () {
    1158  *   var board = JXG.JSXGraph.initBoard('0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1159  *   var p1 = board.create('point', [6.0, 4.0]);
    1160  *   var p2 = board.create('point', [3.0, 2.0]);
    1161  *   var p3 = board.create('point', [1.0, 7.0]);
    1162  *   var bi1 = board.create('bisector', [p1, p2, p3]);
    1163  * })();
    1164  * </script><pre>
    1165  */
    1166 JXG.createBisector = function(board, parents, attributes) {
    1167     var p, l, i, attr;
    1168
    1169     /* TODO bisector polynomials */
    1170     if(parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) {
    1171         // hidden and fixed helper
    1172         attr = JXG.copyAttributes(attributes, board.options, 'bisector', 'point');
    1173         p = board.create('point', [function () { return JXG.Math.Geometry.angleBisector(parents[0], parents[1], parents[2], board); }], attr);
    1174         p.dump = false;
    1175
    1176         for(i=0; i<3; i++)
    1177             parents[i].addChild(p); // required for algorithm requiring dependencies between elements
    1178
    1179         if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
    1180         attr = JXG.copyAttributes(attributes, board.options, 'bisector');
    1181         l = JXG.createLine(board, [parents[1], p], attr);
    1182
    1183         /**
    1184          * Helper point
    1185          * @memberOf Bisector.prototype
    1186          * @type Point
    1187          * @name point
    1188          */
    1189         l.point = p;
    1190
    1191         l.elType = 'bisector';
    1192         l.parents = [parents[0].id, parents[1].id, parents[2].id];
    1193         l.subs = {
    1194             point: p
    1195         };
    1196
    1197         return l;
    1198     }
    1199     else {
    1200         throw new Error("JSXGraph: Can't create angle bisector with parent types '" +
    1201                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1202                         "\nPossible parent types: [point,point,point]");
    1203     }
    1204 };
    1205
    1206 /**
    1207  * @class Bisector lines are similar to {@link Bisector} but takes two lines as parent elements. The resulting element is
    1208  * a composition of two lines.
    1209  * @pseudo
    1210  * @constructor
    1211  * @name Bisectorlines
    1212  * @type JXG.Composition
    1213  * @augments JXG.Composition
    1214  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1215  * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each
    1216  * be divided into two equal angles.
    1217  * @example
    1218  * var p1 = board.create('point', [6.0, 4.0]);
    1219  * var p2 = board.create('point', [3.0, 2.0]);
    1220  * var p3 = board.create('point', [1.0, 7.0]);
    1221  * var p4 = board.create('point', [3.0, 0.0]);
    1222  * var l1 = board.create('line', [p1, p2]);
    1223  * var l2 = board.create('line', [p3, p4]);
    1224  *
    1225  * var bi1 = board.create('bisectorlines', [l1, l2]);
    1226  * </pre><div id="3121ff67-44f0-4dda-bb10-9cda0b80bf18" style="width: 400px; height: 400px;"></div>
    1227  * <script type="text/javascript">
    1228  * (function () {
    1229  *   var board = JXG.JSXGraph.initBoard('3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1230  *   var p1 = board.create('point', [6.0, 4.0]);
    1231  *   var p2 = board.create('point', [3.0, 2.0]);
    1232  *   var p3 = board.create('point', [1.0, 7.0]);
    1233  *   var p4 = board.create('point', [3.0, 0.0]);
    1234  *   var l1 = board.create('line', [p1, p2]);
    1235  *   var l2 = board.create('line', [p3, p4]);
    1236  *   var bi1 = board.create('bisectorlines', [l1, l2]);
    1237  * })();
    1238  * </script><pre>
    1239  */
    1240 JXG.createAngularBisectorsOfTwoLines = function(board, parents, attributes) {
    1241     //
    1242     // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation:
    1243     // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2)
    1244
    1245     var l1 = JXG.getReference(board,parents[0]),
    1246         l2 = JXG.getReference(board,parents[1]),
    1247         g1, g2, attr,
    1248         ret;
    1249
    1250     if(l1.elementClass != JXG.OBJECT_CLASS_LINE || l2.elementClass != JXG.OBJECT_CLASS_LINE) {
    1251         throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" +
    1252                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1253                         "\nPossible parent types: [line,line]");
    1254     }
    1255
    1256     if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
    1257     attr = JXG.copyAttributes(attributes, board.options, 'bisectorlines', 'line1');
    1258     g1 = board.create('line',[
    1259         function(){
    1260             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
    1261             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
    1262             return l1.stdform[0]/d1-l2.stdform[0]/d2;
    1263         },
    1264         function(){
    1265             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
    1266             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
    1267             return l1.stdform[1]/d1-l2.stdform[1]/d2;
    1268         },
    1269         function(){
    1270             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
    1271             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
    1272             return l1.stdform[2]/d1-l2.stdform[2]/d2;
    1273         }
    1274     ], attr);
    1275
    1276     if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.line;
    1277     attr = JXG.copyAttributes(attributes, board.options, 'bisectorlines', 'line2');
    1278     g2 = board.create('line',[
    1279         function(){
    1280             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
    1281             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
    1282             return l1.stdform[0]/d1+l2.stdform[0]/d2;
    1283         },
    1284         function(){
    1285             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
    1286             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
    1287             return l1.stdform[1]/d1+l2.stdform[1]/d2;
    1288         },
    1289         function(){
    1290             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
    1291             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
    1292             return l1.stdform[2]/d1+l2.stdform[2]/d2;
    1293         }
    1294     ], attr);
    1295
    1296     // documentation
    1297     /**
    1298      * First line.
    1299      * @memberOf Bisectorlines.prototype
    1300      * @name line1
    1301      * @type Line
    1302      */
    1303
    1304     /**
    1305      * Second line.
    1306      * @memberOf Bisectorlines.prototype
    1307      * @name line2
    1308      * @type Line
    1309      */
    1310
    1311     ret = new JXG.Composition({line1: g1, line2: g2});
    1312
    1313     g1.dump = false;
    1314     g2.dump = false;
    1315
    1316     ret.elType = 'bisectorlines';
    1317     ret.parents = [l1.id, l2.id];
    1318     ret.subs = {
    1319         line1: g1,
    1320         line2: g2
    1321     };
    1322
    1323     return ret;
    1324 };
    1325
    1326 /**
    1327  * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter
    1328  * is constructed by providing three points.
    1329  * @pseudo
    1330  * @description A circumcenter is given by three points which are all lying on the circle with the
    1331  * constructed circumcenter as the midpoint.
    1332  * @constructor
    1333  * @name Circumcenter
    1334  * @type JXG.Point
    1335  * @augments JXG.Point
    1336  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1337  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined
    1338  * by p1, p2, and p3.
    1339  * @example
    1340  * var p1 = board.create('point', [0.0, 2.0]);
    1341  * var p2 = board.create('point', [2.0, 1.0]);
    1342  * var p3 = board.create('point', [3.0, 3.0]);
    1343  *
    1344  * var cc1 = board.create('circumcenter', [p1, p2, p3]);
    1345  * </pre><div id="e8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div>
    1346  * <script type="text/javascript">
    1347  *   var ccmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1348  *   var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]);
    1349  *   var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]);
    1350  *   var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]);
    1351  *   var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]);
    1352  * </script><pre>
    1353  */
    1354 JXG.createCircumcircleMidpoint = function(board, parents, attributes) {
    1355     var p, i;
    1356
    1357     if( parents[0].elementClass == JXG.OBJECT_CLASS_POINT
    1358        && parents[1].elementClass == JXG.OBJECT_CLASS_POINT
    1359        && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) {
    1360         p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.circumcenterMidpoint(parents[0], parents[1], parents[2], board); }], attributes);
    1361
    1362         for (i = 0; i < 3; i++) {
    1363             parents[i].addChild(p);
    1364         }
    1365
    1366         p.elType = 'circumcenter';
    1367         p.parents = [parents[0].id, parents[1].id, parents[2].id];
    1368
    1369         p.generatePolynomial = function() {
    1370                 /*
    1371                  *  CircumcircleMidpoint takes three points A, B and C  and creates point M, which is the circumcenter of A, B, and C.
    1372                  *
    1373                  *
    1374                  * So we have two conditions:
    1375                  *
    1376                  *   (a)   CT  ==  AT           (distance condition I)
    1377                  *   (b)   BT  ==  AT           (distance condition II)
    1378                  *
    1379                  */
    1380
    1381             var a1 = a.symbolic.x;
    1382             var a2 = a.symbolic.y;
    1383             var b1 = b.symbolic.x;
    1384             var b2 = b.symbolic.y;
    1385             var c1 = c.symbolic.x;
    1386             var c2 = c.symbolic.y;
    1387             var t1 = p.symbolic.x;
    1388             var t2 = p.symbolic.y;
    1389
    1390             var poly1 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',b1,'))^2-((',t2,')-(',b2,'))^2'].join('');
    1391             var poly2 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',c1,'))^2-((',t2,')-(',c2,'))^2'].join('');
    1392
    1393             return [poly1, poly2];
    1394         };
    1395
    1396         return p;
    1397     }
    1398     else {
    1399         throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" +
    1400                         (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1401                         "\nPossible parent types: [point,point,point]");
    1402     }
    1403 };
    1404
    1405 /**
    1406  * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html}
    1407  * @pseudo
    1408  * @constructor
    1409  * @name Incenter
    1410  * @type JXG.Point
    1411  * @augments JXG.Point
    1412  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1413  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described
    1414  * by p1, p2, and p3.
    1415  * @example
    1416  * var p1 = board.create('point', [0.0, 2.0]);
    1417  * var p2 = board.create('point', [2.0, 1.0]);
    1418  * var p3 = board.create('point', [3.0, 3.0]);
    1419  *
    1420  * var ic1 = board.create('incenter', [p1, p2, p3]);
    1421  * </pre><div id="e8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div>
    1422  * <script type="text/javascript">
    1423  *   var icmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1424  *   var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]);
    1425  *   var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]);
    1426  *   var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]);
    1427  *   var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]);
    1428  * </script><pre>
    1429  */
    1430 JXG.createIncenter = function(board, parents, attributes) {
    1431     var p, c,
    1432         A, B, C;
    1433
    1434     if(parents.length >= 3 && JXG.isPoint(parents[0]) && JXG.isPoint(parents[1]) && JXG.isPoint(parents[2])) {
    1435         A = parents[0];
    1436         B = parents[1];
    1437         C = parents[2];
    1438
    1439         p = board.create('point', [function() {
    1440             var a, b, c;
    1441
    1442             a = Math.sqrt((B.X() - C.X())*(B.X() - C.X()) + (B.Y() - C.Y())*(B.Y() - C.Y()));
    1443             b = Math.sqrt((A.X() - C.X())*(A.X() - C.X()) + (A.Y() - C.Y())*(A.Y() - C.Y()));
    1444             c = Math.sqrt((B.X() - A.X())*(B.X() - A.X()) + (B.Y() - A.Y())*(B.Y() - A.Y()));
    1445
    1446             return new JXG.Coords(JXG.COORDS_BY_USER, [(a*A.X()+b*B.X()+c*C.X())/(a+b+c), (a*A.Y()+b*B.Y()+c*C.Y())/(a+b+c)], board);
    1447         }], attributes);
    1448
    1449         p.elType = 'incenter';
    1450         p.parents = [parents[0].id, parents[1].id, parents[2].id];
    1451
    1452     } else {
    1453         throw new Error("JSXGraph: Can't create incenter with parent types '" +
    1454             (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1455             "\nPossible parent types: [point,point,point]");
    1456     }
    1457
    1458     return p;
    1459 };
    1460
    1461 /**
    1462  * @class A circumcircle is given by three points which are all lying on the circle.
    1463  * @pseudo
    1464  * @constructor
    1465  * @name Circumcircle
    1466  * @type JXG.Circle
    1467  * @augments JXG.Circle
    1468  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1469  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed element is the circle determined by <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.
    1470  * @example
    1471  * var p1 = board.create('point', [0.0, 2.0]);
    1472  * var p2 = board.create('point', [2.0, 1.0]);
    1473  * var p3 = board.create('point', [3.0, 3.0]);
    1474  *
    1475  * var cc1 = board.create('circumcircle', [p1, p2, p3]);
    1476  * </pre><div id="e65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div>
    1477  * <script type="text/javascript">
    1478  *   var ccex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1479  *   var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]);
    1480  *   var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]);
    1481  *   var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]);
    1482  *   var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]);
    1483  * </script><pre>
    1484  */
    1485 JXG.createCircumcircle = function(board, parents, attributes) {
    1486     var p, c, attr;
    1487
    1488     try {
    1489         attr = JXG.copyAttributes(attributes, board.options, 'circumcircle', 'center');
    1490         p = JXG.createCircumcircleMidpoint(board, parents, attr);
    1491
    1492         p.dump = false;
    1493
    1494         if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.circle;
    1495         attr = JXG.copyAttributes(attributes, board.options, 'circumcircle');
    1496         c = JXG.createCircle(board, [p, parents[0]], attr);
    1497
    1498         c.elType = 'circumcircle';
    1499         c.parents = [parents[0].id, parents[1].id, parents[2].id];
    1500         c.subs = {
    1501             center: p
    1502         };
    1503     } catch(e) {
    1504         throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
    1505                         (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1506                         "\nPossible parent types: [point,point,point]");
    1507     }
    1508
    1509     // p is already stored as midpoint in c so there's no need to store it explicitly.
    1510
    1511     return c;
    1512 };
    1513
    1514 /**
    1515  * @class An incircle is given by three points.
    1516  * @pseudo
    1517  * @constructor
    1518  * @name Incircle
    1519  * @type JXG.Circle
    1520  * @augments JXG.Circle
    1521  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1522  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of
    1523  * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.
    1524  * @example
    1525  * var p1 = board.create('point', [0.0, 2.0]);
    1526  * var p2 = board.create('point', [2.0, 1.0]);
    1527  * var p3 = board.create('point', [3.0, 3.0]);
    1528  *
    1529  * var ic1 = board.create('incircle', [p1, p2, p3]);
    1530  * </pre><div id="e65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div>
    1531  * <script type="text/javascript">
    1532  *   var icex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1533  *   var icex1_p1 = icex1_board.create('point', [0.0, 2.0]);
    1534  *   var icex1_p2 = icex1_board.create('point', [6.0, 1.0]);
    1535  *   var icex1_p3 = icex1_board.create('point', [3.0, 7.0]);
    1536  *   var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]);
    1537  * </script><pre>
    1538  */
    1539 JXG.createIncircle = function(board, parents, attributes) {
    1540     var p, c, attr, ret;
    1541
    1542     try {
    1543         attr = JXG.copyAttributes(attributes, board.options, 'incircle', 'center');
    1544         p = JXG.createIncenter(board, parents, attr);
    1545
    1546         p.dump = false;
    1547
    1548         if (!JXG.exists(attributes.layer)) attributes.layer = board.options.layer.circle;
    1549         attr = JXG.copyAttributes(attributes, board.options, 'incircle');
    1550         c = JXG.createCircle(board, [p, function() {
    1551             var a = Math.sqrt((parents[1].X() - parents[2].X())*(parents[1].X() - parents[2].X()) + (parents[1].Y() - parents[2].Y())*(parents[1].Y() - parents[2].Y())),
    1552                 b = Math.sqrt((parents[0].X() - parents[2].X())*(parents[0].X() - parents[2].X()) + (parents[0].Y() - parents[2].Y())*(parents[0].Y() - parents[2].Y())),
    1553                 c = Math.sqrt((parents[1].X() - parents[0].X())*(parents[1].X() - parents[0].X()) + (parents[1].Y() - parents[0].Y())*(parents[1].Y() - parents[0].Y())),
    1554                 s = (a+b+c)/2;
    1555
    1556             return Math.sqrt(((s-a)*(s-b)*(s-c))/s);
    1557         }], attr);
    1558
    1559         c.elType = 'incircle';
    1560         c.parents = [parents[0].id, parents[1].id, parents[2].id];
    1561
    1562         /**
    1563          * The center of the incircle
    1564          * @memberOf Incircle.prototype
    1565          * @type Incenter
    1566          * @name center
    1567          */
    1568         c.center = p;
    1569
    1570         c.subs = {
    1571             center: p
    1572         };
    1573     } catch(e) {
    1574         throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
    1575                         (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1576                         "\nPossible parent types: [point,point,point]");
    1577     }
    1578
    1579     // p is already stored as midpoint in c so there's no need to store it explicitly.
    1580
    1581     return c;
    1582 };
    1583
    1584 /**
    1585  * @class This element is used to construct a reflected point.
    1586  * @pseudo
    1587  * @description A reflected point is given by a point and a line. It is determined by the reflection of the given point
    1588  * against the given line.
    1589  * @constructor
    1590  * @name Reflection
    1591  * @type JXG.Point
    1592  * @augments JXG.Point
    1593  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1594  * @param {JXG.Point_JXG.Line} p,l The reflection point is the reflection of p against l.
    1595  * @example
    1596  * var p1 = board.create('point', [0.0, 4.0]);
    1597  * var p2 = board.create('point', [6.0, 1.0]);
    1598  * var l1 = board.create('line', [p1, p2]);
    1599  * var p3 = board.create('point', [3.0, 3.0]);
    1600  *
    1601  * var rp1 = board.create('reflection', [p3, l1]);
    1602  * </pre><div id="087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div>
    1603  * <script type="text/javascript">
    1604  *   var rpex1_board = JXG.JSXGraph.initBoard('087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1605  *   var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]);
    1606  *   var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]);
    1607  *   var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]);
    1608  *   var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]);
    1609  *   var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]);
    1610  * </script><pre>
    1611  */
    1612 JXG.createReflection = function(board, parents, attributes) {
    1613     var l, p, r;
    1614
    1615     if(parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_LINE) {
    1616         p = parents[0];
    1617         l = parents[1];
    1618     }
    1619     else if(parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[0].elementClass == JXG.OBJECT_CLASS_LINE) {
    1620         p = parents[1];
    1621         l = parents[0];
    1622     }
    1623     else {
    1624         throw new Error("JSXGraph: Can't create reflection point with parent types '" +
    1625                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1626                         "\nPossible parent types: [line,point]");
    1627     }
    1628
    1629     r = JXG.createPoint(board, [function () { return JXG.Math.Geometry.reflection(l, p, board); }], attributes);
    1630     p.addChild(r);
    1631     l.addChild(r);
    1632
    1633     r.elType = 'reflection';
    1634     r.parents = [parents[0].id, parents[1].id];
    1635
    1636     r.prepareUpdate().update();
    1637
    1638     r.generatePolynomial = function() {
    1639         /*
    1640          *  Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.
    1641          *  L is defined by two points A and B.
    1642          *
    1643          * So we have two conditions:
    1644          *
    1645          *   (a)   RP  _|_  AB            (orthogonality condition)
    1646          *   (b)   AR  ==   AP            (distance condition)
    1647          *
    1648          */
    1649
    1650         var a1 = l.point1.symbolic.x;
    1651         var a2 = l.point1.symbolic.y;
    1652         var b1 = l.point2.symbolic.x;
    1653         var b2 = l.point2.symbolic.y;
    1654         var p1 = p.symbolic.x;
    1655         var p2 = p.symbolic.y;
    1656         var r1 = r.symbolic.x;
    1657         var r2 = r.symbolic.y;
    1658
    1659         var poly1 = ['((',r2,')-(',p2,'))*((',a2,')-(',b2,'))+((',a1,')-(',b1,'))*((',r1,')-(',p1,'))'].join('');
    1660         var poly2 = ['((',r1,')-(',a1,'))^2+((',r2,')-(',a2,'))^2-((',p1,')-(',a1,'))^2-((',p2,')-(',a2,'))^2'].join('');
    1661
    1662         return [poly1, poly2];
    1663     };
    1664
    1665     return r;
    1666 };
    1667
    1668 /**
    1669  * @class A mirror point will be constructed.
    1670  * @pseudo
    1671  * @description A mirror point is determined by the reflection of a given point against another given point.
    1672  * @constructor
    1673  * @name Mirrorpoint
    1674  * @type JXG.Point
    1675  * @augments JXG.Point
    1676  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1677  * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.
    1678  * @example
    1679  * var p1 = board.create('point', [3.0, 3.0]);
    1680  * var p2 = board.create('point', [6.0, 1.0]);
    1681  *
    1682  * var mp1 = board.create('mirrorpoint', [p1, p2]);
    1683  * </pre><div id="7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div>
    1684  * <script type="text/javascript">
    1685  *   var mpex1_board = JXG.JSXGraph.initBoard('7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1686  *   var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);
    1687  *   var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);
    1688  *   var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);
    1689  * </script><pre>
    1690  */
    1691 JXG.createMirrorPoint = function(board, parents, attributes) {
    1692     var p, i;
    1693
    1694     /* TODO mirror polynomials */
    1695     if(JXG.isPoint(parents[0]) && JXG.isPoint(parents[1])) {
    1696         p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.rotation(parents[0], parents[1], Math.PI, board); }], attributes);
    1697
    1698         for(i = 0; i < 2; i++) {
    1699             parents[i].addChild(p);
    1700         }
    1701
    1702         p.elType = 'mirrorpoint';
    1703         p.parents = [parents[0].id, parents[1].id];
    1704     }
    1705     else {
    1706         throw new Error("JSXGraph: Can't create mirror point with parent types '" +
    1707                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1708                         "\nPossible parent types: [point,point]");
    1709     }
    1710
    1711     p.prepareUpdate().update();
    1712
    1713     return p;
    1714 };
    1715
    1716 /**
    1717  * @class This element is used to visualize the integral of a given curve over a given interval.
    1718  * @pseudo
    1719  * @description The Integral element is used to visualize the area under a given curve over a given interval
    1720  * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,
    1721  * the gliders are used to change the interval dynamically.
    1722  * @constructor
    1723  * @name Integral
    1724  * @type JXG.Curve
    1725  * @augments JXG.Curve
    1726  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1727  * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis
    1728  * within the interval <tt>i</tt>.
    1729  * @example
    1730  * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);
    1731  * var i1 = board.create('integral', [[-1.0, 4.0], c1]);
    1732  * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
    1733  * <script type="text/javascript">
    1734  *   var intex1_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});
    1735  *   var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]);
    1736  *   var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);
    1737  * </script><pre>
    1738  */
    1739 JXG.createIntegral = function(board, parents, attributes) {
    1740     var interval, curve, attr,
    1741         start = 0, end = 0, startx, starty, endx, endy, factor = 1,
    1742         pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,
    1743         Int, t, p;
    1744
    1745     if(JXG.isArray(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_CURVE) {
    1746         interval = parents[0];
    1747         curve = parents[1];
    1748     } else if(JXG.isArray(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_CURVE) {
    1749         interval = parents[1];
    1750         curve = parents[0];
    1751     } else {
    1752         throw new Error("JSXGraph: Can't create integral with parent types '" +
    1753                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1754                         "\nPossible parent types: [[number|function,number|function],curve]");
    1755     }
    1756
    1757     // Correct the interval if necessary - NOT ANYMORE, GGB's fault
    1758     start = interval[0];
    1759     end = interval[1];
    1760
    1761     if(JXG.isFunction(start)) {
    1762         startx = start;
    1763         starty = function () { return curve.Y(startx()); };
    1764         start = startx();
    1765     } else {
    1766         startx = start;
    1767         starty = curve.Y(start);
    1768     }
    1769
    1770     if(JXG.isFunction(start)) {
    1771         endx = end;
    1772         endy = function () { return curve.Y(endx()); };
    1773         end = endx();
    1774     } else {
    1775         endx = end;
    1776         endy = curve.Y(end);
    1777     }
    1778
    1779     if(end < start) {
    1780         factor = -1;
    1781     }
    1782
    1783     attr = JXG.copyAttributes(attributes, board.options, 'integral', 'curveLeft');
    1784     pa_on_curve = board.create('glider', [startx, starty, curve], attr);
    1785     if(JXG.isFunction(startx))
    1786         pa_on_curve.hideElement();
    1787
    1788     attr = JXG.copyAttributes(attributes, board.options, 'integral', 'baseLeft');
    1789     pa_on_axis = board.create('point', [function () { return pa_on_curve.X(); }, 0], attr);
    1790
    1791     //pa_on_curve.addChild(pa_on_axis);
    1792
    1793     attr = JXG.copyAttributes(attributes, board.options, 'integral', 'curveRight');
    1794     pb_on_curve = board.create('glider', [endx, endy, curve], attr);
    1795     if(JXG.isFunction(endx))
    1796         pb_on_curve.hideElement();
    1797
    1798     attr = JXG.copyAttributes(attributes, board.options, 'integral', 'baseRight');
    1799     pb_on_axis = board.create('point', [function () { return pb_on_curve.X(); }, 0], attr);
    1800
    1801     //pb_on_curve.addChild(pb_on_axis);
    1802
    1803     attr = JXG.copyAttributes(attributes, board.options, 'integral');
    1804     if(attr.withLabel !== false) {
    1805         attr = JXG.copyAttributes(attributes, board.options, 'integral', 'label');
    1806         t = board.create('text', [
    1807             function () { return pb_on_curve.X() + 0.2; },
    1808             function () { return pb_on_curve.Y() - 0.8; },
    1809             function () {
    1810                     var Int = JXG.Math.Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
    1811                     return '∫ = ' + (Int).toFixed(4);
    1812                 }
    1813             ], attr);
    1814
    1815         t.dump = false;
    1816
    1817         pa_on_curve.addChild(t);
    1818         pb_on_curve.addChild(t);
    1819     }
    1820
    1821     attr = JXG.copyAttributes(attributes, board.options, 'integral');
    1822     p = board.create('curve', [[0],[0]], attr);
    1823
    1824     // dump stuff
    1825     pa_on_curve.dump = false;
    1826     pa_on_axis.dump = false;
    1827
    1828     pb_on_curve.dump = false;
    1829     pb_on_axis.dump = false;
    1830
    1831     p.elType = 'integral';
    1832     p.parents = [curve.id, interval];
    1833     p.subs = {
    1834         curveLeft: pa_on_curve,
    1835         baseLeft: pa_on_axis,
    1836         curveRight: pb_on_curve,
    1837         baseRight: pb_on_axis
    1838     };
    1839
    1840     if (attr.withLabel) {
    1841         p.subs.label = t;
    1842     }
    1843
    1844     /**
    1845      * documented in JXG.Curve
    1846      * @ignore
    1847      */
    1848     p.updateDataArray = function() {
    1849         var x, y,
    1850             i, left, right;
    1851
    1852         if(pa_on_axis.X() < pb_on_axis.X()) {
    1853             left = pa_on_axis.X();
    1854             right = pb_on_axis.X();
    1855         } else {
    1856             left = pb_on_axis.X();
    1857             right = pa_on_axis.X();
    1858         }
    1859
    1860         x = [left, left];
    1861         y = [0, curve.Y(left)];
    1862
    1863         for(i=0; i < curve.numberPoints; i++) {
    1864             if( (left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right) ) {
    1865                 x.push(curve.points[i].usrCoords[1]);
    1866                 y.push(curve.points[i].usrCoords[2]);
    1867             }
    1868         }
    1869         x.push(right);
    1870         y.push(curve.Y(right));
    1871         x.push(right);
    1872         y.push(0);
    1873
    1874         x.push(left); // close the curve
    1875         y.push(0);
    1876
    1877         this.dataX = x;
    1878         this.dataY = y;
    1879     };
    1880     pa_on_curve.addChild(p);
    1881     pb_on_curve.addChild(p);
    1882
    1883     /**
    1884      * The point on the axis initially corresponding to the lower value of the interval.
    1885      * @memberOf Integral.prototype
    1886      * @name baseLeft
    1887      * @type JXG.Point
    1888      */
    1889     p.baseLeft = pa_on_axis;
    1890
    1891     /**
    1892      * The point on the axis initially corresponding to the higher value of the interval.
    1893      * @memberOf Integral.prototype
    1894      * @name baseRight
    1895      * @type JXG.Point
    1896      */
    1897     p.baseRight = pb_on_axis;
    1898
    1899     /**
    1900      * The glider on the curve corresponding to the lower value of the interval.
    1901      * @memberOf Integral.prototype
    1902      * @name curveLeft
    1903      * @type Glider
    1904      */
    1905     p.curveLeft = pa_on_curve;
    1906
    1907     /**
    1908      * The glider on the axis corresponding to the higher value of the interval.
    1909      * @memberOf Integral.prototype
    1910      * @name curveRight
    1911      * @type Glider
    1912      */
    1913     p.curveRight = pb_on_curve;
    1914
    1915     /**
    1916      * documented in GeometryElement
    1917      * @ignore
    1918      */
    1919     p.label = {
    1920         content: t
    1921     };
    1922
    1923     return p;
    1924 };
    1925
    1926 /**
    1927  * @class This element is used to visualize the locus of a given dependent point.
    1928  * @pseudo
    1929  * @description The locus element is used to visualize the curve a given point describes.
    1930  * @constructor
    1931  * @name Locus
    1932  * @type JXG.Curve
    1933  * @augments JXG.Curve
    1934  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1935  * @param {JXG.Point} p The constructed curve is the geometric locus of the given point.
    1936  * @example
    1937  *  // This examples needs JXG.Server up and running, otherwise it won't work.
    1938  *  p1 = board.create('point', [0, 0]);
    1939  *  p2 = board.create('point', [6, -1]);
    1940  *  c1 = board.create('circle', [p1, 2]);
    1941  *  c2 = board.create('circle', [p2, 1.5]);
    1942  *  g1 = board.create('glider', [6, 3, c1]);
    1943  *  c3 = board.create('circle', [g1, 4]);
    1944  *  g2 = board.create('intersection', [c2,c3,0]);
    1945  *  m1 = board.create('midpoint', [g1,g2]);
    1946  *  loc = board.create('locus', [m1], {strokeColor: 'red'});
    1947  * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
    1948  * <script type="text/javascript">
    1949  *  lcex_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true});
    1950  *  lcex_p1 = lcex_board.create('point', [0, 0]);
    1951  *  lcex_p2 = lcex_board.create('point', [6, -1]);
    1952  *  lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]);
    1953  *  lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]);
    1954  *  lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]);
    1955  *  lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]);
    1956  *  lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]);
    1957  *  lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]);
    1958  *  lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'});
    1959  * </script><pre>
    1960  */
    1961 JXG.createLocus = function(board, parents, attributes) {
    1962     var c, p;
    1963
    1964     if(JXG.isArray(parents) && parents.length == 1 && parents[0].elementClass == JXG.OBJECT_CLASS_POINT) {
    1965         p = parents[0];
    1966     } else {
    1967         throw new Error("JSXGraph: Can't create locus with parent of type other than point." +
    1968                         "\nPossible parent types: [point]");
    1969     }
    1970
    1971     c = board.create('curve', [[null], [null]], attributes);
    1972     c.dontCallServer = false;
    1973
    1974     c.elType = 'locus';
    1975     c.parents = [p.id];
    1976
    1977     /**
    1978      * should be documented in JXG.Curve
    1979      * @ignore
    1980      */
    1981     c.updateDataArray = function () {
    1982         if(c.board.mode > 0)
    1983             return;
    1984
    1985         var spe = JXG.Math.Symbolic.generatePolynomials(board, p, true).join('|');
    1986         if(spe === c.spe)
    1987                 return;
    1988
    1989         c.spe = spe;
    1990
    1991         var cb = function(x, y, eq, t) {
    1992                 c.dataX = x;
    1993                 c.dataY = y;
    1994
    1995                 /**
    1996                  * The implicit definition of the locus.
    1997                  * @memberOf Locus.prototype
    1998                  * @name eq
    1999                  * @type String
    2000                  */
    2001                 c.eq = eq;
    2002
    2003                 /**
    2004                  * The time it took to calculate the locus
    2005                  * @memberOf Locus.prototype
    2006                  * @name ctime
    2007                  * @type Number
    2008                  */
    2009                 c.ctime = t;
    2010
    2011                 // convert equation and use it to build a generatePolynomial-method
    2012                 c.generatePolynomial = (function(equations) {
    2013                     return function(point) {
    2014                         var x = '(' + point.symbolic.x + ')',
    2015                             y = '(' + point.symbolic.y + ')',
    2016                             res = [], i;
    2017
    2018                         for(i=0; i<equations.length; i++)
    2019                             res[i] = equations[i].replace(/\*\*/g, '^').replace(/x/g, x).replace(/y/g, y);
    2020
    2021                         return res;
    2022                     }
    2023                 })(eq);
    2024             },
    2025             data = JXG.Math.Symbolic.geometricLocusByGroebnerBase(board, p, cb);
    2026
    2027         cb(data.datax, data.datay, data.polynomial, data.exectime);
    2028     };
    2029     return c;
    2030 };
    2031
    2032
    2033 /**
    2034  * @class Creates a grid to support the user with element placement.
    2035  * @pseudo
    2036  * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method
    2037  * draws such a grid on the given board. It uses options given in {@link JXG.Options#grid}. This method does not
    2038  * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set
    2039  * to true.
    2040  * @parameter None.
    2041  * @constructor
    2042  * @name Grid
    2043  * @type JXG.Curve
    2044  * @augments JXG.Curve
    2045  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    2046  * @example
    2047  * grid = board.create('grid', []);
    2048  * </pre><div id="a9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div>
    2049  * <script type="text/javascript">
    2050  * (function () {
    2051  *  board = JXG.JSXGraph.initBoard('a9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
    2052  *  grid = board.create('grid', []);
    2053  * })();
    2054  * </script><pre>
    2055  */
    2056 JXG.createGrid = function (board, parents, attributes) {
    2057     var c, attr;
    2058
    2059     attr = JXG.copyAttributes(attributes, board.options, 'grid');
    2060     c = board.create('curve', [[null], [null]], attr);
    2061
    2062     c.elType = 'grid';
    2063     c.parents = [];
    2064
    2065     c.updateDataArray = function () {
    2066         var gridX = this.visProp.gridx,
    2067             gridY = this.visProp.gridy,
    2068             topLeft = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0, 0], board),
    2069             bottomRight = new JXG.Coords(JXG.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board),
    2070             i;
    2071         //horizontal = [[], []], vertical = [[], []];
    2072
    2073         //
    2074         //      |         |         |
    2075         //  ----+---------+---------+-----
    2076         //      |        /|         |
    2077         //      |    gridY|     <---+------   Grid Cell
    2078         //      |        \|         |
    2079         //  ----+---------+---------+-----
    2080         //      |         |\ gridX /|
    2081         //      |         |         |
    2082         //
    2083         // uc: usercoordinates
    2084         //
    2085         // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high.
    2086         // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it
    2087         // is absolutely not user friendly when it comes to use it as an API interface.
    2088         // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i
    2089         // had to refactor these methods:
    2090         //
    2091         //  DONE JXG.Board.calculateSnapSizes (init p1, p2)
    2092         //  DONE JXG.GeonextReader.readGeonext (init gridX, gridY)
    2093         //
    2094
    2095         board.options.grid.hasGrid = true;
    2096
    2097         topLeft.setCoordinates(JXG.COORDS_BY_USER, [Math.floor(topLeft.usrCoords[1] / gridX) * gridX, Math.ceil(topLeft.usrCoords[2] / gridY) * gridY]);
    2098         bottomRight.setCoordinates(JXG.COORDS_BY_USER, [Math.ceil(bottomRight.usrCoords[1] / gridX) * gridX, Math.floor(bottomRight.usrCoords[2] / gridY) * gridY]);
    2099
    2100         c.dataX = [];
    2101         c.dataY = [];
    2102
    2103         // start with the horizontal grid:
    2104         for (i = topLeft.usrCoords[2]; i > bottomRight.usrCoords[2] - gridY; i -= gridY) {
    2105             c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN);
    2106             c.dataY.push(i, i, NaN);
    2107         }
    2108
    2109         // build vertical grid
    2110         for (i = topLeft.usrCoords[1]; i < bottomRight.usrCoords[1] + gridX; i += gridX) {
    2111             c.dataX.push(i, i, NaN);
    2112             c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN);
    2113         }
    2114
    2115     };
    2116
    2117     // we don't care about highlighting so we turn it off completely to save a lot of
    2118     // time on every mouse move
    2119     c.hasPoint = function () {
    2120         return false;
    2121     };
    2122
    2123     board.grids.push(c);
    2124
    2125     return c;
    2126 };
    2127
    2128
    2129 JXG.JSXGraph.registerElement('arrowparallel', JXG.createArrowParallel);
    2130 JXG.JSXGraph.registerElement('bisector', JXG.createBisector);
    2131 JXG.JSXGraph.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);
    2132 JXG.JSXGraph.registerElement('circumcircle', JXG.createCircumcircle);
    2133 JXG.JSXGraph.registerElement('circumcirclemidpoint', JXG.createCircumcircleMidpoint);
    2134 JXG.JSXGraph.registerElement('circumcenter', JXG.createCircumcircleMidpoint);
    2135 JXG.JSXGraph.registerElement('incenter', JXG.createIncenter);
    2136 JXG.JSXGraph.registerElement('incircle', JXG.createIncircle);
    2137 JXG.JSXGraph.registerElement('integral', JXG.createIntegral);
    2138 JXG.JSXGraph.registerElement('midpoint', JXG.createMidpoint);
    2139 JXG.JSXGraph.registerElement('mirrorpoint', JXG.createMirrorPoint);
    2140 JXG.JSXGraph.registerElement('normal', JXG.createNormal);
    2141 JXG.JSXGraph.registerElement('orthogonalprojection', JXG.createOrthogonalProjection);
    2142 JXG.JSXGraph.registerElement('parallel', JXG.createParallel);
    2143 JXG.JSXGraph.registerElement('parallelpoint', JXG.createParallelPoint);
    2144 JXG.JSXGraph.registerElement('perpendicular', JXG.createPerpendicular);
    2145 JXG.JSXGraph.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);
    2146 JXG.JSXGraph.registerElement('perpendicularsegment', JXG.createPerpendicularSegment);
    2147 JXG.JSXGraph.registerElement('reflection', JXG.createReflection);
    2148 JXG.JSXGraph.registerElement('locus', JXG.createLocus);
    2149 JXG.JSXGraph.registerElement('grid', JXG.createGrid);
    2150