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