1 /*
  2     Copyright 2008-2021
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 13 
 14     You can redistribute it and/or modify it under the terms of the
 15 
 16       * GNU Lesser General Public License as published by
 17         the Free Software Foundation, either version 3 of the License, or
 18         (at your option) any later version
 19       OR
 20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 21 
 22     JSXGraph is distributed in the hope that it will be useful,
 23     but WITHOUT ANY WARRANTY; without even the implied warranty of
 24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25     GNU Lesser General Public License for more details.
 26 
 27     You should have received a copy of the GNU Lesser General Public License and
 28     the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
 29     and <http://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 
 33 /*global JXG: true, define: true*/
 34 /*jslint nomen: true, plusplus: true*/
 35 
 36 /* depends:
 37  jxg
 38  math/math
 39  math/geometry
 40  math/numerics
 41  math/statistics
 42  math/symbolic
 43  base/composition
 44  base/coords
 45  base/constants
 46  utils/type
 47   elements:
 48    line
 49    circle
 50    transform
 51    point
 52    glider
 53    text
 54    curve
 55  */
 56 
 57 /**
 58  * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together
 59  * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here
 60  * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the
 61  * following compositions can be found: <ul>
 62  *   <li>{@link Arrowparallel} (currently private)</li>
 63  *   <li>{@link Bisector}</li>
 64  *   <li>{@link Msector}</li>
 65  *   <li>{@link Circumcircle}</li>
 66  *   <li>{@link Circumcirclemidpoint}</li>
 67  *   <li>{@link Integral}</li>
 68  *   <li>{@link Midpoint}</li>
 69  *   <li>{@link Mirrorpoint}</li>
 70  *   <li>{@link Normal}</li>
 71  *   <li>{@link Orthogonalprojection}</li>
 72  *   <li>{@link Parallel}</li>
 73  *   <li>{@link Perpendicular}</li>
 74  *   <li>{@link Perpendicularpoint}</li>
 75  *   <li>{@link Perpendicularsegment}</li>
 76  *   <li>{@link Reflection}</li></ul>
 77  */
 78 
 79 define([
 80     'jxg', 'math/math', 'math/geometry', 'math/numerics', 'base/coords',
 81     'utils/type', 'base/constants', 'base/point', 'base/line', 'base/circle', 'base/transformation',
 82     'base/composition', 'base/curve', 'base/polygon'
 83 ], function (JXG, Mat, Geometry, Numerics, Coords,
 84     Type, Const, Point, Line, Circle, Transform,
 85     Composition, Curve, Polygon) {
 86 
 87     "use strict";
 88 
 89     /**
 90      * @class This is used to construct a point that is the orthogonal projection of a point to a line.
 91      * @pseudo
 92      * @description An orthogonal projection is given by a point and a line. It is determined by projecting the given point
 93      * orthogonal onto the given line.
 94      * @constructor
 95      * @name Orthogonalprojection
 96      * @type JXG.Point
 97      * @augments JXG.Point
 98      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 99      * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
100      * @example
101      * var p1 = board.create('point', [0.0, 4.0]);
102      * var p2 = board.create('point', [6.0, 1.0]);
103      * var l1 = board.create('line', [p1, p2]);
104      * var p3 = board.create('point', [3.0, 3.0]);
105      *
106      * var pp1 = board.create('orthogonalprojection', [p3, l1]);
107      * </pre><div class="jxgbox" id="JXG7708b215-39fa-41b6-b972-19d73d77d791" style="width: 400px; height: 400px;"></div>
108      * <script type="text/javascript">
109      *   var ppex1_board = JXG.JSXGraph.initBoard('JXG7708b215-39fa-41b6-b972-19d73d77d791', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
110      *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
111      *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
112      *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
113      *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
114      *   var ppex1_pp1 = ppex1_board.create('orthogonalprojection', [ppex1_p3, ppex1_l1]);
115      * </script><pre>
116      */
117     JXG.createOrthogonalProjection = function (board, parents, attributes) {
118         var l, p, t, attr;
119 
120         parents[0] = board.select(parents[0]);
121         parents[1] = board.select(parents[1]);
122 
123         if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
124             p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
125             l = parents[1];
126         } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
127             p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
128             l = parents[0];
129         } else {
130             throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
131                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
132                 "\nPossible parent types: [point,line]");
133         }
134 
135         attr = Type.copyAttributes(attributes, board.options, 'orthogonalprojection');
136 
137         t = board.create('point', [
138             function () {
139                 return Geometry.projectPointToLine(p, l, board);
140             }
141         ], attr);
142 
143         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="JXGd5b78842-7b27-4d37-b608-d02519e6cd03" style="width: 400px; height: 400px;"></div>
232      * <script type="text/javascript">
233      *   var pex1_board = JXG.JSXGraph.initBoard('JXGd5b78842-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="JXGded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div>
298      * <script type="text/javascript">
299      *   var ppex1_board = JXG.JSXGraph.initBoard('JXGded148c9-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="JXG037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div>
418      * <script type="text/javascript">
419      *   var pex1_board = JXG.JSXGraph.initBoard('JXG037a6eb2-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="JXG7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div>
498      * <script type="text/javascript">
499      *   var mpex1_board = JXG.JSXGraph.initBoard('JXG7927ef86-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="JXG488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div>
618      * <script type="text/javascript">
619      *   var ppex1_board = JXG.JSXGraph.initBoard('JXG488c4be9-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      * @class A parallel is a line through a given point with the same slope as a given line.
736      * @pseudo
737      * @name Parallel
738      * @augments Line
739      * @constructor
740      * @type JXG.Line
741      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
742      * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l.
743      * @example
744      * // Create a parallel
745      * var p1 = board.create('point', [0.0, 2.0]);
746      * var p2 = board.create('point', [2.0, 1.0]);
747      * var l1 = board.create('line', [p1, p2]);
748      *
749      * var p3 = board.create('point', [3.0, 3.0]);
750      * var pl1 = board.create('parallel', [l1, p3]);
751      * </pre><div class="jxgbox" id="JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div>
752      * <script type="text/javascript">
753      *   var plex1_board = JXG.JSXGraph.initBoard('JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
754      *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
755      *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
756      *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
757      *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
758      *   var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);
759      * </script><pre>
760      */
761     JXG.createParallel = function (board, parents, attributes) {
762         var p, pp, pl, li, i, attr;
763 
764         for (i = 0; i < parents.length; ++i) {
765             parents[i] = board.select(parents[i]);
766         }
767         p = null;
768         if (parents.length === 3) {
769             parents = Type.providePoints(board, parents, attributes, 'point');
770             // line through point parents[2] which is parallel to line through parents[0] and parents[1]
771             p = parents[2];
772             /** @ignore */
773             li = function () {
774                 return Mat.crossProduct(parents[0].coords.usrCoords, parents[1].coords.usrCoords);
775             };
776         } else if (Type.isPointType(board, parents[0])) {
777             // Parallel to line parents[1] through point parents[0]
778             p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
779             /** @ignore */
780             li = function () {
781                 return parents[1].stdform;
782             };
783         } else if (Type.isPointType(board, parents[1])) {
784             // Parallel to line parents[0] through point parents[1]
785             p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
786             /** @ignore */
787             li = function () {
788                 return parents[0].stdform;
789             };
790         }
791 
792         if (!Type.exists(attributes.layer)) {
793             attributes.layer = board.options.layer.line;
794         }
795 
796         attr = Type.copyAttributes(attributes, board.options, 'parallel', 'point');
797         pp = board.create('point', [
798             function () {
799                 return Mat.crossProduct([1, 0, 0], li());
800             }
801         ], attr);
802         pp.isDraggable = true;
803 
804         attr = Type.copyAttributes(attributes, board.options, 'parallel');
805         pl = board.create('line', [p, pp], attr);
806 
807         pl.elType = 'parallel';
808         pl.subs = {
809             point: pp
810         };
811         pl.inherits.push(pp);
812         pl.setParents([parents[0].id, parents[1].id]);
813         if (parents.length === 3) {
814             pl.addParents(parents[2].id);
815         }
816 
817         /**
818          * Helper point used to create the parallel line. This point lies on the line at infinity, hence it's not visible,
819          * not even with visible set to <tt>true</tt>. Creating another line through this point would make that other line
820          * parallel to the create parallel.
821          * @memberOf Parallel.prototype
822          * @name point
823          * @type JXG.Point
824          */
825         pl.point = pp;
826 
827         return pl;
828     };
829 
830     /**
831      * @class An arrow parallel is a parallel segment with an arrow attached.
832      * @pseudo
833      * @constructor
834      * @name Arrowparallel
835      * @type Parallel
836      * @augments Parallel
837      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
838      * @param {JXG.Line_JXG.Point} l,p The constructed arrow contains p and has the same slope as l.
839      * @example
840      * // Create a parallel
841      * var p1 = board.create('point', [0.0, 2.0]);
842      * var p2 = board.create('point', [2.0, 1.0]);
843      * var l1 = board.create('line', [p1, p2]);
844      *
845      * var p3 = board.create('point', [3.0, 3.0]);
846      * var pl1 = board.create('arrowparallel', [l1, p3]);
847      * </pre><div class="jxgbox" id="JXGeeacdf99-036f-4e83-aeb6-f7388423e369" style="width: 400px; height: 400px;"></div>
848      * <script type="text/javascript">
849      * (function () {
850      *   var plex1_board = JXG.JSXGraph.initBoard('JXGeeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
851      *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
852      *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
853      *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
854      *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
855      *   var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_l1, plex1_p3]);
856      * })();
857      * </script><pre>
858      */
859     JXG.createArrowParallel = function (board, parents, attributes) {
860         var p;
861 
862         /* parallel arrow point polynomials are done in createParallelPoint */
863         try {
864             attributes.firstArrow = false;
865             attributes.lastArrow = true;
866             p = JXG.createParallel(board, parents, attributes).setAttribute({straightFirst: false, straightLast: false});
867             p.elType = 'arrowparallel';
868 
869             // parents are set in createParallel
870 
871             return p;
872         } catch (e) {
873             throw new Error("JSXGraph: Can't create arrowparallel with parent types '" +
874                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
875                 "\nPossible parent types: [line,point], [point,point,point]");
876         }
877     };
878 
879     /**
880      * @class Constructs a normal.
881      * @pseudo
882      * @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.
883      * @constructor
884      * @name Normal
885      * @type JXG.Line
886      * @augments JXG.Line
887      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
888      * @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
889      * to the tangent to the object in the given point.
890      * @param {Glider} p Works like above, however the object is given by {@link JXG.CoordsElement#slideObject}.
891      * @example
892      * // Create a normal to a circle.
893      * var p1 = board.create('point', [2.0, 2.0]);
894      * var p2 = board.create('point', [3.0, 2.0]);
895      * var c1 = board.create('circle', [p1, p2]);
896      *
897      * var norm1 = board.create('normal', [c1, p2]);
898      * </pre><div class="jxgbox" id="JXG4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div>
899      * <script type="text/javascript">
900      *   var nlex1_board = JXG.JSXGraph.initBoard('JXG4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
901      *   var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]);
902      *   var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]);
903      *   var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]);
904      *
905      *   // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]);
906      *   var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]);
907      * </script><pre>
908      */
909     JXG.createNormal = function (board, parents, attributes) {
910         var p, c, l, i, g, f, attr, pp, attrp;
911 
912         for (i = 0; i < parents.length; ++i) {
913             parents[i] = board.select(parents[i]);
914         }
915         // One arguments: glider on line, circle or curve
916         if (parents.length === 1) {
917             p = parents[0];
918             c = p.slideObject;
919         // Two arguments: (point,line), (point,circle), (line,point) or (circle,point)
920         } else if (parents.length === 2) {
921             if (Type.isPointType(board, parents[0])) {
922                 p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];
923                 c = parents[1];
924             } else if (Type.isPointType(board, parents[1])) {
925                 c = parents[0];
926                 p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];
927             } else {
928                 throw new Error("JSXGraph: Can't create normal with parent types '" +
929                     (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
930                     "\nPossible parent types: [point,line], [point,circle], [glider]");
931             }
932         } else {
933             throw new Error("JSXGraph: Can't create normal with parent types '" +
934                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
935                 "\nPossible parent types: [point,line], [point,circle], [glider]");
936         }
937 
938         attr = Type.copyAttributes(attributes, board.options, 'normal');
939         if (c.elementClass === Const.OBJECT_CLASS_LINE) {
940             // Private point
941             attrp = Type.copyAttributes(attributes, board.options, 'normal', 'point');
942             pp = board.create('point', [
943                 function () {
944                     var p = Mat.crossProduct([1, 0, 0], c.stdform);
945                     return [p[0], -p[2], p[1]];
946                 }
947             ], attrp);
948             pp.isDraggable = true;
949 
950             l = board.create('line', [p, pp], attr);
951 
952             /**
953              * A helper point used to create a normal to a {@link JXG.Line} object. For normals to circles or curves this
954              * element is <tt>undefined</tt>.
955              * @type JXG.Point
956              * @name point
957              * @memberOf Normal.prototype
958              */
959             l.point = pp;
960             l.subs = {
961                 point: pp
962             };
963             l.inherits.push(pp);
964         } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE) {
965             l = board.create('line', [c.midpoint, p], attr);
966         } else if (c.elementClass === Const.OBJECT_CLASS_CURVE) {
967             if (Type.evaluate(c.visProp.curvetype) !== 'plot') {
968                 g = c.X;
969                 f = c.Y;
970                 l = board.create('line', [
971                     function () {
972                         return -p.X() * Numerics.D(g)(p.position) - p.Y() * Numerics.D(f)(p.position);
973                     },
974                     function () {
975                         return Numerics.D(g)(p.position);
976                     },
977                     function () {
978                         return Numerics.D(f)(p.position);
979                     }
980                 ], attr);
981             } else {                         // curveType 'plot'
982                 l = board.create('line', [
983                     function () {
984                         var i = Math.floor(p.position),
985                             lbda = p.position - i;
986 
987                         if (i === c.numberPoints - 1) {
988                             i -= 1;
989                             lbda = 1;
990                         }
991 
992                         if (i < 0) {
993                             return 1;
994                         }
995 
996                         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));
997                     },
998                     function () {
999                         var i = Math.floor(p.position);
1000 
1001                         if (i === c.numberPoints - 1) {
1002                             i -= 1;
1003                         }
1004 
1005                         if (i < 0) {
1006                             return 0;
1007                         }
1008 
1009                         return c.X(i + 1) - c.X(i);
1010                     },
1011                     function () {
1012                         var i = Math.floor(p.position);
1013 
1014                         if (i === c.numberPoints - 1) {
1015                             i -= 1;
1016                         }
1017 
1018                         if (i < 0) {
1019                             return 0;
1020                         }
1021 
1022                         return c.Y(i + 1) - c.Y(i);
1023                     }
1024                 ], attr);
1025             }
1026         } else if (c.type === Const.OBJECT_TYPE_TURTLE) {
1027             l = board.create('line', [
1028                 function () {
1029                     var el, j,
1030                         i = Math.floor(p.position),
1031                         lbda = p.position - i;
1032 
1033                     // run through all curves of this turtle
1034                     for (j = 0; j < c.objects.length; j++) {
1035                         el = c.objects[j];
1036 
1037                         if (el.type === Const.OBJECT_TYPE_CURVE) {
1038                             if (i < el.numberPoints) {
1039                                 break;
1040                             }
1041 
1042                             i -= el.numberPoints;
1043                         }
1044                     }
1045 
1046                     if (i === el.numberPoints - 1) {
1047                         i -= 1;
1048                         lbda = 1;
1049                     }
1050 
1051                     if (i < 0) {
1052                         return 1;
1053                     }
1054 
1055                     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));
1056                 },
1057                 function () {
1058                     var el, j,
1059                         i = Math.floor(p.position);
1060 
1061                     // run through all curves of this turtle
1062                     for (j = 0; j < c.objects.length; j++) {
1063                         el = c.objects[j];
1064                         if (el.type === Const.OBJECT_TYPE_CURVE) {
1065                             if (i < el.numberPoints) {
1066                                 break;
1067                             }
1068 
1069                             i -= el.numberPoints;
1070                         }
1071                     }
1072 
1073                     if (i === el.numberPoints - 1) {
1074                         i -=  1;
1075                     }
1076 
1077                     if (i < 0) {
1078                         return 0;
1079                     }
1080 
1081                     return el.X(i + 1) - el.X(i);
1082                 },
1083                 function () {
1084                     var el, j,
1085                         i = Math.floor(p.position);
1086 
1087                     // run through all curves of this turtle
1088                     for (j = 0; j < c.objects.length; j++) {
1089                         el = c.objects[j];
1090                         if (el.type === Const.OBJECT_TYPE_CURVE) {
1091                             if (i < el.numberPoints) {
1092                                 break;
1093                             }
1094 
1095                             i -= el.numberPoints;
1096                         }
1097                     }
1098 
1099                     if (i === el.numberPoints - 1) {
1100                         i -= 1;
1101                     }
1102 
1103                     if (i < 0) {
1104                         return 0;
1105                     }
1106 
1107                     return el.Y(i + 1) - el.Y(i);
1108                 }
1109             ], attr);
1110         } else {
1111             throw new Error("JSXGraph: Can't create normal with parent types '" +
1112                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1113                 "\nPossible parent types: [point,line], [point,circle], [glider]");
1114         }
1115 
1116         l.elType = 'normal';
1117         l.setParents(parents);
1118 
1119         return l;
1120     };
1121 
1122     /**
1123      * @class A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and
1124      * C and divides the angle ABC into two equal sized parts.
1125      * @pseudo
1126      * @constructor
1127      * @name Bisector
1128      * @type JXG.Line
1129      * @augments JXG.Line
1130      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1131      * @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
1132      * be divided into two equal angles.
1133      * @example
1134      * var p1 = board.create('point', [6.0, 4.0]);
1135      * var p2 = board.create('point', [3.0, 2.0]);
1136      * var p3 = board.create('point', [1.0, 7.0]);
1137      *
1138      * var bi1 = board.create('bisector', [p1, p2, p3]);
1139      * </pre><div class="jxgbox" id="JXG0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div>
1140      * <script type="text/javascript">
1141      * (function () {
1142      *   var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1143      *   var p1 = board.create('point', [6.0, 4.0]);
1144      *   var p2 = board.create('point', [3.0, 2.0]);
1145      *   var p3 = board.create('point', [1.0, 7.0]);
1146      *   var bi1 = board.create('bisector', [p1, p2, p3]);
1147      * })();
1148      * </script><pre>
1149      */
1150     JXG.createBisector = function (board, parents, attributes) {
1151         var p, l, i, attr;
1152 
1153         parents = Type.providePoints(board, parents, attributes, 'point');
1154         if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {
1155             // hidden and fixed helper
1156             attr = Type.copyAttributes(attributes, board.options, 'bisector', 'point');
1157             attr.snapToGrid = false;
1158 
1159             p = board.create('point', [
1160                 function () {
1161                     return Geometry.angleBisector(parents[0], parents[1], parents[2], board);
1162                 }
1163             ], attr);
1164             p.dump = false;
1165 
1166             for (i = 0; i < 3; i++) {
1167                 // required for algorithm requiring dependencies between elements
1168                 parents[i].addChild(p);
1169             }
1170 
1171             if (!Type.exists(attributes.layer)) {
1172                 attributes.layer = board.options.layer.line;
1173             }
1174 
1175             attr = Type.copyAttributes(attributes, board.options, 'bisector');
1176             l = Line.createLine(board, [parents[1], p], attr);
1177 
1178             /**
1179              * Helper point
1180              * @memberOf Bisector.prototype
1181              * @type Point
1182              * @name point
1183              */
1184             l.point = p;
1185 
1186             l.elType = 'bisector';
1187             l.setParents(parents);
1188             l.subs = {
1189                 point: p
1190             };
1191             l.inherits.push(p);
1192 
1193             return l;
1194         }
1195 
1196         throw new Error("JSXGraph: Can't create angle bisector with parent types '" +
1197             (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1198             "\nPossible parent types: [point,point,point]");
1199     };
1200 
1201     /**
1202      * @class Bisector lines are similar to {@link Bisector} but takes two lines as parent elements. The resulting element is
1203      * a composition of two lines.
1204      * @pseudo
1205      * @constructor
1206      * @name Bisectorlines
1207      * @type JXG.Composition
1208      * @augments JXG.Composition
1209      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1210      * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each
1211      * be divided into two equal angles.
1212      * @example
1213      * var p1 = board.create('point', [6.0, 4.0]);
1214      * var p2 = board.create('point', [3.0, 2.0]);
1215      * var p3 = board.create('point', [1.0, 7.0]);
1216      * var p4 = board.create('point', [3.0, 0.0]);
1217      * var l1 = board.create('line', [p1, p2]);
1218      * var l2 = board.create('line', [p3, p4]);
1219      *
1220      * var bi1 = board.create('bisectorlines', [l1, l2]);
1221      * </pre><div class="jxgbox" id="JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18" style="width: 400px; height: 400px;"></div>
1222      * <script type="text/javascript">
1223      * (function () {
1224      *   var board = JXG.JSXGraph.initBoard('JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1225      *   var p1 = board.create('point', [6.0, 4.0]);
1226      *   var p2 = board.create('point', [3.0, 2.0]);
1227      *   var p3 = board.create('point', [1.0, 7.0]);
1228      *   var p4 = board.create('point', [3.0, 0.0]);
1229      *   var l1 = board.create('line', [p1, p2]);
1230      *   var l2 = board.create('line', [p3, p4]);
1231      *   var bi1 = board.create('bisectorlines', [l1, l2]);
1232      * })();
1233      * </script><pre>
1234      */
1235     JXG.createAngularBisectorsOfTwoLines = function (board, parents, attributes) {
1236         // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation:
1237         // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2)
1238 
1239         var g1, g2, attr, ret,
1240             l1 = board.select(parents[0]),
1241             l2 = board.select(parents[1]);
1242 
1243         if (l1.elementClass !== Const.OBJECT_CLASS_LINE || l2.elementClass !== Const.OBJECT_CLASS_LINE) {
1244             throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" +
1245                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1246                 "\nPossible parent types: [line,line]");
1247         }
1248 
1249         if (!Type.exists(attributes.layer)) {
1250             attributes.layer = board.options.layer.line;
1251         }
1252 
1253         attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line1');
1254         g1 = board.create('line', [
1255             function () {
1256                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1257                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1258 
1259                 return l1.stdform[0] / d1 - l2.stdform[0] / d2;
1260             },
1261             function () {
1262                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1263                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1264 
1265                 return l1.stdform[1] / d1 - l2.stdform[1] / d2;
1266             },
1267             function () {
1268                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1269                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1270 
1271                 return l1.stdform[2] / d1 - l2.stdform[2] / d2;
1272             }
1273         ], attr);
1274 
1275         if (!Type.exists(attributes.layer)) {
1276             attributes.layer = board.options.layer.line;
1277         }
1278         attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line2');
1279         g2 = board.create('line', [
1280             function () {
1281                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1282                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1283 
1284                 return l1.stdform[0] / d1 + l2.stdform[0] / d2;
1285             },
1286             function () {
1287                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1288                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1289 
1290                 return l1.stdform[1] / d1 + l2.stdform[1] / d2;
1291             },
1292             function () {
1293                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1294                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1295 
1296                 return l1.stdform[2] / d1 + l2.stdform[2] / d2;
1297             }
1298         ], attr);
1299 
1300         // documentation
1301         /**
1302          * First line.
1303          * @memberOf Bisectorlines.prototype
1304          * @name line1
1305          * @type Line
1306          */
1307 
1308         /**
1309          * Second line.
1310          * @memberOf Bisectorlines.prototype
1311          * @name line2
1312          * @type Line
1313          */
1314 
1315         ret = new Composition({line1: g1, line2: g2});
1316 
1317         g1.dump = false;
1318         g2.dump = false;
1319 
1320         ret.elType = 'bisectorlines';
1321         ret.setParents([l1.id, l2.id]);
1322         ret.subs = {
1323             line1: g1,
1324             line2: g2
1325         };
1326         // ret.inherits.push(g1, g2);
1327 
1328         return ret;
1329     };
1330 
1331     // /**
1332     //  * @class An m-sector is a line which divides an angle into two angles. It is given by three points A, B, and
1333     //  * C and a real number m, and divides an angle into two angles, an angle with amplitude m and an angle with
1334     //  * amplitude (1-m)
1335     //  * @pseudo
1336     //  * @constructor
1337     //  * @name Msector
1338     //  * @type JXG.Line
1339     //  * @augments JXG.Line
1340     //  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1341     //  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will
1342     //  * be divided into two angles according to the value of <tt>m</tt>.
1343     //  * @example
1344     //  * var p1 = board.create('point', [6.0, 4.0]);
1345     //  * var p2 = board.create('point', [3.0, 2.0]);
1346     //  * var p3 = board.create('point', [1.0, 7.0]);
1347     //  *
1348     //  * var bi1 = board.create('msector', [p1, p2, p3], 1/5);
1349     //  * </pre><div id="JXG0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div>
1350     //  * <script type="text/javascript">
1351     //  * (function () {
1352     //  *   var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1353     //  *   var p1 = board.create('point', [6.0, 4.0]);
1354     //  *   var p2 = board.create('point', [3.0, 2.0]);
1355     //  *   var p3 = board.create('point', [1.0, 7.0]);
1356     //  *   var bi1 = board.create('msector', [p1, p2, p3], 1/5);
1357     //  * })();
1358     //  * </script><pre>
1359     //  */
1360     // JXG.createMsector = function (board, parents, attributes) {
1361     //     var p, l, i, attr;
1362 
1363     //     if (parents[0].elementClass === Const.OBJECT_CLASS_POINT &&
1364     //             parents[1].elementClass === Const.OBJECT_CLASS_POINT &&
1365     //             parents[2].elementClass === Const.OBJECT_CLASS_POINT) {
1366     //         // hidden and fixed helper
1367     //         attr = Type.copyAttributes(attributes, board.options, 'msector', 'point');
1368     //         p = board.create('point', [
1369     //             function () {
1370     //                 return Geometry.angleMsector(parents[0], parents[1], parents[2], parents[3], board);
1371     //             }
1372     //         ], attr);
1373     //         p.dump = false;
1374 
1375     //         for (i = 0; i < 3; i++) {
1376     //             // required for algorithm requiring dependencies between elements
1377     //             parents[i].addChild(p);
1378     //         }
1379 
1380     //         if (!Type.exists(attributes.layer)) {
1381     //             attributes.layer = board.options.layer.line;
1382     //         }
1383 
1384     //         attr = Type.copyAttributes(attributes, board.options, 'msector');
1385     //         l = Line.createLine(board, [parents[1], p], attr);
1386 
1387     //         /**
1388     //          * Helper point
1389     //          * @memberOf Msector.prototype
1390     //          * @type Point
1391     //          * @name point
1392     //          */
1393     //         l.point = p;
1394 
1395     //         l.elType = 'msector';
1396     //         l.parents = [parents[0].id, parents[1].id, parents[2].id];
1397     //         l.subs = {
1398     //             point: p
1399     //         };
1400     //         l.inherits.push(p);
1401 
1402     //         return l;
1403     //     }
1404 
1405     //     throw new Error("JSXGraph: Can't create angle msector with parent types '" +
1406     //         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1407     //         "\nPossible parent types: [point,point,point,Number]");
1408     // };
1409 
1410     /**
1411      * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter
1412      * is constructed by providing three points.
1413      * @pseudo
1414      * @description A circumcenter is given by three points which are all lying on the circle with the
1415      * constructed circumcenter as the midpoint.
1416      * @constructor
1417      * @name Circumcenter
1418      * @type JXG.Point
1419      * @augments JXG.Point
1420      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1421      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined
1422      * by p1, p2, and p3.
1423      * @example
1424      * var p1 = board.create('point', [0.0, 2.0]);
1425      * var p2 = board.create('point', [2.0, 1.0]);
1426      * var p3 = board.create('point', [3.0, 3.0]);
1427      *
1428      * var cc1 = board.create('circumcenter', [p1, p2, p3]);
1429      * </pre><div class="jxgbox" id="JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div>
1430      * <script type="text/javascript">
1431      *   var ccmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1432      *   var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]);
1433      *   var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]);
1434      *   var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]);
1435      *   var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]);
1436      * </script><pre>
1437      */
1438     JXG.createCircumcenter = function (board, parents, attributes) {
1439         var p, i, a, b, c;
1440 
1441         parents = Type.providePoints(board, parents, attributes, 'point');
1442         if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {
1443 
1444             a = parents[0];
1445             b = parents[1];
1446             c = parents[2];
1447 
1448             p = Point.createPoint(board, [
1449                 function () {
1450                     return Geometry.circumcenter(a, b, c, board);
1451                 }
1452             ], attributes);
1453 
1454             for (i = 0; i < 3; i++) {
1455                 parents[i].addChild(p);
1456             }
1457 
1458             p.elType = 'circumcenter';
1459             p.setParents(parents);
1460 
1461             p.generatePolynomial = function () {
1462                 /*
1463                  *  CircumcircleMidpoint takes three points A, B and C  and creates point M, which is the circumcenter of A, B, and C.
1464                  *
1465                  *
1466                  * So we have two conditions:
1467                  *
1468                  *   (a)   CT  ==  AT           (distance condition I)
1469                  *   (b)   BT  ==  AT           (distance condition II)
1470                  *
1471                  */
1472                 var a1 = a.symbolic.x,
1473                     a2 = a.symbolic.y,
1474                     b1 = b.symbolic.x,
1475                     b2 = b.symbolic.y,
1476                     c1 = c.symbolic.x,
1477                     c2 = c.symbolic.y,
1478                     t1 = p.symbolic.x,
1479                     t2 = p.symbolic.y,
1480 
1481                     poly1 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', b1, '))^2-((', t2, ')-(', b2, '))^2'].join(''),
1482                     poly2 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', c1, '))^2-((', t2, ')-(', c2, '))^2'].join('');
1483 
1484                 return [poly1, poly2];
1485             };
1486 
1487             return p;
1488         }
1489 
1490         throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" +
1491             (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1492             "\nPossible parent types: [point,point,point]");
1493     };
1494 
1495     /**
1496      * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html}
1497      * @pseudo
1498      * @constructor
1499      * @name Incenter
1500      * @type JXG.Point
1501      * @augments JXG.Point
1502      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1503      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described
1504      * by p1, p2, and p3.
1505      * @example
1506      * var p1 = board.create('point', [0.0, 2.0]);
1507      * var p2 = board.create('point', [2.0, 1.0]);
1508      * var p3 = board.create('point', [3.0, 3.0]);
1509      *
1510      * var ic1 = board.create('incenter', [p1, p2, p3]);
1511      * </pre><div class="jxgbox" id="JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div>
1512      * <script type="text/javascript">
1513      *   var icmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1514      *   var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]);
1515      *   var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]);
1516      *   var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]);
1517      *   var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]);
1518      * </script><pre>
1519      */
1520     JXG.createIncenter = function (board, parents, attributes) {
1521         var p, A, B, C;
1522 
1523         parents = Type.providePoints(board, parents, attributes, 'point');
1524         if (parents.length >= 3 && Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {
1525             A = parents[0];
1526             B = parents[1];
1527             C = parents[2];
1528 
1529             p = board.create('point', [function () {
1530                 var a, b, c;
1531 
1532                 a = Math.sqrt((B.X() - C.X()) * (B.X() - C.X()) + (B.Y() - C.Y()) * (B.Y() - C.Y()));
1533                 b = Math.sqrt((A.X() - C.X()) * (A.X() - C.X()) + (A.Y() - C.Y()) * (A.Y() - C.Y()));
1534                 c = Math.sqrt((B.X() - A.X()) * (B.X() - A.X()) + (B.Y() - A.Y()) * (B.Y() - A.Y()));
1535 
1536                 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);
1537             }], attributes);
1538 
1539             p.elType = 'incenter';
1540             p.setParents(parents);
1541 
1542         } else {
1543             throw new Error("JSXGraph: Can't create incenter with parent types '" +
1544                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1545                 "\nPossible parent types: [point,point,point]");
1546         }
1547 
1548         return p;
1549     };
1550 
1551     /**
1552      * @class A circumcircle is given by three points which are all lying on the circle.
1553      * @pseudo
1554      * @constructor
1555      * @name Circumcircle
1556      * @type JXG.Circle
1557      * @augments JXG.Circle
1558      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1559      * @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>.
1560      * @example
1561      * var p1 = board.create('point', [0.0, 2.0]);
1562      * var p2 = board.create('point', [2.0, 1.0]);
1563      * var p3 = board.create('point', [3.0, 3.0]);
1564      *
1565      * var cc1 = board.create('circumcircle', [p1, p2, p3]);
1566      * </pre><div class="jxgbox" id="JXGe65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div>
1567      * <script type="text/javascript">
1568      *   var ccex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1569      *   var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]);
1570      *   var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]);
1571      *   var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]);
1572      *   var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]);
1573      * </script><pre>
1574      */
1575     JXG.createCircumcircle = function (board, parents, attributes) {
1576         var p, c, attr;
1577 
1578         parents = Type.providePoints(board, parents, attributes, 'point');
1579         if (parents === false) {
1580             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1581                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1582                 "\nPossible parent types: [point,point,point]");
1583         }
1584 
1585         try {
1586             attr = Type.copyAttributes(attributes, board.options, 'circumcircle', 'center');
1587             p = JXG.createCircumcenter(board, parents, attr);
1588 
1589             p.dump = false;
1590 
1591             if (!Type.exists(attributes.layer)) {
1592                 attributes.layer = board.options.layer.circle;
1593             }
1594             attr = Type.copyAttributes(attributes, board.options, 'circumcircle');
1595             c = Circle.createCircle(board, [p, parents[0]], attr);
1596 
1597             c.elType = 'circumcircle';
1598             c.setParents(parents);
1599             c.subs = {
1600                 center: p
1601             };
1602             c.inherits.push(c);
1603         } catch (e) {
1604             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1605                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1606                 "\nPossible parent types: [point,point,point]");
1607         }
1608 
1609         // p is already stored as midpoint in c so there's no need to store it explicitly.
1610 
1611         return c;
1612     };
1613 
1614     /**
1615      * @class An incircle is given by three points.
1616      * @pseudo
1617      * @constructor
1618      * @name Incircle
1619      * @type JXG.Circle
1620      * @augments JXG.Circle
1621      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1622      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of
1623      * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.
1624      * @example
1625      * var p1 = board.create('point', [0.0, 2.0]);
1626      * var p2 = board.create('point', [2.0, 1.0]);
1627      * var p3 = board.create('point', [3.0, 3.0]);
1628      *
1629      * var ic1 = board.create('incircle', [p1, p2, p3]);
1630      * </pre><div class="jxgbox" id="JXGe65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div>
1631      * <script type="text/javascript">
1632      *   var icex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1633      *   var icex1_p1 = icex1_board.create('point', [0.0, 2.0]);
1634      *   var icex1_p2 = icex1_board.create('point', [6.0, 1.0]);
1635      *   var icex1_p3 = icex1_board.create('point', [3.0, 7.0]);
1636      *   var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]);
1637      * </script><pre>
1638      */
1639     JXG.createIncircle = function (board, parents, attributes) {
1640         var p, c, attr;
1641 
1642         parents = Type.providePoints(board, parents, attributes, 'point');
1643         if (parents === false) {
1644             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1645                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1646                 "\nPossible parent types: [point,point,point]");
1647         }
1648         try {
1649             attr = Type.copyAttributes(attributes, board.options, 'incircle', 'center');
1650             p = JXG.createIncenter(board, parents, attr);
1651 
1652             p.dump = false;
1653 
1654             if (!Type.exists(attributes.layer)) {
1655                 attributes.layer = board.options.layer.circle;
1656             }
1657             attr = Type.copyAttributes(attributes, board.options, 'incircle');
1658             c = Circle.createCircle(board, [p, function () {
1659                 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())),
1660                     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())),
1661                     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())),
1662                     s = (a + b + c) / 2;
1663 
1664                 return Math.sqrt(((s - a) * (s - b) * (s - c)) / s);
1665             }], attr);
1666 
1667             c.elType = 'incircle';
1668             c.setParents(parents);
1669 
1670             /**
1671              * The center of the incircle
1672              * @memberOf Incircle.prototype
1673              * @type Incenter
1674              * @name center
1675              */
1676             c.center = p;
1677 
1678             c.subs = {
1679                 center: c.center
1680             };
1681             c.inherits.push(p);
1682 
1683         } catch (e) {
1684             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1685                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1686                 "\nPossible parent types: [point,point,point]");
1687         }
1688 
1689         // p is already stored as midpoint in c so there's no need to store it explicitly.
1690 
1691         return c;
1692     };
1693 
1694     /**
1695      * @class This element is used to construct reflected elements (points, lines, circles, curves, polygons).
1696      * @pseudo
1697      * @description A reflected element (point, polygon, line or curve) is given by a given
1698      * object of the same type and a line of reflection.
1699      * It is determined by the reflection of the given element
1700      * across the given line.
1701      * @constructor
1702      * @name Reflection
1703      * @type JXG.GeometryElement
1704      * @augments JXG.GeometryElement
1705      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1706      * @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.
1707      * @example
1708      * var p1 = board.create('point', [0.0, 4.0]);
1709      * var p2 = board.create('point', [6.0, 1.0]);
1710      * var l1 = board.create('line', [p1, p2]);
1711      * var p3 = board.create('point', [3.0, 3.0]);
1712      *
1713      * var rp1 = board.create('reflection', [p3, l1]);
1714      * </pre><div class="jxgbox" id="JXG087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div>
1715      * <script type="text/javascript">
1716      *   var rpex1_board = JXG.JSXGraph.initBoard('JXG087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1717      *   var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]);
1718      *   var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]);
1719      *   var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]);
1720      *   var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]);
1721      *   var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]);
1722      * </script><pre>
1723      * @example
1724      *         // Reflection of more elements
1725      *         // reflection line
1726      *         var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});
1727      *
1728      *         var p1 = board.create('point', [-3,-1], {name: "A"});
1729      *         var q1 = board.create('reflection', [p1, li], {name: "A'"});
1730      *
1731      *         var l1 = board.create('line', [1,-5,1]);
1732      *         var l2 = board.create('reflection', [l1, li]);
1733      *
1734      *         var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});
1735      *         var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3});
1736      *
1737      *         var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]);
1738      *         var pol2 = board.create('reflection', [pol1, li]);
1739      *
1740      *         var c1 = board.create('circle', [[-2,-2], [-2, -1]]);
1741      *         var c2 = board.create('reflection', [c1, li]);
1742      *
1743      *         var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});
1744      *         var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'});
1745      *
1746      *         var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {
1747      *                           anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},
1748      *                           fillColor: 'yellow', strokeColor: 'black'});
1749      *         var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});
1750      *
1751      *         var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);
1752      *         var an2 = board.create('reflection', [an1, li]);
1753      *
1754      * </pre><div id="JXG8f763af4-d449-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div>
1755      * <script type="text/javascript">
1756      *     (function() {
1757      *         var board = JXG.JSXGraph.initBoard('JXG8f763af4-d449-11e7-93b3-901b0e1b8723',
1758      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
1759      *             // reflection line
1760      *             var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});
1761      *
1762      *             var p1 = board.create('point', [-3,-1], {name: "A"});
1763      *             var q1 = board.create('reflection', [p1, li], {name: "A'"});
1764      *
1765      *             var l1 = board.create('line', [1,-5,1]);
1766      *             var l2 = board.create('reflection', [l1, li]);
1767      *
1768      *             var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});
1769      *             var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3});
1770      *
1771      *             var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]);
1772      *             var pol2 = board.create('reflection', [pol1, li]);
1773      *
1774      *             var c1 = board.create('circle', [[-2,-2], [-2, -1]]);
1775      *             var c2 = board.create('reflection', [c1, li]);
1776      *
1777      *         var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});
1778      *         var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'});
1779      *
1780      *         var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {
1781      *                           anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},
1782      *                           fillColor: 'yellow', strokeColor: 'black'});
1783      *         var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});
1784      *
1785      *         var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);
1786      *         var an2 = board.create('reflection', [an1, li]);
1787      *
1788      *     })();
1789      *
1790      * </script><pre>
1791      *
1792      */
1793     JXG.createReflection = function (board, parents, attributes) {
1794         var l, org, r, r_c, t, i,
1795             attr, attr2,
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         attr = Type.copyAttributes(attributes, board.options, 'reflection');
1803 
1804         if (Type.isPoint(parents[0])) {
1805             org = Type.providePoints(board, [parents[0]], attr2)[0];
1806         } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE ||
1807                     parents[0].elementClass === Const.OBJECT_CLASS_LINE ||
1808                     parents[0].type === Const.OBJECT_TYPE_POLYGON ||
1809                     parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) {
1810             org = parents[0];
1811         } else {
1812             throw new Error("JSXGraph: Can't create reflection element with parent types '" +
1813                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
1814         }
1815 
1816         if (parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
1817             l = parents[1];
1818         } else {
1819             throw new Error("JSXGraph: Can't create reflected element with parent types '" +
1820                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
1821         }
1822 
1823         t = Transform.createTransform(board, [l], {type: 'reflect'});
1824         if (Type.isPoint(org)) {
1825             r = Point.createPoint(board, [org, t], attr);
1826         // Arcs and sectors are treated as curves
1827         } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){
1828             r = Curve.createCurve(board, [org, t], attr);
1829         } else if (org.elementClass === Const.OBJECT_CLASS_LINE){
1830             r = Line.createLine(board, [org, t], attr);
1831         } else if (org.type === Const.OBJECT_TYPE_POLYGON){
1832             r = Polygon.createPolygon(board, [org, t], attr);
1833         } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE) {
1834             if (attr.type.toLowerCase() === 'euclidean') {
1835                 // Create a circle element from a circle and a Euclidean transformation
1836                 attr2 = Type.copyAttributes(attributes, board.options, 'reflection', 'center');
1837                 r_c = Point.createPoint(board, [org.center, t], attr2);
1838                 r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer();
1839                 r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr);
1840             } else {
1841                 // Create a conic element from a circle and a projective transformation
1842                 r = Circle.createCircle(board, [org, t], attr);
1843             }
1844         } else {
1845             throw new Error("JSXGraph: Can't create reflected element with parent types '" +
1846                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
1847         }
1848         //org.addChild(r);
1849         l.addChild(r);
1850         r.elType = 'reflection';
1851         r.addParents(l);
1852         r.prepareUpdate().update(); //.updateVisibility(Type.evaluate(r.visProp.visible)).updateRenderer();
1853 
1854         if (Type.isPoint(r)) {
1855             r.generatePolynomial = function () {
1856                 /*
1857                  *  Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.
1858                  *  L is defined by two points A and B.
1859                  *
1860                  * So we have two conditions:
1861                  *
1862                  *   (a)   RP  _|_  AB            (orthogonality condition)
1863                  *   (b)   AR  ==   AP            (distance condition)
1864                  *
1865                  */
1866                 var a1 = l.point1.symbolic.x,
1867                     a2 = l.point1.symbolic.y,
1868                     b1 = l.point2.symbolic.x,
1869                     b2 = l.point2.symbolic.y,
1870                     p1 = org.symbolic.x,
1871                     p2 = org.symbolic.y,
1872                     r1 = r.symbolic.x,
1873                     r2 = r.symbolic.y,
1874 
1875                     poly1 = ['((', r2, ')-(', p2, '))*((', a2, ')-(', b2, '))+((', a1, ')-(', b1, '))*((', r1, ')-(', p1, '))'].join(''),
1876                     poly2 = ['((', r1, ')-(', a1, '))^2+((', r2, ')-(', a2, '))^2-((', p1, ')-(', a1, '))^2-((', p2, ')-(', a2, '))^2'].join('');
1877 
1878                 return [poly1, poly2];
1879             };
1880         }
1881 
1882         return r;
1883     };
1884 
1885     /**
1886      * @class A mirror element of a point, line, circle, curve, polygon will be constructed.
1887      * @pseudo
1888      * @description A mirror element is determined by the reflection of a given point, line, circle, curve, polygon across another given point.
1889      * @constructor
1890      * @name Mirrorelement
1891      * @type JXG.GeometryElement
1892      * @augments JXG.GeometryElement
1893      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1894      * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Ppolygon_JXG.Point} p1,p2 The constructed element is the mirror image of p2 across p1.
1895      * @example
1896      *         // point of reflection
1897      *         var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});
1898      *
1899      *         var p1 = board.create('point', [-3,-1], {name: "A"});
1900      *         var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"});
1901      *
1902      *         var l1 = board.create('line', [1, -5, 1]);
1903      *         var l2 = board.create('mirrorelement', [l1, mirr]);
1904      *
1905      *         var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});
1906      *         var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3});
1907      *
1908      *         var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]);
1909      *         var pol2 = board.create('mirrorelement', [pol1, mirr]);
1910      *
1911      *         var c1 = board.create('circle', [[-6,-6], [-6, -5]]);
1912      *         var c2 = board.create('mirrorelement', [c1, mirr]);
1913      *
1914      *         var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});
1915      *         var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'});
1916      *
1917      *         var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {
1918      *                           anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},
1919      *                           fillColor: 'yellow', strokeColor: 'black'});
1920      *         var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});
1921      *
1922      *         var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);
1923      *         var an2 = board.create('mirrorelement', [an1, mirr]);
1924      *
1925      *
1926      * </pre><div id="JXG026c779c-d8d9-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div>
1927      * <script type="text/javascript">
1928      *     (function() {
1929      *         var board = JXG.JSXGraph.initBoard('JXG026c779c-d8d9-11e7-93b3-901b0e1b8723',
1930      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
1931      *             // point of reflection
1932      *             var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});
1933      *
1934      *             var p1 = board.create('point', [-3,-1], {name: "A"});
1935      *             var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"});
1936      *
1937      *             var l1 = board.create('line', [1,-5, 1]);
1938      *             var l2 = board.create('mirrorelement', [l1, mirr]);
1939      *
1940      *             var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});
1941      *             var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3});
1942      *
1943      *             var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]);
1944      *             var pol2 = board.create('mirrorelement', [pol1, mirr]);
1945      *
1946      *             var c1 = board.create('circle', [[-6,-6], [-6, -5]]);
1947      *             var c2 = board.create('mirrorelement', [c1, mirr]);
1948      *
1949      *         var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});
1950      *         var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'});
1951      *
1952      *         var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {
1953      *                           anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},
1954      *                           fillColor: 'yellow', strokeColor: 'black'});
1955      *         var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});
1956      *
1957      *         var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);
1958      *         var an2 = board.create('mirrorelement', [an1, mirr]);
1959      *
1960      *     })();
1961      *
1962      * </script><pre>
1963      */
1964     JXG.createMirrorElement = function (board, parents, attributes) {
1965         var org, i, m, r, r_c, t,
1966             attr, attr2,
1967             errStr = "\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, point]";
1968 
1969         for (i = 0; i < parents.length; ++i) {
1970             parents[i] = board.select(parents[i]);
1971         }
1972 
1973         attr = Type.copyAttributes(attributes, board.options, 'mirrorelement');
1974         if (Type.isPoint(parents[0])) {
1975             // Create point to be mirrored if supplied by coords array.
1976             org = Type.providePoints(board, [parents[0]], attr)[0];
1977         } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE ||
1978                     parents[0].elementClass === Const.OBJECT_CLASS_LINE ||
1979                     parents[0].type === Const.OBJECT_TYPE_POLYGON ||
1980                     parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) {
1981             org = parents[0];
1982         } else {
1983             throw new Error("JSXGraph: Can't create mirror element with parent types '" +
1984                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
1985         }
1986 
1987         if (Type.isPoint(parents[1])) {
1988             attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'point');
1989             // Create mirror point if supplied by coords array.
1990             m = Type.providePoints(board, [parents[1]], attr2)[0];
1991         } else {
1992             throw new Error("JSXGraph: Can't create mirror element with parent types '" +
1993                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
1994         }
1995 
1996         t = Transform.createTransform(board, [Math.PI, m], {type: 'rotate'});
1997         if (Type.isPoint(org)) {
1998             r = Point.createPoint(board, [org, t], attr);
1999 
2000         // Arcs and sectors are treated as curves
2001         } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){
2002             r = Curve.createCurve(board, [org, t], attr);
2003         } else if (org.elementClass === Const.OBJECT_CLASS_LINE){
2004             r = Line.createLine(board, [org, t], attr);
2005         }  else if (org.type === Const.OBJECT_TYPE_POLYGON){
2006             r = Polygon.createPolygon(board, [org, t], attr);
2007         } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE){
2008             if (attr.type.toLowerCase() === 'euclidean') {
2009                 // Create a circle element from a circle and a Euclidean transformation
2010                 attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'center');
2011                 r_c = Point.createPoint(board, [org.center, t], attr2);
2012                 r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer();
2013                 r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr);
2014             } else {
2015                 // Create a conic element from a circle and a projective transformation
2016                 r = Circle.createCircle(board, [org, t], attr);
2017             }
2018         } else {
2019             throw new Error("JSXGraph: Can't create mirror element with parent types '" +
2020                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr);
2021         }
2022 
2023         //org.addChild(r);
2024         m.addChild(r);
2025         r.elType = 'mirrorelement';
2026         r.addParents(m);
2027         r.prepareUpdate().update();
2028 
2029         return r;
2030     };
2031 
2032     /**
2033      * @class A mirror point will be constructed.
2034      * @pseudo
2035      * @description A mirror point is determined by the reflection of a given point against another given point.
2036      * @constructor
2037      * @name Mirrorpoint
2038      * @type JXG.Point
2039      * @augments JXG.Point
2040      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2041      * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.
2042      *
2043      * This method is superseeded by the more general {@link JXG.createMirrorElement}.
2044      * @example
2045      * var p1 = board.create('point', [3.0, 3.0]);
2046      * var p2 = board.create('point', [6.0, 1.0]);
2047      *
2048      * var mp1 = board.create('mirrorpoint', [p1, p2]);
2049      * </pre><div class="jxgbox" id="JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div>
2050      * <script type="text/javascript">
2051      *   var mpex1_board = JXG.JSXGraph.initBoard('JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
2052      *   var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);
2053      *   var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);
2054      *   var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);
2055      * </script><pre>
2056      */
2057     JXG.createMirrorPoint = function (board, parents, attributes) {
2058         var el = JXG.createMirrorElement(board, parents, attributes);
2059         el.elType = 'mirrorpoint';
2060         return el;
2061     };
2062 
2063     /**
2064      * @class This element is used to visualize the integral of a given curve over a given interval.
2065      * @pseudo
2066      * @description The Integral element is used to visualize the area under a given curve over a given interval
2067      * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,
2068      * the gliders are used to change the interval dynamically.
2069      * @constructor
2070      * @name Integral
2071      * @type JXG.Curve
2072      * @augments JXG.Curve
2073      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2074      * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis
2075      * within the interval <tt>i</tt>.
2076      * @example
2077      * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);
2078      * var i1 = board.create('integral', [[-1.0, 4.0], c1]);
2079      * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
2080      * <script type="text/javascript">
2081      *   var intex1_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});
2082      *   var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]);
2083      *   var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);
2084      * </script><pre>
2085      */
2086     JXG.createIntegral = function (board, parents, attributes) {
2087         var interval, curve, attr,
2088             start, end, startx, starty, endx, endy,
2089             pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,
2090             t = null, p;
2091 
2092         if (Type.isArray(parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_CURVE) {
2093             interval = parents[0];
2094             curve = parents[1];
2095         } else if (Type.isArray(parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_CURVE) {
2096             interval = parents[1];
2097             curve = parents[0];
2098         } else {
2099             throw new Error("JSXGraph: Can't create integral with parent types '" +
2100                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
2101                 "\nPossible parent types: [[number|function,number|function],curve]");
2102         }
2103 
2104         attr = Type.copyAttributes(attributes, board.options, 'integral');
2105         attr.withLabel = false;  // There is a custom 'label' below.
2106         p = board.create('curve', [[0], [0]], attr);
2107 
2108         // Correct the interval if necessary - NOT ANYMORE, GGB's fault
2109         start = interval[0];
2110         end = interval[1];
2111 
2112         if (Type.isFunction(start)) {
2113             startx = start;
2114             starty = function () { return curve.Y(startx()); };
2115             start = startx();
2116         } else {
2117             startx = start;
2118             starty = curve.Y(start);
2119         }
2120 
2121         if (Type.isFunction(end)) {
2122             endx = end;
2123             endy = function () { return curve.Y(endx()); };
2124             end = endx();
2125         } else {
2126             endx = end;
2127             endy = curve.Y(end);
2128         }
2129 
2130         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveLeft');
2131         pa_on_curve = board.create('glider', [startx, starty, curve], attr);
2132         if (Type.isFunction(startx)) {
2133             pa_on_curve.hideElement();
2134         }
2135 
2136         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseLeft');
2137         pa_on_axis = board.create('point', [
2138             function () {
2139                 if (Type.evaluate(p.visProp.axis) === 'y') {
2140                     return 0;
2141                 }
2142 
2143                 return pa_on_curve.X();
2144             },
2145             function () {
2146                 if (Type.evaluate(p.visProp.axis) === 'y') {
2147                     return pa_on_curve.Y();
2148                 }
2149 
2150                 return 0;
2151             }
2152         ], attr);
2153 
2154         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveRight');
2155         pb_on_curve = board.create('glider', [endx, endy, curve], attr);
2156         if (Type.isFunction(endx)) {
2157             pb_on_curve.hideElement();
2158         }
2159 
2160         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseRight');
2161         pb_on_axis = board.create('point', [
2162             function () {
2163                 if (Type.evaluate(p.visProp.axis) === 'y') {
2164                     return 0;
2165                 }
2166                 return pb_on_curve.X();
2167             },
2168             function () {
2169                 if (Type.evaluate(p.visProp.axis) === 'y') {
2170                     return pb_on_curve.Y();
2171                 }
2172 
2173                 return 0;
2174             }
2175         ], attr);
2176 
2177         attr = Type.copyAttributes(attributes, board.options, 'integral');
2178         if (attr.withlabel !== false && attr.axis !== 'y') {
2179             attr = Type.copyAttributes(attributes, board.options, 'integral', 'label');
2180             attr = Type.copyAttributes(attr, board.options, 'label');
2181 
2182             t = board.create('text', [
2183                 function () {
2184                     var off = new Coords(Const.COORDS_BY_SCREEN, [
2185                             Type.evaluate(this.visProp.offset[0]) + this.board.origin.scrCoords[1],
2186                             0
2187                         ], this.board, false),
2188                         bb = this.board.getBoundingBox(),
2189                         dx = (bb[2] - bb[0]) * 0.1,
2190                         x = pb_on_curve.X();
2191 
2192                     if (x < bb[0]) {
2193                         x = bb[0] + dx;
2194                     } else if (x > bb[2]) {
2195                         x = bb[2] - dx;
2196                     }
2197 
2198                     return x + off.usrCoords[1];
2199                 },
2200                 function () {
2201                     var off = new Coords(Const.COORDS_BY_SCREEN, [
2202                             0,
2203                             Type.evaluate(this.visProp.offset[1]) + this.board.origin.scrCoords[2]
2204                         ], this.board, false),
2205                         bb = this.board.getBoundingBox(),
2206                         dy = (bb[1] - bb[3]) * 0.1,
2207                         y = pb_on_curve.Y();
2208 
2209                     if (y > bb[1]) {
2210                         y = bb[1] - dy;
2211                     } else if (y < bb[3]) {
2212                         y = bb[3] + dy;
2213                     }
2214 
2215                     return y + off.usrCoords[2];
2216                 },
2217                 function () {
2218                     var Int = Numerics.NewtonCotes([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
2219                     return '∫ = ' + Type.toFixed(Int, 4);
2220                 }
2221             ], attr);
2222 
2223             t.dump = false;
2224 
2225             pa_on_curve.addChild(t);
2226             pb_on_curve.addChild(t);
2227         }
2228 
2229         // dump stuff
2230         pa_on_curve.dump = false;
2231         pa_on_axis.dump = false;
2232 
2233         pb_on_curve.dump = false;
2234         pb_on_axis.dump = false;
2235 
2236         p.elType = 'integral';
2237         p.setParents([curve.id, interval]);
2238         p.subs = {
2239             curveLeft: pa_on_curve,
2240             baseLeft: pa_on_axis,
2241             curveRight: pb_on_curve,
2242             baseRight: pb_on_axis
2243         };
2244         p.inherits.push(pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis);
2245 
2246         if (attr.withLabel) {
2247             p.subs.label = t;
2248             p.inherits.push(t);
2249         }
2250 
2251         /**
2252          * Returns the current value of the integral.
2253          * @memberOf Integral
2254          * @name Value
2255          * @function
2256          * @returns {Number}
2257          */
2258         p.Value = function () {
2259             return Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
2260         };
2261 
2262         /**
2263          * documented in JXG.Curve
2264          * @ignore
2265          */
2266         p.updateDataArray = function () {
2267             var x, y,
2268                 i, left, right,
2269                 lowx, upx,
2270                 lowy, upy;
2271 
2272             if (Type.evaluate(this.visProp.axis) === 'y') {
2273                 if (pa_on_curve.Y() < pb_on_curve.Y()) {
2274                     lowx = pa_on_curve.X();
2275                     lowy = pa_on_curve.Y();
2276                     upx = pb_on_curve.X();
2277                     upy = pb_on_curve.Y();
2278                 } else {
2279                     lowx = pb_on_curve.X();
2280                     lowy = pb_on_curve.Y();
2281                     upx = pa_on_curve.X();
2282                     upy = pa_on_curve.Y();
2283                 }
2284                 left = Math.min(lowx, upx);
2285                 right = Math.max(lowx, upx);
2286 
2287                 x = [0, lowx];
2288                 y = [lowy, lowy];
2289 
2290                 for (i = 0; i < curve.numberPoints; i++) {
2291                     if (lowy <= curve.points[i].usrCoords[2] &&
2292                             left <= curve.points[i].usrCoords[1] &&
2293                             curve.points[i].usrCoords[2] <= upy  &&
2294                             curve.points[i].usrCoords[1] <= right) {
2295                         x.push(curve.points[i].usrCoords[1]);
2296                         y.push(curve.points[i].usrCoords[2]);
2297                     }
2298                 }
2299                 x.push(upx);
2300                 y.push(upy);
2301                 x.push(0);
2302                 y.push(upy);
2303 
2304                 // close the curve
2305                 x.push(0);
2306                 y.push(lowy);
2307             } else {
2308                 if (pa_on_axis.X() < pb_on_axis.X()) {
2309                     left = pa_on_axis.X();
2310                     right = pb_on_axis.X();
2311                 } else {
2312                     left = pb_on_axis.X();
2313                     right = pa_on_axis.X();
2314                 }
2315 
2316                 x = [left, left];
2317                 y = [0, curve.Y(left)];
2318 
2319                 for (i = 0; i < curve.numberPoints; i++) {
2320                     if ((left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right)) {
2321                         x.push(curve.points[i].usrCoords[1]);
2322                         y.push(curve.points[i].usrCoords[2]);
2323                     }
2324                 }
2325                 x.push(right);
2326                 y.push(curve.Y(right));
2327                 x.push(right);
2328                 y.push(0);
2329 
2330                 // close the curve
2331                 x.push(left);
2332                 y.push(0);
2333             }
2334 
2335             this.dataX = x;
2336             this.dataY = y;
2337         };
2338 
2339         pa_on_curve.addChild(p);
2340         pb_on_curve.addChild(p);
2341         pa_on_axis.addChild(p);
2342         pb_on_axis.addChild(p);
2343 
2344         /**
2345          * The point on the axis initially corresponding to the lower value of the interval.
2346          *
2347          * @name baseLeft
2348          * @memberOf Integral
2349          * @type JXG.Point
2350          */
2351         p.baseLeft = pa_on_axis;
2352 
2353         /**
2354          * The point on the axis initially corresponding to the higher value of the interval.
2355          *
2356          * @name baseRight
2357          * @memberOf Integral
2358          * @type JXG.Point
2359          */
2360         p.baseRight = pb_on_axis;
2361 
2362         /**
2363          * The glider on the curve corresponding to the lower value of the interval.
2364          *
2365          * @name curveLeft
2366          * @memberOf Integral
2367          * @type Glider
2368          */
2369         p.curveLeft = pa_on_curve;
2370 
2371         /**
2372          * The glider on the axis corresponding to the higher value of the interval.
2373          *
2374          * @name curveRight
2375          * @memberOf Integral
2376          * @type Glider
2377          */
2378         p.curveRight = pb_on_curve;
2379 
2380         p.methodMap = JXG.deepCopy(p.methodMap, {
2381             curveLeft: 'curveLeft',
2382             baseLeft: 'baseLeft',
2383             curveRight: 'curveRight',
2384             baseRight: 'baseRight',
2385             Value: 'Value'
2386         });
2387 
2388         /**
2389          * documented in GeometryElement
2390          * @ignore
2391          */
2392         p.label = t;
2393 
2394         return p;
2395     };
2396 
2397     /**
2398      * @class Creates a grid to support the user with element placement.
2399      * @pseudo
2400      * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method
2401      * draws such a grid on the given board. This method does not
2402      * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set
2403      * to true.
2404      * @parameter None.
2405      * @constructor
2406      * @name Grid
2407      * @type JXG.Curve
2408      * @augments JXG.Curve
2409      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2410      * @example
2411      * grid = board.create('grid', []);
2412      * </pre><div class="jxgbox" id="JXGa9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div>
2413      * <script type="text/javascript">
2414      * (function () {
2415      *  board = JXG.JSXGraph.initBoard('JXGa9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
2416      *  grid = board.create('grid', []);
2417      * })();
2418      * </script><pre>
2419      */
2420     JXG.createGrid = function (board, parents, attributes) {
2421         var c, attr;
2422 
2423         attr = Type.copyAttributes(attributes, board.options, 'grid');
2424         c = board.create('curve', [[null], [null]], attr);
2425 
2426         c.elType = 'grid';
2427         c.type = Const.OBJECT_TYPE_GRID;
2428 
2429         c.updateDataArray = function () {
2430             var start, end, i, topLeft, bottomRight,
2431                 gridX = Type.evaluate(this.visProp.gridx),
2432                 gridY = Type.evaluate(this.visProp.gridy);
2433 
2434             if (Type.isArray(this.visProp.topleft)) {
2435                 topLeft = new Coords(Type.evaluate(this.visProp.tltype) || Const.COORDS_BY_USER,
2436                                     this.visProp.topleft, board);
2437             } else {
2438                 topLeft = new Coords(Const.COORDS_BY_SCREEN, [0, 0], board);
2439             }
2440 
2441             if (Type.isArray(this.visProp.bottomright)) {
2442                 bottomRight = new Coords(Type.evaluate(this.visProp.brtype) || Const.COORDS_BY_USER,
2443                                     this.visProp.bottomright, board);
2444             } else {
2445                 bottomRight = new Coords(Const.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board);
2446             }
2447 
2448 
2449             //
2450             //      |         |         |
2451             //  ----+---------+---------+-----
2452             //      |        /|         |
2453             //      |    gridY|     <---+------   Grid Cell
2454             //      |        \|         |
2455             //  ----+---------+---------+-----
2456             //      |         |\ gridX /|
2457             //      |         |         |
2458             //
2459             // uc: usercoordinates
2460             //
2461             // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high.
2462             // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it
2463             // is absolutely not user friendly when it comes to use it as an API interface.
2464             // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i
2465             // had to refactor these methods:
2466             //
2467             //  DONE JXG.Board.calculateSnapSizes (init p1, p2)
2468             //  DONE JXG.GeonextReader.readGeonext (init gridX, gridY)
2469             //
2470 
2471             board.options.grid.hasGrid = true;
2472 
2473 			// fix_grid: adding integer function to calculation of start and end values, and adding to calculation of start and end values below
2474 			// To allow this:
2475 			// (axes on the outside, min value of grid = 0.25)
2476             //
2477             //      |    |         |          |
2478             // 1.5 -+----+---------+----------+-----
2479             //      |    |         |          |
2480             //      |    |         |          |
2481             //      |    |         |          |
2482             //   1 -+----+---------+----------+-----
2483             //      |    |         |          |
2484             //      |    |         |          |
2485             //      |    |         |          |
2486             // 0.5 -+----+---------+----------+-----
2487             //      |    |         |          |
2488             //      +----+---------+----------+-----
2489             //           |         |          |
2490             //          0.5        1         1.5
2491             //
2492             // fix_grid: these lines disabled:
2493             // topLeft.setCoordinates(Const.COORDS_BY_USER, [Math.ceil(topLeft.usrCoords[1] / gridX) * gridX, Math.floor(topLeft.usrCoords[2] / gridY) * gridY]);
2494             // bottomRight.setCoordinates(Const.COORDS_BY_USER, [Math.floor(bottomRight.usrCoords[1] / gridX) * gridX, Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY]);
2495 
2496             c.dataX = [];
2497             c.dataY = [];
2498 
2499             // Sometimes the bounding box is used to invert the axis. We have to take this into account here.
2500             // fix_grid: adding integer function to calculation of start and end values
2501             start = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;
2502             end = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY;
2503 
2504             if (topLeft.usrCoords[2] < bottomRight.usrCoords[2]) {
2505                 start = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; // bottomRight.usrCoords[2];
2506                 end = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;
2507             }
2508 
2509             // start with the horizontal grid:
2510             for (i = start; i > end - gridY; i -= gridY) {
2511                 c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN);
2512                 c.dataY.push(i, i, NaN);
2513             }
2514 
2515             // fix_grid: adding integer function to calculation of start and end values
2516             start = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;
2517             end = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;
2518 
2519             if (topLeft.usrCoords[1] > bottomRight.usrCoords[1]) {
2520 				start = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;
2521 				end = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;
2522             }
2523 
2524             // build vertical grid
2525             for (i = start; i < end + gridX; i += gridX) {
2526                 c.dataX.push(i, i, NaN);
2527                 c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN);
2528             }
2529 
2530         };
2531 
2532         // we don't care about highlighting so we turn it off completely to save a lot of
2533         // time on every mouse move
2534         c.hasPoint = function () {
2535             return false;
2536         };
2537 
2538         board.grids.push(c);
2539 
2540         return c;
2541     };
2542 
2543     /**
2544      * @class Creates an area indicating the solution of a linear inequality or an inequality
2545      * of a function graph, i.e. an inequality of type y <= f(x).
2546      * @pseudo
2547      * @description Display the solution set of a linear inequality (less than or equal to).
2548      * To be precise, the solution set of the inequality <i>y <= b/a * x + c/a</i> is shown.
2549      * In case <i>a = 0</i>, that is if the equation of the line is <i>bx + c = 0</i>,
2550      * the area of the inequality <i>bx + c <= 0</i> is shown.
2551      * <p>
2552      * For function graphs the area below the function graph is filled, i.e. the
2553      * area of the inequality y <= f(x).
2554      * With the attribute inverse:true the area of the inequality y >= f(x) is filled.
2555      *
2556      * @param {JXG.Line} l The area drawn will be the area below this line. With the attribute
2557      * inverse:true, the inequality 'greater than or equal to' is shown.
2558      * @constructor
2559      * @name Inequality
2560      * @type JXG.Curve
2561      * @augments JXG.Curve
2562      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2563      * @example
2564      * var p = board.create('point', [1, 3]),
2565      *     q = board.create('point', [-2, -4]),
2566      *     l = board.create('line', [p, q]),
2567      *     ineq = board.create('inequality', [l]);
2568      * ineq = board.create('inequality', [l]);
2569      * </pre><div class="jxgbox" id="JXG2b703006-fd98-11e1-b79e-ef9e591c002e" style="width: 400px; height: 400px;"></div>
2570      * <script type="text/javascript">
2571      * (function () {
2572      *  var board = JXG.JSXGraph.initBoard('JXG2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),
2573      *      p = board.create('point', [1, 3]),
2574      *      q = board.create('point', [-2, -4]),
2575      *      l = board.create('line', [p, q]),
2576      *      ineq = board.create('inequality', [l]);
2577      * })();
2578      * </script><pre>
2579      *
2580      * @example
2581      * // Plot the inequality
2582      * //     y >= 2/3 x + 1
2583      * // or
2584      * //     0 >= -3y + 2x +1
2585      * var l = board.create('line', [1, 2, -3]),
2586      *     ineq = board.create('inequality', [l], {inverse:true});
2587      * </pre><div class="jxgbox" id="JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd" style="width: 400px; height: 400px;"></div>
2588      * <script type="text/javascript">
2589      * (function () {
2590      *  var board = JXG.JSXGraph.initBoard('JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),
2591      *      l = board.create('line', [1, 2, -3]),
2592      *      ineq = board.create('inequality', [l], {inverse:true});
2593      * })();
2594      * </script><pre>
2595      *
2596      * @example
2597      * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]);
2598      *
2599      * var ineq_lower = board.create('inequality', [f]);
2600      * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'});
2601      *
2602      *
2603      * </pre><div id="JXGdb68c574-414c-11e8-839a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div>
2604      * <script type="text/javascript">
2605      *     (function() {
2606      *         var board = JXG.JSXGraph.initBoard('JXGdb68c574-414c-11e8-839a-901b0e1b8723',
2607      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
2608      *     var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]);
2609      *
2610      *     var ineq_lower = board.create('inequality', [f]);
2611      *     var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'});
2612      *
2613      *
2614      *     })();
2615      *
2616      * </script><pre>
2617      *
2618      */
2619     JXG.createInequality = function (board, parents, attributes) {
2620         var f, a, attr;
2621 
2622         attr = Type.copyAttributes(attributes, board.options, 'inequality');
2623         if (parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
2624             a = board.create('curve', [[], []], attr);
2625             a.hasPoint = function () {
2626                 return false;
2627             };
2628             a.updateDataArray = function () {
2629                 var i1, i2,
2630                     // This will be the height of the area. We mustn't rely upon the board height because if we pan the view
2631                     // such that the line is not visible anymore, the borders of the area will get visible in some cases.
2632                     h,
2633                     bb = board.getBoundingBox(),
2634                     factor = attr.inverse ? -1 : 1,
2635                     expansion = 1.5,
2636                     w = expansion * Math.max(bb[2] - bb[0], bb[1] - bb[3]),
2637                     // Fake a point (for Math.Geometry.perpendicular)
2638                     // contains centroid of the board
2639                     dp = {
2640                         coords: {
2641                             usrCoords: [1, (bb[0] + bb[2]) / 2, attr.inverse ? bb[1] : bb[3]]
2642                         }
2643                     },
2644 
2645                     slope1 = parents[0].stdform.slice(1),
2646                     slope2 = slope1;
2647 
2648                 // This is wrong. Example:
2649                 // var line = board.create('line', [0, -1, -1]);
2650                 // var ineq = board.create('inequality', [line]);
2651                 //
2652                 // if (slope1[1] > 0) {
2653                 //     slope1 = Statistics.multiply(slope1, -1);
2654                 //     slope2 = slope1;
2655                 // }
2656 
2657                 // Calculate the area height as
2658                 //  expansion times the distance of the line to the
2659                 // point in the middle of the top/bottom border.
2660                 h = expansion * Math.max(Geometry.perpendicular(parents[0], dp, board)[0].distance(Const.COORDS_BY_USER, dp.coords), w);
2661                 h *= factor;
2662 
2663                 // reuse dp
2664                 dp = {
2665                     coords: {
2666                         usrCoords: [1, (bb[0] + bb[2]) / 2, (bb[1] + bb[3]) / 2]
2667                     }
2668                 };
2669 
2670                 // If dp is on the line, Geometry.perpendicular will return a point not on the line.
2671                 // Since this somewhat odd behavior of Geometry.perpendicular is needed in GEONExT,
2672                 // it is circumvented here.
2673                 if (Math.abs(Mat.innerProduct(dp.coords.usrCoords, parents[0].stdform, 3)) >= Mat.eps) {
2674                     dp = Geometry.perpendicular(parents[0], dp, board)[0].usrCoords;
2675                 } else {
2676                     dp = dp.coords.usrCoords;
2677                 }
2678                 i1 = [1, dp[1] + slope1[1] * w, dp[2] - slope1[0] * w];
2679                 i2 = [1, dp[1] - slope2[1] * w, dp[2] + slope2[0] * w];
2680 
2681                 // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1)
2682                 // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and
2683                 // end up in i2.
2684                 this.dataX = [i1[1], i1[1] + slope1[0] * h, i2[1] + slope2[0] * h, i2[1], i1[1]];
2685                 this.dataY = [i1[2], i1[2] + slope1[1] * h, i2[2] + slope2[1] * h, i2[2], i1[2]];
2686             };
2687         } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE &&
2688             parents[0].visProp.curvetype === 'functiongraph') {
2689 
2690             a = board.create('curve', [[], []], attr);
2691             a.updateDataArray = function() {
2692                 var bbox = this.board.getBoundingBox(),
2693                     points = [],
2694                     infty, first, last,
2695                     len, i,
2696                     mi = parents[0].minX(),
2697                     ma = parents[0].maxX(),
2698                     curve_mi, curve_ma,
2699                     firstx,
2700                     lastx,
2701                     enlarge = (bbox[1] - bbox[3]) * 0.3, // enlarge the bbox vertically by this amount
2702                     inverse = Type.evaluate(this.visProp.inverse);
2703 
2704                 // inverse == true <=> Fill area with y >= f(x)
2705                 infty = (inverse) ? 1 : 3; // we will use either bbox[1] or bbox[3] below
2706 
2707                 this.dataX = [];
2708                 this.dataY = [];
2709                 len = parents[0].points.length;
2710                 if (len == 0) {
2711                     return;
2712                 }
2713 
2714                 bbox[1] += enlarge;
2715                 bbox[3] -= enlarge;
2716 
2717                 last = -1;
2718                 while (last < len - 1) {
2719 
2720                     // Find the first point with real coordinates on this curve segment
2721                     for (i = last + 1, first = len; i < len; i++) {
2722                         if (parents[0].points[i].isReal()) {
2723                             first = i;
2724                             break;
2725                         }
2726                     }
2727                     // No real points found -> exit
2728                     if (first >= len) {
2729                         break;
2730                     }
2731 
2732                     // Find the last point with real coordinates on this curve segment
2733                     for (i = first, last = len - 1; i < len - 1; i++) {
2734                         if (!parents[0].points[i + 1].isReal()) {
2735                             last = i;
2736                             break;
2737                         }
2738                     }
2739 
2740                     firstx = parents[0].points[first].usrCoords[1];
2741                     lastx = parents[0].points[last].usrCoords[1];
2742 
2743                     // Restrict the plot interval if the function ends inside of the board
2744                     curve_mi = (bbox[0] < mi) ? mi : bbox[0];
2745                     curve_ma = (bbox[2] > ma) ? ma : bbox[2];
2746 
2747                     // Found NaNs
2748                     curve_mi = (first === 0)      ? curve_mi : Math.max(curve_mi, firstx);
2749                     curve_ma = (last === len - 1) ? curve_ma : Math.min(curve_ma, lastx);
2750 
2751                     // First and last relevant x-coordinate of the curve
2752                     curve_mi = (first === 0)     ? mi: firstx;
2753                     curve_ma = (last === len - 1)? ma: lastx;
2754 
2755 
2756                     // Copy the curve points
2757                     points = [];
2758 
2759                     points.push([1, curve_mi, bbox[infty]]);
2760                     points.push([1, curve_mi, parents[0].points[first].usrCoords[2]]);
2761                     for (i = first; i <= last; i++) {
2762                         points.push(parents[0].points[i].usrCoords);
2763                     }
2764                     points.push([1, curve_ma, parents[0].points[last].usrCoords[2]]);
2765                     points.push([1, curve_ma, bbox[infty]]);
2766                     points.push(points[0]);
2767 
2768                     for (i = 0; i < points.length; i++) {
2769                         this.dataX.push(points[i][1]);
2770                         this.dataY.push(points[i][2]);
2771                     }
2772 
2773 
2774                     if (last < len - 1) {
2775                         this.dataX.push(NaN);
2776                         this.dataY.push(NaN);
2777                     }
2778               }
2779 
2780             };
2781 
2782             // Previous code:
2783             a.hasPoint = function () {
2784                 return false;
2785             };
2786         } else {
2787             // Not yet practical?
2788             f = Type.createFunction(parents[0]);
2789             if (!Type.exists(f)) {
2790                 throw new Error("JSXGraph: Can't create area with the given parents." +
2791                     "\nPossible parent types: [line], [function]");
2792             }
2793         }
2794 
2795         a.addParents(parents[0]);
2796         return a;
2797     };
2798 
2799 
2800     JXG.registerElement('arrowparallel', JXG.createArrowParallel);
2801     JXG.registerElement('bisector', JXG.createBisector);
2802     JXG.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);
2803     JXG.registerElement('msector', JXG.createMsector);
2804     JXG.registerElement('circumcircle', JXG.createCircumcircle);
2805     JXG.registerElement('circumcirclemidpoint', JXG.createCircumcenter);
2806     JXG.registerElement('circumcenter', JXG.createCircumcenter);
2807     JXG.registerElement('incenter', JXG.createIncenter);
2808     JXG.registerElement('incircle', JXG.createIncircle);
2809     JXG.registerElement('integral', JXG.createIntegral);
2810     JXG.registerElement('midpoint', JXG.createMidpoint);
2811     JXG.registerElement('mirrorelement', JXG.createMirrorElement);
2812     JXG.registerElement('mirrorpoint', JXG.createMirrorPoint);
2813     JXG.registerElement('normal', JXG.createNormal);
2814     JXG.registerElement('orthogonalprojection', JXG.createOrthogonalProjection);
2815     JXG.registerElement('parallel', JXG.createParallel);
2816     JXG.registerElement('parallelpoint', JXG.createParallelPoint);
2817     JXG.registerElement('perpendicular', JXG.createPerpendicular);
2818     JXG.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);
2819     JXG.registerElement('perpendicularsegment', JXG.createPerpendicularSegment);
2820     JXG.registerElement('reflection', JXG.createReflection);
2821     JXG.registerElement('grid', JXG.createGrid);
2822     JXG.registerElement('inequality', JXG.createInequality);
2823 
2824     return {
2825         createArrowParallel: JXG.createArrowParallel,
2826         createBisector: JXG.createBisector,
2827         createAngularBisectorOfTwoLines: JXG.createAngularBisectorsOfTwoLines,
2828         createCircumcircle: JXG.createCircumcircle,
2829         createCircumcenter: JXG.createCircumcenter,
2830         createIncenter: JXG.createIncenter,
2831         createIncircle: JXG.createIncircle,
2832         createIntegral: JXG.createIntegral,
2833         createMidpoint: JXG.createMidpoint,
2834         createMirrorElement: JXG.createMirrorElement,
2835         createMirrorPoint: JXG.createMirrorPoint,
2836         createNormal: JXG.createNormal,
2837         createOrthogonalProjection: JXG.createOrthogonalProjection,
2838         createParallel: JXG.createParallel,
2839         createParallelPoint: JXG.createParallelPoint,
2840         createPerpendicular: JXG.createPerpendicular,
2841         createPerpendicularPoint: JXG.createPerpendicularPoint,
2842         createPerpendicularSegmen: JXG.createPerpendicularSegment,
2843         createReflection: JXG.createReflection,
2844         createGrid: JXG.createGrid,
2845         createInequality: JXG.createInequality
2846     };
2847 });
2848