      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*/
     34 /*jslint nomen: true, plusplus: true*/
     35
     36 /* depends:
     37  jxg
     38  base/constants
     39  base/coords
     40  math/math
     41  math/numerics
     42  utils/type
     43  */
     44
     45 /**
     46  * @fileoverview This file contains the Math.Geometry namespace for calculating algebraic/geometric
     47  * stuff like intersection points, angles, midpoint, and so on.
     48  */
     49
     50 define([
     51     'jxg', 'base/constants', 'base/coords', 'math/math', 'math/numerics', 'utils/type', 'utils/expect'
     52 ], function (JXG, Const, Coords, Mat, Numerics, Type, Expect) {
     53
     54     "use strict";
     55
     56     /**
     57      * Math.Geometry namespace definition
     58      * @name JXG.Math.Geometry
     59      * @namespace
     60      */
     61     Mat.Geometry = {};
     62
     63 // the splitting is necessary due to the shortcut for the circumcircleMidpoint method to circumcenter.
     64
     65     JXG.extend(Mat.Geometry, /** @lends JXG.Math.Geometry */ {
     66         /* ***************************************/
     67         /* *** GENERAL GEOMETRIC CALCULATIONS ****/
     68         /* ***************************************/
     69
     70         /**
     71          * Calculates the angle defined by the points A, B, C.
     72          * @param {JXG.Point,Array} A A point  or [x,y] array.
     73          * @param {JXG.Point,Array} B Another point or [x,y] array.
     74          * @param {JXG.Point,Array} C A circle - no, of course the third point or [x,y] array.
     75          * @deprecated Use {@link JXG.Math.Geometry.rad} instead.
     76          * @see #rad
     77          * @see #trueAngle
     78          * @returns {Number} The angle in radian measure.
     79          */
     80         angle: function (A, B, C) {
     81             var u, v, s, t,
     82                 a = [],
     83                 b = [],
     84                 c = [];
     85
     86             JXG.deprecated('Geometry.angle()', 'Geometry.rad()');
     87             if (A.coords) {
     88                 a[0] = A.coords.usrCoords[1];
     89                 a[1] = A.coords.usrCoords[2];
     90             } else {
     91                 a[0] = A[0];
     92                 a[1] = A[1];
     93             }
     94
     95             if (B.coords) {
     96                 b[0] = B.coords.usrCoords[1];
     97                 b[1] = B.coords.usrCoords[2];
     98             } else {
     99                 b[0] = B[0];
    100                 b[1] = B[1];
    101             }
    102
    103             if (C.coords) {
    104                 c[0] = C.coords.usrCoords[1];
    105                 c[1] = C.coords.usrCoords[2];
    106             } else {
    107                 c[0] = C[0];
    108                 c[1] = C[1];
    109             }
    110
    111             u = a[0] - b[0];
    112             v = a[1] - b[1];
    113             s = c[0] - b[0];
    114             t = c[1] - b[1];
    115
    116             return Math.atan2(u * t - v * s, u * s + v * t);
    117         },
    118
    119         /**
    120          * Calculates the angle defined by the three points A, B, C if you're going from A to C around B counterclockwise.
    121          * @param {JXG.Point,Array} A Point or [x,y] array
    122          * @param {JXG.Point,Array} B Point or [x,y] array
    123          * @param {JXG.Point,Array} C Point or [x,y] array
    124          * @see #rad
    125          * @returns {Number} The angle in degrees.
    126          */
    127         trueAngle: function (A, B, C) {
    128             return this.rad(A, B, C) * 57.295779513082323; // *180.0/Math.PI;
    129         },
    130
    131         /**
    132          * Calculates the internal angle defined by the three points A, B, C if you're going from A to C around B counterclockwise.
    133          * @param {JXG.Point,Array} A Point or [x,y] array
    134          * @param {JXG.Point,Array} B Point or [x,y] array
    135          * @param {JXG.Point,Array} C Point or [x,y] array
    136          * @see #trueAngle
    137          * @returns {Number} Angle in radians.
    138          */
    139         rad: function (A, B, C) {
    140             var ax, ay, bx, by, cx, cy, phi;
    141
    142             if (A.coords) {
    143                 ax = A.coords.usrCoords[1];
    144                 ay = A.coords.usrCoords[2];
    145             } else {
    146                 ax = A[0];
    147                 ay = A[1];
    148             }
    149
    150             if (B.coords) {
    151                 bx = B.coords.usrCoords[1];
    152                 by = B.coords.usrCoords[2];
    153             } else {
    154                 bx = B[0];
    155                 by = B[1];
    156             }
    157
    158             if (C.coords) {
    159                 cx = C.coords.usrCoords[1];
    160                 cy = C.coords.usrCoords[2];
    161             } else {
    162                 cx = C[0];
    163                 cy = C[1];
    164             }
    165
    166             phi = Math.atan2(cy - by, cx - bx) - Math.atan2(ay - by, ax - bx);
    167
    168             if (phi < 0) {
    169                 phi += 6.2831853071795862;
    170             }
    171
    172             return phi;
    173         },
    174
    175         /**
    176          * Calculates a point on the bisection line between the three points A, B, C.
    177          * As a result, the bisection line is defined by two points:
    178          * Parameter B and the point with the coordinates calculated in this function.
    179          * Does not work for ideal points.
    180          * @param {JXG.Point} A Point
    181          * @param {JXG.Point} B Point
    182          * @param {JXG.Point} C Point
    183          * @param [board=A.board] Reference to the board
    184          * @returns {JXG.Coords} Coordinates of the second point defining the bisection.
    185          */
    186         angleBisector: function (A, B, C, board) {
    187             var phiA, phiC, phi,
    188                 Ac = A.coords.usrCoords,
    189                 Bc = B.coords.usrCoords,
    190                 Cc = C.coords.usrCoords,
    191                 x, y;
    192
    193             if (!Type.exists(board)) {
    194                 board = A.board;
    195             }
    196
    197             // Parallel lines
    198             if (Bc[0] === 0) {
    199                 return new Coords(Const.COORDS_BY_USER,
    200                     [1, (Ac[1] + Cc[1]) * 0.5, (Ac[2] + Cc[2]) * 0.5], board);
    201             }
    202
    203             // Non-parallel lines
    204             x = Ac[1] - Bc[1];
    205             y = Ac[2] - Bc[2];
    206             phiA =  Math.atan2(y, x);
    207
    208             x = Cc[1] - Bc[1];
    209             y = Cc[2] - Bc[2];
    210             phiC =  Math.atan2(y, x);
    211
    212             phi = (phiA + phiC) * 0.5;
    213
    214             if (phiA > phiC) {
    215                 phi += Math.PI;
    216             }
    217
    218             x = Math.cos(phi) + Bc[1];
    219             y = Math.sin(phi) + Bc[2];
    220
    221             return new Coords(Const.COORDS_BY_USER, [1, x, y], board);
    222         },
    223
    224         // /**
    225         //  * Calculates a point on the m-section line between the three points A, B, C.
    226         //  * As a result, the m-section line is defined by two points:
    227         //  * Parameter B and the point with the coordinates calculated in this function.
    228         //  * The m-section generalizes the bisector to any real number.
    229         //  * For example, the trisectors of an angle are simply the 1/3-sector and the 2/3-sector.
    230         //  * Does not work for ideal points.
    231         //  * @param {JXG.Point} A Point
    232         //  * @param {JXG.Point} B Point
    233         //  * @param {JXG.Point} C Point
    234         //  * @param {Number} m Number
    235         //  * @param [board=A.board] Reference to the board
    236         //  * @returns {JXG.Coords} Coordinates of the second point defining the bisection.
    237         //  */
    238         // angleMsector: function (A, B, C, m, board) {
    239         //     var phiA, phiC, phi,
    240         //         Ac = A.coords.usrCoords,
    241         //         Bc = B.coords.usrCoords,
    242         //         Cc = C.coords.usrCoords,
    243         //         x, y;
    244
    245         //     if (!Type.exists(board)) {
    246         //         board = A.board;
    247         //     }
    248
    249         //     // Parallel lines
    250         //     if (Bc[0] === 0) {
    251         //         return new Coords(Const.COORDS_BY_USER,
    252         //             [1, (Ac[1] + Cc[1]) * m, (Ac[2] + Cc[2]) * m], board);
    253         //     }
    254
    255         //     // Non-parallel lines
    256         //     x = Ac[1] - Bc[1];
    257         //     y = Ac[2] - Bc[2];
    258         //     phiA =  Math.atan2(y, x);
    259
    260         //     x = Cc[1] - Bc[1];
    261         //     y = Cc[2] - Bc[2];
    262         //     phiC =  Math.atan2(y, x);
    263
    264         //     phi = phiA + ((phiC - phiA) * m);
    265
    266         //     if (phiA - phiC > Math.PI) {
    267         //         phi += 2*m*Math.PI;
    268         //     }
    269
    270         //     x = Math.cos(phi) + Bc[1];
    271         //     y = Math.sin(phi) + Bc[2];
    272
    273         //     return new Coords(Const.COORDS_BY_USER, [1, x, y], board);
    274         // },
    275
    276         /**
    277          * Reflects the point along the line.
    278          * @param {JXG.Line} line Axis of reflection.
    279          * @param {JXG.Point} point Point to reflect.
    280          * @param [board=point.board] Reference to the board
    281          * @returns {JXG.Coords} Coordinates of the reflected point.
    282          */
    283         reflection: function (line, point, board) {
    284             // (v,w) defines the slope of the line
    285             var x0, y0, x1, y1, v, w, mu,
    286                 pc = point.coords.usrCoords,
    287                 p1c = line.point1.coords.usrCoords,
    288                 p2c = line.point2.coords.usrCoords;
    289
    290             if (!Type.exists(board)) {
    291                 board = point.board;
    292             }
    293
    294             v = p2c[1] - p1c[1];
    295             w = p2c[2] - p1c[2];
    296
    297             x0 = pc[1] - p1c[1];
    298             y0 = pc[2] - p1c[2];
    299
    300             mu = (v * y0 - w * x0) / (v * v + w * w);
    301
    302             // point + mu*(-y,x) is the perpendicular foot
    303             x1 = pc[1] + 2 * mu * w;
    304             y1 = pc[2] - 2 * mu * v;
    305
    306             return new Coords(Const.COORDS_BY_USER, [x1, y1], board);
    307         },
    308
    309         /**
    310          * Computes the new position of a point which is rotated
    311          * around a second point (called rotpoint) by the angle phi.
    312          * @param {JXG.Point} rotpoint Center of the rotation
    313          * @param {JXG.Point} point point to be rotated
    314          * @param {Number} phi rotation angle in arc length
    315          * @param {JXG.Board} [board=point.board] Reference to the board
    316          * @returns {JXG.Coords} Coordinates of the new position.
    317          */
    318         rotation: function (rotpoint, point, phi, board) {
    319             var x0, y0, c, s, x1, y1,
    320                 pc = point.coords.usrCoords,
    321                 rotpc = rotpoint.coords.usrCoords;
    322
    323             if (!Type.exists(board)) {
    324                 board = point.board;
    325             }
    326
    327             x0 = pc[1] - rotpc[1];
    328             y0 = pc[2] - rotpc[2];
    329
    330             c = Math.cos(phi);
    331             s = Math.sin(phi);
    332
    333             x1 = x0 * c - y0 * s + rotpc[1];
    334             y1 = x0 * s + y0 * c + rotpc[2];
    335
    336             return new Coords(Const.COORDS_BY_USER, [x1, y1], board);
    337         },
    338
    339         /**
    340          * Calculates the coordinates of a point on the perpendicular to the given line through
    341          * the given point.
    342          * @param {JXG.Line} line A line.
    343          * @param {JXG.Point} point Point which is projected to the line.
    344          * @param {JXG.Board} [board=point.board] Reference to the board
    345          * @returns {Array} Array of length two containing coordinates of a point on the perpendicular to the given line
    346          *                  through the given point and boolean flag "change".
    347          */
    348         perpendicular: function (line, point, board) {
    349             var x, y, change,
    350                 c, z,
    351                 A = line.point1.coords.usrCoords,
    352                 B = line.point2.coords.usrCoords,
    353                 C = point.coords.usrCoords;
    354
    355             if (!Type.exists(board)) {
    356                 board = point.board;
    357             }
    358
    359             // special case: point is the first point of the line
    360             if (point === line.point1) {
    361                 x = A[1] + B[2] - A[2];
    362                 y = A[2] - B[1] + A[1];
    363                 z = A[0] * B[0];
    364
    365                 if (Math.abs(z) < Mat.eps) {
    366                     x =  B[2];
    367                     y = -B[1];
    368                 }
    369                 c = [z, x, y];
    370                 change = true;
    371
    372             // special case: point is the second point of the line
    373             } else if (point === line.point2) {
    374                 x = B[1] + A[2] - B[2];
    375                 y = B[2] - A[1] + B[1];
    376                 z = A[0] * B[0];
    377
    378                 if (Math.abs(z) < Mat.eps) {
    379                     x =  A[2];
    380                     y = -A[1];
    381                 }
    382                 c = [z, x, y];
    383                 change = false;
    384
    385             // special case: point lies somewhere else on the line
    386             } else if (Math.abs(Mat.innerProduct(C, line.stdform, 3)) < Mat.eps) {
    387                 x = C[1] + B[2] - C[2];
    388                 y = C[2] - B[1] + C[1];
    389                 z = B[0];
    390
    391                 if (Math.abs(z) < Mat.eps) {
    392                     x =  B[2];
    393                     y = -B[1];
    394                 }
    395                 change = true;
    396
    397                 if (Math.abs(z) > Mat.eps && Math.abs(x - C[1]) < Mat.eps && Math.abs(y - C[2]) < Mat.eps) {
    398                     x = C[1] + A[2] - C[2];
    399                     y = C[2] - A[1] + C[1];
    400                     change = false;
    401                 }
    402                 c = [z, x, y];
    403
    404             // general case: point does not lie on the line
    405             // -> calculate the foot of the dropped perpendicular
    406             } else {
    407                 c = [0, line.stdform[1], line.stdform[2]];
    408                 c = Mat.crossProduct(c, C);                  // perpendicuar to line
    409                 c = Mat.crossProduct(c, line.stdform);       // intersection of line and perpendicular
    410                 change = true;
    411             }
    412
    413             return [new Coords(Const.COORDS_BY_USER, c, board), change];
    414         },
    415
    416         /**
    417          * @deprecated Please use {@link JXG.Math.Geometry.circumcenter} instead.
    418          */
    419         circumcenterMidpoint: function () {
    420             JXG.deprecated('Geometry.circumcenterMidpoint()', 'Geometry.circumcenter()');
    421             this.circumcenter.apply(this, arguments);
    422         },
    423
    424         /**
    425          * Calculates the center of the circumcircle of the three given points.
    426          * @param {JXG.Point} point1 Point
    427          * @param {JXG.Point} point2 Point
    428          * @param {JXG.Point} point3 Point
    429          * @param {JXG.Board} [board=point1.board] Reference to the board
    430          * @returns {JXG.Coords} Coordinates of the center of the circumcircle of the given points.
    431          */
    432         circumcenter: function (point1, point2, point3, board) {
    433             var u, v, m1, m2,
    434                 A = point1.coords.usrCoords,
    435                 B = point2.coords.usrCoords,
    436                 C = point3.coords.usrCoords;
    437
    438             if (!Type.exists(board)) {
    439                 board = point1.board;
    440             }
    441
    442             u = [B[0] - A[0], -B[2] + A[2], B[1] - A[1]];
    443             v = [(A[0] + B[0])  * 0.5, (A[1] + B[1]) * 0.5, (A[2] + B[2]) * 0.5];
    444             m1 = Mat.crossProduct(u, v);
    445
    446             u = [C[0] - B[0], -C[2] + B[2], C[1] - B[1]];
    447             v = [(B[0] + C[0]) * 0.5, (B[1] + C[1]) * 0.5, (B[2] + C[2]) * 0.5];
    448             m2 = Mat.crossProduct(u, v);
    449
    450             return new Coords(Const.COORDS_BY_USER, Mat.crossProduct(m1, m2), board);
    451         },
    452
    453         /**
    454          * Calculates the euclidean norm for two given arrays of the same length.
    455          * @param {Array} array1 Array of Number
    456          * @param {Array} array2 Array of Number
    457          * @param {Number} [n] Length of the arrays. Default is the minimum length of the given arrays.
    458          * @returns {Number} Euclidean distance of the given vectors.
    459          */
    460         distance: function (array1, array2, n) {
    461             var i,
    462                 sum = 0;
    463
    464             if (!n) {
    465                 n = Math.min(array1.length, array2.length);
    466             }
    467
    468             for (i = 0; i < n; i++) {
    469                 sum += (array1[i] - array2[i]) * (array1[i] - array2[i]);
    470             }
    471
    472             return Math.sqrt(sum);
    473         },
    474
    475         /**
    476          * Calculates euclidean distance for two given arrays of the same length.
    477          * If one of the arrays contains a zero in the first coordinate, and the euclidean distance
    478          * is different from zero it is a point at infinity and we return Infinity.
    479          * @param {Array} array1 Array containing elements of type number.
    480          * @param {Array} array2 Array containing elements of type number.
    481          * @param {Number} [n] Length of the arrays. Default is the minimum length of the given arrays.
    482          * @returns {Number} Euclidean (affine) distance of the given vectors.
    483          */
    484         affineDistance: function (array1, array2, n) {
    485             var d;
    486
    487             d = this.distance(array1, array2, n);
    488
    489             if (d > Mat.eps && (Math.abs(array1[0]) < Mat.eps || Math.abs(array2[0]) < Mat.eps)) {
    490                 return Infinity;
    491             }
    492
    493             return d;
    494         },
    495
    496         /**
    497          * Sort vertices counter clockwise starting with the point with the lowest y coordinate.
    498          *
    499          * @param {Array} p An array containing {@link JXG.Point}, {@link JXG.Coords}, and/or arrays.
    500          *
    501          * @returns {Array}
    502          */
    503         sortVertices: function (p) {
    504             var i, ll,
    505                 ps = Expect.each(p, Expect.coordsArray),
    506                 N = ps.length;
    507
    508             // find the point with the lowest y value
    509             for (i = 1; i < N; i++) {
    510                 if ((ps[i][2] < ps[0][2]) ||
    511                         // if the current and the lowest point have the same y value, pick the one with
    512                         // the lowest x value.
    513                         (Math.abs(ps[i][2] - ps[0][2]) < Mat.eps && ps[i][1] < ps[0][1])) {
    514                     ps = Type.swap(ps, i, 0);
    515                 }
    516             }
    517
    518             // sort ps in increasing order of the angle the points and the ll make with the x-axis
    519             ll = ps.shift();
    520             ps.sort(function (a, b) {
    521                 // atan is monotonically increasing, as we are only interested in the sign of the difference
    522                 // evaluating atan is not necessary
    523                 var rad1 = Math.atan2(a[2] - ll[2], a[1] - ll[1]),
    524                     rad2 = Math.atan2(b[2] - ll[2], b[1] - ll[1]);
    525
    526                 return rad1 - rad2;
    527             });
    528
    529             // put ll back into the array
    530             ps.unshift(ll);
    531
    532             // put the last element also in the beginning
    533             ps.unshift(ps[ps.length - 1]);
    534
    535             return ps;
    536         },
    537
    538         /**
    539          * Signed triangle area of the three points given.
    540          *
    541          * @param {JXG.Point|JXG.Coords|Array} p1
    542          * @param {JXG.Point|JXG.Coords|Array} p2
    543          * @param {JXG.Point|JXG.Coords|Array} p3
    544          *
    545          * @returns {Number}
    546          */
    547         signedTriangle: function (p1, p2, p3) {
    548             var A = Expect.coordsArray(p1),
    549                 B = Expect.coordsArray(p2),
    550                 C = Expect.coordsArray(p3);
    551
    552             return 0.5 * ((B[1] - A[1]) * (C[2] - A[2]) - (B[2] - A[2]) * (C[1] - A[1]));
    553         },
    554
    555         /**
    556          * Determine the signed area of a non-intersecting polygon.
    557          * Surveyor's Formula
    558          *
    559          * @param {Array} p An array containing {@link JXG.Point}, {@link JXG.Coords}, and/or arrays.
    560          * @param {Boolean} [sort=true]
    561          *
    562          * @returns {Number}
    563          */
    564         signedPolygon: function (p, sort) {
    565             var i, N,
    566                 A = 0,
    567                 ps = Expect.each(p, Expect.coordsArray);
    568
    569             if (sort === undefined) {
    570                 sort = true;
    571             }
    572
    573             if (!sort) {
    574                 ps = this.sortVertices(ps);
    575             } else {
    576                 // make sure the polygon is closed. If it is already closed this won't change the sum because the last
    577                 // summand will be 0.
    578                 ps.unshift(ps[ps.length - 1]);
    579             }
    580
    581             N = ps.length;
    582
    583             for (i = 1; i < N; i++) {
    584                 A += ps[i - 1][1] * ps[i][2] - ps[i][1] * ps[i - 1][2];
    585             }
    586
    587             return 0.5 * A;
    588         },
    589
    590         /**
    591          * Calculate the complex hull of a point cloud.
    592          *
    593          * @param {Array} points An array containing {@link JXG.Point}, {@link JXG.Coords}, and/or arrays.
    594          *
    595          * @returns {Array}
    596          */
    597         GrahamScan: function (points) {
    598             var i,
    599                 M = 1,
    600                 ps = Expect.each(points, Expect.coordsArray),
    601                 N = ps.length;
    602
    603             ps = this.sortVertices(ps);
    604             N = ps.length;
    605
    606             for (i = 2; i < N; i++) {
    607                 while (this.signedTriangle(ps[M - 1], ps[M], ps[i]) <= 0) {
    608                     if (M > 1) {
    609                         M -= 1;
    610                     } else if (i === N - 1) {
    611                         break;
    612                     } else {
    613                         i += 1;
    614                     }
    615                 }
    616
    617                 M += 1;
    618                 ps = Type.swap(ps, M, i);
    619             }
    620
    621             return ps.slice(0, M);
    622         },
    623
    624         /**
    625          * A line can be a segment, a straight, or a ray. so it is not always delimited by point1 and point2
    626          * calcStraight determines the visual start point and end point of the line. A segment is only drawn
    627          * from start to end point, a straight line is drawn until it meets the boards boundaries.
    628          * @param {JXG.Line} el Reference to a line object, that needs calculation of start and end point.
    629          * @param {JXG.Coords} point1 Coordinates of the point where line drawing begins. This value is calculated and
    630          * set by this method.
    631          * @param {JXG.Coords} point2 Coordinates of the point where line drawing ends. This value is calculated and set
    632          * by this method.
    633          * @param {Number} margin Optional margin, to avoid the display of the small sides of lines.
    634          * @returns null
    635          * @see Line
    636          * @see JXG.Line
    637          */
    638         calcStraight: function (el, point1, point2, margin) {
    639             var takePoint1, takePoint2, intersection, intersect1, intersect2, straightFirst, straightLast,
    640                 c, p1, p2;
    641
    642             if (!Type.exists(margin)) {
    643                 // Enlarge the drawable region slightly. This hides the small sides
    644                 // of thick lines in most cases.
    645                 margin = 10;
    646             }
    647
    648             straightFirst = Type.evaluate(el.visProp.straightfirst);
    649             straightLast = Type.evaluate(el.visProp.straightlast);
    650
    651             // If one of the point is an ideal point in homogeneous coordinates
    652             // drawing of line segments or rays are not possible.
    653             if (Math.abs(point1.scrCoords[0]) < Mat.eps) {
    654                 straightFirst = true;
    655             }
    656             if (Math.abs(point2.scrCoords[0]) < Mat.eps) {
    657                 straightLast = true;
    658             }
    659
    660             // Do nothing in case of line segments (inside or outside of the board)
    661             if (!straightFirst && !straightLast) {
    662                 return;
    663             }
    664
    665             // Compute the stdform of the line in screen coordinates.
    666             c = [];
    667             c[0] = el.stdform[0] -
    668                 el.stdform[1] * el.board.origin.scrCoords[1] / el.board.unitX +
    669                 el.stdform[2] * el.board.origin.scrCoords[2] / el.board.unitY;
    670             c[1] =  el.stdform[1] / el.board.unitX;
    671             c[2] = -el.stdform[2] / el.board.unitY;
    672
    673             // p1=p2
    674             if (isNaN(c[0] + c[1] + c[2])) {
    675                 return;
    676             }
    677
    678             takePoint1 = false;
    679             takePoint2 = false;
    680
    681             // Line starts at point1 and point1 is inside the board
    682             takePoint1 = !straightFirst &&
    683                 Math.abs(point1.usrCoords[0]) >= Mat.eps &&
    684                 point1.scrCoords[1] >= 0.0 && point1.scrCoords[1] <= el.board.canvasWidth &&
    685                 point1.scrCoords[2] >= 0.0 && point1.scrCoords[2] <= el.board.canvasHeight;
    686
    687             // Line ends at point2 and point2 is inside the board
    688             takePoint2 = !straightLast &&
    689                 Math.abs(point2.usrCoords[0]) >= Mat.eps &&
    690                 point2.scrCoords[1] >= 0.0 && point2.scrCoords[1] <= el.board.canvasWidth &&
    691                 point2.scrCoords[2] >= 0.0 && point2.scrCoords[2] <= el.board.canvasHeight;
    692
    693             // Intersect the line with the four borders of the board.
    694             intersection = this.meetLineBoard(c, el.board, margin);
    695             intersect1 = intersection[0];
    696             intersect2 = intersection[1];
    697
    698             /**
    699              * At this point we have four points:
    700              * point1 and point2 are the first and the second defining point on the line,
    701              * intersect1, intersect2 are the intersections of the line with border around the board.
    702              */
    703
    704             /*
    705              * Here we handle rays where both defining points are outside of the board.
    706              */
    707             // If both points are outside and the complete ray is outside we do nothing
    708             if (!takePoint1 && !takePoint2) {
    709                 // Ray starting at point 1
    710                 if (!straightFirst && straightLast &&
    711                         !this.isSameDirection(point1, point2, intersect1) && !this.isSameDirection(point1, point2, intersect2)) {
    712                     return;
    713                 }
    714
    715                 // Ray starting at point 2
    716                 if (straightFirst && !straightLast &&
    717                         !this.isSameDirection(point2, point1, intersect1) && !this.isSameDirection(point2, point1, intersect2)) {
    718                     return;
    719                 }
    720             }
    721
    722             /*
    723              * If at least one of the defining points is outside of the board
    724              * we take intersect1 or intersect2 as one of the end points
    725              * The order is also important for arrows of axes
    726              */
    727             if (!takePoint1) {
    728                 if (!takePoint2) {
    729                     // Two border intersection points are used
    730                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
    731                         p1 = intersect1;
    732                         p2 = intersect2;
    733                     } else {
    734                         p2 = intersect1;
    735                         p1 = intersect2;
    736                     }
    737                 } else {
    738                     // One border intersection points is used
    739                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
    740                         p1 = intersect1;
    741                     } else {
    742                         p1 = intersect2;
    743                     }
    744                 }
    745             } else {
    746                 if (!takePoint2) {
    747                     // One border intersection points is used
    748                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
    749                         p2 = intersect2;
    750                     } else {
    751                         p2 = intersect1;
    752                     }
    753                 }
    754             }
    755
    756             if (p1) {
    757                 //point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords.slice(1));
    758                 point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords);
    759             }
    760
    761             if (p2) {
    762                 //point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords.slice(1));
    763                 point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords);
    764             }
    765         },
    766
    767         /**
    768          * A line can be a segment, a straight, or a ray. so it is not always delimited by point1 and point2.
    769          *
    770          * This method adjusts the line's delimiting points taking into account its nature, the viewport defined
    771          * by the board.
    772          *
    773          * A segment is delimited by start and end point, a straight line or ray is delimited until it meets the
    774          * boards boundaries. However, if the line has infinite ticks, it will be delimited by the projection of
    775          * the boards vertices onto itself.
    776          *
    777          * @param {JXG.Line} el Reference to a line object, that needs calculation of start and end point.
    778          * @param {JXG.Coords} point1 Coordinates of the point where line drawing begins. This value is calculated and
    779          * set by this method.
    780          * @param {JXG.Coords} point2 Coordinates of the point where line drawing ends. This value is calculated and set
    781          * by this method.
    782          * @see Line
    783          * @see JXG.Line
    784          */
    785         calcLineDelimitingPoints: function (el, point1, point2) {
    786             var distP1P2, boundingBox, lineSlope,
    787                 intersect1, intersect2, straightFirst, straightLast,
    788                 c, p1, p2,
    789                 takePoint1 = false,
    790                 takePoint2 = false;
    791
    792             straightFirst = Type.evaluate(el.visProp.straightfirst);
    793             straightLast = Type.evaluate(el.visProp.straightlast);
    794
    795             // If one of the point is an ideal point in homogeneous coordinates
    796             // drawing of line segments or rays are not possible.
    797             if (Math.abs(point1.scrCoords[0]) < Mat.eps) {
    798                 straightFirst = true;
    799             }
    800             if (Math.abs(point2.scrCoords[0]) < Mat.eps) {
    801                 straightLast = true;
    802             }
    803
    804             // Compute the stdform of the line in screen coordinates.
    805             c = [];
    806             c[0] = el.stdform[0] -
    807                 el.stdform[1] * el.board.origin.scrCoords[1] / el.board.unitX +
    808                 el.stdform[2] * el.board.origin.scrCoords[2] / el.board.unitY;
    809             c[1] =  el.stdform[1] / el.board.unitX;
    810             c[2] = -el.stdform[2] / el.board.unitY;
    811
    812             // p1=p2
    813             if (isNaN(c[0] + c[1] + c[2])) {
    814                 return;
    815             }
    816
    817             takePoint1 = !straightFirst;
    818             takePoint2 = !straightLast;
    819             // Intersect the board vertices on the line to establish the available visual space for the infinite ticks
    820             // Based on the slope of the line we can optimise and only project the two outer vertices
    821
    822             // boundingBox = [x1, y1, x2, y2] upper left, lower right vertices
    823             boundingBox = el.board.getBoundingBox();
    824             lineSlope = el.getSlope();
    825             if (lineSlope >= 0) {
    826                 // project vertices (x2,y1) (x1, y2)
    827                 intersect1 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[2], boundingBox[1]] } }, el, el.board);
    828                 intersect2 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[0], boundingBox[3]] } }, el, el.board);
    829             } else {
    830                 // project vertices (x1, y1) (x2, y2)
    831                 intersect1 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[0], boundingBox[1]] } }, el, el.board);
    832                 intersect2 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[2], boundingBox[3]] } }, el, el.board);
    833             }
    834
    835             /**
    836              * we have four points:
    837              * point1 and point2 are the first and the second defining point on the line,
    838              * intersect1, intersect2 are the intersections of the line with border around the board.
    839              */
    840
    841             /*
    842              * Here we handle rays/segments where both defining points are outside of the board.
    843              */
    844             if (!takePoint1 && !takePoint2) {
    845                 // Segment, if segment does not cross the board, do nothing
    846                 if (!straightFirst && !straightLast) {
    847                     distP1P2 = point1.distance(Const.COORDS_BY_USER, point2);
    848                     // if  intersect1 not between point1 and point2
    849                     if (Math.abs(point1.distance(Const.COORDS_BY_USER, intersect1) +
    850                             intersect1.distance(Const.COORDS_BY_USER, point2) - distP1P2) > Mat.eps) {
    851                         return;
    852                     }
    853                     // if insersect2 not between point1 and point2
    854                     if (Math.abs(point1.distance(Const.COORDS_BY_USER, intersect2) +
    855                             intersect2.distance(Const.COORDS_BY_USER, point2) - distP1P2) > Mat.eps) {
    856                         return;
    857                     }
    858                 }
    859
    860                 // If both points are outside and the complete ray is outside we do nothing
    861                 // Ray starting at point 1
    862                 if (!straightFirst && straightLast &&
    863                         !this.isSameDirection(point1, point2, intersect1) && !this.isSameDirection(point1, point2, intersect2)) {
    864                     return;
    865                 }
    866
    867                 // Ray starting at point 2
    868                 if (straightFirst && !straightLast &&
    869                         !this.isSameDirection(point2, point1, intersect1) && !this.isSameDirection(point2, point1, intersect2)) {
    870                     return;
    871                 }
    872             }
    873
    874             /*
    875              * If at least one of the defining points is outside of the board
    876              * we take intersect1 or intersect2 as one of the end points
    877              * The order is also important for arrows of axes
    878              */
    879             if (!takePoint1) {
    880                 if (!takePoint2) {
    881                     // Two border intersection points are used
    882                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
    883                         p1 = intersect1;
    884                         p2 = intersect2;
    885                     } else {
    886                         p2 = intersect1;
    887                         p1 = intersect2;
    888                     }
    889                 } else {
    890                     // One border intersection points is used
    891                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
    892                         p1 = intersect1;
    893                     } else {
    894                         p1 = intersect2;
    895                     }
    896                 }
    897             } else {
    898                 if (!takePoint2) {
    899                     // One border intersection points is used
    900                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
    901                         p2 = intersect2;
    902                     } else {
    903                         p2 = intersect1;
    904                     }
    905                 }
    906             }
    907
    908             if (p1) {
    909                 //point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords.slice(1));
    910                 point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords);
    911             }
    912
    913             if (p2) {
    914                 //point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords.slice(1));
    915                 point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords);
    916             }
    917         },
    918
    919         /**
    920          * Calculates the visProp.position corresponding to a given angle.
    921          * @param {number} angle angle in radians. Must be in range (-2pi,2pi).
    922          */
    923         calcLabelQuadrant: function(angle) {
    924             var q;
    925             if (angle < 0) {
    926                 angle += 2*Math.PI;
    927             }
    928             q = Math.floor((angle+Math.PI/8)/(Math.PI/4))%8;
    929             return ['rt','urt','top','ulft','lft','llft','lrt'][q];
    930         },
    931
    932         /**
    933          * The vectors <tt>p2-p1</tt> and <tt>i2-i1</tt> are supposed to be collinear. If their cosine is positive
    934          * they point into the same direction otherwise they point in opposite direction.
    935          * @param {JXG.Coords} p1
    936          * @param {JXG.Coords} p2
    937          * @param {JXG.Coords} i1
    938          * @param {JXG.Coords} i2
    939          * @returns {Boolean} True, if <tt>p2-p1</tt> and <tt>i2-i1</tt> point into the same direction
    940          */
    941         isSameDir: function (p1, p2, i1, i2) {
    942             var dpx = p2.usrCoords[1] - p1.usrCoords[1],
    943                 dpy = p2.usrCoords[2] - p1.usrCoords[2],
    944                 dix = i2.usrCoords[1] - i1.usrCoords[1],
    945                 diy = i2.usrCoords[2] - i1.usrCoords[2];
    946
    947             if (Math.abs(p2.usrCoords[0]) < Mat.eps) {
    948                 dpx = p2.usrCoords[1];
    949                 dpy = p2.usrCoords[2];
    950             }
    951
    952             if (Math.abs(p1.usrCoords[0]) < Mat.eps) {
    953                 dpx = -p1.usrCoords[1];
    954                 dpy = -p1.usrCoords[2];
    955             }
    956
    957             return dpx * dix + dpy * diy >= 0;
    958         },
    959
    960         /**
    961          * If you're looking from point "start" towards point "s" and can see the point "p", true is returned. Otherwise false.
    962          * @param {JXG.Coords} start The point you're standing on.
    963          * @param {JXG.Coords} p The point in which direction you're looking.
    964          * @param {JXG.Coords} s The point that should be visible.
    965          * @returns {Boolean} True, if from start the point p is in the same direction as s is, that means s-start = k*(p-start) with k>=0.
    966          */
    967         isSameDirection: function (start, p, s) {
    968             var dx, dy, sx, sy, r = false;
    969
    970             dx = p.usrCoords[1] - start.usrCoords[1];
    971             dy = p.usrCoords[2] - start.usrCoords[2];
    972
    973             sx = s.usrCoords[1] - start.usrCoords[1];
    974             sy = s.usrCoords[2] - start.usrCoords[2];
    975
    976             if (Math.abs(dx) < Mat.eps) {
    977                 dx = 0;
    978             }
    979
    980             if (Math.abs(dy) < Mat.eps) {
    981                 dy = 0;
    982             }
    983
    984             if (Math.abs(sx) < Mat.eps) {
    985                 sx = 0;
    986             }
    987
    988             if (Math.abs(sy) < Mat.eps) {
    989                 sy = 0;
    990             }
    991
    992             if (dx >= 0 && sx >= 0) {
    993                 r = (dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0);
    994             } else if (dx <= 0 && sx <= 0) {
    995                 r = (dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0);
    996             }
    997
    998             return r;
    999         },
    1000
    1001         /****************************************/
    1002         /****          INTERSECTIONS         ****/
    1003         /****************************************/
    1004
    1005         /**
    1006          * Generate the function which computes the coordinates of the intersection point.
    1007          * Primarily used in {@link JXG.Point#createIntersectionPoint}.
    1008          * @param {JXG.Board} board object
    1009          * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2.
    1010          * i determines the intersection point if two points are available: <ul>
    1011          *   <li>i==0: use the positive square root,</li>
    1012          *   <li>i==1: use the negative square root.</li></ul>
    1013          * See further {@link JXG.Point#createIntersectionPoint}.
    1014          * @param {Boolean} alwaysintersect. Flag that determines if segements and arc can have an outer intersection point
    1015          * on their defining line or circle.
    1016          * @returns {Function} Function returning a {@link JXG.Coords} object that determines
    1017          * the intersection point.
    1018          */
    1019         intersectionFunction: function (board, el1, el2, i, j, alwaysintersect) {
    1020             var func, that = this;
    1021
    1022             if (el1.elementClass === Const.OBJECT_CLASS_CURVE &&
    1023                     el2.elementClass === Const.OBJECT_CLASS_CURVE) {
    1024                 // curve - curve
    1025                 /** @ignore */
    1026                 func = function () {
    1027                     return that.meetCurveCurve(el1, el2, i, j, el1.board);
    1028                 };
    1029
    1030             } else if ((el1.elementClass === Const.OBJECT_CLASS_CURVE && el2.elementClass === Const.OBJECT_CLASS_LINE) ||
    1031                     (el2.elementClass === Const.OBJECT_CLASS_CURVE && el1.elementClass === Const.OBJECT_CLASS_LINE)) {
    1032                 // curve - line (this includes intersections between conic sections and lines
    1033                 /** @ignore */
    1034                 func = function () {
    1035                     return that.meetCurveLine(el1, el2, i, el1.board, alwaysintersect);
    1036                 };
    1037
    1038             } else if (el1.elementClass === Const.OBJECT_CLASS_LINE && el2.elementClass === Const.OBJECT_CLASS_LINE) {
    1039                 // line - line, lines may also be segments.
    1040                 /** @ignore */
    1041                 func = function () {
    1042                     var res, c,
    1043                         first1, first2, last1, last2;
    1044
    1045                     first1 = first2 = Type.evaluate(el1.visProp.straightfirst);
    1046                     last1 = last2 = Type.evaluate(el1.visProp.straightlast);
    1047
    1048                     /**
    1049                      * If one of the lines is a segment or ray and
    1050                      * the the intersection point shpould disappear if outside
    1051                      * of the segment or ray we call
    1052                      * meetSegmentSegment
    1053                      */
    1054                     if (!Type.evaluate(alwaysintersect) && (!first1 || !last1 || !first2 || !last2)) {
    1055                         res = that.meetSegmentSegment(
    1056                             el1.point1.coords.usrCoords,
    1057                             el1.point2.coords.usrCoords,
    1058                             el2.point1.coords.usrCoords,
    1059                             el2.point2.coords.usrCoords,
    1060                             el1.board
    1061                         );
    1062
    1063                         if ((!first1 && res[1] < 0) || (!last1 && res[1] > 1) ||
    1064                                 (!first2 && res[2] < 0) || (!last2 && res[2] > 1)) {
    1065                             // Non-existent
    1066                             c = [0, NaN, NaN];
    1067                         } else {
    1068                             c = res[0];
    1069                         }
    1070
    1071                         return (new Coords(Const.COORDS_BY_USER, c, el1.board));
    1072                     }
    1073
    1074                     return that.meet(el1.stdform, el2.stdform, i, el1.board);
    1075                 };
    1076             } else {
    1077                 // All other combinations of circles and lines
    1078                 /** @ignore */
    1079                 func = function () {
    1080                     return that.meet(el1.stdform, el2.stdform, i, el1.board);
    1081                 };
    1082             }
    1083
    1084             return func;
    1085         },
    1086
    1087         /**
    1088          * Computes the intersection of a pair of lines, circles or both.
    1089          * It uses the internal data array stdform of these elements.
    1090          * @param {Array} el1 stdform of the first element (line or circle)
    1091          * @param {Array} el2 stdform of the second element (line or circle)
    1092          * @param {Number} i Index of the intersection point that should be returned.
    1093          * @param board Reference to the board.
    1094          * @returns {JXG.Coords} Coordinates of one of the possible two or more intersection points.
    1095          * Which point will be returned is determined by i.
    1096          */
    1097         meet: function (el1, el2, i, board) {
    1098             var result,
    1099                 eps = Mat.eps;
    1100
    1101             // line line
    1102             if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) < eps) {
    1103                 result = this.meetLineLine(el1, el2, i, board);
    1104             // circle line
    1105             } else if (Math.abs(el1[3]) >= eps && Math.abs(el2[3]) < eps) {
    1106                 result = this.meetLineCircle(el2, el1, i, board);
    1107             // line circle
    1108             } else if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) >= eps) {
    1109                 result = this.meetLineCircle(el1, el2, i, board);
    1110             // circle circle
    1111             } else {
    1112                 result = this.meetCircleCircle(el1, el2, i, board);
    1113             }
    1114
    1115             return result;
    1116         },
    1117
    1118         /**
    1119          * Intersection of the line with the board
    1120          * @param  {Array}     line   stdform of the line in screen coordinates
    1121          * @param  {JXG.Board} board  reference to a board.
    1122          * @param  {Number}    margin optional margin, to avoid the display of the small sides of lines.
    1123          * @returns {Array}            [intersection coords 1, intersection coords 2]
    1124          */
    1125         meetLineBoard: function (line, board, margin) {
    1126              // Intersect the line with the four borders of the board.
    1127             var s = [], intersect1, intersect2, i, j;
    1128
    1129             if (!Type.exists(margin)) {
    1130                 margin = 0;
    1131             }
    1132
    1133             // top
    1134             s[0] = Mat.crossProduct(line, [margin, 0, 1]);
    1135             // left
    1136             s[1] = Mat.crossProduct(line, [margin, 1, 0]);
    1137             // bottom
    1138             s[2] = Mat.crossProduct(line, [-margin - board.canvasHeight, 0, 1]);
    1139             // right
    1140             s[3] = Mat.crossProduct(line, [-margin - board.canvasWidth, 1, 0]);
    1141
    1142             // Normalize the intersections
    1143             for (i = 0; i < 4; i++) {
    1144                 if (Math.abs(s[i][0]) > Mat.eps) {
    1145                     for (j = 2; j > 0; j--) {
    1146                         s[i][j] /= s[i][0];
    1147                     }
    1148                     s[i][0] = 1.0;
    1149                 }
    1150             }
    1151
    1152             // line is parallel to "left", take "top" and "bottom"
    1153             if (Math.abs(s[1][0]) < Mat.eps) {
    1154                 intersect1 = s[0];                          // top
    1155                 intersect2 = s[2];                          // bottom
    1156             // line is parallel to "top", take "left" and "right"
    1157             } else if (Math.abs(s[0][0]) < Mat.eps) {
    1158                 intersect1 = s[1];                          // left
    1159                 intersect2 = s[3];                          // right
    1160             // left intersection out of board (above)
    1161             } else if (s[1][2] < 0) {
    1162                 intersect1 = s[0];                          // top
    1163
    1164                 // right intersection out of board (below)
    1165                 if (s[3][2] > board.canvasHeight) {
    1166                     intersect2 = s[2];                      // bottom
    1167                 } else {
    1168                     intersect2 = s[3];                      // right
    1169                 }
    1170             // left intersection out of board (below)
    1171             } else if (s[1][2] > board.canvasHeight) {
    1172                 intersect1 = s[2];                          // bottom
    1173
    1174                 // right intersection out of board (above)
    1175                 if (s[3][2] < 0) {
    1176                     intersect2 = s[0];                      // top
    1177                 } else {
    1178                     intersect2 = s[3];                      // right
    1179                 }
    1180             } else {
    1181                 intersect1 = s[1];                          // left
    1182
    1183                 // right intersection out of board (above)
    1184                 if (s[3][2] < 0) {
    1185                     intersect2 = s[0];                      // top
    1186                 // right intersection out of board (below)
    1187                 } else if (s[3][2] > board.canvasHeight) {
    1188                     intersect2 = s[2];                      // bottom
    1189                 } else {
    1190                     intersect2 = s[3];                      // right
    1191                 }
    1192             }
    1193
    1194             intersect1 = new Coords(Const.COORDS_BY_SCREEN, intersect1.slice(1), board);
    1195             intersect2 = new Coords(Const.COORDS_BY_SCREEN, intersect2.slice(1), board);
    1196             return [intersect1, intersect2];
    1197         },
    1198
    1199         /**
    1200          * Intersection of two lines.
    1201          * @param {Array} l1 stdform of the first line
    1202          * @param {Array} l2 stdform of the second line
    1203          * @param {number} i unused
    1204          * @param {JXG.Board} board Reference to the board.
    1205          * @returns {JXG.Coords} Coordinates of the intersection point.
    1206          */
    1207         meetLineLine: function (l1, l2, i, board) {
    1208             /*
    1209             var s = Mat.crossProduct(l1, l2);
    1210
    1211             if (Math.abs(s[0]) > Mat.eps) {
    1212                 s[1] /= s[0];
    1213                 s[2] /= s[0];
    1214                 s[0] = 1.0;
    1215             }
    1216             */
    1217             var s = isNaN(l1[5] + l2[5]) ? [0, 0, 0] : Mat.crossProduct(l1, l2);
    1218             return new Coords(Const.COORDS_BY_USER, s, board);
    1219         },
    1220
    1221         /**
    1222          * Intersection of line and circle.
    1223          * @param {Array} lin stdform of the line
    1224          * @param {Array} circ stdform of the circle
    1225          * @param {number} i number of the returned intersection point.
    1226          *   i==0: use the positive square root,
    1227          *   i==1: use the negative square root.
    1228          * @param {JXG.Board} board Reference to a board.
    1229          * @returns {JXG.Coords} Coordinates of the intersection point
    1230          */
    1231         meetLineCircle: function (lin, circ, i, board) {
    1232             var a, b, c, d, n,
    1233                 A, B, C, k, t;
    1234
    1235             // Radius is zero, return center of circle
    1236             if (circ[4] < Mat.eps) {
    1237                 if (Math.abs(Mat.innerProduct([1, circ[6], circ[7]], lin, 3)) < Mat.eps) {
    1238                     return new Coords(Const.COORDS_BY_USER, circ.slice(6, 8), board);
    1239                 }
    1240
    1241                 return new Coords(Const.COORDS_BY_USER, [NaN, NaN], board);
    1242             }
    1243
    1244             c = circ[0];
    1245             b = circ.slice(1, 3);
    1246             a = circ[3];
    1247             d = lin[0];
    1248             n = lin.slice(1, 3);
    1249
    1250             // Line is assumed to be normalized. Therefore, nn==1 and we can skip some operations:
    1251             /*
    1252              var nn = n[0]*n[0]+n[1]*n[1];
    1253              A = a*nn;
    1254              B = (b[0]*n[1]-b[1]*n[0])*nn;
    1255              C = a*d*d - (b[0]*n[0]+b[1]*n[1])*d + c*nn;
    1256              */
    1257             A = a;
    1258             B = (b[0] * n[1] - b[1] * n[0]);
    1259             C = a * d * d - (b[0] * n[0] + b[1] * n[1]) * d + c;
    1260
    1261             k = B * B - 4 * A * C;
    1262             if (k > -Mat.eps * Mat.eps) {
    1263                 k = Math.sqrt(Math.abs(k));
    1264                 t = [(-B + k) / (2 * A), (-B - k) / (2 * A)];
    1265
    1266                 return ((i === 0) ?
    1267                         new Coords(Const.COORDS_BY_USER, [-t[0] * (-n[1]) - d * n[0], -t[0] * n[0] - d * n[1]], board) :
    1268                         new Coords(Const.COORDS_BY_USER, [-t[1] * (-n[1]) - d * n[0], -t[1] * n[0] - d * n[1]], board)
    1269                     );
    1270             }
    1271
    1272             return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);
    1273         },
    1274
    1275         /**
    1276          * Intersection of two circles.
    1277          * @param {Array} circ1 stdform of the first circle
    1278          * @param {Array} circ2 stdform of the second circle
    1279          * @param {number} i number of the returned intersection point.
    1280          *   i==0: use the positive square root,
    1281          *   i==1: use the negative square root.
    1282          * @param {JXG.Board} board Reference to the board.
    1283          * @returns {JXG.Coords} Coordinates of the intersection point
    1284          */
    1285         meetCircleCircle: function (circ1, circ2, i, board) {
    1286             var radicalAxis;
    1287
    1288             // Radius is zero, return center of circle, if on other circle
    1289             if (circ1[4] < Mat.eps) {
    1290                 if (Math.abs(this.distance(circ1.slice(6, 2), circ2.slice(6, 8)) - circ2[4]) < Mat.eps) {
    1291                     return new Coords(Const.COORDS_BY_USER, circ1.slice(6, 8), board);
    1292                 }
    1293
    1294                 return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);
    1295             }
    1296
    1297             // Radius is zero, return center of circle, if on other circle
    1298             if (circ2[4] < Mat.eps) {
    1299                 if (Math.abs(this.distance(circ2.slice(6, 2), circ1.slice(6, 8)) - circ1[4]) < Mat.eps) {
    1300                     return new Coords(Const.COORDS_BY_USER, circ2.slice(6, 8), board);
    1301                 }
    1302
    1303                 return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);
    1304             }
    1305
    1306             radicalAxis = [circ2[3] * circ1[0] - circ1[3] * circ2[0],
    1307                 circ2[3] * circ1[1] - circ1[3] * circ2[1],
    1308                 circ2[3] * circ1[2] - circ1[3] * circ2[2],
    1309                 0, 1, Infinity, Infinity, Infinity];
    1310             radicalAxis = Mat.normalize(radicalAxis);
    1311
    1312             return this.meetLineCircle(radicalAxis, circ1, i, board);
    1313         },
    1314
    1315         /**
    1316          * Compute an intersection of the curves c1 and c2.
    1317          * We want to find values t1, t2 such that
    1318          * c1(t1) = c2(t2), i.e. (c1_x(t1)-c2_x(t2),c1_y(t1)-c2_y(t2)) = (0,0).
    1319          *
    1320          * Methods: segment-wise intersections (default) or generalized Newton method.
    1321          * @param {JXG.Curve} c1 Curve, Line or Circle
    1322          * @param {JXG.Curve} c2 Curve, Line or Circle
    1323          * @param {Number} nr the nr-th intersection point will be returned.
    1324          * @param {Number} t2ini not longer used.
    1325          * @param {JXG.Board} [board=c1.board] Reference to a board object.
    1326          * @param {String} [method='segment'] Intersection method, possible values are 'newton' and 'segment'.
    1327          * @returns {JXG.Coords} intersection point
    1328          */
    1329         meetCurveCurve: function (c1, c2, nr, t2ini, board, method) {
    1330             var co;
    1331
    1332             if (Type.exists(method) && method === 'newton') {
    1333                 co = Numerics.generalizedNewton(c1, c2, nr, t2ini);
    1334             } else {
    1335                 if (c1.bezierDegree === 3 && c2.bezierDegree === 3) {
    1336                     co = this.meetBezierCurveRedBlueSegments(c1, c2, nr);
    1337                 } else {
    1338                     co = this.meetCurveRedBlueSegments(c1, c2, nr);
    1339                 }
    1340             }
    1341
    1342             return (new Coords(Const.COORDS_BY_USER, co, board));
    1343         },
    1344
    1345         /**
    1346          * Intersection of curve with line,
    1347          * Order of input does not matter for el1 and el2.
    1348          * From version 0.99.7 on this method calls
    1349          * {@link JXG.Math.Geometry.meetCurveLineDiscrete}.
    1350          * If higher precision is needed, {@link JXG.Math.Geometry.meetCurveLineContinuous}
    1351          * has to be used.
    1352          *
    1353          * @param {JXG.Curve,JXG.Line} el1 Curve or Line
    1354          * @param {JXG.Curve,JXG.Line} el2 Curve or Line
    1355          * @param {Number} nr the nr-th intersection point will be returned.
    1356          * @param {JXG.Board} [board=el1.board] Reference to a board object.
    1357          * @param {Boolean} alwaysIntersect If false just the segment between the two defining points are tested for intersection
    1358          * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,
    1359          * the ideal point [0,1,0] is returned.
    1360          */
    1361         meetCurveLine: function (el1, el2, nr, board, alwaysIntersect) {
    1362             var v = [0, NaN, NaN], cu, li;
    1363
    1364             if (!Type.exists(board)) {
    1365                 board = el1.board;
    1366             }
    1367
    1368             if (el1.elementClass === Const.OBJECT_CLASS_CURVE) {
    1369                 cu = el1;
    1370                 li = el2;
    1371             } else {
    1372                 cu = el2;
    1373                 li = el1;
    1374             }
    1375
    1376             // if (Type.evaluate(cu.visProp.curvetype) === 'plot') {
    1377                 v = this.meetCurveLineDiscrete(cu, li, nr, board, !alwaysIntersect);
    1378             // } else {
    1379             //     v = this.meetCurveLineContinuous(cu, li, nr, board);
    1380             // }
    1381
    1382             return v;
    1383         },
    1384
    1385         /**
    1386          * Intersection of line and curve, continuous case.
    1387          * Finds the nr-the intersection point
    1388          * Uses {@link JXG.Math.Geometry.meetCurveLineDiscrete} as a first approximation.
    1389          * A more exact solution is then found with {@link JXG.Math.Numerics.root}.
    1390          *
    1391          * @param {JXG.Curve} cu Curve
    1392          * @param {JXG.Line} li Line
    1393          * @param {Number} nr Will return the nr-th intersection point.
    1394          * @param {JXG.Board} board
    1395          *
    1396          */
    1397         meetCurveLineContinuous: function (cu, li, nr, board, testSegment) {
    1398             var t, func0, func1, func0a, v, x, y, z,
    1399                 eps = Mat.eps,
    1400                 epsLow = Mat.eps,
    1401                 steps, delta, tnew, i,
    1402                 tmin, fmin, ft;
    1403
    1404             v = this.meetCurveLineDiscrete(cu, li, nr, board, testSegment);
    1405             x = v.usrCoords[1];
    1406             y = v.usrCoords[2];
    1407
    1408             func0 = function (t) {
    1409                 var c1, c2;
    1410
    1411                 if (t > cu.maxX() || t < cu.minX()) {
    1412                     return Infinity;
    1413                 }
    1414                 c1 = x - cu.X(t);
    1415                 c2 = y - cu.Y(t);
    1416                 return c1 * c1 + c2 * c2;
    1417             };
    1418
    1419             func1 = function (t) {
    1420                 var v = li.stdform[0] + li.stdform[1] * cu.X(t) + li.stdform[2] * cu.Y(t);
    1421                 return v * v;
    1422             };
    1423
    1424             // Find t
    1425             steps = 50;
    1426             delta = (cu.maxX() - cu.minX()) / steps;
    1427             tnew = cu.minX();
    1428
    1429             fmin = 0.0001; //eps;
    1430             tmin = NaN;
    1431             for (i = 0; i < steps; i++) {
    1432                 t = Numerics.root(func0, [Math.max(tnew, cu.minX()), Math.min(tnew + delta, cu.maxX())]);
    1433                 ft = Math.abs(func0(t));
    1434                 if (ft <= fmin) {
    1435                     fmin = ft;
    1436                     tmin = t;
    1437                     if (fmin < eps) {
    1438                         break;
    1439                     }
    1440                 }
    1441
    1442                 tnew += delta;
    1443             }
    1444             t = tmin;
    1445             // Compute "exact" t
    1446             t = Numerics.root(func1, [Math.max(t - delta, cu.minX()), Math.min(t + delta, cu.maxX())]);
    1447
    1448             ft = func1(t);
    1449             // Is the point on the line?
    1450             if (isNaN(ft) || Math.abs(ft) > epsLow) {
    1451                 z = 0.0; //NaN;
    1452             } else {
    1453                 z = 1.0;
    1454             }
    1455
    1456             return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board));
    1457         },
    1458
    1459         /**
    1460          * Intersection of line and curve, continuous case.
    1461          * Segments are treated as lines. Finding the nr-the intersection point
    1462          * works for nr=0,1 only.
    1463          *
    1464          * @private
    1465          * @deprecated
    1466          * @param {JXG.Curve} cu Curve
    1467          * @param {JXG.Line} li Line
    1468          * @param {Number} nr Will return the nr-th intersection point.
    1469          * @param {JXG.Board} board
    1470          *
    1471          * BUG: does not respect cu.minX() and cu.maxX()
    1472          */
    1473         meetCurveLineContinuousOld: function (cu, li, nr, board) {
    1474             var t, t2, i, func, z,
    1475                 tnew, steps, delta, tstart, tend, cux, cuy,
    1476                 eps = Mat.eps * 10;
    1477
    1478             JXG.deprecated('Geometry.meetCurveLineContinuousOld()', 'Geometry.meetCurveLineContinuous()');
    1479             func = function (t) {
    1480                 var v = li.stdform[0] + li.stdform[1] * cu.X(t) + li.stdform[2] * cu.Y(t);
    1481                 return v * v;
    1482             };
    1483
    1484             // Find some intersection point
    1485             if (this.meetCurveLineContinuous.t1memo) {
    1486                 tstart = this.meetCurveLineContinuous.t1memo;
    1487                 t = Numerics.root(func, tstart);
    1488             } else {
    1489                 tstart = cu.minX();
    1490                 tend = cu.maxX();
    1491                 t = Numerics.root(func, [tstart, tend]);
    1492             }
    1493
    1494             this.meetCurveLineContinuous.t1memo = t;
    1495             cux = cu.X(t);
    1496             cuy = cu.Y(t);
    1497
    1498             // Find second intersection point
    1499             if (nr === 1) {
    1500                 if (this.meetCurveLineContinuous.t2memo) {
    1501                     tstart = this.meetCurveLineContinuous.t2memo;
    1502                 }
    1503                 t2 = Numerics.root(func, tstart);
    1504
    1505                 if (!(Math.abs(t2 - t) > 0.1 && Math.abs(cux - cu.X(t2)) > 0.1 && Math.abs(cuy - cu.Y(t2)) > 0.1)) {
    1506                     steps = 20;
    1507                     delta = (cu.maxX() - cu.minX()) / steps;
    1508                     tnew = cu.minX();
    1509
    1510                     for (i = 0; i < steps; i++) {
    1511                         t2 = Numerics.root(func, [tnew, tnew + delta]);
    1512
    1513                         if (Math.abs(func(t2)) <= eps && Math.abs(t2 - t) > 0.1 && Math.abs(cux - cu.X(t2)) > 0.1 && Math.abs(cuy - cu.Y(t2)) > 0.1) {
    1514                             break;
    1515                         }
    1516
    1517                         tnew += delta;
    1518                     }
    1519                 }
    1520                 t = t2;
    1521                 this.meetCurveLineContinuous.t2memo = t;
    1522             }
    1523
    1524             // Is the point on the line?
    1525             if (Math.abs(func(t)) > eps) {
    1526                 z = NaN;
    1527             } else {
    1528                 z = 1.0;
    1529             }
    1530
    1531             return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board));
    1532         },
    1533
    1534         /**
    1535          * Intersection of line and curve, discrete case.
    1536          * Segments are treated as lines.
    1537          * Finding the nr-th intersection point should work for all nr.
    1538          * @param {JXG.Curve} cu
    1539          * @param {JXG.Line} li
    1540          * @param {Number} nr
    1541          * @param {JXG.Board} board
    1542          * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the
    1543          * line defined by the segment
    1544          *
    1545          * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,
    1546          * the ideal point [0,1,0] is returned.
    1547          */
    1548         meetCurveLineDiscrete: function (cu, li, nr, board, testSegment) {
    1549             var i, j,
    1550                 p1, p2, p, q,
    1551                 lip1 = li.point1.coords.usrCoords,
    1552                 lip2 = li.point2.coords.usrCoords,
    1553                 d, res,
    1554                 cnt = 0,
    1555                 len = cu.numberPoints,
    1556                 ev_sf = Type.evaluate(li.visProp.straightfirst),
    1557                 ev_sl = Type.evaluate(li.visProp.straightlast);
    1558
    1559             // In case, no intersection will be found we will take this
    1560             q = new Coords(Const.COORDS_BY_USER, [0, NaN, NaN], board);
    1561
    1562             if (lip1[0] === 0.0) {
    1563                 lip1 = [1, lip2[1] + li.stdform[2], lip2[2] - li.stdform[1]];
    1564             } else if (lip2[0] === 0.0) {
    1565                 lip2 = [1, lip1[1] + li.stdform[2], lip1[2] - li.stdform[1]];
    1566             }
    1567
    1568             p2 = cu.points[0].usrCoords;
    1569             for (i = 1; i < len; i++) {
    1570                 p1 = p2.slice(0);
    1571                 p2 = cu.points[i].usrCoords;
    1572                 d = this.distance(p1, p2);
    1573
    1574                 // The defining points are not identical
    1575                 if (d > Mat.eps) {
    1576                     if (cu.bezierDegree === 3) {
    1577                         res = this.meetBeziersegmentBeziersegment([
    1578                             cu.points[i - 1].usrCoords.slice(1),
    1579                             cu.points[i].usrCoords.slice(1),
    1580                             cu.points[i + 1].usrCoords.slice(1),
    1581                             cu.points[i + 2].usrCoords.slice(1)
    1582                         ], [
    1583                             lip1.slice(1),
    1584                             lip2.slice(1)
    1585                         ], testSegment);
    1586
    1587                         i += 2;
    1588                     } else {
    1589                         res = [this.meetSegmentSegment(p1, p2, lip1, lip2)];
    1590                     }
    1591
    1592                     for (j = 0; j < res.length; j++) {
    1593                         p = res[j];
    1594                         if (0 <= p[1] && p[1] <= 1) {
    1595                             if (cnt === nr) {
    1596                                 /**
    1597                                 * If the intersection point is not part of the segment,
    1598                                 * this intersection point is set to non-existent.
    1599                                 * This prevents jumping of the intersection points.
    1600                                 * But it may be discussed if it is the desired behavior.
    1601                                 */
    1602                                 if (testSegment &&
    1603                                         ((!ev_sf && p[2] < 0) || (!ev_sl && p[2] > 1))) {
    1604                                     return q;  // break;
    1605                                 }
    1606
    1607                                 q = new Coords(Const.COORDS_BY_USER, p[0], board);
    1608                                 return q;      // break;
    1609                             }
    1610                             cnt += 1;
    1611                         }
    1612                     }
    1613                 }
    1614             }
    1615
    1616             return q;
    1617         },
    1618
    1619         /**
    1620          * Find the n-th intersection point of two curves named red (first parameter) and blue (second parameter).
    1621          * We go through each segment of the red curve and search if there is an intersection with a segemnt of the blue curve.
    1622          * This double loop, i.e. the outer loop runs along the red curve and the inner loop runs along the blue curve, defines
    1623          * the n-th intersection point. The segments are either line segments or Bezier curves of degree 3. This depends on
    1624          * the property bezierDegree of the curves.
    1625          * <p>
    1626          * This method works also for transformed curves, since only the already
    1627          * transformed points are used.
    1628          *
    1629          * @param {JXG.Curve} red
    1630          * @param {JXG.Curve} blue
    1631          * @param {Number} nr
    1632          */
    1633         meetCurveRedBlueSegments: function (red, blue, nr) {
    1634             var i, j,
    1635                 red1, red2, blue1, blue2, m,
    1636                 minX, maxX,
    1637                 iFound = 0,
    1638                 lenBlue = blue.numberPoints, //points.length,
    1639                 lenRed = red.numberPoints; //points.length;
    1640
    1641             if (lenBlue <= 1 || lenRed <= 1) {
    1642                 return [0, NaN, NaN];
    1643             }
    1644
    1645             for (i = 1; i < lenRed; i++) {
    1646                 red1 = red.points[i - 1].usrCoords;
    1647                 red2 = red.points[i].usrCoords;
    1648                 minX = Math.min(red1[1], red2[1]);
    1649                 maxX = Math.max(red1[1], red2[1]);
    1650
    1651                 blue2 = blue.points[0].usrCoords;
    1652                 for (j = 1; j < lenBlue; j++) {
    1653                     blue1 = blue2;
    1654                     blue2 = blue.points[j].usrCoords;
    1655
    1656                     if (Math.min(blue1[1], blue2[1]) < maxX && Math.max(blue1[1], blue2[1]) > minX) {
    1657                         m = this.meetSegmentSegment(red1, red2, blue1, blue2);
    1658                         if (m[1] >= 0.0 && m[2] >= 0.0 &&
    1659                                 // The two segments meet in the interior or at the start points
    1660                                 ((m[1] < 1.0 && m[2] < 1.0) ||
    1661                                 // One of the curve is intersected in the very last point
    1662                                 (i === lenRed - 1 && m[1] === 1.0) ||
    1663                                 (j === lenBlue - 1 && m[2] === 1.0))) {
    1664                             if (iFound === nr) {
    1665                                 return m[0];
    1666                             }
    1667
    1668                             iFound++;
    1669                         }
    1670                     }
    1671                 }
    1672             }
    1673
    1674             return [0, NaN, NaN];
    1675         },
    1676
    1677         /**
    1678          * Intersection of two segments.
    1679          * @param {Array} p1 First point of segment 1 using homogeneous coordinates [z,x,y]
    1680          * @param {Array} p2 Second point of segment 1 using homogeneous coordinates [z,x,y]
    1681          * @param {Array} q1 First point of segment 2 using homogeneous coordinates [z,x,y]
    1682          * @param {Array} q2 Second point of segment 2 using homogeneous coordinates [z,x,y]
    1683          * @returns {Array} [Intersection point, t, u] The first entry contains the homogeneous coordinates
    1684          * of the intersection point. The second and third entry gives the position of the intersection between the
    1685          * two defining points. For example, the second entry t is defined by: intersection point = t*p1 + (1-t)*p2.
    1686          **/
    1687         meetSegmentSegment: function (p1, p2, q1, q2) {
    1688             var t, u, diff,
    1689                 li1 = Mat.crossProduct(p1, p2),
    1690                 li2 = Mat.crossProduct(q1, q2),
    1691                 c = Mat.crossProduct(li1, li2),
    1692                 denom = c[0];
    1693
    1694             if (Math.abs(denom) < Mat.eps) {
    1695                 return [c, Infinity, Infinity];
    1696             }
    1697
    1698             diff = [q1[1] - p1[1], q1[2] - p1[2]];
    1699
    1700             // Because of speed issues, evalute the determinants directly
    1701             t = (diff[0] * (q2[2] - q1[2]) - diff[1] * (q2[1] - q1[1])) / denom;
    1702             u = (diff[0] * (p2[2] - p1[2]) - diff[1] * (p2[1] - p1[1])) / denom;
    1703
    1704             return [c, t, u];
    1705         },
    1706
    1707         /****************************************/
    1708         /****   BEZIER CURVE ALGORITHMS      ****/
    1709         /****************************************/
    1710
    1711         /**
    1712          * Splits a Bezier curve segment defined by four points into
    1713          * two Bezier curve segments. Dissection point is t=1/2.
    1714          * @param {Array} curve Array of four coordinate arrays of length 2 defining a
    1715          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
    1716          * @returns {Array} Array consisting of two coordinate arrays for Bezier curves.
    1717          */
    1718         _bezierSplit: function (curve) {
    1719             var p0, p1, p2, p00, p22, p000;
    1720
    1721             p0 = [(curve[0][0] + curve[1][0]) * 0.5, (curve[0][1] + curve[1][1]) * 0.5];
    1722             p1 = [(curve[1][0] + curve[2][0]) * 0.5, (curve[1][1] + curve[2][1]) * 0.5];
    1723             p2 = [(curve[2][0] + curve[3][0]) * 0.5, (curve[2][1] + curve[3][1]) * 0.5];
    1724
    1725             p00 = [(p0[0] + p1[0]) * 0.5, (p0[1] + p1[1]) * 0.5];
    1726             p22 = [(p1[0] + p2[0]) * 0.5, (p1[1] + p2[1]) * 0.5];
    1727
    1728             p000 = [(p00[0] + p22[0]) * 0.5, (p00[1] + p22[1]) * 0.5];
    1729
    1730             return [[curve[0], p0, p00, p000], [p000, p22, p2, curve[3]]];
    1731         },
    1732
    1733         /**
    1734          * Computes the bounding box [minX, maxY, maxX, minY] of a Bezier curve segment
    1735          * from its control points.
    1736          * @param {Array} curve Array of four coordinate arrays of length 2 defining a
    1737          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
    1738          * @returns {Array} Bounding box [minX, maxY, maxX, minY]
    1739          */
    1740         _bezierBbox: function (curve) {
    1741             var bb = [];
    1742
    1743             if (curve.length === 4) {   // bezierDegree == 3
    1744                 bb[0] = Math.min(curve[0][0], curve[1][0], curve[2][0], curve[3][0]); // minX
    1745                 bb[1] = Math.max(curve[0][1], curve[1][1], curve[2][1], curve[3][1]); // maxY
    1746                 bb[2] = Math.max(curve[0][0], curve[1][0], curve[2][0], curve[3][0]); // maxX
    1747                 bb[3] = Math.min(curve[0][1], curve[1][1], curve[2][1], curve[3][1]); // minY
    1748             } else {                   // bezierDegree == 1
    1749                 bb[0] = Math.min(curve[0][0], curve[1][0]); // minX
    1750                 bb[1] = Math.max(curve[0][1], curve[1][1]); // maxY
    1751                 bb[2] = Math.max(curve[0][0], curve[1][0]); // maxX
    1752                 bb[3] = Math.min(curve[0][1], curve[1][1]); // minY
    1753             }
    1754
    1755             return bb;
    1756         },
    1757
    1758         /**
    1759          * Decide if two Bezier curve segments overlap by comparing their bounding boxes.
    1760          * @param {Array} bb1 Bounding box of the first Bezier curve segment
    1761          * @param {Array} bb2 Bounding box of the second Bezier curve segment
    1762          * @returns {Boolean} true if the bounding boxes overlap, false otherwise.
    1763          */
    1764         _bezierOverlap: function (bb1, bb2) {
    1765             return bb1[2] >= bb2[0] && bb1[0] <= bb2[2] && bb1[1] >= bb2[3] && bb1[3] <= bb2[1];
    1766         },
    1767
    1768         /**
    1769          * Append list of intersection points to a list.
    1770          * @private
    1771          */
    1772         _bezierListConcat: function (L, Lnew, t1, t2) {
    1773             var i,
    1774                 t2exists = Type.exists(t2),
    1775                 start = 0,
    1776                 len = Lnew.length,
    1777                 le = L.length;
    1778
    1779             if (le > 0 && len > 0 &&
    1780                     ((L[le - 1][1] === 1 && Lnew[0][1] === 0) ||
    1781                     (t2exists && L[le - 1][2] === 1 && Lnew[0][2] === 0))) {
    1782                 start = 1;
    1783             }
    1784
    1785             for (i = start; i < len; i++) {
    1786                 if (t2exists) {
    1787                     Lnew[i][2] *= 0.5;
    1788                     Lnew[i][2] += t2;
    1789                 }
    1790
    1791                 Lnew[i][1] *= 0.5;
    1792                 Lnew[i][1] += t1;
    1793
    1794                 L.push(Lnew[i]);
    1795             }
    1796         },
    1797
    1798         /**
    1799          * Find intersections of two Bezier curve segments by recursive subdivision.
    1800          * Below maxlevel determine intersections by intersection line segments.
    1801          * @param {Array} red Array of four coordinate arrays of length 2 defining the first
    1802          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
    1803          * @param {Array} blue Array of four coordinate arrays of length 2 defining the second
    1804          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
    1805          * @param {Number} level Recursion level
    1806          * @returns {Array} List of intersection points (up to nine). Each intersection point is an
    1807          * array of length three (homogeneous coordinates) plus preimages.
    1808          */
    1809         _bezierMeetSubdivision: function (red, blue, level) {
    1810             var bbb, bbr,
    1811                 ar, b0, b1, r0, r1, m,
    1812                 p0, p1, q0, q1,
    1813                 L = [],
    1814                 maxLev = 5;      // Maximum recursion level
    1815
    1816             bbr = this._bezierBbox(blue);
    1817             bbb = this._bezierBbox(red);
    1818
    1819             if (!this._bezierOverlap(bbr, bbb)) {
    1820                 return [];
    1821             }
    1822
    1823             if (level < maxLev) {
    1824                 ar = this._bezierSplit(red);
    1825                 r0 = ar[0];
    1826                 r1 = ar[1];
    1827
    1828                 ar = this._bezierSplit(blue);
    1829                 b0 = ar[0];
    1830                 b1 = ar[1];
    1831
    1832                 this._bezierListConcat(L, this._bezierMeetSubdivision(r0, b0, level + 1), 0.0, 0.0);
    1833                 this._bezierListConcat(L, this._bezierMeetSubdivision(r0, b1, level + 1), 0, 0.5);
    1834                 this._bezierListConcat(L, this._bezierMeetSubdivision(r1, b0, level + 1), 0.5, 0.0);
    1835                 this._bezierListConcat(L, this._bezierMeetSubdivision(r1, b1, level + 1), 0.5, 0.5);
    1836
    1837                 return L;
    1838             }
    1839
    1840             // Make homogeneous coordinates
    1841             q0 = [1].concat(red[0]);
    1842             q1 = [1].concat(red[3]);
    1843             p0 = [1].concat(blue[0]);
    1844             p1 = [1].concat(blue[3]);
    1845
    1846             m = this.meetSegmentSegment(q0, q1, p0, p1);
    1847
    1848             if (m[1] >= 0.0 && m[2] >= 0.0 && m[1] <= 1.0 && m[2] <= 1.0) {
    1849                 return [m];
    1850             }
    1851
    1852             return [];
    1853         },
    1854
    1855         /**
    1856          * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the line defined by the segment
    1857          */
    1858         _bezierLineMeetSubdivision: function (red, blue, level, testSegment) {
    1859             var bbb, bbr,
    1860                 ar, r0, r1, m,
    1861                 p0, p1, q0, q1,
    1862                 L = [],
    1863                 maxLev = 5;      // Maximum recursion level
    1864
    1865             bbb = this._bezierBbox(blue);
    1866             bbr = this._bezierBbox(red);
    1867
    1868             if (testSegment && !this._bezierOverlap(bbr, bbb)) {
    1869                 return [];
    1870             }
    1871
    1872             if (level < maxLev) {
    1873                 ar = this._bezierSplit(red);
    1874                 r0 = ar[0];
    1875                 r1 = ar[1];
    1876
    1877                 this._bezierListConcat(L, this._bezierLineMeetSubdivision(r0, blue, level + 1), 0.0);
    1878                 this._bezierListConcat(L, this._bezierLineMeetSubdivision(r1, blue, level + 1), 0.5);
    1879
    1880                 return L;
    1881             }
    1882
    1883             // Make homogeneous coordinates
    1884             q0 = [1].concat(red[0]);
    1885             q1 = [1].concat(red[3]);
    1886             p0 = [1].concat(blue[0]);
    1887             p1 = [1].concat(blue[1]);
    1888
    1889             m = this.meetSegmentSegment(q0, q1, p0, p1);
    1890
    1891             if (m[1] >= 0.0 && m[1] <= 1.0) {
    1892                 if (!testSegment || (m[2] >= 0.0 && m[2] <= 1.0)) {
    1893                     return [m];
    1894                 }
    1895             }
    1896
    1897             return [];
    1898         },
    1899
    1900         /**
    1901          * Find the nr-th intersection point of two Bezier curve segments.
    1902          * @param {Array} red Array of four coordinate arrays of length 2 defining the first
    1903          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
    1904          * @param {Array} blue Array of four coordinate arrays of length 2 defining the second
    1905          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
    1906          * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the line defined by the segment
    1907          * @returns {Array} Array containing the list of all intersection points as homogeneous coordinate arrays plus
    1908          * preimages [x,y], t_1, t_2] of the two Bezier curve segments.
    1909          *
    1910          */
    1911         meetBeziersegmentBeziersegment: function (red, blue, testSegment) {
    1912             var L, L2, i;
    1913
    1914             if (red.length === 4 && blue.length === 4) {
    1915                 L = this._bezierMeetSubdivision(red, blue, 0);
    1916             } else {
    1917                 L = this._bezierLineMeetSubdivision(red, blue, 0, testSegment);
    1918             }
    1919
    1920             L.sort(function (a, b) {
    1921                 return (a[1] - b[1]) * 10000000.0 + (a[2] - b[2]);
    1922             });
    1923
    1924             L2 = [];
    1925             for (i = 0; i < L.length; i++) {
    1926                 // Only push entries different from their predecessor
    1927                 if (i === 0 || (L[i][1] !== L[i - 1][1] || L[i][2] !== L[i - 1][2])) {
    1928                     L2.push(L[i]);
    1929                 }
    1930             }
    1931             return L2;
    1932         },
    1933
    1934         /**
    1935          * Find the nr-th intersection point of two Bezier curves, i.e. curves with bezierDegree == 3.
    1936          * @param {JXG.Curve} red Curve with bezierDegree == 3
    1937          * @param {JXG.Curve} blue Curve with bezierDegree == 3
    1938          * @param {Number} nr The number of the intersection point which should be returned.
    1939          * @returns {Array} The homogeneous coordinates of the nr-th intersection point.
    1940          */
    1941         meetBezierCurveRedBlueSegments: function (red, blue, nr) {
    1942             var p, i, j,
    1943                 redArr, blueArr,
    1944                 bbr, bbb,
    1945                 lenBlue = blue.numberPoints, //points.length,
    1946                 lenRed = red.numberPoints, // points.length,
    1947                 L = [];
    1948
    1949             if (lenBlue < 4 || lenRed < 4) {
    1950                 return [0, NaN, NaN];
    1951             }
    1952
    1953             for (i = 0; i < lenRed - 3; i += 3) {
    1954                 p = red.points;
    1955                 redArr = [
    1956                     [p[i].usrCoords[1], p[i].usrCoords[2]],
    1957                     [p[i + 1].usrCoords[1], p[i + 1].usrCoords[2]],
    1958                     [p[i + 2].usrCoords[1], p[i + 2].usrCoords[2]],
    1959                     [p[i + 3].usrCoords[1], p[i + 3].usrCoords[2]]
    1960                 ];
    1961
    1962                 bbr = this._bezierBbox(redArr);
    1963
    1964                 for (j = 0; j < lenBlue - 3; j += 3) {
    1965                     p = blue.points;
    1966                     blueArr = [
    1967                         [p[j].usrCoords[1], p[j].usrCoords[2]],
    1968                         [p[j + 1].usrCoords[1], p[j + 1].usrCoords[2]],
    1969                         [p[j + 2].usrCoords[1], p[j + 2].usrCoords[2]],
    1970                         [p[j + 3].usrCoords[1], p[j + 3].usrCoords[2]]
    1971                     ];
    1972
    1973                     bbb = this._bezierBbox(blueArr);
    1974                     if (this._bezierOverlap(bbr, bbb)) {
    1975                         L = L.concat(this.meetBeziersegmentBeziersegment(redArr, blueArr));
    1976                         if (L.length > nr) {
    1977                             return L[nr][0];
    1978                         }
    1979                     }
    1980                 }
    1981             }
    1982             if (L.length > nr) {
    1983                 return L[nr][0];
    1984             }
    1985
    1986             return [0, NaN, NaN];
    1987         },
    1988
    1989         bezierSegmentEval: function (t, curve) {
    1990             var f, x, y,
    1991                 t1 = 1.0 - t;
    1992
    1993             x = 0;
    1994             y = 0;
    1995
    1996             f = t1 * t1 * t1;
    1997             x += f * curve[0][0];
    1998             y += f * curve[0][1];
    1999
    2000             f = 3.0 * t * t1 * t1;
    2001             x += f * curve[1][0];
    2002             y += f * curve[1][1];
    2003
    2004             f = 3.0 * t * t * t1;
    2005             x += f * curve[2][0];
    2006             y += f * curve[2][1];
    2007
    2008             f = t * t * t;
    2009             x += f * curve[3][0];
    2010             y += f * curve[3][1];
    2011
    2012             return [1.0, x, y];
    2013         },
    2014
    2015         /**
    2016          * Generate the defining points of a 3rd degree bezier curve that approximates
    2017          * a circle sector defined by three arrays A, B,C, each of length three.
    2018          * The coordinate arrays are given in homogeneous coordinates.
    2019          * @param {Array} A First point
    2020          * @param {Array} B Second point (intersection point)
    2021          * @param {Array} C Third point
    2022          * @param {Boolean} withLegs Flag. If true the legs to the intersection point are part of the curve.
    2023          * @param {Number} sgn Wither 1 or -1. Needed for minor and major arcs. In case of doubt, use 1.
    2024          */
    2025         bezierArc: function (A, B, C, withLegs, sgn) {
    2026             var p1, p2, p3, p4,
    2027                 r, phi, beta,
    2028                 PI2 = Math.PI * 0.5,
    2029                 x = B[1],
    2030                 y = B[2],
    2031                 z = B[0],
    2032                 dataX = [], dataY = [],
    2033                 co, si, ax, ay, bx, by, k, v, d, matrix;
    2034
    2035             r = this.distance(B, A);
    2036
    2037             // x,y, z is intersection point. Normalize it.
    2038             x /= z;
    2039             y /= z;
    2040
    2041             phi = this.rad(A.slice(1), B.slice(1), C.slice(1));
    2042             if (sgn === -1) {
    2043                 phi = 2 * Math.PI - phi;
    2044             }
    2045
    2046             p1 = A;
    2047             p1[1] /= p1[0];
    2048             p1[2] /= p1[0];
    2049             p1[0] /= p1[0];
    2050
    2051             p4 = p1.slice(0);
    2052
    2053             if (withLegs) {
    2054                 dataX = [x, x + 0.333 * (p1[1] - x), x + 0.666 * (p1[1] - x), p1[1]];
    2055                 dataY = [y, y + 0.333 * (p1[2] - y), y + 0.666 * (p1[2] - y), p1[2]];
    2056             } else {
    2057                 dataX = [p1[1]];
    2058                 dataY = [p1[2]];
    2059             }
    2060
    2061             while (phi > Mat.eps) {
    2062                 if (phi > PI2) {
    2063                     beta = PI2;
    2064                     phi -= PI2;
    2065                 } else {
    2066                     beta = phi;
    2067                     phi = 0;
    2068                 }
    2069
    2070                 co = Math.cos(sgn * beta);
    2071                 si = Math.sin(sgn * beta);
    2072
    2073                 matrix = [
    2074                     [1, 0, 0],
    2075                     [x * (1 - co) + y * si, co, -si],
    2076                     [y * (1 - co) - x * si, si,  co]
    2077                 ];
    2078                 v = Mat.matVecMult(matrix, p1);
    2079                 p4 = [v[0] / v[0], v[1] / v[0], v[2] / v[0]];
    2080
    2081                 ax = p1[1] - x;
    2082                 ay = p1[2] - y;
    2083                 bx = p4[1] - x;
    2084                 by = p4[2] - y;
    2085
    2086                 d = Math.sqrt((ax + bx) * (ax + bx) + (ay + by) * (ay + by));
    2087
    2088                 if (Math.abs(by - ay) > Mat.eps) {
    2089                     k = (ax + bx) * (r / d - 0.5) / (by - ay) * 8 / 3;
    2090                 } else {
    2091                     k = (ay + by) * (r / d - 0.5) / (ax - bx) * 8 / 3;
    2092                 }
    2093
    2094                 p2 = [1, p1[1] - k * ay, p1[2] + k * ax];
    2095                 p3 = [1, p4[1] + k * by, p4[2] - k * bx];
    2096
    2097                 dataX = dataX.concat([p2[1], p3[1], p4[1]]);
    2098                 dataY = dataY.concat([p2[2], p3[2], p4[2]]);
    2099                 p1 = p4.slice(0);
    2100             }
    2101
    2102             if (withLegs) {
    2103                 dataX = dataX.concat([ p4[1] + 0.333 * (x - p4[1]), p4[1] + 0.666 * (x - p4[1]), x]);
    2104                 dataY = dataY.concat([ p4[2] + 0.333 * (y - p4[2]), p4[2] + 0.666 * (y - p4[2]), y]);
    2105             }
    2106
    2107             return [dataX, dataY];
    2108         },
    2109
    2110         /****************************************/
    2111         /****           PROJECTIONS          ****/
    2112         /****************************************/
    2113
    2114         /**
    2115          * Calculates the coordinates of the projection of a given point on a given circle. I.o.w. the
    2116          * nearest one of the two intersection points of the line through the given point and the circles
    2117          * center.
    2118          * @param {JXG.Point,JXG.Coords} point Point to project or coords object to project.
    2119          * @param {JXG.Circle} circle Circle on that the point is projected.
    2120          * @param {JXG.Board} [board=point.board] Reference to the board
    2121          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.
    2122          */
    2123         projectPointToCircle: function (point, circle, board) {
    2124             var dist, P, x, y, factor,
    2125                 M = circle.center.coords.usrCoords;
    2126
    2127             if (!Type.exists(board)) {
    2128                 board = point.board;
    2129             }
    2130
    2131             // gave us a point
    2132             if (Type.isPoint(point)) {
    2133                 dist = point.coords.distance(Const.COORDS_BY_USER, circle.center.coords);
    2134                 P = point.coords.usrCoords;
    2135             // gave us coords
    2136             } else {
    2137                 dist = point.distance(Const.COORDS_BY_USER, circle.center.coords);
    2138                 P = point.usrCoords;
    2139             }
    2140
    2141             if (Math.abs(dist) < Mat.eps) {
    2142                 dist = Mat.eps;
    2143             }
    2144
    2145             factor = circle.Radius() / dist;
    2146             x = M[1] + factor * (P[1] - M[1]);
    2147             y = M[2] + factor * (P[2] - M[2]);
    2148
    2149             return new Coords(Const.COORDS_BY_USER, [x, y], board);
    2150         },
    2151
    2152         /**
    2153          * Calculates the coordinates of the orthogonal projection of a given point on a given line. I.o.w. the
    2154          * intersection point of the given line and its perpendicular through the given point.
    2155          * @param {JXG.Point} point Point to project.
    2156          * @param {JXG.Line} line Line on that the point is projected.
    2157          * @param {JXG.Board} [board=point.board] Reference to a board.
    2158          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given line.
    2159          */
    2160         projectPointToLine: function (point, line, board) {
    2161             // Homogeneous version
    2162             var v = [0, line.stdform[1], line.stdform[2]];
    2163
    2164             if (!Type.exists(board)) {
    2165                 board = point.board;
    2166             }
    2167
    2168             v = Mat.crossProduct(v, point.coords.usrCoords);
    2169             //return this.meetLineLine(v, line.stdform, 0, board);
    2170             return new Coords(Const.COORDS_BY_USER, Mat.crossProduct(v, line.stdform), board);
    2171         },
    2172
    2173         /**
    2174          * Calculates the coordinates of the orthogonal projection of a given coordinate array on a given line
    2175          * segment defined by two coordinate arrays.
    2176          * @param {Array} p Point to project.
    2177          * @param {Array} q1 Start point of the line segment on that the point is projected.
    2178          * @param {Array} q2 End point of the line segment on that the point is projected.
    2179          * @returns {Array} The coordinates of the projection of the given point on the given segment
    2180          * and the factor that determines the projected point as a convex combination of the
    2181          * two endpoints q1 and q2 of the segment.
    2182          */
    2183         projectCoordsToSegment: function (p, q1, q2) {
    2184             var t, denom,
    2185                 s = [q2[1] - q1[1], q2[2] - q1[2]],
    2186                 v = [p[1] - q1[1], p[2] - q1[2]];
    2187
    2188             /**
    2189              * If the segment has length 0, i.e. is a point,
    2190              * the projection is equal to that point.
    2191              */
    2192             if (Math.abs(s[0]) < Mat.eps && Math.abs(s[1]) < Mat.eps) {
    2193                 return [q1, 0];
    2194             }
    2195
    2196             t = Mat.innerProduct(v, s);
    2197             denom = Mat.innerProduct(s, s);
    2198             t /= denom;
    2199
    2200             return [ [1, t * s[0] + q1[1], t * s[1] + q1[2]], t];
    2201         },
    2202
    2203         /**
    2204          * Finds the coordinates of the closest point on a Bezier segment of a
    2205          * {@link JXG.Curve} to a given coordinate array.
    2206          * @param {Array} pos Point to project in homogeneous coordinates.
    2207          * @param {JXG.Curve} curve Curve of type "plot" having Bezier degree 3.
    2208          * @param {Number} start Number of the Bezier segment of the curve.
    2209          * @returns {Array} The coordinates of the projection of the given point
    2210          * on the given Bezier segment and the preimage of the curve which
    2211          * determines the closest point.
    2212          */
    2213         projectCoordsToBeziersegment: function (pos, curve, start) {
    2214             var t0,
    2215                 /** @ignore */
    2216                 minfunc = function (t) {
    2217                     var z = [1, curve.X(start + t), curve.Y(start + t)];
    2218
    2219                     z[1] -= pos[1];
    2220                     z[2] -= pos[2];
    2221
    2222                     return z[1] * z[1] + z[2] * z[2];
    2223                 };
    2224
    2225             t0 = JXG.Math.Numerics.fminbr(minfunc, [0.0, 1.0]);
    2226
    2227             return [[1, curve.X(t0 + start), curve.Y(t0 + start)], t0];
    2228         },
    2229
    2230         /**
    2231          * Calculates the coordinates of the projection of a given point on a given curve.
    2232          * Uses {@link JXG.Math.Geometry.projectCoordsToCurve}.
    2233          *
    2234          * @param {JXG.Point} point Point to project.
    2235          * @param {JXG.Curve} curve Curve on that the point is projected.
    2236          * @param {JXG.Board} [board=point.board] Reference to a board.
    2237          * @see #projectCoordsToCurve
    2238          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given graph.
    2239          */
    2240         projectPointToCurve: function (point, curve, board) {
    2241             if (!Type.exists(board)) {
    2242                 board = point.board;
    2243             }
    2244
    2245             var x = point.X(),
    2246                 y = point.Y(),
    2247                 t = point.position || 0.0,
    2248                 result = this.projectCoordsToCurve(x, y, t, curve, board);
    2249
    2250             point.position = result[1];
    2251
    2252             return result[0];
    2253         },
    2254
    2255         /**
    2256          * Calculates the coordinates of the projection of a coordinates pair on a given curve. In case of
    2257          * function graphs this is the
    2258          * intersection point of the curve and the parallel to y-axis through the given point.
    2259          * @param {Number} x coordinate to project.
    2260          * @param {Number} y coordinate to project.
    2261          * @param {Number} t start value for newtons method
    2262          * @param {JXG.Curve} curve Curve on that the point is projected.
    2263          * @param {JXG.Board} [board=curve.board] Reference to a board.
    2264          * @see #projectPointToCurve
    2265          * @returns {JXG.Coords} Array containing the coordinates of the projection of the given point on the given graph and
    2266          * the position on the curve.
    2267          */
    2268         projectCoordsToCurve: function (x, y, t, curve, board) {
    2269             var newCoords, newCoordsObj, i, j,
    2270                 mindist, dist, lbda, v, coords, d,
    2271                 p1, p2, res,
    2272                 minfunc, tnew, fnew, fold, delta, steps,
    2273                 minX, maxX,
    2274                 infty = Number.POSITIVE_INFINITY;
    2275
    2276             if (!Type.exists(board)) {
    2277                 board = curve.board;
    2278             }
    2279
    2280             if (Type.evaluate(curve.visProp.curvetype) === 'plot') {
    2281                 t = 0;
    2282                 mindist = infty;
    2283
    2284                 if (curve.numberPoints === 0) {
    2285                     newCoords = [0, 1, 1];
    2286                 } else {
    2287                     newCoords = [curve.Z(0), curve.X(0), curve.Y(0)];
    2288                 }
    2289
    2290                 if (curve.numberPoints > 1) {
    2291
    2292                     v = [1, x, y];
    2293                     if (curve.bezierDegree === 3) {
    2294                         j = 0;
    2295                     } else {
    2296                         p1 = [curve.Z(0), curve.X(0), curve.Y(0)];
    2297                     }
    2298                     for (i = 0; i < curve.numberPoints - 1; i++) {
    2299                         if (curve.bezierDegree === 3) {
    2300                             res = this.projectCoordsToBeziersegment(v, curve, j);
    2301                         } else {
    2302                             p2 = [curve.Z(i + 1), curve.X(i + 1), curve.Y(i + 1)];
    2303                             res = this.projectCoordsToSegment(v, p1, p2);
    2304                         }
    2305                         lbda = res[1];
    2306                         coords = res[0];
    2307
    2308                         if (0.0 <= lbda && lbda <= 1.0) {
    2309                             dist = this.distance(coords, v);
    2310                             d = i + lbda;
    2311                         } else if (lbda < 0.0) {
    2312                             coords = p1;
    2313                             dist = this.distance(p1, v);
    2314                             d = i;
    2315                         } else if (lbda > 1.0 && i === curve.numberPoints - 2) {
    2316                             coords = p2;
    2317                             dist = this.distance(coords, v);
    2318                             d = curve.numberPoints - 1;
    2319                         }
    2320
    2321                         if (dist < mindist) {
    2322                             mindist = dist;
    2323                             t = d;
    2324                             newCoords = coords;
    2325                         }
    2326
    2327                         if (curve.bezierDegree === 3) {
    2328                             j++;
    2329                             i += 2;
    2330                         } else {
    2331                             p1 = p2;
    2332                         }
    2333                     }
    2334                 }
    2335
    2336                 newCoordsObj = new Coords(Const.COORDS_BY_USER, newCoords, board);
    2337             } else {   // 'parameter', 'polar', 'functiongraph'
    2338                 /** @ignore */
    2339                 minfunc = function (t) {
    2340                     var dx, dy;
    2341                     if (t < curve.minX() || t > curve.maxX()) {
    2342                         return NaN;
    2343                     }
    2344                     dx = x - curve.X(t);
    2345                     dy = y - curve.Y(t);
    2346                     return dx * dx + dy * dy;
    2347                 };
    2348
    2349                 fold = minfunc(t);
    2350                 steps = 50;
    2351                 delta = (curve.maxX() - curve.minX()) / steps;
    2352                 tnew = curve.minX();
    2353
    2354                 for (i = 0; i < steps; i++) {
    2355                     fnew = minfunc(tnew);
    2356
    2357                     if (fnew < fold || isNaN(fold)) {
    2358                         t = tnew;
    2359                         fold = fnew;
    2360                     }
    2361
    2362                     tnew += delta;
    2363                 }
    2364
    2365                 //t = Numerics.root(Numerics.D(minfunc), t);
    2366                 t = Numerics.fminbr(minfunc, [t - delta, t + delta]);
    2367
    2368
    2369                 minX = curve.minX();
    2370                 maxX = curve.maxX();
    2371                 // Distinction between closed and open curves is not necessary.
    2372                 // If closed, the cyclic projection shift will work anyhow
    2373                 // if (Math.abs(curve.X(minX) - curve.X(maxX)) < Mat.eps &&
    2374                 //     Math.abs(curve.Y(minX) - curve.Y(maxX)) < Mat.eps) {
    2375                 //     // Cyclically
    2376                 //     if (t < minX) {
    2377                 //         t = maxX + t - minX;
    2378                 //     }
    2379                 //     if (t > maxX) {
    2380                 //         t = minX + t - maxX;
    2381                 //     }
    2382                 // } else {
    2383                     t = (t < minX) ? minX : t;
    2384                     t = (t > maxX) ? maxX : t;
    2385                 // }
    2386
    2387                 newCoordsObj = new Coords(Const.COORDS_BY_USER, [curve.X(t), curve.Y(t)], board);
    2388             }
    2389
    2390             return [curve.updateTransform(newCoordsObj), t];
    2391         },
    2392
    2393         /**
    2394          * Calculates the coordinates of the closest orthogonal projection of a given coordinate array onto the
    2395          * border of a polygon.
    2396          * @param {Array} p Point to project.
    2397          * @param {JXG.Polygon} pol Polygon element
    2398          * @returns {Array} The coordinates of the closest projection of the given point to the border of the polygon.
    2399          */
    2400         projectCoordsToPolygon: function (p, pol) {
    2401             var i,
    2402                 len = pol.vertices.length,
    2403                 d_best = Infinity,
    2404                 d,
    2405                 projection,
    2406                 bestprojection;
    2407
    2408             for (i = 0; i < len; i++) {
    2409                 projection = JXG.Math.Geometry.projectCoordsToSegment(
    2410                     p,
    2411                     pol.vertices[i].coords.usrCoords,
    2412                     pol.vertices[(i + 1) % len].coords.usrCoords
    2413                 );
    2414
    2415                 d = JXG.Math.Geometry.distance(projection[0], p, 3);
    2416                 if (0 <= projection[1] && projection[1] <= 1 && d < d_best) {
    2417                     bestprojection = projection[0].slice(0);
    2418                     d_best = d;
    2419                 }
    2420             }
    2421             return bestprojection;
    2422         },
    2423
    2424         /**
    2425          * Calculates the coordinates of the projection of a given point on a given turtle. A turtle consists of
    2426          * one or more curves of curveType 'plot'. Uses {@link JXG.Math.Geometry.projectPointToCurve}.
    2427          * @param {JXG.Point} point Point to project.
    2428          * @param {JXG.Turtle} turtle on that the point is projected.
    2429          * @param {JXG.Board} [board=point.board] Reference to a board.
    2430          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given turtle.
    2431          */
    2432         projectPointToTurtle: function (point, turtle, board) {
    2433             var newCoords, t, x, y, i, dist, el, minEl,
    2434                 np = 0,
    2435                 npmin = 0,
    2436                 mindist = Number.POSITIVE_INFINITY,
    2437                 len = turtle.objects.length;
    2438
    2439             if (!Type.exists(board)) {
    2440                 board = point.board;
    2441             }
    2442
    2443             // run through all curves of this turtle
    2444             for (i = 0; i < len; i++) {
    2445                 el = turtle.objects[i];
    2446
    2447                 if (el.elementClass === Const.OBJECT_CLASS_CURVE) {
    2448                     newCoords = this.projectPointToCurve(point, el);
    2449                     dist = this.distance(newCoords.usrCoords, point.coords.usrCoords);
    2450
    2451                     if (dist < mindist) {
    2452                         x = newCoords.usrCoords[1];
    2453                         y = newCoords.usrCoords[2];
    2454                         t = point.position;
    2455                         mindist = dist;
    2456                         minEl = el;
    2457                         npmin = np;
    2458                     }
    2459                     np += el.numberPoints;
    2460                 }
    2461             }
    2462
    2463             newCoords = new Coords(Const.COORDS_BY_USER, [x, y], board);
    2464             point.position = t + npmin;
    2465
    2466             return minEl.updateTransform(newCoords);
    2467         },
    2468
    2469         /**
    2470          * Trivial projection of a point to another point.
    2471          * @param {JXG.Point} point Point to project (not used).
    2472          * @param {JXG.Point} dest Point on that the point is projected.
    2473          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.
    2474          */
    2475         projectPointToPoint: function (point, dest) {
    2476             return dest.coords;
    2477         },
    2478
    2479         /**
    2480          *
    2481          * @param {JXG.Point|JXG.Coords} point
    2482          * @param {JXG.Board} [board]
    2483          */
    2484         projectPointToBoard: function (point, board) {
    2485             var i, l, c,
    2486                 brd = board || point.board,
    2487                 // comparison factor, point coord idx, bbox idx, 1st bbox corner x & y idx, 2nd bbox corner x & y idx
    2488                 config = [
    2489                     // left
    2490                     [1, 1, 0, 0, 3, 0, 1],
    2491                     // top
    2492                     [-1, 2, 1, 0, 1, 2, 1],
    2493                     // right
    2494                     [-1, 1, 2, 2, 1, 2, 3],
    2495                     // bottom
    2496                     [1, 2, 3, 0, 3, 2, 3]
    2497                 ],
    2498                 coords = point.coords || point,
    2499                 bbox = brd.getBoundingBox();
    2500
    2501             for (i = 0; i < 4; i++) {
    2502                 c = config[i];
    2503                 if (c[0] * coords.usrCoords[c[1]] < c[0] * bbox[c[2]]) {
    2504                     // define border
    2505                     l = Mat.crossProduct([1, bbox[c[3]], bbox[c[4]]], [1, bbox[c[5]], bbox[c[6]]]);
    2506                     l[3] = 0;
    2507                     l = Mat.normalize(l);
    2508
    2509                     // project point
    2510                     coords = this.projectPointToLine({coords: coords}, {stdform: l}, brd);
    2511                 }
    2512             }
    2513
    2514             return coords;
    2515         },
    2516
    2517         /**
    2518          * Calculates the distance of a point to a line. The point and the line are given by homogeneous
    2519          * coordinates. For lines this can be line.stdform.
    2520          * @param {Array} point Homogeneous coordinates of a point.
    2521          * @param {Array} line Homogeneous coordinates of a line ([C,A,B] where A*x+B*y+C*z=0).
    2522          * @returns {Number} Distance of the point to the line.
    2523          */
    2524         distPointLine: function (point, line) {
    2525             var a = line[1],
    2526                 b = line[2],
    2527                 c = line[0],
    2528                 nom;
    2529
    2530             if (Math.abs(a) + Math.abs(b) < Mat.eps) {
    2531                 return Number.POSITIVE_INFINITY;
    2532             }
    2533
    2534             nom = a * point[1] + b * point[2] + c;
    2535             a *= a;
    2536             b *= b;
    2537
    2538             return Math.abs(nom) / Math.sqrt(a + b);
    2539         },
    2540
    2541
    2542         /**
    2543          * Helper function to create curve which displays a Reuleaux polygons.
    2544          * @param {Array} points Array of points which should be the vertices of the Reuleaux polygon. Typically,
    2545          * these point list is the array vertices of a regular polygon.
    2546          * @param {Number} nr Number of vertices
    2547          * @returns {Array} An array containing the two functions defining the Reuleaux polygon and the two values
    2548          * for the start and the end of the paramtric curve. array may be used as parent array of a
    2549          * {@link JXG.Curve}.
    2550          *
    2551          * @example
    2552          * var A = brd.create('point',[-2,-2]);
    2553          * var B = brd.create('point',[0,1]);
    2554          * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0});
    2555          * var reuleauxTriangle = brd.create('curve', JXG.Math.Geometry.reuleauxPolygon(pol.vertices, 3),
    2556          *                          {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});
    2557          *
    2558          * </pre><div class="jxgbox" id="2543a843-46a9-4372-abc1-94d9ad2db7ac" style="width: 300px; height: 300px;"></div>
    2559          * <script type="text/javascript">
    2560          * var brd = JXG.JSXGraph.initBoard('2543a843-46a9-4372-abc1-94d9ad2db7ac', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false});
    2561          * var A = brd.create('point',[-2,-2]);
    2562          * var B = brd.create('point',[0,1]);
    2563          * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0});
    2564          * var reuleauxTriangle = brd.create('curve', JXG.Math.Geometry.reuleauxPolygon(pol.vertices, 3),
    2565          *                          {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});
    2566          * </script><pre>
    2567          */
    2568         reuleauxPolygon: function (points, nr) {
    2569             var beta,
    2570                 pi2 = Math.PI * 2,
    2571                 pi2_n = pi2 / nr,
    2572                 diag = (nr - 1) / 2,
    2573                 d = 0,
    2574                 makeFct = function (which, trig) {
    2575                     return function (t, suspendUpdate) {
    2576                         var t1 = (t % pi2 + pi2) % pi2,
    2577                             j = Math.floor(t1 / pi2_n) % nr;
    2578
    2579                         if (!suspendUpdate) {
    2580                             d = points[0].Dist(points[diag]);
    2581                             beta = Mat.Geometry.rad([points[0].X() + 1, points[0].Y()], points[0], points[diag % nr]);
    2582                         }
    2583
    2584                         if (isNaN(j)) {
    2585                             return j;
    2586                         }
    2587
    2588                         t1 = t1 * 0.5 + j * pi2_n * 0.5 + beta;
    2589
    2590                         return points[j][which]() + d * Math[trig](t1);
    2591                     };
    2592                 };
    2593
    2594             return [makeFct('X', 'cos'), makeFct('Y', 'sin'), 0, pi2];
    2595         }
    2596     });
    2597
    2598     return Mat.Geometry;
    2599 });
    2600