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