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 
2069         t = Transform.createTransform(board, [l], {type: 'reflect'});
2070         if (Type.isPoint(org)) {
2071             r = Point.createPoint(board, [org, t], attr);
2072         // Arcs and sectors are treated as curves
2073         } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){
2074             r = Curve.createCurve(board, [org, t], attr);
2075         } else if (org.elementClass === Const.OBJECT_CLASS_LINE){
2076             r = Line.createLine(board, [org, t], attr);
2077         } else if (org.type === Const.OBJECT_TYPE_POLYGON){
2078             r = Polygon.createPolygon(board, [org, t], attr);
2079         } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE) {
2080             if (attr.type.toLowerCase() === 'euclidean') {
2081                 // Create a circle element from a circle and a Euclidean transformation
2082                 attr2 = Type.copyAttributes(attributes, board.options, 'reflection', 'center');
2083                 r_c = Point.createPoint(board, [org.center, t], attr2);
2084                 r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer();
2085                 r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr);
2086             } else {
2087                 // Create a conic element from a circle and a projective transformation
2088                 r = Circle.createCircle(board, [org, t], attr);
2089             }
2090         } else {
2091             throw new Error("JSXGraph: Can't create reflected element with parent types '" +
2092                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
2093         }
2094         if (Type.exists(org._is_new)) {
2095             r.addChild(org);
2096             delete org._is_new;
2097         } else {
2098             // org.addChild(r);
2099         }
2100         l.addChild(r);
2101 
2102         r.elType = 'reflection';
2103         r.addParents(l);
2104         r.prepareUpdate().update(); //.updateVisibility(Type.evaluate(r.visProp.visible)).updateRenderer();
2105 
2106         if (Type.isPoint(r)) {
2107             r.generatePolynomial = function () {
2108                 /*
2109                  *  Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.
2110                  *  L is defined by two points A and B.
2111                  *
2112                  * So we have two conditions:
2113                  *
2114                  *   (a)   RP  _|_  AB            (orthogonality condition)
2115                  *   (b)   AR  ==   AP            (distance condition)
2116                  *
2117                  */
2118                 var a1 = l.point1.symbolic.x,
2119                     a2 = l.point1.symbolic.y,
2120                     b1 = l.point2.symbolic.x,
2121                     b2 = l.point2.symbolic.y,
2122                     p1 = org.symbolic.x,
2123                     p2 = org.symbolic.y,
2124                     r1 = r.symbolic.x,
2125                     r2 = r.symbolic.y,
2126 
2127                     poly1 = ['((', r2, ')-(', p2, '))*((', a2, ')-(', b2, '))+((', a1, ')-(', b1, '))*((', r1, ')-(', p1, '))'].join(''),
2128                     poly2 = ['((', r1, ')-(', a1, '))^2+((', r2, ')-(', a2, '))^2-((', p1, ')-(', a1, '))^2-((', p2, ')-(', a2, '))^2'].join('');
2129 
2130                 return [poly1, poly2];
2131             };
2132         }
2133 
2134         return r;
2135     };
2136 
2137     /**
2138      * @class A mirror element of a point, line, circle, curve, polygon will be constructed.
2139      * @pseudo
2140      * @description A mirror element is determined by the reflection of a given point, line, circle, curve, polygon across another given point.
2141      * @constructor
2142      * @name Mirrorelement
2143      * @type JXG.GeometryElement
2144      * @augments JXG.GeometryElement
2145      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2146      * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Ppolygon_JXG.Point} p1,p2 The constructed element is the mirror image of p2 across p1.
2147      * @example
2148      *         // point of reflection
2149      *         var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});
2150      *
2151      *         var p1 = board.create('point', [-3,-1], {name: "A"});
2152      *         var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"});
2153      *
2154      *         var l1 = board.create('line', [1, -5, 1]);
2155      *         var l2 = board.create('mirrorelement', [l1, mirr]);
2156      *
2157      *         var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});
2158      *         var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3});
2159      *
2160      *         var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]);
2161      *         var pol2 = board.create('mirrorelement', [pol1, mirr]);
2162      *
2163      *         var c1 = board.create('circle', [[-6,-6], [-6, -5]]);
2164      *         var c2 = board.create('mirrorelement', [c1, mirr]);
2165      *
2166      *         var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});
2167      *         var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'});
2168      *
2169      *         var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {
2170      *                           anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},
2171      *                           fillColor: 'yellow', strokeColor: 'black'});
2172      *         var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});
2173      *
2174      *         var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);
2175      *         var an2 = board.create('mirrorelement', [an1, mirr]);
2176      *
2177      *
2178      * </pre><div id="JXG026c779c-d8d9-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div>
2179      * <script type="text/javascript">
2180      *     (function() {
2181      *         var board = JXG.JSXGraph.initBoard('JXG026c779c-d8d9-11e7-93b3-901b0e1b8723',
2182      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
2183      *             // point of reflection
2184      *             var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});
2185      *
2186      *             var p1 = board.create('point', [-3,-1], {name: "A"});
2187      *             var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"});
2188      *
2189      *             var l1 = board.create('line', [1,-5, 1]);
2190      *             var l2 = board.create('mirrorelement', [l1, mirr]);
2191      *
2192      *             var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});
2193      *             var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3});
2194      *
2195      *             var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]);
2196      *             var pol2 = board.create('mirrorelement', [pol1, mirr]);
2197      *
2198      *             var c1 = board.create('circle', [[-6,-6], [-6, -5]]);
2199      *             var c2 = board.create('mirrorelement', [c1, mirr]);
2200      *
2201      *         var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});
2202      *         var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'});
2203      *
2204      *         var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {
2205      *                           anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},
2206      *                           fillColor: 'yellow', strokeColor: 'black'});
2207      *         var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});
2208      *
2209      *         var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);
2210      *         var an2 = board.create('mirrorelement', [an1, mirr]);
2211      *
2212      *     })();
2213      *
2214      * </script><pre>
2215      */
2216     JXG.createMirrorElement = function (board, parents, attributes) {
2217         var org, i, m, r, r_c, t,
2218             attr, attr2,
2219             errStr = "\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, point]";
2220 
2221         for (i = 0; i < parents.length; ++i) {
2222             parents[i] = board.select(parents[i]);
2223         }
2224 
2225         attr = Type.copyAttributes(attributes, board.options, 'mirrorelement');
2226         if (Type.isPoint(parents[0])) {
2227             // Create point to be mirrored if supplied by coords array.
2228             org = Type.providePoints(board, [parents[0]], attr)[0];
2229         } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE ||
2230                     parents[0].elementClass === Const.OBJECT_CLASS_LINE ||
2231                     parents[0].type === Const.OBJECT_TYPE_POLYGON ||
2232                     parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) {
2233             org = parents[0];
2234         } else {
2235             throw new Error("JSXGraph: Can't create mirror element with parent types '" +
2236                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
2237         }
2238 
2239         if (Type.isPoint(parents[1])) {
2240             attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'point');
2241             // Create mirror point if supplied by coords array.
2242             m = Type.providePoints(board, [parents[1]], attr2)[0];
2243         } else {
2244             throw new Error("JSXGraph: Can't create mirror element with parent types '" +
2245                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
2246         }
2247 
2248         t = Transform.createTransform(board, [Math.PI, m], {type: 'rotate'});
2249         if (Type.isPoint(org)) {
2250             r = Point.createPoint(board, [org, t], attr);
2251 
2252         // Arcs and sectors are treated as curves
2253         } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){
2254             r = Curve.createCurve(board, [org, t], attr);
2255         } else if (org.elementClass === Const.OBJECT_CLASS_LINE){
2256             r = Line.createLine(board, [org, t], attr);
2257         }  else if (org.type === Const.OBJECT_TYPE_POLYGON){
2258             r = Polygon.createPolygon(board, [org, t], attr);
2259         } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE){
2260             if (attr.type.toLowerCase() === 'euclidean') {
2261                 // Create a circle element from a circle and a Euclidean transformation
2262                 attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'center');
2263                 r_c = Point.createPoint(board, [org.center, t], attr2);
2264                 r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer();
2265                 r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr);
2266             } else {
2267                 // Create a conic element from a circle and a projective transformation
2268                 r = Circle.createCircle(board, [org, t], attr);
2269             }
2270         } else {
2271             throw new Error("JSXGraph: Can't create mirror element with parent types '" +
2272                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
2273         }
2274 
2275         if (Type.exists(org._is_new)) {
2276             r.addChild(org);
2277             delete org._is_new;
2278         } else {
2279             // org.addChild(r);
2280         }
2281         m.addChild(r);
2282 
2283         r.elType = 'mirrorelement';
2284         r.addParents(m);
2285         r.prepareUpdate().update();
2286 
2287         return r;
2288     };
2289 
2290     /**
2291      * @class A mirror point will be constructed.
2292      * @pseudo
2293      * @description A mirror point is determined by the reflection of a given point against another given point.
2294      * @constructor
2295      * @name Mirrorpoint
2296      * @type JXG.Point
2297      * @augments JXG.Point
2298      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2299      * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.
2300      *
2301      * This method is superseeded by the more general {@link JXG.createMirrorElement}.
2302      * @example
2303      * var p1 = board.create('point', [3.0, 3.0]);
2304      * var p2 = board.create('point', [6.0, 1.0]);
2305      *
2306      * var mp1 = board.create('mirrorpoint', [p1, p2]);
2307      * </pre><div class="jxgbox" id="JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div>
2308      * <script type="text/javascript">
2309      *   var mpex1_board = JXG.JSXGraph.initBoard('JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
2310      *   var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);
2311      *   var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);
2312      *   var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);
2313      * </script><pre>
2314      */
2315     JXG.createMirrorPoint = function (board, parents, attributes) {
2316         var el = JXG.createMirrorElement(board, parents, attributes);
2317         el.elType = 'mirrorpoint';
2318         return el;
2319     };
2320 
2321     /**
2322      * @class This element is used to visualize the integral of a given curve over a given interval.
2323      * @pseudo
2324      * @description The Integral element is used to visualize the area under a given curve over a given interval
2325      * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,
2326      * the gliders are used to change the interval dynamically.
2327      * @constructor
2328      * @name Integral
2329      * @type JXG.Curve
2330      * @augments JXG.Curve
2331      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2332      * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis
2333      * within the interval <tt>i</tt>.
2334      * @example
2335      * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);
2336      * var i1 = board.create('integral', [[-2.0, 2.0], c1]);
2337      * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
2338      * <script type="text/javascript">
2339      *   var intex1_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});
2340      *   var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]);
2341      *   var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);
2342      * </script><pre>
2343      */
2344     JXG.createIntegral = function (board, parents, attributes) {
2345         var interval, curve, attr,
2346             start, end, startx, starty, endx, endy,
2347             pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,
2348             t = null, p;
2349 
2350         if (Type.isArray(parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_CURVE) {
2351             interval = parents[0];
2352             curve = parents[1];
2353         } else if (Type.isArray(parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_CURVE) {
2354             interval = parents[1];
2355             curve = parents[0];
2356         } else {
2357             throw new Error("JSXGraph: Can't create integral with parent types '" +
2358                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
2359                 "\nPossible parent types: [[number|function,number|function],curve]");
2360         }
2361 
2362         attr = Type.copyAttributes(attributes, board.options, 'integral');
2363         attr.withLabel = false;  // There is a custom 'label' below.
2364         p = board.create('curve', [[0], [0]], attr);
2365 
2366         // Correct the interval if necessary - NOT ANYMORE, GGB's fault
2367         start = interval[0];
2368         end = interval[1];
2369 
2370         if (Type.isFunction(start)) {
2371             startx = start;
2372             starty = function () { return curve.Y(startx()); };
2373             start = startx();
2374         } else {
2375             startx = start;
2376             starty = curve.Y(start);
2377         }
2378 
2379         if (Type.isFunction(end)) {
2380             endx = end;
2381             endy = function () { return curve.Y(endx()); };
2382             end = endx();
2383         } else {
2384             endx = end;
2385             endy = curve.Y(end);
2386         }
2387 
2388         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveLeft');
2389         pa_on_curve = board.create('glider', [startx, starty, curve], attr);
2390         if (Type.isFunction(startx)) {
2391             pa_on_curve.hideElement();
2392         }
2393 
2394         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseLeft');
2395         pa_on_axis = board.create('point', [
2396             function () {
2397                 if (Type.evaluate(p.visProp.axis) === 'y') {
2398                     return 0;
2399                 }
2400 
2401                 return pa_on_curve.X();
2402             },
2403             function () {
2404                 if (Type.evaluate(p.visProp.axis) === 'y') {
2405                     return pa_on_curve.Y();
2406                 }
2407 
2408                 return 0;
2409             }
2410         ], attr);
2411 
2412         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveRight');
2413         pb_on_curve = board.create('glider', [endx, endy, curve], attr);
2414         if (Type.isFunction(endx)) {
2415             pb_on_curve.hideElement();
2416         }
2417 
2418         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseRight');
2419         pb_on_axis = board.create('point', [
2420             function () {
2421                 if (Type.evaluate(p.visProp.axis) === 'y') {
2422                     return 0;
2423                 }
2424                 return pb_on_curve.X();
2425             },
2426             function () {
2427                 if (Type.evaluate(p.visProp.axis) === 'y') {
2428                     return pb_on_curve.Y();
2429                 }
2430 
2431                 return 0;
2432             }
2433         ], attr);
2434 
2435         attr = Type.copyAttributes(attributes, board.options, 'integral');
2436         if (attr.withlabel !== false && attr.axis !== 'y') {
2437             attr = Type.copyAttributes(attributes, board.options, 'integral', 'label');
2438             attr = Type.copyAttributes(attr, board.options, 'label');
2439 
2440             t = board.create('text', [
2441                 function () {
2442                     var off = new Coords(Const.COORDS_BY_SCREEN, [
2443                             Type.evaluate(this.visProp.offset[0]) + this.board.origin.scrCoords[1],
2444                             0
2445                         ], this.board, false),
2446                         bb = this.board.getBoundingBox(),
2447                         dx = (bb[2] - bb[0]) * 0.1,
2448                         x = pb_on_curve.X();
2449 
2450                     if (x < bb[0]) {
2451                         x = bb[0] + dx;
2452                     } else if (x > bb[2]) {
2453                         x = bb[2] - dx;
2454                     }
2455 
2456                     return x + off.usrCoords[1];
2457                 },
2458                 function () {
2459                     var off = new Coords(Const.COORDS_BY_SCREEN, [
2460                             0,
2461                             Type.evaluate(this.visProp.offset[1]) + this.board.origin.scrCoords[2]
2462                         ], this.board, false),
2463                         bb = this.board.getBoundingBox(),
2464                         dy = (bb[1] - bb[3]) * 0.1,
2465                         y = pb_on_curve.Y();
2466 
2467                     if (y > bb[1]) {
2468                         y = bb[1] - dy;
2469                     } else if (y < bb[3]) {
2470                         y = bb[3] + dy;
2471                     }
2472 
2473                     return y + off.usrCoords[2];
2474                 },
2475                 function () {
2476                     var Int = Numerics.NewtonCotes([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
2477                     return '∫ = ' + Type.toFixed(Int, 4);
2478                 }
2479             ], attr);
2480 
2481             t.dump = false;
2482 
2483             pa_on_curve.addChild(t);
2484             pb_on_curve.addChild(t);
2485         }
2486 
2487         // dump stuff
2488         pa_on_curve.dump = false;
2489         pa_on_axis.dump = false;
2490 
2491         pb_on_curve.dump = false;
2492         pb_on_axis.dump = false;
2493 
2494         p.elType = 'integral';
2495         p.setParents([curve.id, interval]);
2496         p.subs = {
2497             curveLeft: pa_on_curve,
2498             baseLeft: pa_on_axis,
2499             curveRight: pb_on_curve,
2500             baseRight: pb_on_axis
2501         };
2502         p.inherits.push(pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis);
2503 
2504         if (attr.withLabel) {
2505             p.subs.label = t;
2506             p.inherits.push(t);
2507         }
2508 
2509         /**
2510          * Returns the current value of the integral.
2511          * @memberOf Integral
2512          * @name Value
2513          * @function
2514          * @returns {Number}
2515          */
2516         p.Value = function () {
2517             return Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
2518         };
2519 
2520         /**
2521          * documented in JXG.Curve
2522          * @ignore
2523          */
2524         p.updateDataArray = function () {
2525             var x, y,
2526                 i, left, right,
2527                 lowx, upx,
2528                 lowy, upy;
2529 
2530             if (Type.evaluate(this.visProp.axis) === 'y') {
2531                 if (pa_on_curve.Y() < pb_on_curve.Y()) {
2532                     lowx = pa_on_curve.X();
2533                     lowy = pa_on_curve.Y();
2534                     upx = pb_on_curve.X();
2535                     upy = pb_on_curve.Y();
2536                 } else {
2537                     lowx = pb_on_curve.X();
2538                     lowy = pb_on_curve.Y();
2539                     upx = pa_on_curve.X();
2540                     upy = pa_on_curve.Y();
2541                 }
2542                 left = Math.min(lowx, upx);
2543                 right = Math.max(lowx, upx);
2544 
2545                 x = [0, lowx];
2546                 y = [lowy, lowy];
2547 
2548                 for (i = 0; i < curve.numberPoints; i++) {
2549                     if (lowy <= curve.points[i].usrCoords[2] &&
2550                             left <= curve.points[i].usrCoords[1] &&
2551                             curve.points[i].usrCoords[2] <= upy  &&
2552                             curve.points[i].usrCoords[1] <= right) {
2553                         x.push(curve.points[i].usrCoords[1]);
2554                         y.push(curve.points[i].usrCoords[2]);
2555                     }
2556                 }
2557                 x.push(upx);
2558                 y.push(upy);
2559                 x.push(0);
2560                 y.push(upy);
2561 
2562                 // close the curve
2563                 x.push(0);
2564                 y.push(lowy);
2565             } else {
2566                 if (pa_on_axis.X() < pb_on_axis.X()) {
2567                     left = pa_on_axis.X();
2568                     right = pb_on_axis.X();
2569                 } else {
2570                     left = pb_on_axis.X();
2571                     right = pa_on_axis.X();
2572                 }
2573 
2574                 x = [left, left];
2575                 y = [0, curve.Y(left)];
2576 
2577                 for (i = 0; i < curve.numberPoints; i++) {
2578                     if ((left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right)) {
2579                         x.push(curve.points[i].usrCoords[1]);
2580                         y.push(curve.points[i].usrCoords[2]);
2581                     }
2582                 }
2583                 x.push(right);
2584                 y.push(curve.Y(right));
2585                 x.push(right);
2586                 y.push(0);
2587 
2588                 // close the curve
2589                 x.push(left);
2590                 y.push(0);
2591             }
2592 
2593             this.dataX = x;
2594             this.dataY = y;
2595         };
2596 
2597         pa_on_curve.addChild(p);
2598         pb_on_curve.addChild(p);
2599         pa_on_axis.addChild(p);
2600         pb_on_axis.addChild(p);
2601 
2602         /**
2603          * The point on the axis initially corresponding to the lower value of the interval.
2604          *
2605          * @name baseLeft
2606          * @memberOf Integral
2607          * @type JXG.Point
2608          */
2609         p.baseLeft = pa_on_axis;
2610 
2611         /**
2612          * The point on the axis initially corresponding to the higher value of the interval.
2613          *
2614          * @name baseRight
2615          * @memberOf Integral
2616          * @type JXG.Point
2617          */
2618         p.baseRight = pb_on_axis;
2619 
2620         /**
2621          * The glider on the curve corresponding to the lower value of the interval.
2622          *
2623          * @name curveLeft
2624          * @memberOf Integral
2625          * @type Glider
2626          */
2627         p.curveLeft = pa_on_curve;
2628 
2629         /**
2630          * The glider on the axis corresponding to the higher value of the interval.
2631          *
2632          * @name curveRight
2633          * @memberOf Integral
2634          * @type Glider
2635          */
2636         p.curveRight = pb_on_curve;
2637 
2638         p.methodMap = JXG.deepCopy(p.methodMap, {
2639             curveLeft: 'curveLeft',
2640             baseLeft: 'baseLeft',
2641             curveRight: 'curveRight',
2642             baseRight: 'baseRight',
2643             Value: 'Value'
2644         });
2645 
2646         /**
2647          * documented in GeometryElement
2648          * @ignore
2649          */
2650         p.label = t;
2651 
2652         return p;
2653     };
2654 
2655     /**
2656      * @class Creates a grid to support the user with element placement.
2657      * @pseudo
2658      * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method
2659      * draws such a grid on the given board. This method does not
2660      * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set
2661      * to true.
2662      * @parameter None.
2663      * @constructor
2664      * @name Grid
2665      * @type JXG.Curve
2666      * @augments JXG.Curve
2667      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2668      * @example
2669      * grid = board.create('grid', []);
2670      * </pre><div class="jxgbox" id="JXGa9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div>
2671      * <script type="text/javascript">
2672      * (function () {
2673      *  board = JXG.JSXGraph.initBoard('JXGa9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
2674      *  grid = board.create('grid', []);
2675      * })();
2676      * </script><pre>
2677      */
2678     JXG.createGrid = function (board, parents, attributes) {
2679         var c, attr;
2680 
2681         attr = Type.copyAttributes(attributes, board.options, 'grid');
2682         c = board.create('curve', [[null], [null]], attr);
2683 
2684         c.elType = 'grid';
2685         c.type = Const.OBJECT_TYPE_GRID;
2686 
2687         /**
2688          * @ignore
2689          */
2690          c.updateDataArray = function () {
2691             var start, end, i, topLeft, bottomRight,
2692                 gridX = Type.evaluate(this.visProp.gridx),
2693                 gridY = Type.evaluate(this.visProp.gridy);
2694 
2695             if (Type.isArray(this.visProp.topleft)) {
2696                 topLeft = new Coords(Type.evaluate(this.visProp.tltype) || Const.COORDS_BY_USER,
2697                                     this.visProp.topleft, board);
2698             } else {
2699                 topLeft = new Coords(Const.COORDS_BY_SCREEN, [0, 0], board);
2700             }
2701 
2702             if (Type.isArray(this.visProp.bottomright)) {
2703                 bottomRight = new Coords(Type.evaluate(this.visProp.brtype) || Const.COORDS_BY_USER,
2704                                     this.visProp.bottomright, board);
2705             } else {
2706                 bottomRight = new Coords(Const.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board);
2707             }
2708 
2709 
2710             //
2711             //      |         |         |
2712             //  ----+---------+---------+-----
2713             //      |        /|         |
2714             //      |    gridY|     <---+------   Grid Cell
2715             //      |        \|         |
2716             //  ----+---------+---------+-----
2717             //      |         |\ gridX /|
2718             //      |         |         |
2719             //
2720             // uc: usercoordinates
2721             //
2722             // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high.
2723             // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it
2724             // is absolutely not user friendly when it comes to use it as an API interface.
2725             // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i
2726             // had to refactor these methods:
2727             //
2728             //  DONE JXG.Board.calculateSnapSizes (init p1, p2)
2729             //  DONE JXG.GeonextReader.readGeonext (init gridX, gridY)
2730             //
2731 
2732             board.options.grid.hasGrid = true;
2733 
2734 			// fix_grid: adding integer function to calculation of start and end values, and adding to calculation of start and end values below
2735 			// To allow this:
2736 			// (axes on the outside, min value of grid = 0.25)
2737             //
2738             //      |    |         |          |
2739             // 1.5 -+----+---------+----------+-----
2740             //      |    |         |          |
2741             //      |    |         |          |
2742             //      |    |         |          |
2743             //   1 -+----+---------+----------+-----
2744             //      |    |         |          |
2745             //      |    |         |          |
2746             //      |    |         |          |
2747             // 0.5 -+----+---------+----------+-----
2748             //      |    |         |          |
2749             //      +----+---------+----------+-----
2750             //           |         |          |
2751             //          0.5        1         1.5
2752             //
2753             // fix_grid: these lines disabled:
2754             // topLeft.setCoordinates(Const.COORDS_BY_USER, [Math.ceil(topLeft.usrCoords[1] / gridX) * gridX, Math.floor(topLeft.usrCoords[2] / gridY) * gridY]);
2755             // bottomRight.setCoordinates(Const.COORDS_BY_USER, [Math.floor(bottomRight.usrCoords[1] / gridX) * gridX, Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY]);
2756 
2757             c.dataX = [];
2758             c.dataY = [];
2759 
2760             // Sometimes the bounding box is used to invert the axis. We have to take this into account here.
2761             // fix_grid: adding integer function to calculation of start and end values
2762             start = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;
2763             end = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY;
2764 
2765             if (topLeft.usrCoords[2] < bottomRight.usrCoords[2]) {
2766                 start = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; // bottomRight.usrCoords[2];
2767                 end = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;
2768             }
2769 
2770             // start with the horizontal grid:
2771             for (i = start; i > end - gridY; i -= gridY) {
2772                 c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN);
2773                 c.dataY.push(i, i, NaN);
2774             }
2775 
2776             // fix_grid: adding integer function to calculation of start and end values
2777             start = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;
2778             end = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;
2779 
2780             if (topLeft.usrCoords[1] > bottomRight.usrCoords[1]) {
2781 				start = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;
2782 				end = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;
2783             }
2784 
2785             // build vertical grid
2786             for (i = start; i < end + gridX; i += gridX) {
2787                 c.dataX.push(i, i, NaN);
2788                 c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN);
2789             }
2790 
2791         };
2792 
2793         // we don't care about highlighting so we turn it off completely to save a lot of
2794         // time on every mouse move
2795         c.hasPoint = function () {
2796             return false;
2797         };
2798 
2799         board.grids.push(c);
2800 
2801         return c;
2802     };
2803 
2804     /**
2805      * @class Creates an area indicating the solution of a linear inequality or an inequality
2806      * of a function graph, i.e. an inequality of type y <= f(x).
2807      * @pseudo
2808      * @description Display the solution set of a linear inequality (less than or equal to).
2809      * To be precise, the solution set of the inequality <i>y <= b/a * x + c/a</i> is shown.
2810      * In case <i>a = 0</i>, that is if the equation of the line is <i>bx + c = 0</i>,
2811      * the area of the inequality <i>bx + c <= 0</i> is shown.
2812      * <p>
2813      * For function graphs the area below the function graph is filled, i.e. the
2814      * area of the inequality y <= f(x).
2815      * With the attribute inverse:true the area of the inequality y >= f(x) is filled.
2816      *
2817      * @param {JXG.Line} l The area drawn will be the area below this line. With the attribute
2818      * inverse:true, the inequality 'greater than or equal to' is shown.
2819      * @constructor
2820      * @name Inequality
2821      * @type JXG.Curve
2822      * @augments JXG.Curve
2823      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2824      * @example
2825      * var p = board.create('point', [1, 3]),
2826      *     q = board.create('point', [-2, -4]),
2827      *     l = board.create('line', [p, q]),
2828      *     ineq = board.create('inequality', [l]);
2829      * ineq = board.create('inequality', [l]);
2830      * </pre><div class="jxgbox" id="JXG2b703006-fd98-11e1-b79e-ef9e591c002e" style="width: 400px; height: 400px;"></div>
2831      * <script type="text/javascript">
2832      * (function () {
2833      *  var board = JXG.JSXGraph.initBoard('JXG2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),
2834      *      p = board.create('point', [1, 3]),
2835      *      q = board.create('point', [-2, -4]),
2836      *      l = board.create('line', [p, q]),
2837      *      ineq = board.create('inequality', [l]);
2838      * })();
2839      * </script><pre>
2840      *
2841      * @example
2842      * // Plot the inequality
2843      * //     y >= 2/3 x + 1
2844      * // or
2845      * //     0 >= -3y + 2x +1
2846      * var l = board.create('line', [1, 2, -3]),
2847      *     ineq = board.create('inequality', [l], {inverse:true});
2848      * </pre><div class="jxgbox" id="JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd" style="width: 400px; height: 400px;"></div>
2849      * <script type="text/javascript">
2850      * (function () {
2851      *  var board = JXG.JSXGraph.initBoard('JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),
2852      *      l = board.create('line', [1, 2, -3]),
2853      *      ineq = board.create('inequality', [l], {inverse:true});
2854      * })();
2855      * </script><pre>
2856      *
2857      * @example
2858      * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]);
2859      *
2860      * var ineq_lower = board.create('inequality', [f]);
2861      * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'});
2862      *
2863      *
2864      * </pre><div id="JXGdb68c574-414c-11e8-839a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div>
2865      * <script type="text/javascript">
2866      *     (function() {
2867      *         var board = JXG.JSXGraph.initBoard('JXGdb68c574-414c-11e8-839a-901b0e1b8723',
2868      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
2869      *     var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]);
2870      *
2871      *     var ineq_lower = board.create('inequality', [f]);
2872      *     var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'});
2873      *
2874      *
2875      *     })();
2876      *
2877      * </script><pre>
2878      *
2879      */
2880     JXG.createInequality = function (board, parents, attributes) {
2881         var f, a, attr;
2882 
2883         attr = Type.copyAttributes(attributes, board.options, 'inequality');
2884         if (parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
2885             a = board.create('curve', [[], []], attr);
2886             a.hasPoint = function () {
2887                 return false;
2888             };
2889             a.updateDataArray = function () {
2890                 var i1, i2,
2891                     // This will be the height of the area. We mustn't rely upon the board height because if we pan the view
2892                     // such that the line is not visible anymore, the borders of the area will get visible in some cases.
2893                     h,
2894                     bb = board.getBoundingBox(),
2895                     factor = attr.inverse ? -1 : 1,
2896                     expansion = 1.5,
2897                     w = expansion * Math.max(bb[2] - bb[0], bb[1] - bb[3]),
2898                     // Fake a point (for Math.Geometry.perpendicular)
2899                     // contains centroid of the board
2900                     dp = {
2901                         coords: {
2902                             usrCoords: [1, (bb[0] + bb[2]) / 2, attr.inverse ? bb[1] : bb[3]]
2903                         }
2904                     },
2905 
2906                     slope1 = parents[0].stdform.slice(1),
2907                     slope2 = slope1;
2908 
2909                 // This is wrong. Example:
2910                 // var line = board.create('line', [0, -1, -1]);
2911                 // var ineq = board.create('inequality', [line]);
2912                 //
2913                 // if (slope1[1] > 0) {
2914                 //     slope1 = Statistics.multiply(slope1, -1);
2915                 //     slope2 = slope1;
2916                 // }
2917 
2918                 // Calculate the area height as
2919                 //  expansion times the distance of the line to the
2920                 // point in the middle of the top/bottom border.
2921                 h = expansion * Math.max(Geometry.perpendicular(parents[0], dp, board)[0].distance(Const.COORDS_BY_USER, dp.coords), w);
2922                 h *= factor;
2923 
2924                 // reuse dp
2925                 dp = {
2926                     coords: {
2927                         usrCoords: [1, (bb[0] + bb[2]) / 2, (bb[1] + bb[3]) / 2]
2928                     }
2929                 };
2930 
2931                 // If dp is on the line, Geometry.perpendicular will return a point not on the line.
2932                 // Since this somewhat odd behavior of Geometry.perpendicular is needed in GEONExT,
2933                 // it is circumvented here.
2934                 if (Math.abs(Mat.innerProduct(dp.coords.usrCoords, parents[0].stdform, 3)) >= Mat.eps) {
2935                     dp = Geometry.perpendicular(parents[0], dp, board)[0].usrCoords;
2936                 } else {
2937                     dp = dp.coords.usrCoords;
2938                 }
2939                 i1 = [1, dp[1] + slope1[1] * w, dp[2] - slope1[0] * w];
2940                 i2 = [1, dp[1] - slope2[1] * w, dp[2] + slope2[0] * w];
2941 
2942                 // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1)
2943                 // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and
2944                 // end up in i2.
2945                 this.dataX = [i1[1], i1[1] + slope1[0] * h, i2[1] + slope2[0] * h, i2[1], i1[1]];
2946                 this.dataY = [i1[2], i1[2] + slope1[1] * h, i2[2] + slope2[1] * h, i2[2], i1[2]];
2947             };
2948         } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE &&
2949             parents[0].visProp.curvetype === 'functiongraph') {
2950 
2951             a = board.create('curve', [[], []], attr);
2952             a.updateDataArray = function() {
2953                 var bbox = this.board.getBoundingBox(),
2954                     points = [],
2955                     infty, first, last,
2956                     len, i,
2957                     mi = parents[0].minX(),
2958                     ma = parents[0].maxX(),
2959                     curve_mi, curve_ma,
2960                     firstx,
2961                     lastx,
2962                     enlarge = (bbox[1] - bbox[3]) * 0.3, // enlarge the bbox vertically by this amount
2963                     inverse = Type.evaluate(this.visProp.inverse);
2964 
2965                 // inverse == true <=> Fill area with y >= f(x)
2966                 infty = (inverse) ? 1 : 3; // we will use either bbox[1] or bbox[3] below
2967 
2968                 this.dataX = [];
2969                 this.dataY = [];
2970                 len = parents[0].points.length;
2971                 if (len === 0) {
2972                     return;
2973                 }
2974 
2975                 bbox[1] += enlarge;
2976                 bbox[3] -= enlarge;
2977 
2978                 last = -1;
2979                 while (last < len - 1) {
2980 
2981                     // Find the first point with real coordinates on this curve segment
2982                     for (i = last + 1, first = len; i < len; i++) {
2983                         if (parents[0].points[i].isReal()) {
2984                             first = i;
2985                             break;
2986                         }
2987                     }
2988                     // No real points found -> exit
2989                     if (first >= len) {
2990                         break;
2991                     }
2992 
2993                     // Find the last point with real coordinates on this curve segment
2994                     for (i = first, last = len - 1; i < len - 1; i++) {
2995                         if (!parents[0].points[i + 1].isReal()) {
2996                             last = i;
2997                             break;
2998                         }
2999                     }
3000 
3001                     firstx = parents[0].points[first].usrCoords[1];
3002                     lastx = parents[0].points[last].usrCoords[1];
3003 
3004                     // Restrict the plot interval if the function ends inside of the board
3005                     curve_mi = (bbox[0] < mi) ? mi : bbox[0];
3006                     curve_ma = (bbox[2] > ma) ? ma : bbox[2];
3007 
3008                     // Found NaNs
3009                     curve_mi = (first === 0)      ? curve_mi : Math.max(curve_mi, firstx);
3010                     curve_ma = (last === len - 1) ? curve_ma : Math.min(curve_ma, lastx);
3011 
3012                     // First and last relevant x-coordinate of the curve
3013                     curve_mi = (first === 0)     ? mi: firstx;
3014                     curve_ma = (last === len - 1)? ma: lastx;
3015 
3016 
3017                     // Copy the curve points
3018                     points = [];
3019 
3020                     points.push([1, curve_mi, bbox[infty]]);
3021                     points.push([1, curve_mi, parents[0].points[first].usrCoords[2]]);
3022                     for (i = first; i <= last; i++) {
3023                         points.push(parents[0].points[i].usrCoords);
3024                     }
3025                     points.push([1, curve_ma, parents[0].points[last].usrCoords[2]]);
3026                     points.push([1, curve_ma, bbox[infty]]);
3027                     points.push(points[0]);
3028 
3029                     for (i = 0; i < points.length; i++) {
3030                         this.dataX.push(points[i][1]);
3031                         this.dataY.push(points[i][2]);
3032                     }
3033 
3034 
3035                     if (last < len - 1) {
3036                         this.dataX.push(NaN);
3037                         this.dataY.push(NaN);
3038                     }
3039               }
3040 
3041             };
3042 
3043             // Previous code:
3044             a.hasPoint = function () {
3045                 return false;
3046             };
3047         } else {
3048             // Not yet practical?
3049             f = Type.createFunction(parents[0]);
3050             if (!Type.exists(f)) {
3051                 throw new Error("JSXGraph: Can't create area with the given parents." +
3052                     "\nPossible parent types: [line], [function]");
3053             }
3054         }
3055 
3056         a.addParents(parents[0]);
3057         return a;
3058     };
3059 
3060 
3061     JXG.registerElement('arrowparallel', JXG.createArrowParallel);
3062     JXG.registerElement('bisector', JXG.createBisector);
3063     JXG.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);
3064     JXG.registerElement('msector', JXG.createMsector);
3065     JXG.registerElement('circumcircle', JXG.createCircumcircle);
3066     JXG.registerElement('circumcirclemidpoint', JXG.createCircumcenter);
3067     JXG.registerElement('circumcenter', JXG.createCircumcenter);
3068     JXG.registerElement('incenter', JXG.createIncenter);
3069     JXG.registerElement('incircle', JXG.createIncircle);
3070     JXG.registerElement('integral', JXG.createIntegral);
3071     JXG.registerElement('midpoint', JXG.createMidpoint);
3072     JXG.registerElement('mirrorelement', JXG.createMirrorElement);
3073     JXG.registerElement('mirrorpoint', JXG.createMirrorPoint);
3074     JXG.registerElement('normal', JXG.createNormal);
3075     JXG.registerElement('orthogonalprojection', JXG.createOrthogonalProjection);
3076     JXG.registerElement('parallel', JXG.createParallel);
3077     JXG.registerElement('parallelpoint', JXG.createParallelPoint);
3078     JXG.registerElement('perpendicular', JXG.createPerpendicular);
3079     JXG.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);
3080     JXG.registerElement('perpendicularsegment', JXG.createPerpendicularSegment);
3081     JXG.registerElement('reflection', JXG.createReflection);
3082     JXG.registerElement('grid', JXG.createGrid);
3083     JXG.registerElement('inequality', JXG.createInequality);
3084 
3085     return {
3086         createArrowParallel: JXG.createArrowParallel,
3087         createBisector: JXG.createBisector,
3088         createAngularBisectorOfTwoLines: JXG.createAngularBisectorsOfTwoLines,
3089         createCircumcircle: JXG.createCircumcircle,
3090         createCircumcenter: JXG.createCircumcenter,
3091         createIncenter: JXG.createIncenter,
3092         createIncircle: JXG.createIncircle,
3093         createIntegral: JXG.createIntegral,
3094         createMidpoint: JXG.createMidpoint,
3095         createMirrorElement: JXG.createMirrorElement,
3096         createMirrorPoint: JXG.createMirrorPoint,
3097         createNormal: JXG.createNormal,
3098         createOrthogonalProjection: JXG.createOrthogonalProjection,
3099         createParallel: JXG.createParallel,
3100         createParallelPoint: JXG.createParallelPoint,
3101         createPerpendicular: JXG.createPerpendicular,
3102         createPerpendicularPoint: JXG.createPerpendicularPoint,
3103         createPerpendicularSegmen: JXG.createPerpendicularSegment,
3104         createReflection: JXG.createReflection,
3105         createGrid: JXG.createGrid,
3106         createInequality: JXG.createInequality
3107     };
3108 });
3109