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