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