1 /*
  2     Copyright 2008-2015
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 13 
 14     You can redistribute it and/or modify it under the terms of the
 15 
 16       * GNU Lesser General Public License as published by
 17         the Free Software Foundation, either version 3 of the License, or
 18         (at your option) any later version
 19       OR
 20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 21 
 22     JSXGraph is distributed in the hope that it will be useful,
 23     but WITHOUT ANY WARRANTY; without even the implied warranty of
 24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25     GNU Lesser General Public License for more details.
 26 
 27     You should have received a copy of the GNU Lesser General Public License and
 28     the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
 29     and <http://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 
 33 /*global JXG: true, define: true, console: true, window: true*/
 34 /*jslint nomen: true, plusplus: true*/
 35 
 36 /* depends:
 37  jxg
 38  options
 39  math/math
 40  math/geometry
 41  math/numerics
 42  base/coords
 43  base/constants
 44  base/element
 45  parser/geonext
 46  utils/type
 47   elements:
 48    transform
 49  */
 50 
 51 /**
 52  * @fileoverview The geometry object Point is defined in this file. Point stores all
 53  * style and functional properties that are required to draw and move a point on
 54  * a board.
 55  */
 56 
 57 define([
 58     'jxg', 'options', 'math/math', 'math/geometry', 'math/numerics', 'base/coords', 'base/constants', 'base/element',
 59     'parser/geonext', 'utils/type', 'base/transformation', 'base/coordselement'
 60 ], function (JXG, Options, Mat, Geometry, Numerics, Coords, Const, GeometryElement, GeonextParser, Type, Transform, CoordsElement) {
 61 
 62     "use strict";
 63 
 64     /**
 65      * A point is the basic geometric element. Based on points lines and circles can be constructed which can be intersected
 66      * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for
 67      * all kind of points like free points, gliders, and intersection points.
 68      * @class Creates a new point object. Do not use this constructor to create a point. Use {@link JXG.Board#create} with
 69      * type {@link Point}, {@link Glider}, or {@link Intersection} instead.
 70      * @augments JXG.GeometryElement
 71      * @augments JXG.CoordsElement
 72      * @param {string|JXG.Board} board The board the new point is drawn on.
 73      * @param {Array} coordinates An array with the user coordinates of the point.
 74      * @param {Object} attributes An object containing visual properties like in {@link JXG.Options#point} and
 75      * {@link JXG.Options#elements}, and optional a name and an id.
 76      * @see JXG.Board#generateName
 77      */
 78     JXG.Point = function (board, coordinates, attributes) {
 79         this.constructor(board, attributes, Const.OBJECT_TYPE_POINT, Const.OBJECT_CLASS_POINT);
 80         this.element = this.board.select(attributes.anchor);
 81         this.coordsConstructor(coordinates);
 82 
 83         this.elType = 'point';
 84 
 85         /* Register point at board. */
 86         this.id = this.board.setId(this, 'P');
 87         this.board.renderer.drawPoint(this);
 88         this.board.finalizeAdding(this);
 89 
 90         this.createLabel();
 91     };
 92 
 93     /**
 94      * Inherits here from {@link JXG.GeometryElement}.
 95      */
 96     JXG.Point.prototype = new GeometryElement();
 97     Type.copyPrototypeMethods(JXG.Point, CoordsElement, 'coordsConstructor');
 98 
 99     JXG.extend(JXG.Point.prototype, /** @lends JXG.Point.prototype */ {
100         /**
101          * Checks whether (x,y) is near the point.
102          * @param {Number} x Coordinate in x direction, screen coordinates.
103          * @param {Number} y Coordinate in y direction, screen coordinates.
104          * @returns {Boolean} True if (x,y) is near the point, False otherwise.
105          * @private
106          */
107         hasPoint: function (x, y) {
108             var coordsScr = this.coords.scrCoords, r;
109             r = parseFloat(this.visProp.size) + parseFloat(this.visProp.strokewidth) * 0.5;
110             if (r < this.board.options.precision.hasPoint) {
111                 r = this.board.options.precision.hasPoint;
112             }
113 
114             return ((Math.abs(coordsScr[1] - x) < r + 2) && (Math.abs(coordsScr[2] - y) < r + 2));
115         },
116 
117         /**
118          * Updates the position of the point.
119          */
120         update: function (fromParent) {
121             if (!this.needsUpdate) {
122                 return this;
123             }
124 
125             this.updateCoords(fromParent);
126 
127             if (this.visProp.trace) {
128                 this.cloneToBackground(true);
129             }
130 
131             return this;
132         },
133 
134         /**
135          * Applies the transformations of the element to {@link JXG.Point#baseElement}.
136          * Point transformations are relative to a base element.
137          * @returns {JXG.CoordsElement} Reference to this object.
138          */
139         updateTransform: function () {
140             var c, i;
141 
142             if (this.transformations.length === 0 || this.baseElement === null) {
143                 return this;
144             }
145 
146             // case of bindTo
147             if (this === this.baseElement) {
148                 c = this.transformations[0].apply(this.baseElement, 'self');
149             // case of board.create('point',[baseElement,transform]);
150             } else {
151                 c = this.transformations[0].apply(this.baseElement);
152             }
153 
154             this.coords.setCoordinates(Const.COORDS_BY_USER, c);
155 
156             for (i = 1; i < this.transformations.length; i++) {
157                 this.coords.setCoordinates(Const.COORDS_BY_USER, this.transformations[i].apply(this));
158             }
159             return this;
160         },
161 
162         /**
163          * Calls the renderer to update the drawing.
164          * @private
165          */
166         updateRenderer: function () {
167             if (this.visProp.size > 0) {
168                 this.updateRendererGeneric('updatePoint');
169             }
170             return this;
171         },
172 
173         // documented in JXG.GeometryElement
174         bounds: function () {
175             return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1));
176         },
177 
178         /**
179          * Convert the point to intersection point and update the construction.
180          * To move the point visual onto the intersection, a call of board update is necessary.
181          * TODO docu.
182          * @param {String|Object} el1, el2, i, j The intersecting objects and the numbers.
183          **/
184         makeIntersection: function (el1, el2, i, j) {
185             var func;
186 
187             el1 = this.board.select(el1);
188             el2 = this.board.select(el2);
189 
190             func = Geometry.intersectionFunction(this.board, el1, el2, i, j, this.visProp.alwaysintersect);
191             this.addConstraint([func]);
192 
193             try {
194                 el1.addChild(this);
195                 el2.addChild(this);
196             } catch (e) {
197                 throw new Error("JSXGraph: Can't create 'intersection' with parent types '" +
198                     (typeof el1) + "' and '" + (typeof el2) + "'.");
199             }
200 
201             this.type = Const.OBJECT_TYPE_INTERSECTION;
202             this.elType = 'intersection';
203             this.parents = [el1.id, el2.id, i, j];
204 
205             this.generatePolynomial = function () {
206                 var poly1 = el1.generatePolynomial(this),
207                     poly2 = el2.generatePolynomial(this);
208 
209                 if ((poly1.length === 0) || (poly2.length === 0)) {
210                     return [];
211                 }
212 
213                 return [poly1[0], poly2[0]];
214             };
215 
216             this.prepareUpdate().update();
217         },
218 
219         /**
220          * Set the style of a point. 
221          * Used for GEONExT import and should not be used to set the point's face and size.
222          * @param {Number} i Integer to determine the style.
223          * @private
224          */
225         setStyle: function (i) {
226             var facemap = [
227                 // 0-2
228                 'cross', 'cross', 'cross',
229                 // 3-6
230                 'circle', 'circle', 'circle', 'circle',
231                 // 7-9
232                 'square', 'square', 'square',
233                 // 10-12
234                 'plus', 'plus', 'plus'
235             ], sizemap = [
236                 // 0-2
237                 2, 3, 4,
238                 // 3-6
239                 1, 2, 3, 4,
240                 // 7-9
241                 2, 3, 4,
242                 // 10-12
243                 2, 3, 4
244             ];
245 
246             this.visProp.face = facemap[i];
247             this.visProp.size = sizemap[i];
248 
249             this.board.renderer.changePointStyle(this);
250             return this;
251         },
252 
253         /**
254          * @deprecated Use JXG#normalizePointFace instead
255          * @param s
256          * @return {*}
257          */
258         normalizeFace: function (s) {
259             return Options.normalizePointFace(s);
260         },
261 
262         /**
263          * Set the face of a point element.
264          * @param {String} f String which determines the face of the point. See {@link JXG.GeometryElement#face} for a list of available faces.
265          * @see JXG.GeometryElement#face
266          * @deprecated Use setAttribute()
267          */
268         face: function (f) {
269             this.setAttribute({face: f});
270         },
271 
272         /**
273          * Set the size of a point element
274          * @param {Number} s Integer which determines the size of the point.
275          * @see JXG.GeometryElement#size
276          * @deprecated Use setAttribute()
277          */
278         size: function (s) {
279             this.setAttribute({size: s});
280         },
281 
282         // already documented in GeometryElement
283         cloneToBackground: function () {
284             var copy = {};
285 
286             copy.id = this.id + 'T' + this.numTraces;
287             this.numTraces += 1;
288 
289             copy.coords = this.coords;
290             copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true);
291             copy.visProp.layer = this.board.options.layer.trace;
292             copy.elementClass = Const.OBJECT_CLASS_POINT;
293             copy.board = this.board;
294             Type.clearVisPropOld(copy);
295 
296             this.board.renderer.drawPoint(copy);
297             this.traces[copy.id] = copy.rendNode;
298 
299             return this;
300         }
301 
302     });
303 
304 
305     /**
306      * @class This element is used to provide a constructor for a general point. A free point is created if the given parent elements are all numbers
307      * and the property fixed is not set or set to false. If one or more parent elements is not a number but a string containing a GEONE<sub>x</sub>T
308      * constraint or a function the point will be considered as constrained). That means that the user won't be able to change the point's
309      * position directly.
310      * @pseudo
311      * @description
312      * @name Point
313      * @augments JXG.Point
314      * @constructor
315      * @type JXG.Point
316      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
317      * @param {Number,string,function_Number,string,function_Number,string,function} z_,x,y Parent elements can be two or three elements of type number, a string containing a GEONE<sub>x</sub>T
318      * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is
319      * given by a number, the number determines the initial position of a free point. If given by a string or a function that coordinate will be constrained
320      * that means the user won't be able to change the point's position directly by mouse because it will be calculated automatically depending on the string
321      * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such
322      * parent elements are given they will be interpreted as homogeneous coordinates.
323      * @param {JXG.Point_JXG.Transformation} Point,Transformation A point can also be created providing a transformation. The resulting point is a clone of the base
324      * point transformed by the given Transformation. {@see JXG.Transformation}.
325      * @example
326      * // Create a free point using affine euclidean coordinates
327      * var p1 = board.create('point', [3.5, 2.0]);
328      * </pre><div id="672f1764-7dfa-4abc-a2c6-81fbbf83e44b" style="width: 200px; height: 200px;"></div>
329      * <script type="text/javascript">
330      *   var board = JXG.JSXGraph.initBoard('672f1764-7dfa-4abc-a2c6-81fbbf83e44b', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
331      *   var p1 = board.create('point', [3.5, 2.0]);
332      * </script><pre>
333      * @example
334      * // Create a constrained point using anonymous function
335      * var p2 = board.create('point', [3.5, function () { return p1.X(); }]);
336      * </pre><div id="4fd4410c-3383-4e80-b1bb-961f5eeef224" style="width: 200px; height: 200px;"></div>
337      * <script type="text/javascript">
338      *   var fpex1_board = JXG.JSXGraph.initBoard('4fd4410c-3383-4e80-b1bb-961f5eeef224', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
339      *   var fpex1_p1 = fpex1_board.create('point', [3.5, 2.0]);
340      *   var fpex1_p2 = fpex1_board.create('point', [3.5, function () { return fpex1_p1.X(); }]);
341      * </script><pre>
342      * @example
343      * // Create a point using transformations
344      * var trans = board.create('transform', [2, 0.5], {type:'scale'});
345      * var p3 = board.create('point', [p2, trans]);
346      * </pre><div id="630afdf3-0a64-46e0-8a44-f51bd197bb8d" style="width: 400px; height: 400px;"></div>
347      * <script type="text/javascript">
348      *   var fpex2_board = JXG.JSXGraph.initBoard('630afdf3-0a64-46e0-8a44-f51bd197bb8d', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
349      *   var fpex2_trans = fpex2_board.create('transform', [2, 0.5], {type:'scale'});
350      *   var fpex2_p2 = fpex2_board.create('point', [3.5, 2.0]);
351      *   var fpex2_p3 = fpex2_board.create('point', [fpex2_p2, fpex2_trans]);
352      * </script><pre>
353      */
354     JXG.createPoint = function (board, parents, attributes) {
355         var el, attr;
356 
357         attr = Type.copyAttributes(attributes, board.options, 'point');
358         el = CoordsElement.create(JXG.Point, board, parents, attr);
359         if (!el) {
360             throw new Error("JSXGraph: Can't create point with parent types '" +
361                     (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
362                     "\nPossible parent types: [x,y], [z,x,y], [element,transformation]");
363         }
364 
365         return el;
366     };
367 
368     /**
369      * @class This element is used to provide a constructor for a glider point.
370      * @pseudo
371      * @description A glider is a point which lives on another geometric element like a line, circle, curve, turtle.
372      * @name Glider
373      * @augments JXG.Point
374      * @constructor
375      * @type JXG.Point
376      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
377      * @param {Number_Number_Number_JXG.GeometryElement} z_,x_,y_,GlideObject Parent elements can be two or three elements of type number and the object the glider lives on.
378      * The coordinates are completely optional. If not given the origin is used. If you provide two numbers for coordinates they will be interpreted as affine euclidean
379      * coordinates, otherwise they will be interpreted as homogeneous coordinates. In any case the point will be projected on the glide object.
380      * @example
381      * // Create a glider with user defined coordinates. If the coordinates are not on
382      * // the circle (like in this case) the point will be projected onto the circle.
383      * var p1 = board.create('point', [2.0, 2.0]);
384      * var c1 = board.create('circle', [p1, 2.0]);
385      * var p2 = board.create('glider', [2.0, 1.5, c1]);
386      * </pre><div id="4f65f32f-e50a-4b50-9b7c-f6ec41652930" style="width: 300px; height: 300px;"></div>
387      * <script type="text/javascript">
388      *   var gpex1_board = JXG.JSXGraph.initBoard('4f65f32f-e50a-4b50-9b7c-f6ec41652930', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
389      *   var gpex1_p1 = gpex1_board.create('point', [2.0, 2.0]);
390      *   var gpex1_c1 = gpex1_board.create('circle', [gpex1_p1, 2.0]);
391      *   var gpex1_p2 = gpex1_board.create('glider', [2.0, 1.5, gpex1_c1]);
392      * </script><pre>
393      * @example
394      * // Create a glider with default coordinates (1,0,0). Same premises as above.
395      * var p1 = board.create('point', [2.0, 2.0]);
396      * var c1 = board.create('circle', [p1, 2.0]);
397      * var p2 = board.create('glider', [c1]);
398      * </pre><div id="4de7f181-631a-44b1-a12f-bc4d995609e8" style="width: 200px; height: 200px;"></div>
399      * <script type="text/javascript">
400      *   var gpex2_board = JXG.JSXGraph.initBoard('4de7f181-631a-44b1-a12f-bc4d995609e8', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
401      *   var gpex2_p1 = gpex2_board.create('point', [2.0, 2.0]);
402      *   var gpex2_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]);
403      *   var gpex2_p2 = gpex2_board.create('glider', [gpex2_c1]);
404      * </script><pre>
405      */
406     JXG.createGlider = function (board, parents, attributes) {
407         var el, coords,
408             attr = Type.copyAttributes(attributes, board.options, 'glider');
409 
410         if (parents.length === 1) {
411             coords = [0, 0];
412         } else {
413             coords = parents.slice(0, 2);
414         }
415         el = board.create('point', coords, attr);
416 
417         // eltype is set in here
418         el.makeGlider(parents[parents.length - 1]);
419 
420         return el;
421     };
422 
423 
424     /**
425      * @class This element is used to provide a constructor for an intersection point.
426      * @pseudo
427      * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e.
428      * an intersection point of the two elements.
429      * @name Intersection
430      * @augments JXG.Point
431      * @constructor
432      * @type JXG.Point
433      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
434      * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2. i determines the
435      * intersection point if two points are available: <ul>
436      *   <li>i==0: use the positive square root,</li>
437      *   <li>i==1: use the negative square root.</li></ul>
438      * @example
439      * // Create an intersection point of circle and line
440      * var p1 = board.create('point', [2.0, 2.0]);
441      * var c1 = board.create('circle', [p1, 2.0]);
442      *
443      * var p2 = board.create('point', [2.0, 2.0]);
444      * var p3 = board.create('point', [2.0, 2.0]);
445      * var l1 = board.create('line', [p2, p3]);
446      *
447      * var i = board.create('intersection', [c1, l1, 0]);
448      * </pre><div id="e5b0e190-5200-4bc3-b995-b6cc53dc5dc0" style="width: 300px; height: 300px;"></div>
449      * <script type="text/javascript">
450      *   var ipex1_board = JXG.JSXGraph.initBoard('e5b0e190-5200-4bc3-b995-b6cc53dc5dc0', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
451      *   var ipex1_p1 = ipex1_board.create('point', [4.0, 4.0]);
452      *   var ipex1_c1 = ipex1_board.create('circle', [ipex1_p1, 2.0]);
453      *   var ipex1_p2 = ipex1_board.create('point', [1.0, 1.0]);
454      *   var ipex1_p3 = ipex1_board.create('point', [5.0, 3.0]);
455      *   var ipex1_l1 = ipex1_board.create('line', [ipex1_p2, ipex1_p3]);
456      *   var ipex1_i = ipex1_board.create('intersection', [ipex1_c1, ipex1_l1, 0]);
457      * </script><pre>
458      */
459     JXG.createIntersectionPoint = function (board, parents, attributes) {
460         var el, el1, el2, func, i, j,
461             attr = Type.copyAttributes(attributes, board.options, 'intersection');
462 
463         // make sure we definitely have the indices
464         parents.push(0, 0);
465 
466         el1 = board.select(parents[0]);
467         el2 = board.select(parents[1]);
468 
469         i = parents[2] || 0;
470         j = parents[3] || 0;
471 
472         el = board.create('point', [0, 0, 0], attr);
473 
474         func = Geometry.intersectionFunction(board, el1, el2, i, j, el.visProp.alwaysintersect);
475         el.addConstraint([func]);
476 
477         try {
478             el1.addChild(el);
479             el2.addChild(el);
480         } catch (e) {
481             throw new Error("JSXGraph: Can't create 'intersection' with parent types '" +
482                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'.");
483         }
484 
485         el.type = Const.OBJECT_TYPE_INTERSECTION;
486         el.elType = 'intersection';
487         el.parents = [el1.id, el2.id, i, j];
488 
489         el.generatePolynomial = function () {
490             var poly1 = el1.generatePolynomial(el),
491                 poly2 = el2.generatePolynomial(el);
492 
493             if ((poly1.length === 0) || (poly2.length === 0)) {
494                 return [];
495             }
496 
497             return [poly1[0], poly2[0]];
498         };
499 
500         return el;
501     };
502 
503     /**
504      * @class This element is used to provide a constructor for the "other" intersection point.
505      * @pseudo
506      * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e.
507      * an intersection point of the two elements. Additionally, one intersection point is provided. The function returns the other intersection point.
508      * @name OtherIntersection
509      * @augments JXG.Point
510      * @constructor
511      * @type JXG.Point
512      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
513      * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_JXG.Point} el1,el2,p The result will be a intersection point on el1 and el2. i determines the
514      * intersection point different from p:
515      * @example
516      * // Create an intersection point of circle and line
517      * var p1 = board.create('point', [2.0, 2.0]);
518      * var c1 = board.create('circle', [p1, 2.0]);
519      *
520      * var p2 = board.create('point', [2.0, 2.0]);
521      * var p3 = board.create('point', [2.0, 2.0]);
522      * var l1 = board.create('line', [p2, p3]);
523      *
524      * var i = board.create('intersection', [c1, l1, 0]);
525      * var j = board.create('otherintersection', [c1, l1, i]);
526      * </pre><div id="45e25f12-a1de-4257-a466-27a2ae73614c" style="width: 300px; height: 300px;"></div>
527      * <script type="text/javascript">
528      *   var ipex2_board = JXG.JSXGraph.initBoard('45e25f12-a1de-4257-a466-27a2ae73614c', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
529      *   var ipex2_p1 = ipex2_board.create('point', [4.0, 4.0]);
530      *   var ipex2_c1 = ipex2_board.create('circle', [ipex2_p1, 2.0]);
531      *   var ipex2_p2 = ipex2_board.create('point', [1.0, 1.0]);
532      *   var ipex2_p3 = ipex2_board.create('point', [5.0, 3.0]);
533      *   var ipex2_l1 = ipex2_board.create('line', [ipex2_p2, ipex2_p3]);
534      *   var ipex2_i = ipex2_board.create('intersection', [ipex2_c1, ipex2_l1, 0], {name:'D'});
535      *   var ipex2_j = ipex2_board.create('otherintersection', [ipex2_c1, ipex2_l1, ipex2_i], {name:'E'});
536      * </script><pre>
537      */
538     JXG.createOtherIntersectionPoint = function (board, parents, attributes) {
539         var el, el1, el2, other;
540 
541         if (parents.length !== 3 ||
542                 !Type.isPoint(parents[2]) ||
543                 (parents[0].elementClass !== Const.OBJECT_CLASS_LINE && parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE) ||
544                 (parents[1].elementClass !== Const.OBJECT_CLASS_LINE && parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE)) {
545             // Failure
546             throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '" +
547                 (typeof parents[0]) + "',  '" + (typeof parents[1]) + "'and  '" + (typeof parents[2]) + "'." +
548                 "\nPossible parent types: [circle|line,circle|line,point]");
549         }
550 
551         el1 = board.select(parents[0]);
552         el2 = board.select(parents[1]);
553         other = board.select(parents[2]);
554 
555         el = board.create('point', [function () {
556             var c = Geometry.meet(el1.stdform, el2.stdform, 0, el1.board);
557 
558             if (Math.abs(other.X() - c.usrCoords[1]) > Mat.eps ||
559                     Math.abs(other.Y() - c.usrCoords[2]) > Mat.eps ||
560                     Math.abs(other.Z() - c.usrCoords[0]) > Mat.eps) {
561                 return c;
562             }
563 
564             return Geometry.meet(el1.stdform, el2.stdform, 1, el1.board);
565         }], attributes);
566 
567         el.type = Const.OBJECT_TYPE_INTERSECTION;
568         el.elType = 'otherintersection';
569         el.parents = [el1.id, el2.id, other];
570 
571         el1.addChild(el);
572         el2.addChild(el);
573 
574         el.generatePolynomial = function () {
575             var poly1 = el1.generatePolynomial(el),
576                 poly2 = el2.generatePolynomial(el);
577 
578             if ((poly1.length === 0) || (poly2.length === 0)) {
579                 return [];
580             }
581 
582             return [poly1[0], poly2[0]];
583         };
584 
585         return el;
586     };
587 
588     /**
589      * @class This element is used to provide a constructor for the pole point of a line with respect to a conic or a circle.
590      * @pseudo
591      * @description The pole point is the unique reciprocal relationship of a line with respect to a conic.
592      * The lines tangent to the intersections of a conic and a line intersect at the pole point of that line with respect to that conic.
593      * A line tangent to a conic has the pole point of that line with respect to that conic as the tangent point.
594      * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar.
595      * @name PolePoint
596      * @augments JXG.Point
597      * @constructor
598      * @type JXG.Point
599      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
600      * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or
601      * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the pole point of the line with respect to the conic or the circle.
602      * @example
603      * // Create the pole point of a line with respect to a conic
604      * var p1 = board.create('point', [-1, 2]);
605      * var p2 = board.create('point', [ 1, 4]);
606      * var p3 = board.create('point', [-1,-2]);
607      * var p4 = board.create('point', [ 0, 0]);
608      * var p5 = board.create('point', [ 4,-2]);
609      * var c1 = board.create('conic',[p1,p2,p3,p4,p5]);
610      * var p6 = board.create('point', [-1, 4]);
611      * var p7 = board.create('point', [2, -2]);
612      * var l1 = board.create('line', [p6, p7]);
613      * var p8 = board.create('polepoint', [c1, l1]);
614      * </pre><div id='7b7233a0-f363-47dd-9df5-8018d0d17a98' class='jxgbox' style='width:400px; height:400px;'></div>
615      * <script type='text/javascript'>
616      * var ppex1_board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-8018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false});
617      * var ppex1_p1 = ppex1_board.create('point', [-1, 2]);
618      * var ppex1_p2 = ppex1_board.create('point', [ 1, 4]);
619      * var ppex1_p3 = ppex1_board.create('point', [-1,-2]);
620      * var ppex1_p4 = ppex1_board.create('point', [ 0, 0]);
621      * var ppex1_p5 = ppex1_board.create('point', [ 4,-2]);
622      * var ppex1_c1 = ppex1_board.create('conic',[ppex1_p1,ppex1_p2,ppex1_p3,ppex1_p4,ppex1_p5]);
623      * var ppex1_p6 = ppex1_board.create('point', [-1, 4]);
624      * var ppex1_p7 = ppex1_board.create('point', [2, -2]);
625      * var ppex1_l1 = ppex1_board.create('line', [ppex1_p6, ppex1_p7]);
626      * var ppex1_p8 = ppex1_board.create('polepoint', [ppex1_c1, ppex1_l1]);
627      * </script><pre>
628      * @example
629      * // Create the pole point of a line with respect to a circle
630      * var p1 = board.create('point', [1, 1]);
631      * var p2 = board.create('point', [2, 3]);
632      * var c1 = board.create('circle',[p1,p2]);
633      * var p3 = board.create('point', [-1, 4]);
634      * var p4 = board.create('point', [4, -1]);
635      * var l1 = board.create('line', [p3, p4]);
636      * var p5 = board.create('polepoint', [c1, l1]);
637      * </pre><div id='7b7233a0-f363-47dd-9df5-9018d0d17a98' class='jxgbox' style='width:400px; height:400px;'></div>
638      * <script type='text/javascript'>
639      * var ppex2_board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-9018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false});
640      * var ppex2_p1 = ppex2_board.create('point', [1, 1]);
641      * var ppex2_p2 = ppex2_board.create('point', [2, 3]);
642      * var ppex2_c1 = ppex2_board.create('circle',[ppex2_p1,ppex2_p2]);
643      * var ppex2_p3 = ppex2_board.create('point', [-1, 4]);
644      * var ppex2_p4 = ppex2_board.create('point', [4, -1]);
645      * var ppex2_l1 = ppex2_board.create('line', [ppex2_p3, ppex2_p4]);
646      * var ppex2_p5 = ppex2_board.create('polepoint', [ppex2_c1, ppex2_l1]);
647      * </script><pre>
648      */
649     JXG.createPolePoint = function (board, parents, attributes) {
650         var el, el1, el2,
651             firstParentIsConic, secondParentIsConic,
652             firstParentIsLine, secondParentIsLine;
653 
654         if (parents.length > 1) {
655             firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC ||
656                 parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE);
657             secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC ||
658                 parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE);
659 
660             firstParentIsLine = (parents[0].elementClass === Const.OBJECT_CLASS_LINE);
661             secondParentIsLine = (parents[1].elementClass === Const.OBJECT_CLASS_LINE);
662         }
663 
664 /*        if (parents.length !== 2 || !((
665                 parents[0].type === Const.OBJECT_TYPE_CONIC ||
666                 parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) &&
667                 parents[1].elementClass === Const.OBJECT_CLASS_LINE ||
668                 parents[0].elementClass === Const.OBJECT_CLASS_LINE && (
669                 parents[1].type === Const.OBJECT_TYPE_CONIC ||
670                 parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE))) {*/
671         if (parents.length !== 2 ||
672                 !((firstParentIsConic && secondParentIsLine) ||
673                     (firstParentIsLine && secondParentIsConic))) {
674             // Failure
675             throw new Error("JSXGraph: Can't create 'pole point' with parent types '" +
676                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
677                 "\nPossible parent type: [conic|circle,line], [line,conic|circle]");
678         }
679 
680         if (secondParentIsLine) {
681             el1 = board.select(parents[0]);
682             el2 = board.select(parents[1]);
683         } else {
684             el1 = board.select(parents[1]);
685             el2 = board.select(parents[0]);
686         }
687 
688         el = board.create('point',
689             [function () {
690                 var q = el1.quadraticform,
691                     s = el2.stdform.slice(0, 3);
692 
693                 return [JXG.Math.Numerics.det([s, q[1], q[2]]),
694                         JXG.Math.Numerics.det([q[0], s, q[2]]),
695                         JXG.Math.Numerics.det([q[0], q[1], s])];
696             }], attributes);
697 
698         el.elType = 'polepoint';
699         el.parents = [el1.id, el2.id];
700 
701         el1.addChild(el);
702         el2.addChild(el);
703 
704         return el;
705     };
706 
707     JXG.registerElement('point', JXG.createPoint);
708     JXG.registerElement('glider', JXG.createGlider);
709     JXG.registerElement('intersection', JXG.createIntersectionPoint);
710     JXG.registerElement('otherintersection', JXG.createOtherIntersectionPoint);
711     JXG.registerElement('polepoint', JXG.createPolePoint);
712 
713     return {
714         Point: JXG.Point,
715         createPoint: JXG.createPoint,
716         createGlider: JXG.createGlider,
717         createIntersection: JXG.createIntersectionPoint,
718         createOtherIntersection: JXG.createOtherIntersectionPoint,
719         createPolePoint: JXG.createPolePoint
720     };
721 });
722