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