      1 /*
      2     Copyright 2008-2018
      3         Matthias Ehmann,
      4         Michael Gerhaeuser,
      5         Carsten Miller,
      6         Bianca Valentin,
      7         Alfred Wassermann,
      8         Peter Wilfahrt
      9
     10     This file is part of JSXGraph.
     11
     12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
     13
     14     You can redistribute it and/or modify it under the terms of the
     15
     16       * GNU Lesser General Public License as published by
     17         the Free Software Foundation, either version 3 of the License, or
     18         (at your option) any later version
     19       OR
     20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
     21
     22     JSXGraph is distributed in the hope that it will be useful,
     23     but WITHOUT ANY WARRANTY; without even the implied warranty of
     24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     25     GNU Lesser General Public License for more details.
     26
     27     You should have received a copy of the GNU Lesser General Public License and
     28     the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
     29     and <http://opensource.org/licenses/MIT/>.
     30  */
     31
     32
     33 /*global JXG: true, define: true*/
     34 /*jslint nomen: true, plusplus: true*/
     35
     36 /* depends:
     37  jxg
     38  math/math
     39  math/geometry
     40  math/numerics
     41  math/statistics
     42  math/symbolic
     43  base/composition
     44  base/coords
     45  base/constants
     46  utils/type
     47   elements:
     48    line
     49    circle
     50    transform
     51    point
     52    glider
     53    text
     54    curve
     55  */
     56
     57 /**
     58  * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together
     59  * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here
     60  * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the
     61  * following compositions can be found: <ul>
     62  *   <li>{@link Arrowparallel} (currently private)</li>
     63  *   <li>{@link Bisector}</li>
     64  *   <li>{@link Msector}</li>
     65  *   <li>{@link Circumcircle}</li>
     66  *   <li>{@link Circumcirclemidpoint}</li>
     67  *   <li>{@link Integral}</li>
     68  *   <li>{@link Midpoint}</li>
     69  *   <li>{@link Mirrorpoint}</li>
     70  *   <li>{@link Normal}</li>
     71  *   <li>{@link Orthogonalprojection}</li>
     72  *   <li>{@link Parallel}</li>
     73  *   <li>{@link Perpendicular}</li>
     74  *   <li>{@link Perpendicularpoint}</li>
     75  *   <li>{@link Perpendicularsegment}</li>
     76  *   <li>{@link Reflection}</li></ul>
     77  */
     78
     79 define([
     80     'jxg', 'math/math', 'math/geometry', 'math/numerics', 'math/statistics', 'base/coords', 'utils/type', 'base/constants',
     81     'base/point', 'base/line', 'base/circle', 'base/transformation', 'base/composition', 'base/curve', 'base/text'
     82 ], function (JXG, Mat, Geometry, Numerics, Statistics, Coords, Type, Const, Point, Line, Circle, Transform, Composition, Curve, Text) {
     83
     84     "use strict";
     85
     86     /**
     87      * @class This is used to construct a point that is the orthogonal projection of a point to a line.
     88      * @pseudo
     89      * @description An orthogonal projection is given by a point and a line. It is determined by projecting the given point
     90      * orthogonal onto the given line.
     91      * @constructor
     92      * @name Orthogonalprojection
     93      * @type JXG.Point
     94      * @augments JXG.Point
     95      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
     96      * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
     97      * @example
     98      * var p1 = board.create('point', [0.0, 4.0]);
     99      * var p2 = board.create('point', [6.0, 1.0]);
    100      * var l1 = board.create('line', [p1, p2]);
    101      * var p3 = board.create('point', [3.0, 3.0]);
    102      *
    103      * var pp1 = board.create('orthogonalprojection', [p3, l1]);
    104      * </pre><div class="jxgbox" id="7708b215-39fa-41b6-b972-19d73d77d791" style="width: 400px; height: 400px;"></div>
    105      * <script type="text/javascript">
    106      *   var ppex1_board = JXG.JSXGraph.initBoard('7708b215-39fa-41b6-b972-19d73d77d791', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    107      *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
    108      *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
    109      *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
    110      *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
    111      *   var ppex1_pp1 = ppex1_board.create('orthogonalprojection', [ppex1_p3, ppex1_l1]);
    112      * </script><pre>
    113      */
    114     JXG.createOrthogonalProjection = function (board, parents, attributes) {
    115         var l, p, t, attr;
    116
    117         parents[0] = board.select(parents[0]);
    118         parents[1] = board.select(parents[1]);
    119
    120         if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
    121             p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    122             l = parents[1];
    123         } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
    124             p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    125             l = parents[0];
    126         } else {
    127             throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
    128                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    129                 "\nPossible parent types: [point,line]");
    130         }
    131
    132         attr = Type.copyAttributes(attributes, board.options, 'orthogonalprojection');
    133
    134         t = board.create('point', [
    135             function () {
    136                 return Geometry.projectPointToLine(p, l, board);
    137             }
    138         ], attr);
    139
    140         p.addChild(t);
    141         l.addChild(t);
    142
    143         t.elType = 'orthogonalprojection';
    144         t.setParents([p.id, t.id]);
    145
    146         t.update();
    147
    148         t.generatePolynomial = function () {
    149             /*
    150              *  Perpendicular takes point P and line L and creates point T and line M:
    151              *
    152              *                          | M
    153              *                          |
    154              *                          x P (p1,p2)
    155              *                          |
    156              *                          |
    157              *  L                       |
    158              *  ----------x-------------x------------------------x--------
    159              *            A (a1,a2)     |T (t1,t2)               B (b1,b2)
    160              *                          |
    161              *                          |
    162              *
    163              * So we have two conditions:
    164              *
    165              *   (a)  AT  || TB          (collinearity condition)
    166              *   (b)  PT _|_ AB          (orthogonality condition)
    167              *
    168              *      a2-t2       t2-b2
    169              *     -------  =  -------           (1)
    170              *      a1-t1       t1-b1
    171              *
    172              *      p2-t2         a1-b1
    173              *     -------  =  - -------         (2)
    174              *      p1-t1         a2-b2
    175              *
    176              * Multiplying (1) and (2) with denominators and simplifying gives
    177              *
    178              *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                  (1')
    179              *
    180              *    p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0    (2')
    181              *
    182              */
    183
    184             var a1 = l.point1.symbolic.x,
    185                 a2 = l.point1.symbolic.y,
    186                 b1 = l.point2.symbolic.x,
    187                 b2 = l.point2.symbolic.y,
    188
    189                 p1 = p.symbolic.x,
    190                 p2 = p.symbolic.y,
    191                 t1 = t.symbolic.x,
    192                 t2 = t.symbolic.y,
    193
    194                 poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' +
    195                     a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')',
    196                 poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' +
    197                     t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' +
    198                     a1 + ')+(' + t1 + ')*(' + b1 + ')';
    199
    200             return [poly1, poly2];
    201         };
    202
    203         return t;
    204     };
    205
    206     /**
    207
    208      * @class This element is used to provide a constructor for a perpendicular.
    209      * @pseudo
    210      * @description  A perpendicular is a composition of two elements: a line and a point. The line is orthogonal
    211      * to a given line and contains a given point.
    212      * @name Perpendicular
    213      * @constructor
    214      * @type JXG.Line
    215      * @augments Segment
    216      * @returns A {@link JXG.Line} object through the given point that is orthogonal to the given line.
    217      * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.
    218      * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and
    219      * will contain p.
    220      * @example
    221      * // Create a perpendicular
    222      * var p1 = board.create('point', [0.0, 2.0]);
    223      * var p2 = board.create('point', [2.0, 1.0]);
    224      * var l1 = board.create('line', [p1, p2]);
    225      *
    226      * var p3 = board.create('point', [3.0, 3.0]);
    227      * var perp1 = board.create('perpendicular', [l1, p3]);
    228      * </pre><div class="jxgbox" id="d5b78842-7b27-4d37-b608-d02519e6cd03" style="width: 400px; height: 400px;"></div>
    229      * <script type="text/javascript">
    230      *   var pex1_board = JXG.JSXGraph.initBoard('d5b78842-7b27-4d37-b608-d02519e6cd03', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    231      *   var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);
    232      *   var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);
    233      *   var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);
    234      *   var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);
    235      *   var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]);
    236      * </script><pre>
    237      */
    238     JXG.createPerpendicular = function (board, parents, attributes) {
    239         var p, l, pd, attr;
    240
    241         parents[0] = board.select(parents[0]);
    242         parents[1] = board.select(parents[1]);
    243
    244         if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
    245             l = parents[1];
    246             p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    247         } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
    248             l = parents[0];
    249             p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    250         } else {
    251             throw new Error("JSXGraph: Can't create perpendicular with parent types '" +
    252                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    253                 "\nPossible parent types: [line,point]");
    254         }
    255
    256         attr = Type.copyAttributes(attributes, board.options, 'perpendicular');
    257         pd = Line.createLine(board, [
    258             function () {
    259                 return l.stdform[2] * p.X() - l.stdform[1] * p.Y();
    260             },
    261             function () {
    262                 return -l.stdform[2] * p.Z();
    263             },
    264             function () {
    265                 return l.stdform[1] * p.Z();
    266             }
    267         ], attr);
    268
    269         pd.elType = 'perpendicular';
    270         pd.setParents([l.id, p.id]);
    271
    272         return pd;
    273     };
    274
    275     /**
    276      * @class This is used to construct a perpendicular point.
    277      * @pseudo
    278      * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point
    279      * orthogonal onto the given line. This element should be used in GEONExTReader only. All other applications should
    280      * use orthogonal projection {@link Orthogonalprojection}.
    281      * @constructor
    282      * @name PerpendicularPoint
    283      * @type JXG.Point
    284      * @augments JXG.Point
    285      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    286      * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
    287      * @example
    288      * var p1 = board.create('point', [0.0, 4.0]);
    289      * var p2 = board.create('point', [6.0, 1.0]);
    290      * var l1 = board.create('line', [p1, p2]);
    291      * var p3 = board.create('point', [3.0, 3.0]);
    292      *
    293      * var pp1 = board.create('perpendicularpoint', [p3, l1]);
    294      * </pre><div class="jxgbox" id="ded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div>
    295      * <script type="text/javascript">
    296      *   var ppex1_board = JXG.JSXGraph.initBoard('ded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    297      *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
    298      *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
    299      *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
    300      *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
    301      *   var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]);
    302      * </script><pre>
    303      */
    304     JXG.createPerpendicularPoint = function (board, parents, attributes) {
    305         var l, p, t;
    306
    307         parents[0] = board.select(parents[0]);
    308         parents[1] = board.select(parents[1]);
    309         if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
    310             p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    311             l = parents[1];
    312         } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
    313             p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    314             l = parents[0];
    315         } else {
    316             throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
    317                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    318                 "\nPossible parent types: [point,line]");
    319         }
    320
    321         t = board.create('point', [
    322             function () {
    323                 return Geometry.perpendicular(l, p, board)[0];
    324             }
    325         ], attributes);
    326
    327         p.addChild(t);
    328         l.addChild(t);
    329
    330         t.elType = 'perpendicularpoint';
    331         t.setParents([p.id, l.id]);
    332
    333         t.update();
    334
    335         t.generatePolynomial = function () {
    336             /*
    337              *  Perpendicular takes point P and line L and creates point T and line M:
    338              *
    339              *                          | M
    340              *                          |
    341              *                          x P (p1,p2)
    342              *                          |
    343              *                          |
    344              *  L                       |
    345              *  ----------x-------------x------------------------x--------
    346              *            A (a1,a2)     |T (t1,t2)               B (b1,b2)
    347              *                          |
    348              *                          |
    349              *
    350              * So we have two conditions:
    351              *
    352              *   (a)  AT  || TB          (collinearity condition)
    353              *   (b)  PT _|_ AB          (orthogonality condition)
    354              *
    355              *      a2-t2       t2-b2
    356              *     -------  =  -------           (1)
    357              *      a1-t1       t1-b1
    358              *
    359              *      p2-t2         a1-b1
    360              *     -------  =  - -------         (2)
    361              *      p1-t1         a2-b2
    362              *
    363              * Multiplying (1) and (2) with denominators and simplifying gives
    364              *
    365              *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                  (1')
    366              *
    367              *    p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0    (2')
    368              *
    369              */
    370             var a1 = l.point1.symbolic.x,
    371                 a2 = l.point1.symbolic.y,
    372                 b1 = l.point2.symbolic.x,
    373                 b2 = l.point2.symbolic.y,
    374                 p1 = p.symbolic.x,
    375                 p2 = p.symbolic.y,
    376                 t1 = t.symbolic.x,
    377                 t2 = t.symbolic.y,
    378
    379                 poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' +
    380                     a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')',
    381                 poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' +
    382                     t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' +
    383                     a1 + ')+(' + t1 + ')*(' + b1 + ')';
    384
    385             return [poly1, poly2];
    386         };
    387
    388         return t;
    389     };
    390
    391     /**
    392      * @class This element is used to provide a constructor for a perpendicular segment.
    393      * @pseudo
    394      * @description  A perpendicular is a composition of two elements: a line segment and a point. The line segment is orthogonal
    395      * to a given line and contains a given point and meets the given line in the perpendicular point.
    396      * @name PerpendicularSegment
    397      * @constructor
    398      * @type JXG.Line
    399      * @augments Segment
    400      * @returns An array containing two elements: A {@link JXG.Line} object in the first component and a
    401      * {@link JXG.Point} element in the second component. The line segment is orthogonal to the given line and meets it
    402      * in the returned point.
    403      * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.
    404      * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and
    405      * will contain p. The perpendicular point is the intersection point of the two lines.
    406      * @example
    407      * // Create a perpendicular
    408      * var p1 = board.create('point', [0.0, 2.0]);
    409      * var p2 = board.create('point', [2.0, 1.0]);
    410      * var l1 = board.create('line', [p1, p2]);
    411      *
    412      * var p3 = board.create('point', [3.0, 3.0]);
    413      * var perp1 = board.create('perpendicularsegment', [l1, p3]);
    414      * </pre><div class="jxgbox" id="037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div>
    415      * <script type="text/javascript">
    416      *   var pex1_board = JXG.JSXGraph.initBoard('037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    417      *   var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);
    418      *   var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);
    419      *   var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);
    420      *   var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);
    421      *   var pex1_perp1 = pex1_board.create('perpendicularsegment', [pex1_l1, pex1_p3]);
    422      * </script><pre>
    423      */
    424     JXG.createPerpendicularSegment = function (board, parents, attributes) {
    425         var p, l, pd, t, attr;
    426
    427         parents[0] = board.select(parents[0]);
    428         parents[1] = board.select(parents[1]);
    429         if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
    430             l = parents[1];
    431             p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    432         } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
    433             l = parents[0];
    434             p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    435         } else {
    436             throw new Error("JSXGraph: Can't create perpendicular with parent types '" +
    437                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    438                 "\nPossible parent types: [line,point]");
    439         }
    440         attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment', 'point');
    441         t = JXG.createPerpendicularPoint(board, [l, p], attr);
    442         t.dump = false;
    443
    444         if (!Type.exists(attributes.layer)) {
    445             attributes.layer = board.options.layer.line;
    446         }
    447
    448         attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment');
    449         pd = Line.createLine(board, [
    450             function () {
    451                 return (Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]);
    452             }
    453         ], attr);
    454
    455         /**
    456          * Helper point
    457          * @memberOf PerpendicularSegment.prototype
    458          * @type PerpendicularPoint
    459          * @name point
    460          */
    461         pd.point = t;
    462
    463         pd.elType = 'perpendicularsegment';
    464         pd.setParents([p.id, l.id]);
    465         pd.subs = {
    466             point: t
    467         };
    468         pd.inherits.push(t);
    469
    470         return pd;
    471     };
    472
    473     /**
    474      * @class The midpoint element constructs a point in the middle of two given points.
    475      * @pseudo
    476      * @description A midpoint is given by two points. It is collinear to the given points and the distance
    477      * is the same to each of the given points, i.e. it is in the middle of the given points.
    478      * @constructor
    479      * @name Midpoint
    480      * @type JXG.Point
    481      * @augments JXG.Point
    482      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    483      * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2.
    484      * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of
    485      * the given line l.
    486      * @example
    487      * // Create base elements: 2 points and 1 line
    488      * var p1 = board.create('point', [0.0, 2.0]);
    489      * var p2 = board.create('point', [2.0, 1.0]);
    490      * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
    491      *
    492      * var mp1 = board.create('midpoint', [p1, p2]);
    493      * var mp2 = board.create('midpoint', [l1]);
    494      * </pre><div class="jxgbox" id="7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div>
    495      * <script type="text/javascript">
    496      *   var mpex1_board = JXG.JSXGraph.initBoard('7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    497      *   var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]);
    498      *   var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]);
    499      *   var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
    500      *   var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]);
    501      *   var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]);
    502      * </script><pre>
    503      */
    504     JXG.createMidpoint = function (board, parents, attributes) {
    505         var a, b, t, i,
    506             attr;
    507
    508         for (i = 0; i < parents.length; ++i) {
    509             parents[i] = board.select(parents[i]);
    510         }
    511         if (parents.length === 2 && Type.isPointType(board, parents[0]) && Type.isPointType(board, parents[1])) {
    512             parents = Type.providePoints(board, parents, attributes, 'point');
    513             a = parents[0];
    514             b = parents[1];
    515         } else if (parents.length === 1 && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
    516             a = parents[0].point1;
    517             b = parents[0].point2;
    518         } else {
    519             throw new Error("JSXGraph: Can't create midpoint." +
    520                 "\nPossible parent types: [point,point], [line]");
    521         }
    522
    523         attr = Type.copyAttributes(attributes, board.options, 'midpoint');
    524         t = board.create('point', [
    525             function () {
    526                 var x = a.coords.usrCoords[1] + b.coords.usrCoords[1];
    527                 if (isNaN(x) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) {
    528                     return NaN;
    529                 }
    530
    531                 return x * 0.5;
    532             },
    533             function () {
    534                 var y = a.coords.usrCoords[2] + b.coords.usrCoords[2];
    535                 if (isNaN(y) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) {
    536                     return NaN;
    537                 }
    538
    539                 return y * 0.5;
    540             }], attr);
    541         a.addChild(t);
    542         b.addChild(t);
    543
    544         t.elType = 'midpoint';
    545         t.setParents([a.id, b.id]);
    546
    547         t.prepareUpdate().update();
    548
    549         t.generatePolynomial = function () {
    550             /*
    551              *  Midpoint takes two point A and B or line L (with points P and Q) and creates point T:
    552              *
    553              *  L (not necessarily)
    554              *  ----------x------------------x------------------x--------
    555              *            A (a1,a2)          T (t1,t2)          B (b1,b2)
    556              *
    557              * So we have two conditions:
    558              *
    559              *   (a)   AT  ||  TB           (collinearity condition)
    560              *   (b)  [AT] == [TB]          (equidistant condition)
    561              *
    562              *      a2-t2       t2-b2
    563              *     -------  =  -------                                         (1)
    564              *      a1-t1       t1-b1
    565              *
    566              *     (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2       (2)
    567              *
    568              *
    569              * Multiplying (1) with denominators and simplifying (1) and (2) gives
    570              *
    571              *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                      (1')
    572              *
    573              *    a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0    (2')
    574              *
    575              */
    576             var a1 = a.symbolic.x,
    577                 a2 = a.symbolic.y,
    578                 b1 = b.symbolic.x,
    579                 b2 = b.symbolic.y,
    580                 t1 = t.symbolic.x,
    581                 t2 = t.symbolic.y,
    582
    583                 poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' +
    584                     a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')',
    585                 poly2 = '(' + a1 + ')^2 - 2*(' + a1 + ')*(' + t1 + ')+(' + a2 + ')^2-2*(' + a2 + ')*(' +
    586                     t2 + ')-(' + b1 + ')^2+2*(' + b1 + ')*(' + t1 + ')-(' + b2 + ')^2+2*(' + b2 + ')*(' + t2 + ')';
    587
    588             return [poly1, poly2];
    589         };
    590
    591         return t;
    592     };
    593
    594     /**
    595      * @class This element is used to construct a parallel point.
    596      * @pseudo
    597      * @description A parallel point is given by three points. Taking the euclidean vector from the first to the
    598      * second point, the parallel point is determined by adding that vector to the third point.
    599      * The line determined by the first two points is parallel to the line determined by the third point and the constructed point.
    600      * @constructor
    601      * @name Parallelpoint
    602      * @type JXG.Point
    603      * @augments JXG.Point
    604      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    605      * @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
    606      * <tt>p4 = p3+v</tt>
    607      * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l.
    608      * @example
    609      * var p1 = board.create('point', [0.0, 2.0]);
    610      * var p2 = board.create('point', [2.0, 1.0]);
    611      * var p3 = board.create('point', [3.0, 3.0]);
    612      *
    613      * var pp1 = board.create('parallelpoint', [p1, p2, p3]);
    614      * </pre><div class="jxgbox" id="488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div>
    615      * <script type="text/javascript">
    616      *   var ppex1_board = JXG.JSXGraph.initBoard('488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    617      *   var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]);
    618      *   var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]);
    619      *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
    620      *   var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]);
    621      * </script><pre>
    622      */
    623     JXG.createParallelPoint = function (board, parents, attributes) {
    624         var a, b, c, p, i;
    625
    626         for (i = 0; i < parents.length; ++i) {
    627             parents[i] = board.select(parents[i]);
    628         }
    629         if (parents.length === 3 &&
    630                 Type.isPointType(board, parents[0]) &&
    631                 Type.isPointType(board, parents[1]) &&
    632                 Type.isPointType(board, parents[2])) {
    633             parents = Type.providePoints(board, parents, attributes, 'point');
    634             a = parents[0];
    635             b = parents[1];
    636             c = parents[2];
    637         } else if (Type.isPointType(board, parents[0]) &&
    638                 parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
    639             c = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    640             a = parents[1].point1;
    641             b = parents[1].point2;
    642         } else if (Type.isPointType(board, parents[1]) &&
    643                 parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
    644             c = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    645             a = parents[0].point1;
    646             b = parents[0].point2;
    647         } else {
    648             throw new Error("JSXGraph: Can't create parallel point with parent types '" +
    649                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    650                 "\nPossible parent types: [line,point], [point,point,point]");
    651         }
    652
    653         p = board.create('point', [
    654             function () {
    655                 return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1];
    656             },
    657             function () {
    658                 return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2];
    659             }
    660         ], attributes);
    661
    662         // required for algorithms requiring dependencies between elements
    663         a.addChild(p);
    664         b.addChild(p);
    665         c.addChild(p);
    666
    667         p.elType = 'parallelpoint';
    668         p.setParents([a.id, b.id, c.id]);
    669
    670         // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update.
    671         // can be removed if the above issue is resolved.
    672         p.prepareUpdate().update();
    673
    674         p.generatePolynomial = function () {
    675             /*
    676              *  Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T:
    677              *
    678              *
    679              *                     C (c1,c2)                             T (t1,t2)
    680              *                      x                                     x
    681              *                     /                                     /
    682              *                    /                                     /
    683              *                   /                                     /
    684              *                  /                                     /
    685              *                 /                                     /
    686              *                /                                     /
    687              *               /                                     /
    688              *              /                                     /
    689              *  L (opt)    /                                     /
    690              *  ----------x-------------------------------------x--------
    691              *            A (a1,a2)                             B (b1,b2)
    692              *
    693              * So we have two conditions:
    694              *
    695              *   (a)   CT  ||  AB           (collinearity condition I)
    696              *   (b)   BT  ||  AC           (collinearity condition II)
    697              *
    698              * The corresponding equations are
    699              *
    700              *    (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0         (1)
    701              *    (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0         (2)
    702              *
    703              * Simplifying (1) and (2) gives
    704              *
    705              *    b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0      (1')
    706              *    t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0      (2')
    707              *
    708              */
    709             var a1 = a.symbolic.x,
    710                 a2 = a.symbolic.y,
    711                 b1 = b.symbolic.x,
    712                 b2 = b.symbolic.y,
    713                 c1 = c.symbolic.x,
    714                 c2 = c.symbolic.y,
    715                 t1 = p.symbolic.x,
    716                 t2 = p.symbolic.y,
    717
    718                 poly1 =  '(' + b2 + ')*(' + t1 + ')-(' + b2 + ')*(' + c1 + ')-(' + a2 + ')*(' + t1 + ')+(' +
    719                     a2 + ')*(' + c1 + ')-(' + t2 + ')*(' + b1 + ')+(' + t2 + ')*(' + a1 + ')+(' + c2 + ')*(' +
    720                     b1 + ')-(' + c2 + ')*(' + a1 + ')',
    721                 poly2 =  '(' + t2 + ')*(' + a1 + ')-(' + t2 + ')*(' + c1 + ')-(' + b2 + ')*(' + a1 + ')+(' +
    722                     b2 + ')*(' + c1 + ')-(' + t1 + ')*(' + a2 + ')+(' + t1 + ')*(' + c2 + ')+(' + b1 + ')*(' +
    723                     a2 + ')-(' + b1 + ')*(' + c2 + ')';
    724
    725             return [poly1, poly2];
    726         };
    727
    728         return p;
    729     };
    730
    731
    732     /**
    733      * @class A parallel is a line through a given point with the same slope as a given line.
    734      * @pseudo
    735      * @name Parallel
    736      * @augments Line
    737      * @constructor
    738      * @type JXG.Line
    739      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    740      * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l.
    741      * @example
    742      * // Create a parallel
    743      * var p1 = board.create('point', [0.0, 2.0]);
    744      * var p2 = board.create('point', [2.0, 1.0]);
    745      * var l1 = board.create('line', [p1, p2]);
    746      *
    747      * var p3 = board.create('point', [3.0, 3.0]);
    748      * var pl1 = board.create('parallel', [l1, p3]);
    749      * </pre><div class="jxgbox" id="24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div>
    750      * <script type="text/javascript">
    751      *   var plex1_board = JXG.JSXGraph.initBoard('24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    752      *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
    753      *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
    754      *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
    755      *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
    756      *   var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);
    757      * </script><pre>
    758      */
    759     JXG.createParallel = function (board, parents, attributes) {
    760         var p, pp, pl, li, i, attr;
    761
    762         for (i = 0; i < parents.length; ++i) {
    763             parents[i] = board.select(parents[i]);
    764         }
    765         p = null;
    766         if (parents.length === 3) {
    767             parents = Type.providePoints(board, parents, attributes, 'point');
    768             // line through point parents[2] which is parallel to line through parents[0] and parents[1]
    769             p = parents[2];
    770             /** @ignore */
    771             li = function () {
    772                 return Mat.crossProduct(parents[0].coords.usrCoords, parents[1].coords.usrCoords);
    773             };
    774         } else if (Type.isPointType(board, parents[0])) {
    775             // Parallel to line parents[1] through point parents[0]
    776             p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    777             /** @ignore */
    778             li = function () {
    779                 return parents[1].stdform;
    780             };
    781         } else if (Type.isPointType(board, parents[1])) {
    782             // Parallel to line parents[0] through point parents[1]
    783             p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    784             /** @ignore */
    785             li = function () {
    786                 return parents[0].stdform;
    787             };
    788         }
    789
    790         if (!Type.exists(attributes.layer)) {
    791             attributes.layer = board.options.layer.line;
    792         }
    793
    794         attr = Type.copyAttributes(attributes, board.options, 'parallel', 'point');
    795         pp = board.create('point', [
    796             function () {
    797                 return Mat.crossProduct([1, 0, 0], li());
    798             }
    799         ], attr);
    800         pp.isDraggable = true;
    801
    802         attr = Type.copyAttributes(attributes, board.options, 'parallel');
    803         pl = board.create('line', [p, pp], attr);
    804
    805         pl.elType = 'parallel';
    806         pl.subs = {
    807             point: pp
    808         };
    809         pl.inherits.push(pp);
    810         pl.setParents([parents[0].id, parents[1].id]);
    811         if (parents.length === 3) {
    812             pl.addParents(parents[2].id);
    813         }
    814
    815         /**
    816          * Helper point used to create the parallel line. This point lies on the line at infinity, hence it's not visible,
    817          * not even with visible set to <tt>true</tt>. Creating another line through this point would make that other line
    818          * parallel to the create parallel.
    819          * @memberOf Parallel.prototype
    820          * @name point
    821          * @type JXG.Point
    822          */
    823         pl.point = pp;
    824
    825         return pl;
    826     };
    827
    828     /**
    829      * @class An arrow parallel is a parallel segment with an arrow attached.
    830      * @pseudo
    831      * @constructor
    832      * @name Arrowparallel
    833      * @type Parallel
    834      * @augments Parallel
    835      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    836      * @param {JXG.Line_JXG.Point} l,p The constructed arrow contains p and has the same slope as l.
    837      * @example
    838      * // Create a parallel
    839      * var p1 = board.create('point', [0.0, 2.0]);
    840      * var p2 = board.create('point', [2.0, 1.0]);
    841      * var l1 = board.create('line', [p1, p2]);
    842      *
    843      * var p3 = board.create('point', [3.0, 3.0]);
    844      * var pl1 = board.create('arrowparallel', [l1, p3]);
    845      * </pre><div class="jxgbox" id="eeacdf99-036f-4e83-aeb6-f7388423e369" style="width: 400px; height: 400px;"></div>
    846      * <script type="text/javascript">
    847      * (function () {
    848      *   var plex1_board = JXG.JSXGraph.initBoard('eeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    849      *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
    850      *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
    851      *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
    852      *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
    853      *   var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_l1, plex1_p3]);
    854      * })();
    855      * </script><pre>
    856      */
    857     JXG.createArrowParallel = function (board, parents, attributes) {
    858         var p;
    859
    860         /* parallel arrow point polynomials are done in createParallelPoint */
    861         try {
    862             attributes.firstArrow = false;
    863             attributes.lastArrow = true;
    864             p = JXG.createParallel(board, parents, attributes).setAttribute({straightFirst: false, straightLast: false});
    865             p.elType = 'arrowparallel';
    866
    867             // parents are set in createParallel
    868
    869             return p;
    870         } catch (e) {
    871             throw new Error("JSXGraph: Can't create arrowparallel with parent types '" +
    872                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    873                 "\nPossible parent types: [line,point], [point,point,point]");
    874         }
    875     };
    876
    877     /**
    878      * @class Constructs a normal.
    879      * @pseudo
    880      * @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.
    881      * @constructor
    882      * @name Normal
    883      * @type JXG.Line
    884      * @augments JXG.Line
    885      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    886      * @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
    887      * to the tangent to the object in the given point.
    888      * @param {Glider} p Works like above, however the object is given by {@link Glider#slideObject}.
    889      * @example
    890      * // Create a normal to a circle.
    891      * var p1 = board.create('point', [2.0, 2.0]);
    892      * var p2 = board.create('point', [3.0, 2.0]);
    893      * var c1 = board.create('circle', [p1, p2]);
    894      *
    895      * var norm1 = board.create('normal', [c1, p2]);
    896      * </pre><div class="jxgbox" id="4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div>
    897      * <script type="text/javascript">
    898      *   var nlex1_board = JXG.JSXGraph.initBoard('4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    899      *   var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]);
    900      *   var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]);
    901      *   var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]);
    902      *
    903      *   // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]);
    904      *   var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]);
    905      * </script><pre>
    906      */
    907     JXG.createNormal = function (board, parents, attributes) {
    908         var p, c, l, i, g, f, attr, pp, attrp;
    909
    910         for (i = 0; i < parents.length; ++i) {
    911             parents[i] = board.select(parents[i]);
    912         }
    913         // One arguments: glider on line, circle or curve
    914         if (parents.length === 1) {
    915             p = parents[0];
    916             c = p.slideObject;
    917         // Two arguments: (point,line), (point,circle), (line,point) or (circle,point)
    918         } else if (parents.length === 2) {
    919             if (Type.isPointType(board, parents[0])) {
    920                 p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    921                 c = parents[1];
    922             } else if (Type.isPointType(board, parents[1])) {
    923                 c = parents[0];
    924                 p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    925             } else {
    926                 throw new Error("JSXGraph: Can't create normal with parent types '" +
    927                     (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    928                     "\nPossible parent types: [point,line], [point,circle], [glider]");
    929             }
    930         } else {
    931             throw new Error("JSXGraph: Can't create normal with parent types '" +
    932                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    933                 "\nPossible parent types: [point,line], [point,circle], [glider]");
    934         }
    935
    936         attr = Type.copyAttributes(attributes, board.options, 'normal');
    937         if (c.elementClass === Const.OBJECT_CLASS_LINE) {
    938             // Private point
    939             attrp = Type.copyAttributes(attributes, board.options, 'normal', 'point');
    940             pp = board.create('point', [
    941                 function () {
    942                     var p = Mat.crossProduct([1, 0, 0], c.stdform);
    943                     return [p[0], -p[2], p[1]];
    944                 }
    945             ], attrp);
    946             pp.isDraggable = true;
    947
    948             l = board.create('line', [p, pp], attr);
    949
    950             /**
    951              * A helper point used to create a normal to a {@link JXG.Line} object. For normals to circles or curves this
    952              * element is <tt>undefined</tt>.
    953              * @type JXG.Point
    954              * @name point
    955              * @memberOf Normal.prototype
    956              */
    957             l.point = pp;
    958             l.subs = {
    959                 point: pp
    960             };
    961             l.inherits.push(pp);
    962         } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE) {
    963             l = board.create('line', [c.midpoint, p], attr);
    964         } else if (c.elementClass === Const.OBJECT_CLASS_CURVE) {
    965             if (Type.evaluate(c.visProp.curvetype) !== 'plot') {
    966                 g = c.X;
    967                 f = c.Y;
    968                 l = board.create('line', [
    969                     function () {
    970                         return -p.X() * Numerics.D(g)(p.position) - p.Y() * Numerics.D(f)(p.position);
    971                     },
    972                     function () {
    973                         return Numerics.D(g)(p.position);
    974                     },
    975                     function () {
    976                         return Numerics.D(f)(p.position);
    977                     }
    978                 ], attr);
    979             } else {                         // curveType 'plot'
    980                 l = board.create('line', [
    981                     function () {
    982                         var i = Math.floor(p.position),
    983                             lbda = p.position - i;
    984
    985                         if (i === c.numberPoints - 1) {
    986                             i -= 1;
    987                             lbda = 1;
    988                         }
    989
    990                         if (i < 0) {
    991                             return 1;
    992                         }
    993
    994                         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));
    995                     },
    996                     function () {
    997                         var i = Math.floor(p.position);
    998
    999                         if (i === c.numberPoints - 1) {
    1000                             i -= 1;
    1001                         }
    1002
    1003                         if (i < 0) {
    1004                             return 0;
    1005                         }
    1006
    1007                         return c.X(i + 1) - c.X(i);
    1008                     },
    1009                     function () {
    1010                         var i = Math.floor(p.position);
    1011
    1012                         if (i === c.numberPoints - 1) {
    1013                             i -= 1;
    1014                         }
    1015
    1016                         if (i < 0) {
    1017                             return 0;
    1018                         }
    1019
    1020                         return c.Y(i + 1) - c.Y(i);
    1021                     }
    1022                 ], attr);
    1023             }
    1024         } else if (c.type === Const.OBJECT_TYPE_TURTLE) {
    1025             l = board.create('line', [
    1026                 function () {
    1027                     var el, j,
    1028                         i = Math.floor(p.position),
    1029                         lbda = p.position - i;
    1030
    1031                     // run through all curves of this turtle
    1032                     for (j = 0; j < c.objects.length; j++) {
    1033                         el = c.objects[j];
    1034
    1035                         if (el.type === Const.OBJECT_TYPE_CURVE) {
    1036                             if (i < el.numberPoints) {
    1037                                 break;
    1038                             }
    1039
    1040                             i -= el.numberPoints;
    1041                         }
    1042                     }
    1043
    1044                     if (i === el.numberPoints - 1) {
    1045                         i -= 1;
    1046                         lbda = 1;
    1047                     }
    1048
    1049                     if (i < 0) {
    1050                         return 1;
    1051                     }
    1052
    1053                     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));
    1054                 },
    1055                 function () {
    1056                     var el, j,
    1057                         i = Math.floor(p.position);
    1058
    1059                     // run through all curves of this turtle
    1060                     for (j = 0; j < c.objects.length; j++) {
    1061                         el = c.objects[j];
    1062                         if (el.type === Const.OBJECT_TYPE_CURVE) {
    1063                             if (i < el.numberPoints) {
    1064                                 break;
    1065                             }
    1066
    1067                             i -= el.numberPoints;
    1068                         }
    1069                     }
    1070
    1071                     if (i === el.numberPoints - 1) {
    1072                         i -=  1;
    1073                     }
    1074
    1075                     if (i < 0) {
    1076                         return 0;
    1077                     }
    1078
    1079                     return el.X(i + 1) - el.X(i);
    1080                 },
    1081                 function () {
    1082                     var el, j,
    1083                         i = Math.floor(p.position);
    1084
    1085                     // run through all curves of this turtle
    1086                     for (j = 0; j < c.objects.length; j++) {
    1087                         el = c.objects[j];
    1088                         if (el.type === Const.OBJECT_TYPE_CURVE) {
    1089                             if (i < el.numberPoints) {
    1090                                 break;
    1091                             }
    1092
    1093                             i -= el.numberPoints;
    1094                         }
    1095                     }
    1096
    1097                     if (i === el.numberPoints - 1) {
    1098                         i -= 1;
    1099                     }
    1100
    1101                     if (i < 0) {
    1102                         return 0;
    1103                     }
    1104
    1105                     return el.Y(i + 1) - el.Y(i);
    1106                 }
    1107             ], attr);
    1108         } else {
    1109             throw new Error("JSXGraph: Can't create normal with parent types '" +
    1110                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1111                 "\nPossible parent types: [point,line], [point,circle], [glider]");
    1112         }
    1113
    1114         l.elType = 'normal';
    1115         l.setParents(parents);
    1116
    1117         return l;
    1118     };
    1119
    1120     /**
    1121      * @class A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and
    1122      * C and divides the angle ABC into two equal sized parts.
    1123      * @pseudo
    1124      * @constructor
    1125      * @name Bisector
    1126      * @type JXG.Line
    1127      * @augments JXG.Line
    1128      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1129      * @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
    1130      * be divided into two equal angles.
    1131      * @example
    1132      * var p1 = board.create('point', [6.0, 4.0]);
    1133      * var p2 = board.create('point', [3.0, 2.0]);
    1134      * var p3 = board.create('point', [1.0, 7.0]);
    1135      *
    1136      * var bi1 = board.create('bisector', [p1, p2, p3]);
    1137      * </pre><div class="jxgbox" id="0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div>
    1138      * <script type="text/javascript">
    1139      * (function () {
    1140      *   var board = JXG.JSXGraph.initBoard('0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1141      *   var p1 = board.create('point', [6.0, 4.0]);
    1142      *   var p2 = board.create('point', [3.0, 2.0]);
    1143      *   var p3 = board.create('point', [1.0, 7.0]);
    1144      *   var bi1 = board.create('bisector', [p1, p2, p3]);
    1145      * })();
    1146      * </script><pre>
    1147      */
    1148     JXG.createBisector = function (board, parents, attributes) {
    1149         var p, l, i, attr;
    1150
    1151         parents = Type.providePoints(board, parents, attributes, 'point');
    1152         if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {
    1153             // hidden and fixed helper
    1154             attr = Type.copyAttributes(attributes, board.options, 'bisector', 'point');
    1155             attr.snapToGrid = false;
    1156
    1157             p = board.create('point', [
    1158                 function () {
    1159                     return Geometry.angleBisector(parents[0], parents[1], parents[2], board);
    1160                 }
    1161             ], attr);
    1162             p.dump = false;
    1163
    1164             for (i = 0; i < 3; i++) {
    1165                 // required for algorithm requiring dependencies between elements
    1166                 parents[i].addChild(p);
    1167             }
    1168
    1169             if (!Type.exists(attributes.layer)) {
    1170                 attributes.layer = board.options.layer.line;
    1171             }
    1172
    1173             attr = Type.copyAttributes(attributes, board.options, 'bisector');
    1174             l = Line.createLine(board, [parents[1], p], attr);
    1175
    1176             /**
    1177              * Helper point
    1178              * @memberOf Bisector.prototype
    1179              * @type Point
    1180              * @name point
    1181              */
    1182             l.point = p;
    1183
    1184             l.elType = 'bisector';
    1185             l.setParents(parents);
    1186             l.subs = {
    1187                 point: p
    1188             };
    1189             l.inherits.push(p);
    1190
    1191             return l;
    1192         }
    1193
    1194         throw new Error("JSXGraph: Can't create angle bisector with parent types '" +
    1195             (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1196             "\nPossible parent types: [point,point,point]");
    1197     };
    1198
    1199     /**
    1200      * @class Bisector lines are similar to {@link Bisector} but takes two lines as parent elements. The resulting element is
    1201      * a composition of two lines.
    1202      * @pseudo
    1203      * @constructor
    1204      * @name Bisectorlines
    1205      * @type JXG.Composition
    1206      * @augments JXG.Composition
    1207      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1208      * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each
    1209      * be divided into two equal angles.
    1210      * @example
    1211      * var p1 = board.create('point', [6.0, 4.0]);
    1212      * var p2 = board.create('point', [3.0, 2.0]);
    1213      * var p3 = board.create('point', [1.0, 7.0]);
    1214      * var p4 = board.create('point', [3.0, 0.0]);
    1215      * var l1 = board.create('line', [p1, p2]);
    1216      * var l2 = board.create('line', [p3, p4]);
    1217      *
    1218      * var bi1 = board.create('bisectorlines', [l1, l2]);
    1219      * </pre><div class="jxgbox" id="3121ff67-44f0-4dda-bb10-9cda0b80bf18" style="width: 400px; height: 400px;"></div>
    1220      * <script type="text/javascript">
    1221      * (function () {
    1222      *   var board = JXG.JSXGraph.initBoard('3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1223      *   var p1 = board.create('point', [6.0, 4.0]);
    1224      *   var p2 = board.create('point', [3.0, 2.0]);
    1225      *   var p3 = board.create('point', [1.0, 7.0]);
    1226      *   var p4 = board.create('point', [3.0, 0.0]);
    1227      *   var l1 = board.create('line', [p1, p2]);
    1228      *   var l2 = board.create('line', [p3, p4]);
    1229      *   var bi1 = board.create('bisectorlines', [l1, l2]);
    1230      * })();
    1231      * </script><pre>
    1232      */
    1233     JXG.createAngularBisectorsOfTwoLines = function (board, parents, attributes) {
    1234         // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation:
    1235         // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2)
    1236
    1237         var g1, g2, attr, ret,
    1238             l1 = board.select(parents[0]),
    1239             l2 = board.select(parents[1]);
    1240
    1241         if (l1.elementClass !== Const.OBJECT_CLASS_LINE || l2.elementClass !== Const.OBJECT_CLASS_LINE) {
    1242             throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" +
    1243                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1244                 "\nPossible parent types: [line,line]");
    1245         }
    1246
    1247         if (!Type.exists(attributes.layer)) {
    1248             attributes.layer = board.options.layer.line;
    1249         }
    1250
    1251         attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line1');
    1252         g1 = board.create('line', [
    1253             function () {
    1254                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
    1255                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
    1256
    1257                 return l1.stdform[0] / d1 - l2.stdform[0] / d2;
    1258             },
    1259             function () {
    1260                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
    1261                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
    1262
    1263                 return l1.stdform[1] / d1 - l2.stdform[1] / d2;
    1264             },
    1265             function () {
    1266                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
    1267                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
    1268
    1269                 return l1.stdform[2] / d1 - l2.stdform[2] / d2;
    1270             }
    1271         ], attr);
    1272
    1273         if (!Type.exists(attributes.layer)) {
    1274             attributes.layer = board.options.layer.line;
    1275         }
    1276         attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line2');
    1277         g2 = board.create('line', [
    1278             function () {
    1279                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
    1280                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
    1281
    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                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
    1287
    1288                 return l1.stdform[1] / d1 + l2.stdform[1] / d2;
    1289             },
    1290             function () {
    1291                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
    1292                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
    1293
    1294                 return l1.stdform[2] / d1 + l2.stdform[2] / d2;
    1295             }
    1296         ], attr);
    1297
    1298         // documentation
    1299         /**
    1300          * First line.
    1301          * @memberOf Bisectorlines.prototype
    1302          * @name line1
    1303          * @type Line
    1304          */
    1305
    1306         /**
    1307          * Second line.
    1308          * @memberOf Bisectorlines.prototype
    1309          * @name line2
    1310          * @type Line
    1311          */
    1312
    1313         ret = new Composition({line1: g1, line2: g2});
    1314
    1315         g1.dump = false;
    1316         g2.dump = false;
    1317
    1318         ret.elType = 'bisectorlines';
    1319         ret.setParents([l1.id, l2.id]);
    1320         ret.subs = {
    1321             line1: g1,
    1322             line2: g2
    1323         };
    1324         ret.inherits.push(g1, g2);
    1325
    1326         return ret;
    1327     };
    1328
    1329     // /**
    1330     //  * @class An m-sector is a line which divides an angle into two angles. It is given by three points A, B, and
    1331     //  * C and a real number m, and divides an angle into two angles, an angle with amplitude m and an angle with
    1332     //  * amplitude (1-m)
    1333     //  * @pseudo
    1334     //  * @constructor
    1335     //  * @name Msector
    1336     //  * @type JXG.Line
    1337     //  * @augments JXG.Line
    1338     //  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1339     //  * @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
    1340     //  * be divided into two angles according to the value of <tt>m</tt>.
    1341     //  * @example
    1342     //  * var p1 = board.create('point', [6.0, 4.0]);
    1343     //  * var p2 = board.create('point', [3.0, 2.0]);
    1344     //  * var p3 = board.create('point', [1.0, 7.0]);
    1345     //  *
    1346     //  * var bi1 = board.create('msector', [p1, p2, p3], 1/5);
    1347     //  * </pre><div id="0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div>
    1348     //  * <script type="text/javascript">
    1349     //  * (function () {
    1350     //  *   var board = JXG.JSXGraph.initBoard('0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1351     //  *   var p1 = board.create('point', [6.0, 4.0]);
    1352     //  *   var p2 = board.create('point', [3.0, 2.0]);
    1353     //  *   var p3 = board.create('point', [1.0, 7.0]);
    1354     //  *   var bi1 = board.create('msector', [p1, p2, p3], 1/5);
    1355     //  * })();
    1356     //  * </script><pre>
    1357     //  */
    1358     // JXG.createMsector = function (board, parents, attributes) {
    1359     //     var p, l, i, attr;
    1360
    1361     //     if (parents[0].elementClass === Const.OBJECT_CLASS_POINT &&
    1362     //             parents[1].elementClass === Const.OBJECT_CLASS_POINT &&
    1363     //             parents[2].elementClass === Const.OBJECT_CLASS_POINT) {
    1364     //         // hidden and fixed helper
    1365     //         attr = Type.copyAttributes(attributes, board.options, 'msector', 'point');
    1366     //         p = board.create('point', [
    1367     //             function () {
    1368     //                 return Geometry.angleMsector(parents[0], parents[1], parents[2], parents[3], board);
    1369     //             }
    1370     //         ], attr);
    1371     //         p.dump = false;
    1372
    1373     //         for (i = 0; i < 3; i++) {
    1374     //             // required for algorithm requiring dependencies between elements
    1375     //             parents[i].addChild(p);
    1376     //         }
    1377
    1378     //         if (!Type.exists(attributes.layer)) {
    1379     //             attributes.layer = board.options.layer.line;
    1380     //         }
    1381
    1382     //         attr = Type.copyAttributes(attributes, board.options, 'msector');
    1383     //         l = Line.createLine(board, [parents[1], p], attr);
    1384
    1385     //         /**
    1386     //          * Helper point
    1387     //          * @memberOf Msector.prototype
    1388     //          * @type Point
    1389     //          * @name point
    1390     //          */
    1391     //         l.point = p;
    1392
    1393     //         l.elType = 'msector';
    1394     //         l.parents = [parents[0].id, parents[1].id, parents[2].id];
    1395     //         l.subs = {
    1396     //             point: p
    1397     //         };
    1398     //         l.inherits.push(p);
    1399
    1400     //         return l;
    1401     //     }
    1402
    1403     //     throw new Error("JSXGraph: Can't create angle msector with parent types '" +
    1404     //         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1405     //         "\nPossible parent types: [point,point,point,Number]");
    1406     // };
    1407
    1408     /**
    1409      * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter
    1410      * is constructed by providing three points.
    1411      * @pseudo
    1412      * @description A circumcenter is given by three points which are all lying on the circle with the
    1413      * constructed circumcenter as the midpoint.
    1414      * @constructor
    1415      * @name Circumcenter
    1416      * @type JXG.Point
    1417      * @augments JXG.Point
    1418      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1419      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined
    1420      * by p1, p2, and p3.
    1421      * @example
    1422      * var p1 = board.create('point', [0.0, 2.0]);
    1423      * var p2 = board.create('point', [2.0, 1.0]);
    1424      * var p3 = board.create('point', [3.0, 3.0]);
    1425      *
    1426      * var cc1 = board.create('circumcenter', [p1, p2, p3]);
    1427      * </pre><div class="jxgbox" id="e8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div>
    1428      * <script type="text/javascript">
    1429      *   var ccmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1430      *   var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]);
    1431      *   var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]);
    1432      *   var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]);
    1433      *   var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]);
    1434      * </script><pre>
    1435      */
    1436     JXG.createCircumcenter = function (board, parents, attributes) {
    1437         var p, i, a, b, c;
    1438
    1439         parents = Type.providePoints(board, parents, attributes, 'point');
    1440         if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {
    1441
    1442             a = parents[0];
    1443             b = parents[1];
    1444             c = parents[2];
    1445
    1446             p = Point.createPoint(board, [
    1447                 function () {
    1448                     return Geometry.circumcenter(a, b, c, board);
    1449                 }
    1450             ], attributes);
    1451
    1452             for (i = 0; i < 3; i++) {
    1453                 parents[i].addChild(p);
    1454             }
    1455
    1456             p.elType = 'circumcenter';
    1457             p.setParents(parents);
    1458
    1459             p.generatePolynomial = function () {
    1460                 /*
    1461                  *  CircumcircleMidpoint takes three points A, B and C  and creates point M, which is the circumcenter of A, B, and C.
    1462                  *
    1463                  *
    1464                  * So we have two conditions:
    1465                  *
    1466                  *   (a)   CT  ==  AT           (distance condition I)
    1467                  *   (b)   BT  ==  AT           (distance condition II)
    1468                  *
    1469                  */
    1470                 var a1 = a.symbolic.x,
    1471                     a2 = a.symbolic.y,
    1472                     b1 = b.symbolic.x,
    1473                     b2 = b.symbolic.y,
    1474                     c1 = c.symbolic.x,
    1475                     c2 = c.symbolic.y,
    1476                     t1 = p.symbolic.x,
    1477                     t2 = p.symbolic.y,
    1478
    1479                     poly1 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', b1, '))^2-((', t2, ')-(', b2, '))^2'].join(''),
    1480                     poly2 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', c1, '))^2-((', t2, ')-(', c2, '))^2'].join('');
    1481
    1482                 return [poly1, poly2];
    1483             };
    1484
    1485             return p;
    1486         }
    1487
    1488         throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" +
    1489             (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1490             "\nPossible parent types: [point,point,point]");
    1491     };
    1492
    1493     /**
    1494      * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html}
    1495      * @pseudo
    1496      * @constructor
    1497      * @name Incenter
    1498      * @type JXG.Point
    1499      * @augments JXG.Point
    1500      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1501      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described
    1502      * by p1, p2, and p3.
    1503      * @example
    1504      * var p1 = board.create('point', [0.0, 2.0]);
    1505      * var p2 = board.create('point', [2.0, 1.0]);
    1506      * var p3 = board.create('point', [3.0, 3.0]);
    1507      *
    1508      * var ic1 = board.create('incenter', [p1, p2, p3]);
    1509      * </pre><div class="jxgbox" id="e8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div>
    1510      * <script type="text/javascript">
    1511      *   var icmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1512      *   var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]);
    1513      *   var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]);
    1514      *   var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]);
    1515      *   var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]);
    1516      * </script><pre>
    1517      */
    1518     JXG.createIncenter = function (board, parents, attributes) {
    1519         var p, A, B, C;
    1520
    1521         parents = Type.providePoints(board, parents, attributes, 'point');
    1522         if (parents.length >= 3 && Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {
    1523             A = parents[0];
    1524             B = parents[1];
    1525             C = parents[2];
    1526
    1527             p = board.create('point', [function () {
    1528                 var a, b, c;
    1529
    1530                 a = Math.sqrt((B.X() - C.X()) * (B.X() - C.X()) + (B.Y() - C.Y()) * (B.Y() - C.Y()));
    1531                 b = Math.sqrt((A.X() - C.X()) * (A.X() - C.X()) + (A.Y() - C.Y()) * (A.Y() - C.Y()));
    1532                 c = Math.sqrt((B.X() - A.X()) * (B.X() - A.X()) + (B.Y() - A.Y()) * (B.Y() - A.Y()));
    1533
    1534                 return new Coords(Const.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);
    1535             }], attributes);
    1536
    1537             p.elType = 'incenter';
    1538             p.setParents(parents);
    1539
    1540         } else {
    1541             throw new Error("JSXGraph: Can't create incenter with parent types '" +
    1542                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1543                 "\nPossible parent types: [point,point,point]");
    1544         }
    1545
    1546         return p;
    1547     };
    1548
    1549     /**
    1550      * @class A circumcircle is given by three points which are all lying on the circle.
    1551      * @pseudo
    1552      * @constructor
    1553      * @name Circumcircle
    1554      * @type JXG.Circle
    1555      * @augments JXG.Circle
    1556      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1557      * @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>.
    1558      * @example
    1559      * var p1 = board.create('point', [0.0, 2.0]);
    1560      * var p2 = board.create('point', [2.0, 1.0]);
    1561      * var p3 = board.create('point', [3.0, 3.0]);
    1562      *
    1563      * var cc1 = board.create('circumcircle', [p1, p2, p3]);
    1564      * </pre><div class="jxgbox" id="e65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div>
    1565      * <script type="text/javascript">
    1566      *   var ccex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1567      *   var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]);
    1568      *   var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]);
    1569      *   var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]);
    1570      *   var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]);
    1571      * </script><pre>
    1572      */
    1573     JXG.createCircumcircle = function (board, parents, attributes) {
    1574         var p, c, attr;
    1575
    1576         parents = Type.providePoints(board, parents, attributes, 'point');
    1577         if (parents === false) {
    1578             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
    1579                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1580                 "\nPossible parent types: [point,point,point]");
    1581         }
    1582
    1583         try {
    1584             attr = Type.copyAttributes(attributes, board.options, 'circumcircle', 'center');
    1585             p = JXG.createCircumcenter(board, parents, attr);
    1586
    1587             p.dump = false;
    1588
    1589             if (!Type.exists(attributes.layer)) {
    1590                 attributes.layer = board.options.layer.circle;
    1591             }
    1592             attr = Type.copyAttributes(attributes, board.options, 'circumcircle');
    1593             c = Circle.createCircle(board, [p, parents[0]], attr);
    1594
    1595             c.elType = 'circumcircle';
    1596             c.setParents(parents);
    1597             c.subs = {
    1598                 center: p
    1599             };
    1600             c.inherits.push(c);
    1601         } catch (e) {
    1602             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
    1603                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1604                 "\nPossible parent types: [point,point,point]");
    1605         }
    1606
    1607         // p is already stored as midpoint in c so there's no need to store it explicitly.
    1608
    1609         return c;
    1610     };
    1611
    1612     /**
    1613      * @class An incircle is given by three points.
    1614      * @pseudo
    1615      * @constructor
    1616      * @name Incircle
    1617      * @type JXG.Circle
    1618      * @augments JXG.Circle
    1619      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1620      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of
    1621      * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.
    1622      * @example
    1623      * var p1 = board.create('point', [0.0, 2.0]);
    1624      * var p2 = board.create('point', [2.0, 1.0]);
    1625      * var p3 = board.create('point', [3.0, 3.0]);
    1626      *
    1627      * var ic1 = board.create('incircle', [p1, p2, p3]);
    1628      * </pre><div class="jxgbox" id="e65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div>
    1629      * <script type="text/javascript">
    1630      *   var icex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1631      *   var icex1_p1 = icex1_board.create('point', [0.0, 2.0]);
    1632      *   var icex1_p2 = icex1_board.create('point', [6.0, 1.0]);
    1633      *   var icex1_p3 = icex1_board.create('point', [3.0, 7.0]);
    1634      *   var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]);
    1635      * </script><pre>
    1636      */
    1637     JXG.createIncircle = function (board, parents, attributes) {
    1638         var p, c, attr;
    1639
    1640         parents = Type.providePoints(board, parents, attributes, 'point');
    1641         if (parents === false) {
    1642             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
    1643                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1644                 "\nPossible parent types: [point,point,point]");
    1645         }
    1646         try {
    1647             attr = Type.copyAttributes(attributes, board.options, 'incircle', 'center');
    1648             p = JXG.createIncenter(board, parents, attr);
    1649
    1650             p.dump = false;
    1651
    1652             if (!Type.exists(attributes.layer)) {
    1653                 attributes.layer = board.options.layer.circle;
    1654             }
    1655             attr = Type.copyAttributes(attributes, board.options, 'incircle');
    1656             c = Circle.createCircle(board, [p, function () {
    1657                 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())),
    1658                     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())),
    1659                     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())),
    1660                     s = (a + b + c) / 2;
    1661
    1662                 return Math.sqrt(((s - a) * (s - b) * (s - c)) / s);
    1663             }], attr);
    1664
    1665             c.elType = 'incircle';
    1666             c.setParents(parents);
    1667
    1668             /**
    1669              * The center of the incircle
    1670              * @memberOf Incircle.prototype
    1671              * @type Incenter
    1672              * @name center
    1673              */
    1674             c.center = p;
    1675
    1676             c.subs = {
    1677                 center: c.center
    1678             };
    1679             c.inherits.push(p);
    1680
    1681         } catch (e) {
    1682             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
    1683                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
    1684                 "\nPossible parent types: [point,point,point]");
    1685         }
    1686
    1687         // p is already stored as midpoint in c so there's no need to store it explicitly.
    1688
    1689         return c;
    1690     };
    1691
    1692     /**
    1693      * @class This element is used to construct a reflected point.
    1694      * @pseudo
    1695      * @description A reflected element (point, line or curve) is given by a given
    1696      * object of the same type and a line of reflection.
    1697      * It is determined by the reflection of the given element
    1698      * across the given line.
    1699      * @constructor
    1700      * @name Reflection
    1701      * @type JXG.GeometryElement
    1702      * @augments JXG.GeometryElement
    1703      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1704      * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Polygon_JXG.Line} p,l The reflection element is the reflection of p across the line l.
    1705      * @example
    1706      * var p1 = board.create('point', [0.0, 4.0]);
    1707      * var p2 = board.create('point', [6.0, 1.0]);
    1708      * var l1 = board.create('line', [p1, p2]);
    1709      * var p3 = board.create('point', [3.0, 3.0]);
    1710      *
    1711      * var rp1 = board.create('reflection', [p3, l1]);
    1712      * </pre><div class="jxgbox" id="087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div>
    1713      * <script type="text/javascript">
    1714      *   var rpex1_board = JXG.JSXGraph.initBoard('087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1715      *   var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]);
    1716      *   var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]);
    1717      *   var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]);
    1718      *   var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]);
    1719      *   var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]);
    1720      * </script><pre>
    1721      * @example
    1722      *         // Reflection of more elements
    1723      *         // reflection line
    1724      *         var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});
    1725      *         var reflect = board.create('transform', [li], {type: 'reflect'});
    1726      *
    1727      *         var p1 = board.create('point', [-3,-1], {name: "A"});
    1728      *         var q1 = board.create('reflection', [p1, li], {name: "A'"});
    1729      *
    1730      *         var l1 = board.create('line', [1,-5,1]);
    1731      *         var l2 = board.create('reflection', [l1, li]);
    1732      *
    1733      *         var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]);
    1734      *         var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red'});
    1735      *
    1736      *         var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]);
    1737      *         var pol2 = board.create('reflection', [pol1, li]);
    1738      * </pre><div id="8f763af4-d449-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div>
    1739      * <script type="text/javascript">
    1740      *     (function() {
    1741      *         var board = JXG.JSXGraph.initBoard('8f763af4-d449-11e7-93b3-901b0e1b8723',
    1742      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
    1743      *             // reflection line
    1744      *             var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});
    1745      *             var reflect = board.create('transform', [li], {type: 'reflect'});
    1746      *
    1747      *             var p1 = board.create('point', [-3,-1], {name: "A"});
    1748      *             var q1 = board.create('reflection', [p1, li], {name: "A'"});
    1749      *
    1750      *             var l1 = board.create('line', [1,-5,1]);
    1751      *             var l2 = board.create('reflection', [l1, li]);
    1752      *
    1753      *             var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]);
    1754      *             var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red'});
    1755      *
    1756      *             var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]);
    1757      *             var pol2 = board.create('reflection', [pol1, li]);
    1758      *     })();
    1759      *
    1760      * </script><pre>
    1761      *
    1762      */
    1763     JXG.createReflection = function (board, parents, attributes) {
    1764         var l, org, r, t, i;
    1765
    1766         for (i = 0; i < parents.length; ++i) {
    1767             parents[i] = board.select(parents[i]);
    1768         }
    1769
    1770         if (Type.isPoint(parents[0])) {
    1771             org = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    1772         } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE ||
    1773                     parents[0].elementClass === Const.OBJECT_CLASS_LINE ||
    1774                     parents[0].type === Const.OBJECT_TYPE_POLYGON) {
    1775             org = parents[0];
    1776         } else {
    1777             throw new Error("JSXGraph: Can't create reflection element with parent types '" +
    1778                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1779                 "\nPossible parent types: [point|line|curve|polygon, line]");
    1780         }
    1781
    1782         if (parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
    1783             l = parents[1];
    1784         } else {
    1785             throw new Error("JSXGraph: Can't create reflected element with parent types '" +
    1786                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1787                 "\nPossible parent types: [point|line|curve|polygon, line]");
    1788         }
    1789
    1790         t = Transform.createTransform(board, [l], {type: 'reflect'});
    1791         if (Type.isPoint(org)) {
    1792             r = Point.createPoint(board, [org, t], attributes);
    1793         } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){
    1794             r = Curve.createCurve(board, [org, t], attributes);
    1795         } else if (org.elementClass === Const.OBJECT_CLASS_LINE){
    1796             r = Line.createLine(board, [org, t], attributes);
    1797         }  else if (org.type === Const.OBJECT_TYPE_POLYGON){
    1798             r = Line.createPolygon(board, [org, t], attributes);
    1799         } else {
    1800             throw new Error("JSXGraph: Can't create reflected element with parent types '" +
    1801                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1802                 "\nPossible parent types: [point|line|curve|polygon, line]");
    1803         }
    1804         org.addChild(r);
    1805         l.addChild(r);
    1806         r.elType = 'reflection';
    1807         r.setParents([org, l]);
    1808         r.prepareUpdate().update();
    1809
    1810         if (Type.isPoint(r)) {
    1811             r.generatePolynomial = function () {
    1812                 /*
    1813                  *  Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.
    1814                  *  L is defined by two points A and B.
    1815                  *
    1816                  * So we have two conditions:
    1817                  *
    1818                  *   (a)   RP  _|_  AB            (orthogonality condition)
    1819                  *   (b)   AR  ==   AP            (distance condition)
    1820                  *
    1821                  */
    1822                 var a1 = l.point1.symbolic.x,
    1823                     a2 = l.point1.symbolic.y,
    1824                     b1 = l.point2.symbolic.x,
    1825                     b2 = l.point2.symbolic.y,
    1826                     p1 = org.symbolic.x,
    1827                     p2 = org.symbolic.y,
    1828                     r1 = r.symbolic.x,
    1829                     r2 = r.symbolic.y,
    1830
    1831                     poly1 = ['((', r2, ')-(', p2, '))*((', a2, ')-(', b2, '))+((', a1, ')-(', b1, '))*((', r1, ')-(', p1, '))'].join(''),
    1832                     poly2 = ['((', r1, ')-(', a1, '))^2+((', r2, ')-(', a2, '))^2-((', p1, ')-(', a1, '))^2-((', p2, ')-(', a2, '))^2'].join('');
    1833
    1834                 return [poly1, poly2];
    1835             };
    1836         }
    1837
    1838         return r;
    1839     };
    1840
    1841     /**
    1842      * @class A mirror element will be constructed.
    1843      * @pseudo
    1844      * @description A mirror element is determined by the reflection of a given point across another given point.
    1845      * @constructor
    1846      * @name Mirrorelement
    1847      * @type JXG.GeometryElement
    1848      * @augments JXG.GeometryElement
    1849      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1850      * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Ppolygon_JXG.Point} p1,p2 The constructed element is the mirror image of p2 across p1.
    1851      * @example
    1852      *         // point of reflection
    1853      *         var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});
    1854      *         var t = board.create('transform', [Math.PI, mirr], {type: 'rotate'});
    1855      *
    1856      *         var p1 = board.create('point', [-3,-1], {name: "A"});
    1857      *         var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"});
    1858      *
    1859      *         var l1 = board.create('line', [1,-5,1]);
    1860      *         var l2 = board.create('mirrorelement', [l1, mirr]);
    1861      *
    1862      *         var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]);
    1863      *         var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red'});
    1864      *
    1865      *         var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]);
    1866      *         var pol2 = board.create('mirrorelement', [pol1, mirr]);
    1867      *
    1868      * </pre><div id="026c779c-d8d9-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div>
    1869      * <script type="text/javascript">
    1870      *     (function() {
    1871      *         var board = JXG.JSXGraph.initBoard('026c779c-d8d9-11e7-93b3-901b0e1b8723',
    1872      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
    1873      *             // point of reflection
    1874      *             var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});
    1875      *             var t = board.create('transform', [Math.PI, mirr], {type: 'rotate'});
    1876      *
    1877      *             var p1 = board.create('point', [-3,-1], {name: "A"});
    1878      *             var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"});
    1879      *
    1880      *             var l1 = board.create('line', [1,-5,1]);
    1881      *             var l2 = board.create('mirrorelement', [l1, mirr]);
    1882      *
    1883      *             var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]);
    1884      *             var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red'});
    1885      *
    1886      *             var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]);
    1887      *             var pol2 = board.create('mirrorelement', [pol1, mirr]);
    1888      *
    1889      *
    1890      *     })();
    1891      *
    1892      * </script><pre>
    1893      */
    1894     JXG.createMirrorElement = function (board, parents, attributes) {
    1895         var org, m, r, t;
    1896
    1897         if (Type.isPoint(parents[0])) {
    1898             org = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
    1899         } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE ||
    1900                     parents[0].elementClass === Const.OBJECT_CLASS_LINE ||
    1901                     parents[0].type === Const.OBJECT_TYPE_POLYGON) {
    1902             org = parents[0];
    1903         } else {
    1904             throw new Error("JSXGraph: Can't create mirrot element with parent types '" +
    1905                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1906                 "\nPossible parent types: [point|line|curve|polygon, line]");
    1907         }
    1908
    1909         if (Type.isPoint(parents[1])) {
    1910             m = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
    1911         } else {
    1912             throw new Error("JSXGraph: Can't create mirror element with parent types '" +
    1913                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1914                 "\nPossible parent types: [point|line|curve|polygon, line]");
    1915         }
    1916
    1917         t = Transform.createTransform(board, [Math.PI, m], {type: 'rotate'});
    1918         if (Type.isPoint(org)) {
    1919             r = Point.createPoint(board, [org, t], attributes);
    1920         } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){
    1921             r = Curve.createCurve(board, [org, t], attributes);
    1922         } else if (org.elementClass === Const.OBJECT_CLASS_LINE){
    1923             r = Line.createLine(board, [org, t], attributes);
    1924         }  else if (org.type === Const.OBJECT_TYPE_POLYGON){
    1925             r = Line.createPolygon(board, [org, t], attributes);
    1926         } else {
    1927             throw new Error("JSXGraph: Can't create mirror point with parent types '" +
    1928                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    1929                 "\nPossible parent types: [point|line|curve|polygon, line]");
    1930         }
    1931
    1932         org.addChild(r);
    1933         m.addChild(r);
    1934         r.elType = 'mirrorpoint';
    1935         r.setParents([org, m]);
    1936         r.prepareUpdate().update();
    1937
    1938         return r;
    1939     };
    1940
    1941     /**
    1942      * @class A mirror point will be constructed.
    1943      * @pseudo
    1944      * @description A mirror point is determined by the reflection of a given point against another given point.
    1945      * @constructor
    1946      * @name Mirrorpoint
    1947      * @type JXG.Point
    1948      * @augments JXG.Point
    1949      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1950      * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.
    1951      *
    1952      * This method is superseeded by the more general {@link JXG.createMirrorElement}.
    1953      * @example
    1954      * var p1 = board.create('point', [3.0, 3.0]);
    1955      * var p2 = board.create('point', [6.0, 1.0]);
    1956      *
    1957      * var mp1 = board.create('mirrorpoint', [p1, p2]);
    1958      * </pre><div class="jxgbox" id="7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div>
    1959      * <script type="text/javascript">
    1960      *   var mpex1_board = JXG.JSXGraph.initBoard('7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    1961      *   var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);
    1962      *   var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);
    1963      *   var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);
    1964      * </script><pre>
    1965      */
    1966     JXG.createMirrorPoint = function (board, parents, attributes) {
    1967         return JXG.createMirrorElement(board, parents, attributes);
    1968     };
    1969
    1970     /**
    1971      * @class This element is used to visualize the integral of a given curve over a given interval.
    1972      * @pseudo
    1973      * @description The Integral element is used to visualize the area under a given curve over a given interval
    1974      * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,
    1975      * the gliders are used to change the interval dynamically.
    1976      * @constructor
    1977      * @name Integral
    1978      * @type JXG.Curve
    1979      * @augments JXG.Curve
    1980      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    1981      * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis
    1982      * within the interval <tt>i</tt>.
    1983      * @example
    1984      * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);
    1985      * var i1 = board.create('integral', [[-1.0, 4.0], c1]);
    1986      * </pre><div class="jxgbox" id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
    1987      * <script type="text/javascript">
    1988      *   var intex1_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});
    1989      *   var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]);
    1990      *   var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);
    1991      * </script><pre>
    1992      */
    1993     JXG.createIntegral = function (board, parents, attributes) {
    1994         var interval, curve, attr,
    1995             start, end, startx, starty, endx, endy,
    1996             pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,
    1997             t = null, p;
    1998
    1999         if (Type.isArray(parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_CURVE) {
    2000             interval = parents[0];
    2001             curve = parents[1];
    2002         } else if (Type.isArray(parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_CURVE) {
    2003             interval = parents[1];
    2004             curve = parents[0];
    2005         } else {
    2006             throw new Error("JSXGraph: Can't create integral with parent types '" +
    2007                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    2008                 "\nPossible parent types: [[number|function,number|function],curve]");
    2009         }
    2010
    2011         attr = Type.copyAttributes(attributes, board.options, 'integral');
    2012         attr.withLabel = false;  // There is a custom 'label' below.
    2013         p = board.create('curve', [[0], [0]], attr);
    2014
    2015         // Correct the interval if necessary - NOT ANYMORE, GGB's fault
    2016         start = interval[0];
    2017         end = interval[1];
    2018
    2019         if (Type.isFunction(start)) {
    2020             startx = start;
    2021             starty = function () { return curve.Y(startx()); };
    2022             start = startx();
    2023         } else {
    2024             startx = start;
    2025             starty = curve.Y(start);
    2026         }
    2027
    2028         if (Type.isFunction(end)) {
    2029             endx = end;
    2030             endy = function () { return curve.Y(endx()); };
    2031             end = endx();
    2032         } else {
    2033             endx = end;
    2034             endy = curve.Y(end);
    2035         }
    2036
    2037         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveLeft');
    2038         pa_on_curve = board.create('glider', [startx, starty, curve], attr);
    2039         if (Type.isFunction(startx)) {
    2040             pa_on_curve.hideElement();
    2041         }
    2042
    2043         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseLeft');
    2044         pa_on_axis = board.create('point', [
    2045             function () {
    2046                 if (Type.evaluate(p.visProp.axis) === 'y') {
    2047                     return 0;
    2048                 }
    2049
    2050                 return pa_on_curve.X();
    2051             },
    2052             function () {
    2053                 if (Type.evaluate(p.visProp.axis) === 'y') {
    2054                     return pa_on_curve.Y();
    2055                 }
    2056
    2057                 return 0;
    2058             }
    2059         ], attr);
    2060
    2061         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveRight');
    2062         pb_on_curve = board.create('glider', [endx, endy, curve], attr);
    2063         if (Type.isFunction(endx)) {
    2064             pb_on_curve.hideElement();
    2065         }
    2066
    2067         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseRight');
    2068         pb_on_axis = board.create('point', [
    2069             function () {
    2070                 if (Type.evaluate(p.visProp.axis) === 'y') {
    2071                     return 0;
    2072                 }
    2073                 return pb_on_curve.X();
    2074             },
    2075             function () {
    2076                 if (Type.evaluate(p.visProp.axis) === 'y') {
    2077                     return pb_on_curve.Y();
    2078                 }
    2079
    2080                 return 0;
    2081             }
    2082         ], attr);
    2083
    2084         attr = Type.copyAttributes(attributes, board.options, 'integral');
    2085         if (attr.withlabel !== false && attr.axis !== 'y') {
    2086             attr = Type.copyAttributes(attributes, board.options, 'integral', 'label');
    2087             attr = Type.copyAttributes(attr, board.options, 'label');
    2088
    2089             t = board.create('text', [
    2090                 function () {
    2091                     var off = new Coords(Const.COORDS_BY_SCREEN, [
    2092                             Type.evaluate(this.visProp.offset[0]) + this.board.origin.scrCoords[1],
    2093                             0
    2094                         ], this.board, false),
    2095                         bb = this.board.getBoundingBox(),
    2096                         dx = (bb[2] - bb[0]) * 0.1,
    2097                         x = pb_on_curve.X();
    2098
    2099                     if (x < bb[0]) {
    2100                         x = bb[0] + dx;
    2101                     } else if (x > bb[2]) {
    2102                         x = bb[2] - dx;
    2103                     }
    2104
    2105                     return x + off.usrCoords[1];
    2106                 },
    2107                 function () {
    2108                     var off = new Coords(Const.COORDS_BY_SCREEN, [
    2109                             0,
    2110                             Type.evaluate(this.visProp.offset[1]) + this.board.origin.scrCoords[2]
    2111                         ], this.board, false),
    2112                         bb = this.board.getBoundingBox(),
    2113                         dy = (bb[1] - bb[3]) * 0.1,
    2114                         y = pb_on_curve.Y();
    2115
    2116                     if (y > bb[1]) {
    2117                         y = bb[1] - dy;
    2118                     } else if (y < bb[3]) {
    2119                         y = bb[3] + dy;
    2120                     }
    2121
    2122                     return y + off.usrCoords[2];
    2123                 },
    2124                 function () {
    2125                     var Int = Numerics.NewtonCotes([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
    2126                     return '∫ = ' + Type.toFixed(Int, 4);
    2127                 }
    2128             ], attr);
    2129
    2130             t.dump = false;
    2131
    2132             pa_on_curve.addChild(t);
    2133             pb_on_curve.addChild(t);
    2134         }
    2135
    2136         // dump stuff
    2137         pa_on_curve.dump = false;
    2138         pa_on_axis.dump = false;
    2139
    2140         pb_on_curve.dump = false;
    2141         pb_on_axis.dump = false;
    2142
    2143         p.elType = 'integral';
    2144         p.setParents([curve.id, interval]);
    2145         p.subs = {
    2146             curveLeft: pa_on_curve,
    2147             baseLeft: pa_on_axis,
    2148             curveRight: pb_on_curve,
    2149             baseRight: pb_on_axis
    2150         };
    2151         p.inherits.push(pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis);
    2152
    2153         if (attr.withLabel) {
    2154             p.subs.label = t;
    2155             p.inherits.push(t);
    2156         }
    2157
    2158         /** @ignore */
    2159         p.Value = function () {
    2160             return Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
    2161         };
    2162
    2163         /**
    2164          * documented in JXG.Curve
    2165          * @ignore
    2166          */
    2167         p.updateDataArray = function () {
    2168             var x, y,
    2169                 i, left, right,
    2170                 lowx, upx,
    2171                 lowy, upy;
    2172
    2173             if (Type.evaluate(this.visProp.axis) === 'y') {
    2174                 if (pa_on_curve.Y() < pb_on_curve.Y()) {
    2175                     lowx = pa_on_curve.X();
    2176                     lowy = pa_on_curve.Y();
    2177                     upx = pb_on_curve.X();
    2178                     upy = pb_on_curve.Y();
    2179                 } else {
    2180                     lowx = pb_on_curve.X();
    2181                     lowy = pb_on_curve.Y();
    2182                     upx = pa_on_curve.X();
    2183                     upy = pa_on_curve.Y();
    2184                 }
    2185                 left = Math.min(lowx, upx);
    2186                 right = Math.max(lowx, upx);
    2187
    2188                 x = [0, lowx];
    2189                 y = [lowy, lowy];
    2190
    2191                 for (i = 0; i < curve.numberPoints; i++) {
    2192                     if (lowy <= curve.points[i].usrCoords[2] &&
    2193                             left <= curve.points[i].usrCoords[1] &&
    2194                             curve.points[i].usrCoords[2] <= upy  &&
    2195                             curve.points[i].usrCoords[1] <= right) {
    2196                         x.push(curve.points[i].usrCoords[1]);
    2197                         y.push(curve.points[i].usrCoords[2]);
    2198                     }
    2199                 }
    2200                 x.push(upx);
    2201                 y.push(upy);
    2202                 x.push(0);
    2203                 y.push(upy);
    2204
    2205                 // close the curve
    2206                 x.push(0);
    2207                 y.push(lowy);
    2208             } else {
    2209                 if (pa_on_axis.X() < pb_on_axis.X()) {
    2210                     left = pa_on_axis.X();
    2211                     right = pb_on_axis.X();
    2212                 } else {
    2213                     left = pb_on_axis.X();
    2214                     right = pa_on_axis.X();
    2215                 }
    2216
    2217                 x = [left, left];
    2218                 y = [0, curve.Y(left)];
    2219
    2220                 for (i = 0; i < curve.numberPoints; i++) {
    2221                     if ((left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right)) {
    2222                         x.push(curve.points[i].usrCoords[1]);
    2223                         y.push(curve.points[i].usrCoords[2]);
    2224                     }
    2225                 }
    2226                 x.push(right);
    2227                 y.push(curve.Y(right));
    2228                 x.push(right);
    2229                 y.push(0);
    2230
    2231                 // close the curve
    2232                 x.push(left);
    2233                 y.push(0);
    2234             }
    2235
    2236             this.dataX = x;
    2237             this.dataY = y;
    2238         };
    2239
    2240         pa_on_curve.addChild(p);
    2241         pb_on_curve.addChild(p);
    2242         pa_on_axis.addChild(p);
    2243         pb_on_axis.addChild(p);
    2244
    2245         /**
    2246          * The point on the axis initially corresponding to the lower value of the interval.
    2247          *
    2248          * @name baseLeft
    2249          * @memberOf Integral
    2250          * @type JXG.Point
    2251          */
    2252         p.baseLeft = pa_on_axis;
    2253
    2254         /**
    2255          * The point on the axis initially corresponding to the higher value of the interval.
    2256          *
    2257          * @name baseRight
    2258          * @memberOf Integral
    2259          * @type JXG.Point
    2260          */
    2261         p.baseRight = pb_on_axis;
    2262
    2263         /**
    2264          * The glider on the curve corresponding to the lower value of the interval.
    2265          *
    2266          * @name curveLeft
    2267          * @memberOf Integral
    2268          * @type Glider
    2269          */
    2270         p.curveLeft = pa_on_curve;
    2271
    2272         /**
    2273          * The glider on the axis corresponding to the higher value of the interval.
    2274          *
    2275          * @name curveRight
    2276          * @memberOf Integral
    2277          * @type Glider
    2278          */
    2279         p.curveRight = pb_on_curve;
    2280
    2281         p.methodMap = JXG.deepCopy(p.methodMap, {
    2282             curveLeft: 'curveLeft',
    2283             baseLeft: 'baseLeft',
    2284             curveRight: 'curveRight',
    2285             baseRight: 'baseRight',
    2286             Value: 'Value'
    2287         });
    2288
    2289         /**
    2290          * documented in GeometryElement
    2291          * @ignore
    2292          */
    2293         p.label = t;
    2294
    2295         return p;
    2296     };
    2297
    2298     /**
    2299      * @class Creates a grid to support the user with element placement.
    2300      * @pseudo
    2301      * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method
    2302      * draws such a grid on the given board. It uses options given in {@link JXG.Options#grid}. This method does not
    2303      * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set
    2304      * to true.
    2305      * @parameter None.
    2306      * @constructor
    2307      * @name Grid
    2308      * @type JXG.Curve
    2309      * @augments JXG.Curve
    2310      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    2311      * @example
    2312      * grid = board.create('grid', []);
    2313      * </pre><div class="jxgbox" id="a9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div>
    2314      * <script type="text/javascript">
    2315      * (function () {
    2316      *  board = JXG.JSXGraph.initBoard('a9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
    2317      *  grid = board.create('grid', []);
    2318      * })();
    2319      * </script><pre>
    2320      */
    2321     JXG.createGrid = function (board, parents, attributes) {
    2322         var c, attr;
    2323
    2324         attr = Type.copyAttributes(attributes, board.options, 'grid');
    2325         c = board.create('curve', [[null], [null]], attr);
    2326
    2327         c.elType = 'grid';
    2328         c.type = Const.OBJECT_TYPE_GRID;
    2329
    2330         c.updateDataArray = function () {
    2331             var start, end, i, topLeft, bottomRight,
    2332                 gridX = Type.evaluate(this.visProp.gridx),
    2333                 gridY = Type.evaluate(this.visProp.gridy);
    2334
    2335             if (Type.isArray(this.visProp.topleft)) {
    2336                 topLeft = new Coords(Type.evaluate(this.visProp.tltype) || Const.COORDS_BY_USER,
    2337                                     this.visProp.topleft, board);
    2338             } else {
    2339                 topLeft = new Coords(Const.COORDS_BY_SCREEN, [0, 0], board);
    2340             }
    2341
    2342             if (Type.isArray(this.visProp.bottomright)) {
    2343                 bottomRight = new Coords(Type.evaluate(this.visProp.brtype) || Const.COORDS_BY_USER,
    2344                                     this.visProp.bottomright, board);
    2345             } else {
    2346                 bottomRight = new Coords(Const.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board);
    2347             }
    2348
    2349
    2350             //
    2351             //      |         |         |
    2352             //  ----+---------+---------+-----
    2353             //      |        /|         |
    2354             //      |    gridY|     <---+------   Grid Cell
    2355             //      |        \|         |
    2356             //  ----+---------+---------+-----
    2357             //      |         |\ gridX /|
    2358             //      |         |         |
    2359             //
    2360             // uc: usercoordinates
    2361             //
    2362             // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high.
    2363             // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it
    2364             // is absolutely not user friendly when it comes to use it as an API interface.
    2365             // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i
    2366             // had to refactor these methods:
    2367             //
    2368             //  DONE JXG.Board.calculateSnapSizes (init p1, p2)
    2369             //  DONE JXG.GeonextReader.readGeonext (init gridX, gridY)
    2370             //
    2371
    2372             board.options.grid.hasGrid = true;
    2373
    2374 			// fix_grid: adding integer function to calculation of start and end values, and adding to calculation of start and end values below
    2375 			// To allow this:
    2376 			// (axes on the outside, min value of grid = 0.25)
    2377             //
    2378             //      |    |         |          |
    2379             // 1.5 -+----+---------+----------+-----
    2380             //      |    |         |          |
    2381             //      |    |         |          |
    2382             //      |    |         |          |
    2383             //   1 -+----+---------+----------+-----
    2384             //      |    |         |          |
    2385             //      |    |         |          |
    2386             //      |    |         |          |
    2387             // 0.5 -+----+---------+----------+-----
    2388             //      |    |         |          |
    2389             //      +----+---------+----------+-----
    2390             //           |         |          |
    2391             //          0.5        1         1.5
    2392             //
    2393             // fix_grid: these lines disabled:
    2394             // topLeft.setCoordinates(Const.COORDS_BY_USER, [Math.ceil(topLeft.usrCoords[1] / gridX) * gridX, Math.floor(topLeft.usrCoords[2] / gridY) * gridY]);
    2395             // bottomRight.setCoordinates(Const.COORDS_BY_USER, [Math.floor(bottomRight.usrCoords[1] / gridX) * gridX, Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY]);
    2396
    2397             c.dataX = [];
    2398             c.dataY = [];
    2399
    2400             // Sometimes the bounding box is used to invert the axis. We have to take this into account here.
    2401             // fix_grid: adding integer function to calculation of start and end values
    2402             start = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;
    2403             end = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY;
    2404
    2405             if (topLeft.usrCoords[2] < bottomRight.usrCoords[2]) {
    2406                 start = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; // bottomRight.usrCoords[2];
    2407                 end = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;
    2408             }
    2409
    2410             // start with the horizontal grid:
    2411             for (i = start; i > end - gridY; i -= gridY) {
    2412                 c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN);
    2413                 c.dataY.push(i, i, NaN);
    2414             }
    2415
    2416             // fix_grid: adding integer function to calculation of start and end values
    2417             start = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;
    2418             end = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;
    2419
    2420             if (topLeft.usrCoords[1] > bottomRight.usrCoords[1]) {
    2421 				start = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;
    2422 				end = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;
    2423             }
    2424
    2425             // build vertical grid
    2426             for (i = start; i < end + gridX; i += gridX) {
    2427                 c.dataX.push(i, i, NaN);
    2428                 c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN);
    2429             }
    2430
    2431         };
    2432
    2433         // we don't care about highlighting so we turn it off completely to save a lot of
    2434         // time on every mouse move
    2435         c.hasPoint = function () {
    2436             return false;
    2437         };
    2438
    2439         board.grids.push(c);
    2440
    2441         return c;
    2442     };
    2443
    2444     /**
    2445      * @class Creates an area indicating the solution of a linear inequality.
    2446      * @pseudo
    2447      * @description Display the solution set of a linear inequality (less than or equal to).
    2448      * To be precise, the solution set of the inequality <i>y <= b/a * x + c/a</i> is shown.
    2449      * In case <i>a = 0</i>, that is if the equation of the line is <i>bx + c = 0</i>,
    2450      * the area of the inequality <i>bx + c <= 0</i> is shown.
    2451      * @param {JXG.Line} l The area drawn will be the area below this line. With the attribute
    2452      * inverse:true, the inequality 'greater than or equal to' is shown.
    2453      * @constructor
    2454      * @name Inequality
    2455      * @type JXG.Curve
    2456      * @augments JXG.Curve
    2457      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
    2458      * @example
    2459      * var p = board.create('point', [1, 3]),
    2460      *     q = board.create('point', [-2, -4]),
    2461      *     l = board.create('line', [p, q]),
    2462      *     ineq = board.create('inequality', [l]);
    2463      * ineq = board.create('inequality', [l]);
    2464      * </pre><div class="jxgbox" id="2b703006-fd98-11e1-b79e-ef9e591c002e" style="width: 400px; height: 400px;"></div>
    2465      * <script type="text/javascript">
    2466      * (function () {
    2467      *  var board = JXG.JSXGraph.initBoard('2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),
    2468      *      p = board.create('point', [1, 3]),
    2469      *      q = board.create('point', [-2, -4]),
    2470      *      l = board.create('line', [p, q]),
    2471      *      ineq = board.create('inequality', [l]);
    2472      * })();
    2473      * </script><pre>
    2474      *
    2475      * @example
    2476      * // Plot the inequality
    2477      * //     y >= 2/3 x + 1
    2478      * // or
    2479      * //     0 >= -3y + 2x +1
    2480      * var l = board.create('line', [1, 2, -3]),
    2481      *     ineq = board.create('inequality', [l], {inverse:true});
    2482      * </pre><div class="jxgbox" id="1ded3812-2da4-4323-abaf-1db4bad1bfbd" style="width: 400px; height: 400px;"></div>
    2483      * <script type="text/javascript">
    2484      * (function () {
    2485      *  var board = JXG.JSXGraph.initBoard('1ded3812-2da4-4323-abaf-1db4bad1bfbd', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),
    2486      *      l = board.create('line', [1, 2, -3]),
    2487      *      ineq = board.create('inequality', [l], {inverse:true});
    2488      * })();
    2489      * </script><pre>
    2490      */
    2491     JXG.createInequality = function (board, parents, attributes) {
    2492         var f, a, attr;
    2493
    2494         attr = Type.copyAttributes(attributes, board.options, 'inequality');
    2495         if (parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
    2496             a = board.create('curve', [[], []], attr);
    2497             a.hasPoint = function () {
    2498                 return false;
    2499             };
    2500             a.updateDataArray = function () {
    2501                 var i1, i2,
    2502                     // this will be the height of the area. We mustn't rely upon the board height because if we pan the view
    2503                     // such that the line is not visible anymore, the borders of the area will get visible in some cases.
    2504                     h,
    2505                     bb = board.getBoundingBox(),
    2506                     factor = attr.inverse ? -1 : 1,
    2507                     expansion = 1.5,
    2508                     w = expansion * Math.max(bb[2] - bb[0], bb[1] - bb[3]),
    2509                     // fake a point (for Math.Geometry.perpendicular)
    2510                     dp = {
    2511                         coords: {
    2512                             usrCoords: [1, (bb[0] + bb[2]) / 2, attr.inverse ? bb[1] : bb[3]]
    2513                         }
    2514                     },
    2515
    2516                     slope1 = parents[0].stdform.slice(1),
    2517                     slope2 = slope1;
    2518
    2519                 // This is wrong. Example:
    2520                 // var line = board.create('line', [0, -1, -1]);
    2521                 // var ineq = board.create('inequality', [line]);
    2522                 //
    2523                 // if (slope1[1] > 0) {
    2524                 //     slope1 = Statistics.multiply(slope1, -1);
    2525                 //     slope2 = slope1;
    2526                 // }
    2527
    2528                 // calculate the area height = 2* the distance of the line to the point in the middle of the top/bottom border.
    2529                 h = expansion * Math.max(Geometry.perpendicular(parents[0], dp, board)[0].distance(Const.COORDS_BY_USER, dp.coords), w);
    2530                 h *= factor;
    2531
    2532                 // reuse dp
    2533                 dp = {
    2534                     coords: {
    2535                         usrCoords: [1, (bb[0] + bb[2]) / 2, (bb[1] + bb[3]) / 2]
    2536                     }
    2537                 };
    2538
    2539                 // If dp is on the line, Geometry.perpendicular will return a point not on the line.
    2540                 // Since this somewhat odd behavior of Geometry.perpendicular is needed in GEONExT,
    2541                 // it is circumvented here.
    2542                 if (Math.abs(Mat.innerProduct(dp.coords.usrCoords, parents[0].stdform, 3)) >= Mat.eps) {
    2543                     dp = Geometry.perpendicular(parents[0], dp, board)[0].usrCoords;
    2544                 } else {
    2545                     dp = dp.coords.usrCoords;
    2546                 }
    2547                 i1 = [1, dp[1] + slope1[1] * w, dp[2] - slope1[0] * w];
    2548                 i2 = [1, dp[1] - slope2[1] * w, dp[2] + slope2[0] * w];
    2549
    2550                 // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1)
    2551                 // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and
    2552                 // end up in i2.
    2553                 this.dataX = [i1[1], i1[1] + slope1[0] * h, i2[1] + slope2[0] * h, i2[1], i1[1]];
    2554                 this.dataY = [i1[2], i1[2] + slope1[1] * h, i2[2] + slope2[1] * h, i2[2], i1[2]];
    2555             };
    2556         } else {
    2557             f = Type.createFunction(parents[0]);
    2558             if (!Type.exists(f)) {
    2559                 throw new Error("JSXGraph: Can't create area with the given parents." +
    2560                     "\nPossible parent types: [line], [function]");
    2561             }
    2562         }
    2563
    2564         return a;
    2565     };
    2566
    2567
    2568     JXG.registerElement('arrowparallel', JXG.createArrowParallel);
    2569     JXG.registerElement('bisector', JXG.createBisector);
    2570     JXG.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);
    2571     JXG.registerElement('msector', JXG.createMsector);
    2572     JXG.registerElement('circumcircle', JXG.createCircumcircle);
    2573     JXG.registerElement('circumcirclemidpoint', JXG.createCircumcenter);
    2574     JXG.registerElement('circumcenter', JXG.createCircumcenter);
    2575     JXG.registerElement('incenter', JXG.createIncenter);
    2576     JXG.registerElement('incircle', JXG.createIncircle);
    2577     JXG.registerElement('integral', JXG.createIntegral);
    2578     JXG.registerElement('midpoint', JXG.createMidpoint);
    2579     JXG.registerElement('mirrorelement', JXG.createMirrorElement);
    2580     JXG.registerElement('mirrorpoint', JXG.createMirrorPoint);
    2581     JXG.registerElement('normal', JXG.createNormal);
    2582     JXG.registerElement('orthogonalprojection', JXG.createOrthogonalProjection);
    2583     JXG.registerElement('parallel', JXG.createParallel);
    2584     JXG.registerElement('parallelpoint', JXG.createParallelPoint);
    2585     JXG.registerElement('perpendicular', JXG.createPerpendicular);
    2586     JXG.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);
    2587     JXG.registerElement('perpendicularsegment', JXG.createPerpendicularSegment);
    2588     JXG.registerElement('reflection', JXG.createReflection);
    2589     JXG.registerElement('grid', JXG.createGrid);
    2590     JXG.registerElement('inequality', JXG.createInequality);
    2591
    2592     return {
    2593         createArrowParallel: JXG.createArrowParallel,
    2594         createBisector: JXG.createBisector,
    2595         createAngularBisectorOfTwoLines: JXG.createAngularBisectorsOfTwoLines,
    2596         createCircumcircle: JXG.createCircumcircle,
    2597         createCircumcenter: JXG.createCircumcenter,
    2598         createIncenter: JXG.createIncenter,
    2599         createIncircle: JXG.createIncircle,
    2600         createIntegral: JXG.createIntegral,
    2601         createMidpoint: JXG.createMidpoint,
    2602         createMirrorElement: JXG.createMirrorElement,
    2603         createMirrorPoint: JXG.createMirrorPoint,
    2604         createNormal: JXG.createNormal,
    2605         createOrthogonalProjection: JXG.createOrthogonalProjection,
    2606         createParallel: JXG.createParallel,
    2607         createParallelPoint: JXG.createParallelPoint,
    2608         createPerpendicular: JXG.createPerpendicular,
    2609         createPerpendicularPoint: JXG.createPerpendicularPoint,
    2610         createPerpendicularSegmen: JXG.createPerpendicularSegment,
    2611         createReflection: JXG.createReflection,
    2612         createGrid: JXG.createGrid,
    2613         createInequality: JXG.createInequality
    2614     };
    2615 });
    2616