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