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