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