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