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