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