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