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