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 Parallel}</li>
 40  *   <li>{@link Perpendicular}</li>
 41  *   <li>{@link Perpendicularpoint}</li>
 42  *   <li>{@link Reflection}</li></ul>
 43  */
 44 
 45 /**
 46  * @class This is used to construct a perpendicular point.
 47  * @pseudo
 48  * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point
 49  * orthogonal onto the given line.
 50  * @constructor
 51  * @name Perpendicularpoint
 52  * @type JXG.Point
 53  * @augments JXG.Point
 54  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
 55  * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.
 56  * @example
 57  * var p1 = board.create('point', [0.0, 4.0]);
 58  * var p2 = board.create('point', [6.0, 1.0]);
 59  * var l1 = board.create('line', [p1, p2]);
 60  * var p3 = board.create('point', [3.0, 3.0]);
 61  *
 62  * var pp1 = board.create('perpendicularpoint', [p3, l1]);
 63  * </pre><div id="ded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div>
 64  * <script type="text/javascript">
 65  *   var ppex1_board = JXG.JSXGraph.initBoard('ded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
 66  *   var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);
 67  *   var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);
 68  *   var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);
 69  *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
 70  *   var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]);
 71  * </script><pre>
 72  */
 73 JXG.createPerpendicularPoint = function(board, parentArr, atts) {
 74     var l, p, t;
 75 
 76     if(JXG.isPoint(parentArr[0]) && parentArr[1].type == JXG.OBJECT_TYPE_LINE) {
 77         p = parentArr[0];
 78         l = parentArr[1];
 79     }
 80     else if(JXG.isPoint(parentArr[1]) && parentArr[0].type == JXG.OBJECT_TYPE_LINE) {
 81         p = parentArr[1];
 82         l = parentArr[0];
 83     }
 84     else {
 85         throw new Error("JSXGraph: Can't create perpendicular point with parent types '" +
 86                         (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." +
 87                         "\nPossible parent types: [point,line]");
 88     }
 89 
 90     // no need to call create, the properties will be set through the create('perpendicular') call
 91     t = JXG.createPoint(board, [function () { return JXG.Math.Geometry.perpendicular(l, p, board)[0]; }], {fixed: true, name: atts['name'], id: atts['id']});
 92     p.addChild(t); // notwendig, um auch den Punkt upzudaten
 93     l.addChild(t);
 94 
 95     t.update();
 96 
 97     t.generatePolynomial = function() {
 98         /*
 99          *  Perpendicular takes point P and line L and creates point T and line M:
100          *
101          *                          | M
102          *                          |
103          *                          x P (p1,p2)
104          *                          |
105          *                          |
106          *  L                       |
107          *  ----------x-------------x------------------------x--------
108          *            A (a1,a2)     |T (t1,t2)               B (b1,b2)
109          *                          |
110          *                          |
111          *
112          * So we have two conditions:
113          *
114          *   (a)  AT  || TB          (collinearity condition)
115          *   (b)  PT _|_ AB          (orthogonality condition)
116          *
117          *      a2-t2       t2-b2
118          *     -------  =  -------           (1)
119          *      a1-t1       t1-b1
120          *
121          *      p2-t2         a1-b1
122          *     -------  =  - -------         (2)
123          *      p1-t1         a2-b2
124          *
125          * Multiplying (1) and (2) with denominators and simplifying gives
126          *
127          *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                  (1')
128          *
129          *    p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0    (2')
130          *
131          */
132 
133         var a1 = l.point1.symbolic.x;
134         var a2 = l.point1.symbolic.y;
135         var b1 = l.point2.symbolic.x;
136         var b2 = l.point2.symbolic.y;
137         var p1 = p.symbolic.x;
138         var p2 = p.symbolic.y;
139         var t1 = t.symbolic.x;
140         var t2 = t.symbolic.y;
141 
142         var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
143         var poly2 = '('+p2+')*('+a2+')-('+p2+')*('+b2+')-('+t2+')*('+a2+')+('+t2+')*('+b2+')+('+p1+')*('+a1+')-('+p1+')*('+b1+')-('+t1+')*('+a1+')+('+t1+')*('+b1+')';
144 
145         return [poly1, poly2];
146     };
147 
148     return t;
149 };
150 
151 
152 /**
153  * @class This element is used to provide a constructor for a perpendicular.
154  * @pseudo
155  * @description  A perpendicular is a composition of two elements: a line and a point. The line is orthogonal
156  * to a given line and contains a given point and meets the given line in the perpendicular point.
157  * @name Perpendicular
158  * @constructor
159  * @type Array
160  * @return An array containing two elements: A {@link JXG.Line} object in the first component and a
161  * {@link JXG.Point} element in the second component. The line is orthogonal to the given line and meets it
162  * in the returned point.
163  * @throws {Exception} If the elements cannot be constructed with the given parent objects an exception is thrown.
164  * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and
165  * will contain p. The perpendicular point is the intersection point of the two lines.
166  * @example
167  * // Create a perpendicular
168  * var p1 = board.create('point', [0.0, 2.0]);
169  * var p2 = board.create('point', [2.0, 1.0]);
170  * var l1 = board.create('line', [p1, p2]);
171  *
172  * var p3 = board.create('point', [3.0, 3.0]);
173  * var perp1 = board.create('perpendicular', [l1, p3]);
174  * </pre><div id="037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div>
175  * <script type="text/javascript">
176  *   var pex1_board = JXG.JSXGraph.initBoard('037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
177  *   var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);
178  *   var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);
179  *   var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);
180  *   var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);
181  *   var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]);
182  * </script><pre>
183  */
184 JXG.createPerpendicular = function(board, parentArr, atts) {
185     var p, l, pd, t, ret;
186 
187     parentArr[0] = JXG.getReference(board, parentArr[0]);
188     parentArr[1] = JXG.getReference(board, parentArr[1]);
189 
190     if(JXG.isPoint(parentArr[0]) && parentArr[1].elementClass == JXG.OBJECT_CLASS_LINE) {
191         l = parentArr[1];
192         p = parentArr[0];
193     }
194     else if(JXG.isPoint(parentArr[1]) && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) {
195         l = parentArr[0];
196         p = parentArr[1];
197     }
198     else {
199         throw new Error("JSXGraph: Can't create perpendicular with parent types '" +
200                         (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." +
201                         "\nPossible parent types: [line,point]");
202     }
203 
204     if(!JXG.isArray(atts['id'])) {
205         atts['id'] = ['',''];
206     }
207     if(!JXG.isArray(atts['name'])) {
208         atts['name'] = ['',''];
209     }
210 
211     // no need to call create, the properties will be set through the create('perpendicular') call
212     t = JXG.createPerpendicularPoint(board, [l, p], {fixed: true, name: atts['name'][1], id: atts['id'][1], visible: false});
213     pd = JXG.createSegment(board, [function () { return (JXG.Math.Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]); }], {name: atts['name'][0], id: atts['id'][0]});
214 
215     ret = [pd, t];
216     ret.line = pd;
217     ret.point = t;
218     ret.multipleElements = true;
219 
220     return ret;
221 };
222 
223 /**
224  * @class The midpoint element constructs a point in the middle of two given points.
225  * @pseudo
226  * @description A midpoint is given by two points. It is collinear to the given points and the distance
227  * is the same to each of the given points, i.e. it is in the middle of the given points.
228  * @constructor
229  * @name Midpoint
230  * @type JXG.Point
231  * @augments JXG.Point
232  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
233  * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2.
234  * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of
235  * the given line l.
236  * @example
237  * // Create base elements: 2 points and 1 line
238  * var p1 = board.create('point', [0.0, 2.0]);
239  * var p2 = board.create('point', [2.0, 1.0]);
240  * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
241  *
242  * var mp1 = board.create('midpoint', [p1, p2]);
243  * var mp2 = board.create('midpoint', [l1]);
244  * </pre><div id="7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div>
245  * <script type="text/javascript">
246  *   var mpex1_board = JXG.JSXGraph.initBoard('7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
247  *   var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]);
248  *   var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]);
249  *   var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);
250  *   var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]);
251  *   var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]);
252  * </script><pre>
253  */
254 JXG.createMidpoint = function(board, parentArr, atts) {
255     var a, b, t;
256     if(parentArr.length == 2 && JXG.isPoint(parentArr[0]) && JXG.isPoint(parentArr[1])) {
257         a = parentArr[0];
258         b = parentArr[1];
259     }
260     else if(parentArr.length == 1 && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) {
261         a = parentArr[0].point1;
262         b = parentArr[0].point2;
263     }
264     else {
265         throw new Error("JSXGraph: Can't create midpoint." +
266                         "\nPossible parent types: [point,point], [line]");
267     }
268 
269     if(atts) {
270     	atts['fixed'] = true;
271     } else {
272     	atts = {fixed: true};
273     }
274 
275     t = board.create('point', [function () { return (a.coords.usrCoords[1] + b.coords.usrCoords[1])/2.; },
276                                function () { return (a.coords.usrCoords[2] + b.coords.usrCoords[2])/2.; }], atts);
277     a.addChild(t);
278     b.addChild(t);
279 
280     t.update();
281 
282     t.generatePolynomial = function() {
283         /*
284          *  Midpoint takes two point A and B or line L (with points P and Q) and creates point T:
285          *
286          *  L (not necessarily)
287          *  ----------x------------------x------------------x--------
288          *            A (a1,a2)          T (t1,t2)          B (b1,b2)
289          *
290          * So we have two conditions:
291          *
292          *   (a)   AT  ||  TB           (collinearity condition)
293          *   (b)  [AT] == [TB]          (equidistant condition)
294          *
295          *      a2-t2       t2-b2
296          *     -------  =  -------                                         (1)
297          *      a1-t1       t1-b1
298          *
299          *     (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2       (2)
300          *
301          *
302          * Multiplying (1) with denominators and simplifying (1) and (2) gives
303          *
304          *    a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0                      (1')
305          *
306          *    a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0    (2')
307          *
308          */
309 
310         var a1 = a.symbolic.x;
311         var a2 = a.symbolic.y;
312         var b1 = b.symbolic.x;
313         var b2 = b.symbolic.y;
314         var t1 = t.symbolic.x;
315         var t2 = t.symbolic.y;
316 
317         var poly1 = '('+a2+')*('+t1+')-('+a2+')*('+b1+')+('+t2+')*('+b1+')-('+a1+')*('+t2+')+('+a1+')*('+b2+')-('+t1+')*('+b2+')';
318         var poly2 = '('+a1+')^2 - 2*('+a1+')*('+t1+')+('+a2+')^2-2*('+a2+')*('+t2+')-('+b1+')^2+2*('+b1+')*('+t1+')-('+b2+')^2+2*('+b2+')*('+t2+')';
319 
320         return [poly1, poly2];
321     };
322 
323     // 2009/10/11, mg:
324     // * this is just a test: we're forming three closures in here: One with generatePolynomial and two when we create the
325     //   point by using function objects as positions. So a reference to the current Activation object is held in the scope of
326     //   those three functions. But we don't need a reference to the atts object in any of them, so we're deleting the
327     //   reference to it. Hence, the garbage collector can remove it from memory, if there's no reference to it left.
328     // * first test successful: attributes will be set properly. it remains to test, if this helps us to reduce memory usage.
329     //   for the test we'll query a JXG attribute "nullAtts" which has to be set to true to null the atts parameter. Then
330     //   50,000 midpoints will be created in an example file with resp. without nulling the atts parameter and after that chrome
331     //   will be used to compare the memory usage.
332     if(JXG.nullAtts)
333         atts = null;
334 
335     return t;
336 };
337 
338 /**
339  * @class This element is used to construct a parallel point.
340  * @pseudo
341  * @description A parallel point is given by three points. Taking the euclidean vector from the first to the
342  * second point, the parallel point is determined by adding that vector to the third point.
343  * The line determined by the first two points is parallel to the line determined by the third point and the constructed point.
344  * @constructor
345  * @name Parallelpoint
346  * @type JXG.Point
347  * @augments JXG.Point
348  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
349  * @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
350  * <tt>p4 = p3+v</tt>
351  * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l.
352  * @example
353  * var p1 = board.create('point', [0.0, 2.0]);
354  * var p2 = board.create('point', [2.0, 1.0]);
355  * var p3 = board.create('point', [3.0, 3.0]);
356  *
357  * var pp1 = board.create('parallelpoint', [p1, p2, p3]);
358  * </pre><div id="488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div>
359  * <script type="text/javascript">
360  *   var ppex1_board = JXG.JSXGraph.initBoard('488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
361  *   var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]);
362  *   var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]);
363  *   var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);
364  *   var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]);
365  * </script><pre>
366  */
367 JXG.createParallelPoint = function(board, parentArr, atts) {
368     var a, b, c, p;
369 
370     if(parentArr.length == 3 && parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[2].elementClass == JXG.OBJECT_CLASS_POINT) {
371         a = parentArr[0];
372         b = parentArr[1];
373         c = parentArr[2];
374     } else if (parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_LINE) {
375         c = parentArr[0];
376         a = parentArr[1].point1;
377         b = parentArr[1].point2;
378     } else if (parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) {
379         c = parentArr[1];
380         a = parentArr[0].point1;
381         b = parentArr[0].point2;
382     }
383     else {
384         throw new Error("JSXGraph: Can't create parallel point with parent types '" +
385                         (typeof parentArr[0]) + "', '" + (typeof parentArr[1]) + "' and '" + (typeof parentArr[2]) + "'." +
386                         "\nPossible parent types: [line,point], [point,point,point]");
387     }
388 
389     p = board.create('point', [function () { return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1]; }, 
390                                function () { return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2]; }], 
391                                atts);
392 	// required for algorithms requiring dependencies between elements
393 	a.addChild(p);
394 	b.addChild(p);
395     c.addChild(p);
396 
397     // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update.
398     // can be removed if the above issue is resolved.
399     p.update();
400 
401     p.generatePolynomial = function() {
402         /*
403          *  Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T:
404          *
405          *
406          *                     C (c1,c2)                             T (t1,t2)
407          *                      x                                     x
408          *                     /                                     /
409          *                    /                                     /
410          *                   /                                     /
411          *                  /                                     /
412          *                 /                                     /
413          *                /                                     /
414          *               /                                     /
415          *              /                                     /
416          *  L (opt)    /                                     /
417          *  ----------x-------------------------------------x--------
418          *            A (a1,a2)                             B (b1,b2)
419          *
420          * So we have two conditions:
421          *
422          *   (a)   CT  ||  AB           (collinearity condition I)
423          *   (b)   BT  ||  AC           (collinearity condition II)
424          *
425          * The corresponding equations are
426          *
427          *    (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0         (1)
428          *    (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0         (2)
429          *
430          * Simplifying (1) and (2) gives
431          *
432          *    b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0      (1')
433          *    t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0      (2')
434          *
435          */
436 
437         var a1 = a.symbolic.x;
438         var a2 = a.symbolic.y;
439         var b1 = b.symbolic.x;
440         var b2 = b.symbolic.y;
441         var c1 = c.symbolic.x;
442         var c2 = c.symbolic.y;
443         var t1 = p.symbolic.x;
444         var t2 = p.symbolic.y;
445 
446         var poly1 =  '('+b2+')*('+t1+')-('+b2+')*('+c1+')-('+a2+')*('+t1+')+('+a2+')*('+c1+')-('+t2+')*('+b1+')+('+t2+')*('+a1+')+('+c2+')*('+b1+')-('+c2+')*('+a1+')';
447         var poly2 =  '('+t2+')*('+a1+')-('+t2+')*('+c1+')-('+b2+')*('+a1+')+('+b2+')*('+c1+')-('+t1+')*('+a2+')+('+t1+')*('+c2+')+('+b1+')*('+a2+')-('+b1+')*('+c2+')';
448 
449         return [poly1, poly2];
450     };
451 
452     return p;
453 };
454 
455 /**
456  * @class Constructor for a parallel line.
457  * @pseudo
458  * @description A parallel is a line through a given point with the same slope as a given line.
459  * @constructor
460  * @name Parallel
461  * @type JXG.Line
462  * @augments JXG.Line
463  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
464  * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l.
465  * @example
466  * // Create a parallel
467  * var p1 = board.create('point', [0.0, 2.0]);
468  * var p2 = board.create('point', [2.0, 1.0]);
469  * var l1 = board.create('line', [p1, p2]);
470  *
471  * var p3 = board.create('point', [3.0, 3.0]);
472  * var pl1 = board.create('parallel', [l1, p3]);
473  * </pre><div id="24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div>
474  * <script type="text/javascript">
475  *   var plex1_board = JXG.JSXGraph.initBoard('24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
476  *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
477  *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
478  *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
479  *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
480  *   var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);
481  * </script><pre>
482  */
483 JXG.createParallel = function(board, parents, atts) {
484     var p, pp, pl, cAtts;
485 
486     /* parallel point polynomials are done in createParallelPoint */
487 
488     cAtts = {name: null, id: null, fixed: true, visible: false};
489     if(JXG.isArray(atts['name']) && atts['name'].length == 2) {
490         cAtts['name'] = atts['name'][1];
491         atts['name'] = atts['name'][0];
492     } else
493         cAtts['name'] = atts['name'] + 'p2';
494         
495     if(JXG.isArray(atts['id']) && atts['id'].length == 2) {
496         cAtts['id'] = atts['id'][1];
497         atts['id'] = atts['id'][0];
498     } else if (JXG.exists(atts['id'])) 
499         cAtts['id'] = atts['id'] + 'p2';
500 
501     try {
502         pp = JXG.createParallelPoint(board, parents, cAtts); // non-visible point
503     } catch (e) {
504         throw new Error("JSXGraph: Can't create parallel with parent types '" +
505                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
506                         "\nPossible parent types: [line,point], [point,point,point]");
507     }
508 
509     p = null;
510     if(parents.length == 3)
511         p = parents[2];
512     else if (parents[0].elementClass == JXG.OBJECT_CLASS_POINT)
513         p = parents[0];
514     else if (parents[1].elementClass == JXG.OBJECT_CLASS_POINT)
515         p = parents[1];
516 
517     pl = board.create('line', [p, pp], atts);
518 
519     return pl;
520 };
521 
522 /**
523  * TODO is this really required? it is the same as 'parallel', except that it doesn't touch the first/lastarrow properties and it returns
524  * the parallel point. for now it is set to private. please review the docs-comment before making it public. especially the example section
525  * isn't done by now. --michael
526  * @private
527  * @class Constructs two elements: an arrow and a point.
528  * @pseudo
529  * @description An arrow parallel is an arrow through a given point with the same slope as another given arrow.
530  * @constructor
531  * @name Arrowparallel
532  * @type JXG.Line
533  * @augments JXG.Line
534  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
535  * @param {Arrow_JXG.Point} a,p The constructed arrow contains p and has the same slope as a.
536  * @example
537  * // Create a parallel
538  * var p1 = board.create('point', [0.0, 2.0]);
539  * var p2 = board.create('point', [2.0, 1.0]);
540  * var l1 = board.create('line', [p1, p2]);
541  *
542  * var p3 = board.create('point', [3.0, 3.0]);
543  * var pl1 = board.create('parallel', [l1, p3]);
544  * </pre><div id="qwe" style="width: 400px; height: 400px;"></div>
545  * <script type="text/javascript">
546  *   var plex1_board = JXG.JSXGraph.initBoard('asd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
547  *   var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);
548  *   var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);
549  *   var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);
550  *   var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);
551  *   var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);
552  * </script><pre>
553  */
554 JXG.createArrowParallel = function(board, parents, atts) {
555     var l, cAtts;
556 
557     /* parallel arrow point polynomials are done in createParallelPoint */
558     try {
559         // we don't have to get onto that whole create stack here
560         // because that'll be run for the line l right after leaving that function.
561         l = JXG.createParallel(board, parents, atts);
562     } catch (e) {
563         throw new Error("JSXGraph: Can't create arrowparallel with parent types '" +
564                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
565                         "\nPossible parent types: [line,point], [point,point,point]");
566     }
567 
568     // Select the default behavior. If the user wants something else he would set it in atts.
569     // That gets parsed and set right after this function.
570     l.setStraight(false, false);
571     l.setArrow(false,true);
572     return l;
573 };
574 
575 /**
576  * @class Constructs a normal.
577  * @pseudo
578  * @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.
579  * @constructor
580  * @name Normal
581  * @type JXG.Line
582  * @augments JXG.Line
583  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
584  * @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
585  * to the tangent to the object in the given point.
586  * @param {Glider} p Works like above, however the object is given by {@link Glider#slideObject}.
587  * @example
588  * // Create a normal to a circle.
589  * var p1 = board.create('point', [2.0, 2.0]);
590  * var p2 = board.create('point', [3.0, 2.0]);
591  * var c1 = board.create('circle', [p1, p2]);
592  *
593  * var norm1 = board.create('normal', [c1, p2]);
594  * </pre><div id="4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div>
595  * <script type="text/javascript">
596  *   var nlex1_board = JXG.JSXGraph.initBoard('4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
597  *   var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]);
598  *   var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]);
599  *   var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]);
600  *
601  *   // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]);
602  *   var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]);
603  * </script><pre>
604  */
605 JXG.createNormal = function(board, parents, attributes) {
606     /* TODO normal polynomials */
607     var p;
608     var c;
609     if (parents.length==1) { // One arguments: glider on line, circle or curve
610         p = parents[0];
611         c = p.slideObject;
612     } else if (parents.length==2) { // Two arguments: (point,line), (point,circle), (line,point) or (circle,point)
613         if (JXG.isPoint(parents[0])) {
614             p = parents[0];
615             c = parents[1];
616         } else if (JXG.isPoint(parents[1])) {
617             c = parents[0];
618             p = parents[1];
619         } else {
620             throw new Error("JSXGraph: Can't create normal with parent types '" +
621                             (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
622                             "\nPossible parent types: [point,line], [point,circle], [glider]");
623         }
624     } else {
625         throw new Error("JSXGraph: Can't create normal with parent types '" +
626                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
627                         "\nPossible parent types: [point,line], [point,circle], [glider]");
628     }
629 
630     if(c.elementClass==JXG.OBJECT_CLASS_LINE) {
631         // return board.addNormal(c,p, attributes['id'], attributes['name']); // GEONExT-Style: problems with ideal point
632         // If not needed, then board.addNormal and maybe JXG.Math.Geometry.perpendicular can be removed.
633 
634         // Homogeneous version:
635         // orthogonal(l,p) = (F^\delta\cdot l)\times p
636         return board.create('line', [
637                     function(){ return c.stdform[1]*p.Y()-c.stdform[2]*p.X();},
638                     function(){ return c.stdform[2]*p.Z();},
639                     function(){ return -c.stdform[1]*p.Z();}
640                     ], attributes );
641     }
642     else if(c.elementClass == JXG.OBJECT_CLASS_CIRCLE) {
643         /*
644         var Dg = function(t){ return -c.Radius()*Math.sin(t); };
645         var Df = function(t){ return c.Radius()*Math.cos(t); };
646         return board.create('line', [
647                     function(){ return -p.X()*Dg(p.position)-p.Y()*Df(p.position);},
648                     function(){ return Dg(p.position);},
649                     function(){ return Df(p.position);}
650                     ], attributes );
651         */
652         return board.create('line', [c.midpoint,p], attributes);
653     } else if (c.elementClass == JXG.OBJECT_CLASS_CURVE) {
654         if (c.curveType!='plot') {
655             var g = c.X;
656             var f = c.Y;
657             return board.create('line', [
658                     function(){ return -p.X()*board.D(g)(p.position)-p.Y()*board.D(f)(p.position);},
659                     function(){ return board.D(g)(p.position);},
660                     function(){ return board.D(f)(p.position);}
661                     ], attributes );
662         } else {                         // curveType 'plot'
663             return board.create('line', [
664                     function(){ var i=Math.floor(p.position);
665                                 var lbda = p.position-i;
666                                 if (i==c.numberPoints-1) {i--; lbda=1; }
667                                 if (i<0) return 1.0;
668                                 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));},
669                     function(){ var i=Math.floor(p.position);
670                                 if (i==c.numberPoints-1) i--;
671                                 if (i<0) return 0.0;
672                                 return c.X(i+1)-c.X(i);},
673                     function(){ var i=Math.floor(p.position);
674                                 if (i==c.numberPoints-1) i--;
675                                 if (i<0) return 0.0;
676                                 return c.Y(i+1)-c.Y(i);}
677                     ], attributes );
678         }
679     } else if (c.type == JXG.OBJECT_TYPE_TURTLE) {
680             return board.create('line', [
681                     function(){ var i=Math.floor(p.position);
682                                 var lbda = p.position-i;
683                                 var el,j;
684                                 for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
685                                     el = c.objects[j];
686                                     if (el.type==JXG.OBJECT_TYPE_CURVE) {
687                                         if (i<el.numberPoints) break;
688                                         i-=el.numberPoints;
689                                     }
690                                 }
691                                 if (i==el.numberPoints-1) { i--; lbda=1.0; }
692                                 if (i<0) return 1.0;
693                                 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));},
694                     function(){ var i=Math.floor(p.position);
695                                 var el,j;
696                                 for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
697                                     el = c.objects[j];
698                                     if (el.type==JXG.OBJECT_TYPE_CURVE) {
699                                         if (i<el.numberPoints) break;
700                                         i-=el.numberPoints;
701                                     }
702                                 }
703                                 if (i==el.numberPoints-1) i--;
704                                 if (i<0) return 0.0;
705                                 return el.X(i+1)-el.X(i);},
706                     function(){ var i=Math.floor(p.position);
707                                 var el,j;
708                                 for(j=0;j<c.objects.length;j++) {  // run through all curves of this turtle
709                                     el = c.objects[j];
710                                     if (el.type==JXG.OBJECT_TYPE_CURVE) {
711                                         if (i<el.numberPoints) break;
712                                         i-=el.numberPoints;
713                                     }
714                                 }
715                                 if (i==el.numberPoints-1) i--;
716                                 if (i<0) return 0.0;
717                                 return el.Y(i+1)-el.Y(i);}
718                     ], attributes );
719     }
720     else {
721         throw new Error("JSXGraph: Can't create normal with parent types '" +
722                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
723                         "\nPossible parent types: [point,line], [point,circle], [glider]");
724     }
725 };
726 
727 /**
728  * @class Provides a constructor for an angle bisector.
729  * @pseudo
730  * @description A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and C and divides the angle ABC into two
731  * equal sized parts.
732  * @constructor
733  * @name Bisector
734  * @type JXG.Line
735  * @augments JXG.Line
736  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
737  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by p3 will be divided into two equal angles.
738  * @example
739  * // Create a normal to a circle.
740  * var p1 = board.create('point', [6.0, 4.0]);
741  * var p2 = board.create('point', [3.0, 2.0]);
742  * var p3 = board.create('point', [1.0, 7.0]);
743  *
744  * var bi1 = board.create('bisector', [p1, p2, p3]);
745  * </pre><div id="0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div>
746  * <script type="text/javascript">
747  *   var biex1_board = JXG.JSXGraph.initBoard('0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
748  *   var biex1_p1 = biex1_board.create('point', [6.0, 4.0]);
749  *   var biex1_p2 = biex1_board.create('point', [3.0, 2.0]);
750  *   var biex1_p3 = biex1_board.create('point', [1.0, 7.0]);
751  *   var biex1_bi1 = biex1_board.create('bisector', [biex1_p1, biex1_p2, biex1_p3]);
752  * </script><pre>
753  */
754 JXG.createBisector = function(board, parentArr, atts) {
755     var p, l, cAtts, i;
756     /* TODO bisector polynomials */
757     if(parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[2].elementClass == JXG.OBJECT_CLASS_POINT) {
758 
759         cAtts = {name: '', id: null, fixed: true, visible: false};
760         if(atts) {
761             cAtts = JXG.cloneAndCopy(atts, cAtts);
762         }
763 
764         // hidden and fixed helper
765         p = board.create('point', [function () { return JXG.Math.Geometry.angleBisector(parentArr[0], parentArr[1], parentArr[2], board); }], cAtts);
766 
767         for(i=0; i<3; i++)
768             parentArr[i].addChild(p); // required for algorithm requiring dependencies between elements
769 
770         if(typeof atts['straightFirst'] == 'undefined')
771             atts['straightFirst'] = false;
772         if(typeof atts['straightLast'] == 'undefined')
773             atts['straightLast'] = true;
774         // no need to fire up the create stack because only attributes need to be set and they
775         // will be set for l after returning.
776         l = JXG.createLine(board, [parentArr[1], p], atts);
777         return l;
778     }
779     else {
780         throw new Error("JSXGraph: Can't create angle bisector with parent types '" +
781                         (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." +
782                         "\nPossible parent types: [point,point,point]");
783     }
784 };
785 
786 /**
787  * TODO Is it possible to merge this with createBisector? --michael
788  * The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation:
789  * (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2)
790  * @private
791  */
792 JXG.createAngularBisectorsOfTwoLines = function(board, parents, attributes) {
793     var l1 = JXG.getReference(board,parents[0]),
794         l2 = JXG.getReference(board,parents[1]),
795         id1 = '',
796         id2 = '',
797         n1 = '',
798         n2 = '',
799         ret;
800 
801     if(l1.elementClass != JXG.OBJECT_CLASS_LINE || l2.elementClass != JXG.OBJECT_CLASS_LINE) {
802         throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" +
803                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
804                         "\nPossible parent types: [line,line]");
805     }
806 
807     attributes = JXG.checkAttributes(attributes,{});
808     if (attributes['id']!=null) {
809         if (JXG.isArray(attributes['id'])) {
810             id1 = attributes['id'][0];
811             id2 = attributes['id'][1];
812         } else {
813             id1 = attributes['id'];
814             id2 = attributes['id'];
815         }
816     }
817     if (attributes['name']!=null) {
818         if (JXG.isArray(attributes['name'])) {
819             n1 = attributes['name'][0];
820             n2 = attributes['name'][1];
821         } else {
822             n1 = attributes['name'];
823             n2 = attributes['name'];
824         }
825     }
826 
827     attributes['id'] = id1;
828     attributes['name'] = n1;
829     var g1 = board.create('line',[
830         function(){
831             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
832             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
833             return l1.stdform[0]/d1-l2.stdform[0]/d2;
834         },
835         function(){
836             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
837             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
838             return l1.stdform[1]/d1-l2.stdform[1]/d2;
839         },
840         function(){
841             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
842             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
843             return l1.stdform[2]/d1-l2.stdform[2]/d2;
844         }
845     ], attributes);
846     attributes['id'] = id2;
847     attributes['name'] = n2;
848     var g2 = board.create('line',[
849         function(){
850             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
851             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
852             return l1.stdform[0]/d1+l2.stdform[0]/d2;
853         },
854         function(){
855             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
856             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
857             return l1.stdform[1]/d1+l2.stdform[1]/d2;
858         },
859         function(){
860             var d1 = Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]);
861             var d2 = Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);
862             return l1.stdform[2]/d1+l2.stdform[2]/d2;
863         }
864     ], attributes);
865 
866     ret = [g1, g2];
867     ret.lines = [g1, g2];
868     ret.line1 = g1;
869     ret.line2 = g2;
870 
871     ret.multipleElements = true;
872 
873     return ret;
874 };
875 
876 /**
877  * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter
878  * is constructed by providing three points.
879  * @pseudo
880  * @description A circumcenter is given by three points which are all lying on the circle with the
881  * constructed circumcenter as the midpoint.
882  * @constructor
883  * @name Circumcenter
884  * @type JXG.Point
885  * @augments JXG.Point
886  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
887  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined
888  * by p1, p2, and p3.
889  * @example
890  * var p1 = board.create('point', [0.0, 2.0]);
891  * var p2 = board.create('point', [2.0, 1.0]);
892  * var p3 = board.create('point', [3.0, 3.0]);
893  *
894  * var cc1 = board.create('circumcenter', [p1, p2, p3]);
895  * </pre><div id="e8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div>
896  * <script type="text/javascript">
897  *   var ccmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
898  *   var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]);
899  *   var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]);
900  *   var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]);
901  *   var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]);
902  * </script><pre>
903  */
904 JXG.createCircumcircleMidpoint = function(board, parents, atts) {
905     var p, i;
906 
907     /* TODO circumcircle polynomials */
908 
909     if(parents[0].elementClass == JXG.OBJECT_CLASS_POINT && parents[1].elementClass == JXG.OBJECT_CLASS_POINT && parents[2].elementClass == JXG.OBJECT_CLASS_POINT) {
910         atts['fixed'] = atts['fixed'] || true;
911         p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.circumcenterMidpoint(parents[0], parents[1], parents[2], board); }], atts);
912 
913         for(i=0; i<3; i++)
914             parents[i].addChild(p);
915 
916         p.generatePolynomial = function() {
917                 /*
918                      *  CircumcircleMidpoint takes three points A, B and C  and creates point M, which is the circumcenter of A, B, and C.
919                      *
920                      *
921                      * So we have two conditions:
922                      *
923                      *   (a)   CT  ==  AT           (distance condition I)
924                      *   (b)   BT  ==  AT           (distance condition II)
925                      *
926                      */
927 
928             var a1 = a.symbolic.x;
929             var a2 = a.symbolic.y;
930             var b1 = b.symbolic.x;
931             var b2 = b.symbolic.y;
932             var c1 = c.symbolic.x;
933             var c2 = c.symbolic.y;
934             var t1 = p.symbolic.x;
935             var t2 = p.symbolic.y;
936 
937             var poly1 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',b1,'))^2-((',t2,')-(',b2,'))^2'].join('');
938             var poly2 = ['((',t1,')-(',a1,'))^2+((',t2,')-(',a2,'))^2-((',t1,')-(',c1,'))^2-((',t2,')-(',c2,'))^2'].join('');
939 
940             return [poly1, poly2];
941         };
942 
943         return p;
944     }
945     else {
946         throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" +
947                         (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
948                         "\nPossible parent types: [point,point,point]");
949     }
950 };
951 
952 /**
953  * @class Constructs the incenter of the triangle described by the three given points.
954  * @pseudo
955  * @description http://mathworld.wolfram.com/Incenter.html
956  * @constructor
957  * @name Incenter
958  * @type JXG.Point
959  * @returns An array containing the midpoint in the first component and the circumcircle in the second component.
960  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
961  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described
962  * by p1, p2, and p3.
963  * @example
964  * var p1 = board.create('point', [0.0, 2.0]);
965  * var p2 = board.create('point', [2.0, 1.0]);
966  * var p3 = board.create('point', [3.0, 3.0]);
967  *
968  * var ic1 = board.create('incenter', [p1, p2, p3]);
969  * </pre><div id="e8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div>
970  * <script type="text/javascript">
971  *   var icmex1_board = JXG.JSXGraph.initBoard('e8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
972  *   var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]);
973  *   var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]);
974  *   var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]);
975  *   var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]);
976  * </script><pre>
977  */
978 JXG.createIncenter = function(board, parents, atts) {
979     var p, c, ret,
980         A, B, C;
981 
982     if(parents.length >= 3 && JXG.isPoint(parents[0]) && JXG.isPoint(parents[1]) && JXG.isPoint(parents[2])) {
983         A = parents[0];
984         B = parents[1];
985         C = parents[2];
986 
987         p = board.create('point', [function() {
988             var a, b, c;
989 
990             a = Math.sqrt((B.X() - C.X())*(B.X() - C.X()) + (B.Y() - C.Y())*(B.Y() - C.Y()));
991             b = Math.sqrt((A.X() - C.X())*(A.X() - C.X()) + (A.Y() - C.Y())*(A.Y() - C.Y()));
992             c = Math.sqrt((B.X() - A.X())*(B.X() - A.X()) + (B.Y() - A.Y())*(B.Y() - A.Y()));
993 
994             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);
995         }], atts);
996     } else {
997         throw new Error("JSXGraph: Can't create incenter with parent types '" +
998             (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
999             "\nPossible parent types: [point,point,point]");
1000     }
1001 
1002     return p;
1003 };
1004 
1005 /**
1006  * @class Constructs two elements: a point and a circle. The circle is given by three points which lie on the circle,
1007  * the point is the midpoint of the circle.
1008  * @pseudo
1009  * @description A circumcircle is given by three points which are all lying on the circle.
1010  * @constructor
1011  * @name Circumcircle
1012  * @type array
1013  * @returns An array containing the midpoint in the first component and the circumcircle in the second component.
1014  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
1015  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined
1016  * by p1, p2, and p3.
1017  * @example
1018  * var p1 = board.create('point', [0.0, 2.0]);
1019  * var p2 = board.create('point', [2.0, 1.0]);
1020  * var p3 = board.create('point', [3.0, 3.0]);
1021  *
1022  * var cc1 = board.create('circumcircle', [p1, p2, p3]);
1023  * </pre><div id="e65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div>
1024  * <script type="text/javascript">
1025  *   var ccex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1026  *   var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]);
1027  *   var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]);
1028  *   var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]);
1029  *   var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]);
1030  * </script><pre>
1031  */
1032 JXG.createCircumcircle = function(board, parentArr, atts) {
1033     var p, c, cAtts, ret;
1034 
1035     cAtts = JXG.clone(atts);
1036     if(atts['name'] && JXG.isArray(atts['name'])) {
1037         cAtts['name'] = atts['name'][0];
1038         atts['name'] = atts['name'][1];
1039     }
1040     if(atts['id'] && JXG.isArray(atts['id'])) {
1041         cAtts['id'] = atts['id'][0];
1042         atts['id'] = atts['id'][1];
1043     }
1044 
1045     try {
1046         p = JXG.createCircumcircleMidpoint(board, parentArr, cAtts);
1047         c = JXG.createCircle(board, [p, parentArr[0]], atts);
1048     } catch(e) {
1049         throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1050                         (typeof parentArr[0]) + "', '" + (typeof parentArr[1]) + "' and '" + (typeof parentArr[2]) + "'." +
1051                         "\nPossible parent types: [point,point,point]");
1052     }
1053 
1054     ret = [p, c];
1055 
1056     ret.point = p;
1057     ret.circle = c;
1058 
1059     ret.multipleElements = true;
1060 
1061     return ret;
1062 };
1063 
1064 /**
1065  * @class Constructs two elements: a point and a circle. The circle is given by three points,
1066  * the point is the midpoint of the circle.
1067  * @pseudo
1068  * @description A incircle is given by three points.
1069  * @constructor
1070  * @name Incircle
1071  * @type array
1072  * @returns An array containing the midpoint in the first component and the incircle in the second component.
1073  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
1074  * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of
1075  * p1, p2, and p3.
1076  * @example
1077  * var p1 = board.create('point', [0.0, 2.0]);
1078  * var p2 = board.create('point', [2.0, 1.0]);
1079  * var p3 = board.create('point', [3.0, 3.0]);
1080  *
1081  * var ic1 = board.create('incircle', [p1, p2, p3]);
1082  * </pre><div id="e65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div>
1083  * <script type="text/javascript">
1084  *   var icex1_board = JXG.JSXGraph.initBoard('e65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1085  *   var icex1_p1 = icex1_board.create('point', [0.0, 2.0]);
1086  *   var icex1_p2 = icex1_board.create('point', [6.0, 1.0]);
1087  *   var icex1_p3 = icex1_board.create('point', [3.0, 7.0]);
1088  *   var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]);
1089  * </script><pre>
1090  */
1091 JXG.createIncircle = function(board, parents, atts) {
1092     var p, c, cAtts, ret;
1093 
1094     cAtts = JXG.clone(atts);
1095     if(atts['name'] && JXG.isArray(atts['name'])) {
1096         cAtts['name'] = atts['name'][0];
1097         atts['name'] = atts['name'][1];
1098     }
1099     if(atts['id'] && JXG.isArray(atts['id'])) {
1100         cAtts['id'] = atts['id'][0];
1101         atts['id'] = atts['id'][1];
1102     }
1103 
1104     try {
1105         p = JXG.createIncenter(board, parents, cAtts);
1106         c = JXG.createCircle(board, [p, function() {
1107             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())),
1108                 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())),
1109                 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())),
1110                 s = (a+b+c)/2;
1111 
1112             return Math.sqrt(((s-a)*(s-b)*(s-c))/s);
1113         }], atts);
1114     } catch(e) {
1115         throw new Error("JSXGraph: Can't create circumcircle with parent types '" +
1116                         (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." +
1117                         "\nPossible parent types: [point,point,point]");
1118     }
1119 
1120     ret = [p, c];
1121 
1122     ret.point = p;
1123     ret.circle = c;
1124 
1125     ret.multipleElements = true;
1126 
1127     return ret;
1128 };
1129 
1130 /**
1131  * @class This element is used to construct a reflected point.
1132  * @pseudo
1133  * @description A reflected point is given by a point and a line. It is determined by the reflection of the given point
1134  * against the given line.
1135  * @constructor
1136  * @name Reflection
1137  * @type JXG.Point
1138  * @augments JXG.Point
1139  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
1140  * @param {JXG.Point_JXG.Line} p,l The reflection point is the reflection of p against l.
1141  * @example
1142  * var p1 = board.create('point', [0.0, 4.0]);
1143  * var p2 = board.create('point', [6.0, 1.0]);
1144  * var l1 = board.create('line', [p1, p2]);
1145  * var p3 = board.create('point', [3.0, 3.0]);
1146  *
1147  * var rp1 = board.create('reflection', [p3, l1]);
1148  * </pre><div id="087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div>
1149  * <script type="text/javascript">
1150  *   var rpex1_board = JXG.JSXGraph.initBoard('087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1151  *   var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]);
1152  *   var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]);
1153  *   var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]);
1154  *   var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]);
1155  *   var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]);
1156  * </script><pre>
1157  */
1158 JXG.createReflection = function(board, parentArr, atts) {
1159     var l, p, r;
1160 
1161     if(parentArr[0].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[1].elementClass == JXG.OBJECT_CLASS_LINE) {
1162         p = parentArr[0];
1163         l = parentArr[1];
1164     }
1165     else if(parentArr[1].elementClass == JXG.OBJECT_CLASS_POINT && parentArr[0].elementClass == JXG.OBJECT_CLASS_LINE) {
1166         p = parentArr[1];
1167         l = parentArr[0];
1168     }
1169     else {
1170         throw new Error("JSXGraph: Can't create reflection point with parent types '" +
1171                         (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." +
1172                         "\nPossible parent types: [line,point]");
1173     }
1174 
1175     // force a fixed point
1176     //atts['fixed'] = true;
1177     r = JXG.createPoint(board, [function () { return JXG.Math.Geometry.reflection(l, p, board); }], atts);
1178     p.addChild(r);
1179     l.addChild(r);
1180 
1181     r.update();
1182 
1183     r.generatePolynomial = function() {
1184         /*
1185          *  Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.
1186          *  L is defined by two points A and B.
1187          *
1188          * So we have two conditions:
1189          *
1190          *   (a)   RP  _|_  AB            (orthogonality condition)
1191          *   (b)   AR  ==   AP            (distance condition)
1192          *
1193          */
1194 
1195         var a1 = l.point1.symbolic.x;
1196         var a2 = l.point1.symbolic.y;
1197         var b1 = l.point2.symbolic.x;
1198         var b2 = l.point2.symbolic.y;
1199         var p1 = p.symbolic.x;
1200         var p2 = p.symbolic.y;
1201         var r1 = r.symbolic.x;
1202         var r2 = r.symbolic.y;
1203 
1204         var poly1 = ['((',r2,')-(',p2,'))*((',a2,')-(',b2,'))+((',a1,')-(',b1,'))*((',r1,')-(',p1,'))'].join('');
1205         var poly2 = ['((',r1,')-(',a1,'))^2+((',r2,')-(',a2,'))^2-((',p1,')-(',a1,'))^2-((',p2,')-(',a2,'))^2'].join('');
1206 
1207         return [poly1, poly2];
1208     };
1209 
1210     return r;
1211 };
1212 
1213 // here we have to continue with replacing board.add* stuff
1214 
1215 /**
1216  * @class A mirror point will be constructed.
1217  * @pseudo
1218  * @description A mirror point is determined by the reflection of a given point against another given point.
1219  * @constructor
1220  * @name Mirrorpoint
1221  * @type JXG.Point
1222  * @augments JXG.Point
1223  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
1224  * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.
1225  * @example
1226  * var p1 = board.create('point', [3.0, 3.0]);
1227  * var p2 = board.create('point', [6.0, 1.0]);
1228  *
1229  * var mp1 = board.create('mirrorpoint', [p1, p2]);
1230  * </pre><div id="7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div>
1231  * <script type="text/javascript">
1232  *   var mpex1_board = JXG.JSXGraph.initBoard('7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
1233  *   var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);
1234  *   var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);
1235  *   var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);
1236  * </script><pre>
1237  */
1238 JXG.createMirrorPoint = function(board, parentArr, atts) {
1239     var p, i;
1240 
1241     /* TODO mirror polynomials */
1242     if(JXG.isPoint(parentArr[0]) && JXG.isPoint(parentArr[1])) {
1243         atts['fixed'] = atts['fixed'] || true;
1244         p = JXG.createPoint(board, [function () { return JXG.Math.Geometry.rotation(parentArr[0], parentArr[1], Math.PI, board); }], atts);
1245 
1246         for(i=0; i<2; i++)
1247             parentArr[i].addChild(p);
1248     }
1249     else {
1250         throw new Error("JSXGraph: Can't create mirror point with parent types '" +
1251                         (typeof parentArr[0]) + "' and '" + (typeof parentArr[1]) + "'." +
1252                         "\nPossible parent types: [point,point]");
1253     }
1254 
1255     p.update();
1256 
1257     return p;
1258 };
1259 
1260 /**
1261  * @class This element is used to visualize the integral of a given curve over a given interval.
1262  * @pseudo
1263  * @description The Integral element is used to visualize the area under a given curve over a given interval
1264  * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,
1265  * the gliders are used to change the interval dynamically.
1266  * @constructor
1267  * @name Integral
1268  * @type JXG.Polygon
1269  * @augments JXG.Polygon
1270  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
1271  * @param {array_JXG.Curve} p,l The constructed point is the orthogonal projection of p onto l.
1272  * @example
1273  * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);
1274  * var i1 = board.create('integral', [[-1.0, 4.0], c1]);
1275  * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
1276  * <script type="text/javascript">
1277  *   var intex1_board = JXG.JSXGraph.initBoard('d45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});
1278  *   var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return t*t*t; }]);
1279  *   var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);
1280  * </script><pre>
1281  */
1282 JXG.createIntegral = function(board, parents, attributes) {
1283     var interval, curve, attribs = {},
1284         start = 0, end = 0, startx, starty, endx, endy, factor = 1,
1285         pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,
1286         Int, t, p;
1287 
1288     if(!JXG.isArray(attributes['id']) || (attributes['id'].length != 5)) {
1289         attributes['id'] = ['','','','',''];
1290     }
1291     if(!JXG.isArray(attributes['name']) || (attributes['name'].length != 5)) {
1292        attributes['name'] = ['','','','',''];
1293     }
1294 
1295     if(JXG.isArray(parents[0]) && parents[1].elementClass == JXG.OBJECT_CLASS_CURVE) {
1296         interval = parents[0];
1297         curve = parents[1];
1298     } else if(JXG.isArray(parents[1]) && parents[0].elementClass == JXG.OBJECT_CLASS_CURVE) {
1299         interval = parents[1];
1300         curve = parents[0];
1301     } else {
1302         throw new Error("JSXGraph: Can't create integral with parent types '" +
1303                         (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
1304                         "\nPossible parent types: [[number|function,number|function],curve]");
1305     }
1306 
1307     if( (typeof attributes != 'undefined') && (attributes != null))
1308         attribs = JXG.cloneAndCopy(attributes, {name: attributes.name[0], id: attributes.id[0]});
1309 
1310     // Correct the interval if necessary - NOT ANYMORE, GGB's fault
1311     start = interval[0];
1312     end = interval[1];
1313 
1314     if(JXG.isFunction(start)) {
1315         startx = start;
1316         starty = function () { return curve.yterm(startx()); };
1317         start = startx();
1318     } else {
1319         startx = start;
1320         starty = curve.yterm(start);
1321     }
1322 
1323     if(JXG.isFunction(start)) {
1324         endx = end;
1325         endy = function () { return curve.yterm(endx()); };
1326         end = endx();
1327     } else {
1328         endx = end;
1329         endy = curve.yterm(end);
1330     }
1331 
1332     if(end < start)
1333         factor = -1;
1334 
1335     pa_on_curve = board.create('glider', [startx, starty, curve], attribs);
1336     if(JXG.isFunction(startx))
1337         pa_on_curve.hideElement();
1338 
1339     attribs.name = attributes.name[1];
1340     attribs.id = attributes.id[1];
1341     attribs.visible = false;
1342     pa_on_axis = board.create('point', [function () { return pa_on_curve.X(); }, 0], attribs);
1343 
1344     //pa_on_curve.addChild(pa_on_axis);
1345 
1346     attribs.name = attributes.name[2];
1347     attribs.id = attributes.id[2];
1348     attribs.visible = attributes.visible || true;
1349     pb_on_curve = board.create('glider', [endx, endy, curve], attribs);
1350     if(JXG.isFunction(endx))
1351         pb_on_curve.hideElement();
1352 
1353     attribs.name = attributes.name[3];
1354     attribs.id = attributes.id[3];
1355     attribs.visible = false;
1356     pb_on_axis = board.create('point', [function () { return pb_on_curve.X(); }, 0], attribs);
1357 
1358     //pb_on_curve.addChild(pb_on_axis);
1359 
1360     Int = JXG.Math.Numerics.I([start, end], curve.yterm);
1361     t = board.create('text', [
1362         function () { return pb_on_curve.X() + 0.2; },
1363         function () { return pb_on_curve.Y() - 0.8; },
1364         function () {
1365                 var Int = JXG.Math.Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.yterm);
1366                 return '∫ = ' + (Int).toFixed(4);
1367             }
1368         ],{labelColor: attributes['labelColor']});
1369 
1370     attribs.name = attributes.name[4];
1371     attribs.id = attributes.id[4];
1372     attribs.visible = attributes.visible || true;
1373     attribs.fillColor = attribs.fillColor || board.options.polygon.fillColor;
1374     attribs.highlightFillColor = attribs.highlightFillColor || board.options.polygon.highlightFillColor;
1375     attribs.fillOpacity = attribs.fillOpacity || board.options.polygon.fillOpacity;
1376     attribs.highlightFillOpacity = attribs.highlightFillOpacity || board.options.polygon.highlightFillOpacity;
1377     attribs.strokeWidth = 0;
1378     attribs.highlightStrokeWidth = 0;
1379     attribs.strokeOpacity = 0;
1380 
1381     p = board.create('curve', [[0],[0]], attribs);
1382     p.updateDataArray = function() {
1383         var x, y,
1384             i, left, right;
1385 
1386         if(pa_on_axis.X() < pb_on_axis.X()) {
1387             left = pa_on_axis.X();
1388             right = pb_on_axis.X();
1389         } else {
1390             left = pb_on_axis.X();
1391             right = pa_on_axis.X();
1392         }
1393 
1394         x = [left, left];
1395         y = [0, curve.yterm(left)];
1396 
1397         for(i=0; i < curve.numberPoints; i++) {
1398             if( (left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right) ) {
1399                 x.push(curve.points[i].usrCoords[1]);
1400                 y.push(curve.points[i].usrCoords[2]);
1401             }
1402         }
1403         x.push(right);
1404         y.push(curve.yterm(right));
1405         x.push(right);
1406         y.push(0);
1407 
1408         x.push(left); // close the curve
1409         y.push(0);
1410 
1411         this.dataX = x;
1412         this.dataY = y;
1413     };
1414     pa_on_curve.addChild(p);
1415     pb_on_curve.addChild(p);
1416     pa_on_curve.addChild(t);
1417     pb_on_curve.addChild(t);
1418 
1419     return p;//[pa_on_axis, pb_on_axis, p, t];
1420 
1421 };
1422 
1423 /**
1424  * @class This element is used to visualize the locus of a given dependent point.
1425  * @pseudo
1426  * @description The locus element is used to visualize the curve a given point describes.
1427  * @constructor
1428  * @name Locus
1429  * @type JXG.Curve
1430  * @augments JXG.Curve
1431  * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
1432  * @param {JXG.Point} p The constructed curve is the geometric locus of the given point.
1433  * @example
1434  *  // This examples needs JXG.Server up and running, otherwise it won't work.
1435  *  p1 = board.create('point', [0, 0]);
1436  *  p2 = board.create('point', [6, -1]);
1437  *  c1 = board.create('circle', [p1, 2]);
1438  *  c2 = board.create('circle', [p2, 1.5]);
1439  *  g1 = board.create('glider', [6, 3, c1]);
1440  *  c3 = board.create('circle', [g1, 4]);
1441  *  g2 = board.create('intersection', [c2,c3,0]);
1442  *  m1 = board.create('midpoint', [g1,g2]);
1443  *  loc = board.create('locus', [m1], {strokeColor: 'red'});
1444  * </pre><div id="d45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div>
1445  * <script type="text/javascript">
1446  *  lcex_board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true});
1447  *  lcex_p1 = lcex_board.create('point', [0, 0]);
1448  *  lcex_p2 = lcex_board.create('point', [6, -1]);
1449  *  lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]);
1450  *  lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]);
1451  *  lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]);
1452  *  lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]);
1453  *  lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]);
1454  *  lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]);
1455  *  lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'});
1456  * </script><pre>
1457  */
1458 JXG.createLocus = function(board, parents, attributes) {
1459     var c, p;
1460 
1461     if(JXG.isArray(parents) && parents.length == 1 && parents[0].elementClass == JXG.OBJECT_CLASS_POINT) {
1462         p = parents[0];
1463     } else {
1464         throw new Error("JSXGraph: Can't create locus with parent of type other than point." +
1465                         "\nPossible parent types: [point]");
1466     }
1467 
1468     c = board.create('curve', [[null], [null]], attributes);
1469     c.dontCallServer = false;
1470 
1471     c.updateDataArray = function () {
1472         if(c.board.mode > 0)
1473             return;
1474 
1475         var spe = JXG.Math.Symbolic.generatePolynomials(board, p, true).join('');
1476         if(spe === c.spe)
1477                 return;
1478 
1479         c.spe = spe;
1480 
1481         var cb = function(x, y, eq, t) {
1482                 c.dataX = x;
1483                 c.dataY = y;
1484                 c.eq = eq;
1485                 c.ctime = t;
1486 
1487                 // convert equation and use it to build a generatePolynomial-method
1488                 c.generatePolynomial = (function(equations) {
1489                     return function(point) {
1490                         var x = '(' + point.symbolic.x + ')',
1491                             y = '(' + point.symbolic.y + ')',
1492                             res = [], i;
1493 
1494                         for(i=0; i<equations.length; i++)
1495                             res[i] = equations[i].replace(/\*\*/g, '^').replace(/x/g, x).replace(/y/g, y);
1496 
1497                         return res;
1498                     }
1499                 })(eq);
1500             },
1501             data = JXG.Math.Symbolic.geometricLocusByGroebnerBase(board, p, cb);
1502 
1503         cb(data.datax, data.datay, data.polynomial, data.exectime);
1504     };
1505     return c;
1506 };
1507 
1508 JXG.JSXGraph.registerElement('arrowparallel', JXG.createArrowParallel);
1509 JXG.JSXGraph.registerElement('bisector', JXG.createBisector);
1510 JXG.JSXGraph.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);
1511 JXG.JSXGraph.registerElement('circumcircle', JXG.createCircumcircle);
1512 JXG.JSXGraph.registerElement('circumcirclemidpoint', JXG.createCircumcircleMidpoint);
1513 JXG.JSXGraph.registerElement('circumcenter', JXG.createCircumcircleMidpoint);
1514 JXG.JSXGraph.registerElement('incenter', JXG.createIncenter);
1515 JXG.JSXGraph.registerElement('incircle', JXG.createIncircle);
1516 JXG.JSXGraph.registerElement('integral', JXG.createIntegral);
1517 JXG.JSXGraph.registerElement('midpoint', JXG.createMidpoint);
1518 JXG.JSXGraph.registerElement('mirrorpoint', JXG.createMirrorPoint);
1519 JXG.JSXGraph.registerElement('normal', JXG.createNormal);
1520 JXG.JSXGraph.registerElement('parallel', JXG.createParallel);
1521 JXG.JSXGraph.registerElement('parallelpoint', JXG.createParallelPoint);
1522 JXG.JSXGraph.registerElement('perpendicular', JXG.createPerpendicular);
1523 JXG.JSXGraph.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);
1524 JXG.JSXGraph.registerElement('reflection', JXG.createReflection);
1525 JXG.JSXGraph.registerElement('locus', JXG.createLocus);
1526