      1 /*
      2     Copyright 2008-2018
      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(Type.evaluate(this.visProp.size)) +
    110                     parseFloat(Type.evaluate(this.visProp.strokewidth)) * 0.5;
    111             if (r < this.board.options.precision.hasPoint) {
    112                 r = this.board.options.precision.hasPoint;
    113             }
    114
    115             return ((Math.abs(coordsScr[1] - x) < r + 2) && (Math.abs(coordsScr[2] - y) < r + 2));
    116         },
    117
    118         /**
    119          * Updates the position of the point.
    120          */
    121         update: function (fromParent) {
    122             if (!this.needsUpdate) {
    123                 return this;
    124             }
    125
    126             this.updateCoords(fromParent);
    127
    128             if (Type.evaluate(this.visProp.trace)) {
    129                 this.cloneToBackground(true);
    130             }
    131
    132             return this;
    133         },
    134
    135         /**
    136          * Applies the transformations of the element to {@link JXG.Point#baseElement}.
    137          * Point transformations are relative to a base element.
    138          * @returns {JXG.CoordsElement} Reference to this object.
    139          */
    140         updateTransform: function () {
    141             var c, i;
    142
    143             if (this.transformations.length === 0 || this.baseElement === null) {
    144                 return this;
    145             }
    146
    147             // case of bindTo
    148             if (this === this.baseElement) {
    149                 c = this.transformations[0].apply(this.baseElement, 'self');
    150             // case of board.create('point',[baseElement,transform]);
    151             } else {
    152                 c = this.transformations[0].apply(this.baseElement);
    153             }
    154
    155             this.coords.setCoordinates(Const.COORDS_BY_USER, c);
    156
    157             for (i = 1; i < this.transformations.length; i++) {
    158                 this.coords.setCoordinates(Const.COORDS_BY_USER, this.transformations[i].apply(this));
    159             }
    160             return this;
    161         },
    162
    163         /**
    164          * Calls the renderer to update the drawing.
    165          * @private
    166          */
    167         updateRenderer: function () {
    168             this.updateRendererGeneric('updatePoint');
    169             return this;
    170         },
    171
    172         // documented in JXG.GeometryElement
    173         bounds: function () {
    174             return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1));
    175         },
    176
    177         /**
    178          * Convert the point to intersection point and update the construction.
    179          * To move the point visual onto the intersection, a call of board update is necessary.
    180          * TODO docu.
    181          * @param {String|Object} el1, el2, i, j The intersecting objects and the numbers.
    182          **/
    183         makeIntersection: function (el1, el2, i, j) {
    184             var func;
    185
    186             el1 = this.board.select(el1);
    187             el2 = this.board.select(el2);
    188
    189             func = Geometry.intersectionFunction(this.board, el1, el2, i, j,
    190                     Type.evaluate(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          * @returns {*}
    257          */
    258         normalizeFace: function (s) {
    259             JXG.deprecated('Point.normalizeFace()', 'JXG.normalizePointFace()');
    260             return Options.normalizePointFace(s);
    261         },
    262
    263         /**
    264          * Set the face of a point element.
    265          * @param {String} f String which determines the face of the point. See {@link JXG.GeometryElement#face} for a list of available faces.
    266          * @see JXG.GeometryElement#face
    267          * @deprecated Use setAttribute()
    268          */
    269         face: function (f) {
    270             JXG.deprecated('Point.face()', 'Point.setAttribute()');
    271             this.setAttribute({face: f});
    272         },
    273
    274         /**
    275          * Set the size of a point element
    276          * @param {Number} s Integer which determines the size of the point.
    277          * @see JXG.GeometryElement#size
    278          * @deprecated Use setAttribute()
    279          */
    280         size: function (s) {
    281             JXG.deprecated('Point.size()', 'Point.setAttribute()');
    282             this.setAttribute({size: s});
    283         },
    284
    285         // already documented in GeometryElement
    286         cloneToBackground: function () {
    287             var copy = {};
    288
    289             copy.id = this.id + 'T' + this.numTraces;
    290             this.numTraces += 1;
    291
    292             copy.coords = this.coords;
    293             copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true);
    294             copy.visProp.layer = this.board.options.layer.trace;
    295             copy.elementClass = Const.OBJECT_CLASS_POINT;
    296             copy.board = this.board;
    297             Type.clearVisPropOld(copy);
    298
    299             this.board.renderer.drawPoint(copy);
    300             this.traces[copy.id] = copy.rendNode;
    301
    302             return this;
    303         }
    304
    305     });
    306
    307     /**
    308      * @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
    309      * 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
    310      * 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
    311      * position directly.
    312      * @pseudo
    313      * @description
    314      * @name Point
    315      * @augments JXG.Point
    316      * @constructor
    317      * @type JXG.Point
    318      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
    319      * @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
    320      * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is
    321      * 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
    322      * 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
    323      * 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
    324      * parent elements are given they will be interpreted as homogeneous coordinates.
    325      * @param {JXG.Point_JXG.Transformation_Array} Point,Transformation A point can also be created providing a transformation or an array of transformations.
    326      * The resulting point is a clone of the base point transformed by the given Transformation. {@see JXG.Transformation}.
    327      *
    328      * @example
    329      * // Create a free point using affine euclidean coordinates
    330      * var p1 = board.create('point', [3.5, 2.0]);
    331      * </pre><div class="jxgbox" id="672f1764-7dfa-4abc-a2c6-81fbbf83e44b" style="width: 200px; height: 200px;"></div>
    332      * <script type="text/javascript">
    333      *   var board = JXG.JSXGraph.initBoard('672f1764-7dfa-4abc-a2c6-81fbbf83e44b', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
    334      *   var p1 = board.create('point', [3.5, 2.0]);
    335      * </script><pre>
    336      * @example
    337      * // Create a constrained point using anonymous function
    338      * var p2 = board.create('point', [3.5, function () { return p1.X(); }]);
    339      * </pre><div class="jxgbox" id="4fd4410c-3383-4e80-b1bb-961f5eeef224" style="width: 200px; height: 200px;"></div>
    340      * <script type="text/javascript">
    341      *   var fpex1_board = JXG.JSXGraph.initBoard('4fd4410c-3383-4e80-b1bb-961f5eeef224', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
    342      *   var fpex1_p1 = fpex1_board.create('point', [3.5, 2.0]);
    343      *   var fpex1_p2 = fpex1_board.create('point', [3.5, function () { return fpex1_p1.X(); }]);
    344      * </script><pre>
    345      * @example
    346      * // Create a point using transformations
    347      * var trans = board.create('transform', [2, 0.5], {type:'scale'});
    348      * var p3 = board.create('point', [p2, trans]);
    349      * </pre><div class="jxgbox" id="630afdf3-0a64-46e0-8a44-f51bd197bb8d" style="width: 400px; height: 400px;"></div>
    350      * <script type="text/javascript">
    351      *   var fpex2_board = JXG.JSXGraph.initBoard('630afdf3-0a64-46e0-8a44-f51bd197bb8d', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});
    352      *   var fpex2_trans = fpex2_board.create('transform', [2, 0.5], {type:'scale'});
    353      *   var fpex2_p2 = fpex2_board.create('point', [3.5, 2.0]);
    354      *   var fpex2_p3 = fpex2_board.create('point', [fpex2_p2, fpex2_trans]);
    355      * </script><pre>
    356      */
    357     JXG.createPoint = function (board, parents, attributes) {
    358         var el, attr;
    359
    360         attr = Type.copyAttributes(attributes, board.options, 'point');
    361         el = CoordsElement.create(JXG.Point, board, parents, attr);
    362         if (!el) {
    363             throw new Error("JSXGraph: Can't create point with parent types '" +
    364                     (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    365                     "\nPossible parent types: [x,y], [z,x,y], [element,transformation]");
    366         }
    367
    368         return el;
    369     };
    370
    371     /**
    372      * @class This element is used to provide a constructor for a glider point.
    373      * @pseudo
    374      * @description A glider is a point which lives on another geometric element like a line, circle, curve, turtle.
    375      * @name Glider
    376      * @augments JXG.Point
    377      * @constructor
    378      * @type JXG.Point
    379      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
    380      * @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.
    381      * 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
    382      * coordinates, otherwise they will be interpreted as homogeneous coordinates. In any case the point will be projected on the glide object.
    383      * @example
    384      * // Create a glider with user defined coordinates. If the coordinates are not on
    385      * // the circle (like in this case) the point will be projected onto the circle.
    386      * var p1 = board.create('point', [2.0, 2.0]);
    387      * var c1 = board.create('circle', [p1, 2.0]);
    388      * var p2 = board.create('glider', [2.0, 1.5, c1]);
    389      * </pre><div class="jxgbox" id="4f65f32f-e50a-4b50-9b7c-f6ec41652930" style="width: 300px; height: 300px;"></div>
    390      * <script type="text/javascript">
    391      *   var gpex1_board = JXG.JSXGraph.initBoard('4f65f32f-e50a-4b50-9b7c-f6ec41652930', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
    392      *   var gpex1_p1 = gpex1_board.create('point', [2.0, 2.0]);
    393      *   var gpex1_c1 = gpex1_board.create('circle', [gpex1_p1, 2.0]);
    394      *   var gpex1_p2 = gpex1_board.create('glider', [2.0, 1.5, gpex1_c1]);
    395      * </script><pre>
    396      * @example
    397      * // Create a glider with default coordinates (1,0,0). Same premises as above.
    398      * var p1 = board.create('point', [2.0, 2.0]);
    399      * var c1 = board.create('circle', [p1, 2.0]);
    400      * var p2 = board.create('glider', [c1]);
    401      * </pre><div class="jxgbox" id="4de7f181-631a-44b1-a12f-bc4d995609e8" style="width: 200px; height: 200px;"></div>
    402      * <script type="text/javascript">
    403      *   var gpex2_board = JXG.JSXGraph.initBoard('4de7f181-631a-44b1-a12f-bc4d995609e8', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});
    404      *   var gpex2_p1 = gpex2_board.create('point', [2.0, 2.0]);
    405      *   var gpex2_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]);
    406      *   var gpex2_p2 = gpex2_board.create('glider', [gpex2_c1]);
    407      * </script><pre>
    408      */
    409     JXG.createGlider = function (board, parents, attributes) {
    410         var el, coords,
    411             attr = Type.copyAttributes(attributes, board.options, 'glider');
    412
    413         if (parents.length === 1) {
    414             coords = [0, 0];
    415         } else {
    416             coords = parents.slice(0, 2);
    417         }
    418         el = board.create('point', coords, attr);
    419
    420         // eltype is set in here
    421         el.makeGlider(parents[parents.length - 1]);
    422
    423         return el;
    424     };
    425
    426
    427     /**
    428      * @class This element is used to provide a constructor for an intersection point.
    429      * @pseudo
    430      * @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.
    431      * an intersection point of the two elements.
    432      * @name Intersection
    433      * @augments JXG.Point
    434      * @constructor
    435      * @type JXG.Point
    436      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
    437      * @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
    438      * intersection point if two points are available: <ul>
    439      *   <li>i==0: use the positive square root,</li>
    440      *   <li>i==1: use the negative square root.</li></ul>
    441      * @example
    442      * // Create an intersection point of circle and line
    443      * var p1 = board.create('point', [2.0, 2.0]);
    444      * var c1 = board.create('circle', [p1, 2.0]);
    445      *
    446      * var p2 = board.create('point', [2.0, 2.0]);
    447      * var p3 = board.create('point', [2.0, 2.0]);
    448      * var l1 = board.create('line', [p2, p3]);
    449      *
    450      * var i = board.create('intersection', [c1, l1, 0]);
    451      * </pre><div class="jxgbox" id="e5b0e190-5200-4bc3-b995-b6cc53dc5dc0" style="width: 300px; height: 300px;"></div>
    452      * <script type="text/javascript">
    453      *   var ipex1_board = JXG.JSXGraph.initBoard('e5b0e190-5200-4bc3-b995-b6cc53dc5dc0', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
    454      *   var ipex1_p1 = ipex1_board.create('point', [4.0, 4.0]);
    455      *   var ipex1_c1 = ipex1_board.create('circle', [ipex1_p1, 2.0]);
    456      *   var ipex1_p2 = ipex1_board.create('point', [1.0, 1.0]);
    457      *   var ipex1_p3 = ipex1_board.create('point', [5.0, 3.0]);
    458      *   var ipex1_l1 = ipex1_board.create('line', [ipex1_p2, ipex1_p3]);
    459      *   var ipex1_i = ipex1_board.create('intersection', [ipex1_c1, ipex1_l1, 0]);
    460      * </script><pre>
    461      */
    462     JXG.createIntersectionPoint = function (board, parents, attributes) {
    463         var el, el1, el2, func, i, j,
    464             attr = Type.copyAttributes(attributes, board.options, 'intersection');
    465
    466         // make sure we definitely have the indices
    467         parents.push(0, 0);
    468
    469         el1 = board.select(parents[0]);
    470         el2 = board.select(parents[1]);
    471
    472         i = parents[2] || 0;
    473         j = parents[3] || 0;
    474
    475         el = board.create('point', [0, 0, 0], attr);
    476
    477         // el.visProp.alwaysintersect is evaluated as late as in the returned function
    478         func = Geometry.intersectionFunction(board, el1, el2, i, j, el.visProp.alwaysintersect);
    479         el.addConstraint([func]);
    480
    481         try {
    482             el1.addChild(el);
    483             el2.addChild(el);
    484         } catch (e) {
    485             throw new Error("JSXGraph: Can't create 'intersection' with parent types '" +
    486                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'.");
    487         }
    488
    489         el.type = Const.OBJECT_TYPE_INTERSECTION;
    490         el.elType = 'intersection';
    491         el.setParents([el1.id, el2.id]);
    492
    493         /**
    494          * Array of length 2 containing the numbers i and j.
    495          * The intersection point is i-th intersection point.
    496          * j is unused.
    497          * @type Array
    498          * @private
    499          */
    500         el.intersectionNumbers = [i, j];
    501         el.getParents = function() {
    502             return this.parents.concat(this.intersectionNumbers);
    503         };
    504
    505         el.generatePolynomial = function () {
    506             var poly1 = el1.generatePolynomial(el),
    507                 poly2 = el2.generatePolynomial(el);
    508
    509             if ((poly1.length === 0) || (poly2.length === 0)) {
    510                 return [];
    511             }
    512
    513             return [poly1[0], poly2[0]];
    514         };
    515
    516         return el;
    517     };
    518
    519     /**
    520      * @class This element is used to provide a constructor for the "other" intersection point.
    521      * @pseudo
    522      * @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.
    523      * an intersection point of the two elements. Additionally, one intersection point is provided. The function returns the other intersection point.
    524      * @name OtherIntersection
    525      * @augments JXG.Point
    526      * @constructor
    527      * @type JXG.Point
    528      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
    529      * @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
    530      * intersection point different from p:
    531      * @example
    532      * // Create an intersection point of circle and line
    533      * var p1 = board.create('point', [2.0, 2.0]);
    534      * var c1 = board.create('circle', [p1, 2.0]);
    535      *
    536      * var p2 = board.create('point', [2.0, 2.0]);
    537      * var p3 = board.create('point', [2.0, 2.0]);
    538      * var l1 = board.create('line', [p2, p3]);
    539      *
    540      * var i = board.create('intersection', [c1, l1, 0]);
    541      * var j = board.create('otherintersection', [c1, l1, i]);
    542      * </pre><div class="jxgbox" id="45e25f12-a1de-4257-a466-27a2ae73614c" style="width: 300px; height: 300px;"></div>
    543      * <script type="text/javascript">
    544      *   var ipex2_board = JXG.JSXGraph.initBoard('45e25f12-a1de-4257-a466-27a2ae73614c', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
    545      *   var ipex2_p1 = ipex2_board.create('point', [4.0, 4.0]);
    546      *   var ipex2_c1 = ipex2_board.create('circle', [ipex2_p1, 2.0]);
    547      *   var ipex2_p2 = ipex2_board.create('point', [1.0, 1.0]);
    548      *   var ipex2_p3 = ipex2_board.create('point', [5.0, 3.0]);
    549      *   var ipex2_l1 = ipex2_board.create('line', [ipex2_p2, ipex2_p3]);
    550      *   var ipex2_i = ipex2_board.create('intersection', [ipex2_c1, ipex2_l1, 0], {name:'D'});
    551      *   var ipex2_j = ipex2_board.create('otherintersection', [ipex2_c1, ipex2_l1, ipex2_i], {name:'E'});
    552      * </script><pre>
    553      */
    554     JXG.createOtherIntersectionPoint = function (board, parents, attributes) {
    555         var el, el1, el2, other;
    556
    557         if (parents.length !== 3 ||
    558                 !Type.isPoint(parents[2]) ||
    559                 (parents[0].elementClass !== Const.OBJECT_CLASS_LINE && parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE) ||
    560                 (parents[1].elementClass !== Const.OBJECT_CLASS_LINE && parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE)) {
    561             // Failure
    562             throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '" +
    563                 (typeof parents[0]) + "',  '" + (typeof parents[1]) + "'and  '" + (typeof parents[2]) + "'." +
    564                 "\nPossible parent types: [circle|line,circle|line,point]");
    565         }
    566
    567         el1 = board.select(parents[0]);
    568         el2 = board.select(parents[1]);
    569         other = board.select(parents[2]);
    570
    571         el = board.create('point', [function () {
    572             var c = Geometry.meet(el1.stdform, el2.stdform, 0, el1.board);
    573
    574             if (Math.abs(other.X() - c.usrCoords[1]) > Mat.eps ||
    575                     Math.abs(other.Y() - c.usrCoords[2]) > Mat.eps ||
    576                     Math.abs(other.Z() - c.usrCoords[0]) > Mat.eps) {
    577                 return c;
    578             }
    579
    580             return Geometry.meet(el1.stdform, el2.stdform, 1, el1.board);
    581         }], attributes);
    582
    583         el.type = Const.OBJECT_TYPE_INTERSECTION;
    584         el.elType = 'otherintersection';
    585         el.setParents([el1.id, el2.id, other]);
    586
    587         el1.addChild(el);
    588         el2.addChild(el);
    589
    590         el.generatePolynomial = function () {
    591             var poly1 = el1.generatePolynomial(el),
    592                 poly2 = el2.generatePolynomial(el);
    593
    594             if ((poly1.length === 0) || (poly2.length === 0)) {
    595                 return [];
    596             }
    597
    598             return [poly1[0], poly2[0]];
    599         };
    600
    601         return el;
    602     };
    603
    604     /**
    605      * @class This element is used to provide a constructor for the pole point of a line with respect to a conic or a circle.
    606      * @pseudo
    607      * @description The pole point is the unique reciprocal relationship of a line with respect to a conic.
    608      * 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.
    609      * A line tangent to a conic has the pole point of that line with respect to that conic as the tangent point.
    610      * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar.
    611      * @name PolePoint
    612      * @augments JXG.Point
    613      * @constructor
    614      * @type JXG.Point
    615      * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.
    616      * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or
    617      * @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.
    618      * @example
    619      * // Create the pole point of a line with respect to a conic
    620      * var p1 = board.create('point', [-1, 2]);
    621      * var p2 = board.create('point', [ 1, 4]);
    622      * var p3 = board.create('point', [-1,-2]);
    623      * var p4 = board.create('point', [ 0, 0]);
    624      * var p5 = board.create('point', [ 4,-2]);
    625      * var c1 = board.create('conic',[p1,p2,p3,p4,p5]);
    626      * var p6 = board.create('point', [-1, 4]);
    627      * var p7 = board.create('point', [2, -2]);
    628      * var l1 = board.create('line', [p6, p7]);
    629      * var p8 = board.create('polepoint', [c1, l1]);
    630      * </pre><div class="jxgbox" id='7b7233a0-f363-47dd-9df5-8018d0d17a98' class='jxgbox' style='width:400px; height:400px;'></div>
    631      * <script type='text/javascript'>
    632      * var ppex1_board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-8018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false});
    633      * var ppex1_p1 = ppex1_board.create('point', [-1, 2]);
    634      * var ppex1_p2 = ppex1_board.create('point', [ 1, 4]);
    635      * var ppex1_p3 = ppex1_board.create('point', [-1,-2]);
    636      * var ppex1_p4 = ppex1_board.create('point', [ 0, 0]);
    637      * var ppex1_p5 = ppex1_board.create('point', [ 4,-2]);
    638      * var ppex1_c1 = ppex1_board.create('conic',[ppex1_p1,ppex1_p2,ppex1_p3,ppex1_p4,ppex1_p5]);
    639      * var ppex1_p6 = ppex1_board.create('point', [-1, 4]);
    640      * var ppex1_p7 = ppex1_board.create('point', [2, -2]);
    641      * var ppex1_l1 = ppex1_board.create('line', [ppex1_p6, ppex1_p7]);
    642      * var ppex1_p8 = ppex1_board.create('polepoint', [ppex1_c1, ppex1_l1]);
    643      * </script><pre>
    644      * @example
    645      * // Create the pole point of a line with respect to a circle
    646      * var p1 = board.create('point', [1, 1]);
    647      * var p2 = board.create('point', [2, 3]);
    648      * var c1 = board.create('circle',[p1,p2]);
    649      * var p3 = board.create('point', [-1, 4]);
    650      * var p4 = board.create('point', [4, -1]);
    651      * var l1 = board.create('line', [p3, p4]);
    652      * var p5 = board.create('polepoint', [c1, l1]);
    653      * </pre><div class="jxgbox" id='7b7233a0-f363-47dd-9df5-9018d0d17a98' class='jxgbox' style='width:400px; height:400px;'></div>
    654      * <script type='text/javascript'>
    655      * var ppex2_board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-9018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false});
    656      * var ppex2_p1 = ppex2_board.create('point', [1, 1]);
    657      * var ppex2_p2 = ppex2_board.create('point', [2, 3]);
    658      * var ppex2_c1 = ppex2_board.create('circle',[ppex2_p1,ppex2_p2]);
    659      * var ppex2_p3 = ppex2_board.create('point', [-1, 4]);
    660      * var ppex2_p4 = ppex2_board.create('point', [4, -1]);
    661      * var ppex2_l1 = ppex2_board.create('line', [ppex2_p3, ppex2_p4]);
    662      * var ppex2_p5 = ppex2_board.create('polepoint', [ppex2_c1, ppex2_l1]);
    663      * </script><pre>
    664      */
    665     JXG.createPolePoint = function (board, parents, attributes) {
    666         var el, el1, el2,
    667             firstParentIsConic, secondParentIsConic,
    668             firstParentIsLine, secondParentIsLine;
    669
    670         if (parents.length > 1) {
    671             firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC ||
    672                 parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE);
    673             secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC ||
    674                 parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE);
    675
    676             firstParentIsLine = (parents[0].elementClass === Const.OBJECT_CLASS_LINE);
    677             secondParentIsLine = (parents[1].elementClass === Const.OBJECT_CLASS_LINE);
    678         }
    679
    680 /*        if (parents.length !== 2 || !((
    681                 parents[0].type === Const.OBJECT_TYPE_CONIC ||
    682                 parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) &&
    683                 parents[1].elementClass === Const.OBJECT_CLASS_LINE ||
    684                 parents[0].elementClass === Const.OBJECT_CLASS_LINE && (
    685                 parents[1].type === Const.OBJECT_TYPE_CONIC ||
    686                 parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE))) {*/
    687         if (parents.length !== 2 ||
    688                 !((firstParentIsConic && secondParentIsLine) ||
    689                     (firstParentIsLine && secondParentIsConic))) {
    690             // Failure
    691             throw new Error("JSXGraph: Can't create 'pole point' with parent types '" +
    692                 (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    693                 "\nPossible parent type: [conic|circle,line], [line,conic|circle]");
    694         }
    695
    696         if (secondParentIsLine) {
    697             el1 = board.select(parents[0]);
    698             el2 = board.select(parents[1]);
    699         } else {
    700             el1 = board.select(parents[1]);
    701             el2 = board.select(parents[0]);
    702         }
    703
    704         el = board.create('point',
    705             [function () {
    706                 var q = el1.quadraticform,
    707                     s = el2.stdform.slice(0, 3);
    708
    709                 return [JXG.Math.Numerics.det([s, q[1], q[2]]),
    710                         JXG.Math.Numerics.det([q[0], s, q[2]]),
    711                         JXG.Math.Numerics.det([q[0], q[1], s])];
    712             }], attributes);
    713
    714         el.elType = 'polepoint';
    715         el.setParents([el1.id, el2.id]);
    716
    717         el1.addChild(el);
    718         el2.addChild(el);
    719
    720         return el;
    721     };
    722
    723     JXG.registerElement('point', JXG.createPoint);
    724     JXG.registerElement('glider', JXG.createGlider);
    725     JXG.registerElement('intersection', JXG.createIntersectionPoint);
    726     JXG.registerElement('otherintersection', JXG.createOtherIntersectionPoint);
    727     JXG.registerElement('polepoint', JXG.createPolePoint);
    728
    729     return {
    730         Point: JXG.Point,
    731         createPoint: JXG.createPoint,
    732         createGlider: JXG.createGlider,
    733         createIntersection: JXG.createIntersectionPoint,
    734         createOtherIntersection: JXG.createOtherIntersectionPoint,
    735         createPolePoint: JXG.createPolePoint
    736     };
    737 });
    738