1 /*
  2     Copyright 2008-2017
  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          * @see Line
635          * @see JXG.Line
636          */
637         calcStraight: function (el, point1, point2, margin) {
638             var takePoint1, takePoint2, intersection, intersect1, intersect2, straightFirst, straightLast,
639                 c, p1, p2;
640 
641             if (!Type.exists(margin)) {
642                 // Enlarge the drawable region slightly. This hides the small sides
643                 // of thick lines in most cases.
644                 margin = 10;
645             }
646 
647             straightFirst = Type.evaluate(el.visProp.straightfirst);
648             straightLast = Type.evaluate(el.visProp.straightlast);
649 
650             // If one of the point is an ideal point in homogeneous coordinates
651             // drawing of line segments or rays are not possible.
652             if (Math.abs(point1.scrCoords[0]) < Mat.eps) {
653                 straightFirst = true;
654             }
655             if (Math.abs(point2.scrCoords[0]) < Mat.eps) {
656                 straightLast = true;
657             }
658 
659             // Do nothing in case of line segments (inside or outside of the board)
660             if (!straightFirst && !straightLast) {
661                 return;
662             }
663 
664             // Compute the stdform of the line in screen coordinates.
665             c = [];
666             c[0] = el.stdform[0] -
667                 el.stdform[1] * el.board.origin.scrCoords[1] / el.board.unitX +
668                 el.stdform[2] * el.board.origin.scrCoords[2] / el.board.unitY;
669             c[1] =  el.stdform[1] / el.board.unitX;
670             c[2] = -el.stdform[2] / el.board.unitY;
671 
672             // p1=p2
673             if (isNaN(c[0] + c[1] + c[2])) {
674                 return;
675             }
676 
677             takePoint1 = false;
678             takePoint2 = false;
679 
680             // Line starts at point1 and point1 is inside the board
681             takePoint1 = !straightFirst &&
682                 Math.abs(point1.usrCoords[0]) >= Mat.eps &&
683                 point1.scrCoords[1] >= 0.0 && point1.scrCoords[1] <= el.board.canvasWidth &&
684                 point1.scrCoords[2] >= 0.0 && point1.scrCoords[2] <= el.board.canvasHeight;
685 
686             // Line ends at point2 and point2 is inside the board
687             takePoint2 = !straightLast &&
688                 Math.abs(point2.usrCoords[0]) >= Mat.eps &&
689                 point2.scrCoords[1] >= 0.0 && point2.scrCoords[1] <= el.board.canvasWidth &&
690                 point2.scrCoords[2] >= 0.0 && point2.scrCoords[2] <= el.board.canvasHeight;
691 
692             // Intersect the line with the four borders of the board.
693             intersection = this.meetLineBoard(c, el.board, margin);
694             intersect1 = intersection[0];
695             intersect2 = intersection[1];
696 
697             /**
698              * At this point we have four points:
699              * point1 and point2 are the first and the second defining point on the line,
700              * intersect1, intersect2 are the intersections of the line with border around the board.
701              */
702 
703             /*
704              * Here we handle rays where both defining points are outside of the board.
705              */
706             // If both points are outside and the complete ray is outside we do nothing
707             if (!takePoint1 && !takePoint2) {
708                 // Ray starting at point 1
709                 if (!straightFirst && straightLast &&
710                         !this.isSameDirection(point1, point2, intersect1) && !this.isSameDirection(point1, point2, intersect2)) {
711                     return;
712                 }
713 
714                 // Ray starting at point 2
715                 if (straightFirst && !straightLast &&
716                         !this.isSameDirection(point2, point1, intersect1) && !this.isSameDirection(point2, point1, intersect2)) {
717                     return;
718                 }
719             }
720 
721             /*
722              * If at least one of the defining points is outside of the board
723              * we take intersect1 or intersect2 as one of the end points
724              * The order is also important for arrows of axes
725              */
726             if (!takePoint1) {
727                 if (!takePoint2) {
728                     // Two border intersection points are used
729                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
730                         p1 = intersect1;
731                         p2 = intersect2;
732                     } else {
733                         p2 = intersect1;
734                         p1 = intersect2;
735                     }
736                 } else {
737                     // One border intersection points is used
738                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
739                         p1 = intersect1;
740                     } else {
741                         p1 = intersect2;
742                     }
743                 }
744             } else {
745                 if (!takePoint2) {
746                     // One border intersection points is used
747                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
748                         p2 = intersect2;
749                     } else {
750                         p2 = intersect1;
751                     }
752                 }
753             }
754 
755             if (p1) {
756                 //point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords.slice(1));
757                 point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords);
758             }
759 
760             if (p2) {
761                 //point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords.slice(1));
762                 point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords);
763             }
764         },
765 
766         /**
767          * A line can be a segment, a straight, or a ray. so it is not always delimited by point1 and point2.
768          *
769          * This method adjusts the line's delimiting points taking into account its nature, the viewport defined
770          * by the board.
771          *
772          * A segment is delimited by start and end point, a straight line or ray is delimited until it meets the
773          * boards boundaries. However, if the line has infinite ticks, it will be delimited by the projection of
774          * the boards vertices onto itself.
775          *
776          * @param {JXG.Line} el Reference to a line object, that needs calculation of start and end point.
777          * @param {JXG.Coords} point1 Coordinates of the point where line drawing begins. This value is calculated and
778          * set by this method.
779          * @param {JXG.Coords} point2 Coordinates of the point where line drawing ends. This value is calculated and set
780          * by this method.
781          * @see Line
782          * @see JXG.Line
783          */
784         calcLineDelimitingPoints: function (el, point1, point2) {
785             var distP1P2, boundingBox, lineSlope,
786                 intersect1, intersect2, straightFirst, straightLast,
787                 c, p1, p2,
788                 takePoint1 = false,
789                 takePoint2 = false;
790 
791             straightFirst = Type.evaluate(el.visProp.straightfirst);
792             straightLast = Type.evaluate(el.visProp.straightlast);
793 
794             // If one of the point is an ideal point in homogeneous coordinates
795             // drawing of line segments or rays are not possible.
796             if (Math.abs(point1.scrCoords[0]) < Mat.eps) {
797                 straightFirst = true;
798             }
799             if (Math.abs(point2.scrCoords[0]) < Mat.eps) {
800                 straightLast = true;
801             }
802 
803             // Compute the stdform of the line in screen coordinates.
804             c = [];
805             c[0] = el.stdform[0] -
806                 el.stdform[1] * el.board.origin.scrCoords[1] / el.board.unitX +
807                 el.stdform[2] * el.board.origin.scrCoords[2] / el.board.unitY;
808             c[1] =  el.stdform[1] / el.board.unitX;
809             c[2] = -el.stdform[2] / el.board.unitY;
810 
811             // p1=p2
812             if (isNaN(c[0] + c[1] + c[2])) {
813                 return;
814             }
815 
816             takePoint1 = !straightFirst;
817             takePoint2 = !straightLast;
818             // Intersect the board vertices on the line to establish the available visual space for the infinite ticks
819             // Based on the slope of the line we can optimise and only project the two outer vertices
820 
821             // boundingBox = [x1, y1, x2, y2] upper left, lower right vertices
822             boundingBox = el.board.getBoundingBox();
823             lineSlope = el.getSlope();
824             if (lineSlope >= 0) {
825                 // project vertices (x2,y1) (x1, y2)
826                 intersect1 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[2], boundingBox[1]] } }, el, el.board);
827                 intersect2 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[0], boundingBox[3]] } }, el, el.board);
828             } else {
829                 // project vertices (x1, y1) (x2, y2)
830                 intersect1 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[0], boundingBox[1]] } }, el, el.board);
831                 intersect2 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[2], boundingBox[3]] } }, el, el.board);
832             }
833 
834             /**
835              * we have four points:
836              * point1 and point2 are the first and the second defining point on the line,
837              * intersect1, intersect2 are the intersections of the line with border around the board.
838              */
839 
840             /*
841              * Here we handle rays/segments where both defining points are outside of the board.
842              */
843             if (!takePoint1 && !takePoint2) {
844                 // Segment, if segment does not cross the board, do nothing
845                 if (!straightFirst && !straightLast) {
846                     distP1P2 = point1.distance(Const.COORDS_BY_USER, point2);
847                     // if  intersect1 not between point1 and point2
848                     if (Math.abs(point1.distance(Const.COORDS_BY_USER, intersect1) +
849                             intersect1.distance(Const.COORDS_BY_USER, point2) - distP1P2) > Mat.eps) {
850                         return;
851                     }
852                     // if insersect2 not between point1 and point2
853                     if (Math.abs(point1.distance(Const.COORDS_BY_USER, intersect2) +
854                             intersect2.distance(Const.COORDS_BY_USER, point2) - distP1P2) > Mat.eps) {
855                         return;
856                     }
857                 }
858 
859                 // If both points are outside and the complete ray is outside we do nothing
860                 // Ray starting at point 1
861                 if (!straightFirst && straightLast &&
862                         !this.isSameDirection(point1, point2, intersect1) && !this.isSameDirection(point1, point2, intersect2)) {
863                     return;
864                 }
865 
866                 // Ray starting at point 2
867                 if (straightFirst && !straightLast &&
868                         !this.isSameDirection(point2, point1, intersect1) && !this.isSameDirection(point2, point1, intersect2)) {
869                     return;
870                 }
871             }
872 
873             /*
874              * If at least one of the defining points is outside of the board
875              * we take intersect1 or intersect2 as one of the end points
876              * The order is also important for arrows of axes
877              */
878             if (!takePoint1) {
879                 if (!takePoint2) {
880                     // Two border intersection points are used
881                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
882                         p1 = intersect1;
883                         p2 = intersect2;
884                     } else {
885                         p2 = intersect1;
886                         p1 = intersect2;
887                     }
888                 } else {
889                     // One border intersection points is used
890                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
891                         p1 = intersect1;
892                     } else {
893                         p1 = intersect2;
894                     }
895                 }
896             } else {
897                 if (!takePoint2) {
898                     // One border intersection points is used
899                     if (this.isSameDir(point1, point2, intersect1, intersect2)) {
900                         p2 = intersect2;
901                     } else {
902                         p2 = intersect1;
903                     }
904                 }
905             }
906 
907             if (p1) {
908                 //point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords.slice(1));
909                 point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords);
910             }
911 
912             if (p2) {
913                 //point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords.slice(1));
914                 point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords);
915             }
916         },
917 
918         /**
919          * The vectors <tt>p2-p1</tt> and <tt>i2-i1</tt> are supposed to be collinear. If their cosine is positive
920          * they point into the same direction otherwise they point in opposite direction.
921          * @param {JXG.Coords} p1
922          * @param {JXG.Coords} p2
923          * @param {JXG.Coords} i1
924          * @param {JXG.Coords} i2
925          * @returns {Boolean} True, if <tt>p2-p1</tt> and <tt>i2-i1</tt> point into the same direction
926          */
927         isSameDir: function (p1, p2, i1, i2) {
928             var dpx = p2.usrCoords[1] - p1.usrCoords[1],
929                 dpy = p2.usrCoords[2] - p1.usrCoords[2],
930                 dix = i2.usrCoords[1] - i1.usrCoords[1],
931                 diy = i2.usrCoords[2] - i1.usrCoords[2];
932 
933             if (Math.abs(p2.usrCoords[0]) < Mat.eps) {
934                 dpx = p2.usrCoords[1];
935                 dpy = p2.usrCoords[2];
936             }
937 
938             if (Math.abs(p1.usrCoords[0]) < Mat.eps) {
939                 dpx = -p1.usrCoords[1];
940                 dpy = -p1.usrCoords[2];
941             }
942 
943             return dpx * dix + dpy * diy >= 0;
944         },
945 
946         /**
947          * If you're looking from point "start" towards point "s" and can see the point "p", true is returned. Otherwise false.
948          * @param {JXG.Coords} start The point you're standing on.
949          * @param {JXG.Coords} p The point in which direction you're looking.
950          * @param {JXG.Coords} s The point that should be visible.
951          * @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.
952          */
953         isSameDirection: function (start, p, s) {
954             var dx, dy, sx, sy, r = false;
955 
956             dx = p.usrCoords[1] - start.usrCoords[1];
957             dy = p.usrCoords[2] - start.usrCoords[2];
958 
959             sx = s.usrCoords[1] - start.usrCoords[1];
960             sy = s.usrCoords[2] - start.usrCoords[2];
961 
962             if (Math.abs(dx) < Mat.eps) {
963                 dx = 0;
964             }
965 
966             if (Math.abs(dy) < Mat.eps) {
967                 dy = 0;
968             }
969 
970             if (Math.abs(sx) < Mat.eps) {
971                 sx = 0;
972             }
973 
974             if (Math.abs(sy) < Mat.eps) {
975                 sy = 0;
976             }
977 
978             if (dx >= 0 && sx >= 0) {
979                 r = (dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0);
980             } else if (dx <= 0 && sx <= 0) {
981                 r = (dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0);
982             }
983 
984             return r;
985         },
986 
987         /****************************************/
988         /****          INTERSECTIONS         ****/
989         /****************************************/
990 
991         /**
992          * Generate the function which computes the coordinates of the intersection point.
993          * Primarily used in {@link JXG.Point#createIntersectionPoint}.
994          * @param {JXG.Board} board object
995          * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2.
996          * i determines the intersection point if two points are available: <ul>
997          *   <li>i==0: use the positive square root,</li>
998          *   <li>i==1: use the negative square root.</li></ul>
999          * See further {@link JXG.Point#createIntersectionPoint}.
1000          * @param {Boolean} alwaysintersect. Flag that determines if segements and arc can have an outer intersection point
1001          * on their defining line or circle.
1002          * @returns {Function} Function returning a {@link JXG.Coords} object that determines
1003          * the intersection point.
1004          */
1005         intersectionFunction: function (board, el1, el2, i, j, alwaysintersect) {
1006             var func, that = this;
1007 
1008             if (el1.elementClass === Const.OBJECT_CLASS_CURVE &&
1009                     el2.elementClass === Const.OBJECT_CLASS_CURVE) {
1010                 // curve - curve
1011                 /** @ignore */
1012                 func = function () {
1013                     return that.meetCurveCurve(el1, el2, i, j, el1.board);
1014                 };
1015 
1016             } else if ((el1.elementClass === Const.OBJECT_CLASS_CURVE && el2.elementClass === Const.OBJECT_CLASS_LINE) ||
1017                     (el2.elementClass === Const.OBJECT_CLASS_CURVE && el1.elementClass === Const.OBJECT_CLASS_LINE)) {
1018                 // curve - line (this includes intersections between conic sections and lines
1019                 /** @ignore */
1020                 func = function () {
1021                     return that.meetCurveLine(el1, el2, i, el1.board, alwaysintersect);
1022                 };
1023 
1024             } else if (el1.elementClass === Const.OBJECT_CLASS_LINE && el2.elementClass === Const.OBJECT_CLASS_LINE) {
1025                 // line - line, lines may also be segments.
1026                 /** @ignore */
1027                 func = function () {
1028                     var res, c,
1029                         first1, first2, last1, last2;
1030 
1031                     first1 = first2 = Type.evaluate(el1.visProp.straightfirst);
1032                     last1 = last2 = Type.evaluate(el1.visProp.straightlast);
1033 
1034                     /**
1035                      * If one of the lines is a segment or ray and
1036                      * the the intersection point shpould disappear if outside
1037                      * of the segment or ray we call
1038                      * meetSegmentSegment
1039                      */
1040                     if (!Type.evaluate(alwaysintersect) && (!first1 || !last1 || !first2 || !last2)) {
1041                         res = that.meetSegmentSegment(
1042                             el1.point1.coords.usrCoords,
1043                             el1.point2.coords.usrCoords,
1044                             el2.point1.coords.usrCoords,
1045                             el2.point2.coords.usrCoords,
1046                             el1.board
1047                         );
1048 
1049                         if ((!first1 && res[1] < 0) || (!last1 && res[1] > 1) ||
1050                                 (!first2 && res[2] < 0) || (!last2 && res[2] > 1)) {
1051                             // Non-existent
1052                             c = [0, NaN, NaN];
1053                         } else {
1054                             c = res[0];
1055                         }
1056 
1057                         return (new Coords(Const.COORDS_BY_USER, c, el1.board));
1058                     }
1059 
1060                     return that.meet(el1.stdform, el2.stdform, i, el1.board);
1061                 };
1062             } else {
1063                 // All other combinations of circles and lines
1064                 /** @ignore */
1065                 func = function () {
1066                     return that.meet(el1.stdform, el2.stdform, i, el1.board);
1067                 };
1068             }
1069 
1070             return func;
1071         },
1072 
1073         /**
1074          * Computes the intersection of a pair of lines, circles or both.
1075          * It uses the internal data array stdform of these elements.
1076          * @param {Array} el1 stdform of the first element (line or circle)
1077          * @param {Array} el2 stdform of the second element (line or circle)
1078          * @param {Number} i Index of the intersection point that should be returned.
1079          * @param board Reference to the board.
1080          * @returns {JXG.Coords} Coordinates of one of the possible two or more intersection points.
1081          * Which point will be returned is determined by i.
1082          */
1083         meet: function (el1, el2, i, board) {
1084             var result,
1085                 eps = Mat.eps;
1086 
1087             // line line
1088             if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) < eps) {
1089                 result = this.meetLineLine(el1, el2, i, board);
1090             // circle line
1091             } else if (Math.abs(el1[3]) >= eps && Math.abs(el2[3]) < eps) {
1092                 result = this.meetLineCircle(el2, el1, i, board);
1093             // line circle
1094             } else if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) >= eps) {
1095                 result = this.meetLineCircle(el1, el2, i, board);
1096             // circle circle
1097             } else {
1098                 result = this.meetCircleCircle(el1, el2, i, board);
1099             }
1100 
1101             return result;
1102         },
1103 
1104         /**
1105          * Intersection of the line with the board
1106          * @param  {Array}     line   stdform of the line in screen coordinates
1107          * @param  {JXG.Board} board  reference to a board.
1108          * @param  {Number}    margin optional margin, to avoid the display of the small sides of lines.
1109          * @returns {Array}            [intersection coords 1, intersection coords 2]
1110          */
1111         meetLineBoard: function (line, board, margin) {
1112              // Intersect the line with the four borders of the board.
1113             var s = [], intersect1, intersect2, i, j;
1114 
1115             if (!Type.exists(margin)) {
1116                 margin = 0;
1117             }
1118 
1119             // top
1120             s[0] = Mat.crossProduct(line, [margin, 0, 1]);
1121             // left
1122             s[1] = Mat.crossProduct(line, [margin, 1, 0]);
1123             // bottom
1124             s[2] = Mat.crossProduct(line, [-margin - board.canvasHeight, 0, 1]);
1125             // right
1126             s[3] = Mat.crossProduct(line, [-margin - board.canvasWidth, 1, 0]);
1127 
1128             // Normalize the intersections
1129             for (i = 0; i < 4; i++) {
1130                 if (Math.abs(s[i][0]) > Mat.eps) {
1131                     for (j = 2; j > 0; j--) {
1132                         s[i][j] /= s[i][0];
1133                     }
1134                     s[i][0] = 1.0;
1135                 }
1136             }
1137 
1138             // line is parallel to "left", take "top" and "bottom"
1139             if (Math.abs(s[1][0]) < Mat.eps) {
1140                 intersect1 = s[0];                          // top
1141                 intersect2 = s[2];                          // bottom
1142             // line is parallel to "top", take "left" and "right"
1143             } else if (Math.abs(s[0][0]) < Mat.eps) {
1144                 intersect1 = s[1];                          // left
1145                 intersect2 = s[3];                          // right
1146             // left intersection out of board (above)
1147             } else if (s[1][2] < 0) {
1148                 intersect1 = s[0];                          // top
1149 
1150                 // right intersection out of board (below)
1151                 if (s[3][2] > board.canvasHeight) {
1152                     intersect2 = s[2];                      // bottom
1153                 } else {
1154                     intersect2 = s[3];                      // right
1155                 }
1156             // left intersection out of board (below)
1157             } else if (s[1][2] > board.canvasHeight) {
1158                 intersect1 = s[2];                          // bottom
1159 
1160                 // right intersection out of board (above)
1161                 if (s[3][2] < 0) {
1162                     intersect2 = s[0];                      // top
1163                 } else {
1164                     intersect2 = s[3];                      // right
1165                 }
1166             } else {
1167                 intersect1 = s[1];                          // left
1168 
1169                 // right intersection out of board (above)
1170                 if (s[3][2] < 0) {
1171                     intersect2 = s[0];                      // top
1172                 // right intersection out of board (below)
1173                 } else if (s[3][2] > board.canvasHeight) {
1174                     intersect2 = s[2];                      // bottom
1175                 } else {
1176                     intersect2 = s[3];                      // right
1177                 }
1178             }
1179 
1180             intersect1 = new Coords(Const.COORDS_BY_SCREEN, intersect1.slice(1), board);
1181             intersect2 = new Coords(Const.COORDS_BY_SCREEN, intersect2.slice(1), board);
1182             return [intersect1, intersect2];
1183         },
1184 
1185         /**
1186          * Intersection of two lines.
1187          * @param {Array} l1 stdform of the first line
1188          * @param {Array} l2 stdform of the second line
1189          * @param {number} i unused
1190          * @param {JXG.Board} board Reference to the board.
1191          * @returns {JXG.Coords} Coordinates of the intersection point.
1192          */
1193         meetLineLine: function (l1, l2, i, board) {
1194             /*
1195             var s = Mat.crossProduct(l1, l2);
1196 
1197             if (Math.abs(s[0]) > Mat.eps) {
1198                 s[1] /= s[0];
1199                 s[2] /= s[0];
1200                 s[0] = 1.0;
1201             }
1202             */
1203             var s = isNaN(l1[5] + l2[5]) ? [0, 0, 0] : Mat.crossProduct(l1, l2);
1204             return new Coords(Const.COORDS_BY_USER, s, board);
1205         },
1206 
1207         /**
1208          * Intersection of line and circle.
1209          * @param {Array} lin stdform of the line
1210          * @param {Array} circ stdform of the circle
1211          * @param {number} i number of the returned intersection point.
1212          *   i==0: use the positive square root,
1213          *   i==1: use the negative square root.
1214          * @param {JXG.Board} board Reference to a board.
1215          * @returns {JXG.Coords} Coordinates of the intersection point
1216          */
1217         meetLineCircle: function (lin, circ, i, board) {
1218             var a, b, c, d, n,
1219                 A, B, C, k, t;
1220 
1221             // Radius is zero, return center of circle
1222             if (circ[4] < Mat.eps) {
1223                 if (Math.abs(Mat.innerProduct([1, circ[6], circ[7]], lin, 3)) < Mat.eps) {
1224                     return new Coords(Const.COORDS_BY_USER, circ.slice(6, 8), board);
1225                 }
1226 
1227                 return new Coords(Const.COORDS_BY_USER, [NaN, NaN], board);
1228             }
1229 
1230             c = circ[0];
1231             b = circ.slice(1, 3);
1232             a = circ[3];
1233             d = lin[0];
1234             n = lin.slice(1, 3);
1235 
1236             // Line is assumed to be normalized. Therefore, nn==1 and we can skip some operations:
1237             /*
1238              var nn = n[0]*n[0]+n[1]*n[1];
1239              A = a*nn;
1240              B = (b[0]*n[1]-b[1]*n[0])*nn;
1241              C = a*d*d - (b[0]*n[0]+b[1]*n[1])*d + c*nn;
1242              */
1243             A = a;
1244             B = (b[0] * n[1] - b[1] * n[0]);
1245             C = a * d * d - (b[0] * n[0] + b[1] * n[1]) * d + c;
1246 
1247             k = B * B - 4 * A * C;
1248             if (k > -Mat.eps * Mat.eps) {
1249                 k = Math.sqrt(Math.abs(k));
1250                 t = [(-B + k) / (2 * A), (-B - k) / (2 * A)];
1251 
1252                 return ((i === 0) ?
1253                         new Coords(Const.COORDS_BY_USER, [-t[0] * (-n[1]) - d * n[0], -t[0] * n[0] - d * n[1]], board) :
1254                         new Coords(Const.COORDS_BY_USER, [-t[1] * (-n[1]) - d * n[0], -t[1] * n[0] - d * n[1]], board)
1255                     );
1256             }
1257 
1258             return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);
1259         },
1260 
1261         /**
1262          * Intersection of two circles.
1263          * @param {Array} circ1 stdform of the first circle
1264          * @param {Array} circ2 stdform of the second circle
1265          * @param {number} i number of the returned intersection point.
1266          *   i==0: use the positive square root,
1267          *   i==1: use the negative square root.
1268          * @param {JXG.Board} board Reference to the board.
1269          * @returns {JXG.Coords} Coordinates of the intersection point
1270          */
1271         meetCircleCircle: function (circ1, circ2, i, board) {
1272             var radicalAxis;
1273 
1274             // Radius is zero, return center of circle, if on other circle
1275             if (circ1[4] < Mat.eps) {
1276                 if (Math.abs(this.distance(circ1.slice(6, 2), circ2.slice(6, 8)) - circ2[4]) < Mat.eps) {
1277                     return new Coords(Const.COORDS_BY_USER, circ1.slice(6, 8), board);
1278                 }
1279 
1280                 return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);
1281             }
1282 
1283             // Radius is zero, return center of circle, if on other circle
1284             if (circ2[4] < Mat.eps) {
1285                 if (Math.abs(this.distance(circ2.slice(6, 2), circ1.slice(6, 8)) - circ1[4]) < Mat.eps) {
1286                     return new Coords(Const.COORDS_BY_USER, circ2.slice(6, 8), board);
1287                 }
1288 
1289                 return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);
1290             }
1291 
1292             radicalAxis = [circ2[3] * circ1[0] - circ1[3] * circ2[0],
1293                 circ2[3] * circ1[1] - circ1[3] * circ2[1],
1294                 circ2[3] * circ1[2] - circ1[3] * circ2[2],
1295                 0, 1, Infinity, Infinity, Infinity];
1296             radicalAxis = Mat.normalize(radicalAxis);
1297 
1298             return this.meetLineCircle(radicalAxis, circ1, i, board);
1299         },
1300 
1301         /**
1302          * Compute an intersection of the curves c1 and c2.
1303          * We want to find values t1, t2 such that
1304          * c1(t1) = c2(t2), i.e. (c1_x(t1)-c2_x(t2),c1_y(t1)-c2_y(t2)) = (0,0).
1305          *
1306          * Methods: segment-wise intersections (default) or generalized Newton method.
1307          * @param {JXG.Curve} c1 Curve, Line or Circle
1308          * @param {JXG.Curve} c2 Curve, Line or Circle
1309          * @param {Number} nr the nr-th intersection point will be returned.
1310          * @param {Number} t2ini not longer used.
1311          * @param {JXG.Board} [board=c1.board] Reference to a board object.
1312          * @param {String} [method='segment'] Intersection method, possible values are 'newton' and 'segment'.
1313          * @returns {JXG.Coords} intersection point
1314          */
1315         meetCurveCurve: function (c1, c2, nr, t2ini, board, method) {
1316             var co;
1317 
1318             if (Type.exists(method) && method === 'newton') {
1319                 co = Numerics.generalizedNewton(c1, c2, nr, t2ini);
1320             } else {
1321                 if (c1.bezierDegree === 3 && c2.bezierDegree === 3) {
1322                     co = this.meetBezierCurveRedBlueSegments(c1, c2, nr);
1323                 } else {
1324                     co = this.meetCurveRedBlueSegments(c1, c2, nr);
1325                 }
1326             }
1327 
1328             return (new Coords(Const.COORDS_BY_USER, co, board));
1329         },
1330 
1331         /**
1332          * Intersection of curve with line,
1333          * Order of input does not matter for el1 and el2.
1334          * @param {JXG.Curve,JXG.Line} el1 Curve or Line
1335          * @param {JXG.Curve,JXG.Line} el2 Curve or Line
1336          * @param {Number} nr the nr-th intersection point will be returned.
1337          * @param {JXG.Board} [board=el1.board] Reference to a board object.
1338          * @param {Boolean} alwaysIntersect If false just the segment between the two defining points are tested for intersection
1339          * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,
1340          * the ideal point [0,1,0] is returned.
1341          */
1342         meetCurveLine: function (el1, el2, nr, board, alwaysIntersect) {
1343             var v = [0, NaN, NaN], cu, li;
1344 
1345             if (!Type.exists(board)) {
1346                 board = el1.board;
1347             }
1348 
1349             if (el1.elementClass === Const.OBJECT_CLASS_CURVE) {
1350                 cu = el1;
1351                 li = el2;
1352             } else {
1353                 cu = el2;
1354                 li = el1;
1355             }
1356 
1357             if (Type.evaluate(cu.visProp.curvetype) === 'plot') {
1358                 v = this.meetCurveLineDiscrete(cu, li, nr, board, !alwaysIntersect);
1359             } else {
1360                 v = this.meetCurveLineContinuous(cu, li, nr, board);
1361             }
1362 
1363             return v;
1364         },
1365 
1366         /**
1367          * Intersection of line and curve, continuous case.
1368          * Finds the nr-the intersection point
1369          * Uses {@link JXG.Math.Geometry.meetCurveLineDiscrete} as a first approximation.
1370          * A more exact solution is then found with
1371          * {@link JXG.Math.Geometry.meetCurveLineDiscrete}.
1372          *
1373          * @param {JXG.Curve} cu Curve
1374          * @param {JXG.Line} li Line
1375          * @param {Number} nr Will return the nr-th intersection point.
1376          * @param {JXG.Board} board
1377          *
1378          */
1379         meetCurveLineContinuous: function (cu, li, nr, board, testSegment) {
1380             var t, func0, func1, func0a, v, x, y, z,
1381                 eps = Mat.eps,
1382                 epsLow = Mat.eps,
1383                 steps, delta, tnew, i,
1384                 tmin, fmin, ft;
1385 
1386             v = this.meetCurveLineDiscrete(cu, li, nr, board, testSegment);
1387             x = v.usrCoords[1];
1388             y = v.usrCoords[2];
1389 
1390             func0 = function (t) {
1391                 var c1 = x - cu.X(t),
1392                     c2 = y - cu.Y(t);
1393 
1394                 return c1 * c1 + c2 * c2;
1395             };
1396 
1397             func1 = function (t) {
1398                 var v = li.stdform[0] + li.stdform[1] * cu.X(t) + li.stdform[2] * cu.Y(t);
1399                 return v * v;
1400             };
1401 
1402             // Find t
1403             steps = 50;
1404             delta = (cu.maxX() - cu.minX()) / steps;
1405             tnew = cu.minX();
1406 
1407             fmin = 0.0001; //eps;
1408             tmin = NaN;
1409             for (i = 0; i < steps; i++) {
1410                 t = Numerics.root(func0, [tnew, tnew + delta]);
1411                 ft = Math.abs(func0(t));
1412                 if (ft <= fmin) {
1413                     fmin = ft;
1414                     tmin = t;
1415                     if (fmin < eps) {
1416                         break;
1417                     }
1418                 }
1419 
1420                 tnew += delta;
1421             }
1422             t = tmin;
1423             // Compute "exact" t
1424             t = Numerics.root(func1, [t - delta, t + delta]);
1425 
1426             ft = func1(t);
1427             // Is the point on the line?
1428             if (isNaN(ft) || Math.abs(ft) > epsLow) {
1429                 z = 0.0; //NaN;
1430             } else {
1431                 z = 1.0;
1432             }
1433 
1434             return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board));
1435         },
1436 
1437         /**
1438          * Intersection of line and curve, continuous case.
1439          * Segments are treated as lines. Finding the nr-the intersection point
1440          * works for nr=0,1 only.
1441          *
1442          * @private
1443          * @deprecated
1444          * @param {JXG.Curve} cu Curve
1445          * @param {JXG.Line} li Line
1446          * @param {Number} nr Will return the nr-th intersection point.
1447          * @param {JXG.Board} board
1448          *
1449          * BUG: does not respect cu.minX() and cu.maxX()
1450          */
1451         meetCurveLineContinuousOld: function (cu, li, nr, board) {
1452             var t, t2, i, func, z,
1453                 tnew, steps, delta, tstart, tend, cux, cuy,
1454                 eps = Mat.eps * 10;
1455 
1456             JXG.deprecated('Geometry.meetCurveLineContinuousOld()', 'Geometry.meetCurveLineContinuous()');
1457             func = function (t) {
1458                 var v = li.stdform[0] + li.stdform[1] * cu.X(t) + li.stdform[2] * cu.Y(t);
1459                 return v * v;
1460             };
1461 
1462             // Find some intersection point
1463             if (this.meetCurveLineContinuous.t1memo) {
1464                 tstart = this.meetCurveLineContinuous.t1memo;
1465                 t = Numerics.root(func, tstart);
1466             } else {
1467                 tstart = cu.minX();
1468                 tend = cu.maxX();
1469                 t = Numerics.root(func, [tstart, tend]);
1470             }
1471 
1472             this.meetCurveLineContinuous.t1memo = t;
1473             cux = cu.X(t);
1474             cuy = cu.Y(t);
1475 
1476             // Find second intersection point
1477             if (nr === 1) {
1478                 if (this.meetCurveLineContinuous.t2memo) {
1479                     tstart = this.meetCurveLineContinuous.t2memo;
1480                 }
1481                 t2 = Numerics.root(func, tstart);
1482 
1483                 if (!(Math.abs(t2 - t) > 0.1 && Math.abs(cux - cu.X(t2)) > 0.1 && Math.abs(cuy - cu.Y(t2)) > 0.1)) {
1484                     steps = 20;
1485                     delta = (cu.maxX() - cu.minX()) / steps;
1486                     tnew = cu.minX();
1487 
1488                     for (i = 0; i < steps; i++) {
1489                         t2 = Numerics.root(func, [tnew, tnew + delta]);
1490 
1491                         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) {
1492                             break;
1493                         }
1494 
1495                         tnew += delta;
1496                     }
1497                 }
1498                 t = t2;
1499                 this.meetCurveLineContinuous.t2memo = t;
1500             }
1501 
1502             // Is the point on the line?
1503             if (Math.abs(func(t)) > eps) {
1504                 z = NaN;
1505             } else {
1506                 z = 1.0;
1507             }
1508 
1509             return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board));
1510         },
1511 
1512         /**
1513          * Intersection of line and curve, discrete case.
1514          * Segments are treated as lines.
1515          * Finding the nr-th intersection point should work for all nr.
1516          * @param {JXG.Curve} cu
1517          * @param {JXG.Line} li
1518          * @param {Number} nr
1519          * @param {JXG.Board} board
1520          * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the
1521          * line defined by the segment
1522          *
1523          * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,
1524          * the ideal point [0,1,0] is returned.
1525          */
1526         meetCurveLineDiscrete: function (cu, li, nr, board, testSegment) {
1527             var i, j,
1528                 p1, p2, p, q,
1529                 lip1 = li.point1.coords.usrCoords,
1530                 lip2 = li.point2.coords.usrCoords,
1531                 d, res,
1532                 cnt = 0,
1533                 len = cu.numberPoints,
1534                 ev_sf = Type.evaluate(li.visProp.straightfirst),
1535                 ev_sl = Type.evaluate(li.visProp.straightlast);
1536 
1537             // In case, no intersection will be found we will take this
1538             q = new Coords(Const.COORDS_BY_USER, [0, NaN, NaN], board);
1539 
1540             if (lip1[0] === 0.0) {
1541                 lip1 = [1, lip2[1] + li.stdform[2], lip2[2] - li.stdform[1]];
1542             } else if (lip2[0] === 0.0) {
1543                 lip2 = [1, lip1[1] + li.stdform[2], lip1[2] - li.stdform[1]];
1544             }
1545 
1546             p2 = cu.points[0].usrCoords;
1547             for (i = 1; i < len; i++) {
1548                 p1 = p2.slice(0);
1549                 p2 = cu.points[i].usrCoords;
1550                 d = this.distance(p1, p2);
1551 
1552                 // The defining points are not identical
1553                 if (d > Mat.eps) {
1554                     if (cu.bezierDegree === 3) {
1555                         res = this.meetBeziersegmentBeziersegment([
1556                             cu.points[i - 1].usrCoords.slice(1),
1557                             cu.points[i].usrCoords.slice(1),
1558                             cu.points[i + 1].usrCoords.slice(1),
1559                             cu.points[i + 2].usrCoords.slice(1)
1560                         ], [
1561                             lip1.slice(1),
1562                             lip2.slice(1)
1563                         ], testSegment);
1564 
1565                         i += 2;
1566                     } else {
1567                         res = [this.meetSegmentSegment(p1, p2, lip1, lip2)];
1568                     }
1569 
1570                     for (j = 0; j < res.length; j++) {
1571                         p = res[j];
1572                         if (0 <= p[1] && p[1] <= 1) {
1573                             if (cnt === nr) {
1574                                 /**
1575                                 * If the intersection point is not part of the segment,
1576                                 * this intersection point is set to non-existent.
1577                                 * This prevents jumping of the intersection points.
1578                                 * But it may be discussed if it is the desired behavior.
1579                                 */
1580                                 if (testSegment &&
1581                                         ((!ev_sf && p[2] < 0) || (!ev_sl && p[2] > 1))) {
1582                                     return q;  // break;
1583                                 }
1584 
1585                                 q = new Coords(Const.COORDS_BY_USER, p[0], board);
1586                                 return q;      // break;
1587                             }
1588                             cnt += 1;
1589                         }
1590                     }
1591                 }
1592             }
1593 
1594             return q;
1595         },
1596 
1597         /**
1598          * Find the n-th intersection point of two curves named red (first parameter) and blue (second parameter).
1599          * We go through each segment of the red curve and search if there is an intersection with a segemnt of the blue curve.
1600          * This double loop, i.e. the outer loop runs along the red curve and the inner loop runs along the blue curve, defines
1601          * the n-th intersection point. The segments are either line segments or Bezier curves of degree 3. This depends on
1602          * the property bezierDegree of the curves.
1603          *
1604          * @param {JXG.Curve} red
1605          * @param {JXG.Curve} blue
1606          * @param {Number} nr
1607          */
1608         meetCurveRedBlueSegments: function (red, blue, nr) {
1609             var i, j,
1610                 red1, red2, blue1, blue2, m,
1611                 minX, maxX,
1612                 iFound = 0,
1613                 lenBlue = blue.numberPoints, //points.length,
1614                 lenRed = red.numberPoints; //points.length;
1615 
1616             if (lenBlue <= 1 || lenRed <= 1) {
1617                 return [0, NaN, NaN];
1618             }
1619 
1620             for (i = 1; i < lenRed; i++) {
1621                 red1 = red.points[i - 1].usrCoords;
1622                 red2 = red.points[i].usrCoords;
1623                 minX = Math.min(red1[1], red2[1]);
1624                 maxX = Math.max(red1[1], red2[1]);
1625 
1626                 blue2 = blue.points[0].usrCoords;
1627                 for (j = 1; j < lenBlue; j++) {
1628                     blue1 = blue2;
1629                     blue2 = blue.points[j].usrCoords;
1630 
1631                     if (Math.min(blue1[1], blue2[1]) < maxX && Math.max(blue1[1], blue2[1]) > minX) {
1632                         m = this.meetSegmentSegment(red1, red2, blue1, blue2);
1633                         if (m[1] >= 0.0 && m[2] >= 0.0 &&
1634                                 // The two segments meet in the interior or at the start points
1635                                 ((m[1] < 1.0 && m[2] < 1.0) ||
1636                                 // One of the curve is intersected in the very last point
1637                                 (i === lenRed - 1 && m[1] === 1.0) ||
1638                                 (j === lenBlue - 1 && m[2] === 1.0))) {
1639                             if (iFound === nr) {
1640                                 return m[0];
1641                             }
1642 
1643                             iFound++;
1644                         }
1645                     }
1646                 }
1647             }
1648 
1649             return [0, NaN, NaN];
1650         },
1651 
1652         /**
1653          * Intersection of two segments.
1654          * @param {Array} p1 First point of segment 1 using homogeneous coordinates [z,x,y]
1655          * @param {Array} p2 Second point of segment 1 using homogeneous coordinates [z,x,y]
1656          * @param {Array} q1 First point of segment 2 using homogeneous coordinates [z,x,y]
1657          * @param {Array} q2 Second point of segment 2 using homogeneous coordinates [z,x,y]
1658          * @returns {Array} [Intersection point, t, u] The first entry contains the homogeneous coordinates
1659          * of the intersection point. The second and third entry gives the position of the intersection between the
1660          * two defining points. For example, the second entry t is defined by: intersection point = t*p1 + (1-t)*p2.
1661          **/
1662         meetSegmentSegment: function (p1, p2, q1, q2) {
1663             var t, u, diff,
1664                 li1 = Mat.crossProduct(p1, p2),
1665                 li2 = Mat.crossProduct(q1, q2),
1666                 c = Mat.crossProduct(li1, li2),
1667                 denom = c[0];
1668 
1669             if (Math.abs(denom) < Mat.eps) {
1670                 return [c, Infinity, Infinity];
1671             }
1672 
1673             diff = [q1[1] - p1[1], q1[2] - p1[2]];
1674 
1675             // Because of speed issues, evalute the determinants directly
1676             t = (diff[0] * (q2[2] - q1[2]) - diff[1] * (q2[1] - q1[1])) / denom;
1677             u = (diff[0] * (p2[2] - p1[2]) - diff[1] * (p2[1] - p1[1])) / denom;
1678 
1679             return [c, t, u];
1680         },
1681 
1682         /****************************************/
1683         /****   BEZIER CURVE ALGORITHMS      ****/
1684         /****************************************/
1685 
1686         /**
1687          * Splits a Bezier curve segment defined by four points into
1688          * two Bezier curve segments. Dissection point is t=1/2.
1689          * @param {Array} curve Array of four coordinate arrays of length 2 defining a
1690          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
1691          * @returns {Array} Array consisting of two coordinate arrays for Bezier curves.
1692          */
1693         _bezierSplit: function (curve) {
1694             var p0, p1, p2, p00, p22, p000;
1695 
1696             p0 = [(curve[0][0] + curve[1][0]) * 0.5, (curve[0][1] + curve[1][1]) * 0.5];
1697             p1 = [(curve[1][0] + curve[2][0]) * 0.5, (curve[1][1] + curve[2][1]) * 0.5];
1698             p2 = [(curve[2][0] + curve[3][0]) * 0.5, (curve[2][1] + curve[3][1]) * 0.5];
1699 
1700             p00 = [(p0[0] + p1[0]) * 0.5, (p0[1] + p1[1]) * 0.5];
1701             p22 = [(p1[0] + p2[0]) * 0.5, (p1[1] + p2[1]) * 0.5];
1702 
1703             p000 = [(p00[0] + p22[0]) * 0.5, (p00[1] + p22[1]) * 0.5];
1704 
1705             return [[curve[0], p0, p00, p000], [p000, p22, p2, curve[3]]];
1706         },
1707 
1708         /**
1709          * Computes the bounding box [minX, maxY, maxX, minY] of a Bezier curve segment
1710          * from its control points.
1711          * @param {Array} curve Array of four coordinate arrays of length 2 defining a
1712          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
1713          * @returns {Array} Bounding box [minX, maxY, maxX, minY]
1714          */
1715         _bezierBbox: function (curve) {
1716             var bb = [];
1717 
1718             if (curve.length === 4) {   // bezierDegree == 3
1719                 bb[0] = Math.min(curve[0][0], curve[1][0], curve[2][0], curve[3][0]); // minX
1720                 bb[1] = Math.max(curve[0][1], curve[1][1], curve[2][1], curve[3][1]); // maxY
1721                 bb[2] = Math.max(curve[0][0], curve[1][0], curve[2][0], curve[3][0]); // maxX
1722                 bb[3] = Math.min(curve[0][1], curve[1][1], curve[2][1], curve[3][1]); // minY
1723             } else {                   // bezierDegree == 1
1724                 bb[0] = Math.min(curve[0][0], curve[1][0]); // minX
1725                 bb[1] = Math.max(curve[0][1], curve[1][1]); // maxY
1726                 bb[2] = Math.max(curve[0][0], curve[1][0]); // maxX
1727                 bb[3] = Math.min(curve[0][1], curve[1][1]); // minY
1728             }
1729 
1730             return bb;
1731         },
1732 
1733         /**
1734          * Decide if two Bezier curve segments overlap by comparing their bounding boxes.
1735          * @param {Array} bb1 Bounding box of the first Bezier curve segment
1736          * @param {Array} bb2 Bounding box of the second Bezier curve segment
1737          * @returns {Boolean} true if the bounding boxes overlap, false otherwise.
1738          */
1739         _bezierOverlap: function (bb1, bb2) {
1740             return bb1[2] >= bb2[0] && bb1[0] <= bb2[2] && bb1[1] >= bb2[3] && bb1[3] <= bb2[1];
1741         },
1742 
1743         /**
1744          * Append list of intersection points to a list.
1745          * @private
1746          */
1747         _bezierListConcat: function (L, Lnew, t1, t2) {
1748             var i,
1749                 t2exists = Type.exists(t2),
1750                 start = 0,
1751                 len = Lnew.length,
1752                 le = L.length;
1753 
1754             if (le > 0 && len > 0 &&
1755                     ((L[le - 1][1] === 1 && Lnew[0][1] === 0) ||
1756                     (t2exists && L[le - 1][2] === 1 && Lnew[0][2] === 0))) {
1757                 start = 1;
1758             }
1759 
1760             for (i = start; i < len; i++) {
1761                 if (t2exists) {
1762                     Lnew[i][2] *= 0.5;
1763                     Lnew[i][2] += t2;
1764                 }
1765 
1766                 Lnew[i][1] *= 0.5;
1767                 Lnew[i][1] += t1;
1768 
1769                 L.push(Lnew[i]);
1770             }
1771         },
1772 
1773         /**
1774          * Find intersections of two Bezier curve segments by recursive subdivision.
1775          * Below maxlevel determine intersections by intersection line segments.
1776          * @param {Array} red Array of four coordinate arrays of length 2 defining the first
1777          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
1778          * @param {Array} blue Array of four coordinate arrays of length 2 defining the second
1779          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
1780          * @param {Number} level Recursion level
1781          * @returns {Array} List of intersection points (up to nine). Each intersection point is an
1782          * array of length three (homogeneous coordinates) plus preimages.
1783          */
1784         _bezierMeetSubdivision: function (red, blue, level) {
1785             var bbb, bbr,
1786                 ar, b0, b1, r0, r1, m,
1787                 p0, p1, q0, q1,
1788                 L = [],
1789                 maxLev = 5;      // Maximum recursion level
1790 
1791             bbr = this._bezierBbox(blue);
1792             bbb = this._bezierBbox(red);
1793 
1794             if (!this._bezierOverlap(bbr, bbb)) {
1795                 return [];
1796             }
1797 
1798             if (level < maxLev) {
1799                 ar = this._bezierSplit(red);
1800                 r0 = ar[0];
1801                 r1 = ar[1];
1802 
1803                 ar = this._bezierSplit(blue);
1804                 b0 = ar[0];
1805                 b1 = ar[1];
1806 
1807                 this._bezierListConcat(L, this._bezierMeetSubdivision(r0, b0, level + 1), 0.0, 0.0);
1808                 this._bezierListConcat(L, this._bezierMeetSubdivision(r0, b1, level + 1), 0, 0.5);
1809                 this._bezierListConcat(L, this._bezierMeetSubdivision(r1, b0, level + 1), 0.5, 0.0);
1810                 this._bezierListConcat(L, this._bezierMeetSubdivision(r1, b1, level + 1), 0.5, 0.5);
1811 
1812                 return L;
1813             }
1814 
1815             // Make homogeneous coordinates
1816             q0 = [1].concat(red[0]);
1817             q1 = [1].concat(red[3]);
1818             p0 = [1].concat(blue[0]);
1819             p1 = [1].concat(blue[3]);
1820 
1821             m = this.meetSegmentSegment(q0, q1, p0, p1);
1822 
1823             if (m[1] >= 0.0 && m[2] >= 0.0 && m[1] <= 1.0 && m[2] <= 1.0) {
1824                 return [m];
1825             }
1826 
1827             return [];
1828         },
1829 
1830         /**
1831          * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the line defined by the segment
1832          */
1833         _bezierLineMeetSubdivision: function (red, blue, level, testSegment) {
1834             var bbb, bbr,
1835                 ar, r0, r1, m,
1836                 p0, p1, q0, q1,
1837                 L = [],
1838                 maxLev = 5;      // Maximum recursion level
1839 
1840             bbb = this._bezierBbox(blue);
1841             bbr = this._bezierBbox(red);
1842 
1843             if (testSegment && !this._bezierOverlap(bbr, bbb)) {
1844                 return [];
1845             }
1846 
1847             if (level < maxLev) {
1848                 ar = this._bezierSplit(red);
1849                 r0 = ar[0];
1850                 r1 = ar[1];
1851 
1852                 this._bezierListConcat(L, this._bezierLineMeetSubdivision(r0, blue, level + 1), 0.0);
1853                 this._bezierListConcat(L, this._bezierLineMeetSubdivision(r1, blue, level + 1), 0.5);
1854 
1855                 return L;
1856             }
1857 
1858             // Make homogeneous coordinates
1859             q0 = [1].concat(red[0]);
1860             q1 = [1].concat(red[3]);
1861             p0 = [1].concat(blue[0]);
1862             p1 = [1].concat(blue[1]);
1863 
1864             m = this.meetSegmentSegment(q0, q1, p0, p1);
1865 
1866             if (m[1] >= 0.0 && m[1] <= 1.0) {
1867                 if (!testSegment || (m[2] >= 0.0 && m[2] <= 1.0)) {
1868                     return [m];
1869                 }
1870             }
1871 
1872             return [];
1873         },
1874 
1875         /**
1876          * Find the nr-th intersection point of two Bezier curve segments.
1877          * @param {Array} red Array of four coordinate arrays of length 2 defining the first
1878          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
1879          * @param {Array} blue Array of four coordinate arrays of length 2 defining the second
1880          * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].
1881          * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the line defined by the segment
1882          * @returns {Array} Array containing the list of all intersection points as homogeneous coordinate arrays plus
1883          * preimages [x,y], t_1, t_2] of the two Bezier curve segments.
1884          *
1885          */
1886         meetBeziersegmentBeziersegment: function (red, blue, testSegment) {
1887             var L, L2, i;
1888 
1889             if (red.length === 4 && blue.length === 4) {
1890                 L = this._bezierMeetSubdivision(red, blue, 0);
1891             } else {
1892                 L = this._bezierLineMeetSubdivision(red, blue, 0, testSegment);
1893             }
1894 
1895             L.sort(function (a, b) {
1896                 return (a[1] - b[1]) * 10000000.0 + (a[2] - b[2]);
1897             });
1898 
1899             L2 = [];
1900             for (i = 0; i < L.length; i++) {
1901                 // Only push entries different from their predecessor
1902                 if (i === 0 || (L[i][1] !== L[i - 1][1] || L[i][2] !== L[i - 1][2])) {
1903                     L2.push(L[i]);
1904                 }
1905             }
1906             return L2;
1907         },
1908 
1909         /**
1910          * Find the nr-th intersection point of two Bezier curves, i.e. curves with bezierDegree == 3.
1911          * @param {JXG.Curve} red Curve with bezierDegree == 3
1912          * @param {JXG.Curve} blue Curve with bezierDegree == 3
1913          * @param {Number} nr The number of the intersection point which should be returned.
1914          * @returns {Array} The homogeneous coordinates of the nr-th intersection point.
1915          */
1916         meetBezierCurveRedBlueSegments: function (red, blue, nr) {
1917             var p, i, j,
1918                 redArr, blueArr,
1919                 bbr, bbb,
1920                 lenBlue = blue.numberPoints, //points.length,
1921                 lenRed = red.numberPoints, // points.length,
1922                 L = [];
1923 
1924             if (lenBlue < 4 || lenRed < 4) {
1925                 return [0, NaN, NaN];
1926             }
1927 
1928             for (i = 0; i < lenRed - 3; i += 3) {
1929                 p = red.points;
1930                 redArr = [
1931                     [p[i].usrCoords[1], p[i].usrCoords[2]],
1932                     [p[i + 1].usrCoords[1], p[i + 1].usrCoords[2]],
1933                     [p[i + 2].usrCoords[1], p[i + 2].usrCoords[2]],
1934                     [p[i + 3].usrCoords[1], p[i + 3].usrCoords[2]]
1935                 ];
1936 
1937                 bbr = this._bezierBbox(redArr);
1938 
1939                 for (j = 0; j < lenBlue - 3; j += 3) {
1940                     p = blue.points;
1941                     blueArr = [
1942                         [p[j].usrCoords[1], p[j].usrCoords[2]],
1943                         [p[j + 1].usrCoords[1], p[j + 1].usrCoords[2]],
1944                         [p[j + 2].usrCoords[1], p[j + 2].usrCoords[2]],
1945                         [p[j + 3].usrCoords[1], p[j + 3].usrCoords[2]]
1946                     ];
1947 
1948                     bbb = this._bezierBbox(blueArr);
1949                     if (this._bezierOverlap(bbr, bbb)) {
1950                         L = L.concat(this.meetBeziersegmentBeziersegment(redArr, blueArr));
1951                         if (L.length > nr) {
1952                             return L[nr][0];
1953                         }
1954                     }
1955                 }
1956             }
1957             if (L.length > nr) {
1958                 return L[nr][0];
1959             }
1960 
1961             return [0, NaN, NaN];
1962         },
1963 
1964         bezierSegmentEval: function (t, curve) {
1965             var f, x, y,
1966                 t1 = 1.0 - t;
1967 
1968             x = 0;
1969             y = 0;
1970 
1971             f = t1 * t1 * t1;
1972             x += f * curve[0][0];
1973             y += f * curve[0][1];
1974 
1975             f = 3.0 * t * t1 * t1;
1976             x += f * curve[1][0];
1977             y += f * curve[1][1];
1978 
1979             f = 3.0 * t * t * t1;
1980             x += f * curve[2][0];
1981             y += f * curve[2][1];
1982 
1983             f = t * t * t;
1984             x += f * curve[3][0];
1985             y += f * curve[3][1];
1986 
1987             return [1.0, x, y];
1988         },
1989 
1990         /**
1991          * Generate the defining points of a 3rd degree bezier curve that approximates
1992          * a circle sector defined by three arrays A, B,C, each of length three.
1993          * The coordinate arrays are given in homogeneous coordinates.
1994          * @param {Array} A First point
1995          * @param {Array} B Second point (intersection point)
1996          * @param {Array} C Third point
1997          * @param {Boolean} withLegs Flag. If true the legs to the intersection point are part of the curve.
1998          * @param {Number} sgn Wither 1 or -1. Needed for minor and major arcs. In case of doubt, use 1.
1999          */
2000         bezierArc: function (A, B, C, withLegs, sgn) {
2001             var p1, p2, p3, p4,
2002                 r, phi, beta,
2003                 PI2 = Math.PI * 0.5,
2004                 x = B[1],
2005                 y = B[2],
2006                 z = B[0],
2007                 dataX = [], dataY = [],
2008                 co, si, ax, ay, bx, by, k, v, d, matrix;
2009 
2010             r = this.distance(B, A);
2011 
2012             // x,y, z is intersection point. Normalize it.
2013             x /= z;
2014             y /= z;
2015 
2016             phi = this.rad(A.slice(1), B.slice(1), C.slice(1));
2017             if (sgn === -1) {
2018                 phi = 2 * Math.PI - phi;
2019             }
2020 
2021             p1 = A;
2022             p1[1] /= p1[0];
2023             p1[2] /= p1[0];
2024             p1[0] /= p1[0];
2025 
2026             p4 = p1.slice(0);
2027 
2028             if (withLegs) {
2029                 dataX = [x, x + 0.333 * (p1[1] - x), x + 0.666 * (p1[1] - x), p1[1]];
2030                 dataY = [y, y + 0.333 * (p1[2] - y), y + 0.666 * (p1[2] - y), p1[2]];
2031             } else {
2032                 dataX = [p1[1]];
2033                 dataY = [p1[2]];
2034             }
2035 
2036             while (phi > Mat.eps) {
2037                 if (phi > PI2) {
2038                     beta = PI2;
2039                     phi -= PI2;
2040                 } else {
2041                     beta = phi;
2042                     phi = 0;
2043                 }
2044 
2045                 co = Math.cos(sgn * beta);
2046                 si = Math.sin(sgn * beta);
2047 
2048                 matrix = [
2049                     [1, 0, 0],
2050                     [x * (1 - co) + y * si, co, -si],
2051                     [y * (1 - co) - x * si, si,  co]
2052                 ];
2053                 v = Mat.matVecMult(matrix, p1);
2054                 p4 = [v[0] / v[0], v[1] / v[0], v[2] / v[0]];
2055 
2056                 ax = p1[1] - x;
2057                 ay = p1[2] - y;
2058                 bx = p4[1] - x;
2059                 by = p4[2] - y;
2060 
2061                 d = Math.sqrt((ax + bx) * (ax + bx) + (ay + by) * (ay + by));
2062 
2063                 if (Math.abs(by - ay) > Mat.eps) {
2064                     k = (ax + bx) * (r / d - 0.5) / (by - ay) * 8 / 3;
2065                 } else {
2066                     k = (ay + by) * (r / d - 0.5) / (ax - bx) * 8 / 3;
2067                 }
2068 
2069                 p2 = [1, p1[1] - k * ay, p1[2] + k * ax];
2070                 p3 = [1, p4[1] + k * by, p4[2] - k * bx];
2071 
2072                 dataX = dataX.concat([p2[1], p3[1], p4[1]]);
2073                 dataY = dataY.concat([p2[2], p3[2], p4[2]]);
2074                 p1 = p4.slice(0);
2075             }
2076 
2077             if (withLegs) {
2078                 dataX = dataX.concat([ p4[1] + 0.333 * (x - p4[1]), p4[1] + 0.666 * (x - p4[1]), x]);
2079                 dataY = dataY.concat([ p4[2] + 0.333 * (y - p4[2]), p4[2] + 0.666 * (y - p4[2]), y]);
2080             }
2081 
2082             return [dataX, dataY];
2083         },
2084 
2085         /****************************************/
2086         /****           PROJECTIONS          ****/
2087         /****************************************/
2088 
2089         /**
2090          * Calculates the coordinates of the projection of a given point on a given circle. I.o.w. the
2091          * nearest one of the two intersection points of the line through the given point and the circles
2092          * center.
2093          * @param {JXG.Point,JXG.Coords} point Point to project or coords object to project.
2094          * @param {JXG.Circle} circle Circle on that the point is projected.
2095          * @param {JXG.Board} [board=point.board] Reference to the board
2096          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.
2097          */
2098         projectPointToCircle: function (point, circle, board) {
2099             var dist, P, x, y, factor,
2100                 M = circle.center.coords.usrCoords;
2101 
2102             if (!Type.exists(board)) {
2103                 board = point.board;
2104             }
2105 
2106             // gave us a point
2107             if (Type.isPoint(point)) {
2108                 dist = point.coords.distance(Const.COORDS_BY_USER, circle.center.coords);
2109                 P = point.coords.usrCoords;
2110             // gave us coords
2111             } else {
2112                 dist = point.distance(Const.COORDS_BY_USER, circle.center.coords);
2113                 P = point.usrCoords;
2114             }
2115 
2116             if (Math.abs(dist) < Mat.eps) {
2117                 dist = Mat.eps;
2118             }
2119 
2120             factor = circle.Radius() / dist;
2121             x = M[1] + factor * (P[1] - M[1]);
2122             y = M[2] + factor * (P[2] - M[2]);
2123 
2124             return new Coords(Const.COORDS_BY_USER, [x, y], board);
2125         },
2126 
2127         /**
2128          * Calculates the coordinates of the orthogonal projection of a given point on a given line. I.o.w. the
2129          * intersection point of the given line and its perpendicular through the given point.
2130          * @param {JXG.Point} point Point to project.
2131          * @param {JXG.Line} line Line on that the point is projected.
2132          * @param {JXG.Board} [board=point.board] Reference to a board.
2133          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given line.
2134          */
2135         projectPointToLine: function (point, line, board) {
2136             // Homogeneous version
2137             var v = [0, line.stdform[1], line.stdform[2]];
2138 
2139             if (!Type.exists(board)) {
2140                 board = point.board;
2141             }
2142 
2143             v = Mat.crossProduct(v, point.coords.usrCoords);
2144             //return this.meetLineLine(v, line.stdform, 0, board);
2145             return new Coords(Const.COORDS_BY_USER, Mat.crossProduct(v, line.stdform), board);
2146         },
2147 
2148         /**
2149          * Calculates the coordinates of the orthogonal projection of a given coordinate array on a given line
2150          * segment defined by two coordinate arrays.
2151          * @param {Array} p Point to project.
2152          * @param {Array} q1 Start point of the line segment on that the point is projected.
2153          * @param {Array} q2 End point of the line segment on that the point is projected.
2154          * @returns {Array} The coordinates of the projection of the given point on the given segment
2155          * and the factor that determines the projected point as a convex combination of the
2156          * two endpoints q1 and q2 of the segment.
2157          */
2158         projectCoordsToSegment: function (p, q1, q2) {
2159             var t, denom,
2160                 s = [q2[1] - q1[1], q2[2] - q1[2]],
2161                 v = [p[1] - q1[1], p[2] - q1[2]];
2162 
2163             /**
2164              * If the segment has length 0, i.e. is a point,
2165              * the projection is equal to that point.
2166              */
2167             if (Math.abs(s[0]) < Mat.eps && Math.abs(s[1]) < Mat.eps) {
2168                 return [q1, 0];
2169             }
2170 
2171             t = Mat.innerProduct(v, s);
2172             denom = Mat.innerProduct(s, s);
2173             t /= denom;
2174 
2175             return [ [1, t * s[0] + q1[1], t * s[1] + q1[2]], t];
2176         },
2177 
2178         /**
2179          * Finds the coordinates of the closest point on a Bezier segment of a
2180          * {@link JXG.Curve} to a given coordinate array.
2181          * @param {Array} pos Point to project in homogeneous coordinates.
2182          * @param {JXG.Curve} curve Curve of type "plot" having Bezier degree 3.
2183          * @param {Number} start Number of the Bezier segment of the curve.
2184          * @returns {Array} The coordinates of the projection of the given point
2185          * on the given Bezier segment and the preimage of the curve which
2186          * determines the closest point.
2187          */
2188         projectCoordsToBeziersegment: function (pos, curve, start) {
2189             var t0,
2190                 minfunc = function (t) {
2191                     var z = [1, curve.X(start + t), curve.Y(start + t)];
2192 
2193                     z[1] -= pos[1];
2194                     z[2] -= pos[2];
2195 
2196                     return z[1] * z[1] + z[2] * z[2];
2197                 };
2198 
2199             t0 = JXG.Math.Numerics.fminbr(minfunc, [0.0, 1.0]);
2200 
2201             return [[1, curve.X(t0 + start), curve.Y(t0 + start)], t0];
2202         },
2203 
2204         /**
2205          * Calculates the coordinates of the projection of a given point on a given curve.
2206          * Uses {@link JXG.Math.Geometry.projectCoordsToCurve}.
2207          *
2208          * @param {JXG.Point} point Point to project.
2209          * @param {JXG.Curve} curve Curve on that the point is projected.
2210          * @param {JXG.Board} [board=point.board] Reference to a board.
2211          * @see #projectCoordsToCurve
2212          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given graph.
2213          */
2214         projectPointToCurve: function (point, curve, board) {
2215             if (!Type.exists(board)) {
2216                 board = point.board;
2217             }
2218 
2219             var x = point.X(),
2220                 y = point.Y(),
2221                 t = point.position || 0.0,
2222                 result = this.projectCoordsToCurve(x, y, t, curve, board);
2223 
2224             point.position = result[1];
2225 
2226             return result[0];
2227         },
2228 
2229         /**
2230          * Calculates the coordinates of the projection of a coordinates pair on a given curve. In case of
2231          * function graphs this is the
2232          * intersection point of the curve and the parallel to y-axis through the given point.
2233          * @param {Number} x coordinate to project.
2234          * @param {Number} y coordinate to project.
2235          * @param {Number} t start value for newtons method
2236          * @param {JXG.Curve} curve Curve on that the point is projected.
2237          * @param {JXG.Board} [board=curve.board] Reference to a board.
2238          * @see #projectPointToCurve
2239          * @returns {JXG.Coords} Array containing the coordinates of the projection of the given point on the given graph and
2240          * the position on the curve.
2241          */
2242         projectCoordsToCurve: function (x, y, t, curve, board) {
2243             var newCoords, newCoordsObj, i, j,
2244                 mindist, dist, lbda, v, coords, d,
2245                 p1, p2, res,
2246                 minfunc, tnew, fnew, fold, delta, steps,
2247                 infty = Number.POSITIVE_INFINITY;
2248 
2249             if (!Type.exists(board)) {
2250                 board = curve.board;
2251             }
2252 
2253             if (Type.evaluate(curve.visProp.curvetype) === 'plot') {
2254                 t = 0;
2255                 mindist = infty;
2256 
2257                 if (curve.numberPoints === 0) {
2258                     newCoords = [0, 1, 1];
2259                 } else {
2260                     newCoords = [curve.Z(0), curve.X(0), curve.Y(0)];
2261                 }
2262 
2263                 if (curve.numberPoints > 1) {
2264 
2265                     v = [1, x, y];
2266                     if (curve.bezierDegree === 3) {
2267                         j = 0;
2268                     } else {
2269                         p1 = [curve.Z(0), curve.X(0), curve.Y(0)];
2270                     }
2271                     for (i = 0; i < curve.numberPoints - 1; i++) {
2272                         if (curve.bezierDegree === 3) {
2273                             res = this.projectCoordsToBeziersegment(v, curve, j);
2274                         } else {
2275                             p2 = [curve.Z(i + 1), curve.X(i + 1), curve.Y(i + 1)];
2276                             res = this.projectCoordsToSegment(v, p1, p2);
2277                         }
2278                         lbda = res[1];
2279                         coords = res[0];
2280 
2281                         if (0.0 <= lbda && lbda <= 1.0) {
2282                             dist = this.distance(coords, v);
2283                             d = i + lbda;
2284                         } else if (lbda < 0.0) {
2285                             coords = p1;
2286                             dist = this.distance(p1, v);
2287                             d = i;
2288                         } else if (lbda > 1.0 && i === curve.numberPoints - 2) {
2289                             coords = p2;
2290                             dist = this.distance(coords, v);
2291                             d = curve.numberPoints - 1;
2292                         }
2293 
2294                         if (dist < mindist) {
2295                             mindist = dist;
2296                             t = d;
2297                             newCoords = coords;
2298                         }
2299 
2300                         if (curve.bezierDegree === 3) {
2301                             j++;
2302                             i += 2;
2303                         } else {
2304                             p1 = p2;
2305                         }
2306                     }
2307                 }
2308 
2309                 newCoordsObj = new Coords(Const.COORDS_BY_USER, newCoords, board);
2310             } else {   // 'parameter', 'polar', 'functiongraph'
2311                 minfunc = function (t) {
2312                     var dx = x - curve.X(t),
2313                         dy = y - curve.Y(t);
2314                     return dx * dx + dy * dy;
2315                 };
2316 
2317                 fold = minfunc(t);
2318                 steps = 50;
2319                 delta = (curve.maxX() - curve.minX()) / steps;
2320                 tnew = curve.minX();
2321 
2322                 for (i = 0; i < steps; i++) {
2323                     fnew = minfunc(tnew);
2324 
2325                     if (fnew < fold || isNaN(fold)) {
2326                         t = tnew;
2327                         fold = fnew;
2328                     }
2329 
2330                     tnew += delta;
2331                 }
2332 
2333                 //t = Numerics.root(Numerics.D(minfunc), t);
2334                 t = Numerics.fminbr(minfunc, [t - delta, t + delta]);
2335 
2336                 if (t < curve.minX()) {
2337                     t = curve.maxX() + t - curve.minX();
2338                 }
2339 
2340                 // Cyclically
2341                 if (t > curve.maxX()) {
2342                     t = curve.minX() + t - curve.maxX();
2343                 }
2344 
2345                 newCoordsObj = new Coords(Const.COORDS_BY_USER, [curve.X(t), curve.Y(t)], board);
2346             }
2347 
2348             return [curve.updateTransform(newCoordsObj), t];
2349         },
2350 
2351         /**
2352          * Calculates the coordinates of the closest orthogonal projection of a given coordinate array onto the
2353          * border of a polygon.
2354          * @param {Array} p Point to project.
2355          * @param {JXG.Polygon} pol Polygon element
2356          * @returns {Array} The coordinates of the closest projection of the given point to the border of the polygon.
2357          */
2358         projectCoordsToPolygon: function (p, pol) {
2359             var i,
2360                 len = pol.vertices.length,
2361                 d_best = Infinity,
2362                 d,
2363                 projection,
2364                 bestprojection;
2365 
2366             for (i = 0; i < len; i++) {
2367                 projection = JXG.Math.Geometry.projectCoordsToSegment(
2368                     p,
2369                     pol.vertices[i].coords.usrCoords,
2370                     pol.vertices[(i + 1) % len].coords.usrCoords
2371                 );
2372 
2373                 d = JXG.Math.Geometry.distance(projection[0], p, 3);
2374                 if (0 <= projection[1] && projection[1] <= 1 && d < d_best) {
2375                     bestprojection = projection[0].slice(0);
2376                     d_best = d;
2377                 }
2378             }
2379             return bestprojection;
2380         },
2381 
2382         /**
2383          * Calculates the coordinates of the projection of a given point on a given turtle. A turtle consists of
2384          * one or more curves of curveType 'plot'. Uses {@link JXG.Math.Geometry.projectPointToCurve}.
2385          * @param {JXG.Point} point Point to project.
2386          * @param {JXG.Turtle} turtle on that the point is projected.
2387          * @param {JXG.Board} [board=point.board] Reference to a board.
2388          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given turtle.
2389          */
2390         projectPointToTurtle: function (point, turtle, board) {
2391             var newCoords, t, x, y, i, dist, el, minEl,
2392                 np = 0,
2393                 npmin = 0,
2394                 mindist = Number.POSITIVE_INFINITY,
2395                 len = turtle.objects.length;
2396 
2397             if (!Type.exists(board)) {
2398                 board = point.board;
2399             }
2400 
2401             // run through all curves of this turtle
2402             for (i = 0; i < len; i++) {
2403                 el = turtle.objects[i];
2404 
2405                 if (el.elementClass === Const.OBJECT_CLASS_CURVE) {
2406                     newCoords = this.projectPointToCurve(point, el);
2407                     dist = this.distance(newCoords.usrCoords, point.coords.usrCoords);
2408 
2409                     if (dist < mindist) {
2410                         x = newCoords.usrCoords[1];
2411                         y = newCoords.usrCoords[2];
2412                         t = point.position;
2413                         mindist = dist;
2414                         minEl = el;
2415                         npmin = np;
2416                     }
2417                     np += el.numberPoints;
2418                 }
2419             }
2420 
2421             newCoords = new Coords(Const.COORDS_BY_USER, [x, y], board);
2422             point.position = t + npmin;
2423 
2424             return minEl.updateTransform(newCoords);
2425         },
2426 
2427         /**
2428          * Trivial projection of a point to another point.
2429          * @param {JXG.Point} point Point to project (not used).
2430          * @param {JXG.Point} dest Point on that the point is projected.
2431          * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.
2432          */
2433         projectPointToPoint: function (point, dest) {
2434             return dest.coords;
2435         },
2436 
2437         /**
2438          *
2439          * @param {JXG.Point|JXG.Coords} point
2440          * @param {JXG.Board} [board]
2441          */
2442         projectPointToBoard: function (point, board) {
2443             var i, l, c,
2444                 brd = board || point.board,
2445                 // comparison factor, point coord idx, bbox idx, 1st bbox corner x & y idx, 2nd bbox corner x & y idx
2446                 config = [
2447                     // left
2448                     [1, 1, 0, 0, 3, 0, 1],
2449                     // top
2450                     [-1, 2, 1, 0, 1, 2, 1],
2451                     // right
2452                     [-1, 1, 2, 2, 1, 2, 3],
2453                     // bottom
2454                     [1, 2, 3, 0, 3, 2, 3]
2455                 ],
2456                 coords = point.coords || point,
2457                 bbox = brd.getBoundingBox();
2458 
2459             for (i = 0; i < 4; i++) {
2460                 c = config[i];
2461                 if (c[0] * coords.usrCoords[c[1]] < c[0] * bbox[c[2]]) {
2462                     // define border
2463                     l = Mat.crossProduct([1, bbox[c[3]], bbox[c[4]]], [1, bbox[c[5]], bbox[c[6]]]);
2464                     l[3] = 0;
2465                     l = Mat.normalize(l);
2466 
2467                     // project point
2468                     coords = this.projectPointToLine({coords: coords}, {stdform: l}, brd);
2469                 }
2470             }
2471 
2472             return coords;
2473         },
2474 
2475         /**
2476          * Calculates the distance of a point to a line. The point and the line are given by homogeneous
2477          * coordinates. For lines this can be line.stdform.
2478          * @param {Array} point Homogeneous coordinates of a point.
2479          * @param {Array} line Homogeneous coordinates of a line ([C,A,B] where A*x+B*y+C*z=0).
2480          * @returns {Number} Distance of the point to the line.
2481          */
2482         distPointLine: function (point, line) {
2483             var a = line[1],
2484                 b = line[2],
2485                 c = line[0],
2486                 nom;
2487 
2488             if (Math.abs(a) + Math.abs(b) < Mat.eps) {
2489                 return Number.POSITIVE_INFINITY;
2490             }
2491 
2492             nom = a * point[1] + b * point[2] + c;
2493             a *= a;
2494             b *= b;
2495 
2496             return Math.abs(nom) / Math.sqrt(a + b);
2497         },
2498 
2499 
2500         /**
2501          * Helper function to create curve which displays a Reuleaux polygons.
2502          * @param {Array} points Array of points which should be the vertices of the Reuleaux polygon. Typically,
2503          * these point list is the array vertices of a regular polygon.
2504          * @param {Number} nr Number of vertices
2505          * @returns {Array} An array containing the two functions defining the Reuleaux polygon and the two values
2506          * for the start and the end of the paramtric curve. array may be used as parent array of a
2507          * {@link JXG.Curve}.
2508          *
2509          * @example
2510          * var A = brd.create('point',[-2,-2]);
2511          * var B = brd.create('point',[0,1]);
2512          * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0});
2513          * var reuleauxTriangle = brd.create('curve', JXG.Math.Geometry.reuleauxPolygon(pol.vertices, 3),
2514          *                          {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});
2515          *
2516          * </pre><div class="jxgbox" id="2543a843-46a9-4372-abc1-94d9ad2db7ac" style="width: 300px; height: 300px;"></div>
2517          * <script type="text/javascript">
2518          * var brd = JXG.JSXGraph.initBoard('2543a843-46a9-4372-abc1-94d9ad2db7ac', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false});
2519          * var A = brd.create('point',[-2,-2]);
2520          * var B = brd.create('point',[0,1]);
2521          * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0});
2522          * var reuleauxTriangle = brd.create('curve', JXG.Math.Geometry.reuleauxPolygon(pol.vertices, 3),
2523          *                          {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});
2524          * </script><pre>
2525          */
2526         reuleauxPolygon: function (points, nr) {
2527             var beta,
2528                 pi2 = Math.PI * 2,
2529                 pi2_n = pi2 / nr,
2530                 diag = (nr - 1) / 2,
2531                 d = 0,
2532                 makeFct = function (which, trig) {
2533                     return function (t, suspendUpdate) {
2534                         var t1 = (t % pi2 + pi2) % pi2,
2535                             j = Math.floor(t1 / pi2_n) % nr;
2536 
2537                         if (!suspendUpdate) {
2538                             d = points[0].Dist(points[diag]);
2539                             beta = Mat.Geometry.rad([points[0].X() + 1, points[0].Y()], points[0], points[diag % nr]);
2540                         }
2541 
2542                         if (isNaN(j)) {
2543                             return j;
2544                         }
2545 
2546                         t1 = t1 * 0.5 + j * pi2_n * 0.5 + beta;
2547 
2548                         return points[j][which]() + d * Math[trig](t1);
2549                     };
2550                 };
2551 
2552             return [makeFct('X', 'cos'), makeFct('Y', 'sin'), 0, pi2];
2553         }
2554     });
2555 
2556     return Mat.Geometry;
2557 });
2558