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