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