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             p = board.create('point', [
1132                 function () {
1133                     return Geometry.angleBisector(parents[0], parents[1], parents[2], board);
1134                 }
1135             ], attr);
1136             p.dump = false;
1137 
1138             for (i = 0; i < 3; i++) {
1139                 // required for algorithm requiring dependencies between elements
1140                 parents[i].addChild(p);
1141             }
1142 
1143             if (!Type.exists(attributes.layer)) {
1144                 attributes.layer = board.options.layer.line;
1145             }
1146 
1147             attr = Type.copyAttributes(attributes, board.options, 'bisector');
1148             l = Line.createLine(board, [parents[1], p], attr);
1149 
1150             /**
1151              * Helper point
1152              * @memberOf Bisector.prototype
1153              * @type Point
1154              * @name point
1155              */
1156             l.point = p;
1157 
1158             l.elType = 'bisector';
1159             l.parents = [parents[0].id, parents[1].id, parents[2].id];
1160             l.subs = {
1161                 point: p
1162             };
1163 
1164             return l;
1165         }
1166 
1167         throw new Error("JSXGraph: Can't create angle bisector with parent types '" +
1168             (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1169             "\nPossible parent types: [point,point,point]");
1170     };
1171 
1172     /**
1173      * @class Bisector lines are similar to {@link Bisector} but takes two lines as parent elements. The resulting element is
1174      * a composition of two lines.
1175      * @pseudo
1176      * @constructor
1177      * @name Bisectorlines
1178      * @type JXG.Composition
1179      * @augments JXG.Composition
1180      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1181      * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each
1182      * be divided into two equal angles.
1183      * @example
1184      * var p1 = board.create('point', [6.0, 4.0]);
1185      * var p2 = board.create('point', [3.0, 2.0]);
1186      * var p3 = board.create('point', [1.0, 7.0]);
1187      * var p4 = board.create('point', [3.0, 0.0]);
1188      * var l1 = board.create('line', [p1, p2]);
1189      * var l2 = board.create('line', [p3, p4]);
1190      *
1191      * var bi1 = board.create('bisectorlines', [l1, l2]);
1192      * </pre><div id="3121ff67-44f0-4dda-bb10-9cda0b80bf18" style="width: 400px; height: 400px;"></div>
1193      * <script type="text/javascript">
1194      * (function () {
1195      *   var board = JXG.JSXGraph.initBoard('3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1196      *   var p1 = board.create('point', [6.0, 4.0]);
1197      *   var p2 = board.create('point', [3.0, 2.0]);
1198      *   var p3 = board.create('point', [1.0, 7.0]);
1199      *   var p4 = board.create('point', [3.0, 0.0]);
1200      *   var l1 = board.create('line', [p1, p2]);
1201      *   var l2 = board.create('line', [p3, p4]);
1202      *   var bi1 = board.create('bisectorlines', [l1, l2]);
1203      * })();
1204      * </script><pre>
1205      */
1206     JXG.createAngularBisectorsOfTwoLines = function (board, parents, attributes) {
1207         // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation:
1208         // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2)
1209 
1210         var g1, g2, attr, ret,
1211             l1 = board.select(parents[0]),
1212             l2 = board.select(parents[1]);
1213 
1214         if (l1.elementClass !== Const.OBJECT_CLASS_LINE || l2.elementClass !== Const.OBJECT_CLASS_LINE) {
1215             throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" +
1216                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1217                 "\nPossible parent types: [line,line]");
1218         }
1219 
1220         if (!Type.exists(attributes.layer)) {
1221             attributes.layer = board.options.layer.line;
1222         }
1223 
1224         attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line1');
1225         g1 = board.create('line', [
1226             function () {
1227                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1228                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1229 
1230                 return l1.stdform[0] / d1 - l2.stdform[0] / d2;
1231             },
1232             function () {
1233                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1234                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1235 
1236                 return l1.stdform[1] / d1 - l2.stdform[1] / d2;
1237             },
1238             function () {
1239                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1240                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1241 
1242                 return l1.stdform[2] / d1 - l2.stdform[2] / d2;
1243             }
1244         ], attr);
1245 
1246         if (!Type.exists(attributes.layer)) {
1247             attributes.layer = board.options.layer.line;
1248         }
1249         attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line2');
1250         g2 = board.create('line', [
1251             function () {
1252                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1253                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1254 
1255                 return l1.stdform[0] / d1 + l2.stdform[0] / d2;
1256             },
1257             function () {
1258                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1259                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1260 
1261                 return l1.stdform[1] / d1 + l2.stdform[1] / d2;
1262             },
1263             function () {
1264                 var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),
1265                     d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);
1266 
1267                 return l1.stdform[2] / d1 + l2.stdform[2] / d2;
1268             }
1269         ], attr);
1270 
1271         // documentation
1272         /**
1273          * First line.
1274          * @memberOf Bisectorlines.prototype
1275          * @name line1
1276          * @type Line
1277          */
1278 
1279         /**
1280          * Second line.
1281          * @memberOf Bisectorlines.prototype
1282          * @name line2
1283          * @type Line
1284          */
1285 
1286         ret = new Composition({line1: g1, line2: g2});
1287 
1288         g1.dump = false;
1289         g2.dump = false;
1290 
1291         ret.elType = 'bisectorlines';
1292         ret.parents = [l1.id, l2.id];
1293         ret.subs = {
1294             line1: g1,
1295             line2: g2
1296         };
1297 
1298         return ret;
1299     };
1300 
1301     /**
1302      * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter
1303      * is constructed by providing three points.
1304      * @pseudo
1305      * @description A circumcenter is given by three points which are all lying on the circle with the
1306      * constructed circumcenter as the midpoint.
1307      * @constructor
1308      * @name Circumcenter
1309      * @type JXG.Point
1310      * @augments JXG.Point
1311      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1312      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined
1313      * by p1, p2, and p3.
1314      * @example
1315      * var p1 = board.create('point', [0.0, 2.0]);
1316      * var p2 = board.create('point', [2.0, 1.0]);
1317      * var p3 = board.create('point', [3.0, 3.0]);
1318      *
1319      * var cc1 = board.create('circumcenter', [p1, p2, p3]);
1320      * </pre><div id="e8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div>
1321      * <script type="text/javascript">
1322      *   var ccmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1323      *   var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]);
1324      *   var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]);
1325      *   var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]);
1326      *   var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]);
1327      * </script><pre>
1328      */
1329     JXG.createCircumcenter = function (board, parents, attributes) {
1330         var p, i, a, b, c;
1331 
1332         if (parents[0].elementClass === Const.OBJECT_CLASS_POINT && parents[1].elementClass === Const.OBJECT_CLASS_POINT &&
1333                 parents[2].elementClass === Const.OBJECT_CLASS_POINT) {
1334             a = parents[0];
1335             b = parents[1];
1336             c = parents[2];
1337 
1338             p = Point.createPoint(board, [
1339                 function () {
1340                     return Geometry.circumcenterMidpoint(a, b, c, board);
1341                 }
1342             ], attributes);
1343 
1344             for (i = 0; i < 3; i++) {
1345                 parents[i].addChild(p);
1346             }
1347 
1348             p.elType = 'circumcenter';
1349             p.parents = [a.id, b.id, c.id];
1350 
1351             p.generatePolynomial = function () {
1352                 /*
1353                  *  CircumcircleMidpoint takes three points A, B and C  and creates point M, which is the circumcenter of A, B, and C.
1354                  *
1355                  *
1356                  * So we have two conditions:
1357                  *
1358                  *   (a)   CT  ==  AT           (distance condition I)
1359                  *   (b)   BT  ==  AT           (distance condition II)
1360                  *
1361                  */
1362                 var a1 = a.symbolic.x,
1363                     a2 = a.symbolic.y,
1364                     b1 = b.symbolic.x,
1365                     b2 = b.symbolic.y,
1366                     c1 = c.symbolic.x,
1367                     c2 = c.symbolic.y,
1368                     t1 = p.symbolic.x,
1369                     t2 = p.symbolic.y,
1370 
1371                     poly1 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', b1, '))^2-((', t2, ')-(', b2, '))^2'].join(''),
1372                     poly2 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', c1, '))^2-((', t2, ')-(', c2, '))^2'].join('');
1373 
1374                 return [poly1, poly2];
1375             };
1376 
1377             return p;
1378         }
1379 
1380         throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" +
1381             (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1382             "\nPossible parent types: [point,point,point]");
1383     };
1384 
1385     /**
1386      * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html}
1387      * @pseudo
1388      * @constructor
1389      * @name Incenter
1390      * @type JXG.Point
1391      * @augments JXG.Point
1392      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1393      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described
1394      * by p1, p2, and p3.
1395      * @example
1396      * var p1 = board.create('point', [0.0, 2.0]);
1397      * var p2 = board.create('point', [2.0, 1.0]);
1398      * var p3 = board.create('point', [3.0, 3.0]);
1399      *
1400      * var ic1 = board.create('incenter', [p1, p2, p3]);
1401      * </pre><div id="e8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div>
1402      * <script type="text/javascript">
1403      *   var icmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1404      *   var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]);
1405      *   var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]);
1406      *   var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]);
1407      *   var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]);
1408      * </script><pre>
1409      */
1410     JXG.createIncenter = function (board, parents, attributes) {
1411         var p, A, B, C;
1412 
1413         if (parents.length >= 3 && Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {
1414             A = parents[0];
1415             B = parents[1];
1416             C = parents[2];
1417 
1418             p = board.create('point', [function () {
1419                 var a, b, c;
1420 
1421                 a = Math.sqrt((B.X() - C.X()) * (B.X() - C.X()) + (B.Y() - C.Y()) * (B.Y() - C.Y()));
1422                 b = Math.sqrt((A.X() - C.X()) * (A.X() - C.X()) + (A.Y() - C.Y()) * (A.Y() - C.Y()));
1423                 c = Math.sqrt((B.X() - A.X()) * (B.X() - A.X()) + (B.Y() - A.Y()) * (B.Y() - A.Y()));
1424 
1425                 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);
1426             }], attributes);
1427 
1428             p.elType = 'incenter';
1429             p.parents = [parents[0].id, parents[1].id, parents[2].id];
1430 
1431         } else {
1432             throw new Error("JSXGraph: Can't create incenter with parent types '" +
1433                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1434                 "\nPossible parent types: [point,point,point]");
1435         }
1436 
1437         return p;
1438     };
1439 
1440     /**
1441      * @class A circumcircle is given by three points which are all lying on the circle.
1442      * @pseudo
1443      * @constructor
1444      * @name Circumcircle
1445      * @type JXG.Circle
1446      * @augments JXG.Circle
1447      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1448      * @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>.
1449      * @example
1450      * var p1 = board.create('point', [0.0, 2.0]);
1451      * var p2 = board.create('point', [2.0, 1.0]);
1452      * var p3 = board.create('point', [3.0, 3.0]);
1453      *
1454      * var cc1 = board.create('circumcircle', [p1, p2, p3]);
1455      * </pre><div id="e65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div>
1456      * <script type="text/javascript">
1457      *   var ccex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1458      *   var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]);
1459      *   var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]);
1460      *   var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]);
1461      *   var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]);
1462      * </script><pre>
1463      */
1464     JXG.createCircumcircle = function (board, parents, attributes) {
1465         var p, c, attr;
1466 
1467         try {
1468             attr = Type.copyAttributes(attributes, board.options, 'circumcircle', 'center');
1469             p = JXG.createCircumcenter(board, parents, attr);
1470 
1471             p.dump = false;
1472 
1473             if (!Type.exists(attributes.layer)) {
1474                 attributes.layer = board.options.layer.circle;
1475             }
1476             attr = Type.copyAttributes(attributes, board.options, 'circumcircle');
1477             c = Circle.createCircle(board, [p, parents[0]], attr);
1478 
1479             c.elType = 'circumcircle';
1480             c.parents = [parents[0].id, parents[1].id, parents[2].id];
1481             c.subs = {
1482                 center: p
1483             };
1484         } catch (e) {
1485             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1486                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1487                 "\nPossible parent types: [point,point,point]");
1488         }
1489 
1490         // p is already stored as midpoint in c so there's no need to store it explicitly.
1491 
1492         return c;
1493     };
1494 
1495     /**
1496      * @class An incircle is given by three points.
1497      * @pseudo
1498      * @constructor
1499      * @name Incircle
1500      * @type JXG.Circle
1501      * @augments JXG.Circle
1502      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1503      * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of
1504      * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.
1505      * @example
1506      * var p1 = board.create('point', [0.0, 2.0]);
1507      * var p2 = board.create('point', [2.0, 1.0]);
1508      * var p3 = board.create('point', [3.0, 3.0]);
1509      *
1510      * var ic1 = board.create('incircle', [p1, p2, p3]);
1511      * </pre><div id="e65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div>
1512      * <script type="text/javascript">
1513      *   var icex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1514      *   var icex1_p1 = icex1_board.create('point', [0.0, 2.0]);
1515      *   var icex1_p2 = icex1_board.create('point', [6.0, 1.0]);
1516      *   var icex1_p3 = icex1_board.create('point', [3.0, 7.0]);
1517      *   var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]);
1518      * </script><pre>
1519      */
1520     JXG.createIncircle = function (board, parents, attributes) {
1521         var p, c, attr;
1522 
1523         try {
1524             attr = Type.copyAttributes(attributes, board.options, 'incircle', 'center');
1525             p = JXG.createIncenter(board, parents, attr);
1526 
1527             p.dump = false;
1528 
1529             if (!Type.exists(attributes.layer)) {
1530                 attributes.layer = board.options.layer.circle;
1531             }
1532             attr = Type.copyAttributes(attributes, board.options, 'incircle');
1533             c = Circle.createCircle(board, [p, function () {
1534                 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())),
1535                     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())),
1536                     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())),
1537                     s = (a + b + c) / 2;
1538 
1539                 return Math.sqrt(((s - a) * (s - b) * (s - c)) / s);
1540             }], attr);
1541 
1542             c.elType = 'incircle';
1543             c.parents = [parents[0].id, parents[1].id, parents[2].id];
1544 
1545             /**
1546              * The center of the incircle
1547              * @memberOf Incircle.prototype
1548              * @type Incenter
1549              * @name center
1550              */
1551             c.center = p;
1552 
1553             c.subs = {
1554                 center: p
1555             };
1556         } catch (e) {
1557             throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1558                 (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1559                 "\nPossible parent types: [point,point,point]");
1560         }
1561 
1562         // p is already stored as midpoint in c so there's no need to store it explicitly.
1563 
1564         return c;
1565     };
1566 
1567     /**
1568      * @class This element is used to construct a reflected point.
1569      * @pseudo
1570      * @description A reflected point is given by a point and a line. It is determined by the reflection of the given point
1571      * against the given line.
1572      * @constructor
1573      * @name Reflection
1574      * @type JXG.Point
1575      * @augments JXG.Point
1576      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1577      * @param {JXG.Point_JXG.Line} p,l The reflection point is the reflection of p against l.
1578      * @example
1579      * var p1 = board.create('point', [0.0, 4.0]);
1580      * var p2 = board.create('point', [6.0, 1.0]);
1581      * var l1 = board.create('line', [p1, p2]);
1582      * var p3 = board.create('point', [3.0, 3.0]);
1583      *
1584      * var rp1 = board.create('reflection', [p3, l1]);
1585      * </pre><div id="087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div>
1586      * <script type="text/javascript">
1587      *   var rpex1_board = JXG.JSXGraph.initBoard('087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1588      *   var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]);
1589      *   var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]);
1590      *   var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]);
1591      *   var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]);
1592      *   var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]);
1593      * </script><pre>
1594      */
1595     JXG.createReflection = function (board, parents, attributes) {
1596         var l, p, r, t;
1597 
1598         if (parents[0].elementClass === Const.OBJECT_CLASS_POINT && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {
1599             p = parents[0];
1600             l = parents[1];
1601         } else if (parents[1].elementClass === Const.OBJECT_CLASS_POINT && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
1602             p = parents[1];
1603             l = parents[0];
1604         } else {
1605             throw new Error("JSXGraph: Can't create reflection point with parent types '" +
1606                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1607                 "\nPossible parent types: [line,point]");
1608         }
1609 
1610         t = Transform.createTransform(board, [l], {type: 'reflect'});
1611         r = Point.createPoint(board, [p, t], attributes);
1612         p.addChild(r);
1613         l.addChild(r);
1614 
1615         r.elType = 'reflection';
1616         r.parents = [parents[0].id, parents[1].id];
1617 
1618         r.prepareUpdate().update();
1619 
1620         r.generatePolynomial = function () {
1621             /*
1622              *  Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.
1623              *  L is defined by two points A and B.
1624              *
1625              * So we have two conditions:
1626              *
1627              *   (a)   RP  _|_  AB            (orthogonality condition)
1628              *   (b)   AR  ==   AP            (distance condition)
1629              *
1630              */
1631             var a1 = l.point1.symbolic.x,
1632                 a2 = l.point1.symbolic.y,
1633                 b1 = l.point2.symbolic.x,
1634                 b2 = l.point2.symbolic.y,
1635                 p1 = p.symbolic.x,
1636                 p2 = p.symbolic.y,
1637                 r1 = r.symbolic.x,
1638                 r2 = r.symbolic.y,
1639 
1640                 poly1 = ['((', r2, ')-(', p2, '))*((', a2, ')-(', b2, '))+((', a1, ')-(', b1, '))*((', r1, ')-(', p1, '))'].join(''),
1641                 poly2 = ['((', r1, ')-(', a1, '))^2+((', r2, ')-(', a2, '))^2-((', p1, ')-(', a1, '))^2-((', p2, ')-(', a2, '))^2'].join('');
1642 
1643             return [poly1, poly2];
1644         };
1645 
1646         return r;
1647     };
1648 
1649     /**
1650      * @class A mirror point will be constructed.
1651      * @pseudo
1652      * @description A mirror point is determined by the reflection of a given point against another given point.
1653      * @constructor
1654      * @name Mirrorpoint
1655      * @type JXG.Point
1656      * @augments JXG.Point
1657      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1658      * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.
1659      * @example
1660      * var p1 = board.create('point', [3.0, 3.0]);
1661      * var p2 = board.create('point', [6.0, 1.0]);
1662      *
1663      * var mp1 = board.create('mirrorpoint', [p1, p2]);
1664      * </pre><div id="7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div>
1665      * <script type="text/javascript">
1666      *   var mpex1_board = JXG.JSXGraph.initBoard('7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1667      *   var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);
1668      *   var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);
1669      *   var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);
1670      * </script><pre>
1671      */
1672     JXG.createMirrorPoint = function (board, parents, attributes) {
1673         var p, i;
1674 
1675         if (Type.isPoint(parents[0]) && Type.isPoint(parents[1])) {
1676             p = Point.createPoint(board, [
1677                 function () {
1678                     return Geometry.rotation(parents[0], parents[1], Math.PI, board);
1679                 }
1680             ], attributes);
1681 
1682             for (i = 0; i < 2; i++) {
1683                 parents[i].addChild(p);
1684             }
1685 
1686             p.elType = 'mirrorpoint';
1687             p.parents = [parents[0].id, parents[1].id];
1688         } else {
1689             throw new Error("JSXGraph: Can't create mirror point with parent types '" +
1690                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1691                 "\nPossible parent types: [point,point]");
1692         }
1693 
1694         p.prepareUpdate().update();
1695 
1696         return p;
1697     };
1698 
1699     /**
1700      * @class This element is used to visualize the integral of a given curve over a given interval.
1701      * @pseudo
1702      * @description The Integral element is used to visualize the area under a given curve over a given interval
1703      * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,
1704      * the gliders are used to change the interval dynamically.
1705      * @constructor
1706      * @name Integral
1707      * @type JXG.Curve
1708      * @augments JXG.Curve
1709      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
1710      * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis
1711      * within the interval <tt>i</tt>.
1712      * @example
1713      * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);
1714      * var i1 = board.create('integral', [[-1.0, 4.0], c1]);
1715      * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
1716      * <script type="text/javascript">
1717      *   var intex1_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});
1718      *   var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]);
1719      *   var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);
1720      * </script><pre>
1721      */
1722     JXG.createIntegral = function (board, parents, attributes) {
1723         var interval, curve, attr,
1724             start, end, startx, starty, endx, endy,
1725             pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,
1726             t = null, p;
1727 
1728         if (Type.isArray(parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_CURVE) {
1729             interval = parents[0];
1730             curve = parents[1];
1731         } else if (Type.isArray(parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_CURVE) {
1732             interval = parents[1];
1733             curve = parents[0];
1734         } else {
1735             throw new Error("JSXGraph: Can't create integral with parent types '" +
1736                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1737                 "\nPossible parent types: [[number|function,number|function],curve]");
1738         }
1739 
1740         attr = Type.copyAttributes(attributes, board.options, 'integral');
1741         attr.withLabel = false;  // There is a custom 'label' below.
1742         p = board.create('curve', [[0], [0]], attr);
1743 
1744         // Correct the interval if necessary - NOT ANYMORE, GGB's fault
1745         start = interval[0];
1746         end = interval[1];
1747 
1748         if (Type.isFunction(start)) {
1749             startx = start;
1750             starty = function () { return curve.Y(startx()); };
1751             start = startx();
1752         } else {
1753             startx = start;
1754             starty = curve.Y(start);
1755         }
1756 
1757         if (Type.isFunction(end)) {
1758             endx = end;
1759             endy = function () { return curve.Y(endx()); };
1760             end = endx();
1761         } else {
1762             endx = end;
1763             endy = curve.Y(end);
1764         }
1765 
1766         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveLeft');
1767         pa_on_curve = board.create('glider', [startx, starty, curve], attr);
1768         if (Type.isFunction(startx)) {
1769             pa_on_curve.hideElement();
1770         }
1771 
1772         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseLeft');
1773         pa_on_axis = board.create('point', [
1774             function () {
1775                 if (p.visProp.axis === 'y') {
1776                     return 0;
1777                 }
1778 
1779                 return pa_on_curve.X();
1780             },
1781             function () {
1782                 if (p.visProp.axis === 'y') {
1783                     return pa_on_curve.Y();
1784                 }
1785 
1786                 return 0;
1787             }
1788         ], attr);
1789 
1790         attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveRight');
1791         pb_on_curve = board.create('glider', [endx, endy, curve], attr);
1792         if (Type.isFunction(endx)) {
1793             pb_on_curve.hideElement();
1794         }
1795 
1796         attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseRight');
1797         pb_on_axis = board.create('point', [
1798             function () {
1799                 if (p.visProp.axis === 'y') {
1800                     return 0;
1801                 }
1802 
1803                 return pb_on_curve.X();
1804             },
1805             function () {
1806                 if (p.visProp.axis === 'y') {
1807                     return pb_on_curve.Y();
1808                 }
1809 
1810                 return 0;
1811             }
1812         ], attr);
1813 
1814         attr = Type.copyAttributes(attributes, board.options, 'integral');
1815         if (attr.withlabel !== false && attr.axis !== 'y') {
1816             attr = Type.copyAttributes(attributes, board.options, 'integral', 'label');
1817             attr = Type.copyAttributes(attr, board.options, 'label');
1818 
1819             t = board.create('text', [
1820                 function () {
1821                     var off = new Coords(Const.COORDS_BY_SCREEN, [
1822                         this.visProp.offset[0] + this.board.origin.scrCoords[1],
1823                         0
1824                     ], this.board, false);
1825 
1826                     return pb_on_curve.X() + off.usrCoords[1];
1827                 },
1828                 function () {
1829                     var off = new Coords(Const.COORDS_BY_SCREEN, [
1830                         0,
1831                         this.visProp.offset[1] + this.board.origin.scrCoords[2]
1832                     ], this.board, false);
1833 
1834                     return pb_on_curve.Y() + off.usrCoords[2];
1835                 },
1836                 function () {
1837                     var Int = Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
1838                     return '∫ = ' + Int.toFixed(4);
1839                 }
1840             ], attr);
1841 
1842             t.dump = false;
1843 
1844             pa_on_curve.addChild(t);
1845             pb_on_curve.addChild(t);
1846         }
1847 
1848         // dump stuff
1849         pa_on_curve.dump = false;
1850         pa_on_axis.dump = false;
1851 
1852         pb_on_curve.dump = false;
1853         pb_on_axis.dump = false;
1854 
1855         p.elType = 'integral';
1856         p.parents = [curve.id, interval];
1857         p.subs = {
1858             curveLeft: pa_on_curve,
1859             baseLeft: pa_on_axis,
1860             curveRight: pb_on_curve,
1861             baseRight: pb_on_axis
1862         };
1863 
1864         if (attr.withLabel) {
1865             p.subs.label = t;
1866         }
1867 
1868         /** @ignore */
1869         p.Value = function () {
1870             return Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);
1871         };
1872 
1873         /**
1874          * documented in JXG.Curve
1875          * @ignore
1876          */
1877         p.updateDataArray = function () {
1878             var x, y,
1879                 i, left, right,
1880                 lowx, upx,
1881                 lowy, upy;
1882 
1883             if (this.visProp.axis === 'y') {
1884                 if (pa_on_curve.Y() < pb_on_curve.Y()) {
1885                     lowx = pa_on_curve.X();
1886                     lowy = pa_on_curve.Y();
1887                     upx = pb_on_curve.X();
1888                     upy = pb_on_curve.Y();
1889                 } else {
1890                     lowx = pb_on_curve.X();
1891                     lowy = pb_on_curve.Y();
1892                     upx = pa_on_curve.X();
1893                     upy = pa_on_curve.Y();
1894                 }
1895                 left = Math.min(lowx, upx);
1896                 right = Math.max(lowx, upx);
1897 
1898                 x = [0, lowx];
1899                 y = [lowy, lowy];
1900 
1901                 for (i = 0; i < curve.numberPoints; i++) {
1902                     if (lowy <= curve.points[i].usrCoords[2] &&
1903                             left <= curve.points[i].usrCoords[1] &&
1904                             curve.points[i].usrCoords[2] <= upy  &&
1905                             curve.points[i].usrCoords[1] <= right) {
1906                         x.push(curve.points[i].usrCoords[1]);
1907                         y.push(curve.points[i].usrCoords[2]);
1908                     }
1909                 }
1910                 x.push(upx);
1911                 y.push(upy);
1912                 x.push(0);
1913                 y.push(upy);
1914 
1915                 // close the curve
1916                 x.push(0);
1917                 y.push(lowy);
1918             } else {
1919                 if (pa_on_axis.X() < pb_on_axis.X()) {
1920                     left = pa_on_axis.X();
1921                     right = pb_on_axis.X();
1922                 } else {
1923                     left = pb_on_axis.X();
1924                     right = pa_on_axis.X();
1925                 }
1926 
1927                 x = [left, left];
1928                 y = [0, curve.Y(left)];
1929 
1930                 for (i = 0; i < curve.numberPoints; i++) {
1931                     if ((left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right)) {
1932                         x.push(curve.points[i].usrCoords[1]);
1933                         y.push(curve.points[i].usrCoords[2]);
1934                     }
1935                 }
1936                 x.push(right);
1937                 y.push(curve.Y(right));
1938                 x.push(right);
1939                 y.push(0);
1940 
1941                 // close the curve
1942                 x.push(left);
1943                 y.push(0);
1944             }
1945 
1946             this.dataX = x;
1947             this.dataY = y;
1948         };
1949         pa_on_curve.addChild(p);
1950         pb_on_curve.addChild(p);
1951 
1952         /**
1953          * The point on the axis initially corresponding to the lower value of the interval.
1954          * @memberOf Integral.prototype
1955          * @name baseLeft
1956          * @type JXG.Point
1957          */
1958         p.baseLeft = pa_on_axis;
1959 
1960         /**
1961          * The point on the axis initially corresponding to the higher value of the interval.
1962          * @memberOf Integral.prototype
1963          * @name baseRight
1964          * @type JXG.Point
1965          */
1966         p.baseRight = pb_on_axis;
1967 
1968         /**
1969          * The glider on the curve corresponding to the lower value of the interval.
1970          * @memberOf Integral.prototype
1971          * @name curveLeft
1972          * @type Glider
1973          */
1974         p.curveLeft = pa_on_curve;
1975 
1976         /**
1977          * The glider on the axis corresponding to the higher value of the interval.
1978          * @memberOf Integral.prototype
1979          * @name curveRight
1980          * @type Glider
1981          */
1982         p.curveRight = pb_on_curve;
1983 
1984         p.methodMap = JXG.deepCopy(p.methodMap, {
1985             curveLeft: 'curveLeft',
1986             baseLeft: 'baseLeft',
1987             curveRight: 'curveRight',
1988             baseRight: 'baseRight',
1989             Value: 'Value'
1990         });
1991 
1992         /**
1993          * documented in GeometryElement
1994          * @ignore
1995          */
1996         p.label = t;
1997 
1998         return p;
1999     };
2000 
2001     /**
2002      * @class Creates a grid to support the user with element placement.
2003      * @pseudo
2004      * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method
2005      * draws such a grid on the given board. It uses options given in {@link JXG.Options#grid}. This method does not
2006      * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set
2007      * to true.
2008      * @parameter None.
2009      * @constructor
2010      * @name Grid
2011      * @type JXG.Curve
2012      * @augments JXG.Curve
2013      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2014      * @example
2015      * grid = board.create('grid', []);
2016      * </pre><div id="a9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div>
2017      * <script type="text/javascript">
2018      * (function () {
2019      *  board = JXG.JSXGraph.initBoard('a9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
2020      *  grid = board.create('grid', []);
2021      * })();
2022      * </script><pre>
2023      */
2024     JXG.createGrid = function (board, parents, attributes) {
2025         var c, attr;
2026 
2027         attr = Type.copyAttributes(attributes, board.options, 'grid');
2028         c = board.create('curve', [[null], [null]], attr);
2029 
2030         c.elType = 'grid';
2031         c.parents = [];
2032         c.type = Const.OBJECT_TYPE_GRID;
2033 
2034         c.updateDataArray = function () {
2035             var start, end, i, topLeft, bottomRight,
2036                 gridX = this.visProp.gridx,
2037                 gridY = this.visProp.gridy;
2038 
2039             if (Type.isArray(this.visProp.topleft)) {
2040                 topLeft = new Coords(this.visProp.tltype || Const.COORDS_BY_USER, this.visProp.topleft, board);
2041             } else {
2042                 topLeft = new Coords(Const.COORDS_BY_SCREEN, [0, 0], board);
2043             }
2044 
2045             if (Type.isArray(this.visProp.bottomright)) {
2046                 bottomRight = new Coords(this.visProp.brtype || Const.COORDS_BY_USER, this.visProp.bottomright, board);
2047             } else {
2048                 bottomRight = new Coords(Const.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board);
2049             }
2050 
2051 
2052             //
2053             //      |         |         |
2054             //  ----+---------+---------+-----
2055             //      |        /|         |
2056             //      |    gridY|     <---+------   Grid Cell
2057             //      |        \|         |
2058             //  ----+---------+---------+-----
2059             //      |         |\ gridX /|
2060             //      |         |         |
2061             //
2062             // uc: usercoordinates
2063             //
2064             // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high.
2065             // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it
2066             // is absolutely not user friendly when it comes to use it as an API interface.
2067             // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i
2068             // had to refactor these methods:
2069             //
2070             //  DONE JXG.Board.calculateSnapSizes (init p1, p2)
2071             //  DONE JXG.GeonextReader.readGeonext (init gridX, gridY)
2072             //
2073 
2074             board.options.grid.hasGrid = true;
2075 
2076             topLeft.setCoordinates(Const.COORDS_BY_USER, [Math.floor(topLeft.usrCoords[1] / gridX) * gridX, Math.ceil(topLeft.usrCoords[2] / gridY) * gridY]);
2077             bottomRight.setCoordinates(Const.COORDS_BY_USER, [Math.ceil(bottomRight.usrCoords[1] / gridX) * gridX, Math.floor(bottomRight.usrCoords[2] / gridY) * gridY]);
2078 
2079             c.dataX = [];
2080             c.dataY = [];
2081 
2082             // Sometimes the bounding box is used to invert the axis. We have to take this into account here.
2083             start = topLeft.usrCoords[2];
2084             end = bottomRight.usrCoords[2];
2085 
2086             if (topLeft.usrCoords[2] < bottomRight.usrCoords[2]) {
2087                 start = bottomRight.usrCoords[2];
2088                 end = topLeft.usrCoords[2];
2089             }
2090 
2091             // start with the horizontal grid:
2092             for (i = start; i > end - gridY; i -= gridY) {
2093                 c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN);
2094                 c.dataY.push(i, i, NaN);
2095             }
2096 
2097             start = topLeft.usrCoords[1];
2098             end = bottomRight.usrCoords[1];
2099 
2100             if (topLeft.usrCoords[1] > bottomRight.usrCoords[1]) {
2101                 start = bottomRight.usrCoords[1];
2102                 end = topLeft.usrCoords[1];
2103             }
2104 
2105             // build vertical grid
2106             for (i = start; i < end + gridX; i += gridX) {
2107                 c.dataX.push(i, i, NaN);
2108                 c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN);
2109             }
2110 
2111         };
2112 
2113         // we don't care about highlighting so we turn it off completely to save a lot of
2114         // time on every mouse move
2115         c.hasPoint = function () {
2116             return false;
2117         };
2118 
2119         board.grids.push(c);
2120 
2121         return c;
2122     };
2123 
2124     /**
2125      * @class Creates an area indicating the solution of a linear inequality.
2126      * @pseudo
2127      * @description Display the solution set of a linear inequality (less than or equal to).
2128      * @param {JXG.Line} l The area drawn will be the area below this line.
2129      * @constructor
2130      * @name Inequality
2131      * @type JXG.Curve
2132      * @augments JXG.Curve
2133      * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
2134      * @example
2135      * p = board.create('point', [1, 3]);
2136      * q = board.create('point', [-2, -4]);
2137      * l = board.create('line', [p, q]);
2138      * ineq = board.create('inequality', [l]);
2139      * </pre><div id="2b703006-fd98-11e1-b79e-ef9e591c002e" style="width: 400px; height: 400px;"></div>
2140      * <script type="text/javascript">
2141      * (function () {
2142      *  board = JXG.JSXGraph.initBoard('2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});
2143      *  p = board.create('point', [1, 3]);
2144      *  q = board.create('point', [-2, -4]);
2145      *  l = board.create('line', [p, q]);
2146      *  ineq = board.create('inequality', [l]);
2147      * })();
2148      * </script><pre>
2149      */
2150     JXG.createInequality = function (board, parents, attributes) {
2151         var f, a, attr;
2152 
2153         attr = Type.copyAttributes(attributes, board.options, 'inequality');
2154         if (parents[0].elementClass === Const.OBJECT_CLASS_LINE) {
2155             a = board.create('curve', [[], []], attr);
2156             a.hasPoint = function () {
2157                 return false;
2158             };
2159             a.updateDataArray = function () {
2160                 var i1, i2,
2161                     // this will be the height of the area. We mustn't rely upon the board height because if we pan the view
2162                     // such that the line is not visible anymore, the borders of the area will get visible in some cases.
2163                     h,
2164                     bb = board.getBoundingBox(),
2165                     factor = attr.inverse ? -1 : 1,
2166                     expansion = 1.5,
2167                     w = expansion * Math.max(bb[2] - bb[0], bb[1] - bb[3]),
2168                     // fake a point (for Math.Geometry.perpendicular)
2169                     dp = {
2170                         coords: {
2171                             usrCoords: [1, (bb[0] + bb[2]) / 2, attr.inverse ? bb[1] : bb[3]]
2172                         }
2173                     },
2174 
2175                     slope1 = parents[0].stdform.slice(1),
2176                     slope2 = slope1;
2177 
2178                 if (slope1[1] > 0) {
2179                     slope1 = Statistics.multiply(slope1, -1);
2180                     slope2 = slope1;
2181                 }
2182 
2183                 // calculate the area height = 2* the distance of the line to the point in the middle of the top/bottom border.
2184                 h = expansion * Math.max(Geometry.perpendicular(parents[0], dp, board)[0].distance(Const.COORDS_BY_USER, dp.coords), w);
2185                 h *= factor;
2186 
2187                 // reuse dp
2188                 dp = {
2189                     coords: {
2190                         usrCoords: [1, (bb[0] + bb[2]) / 2, (bb[1] + bb[3]) / 2]
2191                     }
2192                 };
2193                 dp = Geometry.perpendicular(parents[0], dp, board)[0].usrCoords;
2194                 i1 = [1, dp[1] + slope1[1] * w, dp[2] - slope1[0] * w];
2195                 i2 = [1, dp[1] - slope2[1] * w, dp[2] + slope2[0] * w];
2196 
2197                 // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1)
2198                 // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and
2199                 // end up in i2.
2200                 this.dataX = [i1[1], i1[1] + slope1[0] * h, i2[1] + slope2[0] * h, i2[1], i1[1]];
2201                 this.dataY = [i1[2], i1[2] + slope1[1] * h, i2[2] + slope2[1] * h, i2[2], i1[2]];
2202             };
2203         } else {
2204             f = Type.createFunction(parents[0]);
2205             if (!Type.exists(f)) {
2206                 throw new Error("JSXGraph: Can't create area with the given parents." +
2207                     "\nPossible parent types: [line], [function]");
2208             }
2209         }
2210 
2211         return a;
2212     };
2213 
2214 
2215     JXG.registerElement('arrowparallel', JXG.createArrowParallel);
2216     JXG.registerElement('bisector', JXG.createBisector);
2217     JXG.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);
2218     JXG.registerElement('circumcircle', JXG.createCircumcircle);
2219     JXG.registerElement('circumcirclemidpoint', JXG.createCircumcenter);
2220     JXG.registerElement('circumcenter', JXG.createCircumcenter);
2221     JXG.registerElement('incenter', JXG.createIncenter);
2222     JXG.registerElement('incircle', JXG.createIncircle);
2223     JXG.registerElement('integral', JXG.createIntegral);
2224     JXG.registerElement('midpoint', JXG.createMidpoint);
2225     JXG.registerElement('mirrorpoint', JXG.createMirrorPoint);
2226     JXG.registerElement('normal', JXG.createNormal);
2227     JXG.registerElement('orthogonalprojection', JXG.createOrthogonalProjection);
2228     JXG.registerElement('parallel', JXG.createParallel);
2229     JXG.registerElement('parallelpoint', JXG.createParallelPoint);
2230     JXG.registerElement('perpendicular', JXG.createPerpendicular);
2231     JXG.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);
2232     JXG.registerElement('perpendicularsegment', JXG.createPerpendicularSegment);
2233     JXG.registerElement('reflection', JXG.createReflection);
2234     JXG.registerElement('grid', JXG.createGrid);
2235     JXG.registerElement('inequality', JXG.createInequality);
2236 
2237     return {
2238         createArrowParallel: JXG.createArrowParallel,
2239         createBisector: JXG.createBisector,
2240         createAngularBisectorOfTwoLines: JXG.createAngularBisectorsOfTwoLines,
2241         createCircumcircle: JXG.createCircumcircle,
2242         createCircumcenter: JXG.createCircumcenter,
2243         createIncenter: JXG.createIncenter,
2244         createIncircle: JXG.createIncircle,
2245         createIntegral: JXG.createIntegral,
2246         createMidpoint: JXG.createMidpoint,
2247         createMirrorPoint: JXG.createMirrorPoint,
2248         createNormal: JXG.createNormal,
2249         createOrthogonalProjection: JXG.createOrthogonalProjection,
2250         createParallel: JXG.createParallel,
2251         createParallelPoint: JXG.createParallelPoint,
2252         createPerpendicular: JXG.createPerpendicular,
2253         createPerpendicularPoint: JXG.createPerpendicularPoint,
2254         createPerpendicularSegmen: JXG.createPerpendicularSegment,
2255         createReflection: JXG.createReflection,
2256         createGrid: JXG.createGrid,
2257         createInequality: JXG.createInequality
2258     };
2259 });
2260