diff options
Diffstat (limited to 'Master/texmf/asymptote/geometry.asy')
-rw-r--r-- | Master/texmf/asymptote/geometry.asy | 7192 |
1 files changed, 0 insertions, 7192 deletions
diff --git a/Master/texmf/asymptote/geometry.asy b/Master/texmf/asymptote/geometry.asy deleted file mode 100644 index bbbc823fc54..00000000000 --- a/Master/texmf/asymptote/geometry.asy +++ /dev/null @@ -1,7192 +0,0 @@ -// geometry.asy - -// Copyright (C) 2007 -// Author: Philippe IVALDI 2007/09/01 -// http://www.piprime.fr/ - -// This program is free software ; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation ; either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY ; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public License -// along with this program ; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -// COMMENTARY: -// An Asymptote geometry module. - -// THANKS: -// Special thanks to Olivier Guibé for his help in mathematical issues. - -// BUGS: - -// CODE: - -import math; -import markers; - -// A rotation in the direction dir limited to [-90,90] -// This is useful for rotating text along a line in the direction dir. -private transform rotate(explicit pair dir) -{ - real angle=degrees(dir); - if(angle > 90 && angle < 270) angle -= 180; - return rotate(angle); -} - -// *=======================================================* -// *........................HEADER.........................* -/*<asyxml><variable type="real" signature="epsgeo"><code></asyxml>*/ -real epsgeo = 10 * sqrt(realEpsilon);/*<asyxml></code><documentation>Variable used in the approximate calculations.</documentation></variable></asyxml>*/ - -/*<asyxml><function type="void" signature="addMargins(picture,real,real,real,real)"><code></asyxml>*/ -void addMargins(picture pic = currentpicture, - real lmargin = 0, real bmargin = 0, - real rmargin = lmargin, real tmargin = bmargin, - bool rigid = true, bool allObject = true) -{/*<asyxml></code><documentation>Add margins to 'pic' with respect to - the current bounding box of 'pic'. - If 'rigid' is false, margins are added iff an infinite curve will - be prolonged on the margin. - If 'allObject' is false, fixed - size objects (such as labels and - arrowheads) will be ignored.</documentation></function></asyxml>*/ - pair m = allObject ? truepoint(pic, SW) : point(pic, SW); - pair M = allObject ? truepoint(pic, NE) : point(pic, NE); - if(rigid) { - draw(m - inverse(pic.calculateTransform()) * (lmargin, bmargin), invisible); - draw(M + inverse(pic.calculateTransform()) * (rmargin, tmargin), invisible); - } else pic.addBox(m, M, -(lmargin, bmargin), (rmargin, tmargin)); -} - -real approximate(real t) -{ - real ot = t; - if(abs(t - ceil(t)) < epsgeo) ot = ceil(t); - else if(abs(t - floor(t)) < epsgeo) ot = floor(t); - return ot; -} - -real[] approximate(real[] T) -{ - return map(approximate, T); -} - -/*<asyxml><function type="real" signature="binomial(real,real)"><code></asyxml>*/ -real binomial(real n, real k) -{/*<asyxml></code><documentation>Return n!/((n - k)!*k!)</documentation></function></asyxml>*/ - return gamma(n + 1)/(gamma(n - k + 1) * gamma(k + 1)); -} - -/*<asyxml><function type="real" signature="rf(real,real,real)"><code></asyxml>*/ -real rf(real x, real y, real z) -{/*<asyxml></code><documentation>Computes Carlson's elliptic integral of the first kind. - x, y, and z must be non negative, and at most one can be zero.</documentation></function></asyxml>*/ - real ERRTOL = 0.0025, - TINY = 1.5e-38, - BIG = 3e37, - THIRD = 1/3, - C1 = 1/24, - C2 = 0.1, - C3 = 3/44, - C4 = 1/14; - real alamb, ave, delx, dely, delz, e2, e3, sqrtx, sqrty, sqrtz, xt, yt, zt; - if(min(x, y, z) < 0 || min(x + y, x + z, y + z) < TINY || - max(x, y, z) > BIG) abort("rf: invalid arguments."); - xt = x; - yt = y; - zt = z; - do { - sqrtx = sqrt(xt); - sqrty = sqrt(yt); - sqrtz = sqrt(zt); - alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz; - xt = 0.25 * (xt + alamb); - yt = 0.25 * (yt + alamb); - zt = 0.25 * (zt + alamb); - ave = THIRD * (xt + yt + zt); - delx = (ave - xt)/ave; - dely = (ave - yt)/ave; - delz = (ave - zt)/ave; - } while(max(fabs(delx), fabs(dely), fabs(delz)) > ERRTOL); - e2 = delx * dely - delz * delz; - e3 = delx * dely * delz; - return (1.0 + (C1 * e2 - C2 - C3 * e3) * e2 + C4 * e3)/sqrt(ave); -} - -/*<asyxml><function type="real" signature="rd(real,real,real)"><code></asyxml>*/ -real rd(real x, real y, real z) -{/*<asyxml></code><documentation>Computes Carlson's elliptic integral of the second kind. - x and y must be positive, and at most one can be zero. - z must be non negative.</documentation></function></asyxml>*/ - real ERRTOL = 0.0015, - TINY = 1e-25, - BIG = 4.5 * 10.0^21, - C1 = (3/14), - C2 = (1/6), - C3 = (9/22), - C4 = (3/26), - C5 = (0.25 * C3), - C6 = (1.5 * C4); - real alamb, ave, delx, dely, delz, ea, eb, ec, ed, ee, fac, sqrtx, sqrty, - sqrtz, sum, xt, yt, zt; - if (min(x, y) < 0 || min(x + y, z) < TINY || max(x, y, z) > BIG) - abort("rd: invalid arguments"); - xt = x; - yt = y; - zt = z; - sum = 0; - fac = 1; - do { - sqrtx = sqrt(xt); - sqrty = sqrt(yt); - sqrtz = sqrt(zt); - alamb = sqrtx * (sqrty + sqrtz) + sqrty * sqrtz; - sum += fac/(sqrtz * (zt + alamb)); - fac = 0.25 * fac; - xt = 0.25 * (xt + alamb); - yt = 0.25 * (yt + alamb); - zt = 0.25 * (zt + alamb); - ave = 0.2 * (xt + yt + 3.0 * zt); - delx = (ave - xt)/ave; - dely = (ave - yt)/ave; - delz = (ave - zt)/ave; - } while (max(fabs(delx), fabs(dely), fabs(delz)) > ERRTOL); - ea = delx * dely; - eb = delz * delz; - ec = ea - eb; - ed = ea - 6 * eb; - ee = ed + ec + ec; - return 3 * sum + fac * (1.0 + ed * (-C1 + C5 * ed - C6 * delz * ee) - +delz * (C2 * ee + delz * (-C3 * ec + delz * C4 * ea)))/(ave * sqrt(ave)); -} - -/*<asyxml><function type="real" signature="elle(real,real)"><code></asyxml>*/ -real elle(real phi, real k) -{/*<asyxml></code><documentation>Legendre elliptic integral of the 2nd kind, - evaluated using Carlson's functions RD and RF. - The argument ranges are -infinity < phi < +infinity, 0 <= k * sin(phi) <= 1.</documentation></function></asyxml>*/ - real result; - if (phi >= 0 && phi <= pi/2) { - real cc, q, s; - s = sin(phi); - cc = cos(phi)^2; - q = (1 - s * k) * (1 + s * k); - result = s * (rf(cc, q, 1) - (s * k)^2 * rd(cc, q, 1)/3); - } else - if (phi <= pi && phi >= 0) { - result = 2 * elle(pi/2, k) - elle(pi - phi, k); - } else - if (phi <= 3 * pi/2 && phi >= 0) { - result = 2 * elle(pi/2, k) + elle(phi - pi, k); - } else - if (phi <= 2 * pi && phi >= 0) { - result = 4 * elle(pi/2, k) - elle(2 * pi - phi, k); - } else - if (phi >= 0) { - int nb = floor(0.5 * phi/pi); - result = nb * elle(2 * pi, k) + elle(phi%(2 * pi), k); - } else result = -elle(-phi, k); - return result; -} - -/*<asyxml><function type="pair[]" signature="intersectionpoints(pair,pair,real,real,real,real,real,real)"><code></asyxml>*/ -pair[] intersectionpoints(pair A, pair B, - real a, real b, real c, real d, real f, real g) -{/*<asyxml></code><documentation>Intersection points with the line (AB) and the quadric curve - a * x^2 + b * x * y + c * y^2 + d * x + f * y + g = 0 given in the default coordinate system</documentation></function></asyxml>*/ - pair[] op; - real ap = B.y - A.y, - bpp = A.x - B.x, - cp = A.y * B.x - A.x * B.y; - real sol[]; - if (abs(ap) > epsgeo) { - real aa = ap * c + a * bpp^2/ap - b * bpp, - bb = ap * f - bpp * d + 2 * a * bpp * cp/ap - b * cp, - cc = ap * g - cp * d + a * cp^2/ap; - sol = quadraticroots(aa, bb, cc); - for (int i = 0; i < sol.length; ++i) { - op.push((-bpp * sol[i]/ap - cp/ap, sol[i])); - } - } else { - real aa = a * bpp, - bb = d * bpp - b * cp, - cc = g * bpp - cp * f + c * cp^2/bpp; - sol = quadraticroots(aa, bb, cc); - for (int i = 0; i < sol.length; ++i) { - op.push((sol[i], -cp/bpp)); - } - } - return op; -} - -/*<asyxml><function type="pair[]" signature="intersectionpoints(pair,pair,real[])"><code></asyxml>*/ -pair[] intersectionpoints(pair A, pair B, real[] equation) -{/*<asyxml></code><documentation>Return the intersection points of the line AB with - the conic whose an equation is - equation[0] * x^2 + equation[1] * x * y + equation[2] * y^2 + equation[3] * x + equation[4] * y + equation[5] = 0</documentation></function></asyxml>*/ - if(equation.length != 6) abort("intersectionpoints: bad length of array for a conic equation."); - return intersectionpoints(A, B, equation[0], equation[1], equation[2], - equation[3], equation[4], equation[5]); -} -// *........................HEADER.........................* -// *=======================================================* - -// *=======================================================* -// *......................COORDINATES......................* - -real EPS = sqrt(realEpsilon); - -/*<asyxml><typedef type = "convert" return = "pair" params = "pair"><code></asyxml>*/ -typedef pair convert(pair);/*<asyxml></code><documentation>Function type to convert pair in an other coordinate system.</documentation></typedef></asyxml>*/ -/*<asyxml><typedef type = "abs" return = "real" params = "pair"><code></asyxml>*/ -typedef real abs(pair);/*<asyxml></code><documentation>Function type to calculate modulus of pair.</documentation></typedef></asyxml>*/ -/*<asyxml><typedef type = "dot" return = "real" params = "pair, pair"><code></asyxml>*/ -typedef real dot(pair, pair);/*<asyxml></code><documentation>Function type to calculate dot product.</documentation></typedef></asyxml>*/ -/*<asyxml><typedef type = "polar" return = "pair" params = "real, real"><code></asyxml>*/ -typedef pair polar(real, real);/*<asyxml></code><documentation>Function type to calculate the coordinates from the polar coordinates.</documentation></typedef></asyxml>*/ - -/*<asyxml><struct signature="coordsys"><code></asyxml>*/ -struct coordsys -{/*<asyxml></code><documentation>This structure represents a coordinate system in the plane.</documentation></asyxml>*/ - /*<asyxml><method type = "pair" signature="relativetodefault(pair)"><code></asyxml>*/ - restricted convert relativetodefault = new pair(pair m){return m;};/*<asyxml></code><documentation>Convert a pair given relatively to this coordinate system to - the pair relatively to the default coordinate system.</documentation></method></asyxml>*/ - /*<asyxml><method type = "pair" signature="defaulttorelativet(pair)"><code></asyxml>*/ - restricted convert defaulttorelative = new pair(pair m){return m;};/*<asyxml></code><documentation>Convert a pair given relatively to the default coordinate system to - the pair relatively to this coordinate system.</documentation></method></asyxml>*/ - /*<asyxml><method type = "real" signature="dot(pair,pair)"><code></asyxml>*/ - restricted dot dot = new real(pair m, pair n){return dot(m, n);};/*<asyxml></code><documentation>Return the dot product of this coordinate system.</documentation></method></asyxml>*/ - /*<asyxml><method type = "real" signature="abs(pair)"><code></asyxml>*/ - restricted abs abs = new real(pair m){return abs(m);};/*<asyxml></code><documentation>Return the modulus of a pair in this coordinate system.</documentation></method></asyxml>*/ - /*<asyxml><method type = "pair" signature="polar(real,real)"><code></asyxml>*/ - restricted polar polar = new pair(real r, real a){return (r * cos(a), r * sin(a));};/*<asyxml></code><documentation>Polar coordinates routine of this coordinate system.</documentation></method></asyxml>*/ - /*<asyxml><property type = "pair" signature="O,i,j"><code></asyxml>*/ - restricted pair O = (0, 0), i = (1, 0), j = (0, 1);/*<asyxml></code><documentation>Origin and units vector.</documentation></property></asyxml>*/ - /*<asyxml><method type = "void" signature="init(convert,convert,polar,dot)"><code></asyxml>*/ - void init(convert rtd, convert dtr, - polar polar, dot dot) - {/*<asyxml></code><documentation>The default constructor of the coordinate system.</documentation></method></asyxml>*/ - this.relativetodefault = rtd; - this.defaulttorelative = dtr; - this.polar = polar; - this.dot = dot; - this.abs = new real(pair m){return sqrt(dot(m, m));};; - this.O = rtd((0, 0)); - this.i = rtd((1, 0)) - O; - this.j = rtd((0, 1)) - O; - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><operator type = "bool" signature="==(coordsys,coordsys)"><code></asyxml>*/ -bool operator ==(coordsys c1, coordsys c2) -{/*<asyxml></code><documentation>Return true iff the coordinate system have the same origin and units vector.</documentation></operator></asyxml>*/ - return c1.O == c2.O && c1.i == c2.i && c1.j == c2.j; -} - -/*<asyxml><function type="coordsys" signature="cartesiansystem(pair,pair,pair)"><code></asyxml>*/ -coordsys cartesiansystem(pair O = (0, 0), pair i, pair j) -{/*<asyxml></code><documentation>Return the Cartesian coordinate system (O, i, j).</documentation></function></asyxml>*/ - coordsys R; - real[][] P = {{0, 0}, {0, 0}}; - real[][] iP; - P[0][0] = i.x; - P[0][1] = j.x; - P[1][0] = i.y; - P[1][1] = j.y; - iP = inverse(P); - real ni = abs(i); - real nj = abs(j); - real ij = angle(j) - angle(i); - - pair rtd(pair m) - { - return O + (P[0][0] * m.x + P[0][1] * m.y, P[1][0] * m.x + P[1][1] * m.y); - } - - pair dtr(pair m) - { - m-=O; - return (iP[0][0] * m.x + iP[0][1] * m.y, iP[1][0] * m.x + iP[1][1] * m.y); - } - - pair polar(real r, real a) - { - real ca = sin(ij - a)/(ni * sin(ij)); - real sa = sin(a)/(nj * sin(ij)); - return r * (ca, sa); - } - - real tdot(pair m, pair n) - { - return m.x * n.x * ni^2 + m.y * n.y * nj^2 + (m.x * n.y + n.x * m.y) * dot(i, j); - } - - R.init(rtd, dtr, polar, tdot); - return R; -} - - -/*<asyxml><function type="void" signature="show(picture,Label,Label,Label,coordsys,pen,pen,pen,pen,pen)"><code></asyxml>*/ -void show(picture pic = currentpicture, Label lo = "$O$", - Label li = "$\vec{\imath}$", - Label lj = "$\vec{\jmath}$", - coordsys R, - pen dotpen = currentpen, pen xpen = currentpen, pen ypen = xpen, - pen ipen = red, - pen jpen = ipen, - arrowbar arrow = Arrow) -{/*<asyxml></code><documentation>Draw the components (O, i, j, x - axis, y - axis) of 'R'.</documentation></function></asyxml>*/ - unravel R; - dot(pic, O, dotpen); - drawline(pic, O, O + i, xpen); - drawline(pic, O, O + j, ypen); - draw(pic, li, O--(O + i), ipen, arrow); - Label lj = lj.copy(); - lj.align(lj.align, unit(I * j)); - draw(pic, lj, O--(O + j), jpen, arrow); - draw(pic, lj, O--(O + j), jpen, arrow); - Label lo = lo.copy(); - lo.align(lo.align, -2 * dir(O--O + i, O--O + j)); - lo.p(dotpen); - label(pic, lo, O); -} - -/*<asyxml><operator type = "pair" signature="/(pair,coordsys)"><code></asyxml>*/ -pair operator /(pair p, coordsys R) -{/*<asyxml></code><documentation>Return the xy - coordinates of 'p' relatively to - the coordinate system 'R'. - For example, if R = cartesiansystem((1, 2), (1, 0), (0, 1)), (0, 0)/R is (-1, -2).</documentation></operator></asyxml>*/ - return R.defaulttorelative(p); -} - -/*<asyxml><operator type = "pair" signature="*(coordsys,pair)"><code></asyxml>*/ -pair operator *(coordsys R, pair p) -{/*<asyxml></code><documentation>Return the coordinates of 'p' given in the - xy - coordinates 'R'. - For example, if R = cartesiansystem((1, 2), (1, 0), (0, 1)), R * (0, 0) is (1, 2).</documentation></operator></asyxml>*/ - return R.relativetodefault(p); -} - -/*<asyxml><operator type = "path" signature="*(coordsys,path)"><code></asyxml>*/ -path operator *(coordsys R, path g) -{/*<asyxml></code><documentation>Return the reconstructed path applying R * pair to each node, pre and post control point of 'g'.</documentation></operator></asyxml>*/ - guide og = R * point(g, 0); - real l = length(g); - for(int i = 1; i <= l; ++i) - { - pair P = R * point(g, i); - pair post = R * postcontrol(g, i - 1); - pair pre = R * precontrol(g, i); - if(i == l && (cyclic(g))) - og = og..controls post and pre..cycle; - else - og = og..controls post and pre..P; - } - return og; -} - -/*<asyxml><operator type = "coordsys" signature="*(transform,coordsys)"><code></asyxml>*/ -coordsys operator *(transform t,coordsys R) -{/*<asyxml></code><documentation>Provide transform * coordsys. - Note that shiftless(t) is applied to R.i and R.j.</documentation></operator></asyxml>*/ - coordsys oc; - oc = cartesiansystem(t * R.O, shiftless(t) * R.i, shiftless(t) * R.j); - return oc; -} - -/*<asyxml><constant type = "coordsys" signature="defaultcoordsys"><code></asyxml>*/ -restricted coordsys defaultcoordsys = cartesiansystem(0, (1, 0), (0, 1));/*<asyxml></code><documentation>One can always refer to the default coordinate system using this constant.</documentation></constant></asyxml>*/ -/*<asyxml><variable type="coordsys" signature="currentcoordsys"><code></asyxml>*/ -coordsys currentcoordsys = defaultcoordsys;/*<asyxml></code><documentation>The coordinate system used by default.</documentation></variable></asyxml>*/ - -/*<asyxml><struct signature="point"><code></asyxml>*/ -struct point -{/*<asyxml></code><documentation>This structure replaces the pair to embed its coordinate system. - For example, if 'P = point(cartesiansystem((1, 2), i, j), (0, 0))', - P is equal to the pair (1, 2).</documentation></asyxml>*/ - /*<asyxml><property type = "coordsys" signature="coordsys"><code></asyxml>*/ - coordsys coordsys;/*<asyxml></code><documentation>The coordinate system of this point.</documentation></property><property type = "pair" signature="coordinates"><code></asyxml>*/ - restricted pair coordinates;/*<asyxml></code><documentation>The coordinates of this point relatively to the coordinate system 'coordsys'.</documentation></property><property type = "real" signature="x, y"><code></asyxml>*/ - restricted real x, y;/*<asyxml></code><documentation>The xpart and the ypart of 'coordinates'.</documentation></property></asyxml>*/ - /*<asyxml><method type = "" signature="init(coordsys,pair)"><code><property type = "real" signature="m"><code></asyxml>*/ - real m = 1;/*<asyxml></code><documentation>Used to cast mass<->point.</documentation></property></asyxml>*/ - void init(coordsys R, pair coordinates, real mass) - {/*<asyxml></code><documentation>The constructor.</documentation></method></asyxml>*/ - this.coordsys = R; - this.coordinates = coordinates; - this.x = coordinates.x; - this.y = coordinates.y; - this.m = mass; - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="point" signature="point(coordsys,pair,real)"><code></asyxml>*/ -point point(coordsys R, pair p, real m = 1) -{/*<asyxml></code><documentation>Return the point which has the coodinates 'p' in the - coordinate system 'R' and the mass 'm'.</documentation></function></asyxml>*/ - point op; - op.init(R, p, m); - return op; -} - -/*<asyxml><function type="point" signature="point(explicit pair,real)"><code></asyxml>*/ -point point(explicit pair p, real m) -{/*<asyxml></code><documentation>Return the point which has the coodinates 'p' in the current - coordinate system and the mass 'm'.</documentation></function></asyxml>*/ - point op; - op.init(currentcoordsys, p, m); - return op; -} - -/*<asyxml><function type="point" signature="point(coordsys,explicit point,real)"><code></asyxml>*/ -point point(coordsys R, explicit point M, real m = M.m) -{/*<asyxml></code><documentation>Return the point of 'R' which has the coordinates of 'M' and the mass 'm'. - Do not confuse this routine with the further routine 'changecoordsys'.</documentation></function></asyxml>*/ - point op; - op.init(R, M.coordinates, M.m); - return op; -} - -/*<asyxml><function type="point" signature="changecoordsys(coordsys,point)"><code></asyxml>*/ -point changecoordsys(coordsys R, point M) -{/*<asyxml></code><documentation>Return the point 'M' in the coordinate system 'coordsys'. - In other words, the returned point marks the same plot as 'M' does.</documentation></function></asyxml>*/ - point op; - coordsys mco = M.coordsys; - op.init(R, R.defaulttorelative(mco.relativetodefault(M.coordinates)), M.m); - return op; -} - -/*<asyxml><function type="pair" signature="pair coordinates(point)"><code></asyxml>*/ -pair coordinates(point M) -{/*<asyxml></code><documentation>Return the coordinates of 'M' in its coordinate system.</documentation></function></asyxml>*/ - return M.coordinates; -} - -/*<asyxml><function type="bool" signature="bool samecoordsys(bool...point[])"><code></asyxml>*/ -bool samecoordsys(bool warn = true ... point[] M) -{/*<asyxml></code><documentation>Return true iff all the points have the same coordinate system. - If 'warn' is true and the coordinate systems are different, a warning is sent.</documentation></function></asyxml>*/ - bool ret = true; - coordsys t = M[0].coordsys; - for (int i = 1; i < M.length; ++i) { - ret = (t == M[i].coordsys); - if(!ret) break; - t = M[i].coordsys; - } - if(warn && !ret) - warning("coodinatesystem", - "the coordinate system of two objects are not the same. -The operation will be done relative to the default coordinate system."); - return ret; -} - -/*<asyxml><function type="point[]" signature="standardizecoordsys(coordsys,bool...point[])"><code></asyxml>*/ -point[] standardizecoordsys(coordsys R = currentcoordsys, - bool warn = true ... point[] M) -{/*<asyxml></code><documentation>Return the points with the same coordinate system 'R'. - If 'warn' is true and the coordinate systems are different, a warning is sent.</documentation></function></asyxml>*/ - point[] op = new point[]; - op = M; - if(!samecoordsys(warn ... M)) - for (int i = 1; i < M.length; ++i) - op[i] = changecoordsys(R, M[i]); - return op; -} - -/*<asyxml><operator type = "pair" signature="cast(point)"><code></asyxml>*/ -pair operator cast(point P) -{/*<asyxml></code><documentation>Cast point to pair.</documentation></operator></asyxml>*/ - return P.coordsys.relativetodefault(P.coordinates); -} - -/*<asyxml><operator type = "pair[]" signature="cast(point[])"><code></asyxml>*/ -pair[] operator cast(point[] P) -{/*<asyxml></code><documentation>Cast point[] to pair[].</documentation></operator></asyxml>*/ - pair[] op; - for (int i = 0; i < P.length; ++i) { - op.push((pair)P[i]); - } - return op; -} - -/*<asyxml><operator type = "point" signature="cast(pair)"><code></asyxml>*/ -point operator cast(pair p) -{/*<asyxml></code><documentation>Cast pair to point relatively to the current coordinate - system 'currentcoordsys'.</documentation></operator></asyxml>*/ - return point(currentcoordsys, p); -} - -/*<asyxml><operator type = "point[]" signature="cast(pair[])"><code></asyxml>*/ -point[] operator cast(pair[] p) -{/*<asyxml></code><documentation>Cast pair[] to point[] relatively to the current coordinate - system 'currentcoordsys'.</documentation></operator></asyxml>*/ - pair[] op; - for (int i = 0; i < p.length; ++i) { - op.push((point)p[i]); - } - return op; -} - -/*<asyxml><function type="pair" signature="locate(point)"><code></asyxml>*/ -pair locate(point P) -{/*<asyxml></code><documentation>Return the coordinates of 'P' in the default coordinate system.</documentation></function></asyxml>*/ - return P.coordsys * P.coordinates; -} - -/*<asyxml><function type="point" signature="locate(pair)"><code></asyxml>*/ -point locate(pair p) -{/*<asyxml></code><documentation>Return the point in the current coordinate system 'currentcoordsys'.</documentation></function></asyxml>*/ - return p; //automatic casting 'pair to point'. -} - -/*<asyxml><operator type = "point" signature="*(real,explicit point)"><code></asyxml>*/ -point operator *(real x, explicit point P) -{/*<asyxml></code><documentation>Multiply the coordinates (not the mass) of 'P' by 'x'.</documentation></operator></asyxml>*/ - return point(P.coordsys, x * P.coordinates, P.m); -} - -/*<asyxml><operator type = "point" signature="/(explicit point,real)"><code></asyxml>*/ -point operator /(explicit point P, real x) -{/*<asyxml></code><documentation>Divide the coordinates (not the mass) of 'P' by 'x'.</documentation></operator></asyxml>*/ - return point(P.coordsys, P.coordinates/x, P.m); -} - -/*<asyxml><operator type = "point" signature="/(real,explicit point)"><code></asyxml>*/ -point operator /(real x, explicit point P) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - return point(P.coordsys, x/P.coordinates, P.m); -} - -/*<asyxml><operator type = "point" signature="-(explicit point)"><code></asyxml>*/ -point operator -(explicit point P) -{/*<asyxml></code><documentation>-P. The mass is inchanged.</documentation></operator></asyxml>*/ - return point(P.coordsys, -P.coordinates, P.m); -} - -/*<asyxml><operator type = "point" signature="+(explicit point,explicit point)"><code></asyxml>*/ -point operator +(explicit point P1, explicit point P2) -{/*<asyxml></code><documentation>Provide 'point + point'. - If the two points haven't the same coordinate system, a warning is sent and the - returned point has the default coordinate system 'defaultcoordsys'. - The masses are added.</documentation></operator></asyxml>*/ - point[] P = standardizecoordsys(P1, P2); - coordsys R = P[0].coordsys; - return point(R, P[0].coordinates + P[1].coordinates, P1.m + P2.m); -} - -/*<asyxml><operator type = "point" signature="+(explicit point,explicit pair)"><code></asyxml>*/ -point operator +(explicit point P1, explicit pair p2) -{/*<asyxml></code><documentation>Provide 'point + pair'. - The pair 'p2' is supposed to be coordinates relatively to the coordinates system of 'P1'. - The mass is not changed.</documentation></operator></asyxml>*/ - coordsys R = currentcoordsys; - return point(R, P1.coordinates + point(R, p2).coordinates, P1.m); -} -point operator +(explicit pair p1, explicit point p2) -{ - return p2 + p1; -} - -/*<asyxml><operator type = "point" signature="-(explicit point,explicit point)"><code></asyxml>*/ -point operator -(explicit point P1, explicit point P2) -{/*<asyxml></code><documentation>Provide 'point - point'.</documentation></operator></asyxml>*/ - return P1 + (-P2); -} - -/*<asyxml><operator type = "point" signature="-(explicit point,explicit pair)"><code></asyxml>*/ -point operator -(explicit point P1, explicit pair p2) -{/*<asyxml></code><documentation>Provide 'point - pair'. - The pair 'p2' is supposed to be coordinates relatively to the coordinates system of 'P1'.</documentation></operator></asyxml>*/ - return P1 + (-p2); -} -point operator -(explicit pair p1, explicit point P2) -{ - return p1 + (-P2); -} - -/*<asyxml><operator type = "point" signature="*(transform,explicit point)"><code></asyxml>*/ -point operator *(transform t, explicit point P) -{/*<asyxml></code><documentation>Provide 'transform * point'. - Note that the transforms scale, xscale, yscale and rotate are carried out relatively - the default coordinate system 'defaultcoordsys' which is not desired for point - defined in an other coordinate system. - On can use scale(real, point), xscale(real, point), yscale(real, point), rotate(real, point), - scaleO(real), xscaleO(real), yscaleO(real) and rotateO(real) (described further) - to change the coordinate system of reference.</documentation></operator></asyxml>*/ - coordsys R = P.coordsys; - return point(R, (t * locate(P))/R, P.m); -} - -/*<asyxml><operator type = "point" signature="*(explicit point,explicit point)"><code></asyxml>*/ -point operator *(explicit point P1, explicit point P2) -{/*<asyxml></code><documentation>Provide 'point * point'. - The resulted mass is the mass of P2</documentation></operator></asyxml>*/ - point[] P = standardizecoordsys(P1, P2); - coordsys R = P[0].coordsys; - return point(R, P[0].coordinates * P[1].coordinates, P2.m); -} - -/*<asyxml><operator type = "point" signature="*(explicit point,explicit pair)"><code></asyxml>*/ -point operator *(explicit point P1, explicit pair p2) -{/*<asyxml></code><documentation>Provide 'point * pair'. - The pair 'p2' is supposed to be the coordinates of - the point in the coordinates system of 'P1'. - 'pair * point' is also defined.</documentation></operator></asyxml>*/ - point P = point(P1.coordsys, p2, P1.m); - return P1 * P; -} -point operator *(explicit pair p1, explicit point p2) -{ - return p2 * p1; -} - -/*<asyxml><operator type = "bool" signature="==(explicit point,explicit point)"><code></asyxml>*/ -bool operator ==(explicit point M, explicit point N) -{/*<asyxml></code><documentation>Provide the test 'M == N' wish returns true iff MN < EPS</documentation></operator></asyxml>*/ - return abs(locate(M) - locate(N)) < EPS; -} - -/*<asyxml><operator type = "bool" signature="!=(explicit point,explicit point)"><code></asyxml>*/ -bool operator !=(explicit point M, explicit point N) -{/*<asyxml></code><documentation>Provide the test 'M != N' wish return true iff MN >= EPS</documentation></operator></asyxml>*/ - return !(M == N); -} - -/*<asyxml><operator type = "guide" signature="cast(point)"><code></asyxml>*/ -guide operator cast(point p) -{/*<asyxml></code><documentation>Cast point to guide.</documentation></operator></asyxml>*/ - return locate(p); -} - -/*<asyxml><operator type = "path" signature="cast(point)"><code></asyxml>*/ -path operator cast(point p) -{/*<asyxml></code><documentation>Cast point to path.</documentation></operator></asyxml>*/ - return locate(p); -} - -/*<asyxml><function type="void" signature="dot(picture,Label,explicit point,align,string,pen)"><code></asyxml>*/ -void dot(picture pic = currentpicture, Label L, explicit point Z, - align align = NoAlign, - string format = defaultformat, pen p = currentpen) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - Label L = L.copy(); - L.position(locate(Z)); - if(L.s == "") { - if(format == "") format = defaultformat; - L.s = "("+format(format, Z.x)+", "+format(format, Z.y)+")"; - } - L.align(align, E); - L.p(p); - dot(pic, locate(Z), p); - add(pic, L); -} - -/*<asyxml><function type="real" signature="abs(coordsys,pair)"><code></asyxml>*/ -real abs(coordsys R, pair m) -{/*<asyxml></code><documentation>Return the modulus |m| in the coordinate system 'R'.</documentation></function></asyxml>*/ - return R.abs(m); -} - -/*<asyxml><function type="real" signature="abs(explicit point)"><code></asyxml>*/ -real abs(explicit point M) -{/*<asyxml></code><documentation>Return the modulus |M| in its coordinate system.</documentation></function></asyxml>*/ - return M.coordsys.abs(M.coordinates); -} - -/*<asyxml><function type="real" signature="length(explicit point)"><code></asyxml>*/ -real length(explicit point M) -{/*<asyxml></code><documentation>Return the modulus |M| in its coordinate system (same as 'abs').</documentation></function></asyxml>*/ - return M.coordsys.abs(M.coordinates); -} - -/*<asyxml><function type="point" signature="conj(explicit point)"><code></asyxml>*/ -point conj(explicit point M) -{/*<asyxml></code><documentation>Conjugate.</documentation></function></asyxml>*/ - return point(M.coordsys, conj(M.coordinates), M.m); -} - -/*<asyxml><function type="real" signature="degrees(explicit point,coordsys,bool)"><code></asyxml>*/ -real degrees(explicit point M, coordsys R = M.coordsys, bool warn = true) -{/*<asyxml></code><documentation>Return the angle of M (in degrees) relatively to 'R'.</documentation></function></asyxml>*/ - return (degrees(locate(M) - R.O, warn) - degrees(R.i))%360; -} - -/*<asyxml><function type="real" signature="angle(explicit point,coordsys,bool)"><code></asyxml>*/ -real angle(explicit point M, coordsys R = M.coordsys, bool warn = true) -{/*<asyxml></code><documentation>Return the angle of M (in radians) relatively to 'R'.</documentation></function></asyxml>*/ - return radians(degrees(M, R, warn)); -} - -/*<asyxml><function type="bool" signature="finite(explicit point)"><code></asyxml>*/ -bool finite(explicit point p) -{/*<asyxml></code><documentation>Avoid to compute 'finite((pair)(infinite_point))'.</documentation></function></asyxml>*/ - return finite(p.coordinates); -} - -/*<asyxml><function type="real" signature="dot(point,point)"><code></asyxml>*/ -real dot(point A, point B) -{/*<asyxml></code><documentation>Return the dot product in the coordinate system of 'A'.</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A.coordsys, A, B); - return P[0].coordsys.dot(P[0].coordinates, P[1].coordinates); -} - -/*<asyxml><function type="real" signature="dot(point,explicit pair)"><code></asyxml>*/ -real dot(point A, explicit pair B) -{/*<asyxml></code><documentation>Return the dot product in the default coordinate system. - dot(explicit pair, point) is also defined.</documentation></function></asyxml>*/ - return dot(locate(A), B); -} -real dot(explicit pair A, point B) -{ - return dot(A, locate(B)); -} - -/*<asyxml><function type="transforms" signature="rotateO(real)"><code></asyxml>*/ -transform rotateO(real a) -{/*<asyxml></code><documentation>Rotation around the origin of the current coordinate system.</documentation></function></asyxml>*/ - return rotate(a, currentcoordsys.O); -}; - -/*<asyxml><function type="transform" signature="projection(point,point)"><code></asyxml>*/ -transform projection(point A, point B) -{/*<asyxml></code><documentation>Return the orthogonal projection on the line (AB).</documentation></function></asyxml>*/ - pair dir = unit(locate(A) - locate(B)); - pair a = locate(A); - real cof = dir.x * a.x + dir.y * a.y; - real tx = a.x - dir.x * cof; - real txx = dir.x^2; - real txy = dir.x * dir.y; - real ty = a.y - dir.y * cof; - real tyx = txy; - real tyy = dir.y^2; - transform t = (tx, ty, txx, txy, tyx, tyy); - return t; -} - -/*<asyxml><function type="transform" signature="projection(point,point,point,point,bool)"><code></asyxml>*/ -transform projection(point A, point B, point C, point D, bool safe = false) -{/*<asyxml></code><documentation>Return the (CD) parallel projection on (AB). - If 'safe = true' and (AB)//(CD) return the identity. - If 'safe = false' and (AB)//(CD) return an infinity scaling.</documentation></function></asyxml>*/ - pair a = locate(A); - pair u = unit(locate(B) - locate(A)); - pair v = unit(locate(D) - locate(C)); - real c = u.x * a.y - u.y * a.x; - real d = (conj(u) * v).y; - if (abs(d) < epsgeo) { - return safe ? identity() : scale(infinity); - } - real tx = c * v.x/d; - real ty = c * v.y/d; - real txx = u.x * v.y/d; - real txy = -u.x * v.x/d; - real tyx = u.y * v.y/d; - real tyy = -u.y * v.x/d; - transform t = (tx, ty, txx, txy, tyx, tyy); - return t; -} - -/*<asyxml><function type="transform" signature="scale(real,point)"><code></asyxml>*/ -transform scale(real k, point M) -{/*<asyxml></code><documentation>Homothety.</documentation></function></asyxml>*/ - pair P = locate(M); - return shift(P) * scale(k) * shift(-P); -} - -/*<asyxml><function type="transform" signature="xscale(real,point)"><code></asyxml>*/ -transform xscale(real k, point M) -{/*<asyxml></code><documentation>xscale from 'M' relatively to the x - axis of the coordinate system of 'M'.</documentation></function></asyxml>*/ - pair P = locate(M); - real a = degrees(M.coordsys.i); - return (shift(P) * rotate(a)) * xscale(k) * (rotate(-a) * shift(-P)); -} - -/*<asyxml><function type="transform" signature="yscale(real,point)"><code></asyxml>*/ -transform yscale(real k, point M) -{/*<asyxml></code><documentation>yscale from 'M' relatively to the y - axis of the coordinate system of 'M'.</documentation></function></asyxml>*/ - pair P = locate(M); - real a = degrees(M.coordsys.j) - 90; - return (shift(P) * rotate(a)) * yscale(k) * (rotate(-a) * shift(-P)); -} - -/*<asyxml><function type="transform" signature="scale(real,point,point,point,point,bool)"><code></asyxml>*/ -transform scale(real k, point A, point B, point C, point D, bool safe = false) -{/*<asyxml></code><documentation><url href = "http://fr.wikipedia.org/wiki/Affinit%C3%A9_%28math%C3%A9matiques%29"/> - (help me for English translation...) - If 'safe = true' and (AB)//(CD) return the identity. - If 'safe = false' and (AB)//(CD) return a infinity scaling.</documentation></function></asyxml>*/ - pair a = locate(A); - pair u = unit(locate(B) - locate(A)); - pair v = unit(locate(D) - locate(C)); - real c = u.x * a.y - u.y * a.x; - real d = (conj(u) * v).y; - real d = (conj(u) * v).y; - if (abs(d) < epsgeo) { - return safe ? identity() : scale(infinity); - } - real tx = (1 - k) * c * v.x/d; - real ty = (1 - k) * c * v.y/d; - real txx = (1 - k) * u.x * v.y/d + k; - real txy = (k - 1) * u.x * v.x/d; - real tyx = (1 - k) * u.y * v.y/d; - real tyy = (k - 1) * u.y * v.x/d + k; - transform t = (tx, ty, txx, txy, tyx, tyy); - return t; -} - -/*<asyxml><function type="transform" signature="scaleO(real)"><code></asyxml>*/ -transform scaleO(real x) -{/*<asyxml></code><documentation>Homothety from the origin of the current coordinate system.</documentation></function></asyxml>*/ - return scale(x, (0, 0)); -} - -/*<asyxml><function type="transform" signature="xscaleO(real)"><code></asyxml>*/ -transform xscaleO(real x) -{/*<asyxml></code><documentation>xscale from the origin and relatively to the current coordinate system.</documentation></function></asyxml>*/ - return scale(x, (0, 0), (0, 1), (0, 0), (1, 0)); -} - -/*<asyxml><function type="transform" signature="yscaleO(real)"><code></asyxml>*/ -transform yscaleO(real x) -{/*<asyxml></code><documentation>yscale from the origin and relatively to the current coordinate system.</documentation></function></asyxml>*/ - return scale(x, (0, 0), (1, 0), (0, 0), (0, 1)); -} - -/*<asyxml><struct signature="vector"><code></asyxml>*/ -struct vector -{/*<asyxml></code><documentation>Like a point but casting to pair, adding etc does not take account - of the origin of the coordinate system.</documentation><property type = "point" signature="v"><code></asyxml>*/ - point v;/*<asyxml></code><documentation>Coordinates as a point (embed coordinate system and pair).</documentation></property></asyxml>*/ -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><operator type = "point" signature="cast(vector)"><code></asyxml>*/ -point operator cast(vector v) -{/*<asyxml></code><documentation>Cast vector 'v' to point 'M' so that OM = v.</documentation></operator></asyxml>*/ - return v.v; -} - -/*<asyxml><operator type = "vector" signature="cast(pair)"><code></asyxml>*/ -vector operator cast(pair v) -{/*<asyxml></code><documentation>Cast pair to vector relatively to the current coordinate - system 'currentcoordsys'.</documentation></operator></asyxml>*/ - vector ov; - ov.v = point(currentcoordsys, v); - return ov; -} - -/*<asyxml><operator type = "vector" signature="cast(explicit point)"><code></asyxml>*/ -vector operator cast(explicit point v) -{/*<asyxml></code><documentation>A point can be interpreted like a vector using the code - '(vector)a_point'.</documentation></operator></asyxml>*/ - vector ov; - ov.v = v; - return ov; -} - -/*<asyxml><operator type = "pair" signature="cast(explicit vector)"><code></asyxml>*/ -pair operator cast(explicit vector v) -{/*<asyxml></code><documentation>Cast vector to pair (the coordinates of 'v' in the default coordinate system).</documentation></operator></asyxml>*/ - return locate(v.v) - v.v.coordsys.O; -} - -/*<asyxml><operator type = "align" signature="cast(vector)"><code></asyxml>*/ -align operator cast(vector v) -{/*<asyxml></code><documentation>Cast vector to align.</documentation></operator></asyxml>*/ - return (pair)v; -} - -/*<asyxml><function type="vector" signature="vector(coordsys, pair)"><code></asyxml>*/ -vector vector(coordsys R = currentcoordsys, pair v) -{/*<asyxml></code><documentation>Return the vector of 'R' which has the coordinates 'v'.</documentation></function></asyxml>*/ - vector ov; - ov.v = point(R, v); - return ov; -} - -/*<asyxml><function type="vector" signature="vector(point)"><code></asyxml>*/ -vector vector(point M) -{/*<asyxml></code><documentation>Return the vector OM, where O is the origin of the coordinate system of 'M'. - Useful to write 'vector(P - M);' instead of '(vector)(P - M)'.</documentation></function></asyxml>*/ - return M; -} - -/*<asyxml><function type="point" signature="point(explicit vector)"><code></asyxml>*/ -point point(explicit vector u) -{/*<asyxml></code><documentation>Return the point M so that OM = u, where O is the origin of the coordinate system of 'u'.</documentation></function></asyxml>*/ - return u.v; -} - -/*<asyxml><function type="pair" signature="locate(explicit vector)"><code></asyxml>*/ -pair locate(explicit vector v) -{/*<asyxml></code><documentation>Return the coordinates of 'v' in the default coordinate system (like casting vector to pair).</documentation></function></asyxml>*/ - return (pair)v; -} - -/*<asyxml><function type="void" signature="show(Label,pen,arrowbar)"><code></asyxml>*/ -void show(Label L, vector v, pen p = currentpen, arrowbar arrow = Arrow) -{/*<asyxml></code><documentation>Draw the vector v (from the origin of its coordinate system).</documentation></function></asyxml>*/ - coordsys R = v.v.coordsys; - draw(L, R.O--v.v, p, arrow); -} - -/*<asyxml><function type="vector" signature="changecoordsys(coordsys,vector)"><code></asyxml>*/ -vector changecoordsys(coordsys R, vector v) -{/*<asyxml></code><documentation>Return the vector 'v' relatively to coordinate system 'R'.</documentation></function></asyxml>*/ - vector ov; - ov.v = point(R, (locate(v) + R.O)/R); - return ov; -} - -/*<asyxml><operator type = "vector" signature="*(real,explicit vector)"><code></asyxml>*/ -vector operator *(real x, explicit vector v) -{/*<asyxml></code><documentation>Provide real * vector.</documentation></operator></asyxml>*/ - return x * v.v; -} - -/*<asyxml><operator type = "vector" signature="/(explicit vector,real)"><code></asyxml>*/ -vector operator /(explicit vector v, real x) -{/*<asyxml></code><documentation>Provide vector/real</documentation></operator></asyxml>*/ - return v.v/x; -} - -/*<asyxml><operator type = "vector" signature="*(transform t,explicit vector)"><code></asyxml>*/ -vector operator *(transform t, explicit vector v) -{/*<asyxml></code><documentation>Provide transform * vector.</documentation></operator></asyxml>*/ - return t * v.v; -} - -/*<asyxml><operator type = "vector" signature="*(explicit point,explicit vector)"><code></asyxml>*/ -vector operator *(explicit point M, explicit vector v) -{/*<asyxml></code><documentation>Provide point * vector</documentation></operator></asyxml>*/ - return M * v.v; -} - -/*<asyxml><operator type = "point" signature="+(explicit point,explicit vector)"><code></asyxml>*/ -point operator +(point M, explicit vector v) -{/*<asyxml></code><documentation>Return 'M' shifted by 'v'.</documentation></operator></asyxml>*/ - return shift(locate(v)) * M; -} - -/*<asyxml><operator type = "point" signature="-(explicit point,explicit vector)"><code></asyxml>*/ -point operator -(point M, explicit vector v) -{/*<asyxml></code><documentation>Return 'M' shifted by '-v'.</documentation></operator></asyxml>*/ - return shift(-locate(v)) * M; -} - -/*<asyxml><operator type = "vector" signature="-(explicit vector)"><code></asyxml>*/ -vector operator -(explicit vector v) -{/*<asyxml></code><documentation>Provide -v.</documentation></operator></asyxml>*/ - return -v.v; -} - -/*<asyxml><operator type = "point" signature="+(explicit pair,explicit vector)"><code></asyxml>*/ -point operator +(explicit pair m, explicit vector v) -{/*<asyxml></code><documentation>The pair 'm' is supposed to be the coordinates of - a point in the current coordinates system 'currentcoordsys'. - Return this point shifted by the vector 'v'.</documentation></operator></asyxml>*/ - return locate(m) + v; -} - -/*<asyxml><operator type = "point" signature="-(explicit pair,explicit vector)"><code></asyxml>*/ -point operator -(explicit pair m, explicit vector v) -{/*<asyxml></code><documentation>The pair 'm' is supposed to be the coordinates of - a point in the current coordinates system 'currentcoordsys'. - Return this point shifted by the vector '-v'.</documentation></operator></asyxml>*/ - return m + (-v); -} - -/*<asyxml><operator type = "vector" signature="+(explicit vector,explicit vector)"><code></asyxml>*/ -vector operator +(explicit vector v1, explicit vector v2) -{/*<asyxml></code><documentation>Provide vector + vector. - If the two vector haven't the same coordinate system, the returned - vector is relative to the default coordinate system (without warning).</documentation></operator></asyxml>*/ - coordsys R = v1.v.coordsys; - if(samecoordsys(false, v1, v2)){R = defaultcoordsys;} - return vector(R, (locate(v1) + locate(v2))/R); -} - -/*<asyxml><operator type = "vector" signature="-(explicit vector, explicit vector)"><code></asyxml>*/ -vector operator -(explicit vector v1, explicit vector v2) -{/*<asyxml></code><documentation>Provide vector - vector. - If the two vector haven't the same coordinate system, the returned - vector is relative to the default coordinate system (without warning).</documentation></operator></asyxml>*/ - return v1 + (-v2); -} - -/*<asyxml><operator type = "bool" signature="==(explicit vector,explicit vector)"><code></asyxml>*/ -bool operator ==(explicit vector u, explicit vector v) -{/*<asyxml></code><documentation>Return true iff |u - v|<EPS.</documentation></operator></asyxml>*/ - return abs(u - v) < EPS; -} - -/*<asyxml><function type="bool" signature="collinear(vector,vector)"><code></asyxml>*/ -bool collinear(vector u, vector v) -{/*<asyxml></code><documentation>Return 'true' iff the vectors 'u' and 'v' are collinear.</documentation></function></asyxml>*/ - return abs(ypart((conj((pair)u) * (pair)v))) < EPS; -} - -/*<asyxml><function type="vector" signature="unit(point)"><code></asyxml>*/ -vector unit(point M) -{/*<asyxml></code><documentation>Return the unit vector according to the modulus of its coordinate system.</documentation></function></asyxml>*/ - return M/abs(M); -} - -/*<asyxml><function type="vector" signature="unit(vector)"><code></asyxml>*/ -vector unit(vector u) -{/*<asyxml></code><documentation>Return the unit vector according to the modulus of its coordinate system.</documentation></function></asyxml>*/ - return u.v/abs(u.v); -} - -/*<asyxml><function type="real" signature="degrees(vector,coordsys,bool)"><code></asyxml>*/ -real degrees(vector v, - coordsys R = v.v.coordsys, - bool warn = true) -{/*<asyxml></code><documentation>Return the angle of 'v' (in degrees) relatively to 'R'.</documentation></function></asyxml>*/ - return (degrees(locate(v), warn) - degrees(R.i))%360; -} - -/*<asyxml><function type="real" signature="angle(vector,coordsys,bool)"><code></asyxml>*/ -real angle(explicit vector v, - coordsys R = v.v.coordsys, - bool warn = true) -{/*<asyxml></code><documentation>Return the angle of 'v' (in radians) relatively to 'R'.</documentation></function></asyxml>*/ - return radians(degrees(v, R, warn)); -} - -/*<asyxml><function type="vector" signature="conj(explicit vector)"><code></asyxml>*/ -vector conj(explicit vector u) -{/*<asyxml></code><documentation>Conjugate.</documentation></function></asyxml>*/ - return conj(u.v); -} - -/*<asyxml><function type="transform" signature="rotate(explicit vector)"><code></asyxml>*/ -transform rotate(explicit vector dir) -{/*<asyxml></code><documentation>A rotation in the direction 'dir' limited to [-90, 90] - This is useful for rotating text along a line in the direction dir. - rotate(explicit point dir) is also defined. - </documentation></function></asyxml>*/ - return rotate(locate(dir)); -} -transform rotate(explicit point dir){return rotate(locate(vector(dir)));} -// *......................COORDINATES......................* -// *=======================================================* - -// *=======================================================* -// *.........................BASES.........................* -/*<asyxml><variable type="point" signature="origin"><code></asyxml>*/ -point origin = point(defaultcoordsys, (0, 0));/*<asyxml></code><documentation>The origin of the current coordinate system.</documentation></variable></asyxml>*/ - -/*<asyxml><function type="point" signature="origin(coordsys)"><code></asyxml>*/ -point origin(coordsys R = currentcoordsys) -{/*<asyxml></code><documentation>Return the origin of the coordinate system 'R'.</documentation></function></asyxml>*/ - return point(R, (0, 0)); //use automatic casting; -} - -/*<asyxml><variable type="real" signature="linemargin"><code></asyxml>*/ -real linemargin = 0;/*<asyxml></code><documentation>Margin used to draw lines.</documentation></variable></asyxml>*/ -/*<asyxml><function type="real" signature="linemargin()"><code></asyxml>*/ -real linemargin() -{/*<asyxml></code><documentation>Return the margin used to draw lines.</documentation></function></asyxml>*/ - return linemargin; -} - -/*<asyxml><variable type="pen" signature="addpenline"><code></asyxml>*/ -pen addpenline = squarecap;/*<asyxml></code><documentation>Add this property to the drawing pen of "finish" lines.</documentation></variable></asyxml>*/ -pen addpenline(pen p) { - return addpenline + p; -} - -/*<asyxml><variable type="pen" signature="addpenarc"><code></asyxml>*/ -pen addpenarc = squarecap;/*<asyxml></code><documentation>Add this property to the drawing pen of arcs.</documentation></variable></asyxml>*/ -pen addpenarc(pen p) {return addpenarc + p;} - -/*<asyxml><variable type="string" signature="defaultmassformat"><code></asyxml>*/ -string defaultmassformat = "$\left(%L;%.4g\right)$";/*<asyxml></code><documentation>Format used to construct the default label of masses.</documentation></variable></asyxml>*/ - -/*<asyxml><function type="int" signature="sgnd(real)"><code></asyxml>*/ -int sgnd(real x) -{/*<asyxml></code><documentation>Return the -1 if x < 0, 1 if x >= 0.</documentation></function></asyxml>*/ - return (x == 0) ? 1 : sgn(x); -} -int sgnd(int x) -{ - return (x == 0) ? 1 : sgn(x); -} - -/*<asyxml><function type="bool" signature="defined(pair)"><code></asyxml>*/ -bool defined(point P) -{/*<asyxml></code><documentation>Return true iff the coordinates of 'P' are finite.</documentation></function></asyxml>*/ - return finite(P.coordinates); -} - -/*<asyxml><function type="bool" signature="onpath(picture,path,point,pen)"><code></asyxml>*/ -bool onpath(picture pic = currentpicture, path g, point M, pen p = currentpen) -{/*<asyxml></code><documentation>Return true iff 'M' is on the path drawn with the pen 'p' in 'pic'.</documentation></function></asyxml>*/ - transform t = inverse(pic.calculateTransform()); - return intersect(g, shift(locate(M)) * scale(linewidth(p)/2) * t * unitcircle).length > 0; -} - -/*<asyxml><function type="bool" signature="sameside(point,point,point)"><code></asyxml>*/ -bool sameside(point M, point N, point O) -{/*<asyxml></code><documentation>Return 'true' iff 'M' and 'N' are same side of the point 'O'.</documentation></function></asyxml>*/ - pair m = M, n = N, o = O; - return dot(m - o, n - o) >= -epsgeo; -} - -/*<asyxml><function type="bool" signature="between(point,point,point)"><code></asyxml>*/ -bool between(point M, point O, point N) -{/*<asyxml></code><documentation>Return 'true' iff 'O' is between 'M' and 'N'.</documentation></function></asyxml>*/ - return (!sameside(N, M, O) || M == O || N == O); -} - - -typedef path pathModifier(path); -pathModifier NoModifier = new path(path g){return g;}; - -private void Drawline(picture pic = currentpicture, Label L = "", pair P, bool dirP = true, pair Q, bool dirQ = true, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, - Label legend = "", marker marker = nomarker, - pathModifier pathModifier = NoModifier) -{/* Add the two parameters 'dirP' and 'dirQ' to the native routine - 'drawline' of the module 'math'. - Segment [PQ] will be prolonged in direction of P if 'dirP = true', in - direction of Q if 'dirQ = true'. - If 'dirP = dirQ = true', the behavior is that of the native 'drawline'. - Add all the other parameters of 'Draw'.*/ - pic.add(new void (frame f, transform t, transform T, pair m, pair M) { - picture opic; - // Reduce the bounds by the size of the pen. - m -= min(p) - (linemargin(), linemargin()); M -= max(p) + (linemargin(), linemargin()); - - // Calculate the points and direction vector in the transformed space. - t = t * T; - pair z = t * P; - pair q = t * Q; - pair v = q - z; - // path g; - pair ptp, ptq; - real cp = dirP ? 1:0; - real cq = dirQ ? 1:0; - // Handle horizontal and vertical lines. - if(v.x == 0) { - if(m.x <= z.x && z.x <= M.x) - if (dot(v, m - z) < 0) { - ptp = (z.x, z.y + cp * (m.y - z.y)); - ptq = (z.x, q.y + cq * (M.y - q.y)); - } else { - ptq = (z.x, q.y + cq * (m.y - q.y)); - ptp = (z.x, z.y + cp * (M.y - z.y)); - } - } else if(v.y == 0) { - if (dot(v, m - z) < 0) { - ptp = (z.x + cp * (m.x - z.x), z.y); - ptq = (q.x + cq * (M.x - q.x), z.y); - } else { - ptq = (q.x + cq * (m.x - q.x), z.y); - ptp = (z.x + cp * (M.x - z.x), z.y); - } - } else { - // Calculate the maximum and minimum t values allowed for the - // parametric equation z + t * v - real mx = (m.x - z.x)/v.x, Mx = (M.x - z.x)/v.x; - real my = (m.y - z.y)/v.y, My = (M.y - z.y)/v.y; - real tmin = max(v.x > 0 ? mx : Mx, v.y > 0 ? my : My); - real tmax = min(v.x > 0 ? Mx : mx, v.y > 0 ? My : my); - pair pmin = z + tmin * v; - pair pmax = z + tmax * v; - if(tmin <= tmax) { - ptp = z + cp * tmin * v; - ptq = z + (cq == 0 ? v:tmax * v); - } - } - path g = ptp--ptq; - if (length(g)>0) - { - if(L.s != "") { - Label lL = L.copy(); - if(L.defaultposition) lL.position(Relative(.9)); - lL.p(p); - lL.out(opic, g); - } - g = pathModifier(g); - if(linetype(p).length == 0){ - pair m = midpoint(g); - pen tp; - tp = dirP ? p : addpenline(p); - draw(opic, pathModifier(m--ptp), tp); - tp = dirQ ? p : addpenline(p); - draw(opic, pathModifier(m--ptq), tp); - } else { - draw(opic, g, p); - } - marker.markroutine(opic, marker.f, g); - arrow(opic, g, p, NoMargin); - add(f, opic.fit()); - } - }); -} - -/*<asyxml><function type="void" signature="clipdraw(picture,Label,path,align,pen,arrowbar,arrowbar,real,real,Label,marker)"><code></asyxml>*/ -void clipdraw(picture pic = currentpicture, Label L = "", path g, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, arrowbar bar = None, - real xmargin = 0, real ymargin = xmargin, - Label legend = "", marker marker = nomarker) -{/*<asyxml></code><documentation>Draw the path 'g' on 'pic' clipped to the bounding box of 'pic'.</documentation></function></asyxml>*/ - if(L.s != "") { - picture tmp; - label(tmp, L, g, p); - add(pic, tmp); - } - pic.add(new void (frame f, transform t, transform T, pair m, pair M) { - // Reduce the bounds by the size of the pen and the margins. - m += min(p) + (xmargin, ymargin); M -= max(p) + (xmargin, ymargin); - path bound = box(m, M); - picture tmp; - draw(tmp, "", t * T * g, align, p, arrow, bar, NoMargin, legend, marker); - clip(tmp, bound); - add(f, tmp.fit()); - }); -} - -/*<asyxml><function type="void" signature="distance(picture pic,Label,point,point,bool,real,pen,pen,arrow)"><code></asyxml>*/ -void distance(picture pic = currentpicture, Label L = "", point A, point B, - bool rotated = true, real offset = 3mm, - pen p = currentpen, pen joinpen = invisible, - arrowbar arrow = Arrows(NoFill)) -{/*<asyxml></code><documentation>Draw arrow between A and B (from FAQ).</documentation></function></asyxml>*/ - pair A = A, B = B; - path g = A--B; - transform Tp = shift(-offset * unit(B - A) * I); - pic.add(new void(frame f, transform t) { - picture opic; - path G = Tp * t * g; - transform id = identity(); - transform T = rotated ? rotate(B - A) : id; - Label L = L.copy(); - L.align(L.align, Center); - if(abs(ypart((conj(A - B) * L.align.dir))) < epsgeo && L.filltype == NoFill) - L.filltype = UnFill(1); - draw(opic, T * L, G, p, arrow, Bars, PenMargins); - pair Ap = t * A, Bp = t * B; - draw(opic, (Ap--Tp * Ap)^^(Bp--Tp * Bp), joinpen); - add(f, opic.fit()); - }, true); - pic.addBox(min(g), max(g), Tp * min(p), Tp * max(p)); -} - -/*<asyxml><variable type="real" signature="perpfactor"><code></asyxml>*/ -real perpfactor = 1;/*<asyxml></code><documentation>Factor for drawing perpendicular symbol.</documentation></variable></asyxml>*/ -/*<asyxml><function type="void" signature="perpendicularmark(picture,point,explicit pair,explicit pair,real,pen,margin,filltype)"><code></asyxml>*/ -void perpendicularmark(picture pic = currentpicture, point z, - explicit pair align, - explicit pair dir = E, real size = 0, - pen p = currentpen, - margin margin = NoMargin, - filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw a perpendicular symbol at z aligned in the direction align - relative to the path z--z + dir. - dir(45 + n * 90), where n in N*, are common values for 'align'.</documentation></function></asyxml>*/ - p = squarecap + p; - if(size == 0) size = perpfactor * 3mm + sqrt(1 + linewidth(p)) - 1; - frame apic; - pair d1 = size * align * unit(dir) * dir(-45); - pair d2 = I * d1; - path g = d1--d1 + d2--d2; - g = margin(g, p).g; - draw(apic, g, p); - if(filltype != NoFill) filltype.fill(apic, (relpoint(g, 0) - relpoint(g, 0.5)+ - relpoint(g, 1))--g--cycle, p + solid); - add(pic, apic, locate(z)); -} - -/*<asyxml><function type="void" signature="perpendicularmark(picture,point,vector,vector,real,pen,margin,filltype)"><code></asyxml>*/ -void perpendicularmark(picture pic = currentpicture, point z, - vector align, - vector dir = E, real size = 0, - pen p = currentpen, - margin margin = NoMargin, - filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw a perpendicular symbol at z aligned in the direction align - relative to the path z--z + dir. - dir(45 + n * 90), where n in N, are common values for 'align'.</documentation></function></asyxml>*/ - perpendicularmark(pic, z, (pair)align, (pair)dir, size, - p, margin, filltype); -} - -/*<asyxml><function type="void" signature="perpendicularmark(picture,point,explicit pair,path,real,pen,margin,filltype)"><code></asyxml>*/ -void perpendicularmark(picture pic = currentpicture, point z, explicit pair align, path g, - real size = 0, pen p = currentpen, - margin margin = NoMargin, - filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw a perpendicular symbol at z aligned in the direction align - relative to the path z--z + dir(g, 0). - dir(45 + n * 90), where n in N, are common values for 'align'.</documentation></function></asyxml>*/ - perpendicularmark(pic, z, align, dir(g, 0), size, p, margin, filltype); -} - -/*<asyxml><function type="void" signature="perpendicularmark(picture,point,vector,path,real,pen,margin,filltype)"><code></asyxml>*/ -void perpendicularmark(picture pic = currentpicture, point z, vector align, path g, - real size = 0, pen p = currentpen, - margin margin = NoMargin, - filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw a perpendicular symbol at z aligned in the direction align - relative to the path z--z + dir(g, 0). - dir(45 + n * 90), where n in N, are common values for 'align'.</documentation></function></asyxml>*/ - perpendicularmark(pic, z, (pair)align, dir(g, 0), size, p, margin, filltype); -} - -/*<asyxml><function type="void" signature="markrightangle(picture,point,point,point,real,pen,margin,filltype)"><code></asyxml>*/ -void markrightangle(picture pic = currentpicture, point A, point O, - point B, real size = 0, pen p = currentpen, - margin margin = NoMargin, - filltype filltype = NoFill) -{/*<asyxml></code><documentation>Mark the angle AOB with a perpendicular symbol.</documentation></function></asyxml>*/ - pair Ap = A, Bp = B, Op = O; - pair dir = Ap - Op; - real a1 = degrees(dir); - pair align = rotate(-a1) * unit(dir(Op--Ap, Op--Bp)); - if (margin == NoMargin) - margin = TrueMargin(linewidth(currentpen)/2, linewidth(currentpen)/2); - perpendicularmark(pic = pic, z = O, align = align, - dir = dir, size = size, p = p, - margin = margin, filltype = filltype); -} - -/*<asyxml><function type="bool" signature="simeq(point,point,real)"><code></asyxml>*/ -bool simeq(point A, point B, real fuzz = epsgeo) -{/*<asyxml></code><documentation>Return true iff abs(A - B) < fuzz. - This routine is used internally to know if two points are equal, in particular by the operator == in 'point == point'.</documentation></function></asyxml>*/ - return (abs(A - B) < fuzz); -} -bool simeq(point a, real b, real fuzz = epsgeo) -{ - coordsys R = a.coordsys; - return (abs(a - point(R, ((pair)b)/R)) < fuzz); -} - -/*<asyxml><function type="pair" signature="attract(pair,path,real)"><code></asyxml>*/ -pair attract(pair m, path g, real fuzz = 0) -{/*<asyxml></code><documentation>Return the nearest point (A PAIR) of 'm' which is on the path g. - 'fuzz' is the argument 'fuzz' of 'intersect'.</documentation></function></asyxml>*/ - if(intersect(m, g, fuzz).length > 0) return m; - pair p; - real step = 1, r = 0; - real[] t; - static real eps = sqrt(realEpsilon); - do {// Find a radius for intersection - r += step; - t = intersect(shift(m) * scale(r) * unitcircle, g); - } while(t.length <= 0); - p = point(g, t[1]); - real rm = 0, rM = r; - while(rM - rm > eps) { - r = (rm + rM)/2; - t = intersect(shift(m) * scale(r) * unitcircle, g, fuzz); - if(t.length <= 0) { - rm = r; - } else { - rM = r; - p = point(g, t[1]); - } - } - return p; -} - -/*<asyxml><function type="point" signature="attract(point,path,real)"><code></asyxml>*/ -point attract(point M, path g, real fuzz = 0) -{/*<asyxml></code><documentation>Return the nearest point (A POINT) of 'M' which is on the path g. - 'fuzz' is the argument 'fuzz' of 'intersect'.</documentation></function></asyxml>*/ - return point(M.coordsys, attract(locate(M), g)/M.coordsys); -} - -/*<asyxml><function type="real[]" signature="intersect(path,explicit pair)"><code></asyxml>*/ -real[] intersect(path g, explicit pair p, real fuzz = 0) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - fuzz = fuzz <= 0 ? sqrt(realEpsilon) : fuzz; - real[] or; - real r = realEpsilon; - do{ - or = intersect(g, shift(p) * scale(r) * unitcircle, fuzz); - r *= 2; - } while(or.length == 0); - return or; -} - -/*<asyxml><function type="real[]" signature="intersect(path,explicit point)"><code></asyxml>*/ -real[] intersect(path g, explicit point P, real fuzz = epsgeo) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersect(g, locate(P), fuzz); -} -// *.........................BASES.........................* -// *=======================================================* - -// *=======================================================* -// *.........................LINES.........................* -/*<asyxml><struct signature="line"><code></asyxml>*/ -struct line -{/*<asyxml></code><documentation>This structure provides the objects line, semi - line and segment oriented from A to B. - All the calculus with this structure will be as exact as Asymptote can do. - For a full precision, you must not cast 'line' to 'path' excepted for drawing routines.</documentation></asyxml>*/ - /*<asyxml><property type = "point" signature="A,B"><code></asyxml>*/ - restricted point A,B;/*<asyxml></code><documentation>Two line's points with same coordinate system.</documentation></property><property type = "bool" signature="extendA,extendB"><code></asyxml>*/ - bool extendA,extendB;/*<asyxml></code><documentation>If true,extend 'l' in direction of A (resp. B).</documentation></property><property type = "vector" signature="u,v"><code></asyxml>*/ - restricted vector u,v;/*<asyxml></code><documentation>u = unit(AB) = direction vector,v = normal vector.</documentation></property><property type = "real" signature="a,b,c"><code></asyxml>*/ - restricted real a,b,c;/*<asyxml></code><documentation>Coefficients of the equation ax + by + c = 0 in the coordinate system of 'A'.</documentation></property><property type = "real" signature="slope,origin"><code></asyxml>*/ - restricted real slope, origin;/*<asyxml></code><documentation>Slope and ordinate at the origin.</documentation></property></asyxml>*/ - /*<asyxml><method type = "line" signature="copy()"><code></asyxml>*/ - line copy() - {/*<asyxml></code><documentation>Copy a line in a new instance.</documentation></method></asyxml>*/ - line l = new line; - l.A = A; - l.B = B; - l.a = a; - l.b = b; - l.c = c; - l.slope = slope; - l.origin = origin; - l.u = u; - l.v = v; - l.extendA = extendA; - l.extendB = extendB; - return l; - } - - /*<asyxml><method type = "void" signature="init(point,bool,point,bool)"><code></asyxml>*/ - void init(point A, bool extendA = true, point B, bool extendB = true) - {/*<asyxml></code><documentation>Initialize line. - If 'extendA' is true, the "line" is infinite in the direction of A.</documentation></method></asyxml>*/ - point[] P = standardizecoordsys(A, B); - this.A = P[0]; - this.B = P[1]; - this.a = B.y - A.y; - this.b = A.x - B.x; - this.c = A.y * B.x - A.x * B.y; - this.slope= (this.b == 0) ? infinity : -this.a/this.b; - this.origin = (this.b == 0) ? (this.c == 0) ? 0:infinity : -this.c/this.b; - this.u = unit(P[1]-P[0]); - // int tmp = sgnd(this.slope); - // this.u = (dot((pair)this.u, N) >= 0) ? tmp * this.u : -tmp * this.u; - this.v = rotate(90, point(P[0].coordsys, (0, 0))) * this.u; - this.extendA = extendA; - this.extendB = extendB; - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="line" signature="line(point,bool,point,bool)"><code></asyxml>*/ -line line(point A, bool extendA = true, point B, bool extendB = true) -{/*<asyxml></code><documentation>Return the line passing through 'A' and 'B'. - If 'extendA' is true, the "line" is infinite in the direction of A. - A "line" can be half-line or segment.</documentation></function></asyxml>*/ - if (A == B) abort("line: the points must be distinct."); - line l; - l.init(A, extendA, B, extendB); - return l; -} - -/*<asyxml><struct signature="segment"><code></asyxml>*/ -struct segment -{/*<asyxml></code><documentation><look href = "struct line"/>.</documentation></asyxml>*/ - restricted point A, B;// Extremity. - restricted vector u, v;// u = direction vector, v = normal vector. - restricted real a, b, c;// Coefficients of the équation ax + by + c = 0 - restricted real slope, origin; - segment copy() - { - segment s = new segment; - s.A = A; - s.B = B; - s.a = a; - s.b = b; - s.c = c; - s.slope = slope; - s.origin = origin; - s.u = u; - s.v = v; - return s; - } - - void init(point A, point B) - { - line l; - l.init(A, B); - this.A = l.A; this.B = l.B; - this.a = l.a; this.b = l.b; this.c = l.c; - this.slope = l.slope; this.origin = l.origin; - this.u = l.u; this.v = l.v; - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="segment" signature="segment(point,point)"><code></asyxml>*/ -segment segment(point A, point B) -{/*<asyxml></code><documentation>Return the segment whose the extremities are A and B.</documentation></function></asyxml>*/ - segment s; - s.init(A, B); - return s; -} - -/*<asyxml><function type="real" signature="length(segment)"><code></asyxml>*/ -real length(segment s) -{/*<asyxml></code><documentation>Return the length of 's'.</documentation></function></asyxml>*/ - return abs(s.A - s.B); -} - -/*<asyxml><operator type = "line" signature="cast(segment)"><code></asyxml>*/ -line operator cast(segment s) -{/*<asyxml></code><documentation>A segment is casted to a "finite line".</documentation></operator></asyxml>*/ - return line(s.A, false, s.B, false); -} - -/*<asyxml><operator type = "segment" signature="cast(line)"><code></asyxml>*/ -segment operator cast(line l) -{/*<asyxml></code><documentation>Cast line 'l' to segment [l.A l.B].</documentation></operator></asyxml>*/ - return segment(l.A, l.B); -} - -/*<asyxml><operator type = "line" signature="*(transform,line)"><code></asyxml>*/ -line operator *(transform t, line l) -{/*<asyxml></code><documentation>Provide transform * line</documentation></operator></asyxml>*/ - return line(t * l.A, l.extendA, t * l.B, l.extendB); -} -/*<asyxml><operator type = "line" signature="/(line,real)"><code></asyxml>*/ -line operator /(line l, real x) -{/*<asyxml></code><documentation>Provide l/x. - Return the line passing through l.A/x and l.B/x.</documentation></operator></asyxml>*/ - return line(l.A/x, l.extendA, l.B/x, l.extendB); -} -line operator /(line l, int x){return line(l.A/x, l.B/x);} -/*<asyxml><operator type = "line" signature="*(real,line)"><code></asyxml>*/ -line operator *(real x, line l) -{/*<asyxml></code><documentation>Provide x * l. - Return the line passing through x * l.A and x * l.B.</documentation></operator></asyxml>*/ - return line(x * l.A, l.extendA, x * l.B, l.extendB); -} -line operator *(int x, line l){return line(x * l.A, l.extendA, x * l.B, l.extendB);} - -/*<asyxml><operator type = "line" signature="*(point,line)"><code></asyxml>*/ -line operator *(point M, line l) -{/*<asyxml></code><documentation>Provide point * line. - Return the line passing through unit(M) * l.A and unit(M) * l.B.</documentation></operator></asyxml>*/ - return line(unit(M) * l.A, l.extendA, unit(M) * l.B, l.extendB); -} -/*<asyxml><operator type = "line" signature="+(line,point)"><code></asyxml>*/ -line operator +(line l, vector u) -{/*<asyxml></code><documentation>Provide line + vector (and so line + point). - Return the line 'l' shifted by 'u'.</documentation></operator></asyxml>*/ - return line(l.A + u, l.extendA, l.B + u, l.extendB); -} -/*<asyxml><operator type = "line" signature="-(line,vector)"><code></asyxml>*/ -line operator -(line l, vector u) -{/*<asyxml></code><documentation>Provide line - vector (and so line - point). - Return the line 'l' shifted by '-u'.</documentation></operator></asyxml>*/ - return line(l.A - u, l.extendA, l.B - u, l.extendB); -} - -/*<asyxml><operator type = "line[]" signature="^^(line,line)"><code></asyxml>*/ -line[] operator ^^(line l1, line l2) -{/*<asyxml></code><documentation>Provide line^^line. - Return the line array {l1, l2}.</documentation></operator></asyxml>*/ - line[] ol; - ol.push(l1); ol.push(l2); - return ol; -} - -/*<asyxml><operator type = "line[]" signature="^^(line,line[])"><code></asyxml>*/ -line[] operator ^^(line l1, line[] l2) -{/*<asyxml></code><documentation>Provide line^^line[]. - Return the line array {l1, l2[0], l2[1]...}. - line[]^^line is also defined.</documentation></operator></asyxml>*/ - line[] ol; - ol.push(l1); - for (int i = 0; i < l2.length; ++i) { - ol.push(l2[i]); - } - return ol; -} -line[] operator ^^(line[] l2, line l1) -{ - line[] ol = l2; - ol.push(l1); - return ol; -} - -/*<asyxml><operator type = "line[]" signature="^^(line,line[])"><code></asyxml>*/ -line[] operator ^^(line l1[], line[] l2) -{/*<asyxml></code><documentation>Provide line[]^^line[]. - Return the line array {l1[0], l1[1], ..., l2[0], l2[1], ...}.</documentation></operator></asyxml>*/ - line[] ol = l1; - for (int i = 0; i < l2.length; ++i) { - ol.push(l2[i]); - } - return ol; -} - -/*<asyxml><function type="bool" signature="sameside(point,point,line)"><code></asyxml>*/ -bool sameside(point M, point P, line l) -{/*<asyxml></code><documentation>Return 'true' iff 'M' and 'N' are same side of the line (or on the line) 'l'.</documentation></function></asyxml>*/ - pair A = l.A, B = l.B, m = M, p = P; - pair mil = (A + B)/2; - pair mA = rotate(90, mil) * A; - pair mB = rotate(-90, mil) * A; - return (abs(m - mA) <= abs(m - mB)) == (abs(p - mA) <= abs(p - mB)); - // transform proj = projection(l.A, l.B); - // point Mp = proj * M; - // point Pp = proj * P; - // dot(Mp);dot(Pp); - // return dot(locate(Mp - M), locate(Pp - P)) >= 0; -} - -/*<asyxml><function type="line" signature="line(segment)"><code></asyxml>*/ -line line(segment s) -{/*<asyxml></code><documentation>Return the line passing through 's.A' - and 's.B'.</documentation></function></asyxml>*/ - return line(s.A, s.B); -} -/*<asyxml><function type="segment" signature="segment(line)"><code></asyxml>*/ -segment segment(line l) -{/*<asyxml></code><documentation>Return the segment whose extremities - are 'l.A' and 'l.B'.</documentation></function></asyxml>*/ - return segment(l.A, l.B); -} - -/*<asyxml><function type="point" signature="midpoint(segment)"><code></asyxml>*/ -point midpoint(segment s) -{/*<asyxml></code><documentation>Return the midpoint of 's'.</documentation></function></asyxml>*/ - return 0.5 * (s.A + s.B); -} - -/*<asyxml><function type="void" signature="write(line)"><code></asyxml>*/ -void write(explicit line l) -{/*<asyxml></code><documentation>Write some informations about 'l'.</documentation></function></asyxml>*/ - write("A = "+(string)((pair)l.A)); - write("Extend A = "+(l.extendA ? "true" : "false")); - write("B = "+(string)((pair)l.B)); - write("Extend B = "+(l.extendB ? "true" : "false")); - write("u = "+(string)((pair)l.u)); - write("v = "+(string)((pair)l.v)); - write("a = "+(string) l.a); - write("b = "+(string) l.b); - write("c = "+(string) l.c); - write("slope = "+(string) l.slope); - write("origin = "+(string) l.origin); -} - -/*<asyxml><function type="void" signature="write(explicit segment)"><code></asyxml>*/ -void write(explicit segment s) -{/*<asyxml></code><documentation>Write some informations about 's'.</documentation></function></asyxml>*/ - write("A = "+(string)((pair)s.A)); - write("B = "+(string)((pair)s.B)); - write("u = "+(string)((pair)s.u)); - write("v = "+(string)((pair)s.v)); - write("a = "+(string) s.a); - write("b = "+(string) s.b); - write("c = "+(string) s.c); - write("slope = "+(string) s.slope); - write("origin = "+(string) s.origin); -} - -/*<asyxml><operator type = "bool" signature="==(line,line)"><code></asyxml>*/ -bool operator ==(line l1, line l2) -{/*<asyxml></code><documentation>Provide the test 'line == line'.</documentation></operator></asyxml>*/ - return (collinear(l1.u, l2.u) && - abs(ypart((locate(l1.A) - locate(l1.B))/(locate(l1.A) - locate(l2.B)))) < epsgeo && - l1.extendA == l2.extendA && l1.extendB == l2.extendB); -} - -/*<asyxml><operator type = "bool" signature="!=(line,line)"><code></asyxml>*/ -bool operator !=(line l1, line l2) -{/*<asyxml></code><documentation>Provide the test 'line != line'.</documentation></operator></asyxml>*/ - return !(l1 == l2); -} - -/*<asyxml><operator type = "bool" signature="@(point,line)"><code></asyxml>*/ -bool operator @(point m, line l) -{/*<asyxml></code><documentation>Provide the test 'point @ line'. - Return true iff 'm' is on the 'l'.</documentation></operator></asyxml>*/ - point M = changecoordsys(l.A.coordsys, m); - if (abs(l.a * M.x + l.b * M.y + l.c) >= epsgeo) return false; - if (l.extendA && l.extendB) return true; - if (!l.extendA && !l.extendB) return between(l.A, M, l.B); - if (l.extendA) return sameside(M, l.A, l.B); - return sameside(M, l.B, l.A); -} - -/*<asyxml><function type="coordsys" signature="coordsys(line)"><code></asyxml>*/ -coordsys coordsys(line l) -{/*<asyxml></code><documentation>Return the coordinate system in which 'l' is defined.</documentation></function></asyxml>*/ - return l.A.coordsys; -} - -/*<asyxml><function type="line" signature="reverse(line)"><code></asyxml>*/ -line reverse(line l) -{/*<asyxml></code><documentation>Permute the points 'A' and 'B' of 'l' and so its orientation.</documentation></function></asyxml>*/ - return line(l.B, l.extendB, l.A, l.extendA); -} - -/*<asyxml><function type="line" signature="extend(line)"><code></asyxml>*/ -line extend(line l) -{/*<asyxml></code><documentation>Return the infinite line passing through 'l.A' and 'l.B'.</documentation></function></asyxml>*/ - line ol = l.copy(); - ol.extendA = true; - ol.extendB = true; - return ol; -} - -/*<asyxml><function type="line" signature="complementary(explicit line)"><code></asyxml>*/ -line complementary(explicit line l) -{/*<asyxml></code><documentation>Return the complementary of a half-line with respect of - the full line 'l'.</documentation></function></asyxml>*/ - if (l.extendA && l.extendB) - abort("complementary: the parameter is not a half-line."); - point origin = l.extendA ? l.B : l.A; - point ptdir = l.extendA ? - rotate(180, l.B) * l.A : rotate(180, l.A) * l.B; - return line(origin, false, ptdir); -} - -/*<asyxml><function type="line[]" signature="complementary(explicit segment)"><code></asyxml>*/ -line[] complementary(explicit segment s) -{/*<asyxml></code><documentation>Return the two half-lines of origin 's.A' and 's.B' respectively.</documentation></function></asyxml>*/ - line[] ol = new line[2]; - ol[0] = complementary(line(s.A, false, s.B)); - ol[1] = complementary(line(s.A, s.B, false)); - return ol; -} - -/*<asyxml><function type="line" signature="Ox(coordsys)"><code></asyxml>*/ -line Ox(coordsys R = currentcoordsys) -{/*<asyxml></code><documentation>Return the x-axis of 'R'.</documentation></function></asyxml>*/ - return line(point(R, (0, 0)), point(R, E)); -} -/*<asyxml><constant type = "line" signature="Ox"><code></asyxml>*/ -restricted line Ox = Ox();/*<asyxml></code><documentation>the x-axis of - the default coordinate system.</documentation></constant></asyxml>*/ - -/*<asyxml><function type="line" signature="Oy(coordsys)"><code></asyxml>*/ -line Oy(coordsys R = currentcoordsys) -{/*<asyxml></code><documentation>Return the y-axis of 'R'.</documentation></function></asyxml>*/ - return line(point(R, (0, 0)), point(R, N)); -} -/*<asyxml><constant type = "line" signature="Oy"><code></asyxml>*/ -restricted line Oy = Oy();/*<asyxml></code><documentation>the y-axis of - the default coordinate system.</documentation></constant></asyxml>*/ - -/*<asyxml><function type="line" signature="line(real,point)"><code></asyxml>*/ -line line(real a, point A = point(currentcoordsys, (0, 0))) -{/*<asyxml></code><documentation>Return the line passing through 'A' with an - angle (in the coordinate system of A) 'a' in degrees. - line(point, real) is also defined.</documentation></function></asyxml>*/ - return line(A, A + point(A.coordsys, A.coordsys.polar(1, radians(a)))); -} -line line(point A = point(currentcoordsys, (0, 0)), real a) -{ - return line(a, A); -} -line line(int a, point A = point(currentcoordsys, (0, 0))) -{ - return line((real)a, A); -} - -/*<asyxml><function type="line" signature="line(coordsys,real,real)"><code></asyxml>*/ -line line(coordsys R = currentcoordsys, real slope, real origin) -{/*<asyxml></code><documentation>Return the line defined by slope and y-intercept relative to 'R'.</documentation></function></asyxml>*/ - if (slope == infinity || slope == -infinity) - abort("The slope is infinite. Please, use the routine 'vline'."); - return line(point(R, (0, origin)), point(R, (1, origin + slope))); -} - -/*<asyxml><function type="line" signature="line(coordsys,real,real,real)"><code></asyxml>*/ -line line(coordsys R = currentcoordsys, real a, real b, real c) -{/*<asyxml></code><documentation>Retrun the line defined by equation relative to 'R'.</documentation></function></asyxml>*/ - if (a == 0 && b == 0) abort("line: inconsistent equation..."); - pair M; - M = (a == 0) ? (0, -c/b) : (-c/a, 0); - return line(point(R, M), point(R, M + (-b, a))); -} - -/*<asyxml><function type="line" signature="vline(coordsys)"><code></asyxml>*/ -line vline(coordsys R = currentcoordsys) -{/*<asyxml></code><documentation>Return a vertical line in 'R' passing through the origin of 'R'.</documentation></function></asyxml>*/ - point P = point(R, (0, 0)); - point PP = point(R, (R.O + N)/R); - return line(P, PP); -} -/*<asyxml><constant type = "line" signature="vline"><code></asyxml>*/ -restricted line vline = vline();/*<asyxml></code><documentation>The vertical line in the current coordinate system passing - through the origin of this system.</documentation></constant></asyxml>*/ - -/*<asyxml><function type="line" signature="hline(coordsys)"><code></asyxml>*/ -line hline(coordsys R = currentcoordsys) -{/*<asyxml></code><documentation>Return a horizontal line in 'R' passing through the origin of 'R'.</documentation></function></asyxml>*/ - point P = point(R, (0, 0)); - point PP = point(R, (R.O + E)/R); - return line(P, PP); -} -/*<asyxml><constant type = "line" signature="hline"><code></asyxml>*/ -line hline = hline();/*<asyxml></code><documentation>The horizontal line in the current coordinate system passing - through the origin of this system.</documentation></constant></asyxml>*/ - -/*<asyxml><function type="line" signature="changecoordsys(coordsys,line)"><code></asyxml>*/ -line changecoordsys(coordsys R, line l) -{/*<asyxml></code><documentation>Return the line 'l' in the coordinate system 'R'.</documentation></function></asyxml>*/ - point A = changecoordsys(R, l.A); - point B = changecoordsys(R, l.B); - return line(A, B); -} - -/*<asyxml><function type="transform" signature="scale(real,line,line,bool)"><code></asyxml>*/ -transform scale(real k, line l1, line l2, bool safe = false) -{/*<asyxml></code><documentation>Return the dilatation with respect to - 'l1' in the direction of 'l2'.</documentation></function></asyxml>*/ - return scale(k, l1.A, l1.B, l2.A, l2.B, safe); -} - -/*<asyxml><function type="transform" signature="reflect(line)"><code></asyxml>*/ -transform reflect(line l) -{/*<asyxml></code><documentation>Return the reflect about the line 'l'.</documentation></function></asyxml>*/ - return reflect((pair)l.A, (pair)l.B); -} - -/*<asyxml><function type="transform" signature="reflect(line,line)"><code></asyxml>*/ -transform reflect(line l1, line l2, bool safe = false) -{/*<asyxml></code><documentation>Return the reflect about the line - 'l1' in the direction of 'l2'.</documentation></function></asyxml>*/ - return scale(-1.0, l1, l2, safe); -} - - -/*<asyxml><function type="point[]" signature="intersectionpoints(line,path)"><code></asyxml>*/ -point[] intersectionpoints(line l, path g) -{/*<asyxml></code><documentation>Return all points of intersection of the line 'l' with the path 'g'.</documentation></function></asyxml>*/ - // TODO utiliser la version 1.44 de intersections(path g, pair p, pair q) - // real [] t = intersections(g, l.A, l.B); - // coordsys R = coordsys(l); - // return sequence(new point(int n){return point(R, point(g, t[n])/R);}, t.length); - real [] t; - pair[] op; - pair A = l.A; - pair B = l.B; - real dy = B.y - A.y, - dx = A.x - B.x, - lg = length(g); - - for (int i = 0; i < lg; ++i) - { - pair z0 = point(g, i), - z1 = point(g, i + 1), - c0 = postcontrol(g, i), - c1 = precontrol(g, i + 1), - t3 = z1 - z0 - 3 * c1 + 3 * c0, - t2 = 3 * z0 + 3 * c1 - 6 * c0, - t1 = 3 * c0 - 3z0; - real a = dy * t3.x + dx * t3.y, - b = dy * t2.x + dx * t2.y, - c = dy * t1.x + dx * t1.y, - d = dy * z0.x + dx * z0.y + A.y * B.x - A.x * B.y; - - t = cubicroots(a, b, c, d); - for (int j = 0; j < t.length; ++j) - if ( - t[j]>=0 - && ( - t[j]<1 - || ( - t[j] == 1 - && (i == lg - 1) - && !cyclic(g) - ) - ) - ) { - op.push(point(g, i + t[j])); - } - } - - point[] opp; - for (int i = 0; i < op.length; ++i) - opp.push(point(coordsys(l), op[i]/coordsys(l))); - return opp; -} - -/*<asyxml><function type="point" signature="intersectionpoint(line,line)"><code></asyxml>*/ -point intersectionpoint(line l1, line l2) -{/*<asyxml></code><documentation>Return the point of intersection of line 'l1' with 'l2'. - If 'l1' and 'l2' have an infinity or none point of intersection, - this routine return (infinity, infinity).</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(l1.A, l1.B, l2.A, l2.B); - coordsys R = P[0].coordsys; - pair p = extension(P[0], P[1], P[2], P[3]); - if(finite(p)){ - point p = point(R, p/R); - if (p @ l1 && p @ l2) return p; - } - return point(R, (infinity, infinity)); -} - -/*<asyxml><function type="line" signature="parallel(point,line)"><code></asyxml>*/ -line parallel(point M, line l) -{/*<asyxml></code><documentation>Return the line parallel to 'l' passing through 'M'.</documentation></function></asyxml>*/ - point A, B; - if (M.coordsys != coordsys(l)) - { - A = changecoordsys(M.coordsys, l.A); - B = changecoordsys(M.coordsys, l.B); - } else {A = l.A;B = l.B;} - return line(M, M - A + B); -} - -/*<asyxml><function type="line" signature="parallel(point,explicit vector)"><code></asyxml>*/ -line parallel(point M, explicit vector dir) -{/*<asyxml></code><documentation>Return the line of direction 'dir' and passing through 'M'.</documentation></function></asyxml>*/ - return line(M, M + locate(dir)); -} - -/*<asyxml><function type="line" signature="parallel(point,explicit pair)"><code></asyxml>*/ -line parallel(point M, explicit pair dir) -{/*<asyxml></code><documentation>Return the line of direction 'dir' and passing through 'M'.</documentation></function></asyxml>*/ - return line(M, M + vector(currentcoordsys, dir)); -} - -/*<asyxml><function type="bool" signature="parallel(line,line)"><code></asyxml>*/ -bool parallel(line l1, line l2, bool strictly = false) -{/*<asyxml></code><documentation>Return 'true' if 'l1' and 'l2' are (strictly ?) parallel.</documentation></function></asyxml>*/ - bool coll = collinear(l1.u, l2.u); - return strictly ? coll && (l1 != l2) : coll; -} - -/*<asyxml><function type="bool" signature="concurrent(...line[])"><code></asyxml>*/ -bool concurrent(... line[] l) -{/*<asyxml></code><documentation>Returns true if all the lines 'l' are concurrent.</documentation></function></asyxml>*/ - if (l.length < 3) abort("'concurrent' needs at least for three lines ..."); - pair point = intersectionpoint(l[0], l[1]); - bool conc; - for (int i = 2; i < l.length; ++i) { - pair pt = intersectionpoint(l[i - 1], l[i]); - conc = simeq(pt, point); - if (!conc) break; - } - return conc; -} - -/*<asyxml><function type="transform" signature="projection(line)"><code></asyxml>*/ -transform projection(line l) -{/*<asyxml></code><documentation>Return the orthogonal projection on 'l'.</documentation></function></asyxml>*/ - return projection(l.A, l.B); -} - -/*<asyxml><function type="transform" signature="projection(line,line,bool)"><code></asyxml>*/ -transform projection(line l1, line l2, bool safe = false) -{/*<asyxml></code><documentation>Return the projection on (AB) in parallel of (CD). - If 'safe = true' and (l1)//(l2) return the identity. - If 'safe = false' and (l1)//(l2) return a infinity scaling.</documentation></function></asyxml>*/ - return projection(l1.A, l1.B, l2.A, l2.B, safe); -} - -/*<asyxml><function type="transform" signature="vprojection(line,bool)"><code></asyxml>*/ -transform vprojection(line l, bool safe = false) -{/*<asyxml></code><documentation>Return the projection on 'l' in parallel of N--S. - If 'safe' is 'true' the projected point keeps the same place if 'l' - is vertical.</documentation></function></asyxml>*/ - coordsys R = defaultcoordsys; - return projection(l, line(point(R, N), point(R, S)), safe); -} - -/*<asyxml><function type="transform" signature="hprojection(line,bool)"><code></asyxml>*/ -transform hprojection(line l, bool safe = false) -{/*<asyxml></code><documentation>Return the projection on 'l' in parallel of E--W. - If 'safe' is 'true' the projected point keeps the same place if 'l' - is horizontal.</documentation></function></asyxml>*/ - coordsys R = defaultcoordsys; - return projection(l, line(point(R, E), point(R, W)), safe); -} - -/*<asyxml><function type="line" signature="perpendicular(point,line)"><code></asyxml>*/ -line perpendicular(point M, line l) -{/*<asyxml></code><documentation>Return the perpendicular line of 'l' passing through 'M'.</documentation></function></asyxml>*/ - point Mp = projection(l) * M; - point A = Mp == l.A ? l.B : l.A; - return line(Mp, rotate(90, Mp) * A); -} - -/*<asyxml><function type="line" signature="perpendicular(point,explicit vector)"><code></asyxml>*/ -line perpendicular(point M, explicit vector normal) -{/*<asyxml></code><documentation>Return the line passing through 'M' - whose normal is \param{normal}.</documentation></function></asyxml>*/ - return perpendicular(M, line(M, M + locate(normal))); -} - -/*<asyxml><function type="line" signature="perpendicular(point,explicit pair)"><code></asyxml>*/ -line perpendicular(point M, explicit pair normal) -{/*<asyxml></code><documentation>Return the line passing through 'M' - whose normal is \param{normal} (given in the currentcoordsys).</documentation></function></asyxml>*/ - return perpendicular(M, line(M, M + vector(currentcoordsys, normal))); -} - -/*<asyxml><function type="bool" signature="perpendicular(line,line)"><code></asyxml>*/ -bool perpendicular(line l1, line l2) -{/*<asyxml></code><documentation>Return 'true' if 'l1' and 'l2' are perpendicular.</documentation></function></asyxml>*/ - return abs(dot(locate(l1.u), locate(l2.u))) < epsgeo ; -} - -/*<asyxml><function type="real" signature="angle(line,coordsys)"><code></asyxml>*/ -real angle(line l, coordsys R = coordsys(l)) -{/*<asyxml></code><documentation>Return the angle of the oriented line 'l', - in radian, in the interval ]-pi, pi] and relatively to 'R'.</documentation></function></asyxml>*/ - return angle(l.u, R, false); -} - -/*<asyxml><function type="real" signature="degrees(line,coordsys,bool)"><code></asyxml>*/ -real degrees(line l, coordsys R = coordsys(l)) -{/*<asyxml></code><documentation>Returns the angle of the oriented line 'l' in degrees, - in the interval [0, 360[ and relatively to 'R'.</documentation></function></asyxml>*/ - return degrees(angle(l, R)); -} - -/*<asyxml><function type="real" signature="sharpangle(line,line)"><code></asyxml>*/ -real sharpangle(line l1, line l2) -{/*<asyxml></code><documentation>Return the measure in radians of the sharp angle formed by 'l1' and 'l2'.</documentation></function></asyxml>*/ - vector u1 = l1.u; - vector u2 = (dot(l1.u, l2.u) < 0) ? -l2.u : l2.u; - real a12 = angle(locate(u2)) - angle(locate(u1)); - a12 = a12%(sgnd(a12) * pi); - if (a12 <= -pi/2) { - a12 += pi; - } else if (a12 > pi/2) { - a12 -= pi; - } - return a12; -} - -/*<asyxml><function type="real" signature="angle(line,line)"><code></asyxml>*/ -real angle(line l1, line l2) -{/*<asyxml></code><documentation>Return the measure in radians of oriented angle (l1.u, l2.u).</documentation></function></asyxml>*/ - return angle(locate(l2.u)) - angle(locate(l1.u)); -} - -/*<asyxml><function type="real" signature="degrees(line,line)"><code></asyxml>*/ -real degrees(line l1, line l2) -{/*<asyxml></code><documentation>Return the measure in degrees of the - angle formed by the oriented lines 'l1' and 'l2'.</documentation></function></asyxml>*/ - return degrees(angle(l1, l2)); -} - -/*<asyxml><function type="real" signature="sharpdegrees(line,line)"><code></asyxml>*/ -real sharpdegrees(line l1, line l2) -{/*<asyxml></code><documentation>Return the measure in degrees of the sharp angle formed by 'l1' and 'l2'.</documentation></function></asyxml>*/ - return degrees(sharpangle(l1, l2)); -} - -/*<asyxml><function type="line" signature="bisector(line,line,real,bool)"><code></asyxml>*/ -line bisector(line l1, line l2, real angle = 0, bool sharp = true) -{/*<asyxml></code><documentation>Return the bisector of the angle formed by 'l1' and 'l2' - rotated by the angle 'angle' (in degrees) around intersection point of 'l1' with 'l2'. - If 'sharp' is true (the default), this routine returns the bisector of the sharp angle. - Note that the returned line inherit of coordinate system of 'l1'.</documentation></function></asyxml>*/ - line ol; - if (l1 == l2) return l1; - point A = intersectionpoint(l1, l2); - if (finite(A)) { - if(sharp) ol = rotate(sharpdegrees(l1, l2)/2 + angle, A) * l1; - else { - coordsys R = coordsys(l1); - pair a = A, b = A + l1.u, c = A + l2.u; - pair pp = extension(a, a + dir(a--b, a--c), b, b + dir(b--a, b--c)); - return rotate(angle, A) * line(A, point(R, pp/R)); - } - } else { - ol = l1; - } - return ol; -} - -/*<asyxml><function type="line" signature="sector(int,int,line,line,real,bool)"><code></asyxml>*/ -line sector(int n = 2, int p = 1, line l1, line l2, real angle = 0, bool sharp = true) -{/*<asyxml></code><documentation>Return the p-th nth-sector of the angle - formed by the oriented line 'l1' and 'l2' - rotated by the angle 'angle' (in degrees) around the intersection point of 'l1' with 'l2'. - If 'sharp' is true (the default), this routine returns the bisector of the sharp angle. - Note that the returned line inherit of coordinate system of 'l1'.</documentation></function></asyxml>*/ - line ol; - if (l1 == l2) return l1; - point A = intersectionpoint(l1, l2); - if (finite(A)) { - if(sharp) ol = rotate(p * sharpdegrees(l1, l2)/n + angle, A) * l1; - else { - ol = rotate(p * degrees(l1, l2)/n + angle, A) * l1; - } - } else { - ol = l1; - } - return ol; -} - -/*<asyxml><function type="line" signature="bisector(point,point,point,point,real)"><code></asyxml>*/ -line bisector(point A, point B, point C, point D, real angle = 0, bool sharp = true) -{/*<asyxml></code><documentation>Return the bisector of the angle formed by the lines (AB) and (CD). - <look href = "#bisector(line, line, real, bool)"/>.</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A, B, C, D); - return bisector(line(P[0], P[1]), line(P[2], P[3]), angle, sharp); -} - -/*<asyxml><function type="line" signature="bisector(segment,real)"><code></asyxml>*/ -line bisector(segment s, real angle = 0) -{/*<asyxml></code><documentation>Return the bisector of the segment line 's' rotated by 'angle' (in degrees) around the - midpoint of 's'.</documentation></function></asyxml>*/ - coordsys R = coordsys(s); - point m = midpoint(s); - vector dir = rotateO(90) * unit(s.A - m); - return rotate(angle, m) * line(m + dir, m - dir); -} - -/*<asyxml><function type="line" signature="bisector(point,point,real)"><code></asyxml>*/ -line bisector(point A, point B, real angle = 0) -{/*<asyxml></code><documentation>Return the bisector of the segment line [AB] rotated by 'angle' (in degrees) around the - midpoint of [AB].</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A, B); - return bisector(segment(P[0], P[1]), angle); -} - -/*<asyxml><function type="real" signature="distance(point,line)"><code></asyxml>*/ -real distance(point M, line l) -{/*<asyxml></code><documentation>Return the distance from 'M' to 'l'. - distance(line, point) is also defined.</documentation></function></asyxml>*/ - point A = changecoordsys(defaultcoordsys, l.A); - point B = changecoordsys(defaultcoordsys, l.B); - line ll = line(A, B); - pair m = locate(M); - return abs(ll.a * m.x + ll.b * m.y + ll.c)/sqrt(ll.a^2 + ll.b^2); -} - -real distance(line l, point M) -{ - return distance(M, l); -} - -/*<asyxml><function type="void" signature="draw(picture,Label,line,bool,bool,align,pen,arrowbar,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label L = "", - line l, bool dirA = l.extendA, bool dirB = l.extendB, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, - Label legend = "", marker marker = nomarker, - pathModifier pathModifier = NoModifier) -{/*<asyxml></code><documentation>Draw the line 'l' without altering the size of picture pic. - The boolean parameters control the infinite section. - The global variable 'linemargin' (default value is 0) allows to modify - the bounding box in which the line must be drawn.</documentation></function></asyxml>*/ - if(!(dirA || dirB)) draw(l.A--l.B, invisible);// l is a segment. - Drawline(pic, L, l.A, dirP = dirA, l.B, dirQ = dirB, - align, p, arrow, - legend, marker, pathModifier); -} - -/*<asyxml><function type="void" signature="draw(picture,Label[], line[], align,pen[], arrowbar,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label[] L = new Label[], line[] l, - align align = NoAlign, pen[] p = new pen[], - arrowbar arrow = None, - Label[] legend = new Label[], marker marker = nomarker, - pathModifier pathModifier = NoModifier) -{/*<asyxml></code><documentation>Draw each lines with the corresponding pen.</documentation></function></asyxml>*/ - for (int i = 0; i < l.length; ++i) { - draw(pic, L.length>0 ? L[i] : "", l[i], - align, p = p.length>0 ? p[i] : currentpen, - arrow, legend.length>0 ? legend[i] : "", marker, - pathModifier); - } -} - -/*<asyxml><function type="void" signature="draw(picture,Label[], line[], align,pen,arrowbar,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label[] L = new Label[], line[] l, - align align = NoAlign, pen p, - arrowbar arrow = None, - Label[] legend = new Label[], marker marker = nomarker, - pathModifier pathModifier = NoModifier) -{/*<asyxml></code><documentation>Draw each lines with the same pen 'p'.</documentation></function></asyxml>*/ - pen[] tp = sequence(new pen(int i){return p;}, l.length); - draw(pic, L, l, align, tp, arrow, legend, marker, pathModifier); -} - -/*<asyxml><function type="void" signature="show(picture,line,pen)"><code></asyxml>*/ -void show(picture pic = currentpicture, line l, pen p = red) -{/*<asyxml></code><documentation>Draw some informations of 'l'.</documentation></function></asyxml>*/ - dot("$A$", (pair)l.A, align = -locate(l.v), p); - dot("$B$", (pair)l.B, align = -locate(l.v), p); - draw(l, dotted); - draw("$\vec{u}$", locate(l.A)--locate(l.A + l.u), p, Arrow); - draw("$\vec{v}$", locate(l.A)--locate(l.A + l.v), p, Arrow); -} - -/*<asyxml><function type="point[]" signature="sameside(point,line,line)"><code></asyxml>*/ -point[] sameside(point M, line l1, line l2) -{/*<asyxml></code><documentation>Return two points on 'l1' and 'l2' respectively. - The first point is from the same side of M relatively to 'l2', - the second point is from the same side of M relatively to 'l1'.</documentation></function></asyxml>*/ - point[] op; - coordsys R1 = coordsys(l1); - coordsys R2 = coordsys(l2); - if (parallel(l1, l2)) { - op.push(projection(l1) * M); - op.push(projection(l2) * M); - } else { - point O = intersectionpoint(l1, l2); - if (M @ l2) op.push((sameside(M, O + l1.u, l2)) ? O + l1.u : rotate(180, O) * (O + l1.u)); - else op.push(projection(l1, l2) * M); - if (M @ l1) op.push((sameside(M, O + l2.u, l1)) ? O + l2.u : rotate(180, O) * (O + l2.u)); - else {op.push(projection(l2, l1) * M);} - } - return op; -} - -/*<asyxml><function type="void" signature="markangle(picture,Label,int,real,real,explicit line,explicit line,explicit pair,arrowbar,pen,filltype,margin,marker)"><code></asyxml>*/ -void markangle(picture pic = currentpicture, - Label L = "", int n = 1, real radius = 0, real space = 0, - explicit line l1, explicit line l2, explicit pair align = dir(1), - arrowbar arrow = None, pen p = currentpen, - filltype filltype = NoFill, - margin margin = NoMargin, marker marker = nomarker) -{/*<asyxml></code><documentation>Mark the angle (l1, l2) aligned in the direction 'align' relative to 'l1'. - Commune values for 'align' are dir(real).</documentation></function></asyxml>*/ - if (parallel(l1, l2, true)) return; - real al = degrees(l1, defaultcoordsys); - pair O, A, B; - if (radius == 0) radius = markangleradius(p); - real d = degrees(locate(l1.u)); - align = rotate(d) * align; - if (l1 == l2) { - O = midpoint(segment(l1.A, l1.B)); - A = l1.A;B = l1.B; - if (sameside(rotate(sgn(angle(B-A)) * 45, O) * A, O + align, l1)) {radius = -radius;} - } else { - O = intersectionpoint(extend(l1), extend(l2)); - pair R = O + align; - point [] ss = sameside(point(coordsys(l1), R/coordsys(l1)), l1, l2); - A = ss[0]; - B = ss[1]; - } - markangle(pic = pic, L = L, n = n, radius = radius, space = space, - O = O, A = A, B = B, - arrow = arrow, p = p, filltype = filltype, - margin = margin, marker = marker); -} - -/*<asyxml><function type="void" signature="markangle(picture,Label,int,real,real,explicit line,explicit line,explicit vector,arrowbar,pen,filltype,margin,marker)"><code></asyxml>*/ -void markangle(picture pic = currentpicture, - Label L = "", int n = 1, real radius = 0, real space = 0, - explicit line l1, explicit line l2, explicit vector align, - arrowbar arrow = None, pen p = currentpen, - filltype filltype = NoFill, - margin margin = NoMargin, marker marker = nomarker) -{/*<asyxml></code><documentation>Mark the angle (l1, l2) in the direction 'dir' given relatively to 'l1'.</documentation></function></asyxml>*/ - markangle(pic, L, n, radius, space, l1, l2, (pair)align, arrow, - p, filltype, margin, marker); -} - -/*<asyxml><function type="void" signature="markangle(picture,Label,int,real,real,line,line,arrowbar,pen,filltype,margin,marker)"><code></asyxml>*/ -// void markangle(picture pic = currentpicture, -// Label L = "", int n = 1, real radius = 0, real space = 0, -// explicit line l1, explicit line l2, -// arrowbar arrow = None, pen p = currentpen, -// filltype filltype = NoFill, -// margin margin = NoMargin, marker marker = nomarker) -// {/*<asyxml></code><documentation>Mark the oriented angle (l1, l2).</documentation></function></asyxml>*/ -// if (parallel(l1, l2, true)) return; -// real al = degrees(l1, defaultcoordsys); -// pair O, A, B; -// if (radius == 0) radius = markangleradius(p); -// real d = degrees(locate(l1.u)); -// if (l1 == l2) { -// O = midpoint(segment(l1.A, l1.B)); -// } else { -// O = intersectionpoint(extend(l1), extend(l2)); -// } -// A = O + locate(l1.u); -// B = O + locate(l2.u); -// markangle(pic = pic, L = L, n = n, radius = radius, space = space, -// O = O, A = A, B = B, -// arrow = arrow, p = p, filltype = filltype, -// margin = margin, marker = marker); -// } - -/*<asyxml><function type="void" signature="perpendicularmark(picture,line,line,real,pen,int,margin,filltype)"><code></asyxml>*/ -void perpendicularmark(picture pic = currentpicture, line l1, line l2, - real size = 0, pen p = currentpen, int quarter = 1, - margin margin = NoMargin, filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw a right angle at the intersection point of lines and - aligned in the 'quarter' nth quarter of circle formed by 'l1.u' and - 'l2.u'.</documentation></function></asyxml>*/ - point P = intersectionpoint(l1, l2); - pair align = rotate(90 * (quarter - 1)) * dir(45); - perpendicularmark(P, align, locate(l1.u), size, p, margin, filltype); -} -// *.........................LINES.........................* -// *=======================================================* - -// *=======================================================* -// *........................CONICS.........................* -/*<asyxml><struct signature="bqe"><code></asyxml>*/ -struct bqe -{/*<asyxml></code><documentation>Bivariate Quadratic Equation.</documentation></asyxml>*/ - /*<asyxml><property type = "real[]" signature="a"><code></asyxml>*/ - real[] a;/*<asyxml></code><documentation>a[0] * x^2 + a[1] * x * y + a[2] * y^2 + a[3] * x + a[4] * y + a[5] = 0</documentation></property><property type = "coordsys" signature="coordsys"><code></asyxml>*/ - coordsys coordsys;/*<asyxml></code></property></asyxml>*/ -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="bqe" signature="bqe(coordsys,real,real,real,real,real,real)"><code></asyxml>*/ -bqe bqe(coordsys R = currentcoordsys, - real a, real b, real c, real d, real e, real f) -{/*<asyxml></code><documentation>Return the bivariate quadratic equation - a[0] * x^2 + a[1] * x * y + a[2] * y^2 + a[3] * x + a[4] * y + a[5] = 0 - relatively to the coordinate system R.</documentation></function></asyxml>*/ - bqe obqe; - obqe.coordsys = R; - obqe.a = new real[] {a, b, c, d, e, f}; - return obqe; -} - -/*<asyxml><function type="bqe" signature="changecoordsys(coordsys,bqe)"><code></asyxml>*/ -bqe changecoordsys(coordsys R, bqe bqe) -{/*<asyxml></code><documentation>Returns the bivariate quadratic equation relatively to 'R'.</documentation></function></asyxml>*/ - pair i = coordinates(changecoordsys(R, vector(defaultcoordsys, - bqe.coordsys.i))); - pair j = coordinates(changecoordsys(R, vector(defaultcoordsys, - bqe.coordsys.j))); - pair O = coordinates(changecoordsys(R, point(defaultcoordsys, - bqe.coordsys.O))); - real a = bqe.a[0], b = bqe.a[1], c = bqe.a[2], d = bqe.a[3], f = bqe.a[4], g = bqe.a[5]; - real ux = i.x, uy = i.y; - real vx = j.x, vy = j.y; - real ox = O.x, oy = O.y; - real D = ux * vy - uy * vx; - real ap = (a * vy^2 - b * uy * vy + c * uy^2)/D^2; - real bpp = (-2 * a * vx * vy + b * ux * vy + b * uy * vx - 2 * c * ux * uy)/D^2; - real cp = (a * vx^2 - b * ux * vx + c * ux^2)/D^2; - real dp = (-2a * ox * vy^2 + 2a * oy * vx * vy + 2b * ox * uy * vy- - b * oy * ux * vy - b * oy * uy * vx - 2c * ox * uy^2 + 2c * oy * uy * ux)/D^2+ - (d * vy - f * uy)/D; - real fp = (2a * ox * vx * vy - b * ox * ux * vy - 2a * oy * vx^2- - b * ox * uy * vx + 2 * b * oy * ux * vx + 2c * ox * ux * uy - 2c * oy * ux^2)/D^2+ - (f * ux - d * vx)/D; - g = (a * ox^2 * vy^2 - 2a * ox * oy * vx * vy - b * ox^2 * uy * vy + b * ox * oy * ux * vy+ - a * oy^2 * vx^2 + b * ox * oy * uy * vx - b * oy^2 * ux * vx + c * ox^2 * uy^2- - 2 * c * ox * oy * ux * uy + c * oy^2 * ux^2)/D^2+ - (d * oy * vx + f * ox * uy - d * ox * vy - f * oy * ux)/D + g; - bqe obqe; - obqe.a = approximate(new real[] {ap, bpp, cp, dp, fp, g}); - obqe.coordsys = R; - return obqe; -} - -/*<asyxml><function type="bqe" signature="bqe(point,point,point,point,point)"><code></asyxml>*/ -bqe bqe(point M1, point M2, point M3, point M4, point M5) -{/*<asyxml></code><documentation>Return the bqe of conic passing through the five points (if possible).</documentation></function></asyxml>*/ - coordsys R; - pair[] pts; - if (samecoordsys(M1, M2, M3, M4, M5)) { - R = M1.coordsys; - pts= new pair[] {M1.coordinates, M2.coordinates, M3.coordinates, M4.coordinates, M5.coordinates}; - } else { - R = defaultcoordsys; - pts= new pair[] {M1, M2, M3, M4, M5}; - } - real[][] M; - real[] x; - bqe bqe; - bqe.coordsys = R; - for (int i = 0; i < 5; ++i) {// Try a = -1 - M[i] = new real[] {pts[i].x * pts[i].y, pts[i].y^2, pts[i].x, pts[i].y, 1}; - x[i] = pts[i].x^2; - } - if(abs(determinant(M)) < 1e-5) {// Try c = -1 - for (int i = 0; i < 5; ++i) { - M[i] = new real[] {pts[i].x^2, pts[i].x * pts[i].y, pts[i].x, pts[i].y, 1}; - x[i] = pts[i].y^2; - } - real[] coef = solve(M, x); - bqe.a = new real[] {coef[0], coef[1], -1, coef[2], coef[3], coef[4]}; - } else { - real[] coef = solve(M, x); - bqe.a = new real[] {-1, coef[0], coef[1], coef[2], coef[3], coef[4]}; - } - bqe.a = approximate(bqe.a); - return bqe; -} - -/*<asyxml><function type="bool" signature="samecoordsys(bool...bqe[])"><code></asyxml>*/ -bool samecoordsys(bool warn = true ... bqe[] bqes) -{/*<asyxml></code><documentation>Return true if all the bivariate quadratic equations have the same coordinate system.</documentation></function></asyxml>*/ - bool ret = true; - coordsys t = bqes[0].coordsys; - for (int i = 1; i < bqes.length; ++i) { - ret = (t == bqes[i].coordsys); - if(!ret) break; - t = bqes[i].coordsys; - } - if(warn && !ret) - warning("coodinatesystem", - "the coordinate system of two bivariate quadratic equations are not -the same. The operation will be done relatively to the default coordinate -system."); - return ret; -} - -/*<asyxml><function type="real[]" signature="realquarticroots(real,real,real,real,real)"><code></asyxml>*/ -real[] realquarticroots(real a, real b, real c, real d, real e) -{/*<asyxml></code><documentation>Return the real roots of the quartic equation ax^4 + b^x3 + cx^2 + dx = 0.</documentation></function></asyxml>*/ - static real Fuzz = sqrt(realEpsilon); - pair[] zroots = quarticroots(a, b, c, d, e); - real[] roots; - real p(real x){return a * x^4 + b * x^3 + c * x^2 + d * x + e;} - real prime(real x){return 4 * a * x^3 + 3 * b * x^2 + 2 * c * x + d;} - real x; - bool search = true; - int n; - void addroot(real x) - { - bool exist = false; - for (int i = 0; i < roots.length; ++i) { - if(abs(roots[i]-x) < 1e-5) {exist = true; break;} - } - if(!exist) roots.push(x); - } - for(int i = 0; i < zroots.length; ++i) { - if(zroots[i].y == 0 || abs(p(zroots[i].x)) < Fuzz) addroot(zroots[i].x); - else { - if(abs(zroots[i].y) < 1e-3) { - x = zroots[i].x; - search = true; - n = 200; - while(search) { - real tx = abs(p(x)) < Fuzz ? x : newton(iterations = n, p, prime, x); - if(tx < realMax) { - if(abs(p(tx)) < Fuzz) { - addroot(tx); - search = false; - } else if(n < 200) n *=2; - else { - search = false; - } - } else search = false; //It's not a real root. - } - } - } - } - return roots; -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(bqe,bqe)"><code></asyxml>*/ -point[] intersectionpoints(bqe bqe1, bqe bqe2) -{/*<asyxml></code><documentation>Return the interscetion of the two conic sections whose equations are 'bqe1' and 'bqe2'.</documentation></function></asyxml>*/ - coordsys R = bqe1.coordsys; - bqe lbqe1, lbqe2; - real[] a, b; - if(R != bqe2.coordsys) { - R = currentcoordsys; - a = changecoordsys(R, bqe1).a; - b = changecoordsys(R, bqe2).a; - } else { - a = bqe1.a; - b = bqe2.a; - } - static real e = 100 * sqrt(realEpsilon); - real[] x, y, c; - point[] P; - if(abs(a[0]-b[0]) > e || abs(a[1]-b[1]) > e || abs(a[2]-b[2]) > e) { - c = new real[] {-2 * a[0]*a[2]*b[0]*b[2]+a[0]*a[2]*b[1]^2 - a[0]*a[1]*b[2]*b[1]+a[1]^2 * b[0]*b[2]- - a[2]*a[1]*b[0]*b[1]+a[0]^2 * b[2]^2 + a[2]^2 * b[0]^2, - -a[2]*a[1]*b[0]*b[4]-a[2]*a[4]*b[0]*b[1]-a[1]*a[3]*b[2]*b[1]+2 * a[0]*a[2]*b[1]*b[4]- - a[0]*a[1]*b[2]*b[4]+a[1]^2 * b[2]*b[3]-2 * a[2]*a[3]*b[0]*b[2]-2 * a[0]*a[2]*b[2]*b[3]+ - a[2]*a[3]*b[1]^2 - a[2]*a[1]*b[1]*b[3]+2 * a[1]*a[4]*b[0]*b[2]+2 * a[2]^2 * b[0]*b[3]- - a[0]*a[4]*b[2]*b[1]+2 * a[0]*a[3]*b[2]^2, - -a[3]*a[4]*b[2]*b[1]+a[2]*a[5]*b[1]^2 - a[1]*a[5]*b[2]*b[1]-a[1]*a[3]*b[2]*b[4]+ - a[1]^2 * b[2]*b[5]-2 * a[2]*a[3]*b[2]*b[3]+2 * a[2]^2 * b[0]*b[5]+2 * a[0]*a[5]*b[2]^2 + a[3]^2 * b[2]^2- - 2 * a[2]*a[5]*b[0]*b[2]+2 * a[1]*a[4]*b[2]*b[3]-a[2]*a[4]*b[1]*b[3]-2 * a[0]*a[2]*b[2]*b[5]+ - a[2]^2 * b[3]^2 + 2 * a[2]*a[3]*b[1]*b[4]-a[2]*a[4]*b[0]*b[4]+a[4]^2 * b[0]*b[2]-a[2]*a[1]*b[3]*b[4]- - a[2]*a[1]*b[1]*b[5]-a[0]*a[4]*b[2]*b[4]+a[0]*a[2]*b[4]^2, - -a[4]*a[5]*b[2]*b[1]+a[2]*a[3]*b[4]^2 + 2 * a[3]*a[5]*b[2]^2 - a[2]*a[1]*b[4]*b[5]- - a[2]*a[4]*b[3]*b[4]+2 * a[2]^2 * b[3]*b[5]-2 * a[2]*a[3]*b[2]*b[5]-a[3]*a[4]*b[2]*b[4]- - 2 * a[2]*a[5]*b[2]*b[3]-a[2]*a[4]*b[1]*b[5]+2 * a[1]*a[4]*b[2]*b[5]-a[1]*a[5]*b[2]*b[4]+ - a[4]^2 * b[2]*b[3]+2 * a[2]*a[5]*b[1]*b[4], - -2 * a[2]*a[5]*b[2]*b[5]+a[4]^2 * b[2]*b[5]+a[5]^2 * b[2]^2 - a[4]*a[5]*b[2]*b[4]+a[2]*a[5]*b[4]^2+ - a[2]^2 * b[5]^2 - a[2]*a[4]*b[4]*b[5]}; - x = realquarticroots(c[0], c[1], c[2], c[3], c[4]); - } else { - if(abs(b[4]-a[4]) > e){ - real D = (b[4]-a[4])^2; - c = new real[] {(a[0]*b[4]^2 + (-a[1]*b[3]-2 * a[0]*a[4]+a[1]*a[3]) * b[4]+a[2]*b[3]^2+ - (a[1]*a[4]-2 * a[2]*a[3]) * b[3]+a[0]*a[4]^2 - a[1]*a[3]*a[4]+a[2]*a[3]^2)/D, - -((a[1]*b[4]-2 * a[2]*b[3]-a[1]*a[4]+2 * a[2]*a[3]) * b[5]-a[3]*b[4]^2 + (a[4]*b[3]-a[1]*a[5]+a[3]*a[4]) * b[4]+(2 * a[2]*a[5]-a[4]^2) * b[3]+(a[1]*a[4]-2 * a[2]*a[3]) * a[5])/D, - a[2]*(a[5]-b[5])^2/D + a[4]*(a[5]-b[5])/(b[4]-a[4]) + a[5]}; - x = quadraticroots(c[0], c[1], c[2]); - } else { - if(abs(a[3]-b[3]) > e) { - real D = b[3]-a[3]; - c = new real[] {a[2], (-a[1]*b[5] + a[4]*b[3] + a[1]*a[5] - a[3]*a[4])/D, - a[0]*(a[5]-b[5])^2/D^2 + a[3]*(a[5]-b[5])/D + a[5]}; - y = quadraticroots(c[0], c[1], c[2]); - for (int i = 0; i < y.length; ++i) { - c = new real[] {a[0], a[1]*y[i]+a[3], a[2]*y[i]^2 + a[4]*y[i]+a[5]}; - x = quadraticroots(c[0], c[1], c[2]); - for (int j = 0; j < x.length; ++j) { - if(abs(b[0]*x[j]^2 + b[1]*x[j]*y[i]+b[2]*y[i]^2 + b[3]*x[j]+b[4]*y[i]+b[5]) < 1e-5) - P.push(point(R, (x[j], y[i]))); - } - } - return P; - } else { - if(abs(a[5]-b[5]) < e) abort("intersectionpoints: intersection of identical conics."); - } - } - } - for (int i = 0; i < x.length; ++i) { - c = new real[] {a[2], a[1]*x[i]+a[4], a[0]*x[i]^2 + a[3]*x[i]+a[5]}; - y = quadraticroots(c[0], c[1], c[2]); - for (int j = 0; j < y.length; ++j) { - if(abs(b[0]*x[i]^2 + b[1]*x[i]*y[j]+b[2]*y[j]^2 + b[3]*x[i]+b[4]*y[j]+b[5]) < 1e-5) - P.push(point(R, (x[i], y[j]))); - } - } - return P; -} - -/*<asyxml><struct signature="conic"><code></asyxml>*/ -struct conic -{/*<asyxml></code><documentation></documentation><property type = "real" signature="e,p,h"><code></asyxml>*/ - real e, p, h;/*<asyxml></code><documentation>BE CAREFUL: h = distance(F, D) and p = h * e (http://en.wikipedia.org/wiki/Ellipse) - While http://mathworld.wolfram.com/ takes p = distance(F,D).</documentation></property><property type = "point" signature="F"><code></asyxml>*/ - point F;/*<asyxml></code><documentation>Focus.</documentation></property><property type = "line" signature="D"><code></asyxml>*/ - line D;/*<asyxml></code><documentation>Directrix.</documentation></property><property type = "line" signature="l"><code></asyxml>*/ - line[] l;/*<asyxml></code><documentation>Case of degenerated conic (not yet implemented !).</documentation></property></asyxml>*/ -}/*<asyxml></struct></asyxml>*/ - -bool degenerate(conic c) -{ - return !finite(c.p) || !finite(c.h); -} - -/*ANCconic conic(point, line, real)ANC*/ -conic conic(point F, line l, real e) -{/*DOC - The conic section define by the eccentricity 'e', the focus 'F' - and the directrix 'l'. - Note that an eccentricity equal to 0 defines a circle centered at F, - with a radius equal at the distance from 'F' to 'l'. - If the coordinate system of 'F' and 'l' are not identical, the conic is - attached to 'defaultcoordsys'. - DOC*/ - if(e < 0) abort("conic: 'e' can't be negative."); - conic oc; - point[] P = standardizecoordsys(F, l.A, l.B); - line ll; - ll = line(P[1], P[2]); - oc.e = e < epsgeo ? 0 : e; // Handle case of circle. - oc.F = P[0]; - oc.D = ll; - oc.h = distance(P[0], ll); - oc.p = abs(e) < epsgeo ? oc.h : e * oc.h; - return oc; -} - -/*<asyxml><struct signature="circle"><code></asyxml>*/ -struct circle -{/*<asyxml></code><documentation>All the calculus with this structure will be as exact as Asymptote can do. - For a full precision, you must not cast 'circle' to 'path' excepted for drawing routines.</documentation></asyxml>*/ - /*<asyxml><property type = "point" signature="C"><code></asyxml>*/ - point C;/*<asyxml></code><documentation>Center</documentation></property><property><code></asyxml>*/ - real r;/*<asyxml></code><documentation>Radius</documentation></property><property><code></asyxml>*/ - line l;/*<asyxml></code><documentation>If the radius is infinite, this line is used instead of circle.</documentation></property></asyxml>*/ -}/*<asyxml></struct></asyxml>*/ - -bool degenerate(circle c) -{ - return !finite(c.r); -} - -line line(circle c){ - if(finite(c.r)) abort("Circle can not be casted to line here."); - return c.l; -} - -/*<asyxml><struct signature="ellipse"><code></asyxml>*/ -struct ellipse -{/*<asyxml></code><documentation>Look at <html><a href = "http://mathworld.wolfram.com/Ellipse.html">http://mathworld.wolfram.com/Ellipse.html</a></html></documentation></asyxml>*/ - /*<asyxml><property type = "point" signature="F1,F2,C"><code></asyxml>*/ - restricted point F1,F2,C;/*<asyxml></code><documentation>Foci and center.</documentation></property><property type = "real" signature="a,b,c,e,p"><code></asyxml>*/ - restricted real a,b,c,e,p;/*<asyxml></code></property><property type = "real" signature="angle"><code></asyxml>*/ - restricted real angle;/*<asyxml></code><documentation>Value is degrees(F1 - F2).</documentation></property><property type = "line" signature="D1,D2"><code></asyxml>*/ - restricted line D1,D2;/*<asyxml></code><documentation>Directrices.</documentation></property><property type = "line" signature="l"><code></asyxml>*/ - line l;/*<asyxml></code><documentation>If one axis is infinite, this line is used instead of ellipse.</documentation></property></asyxml>*/ - /*<asyxml><method type = "void" signature="init(point,point,real)"><code></asyxml>*/ - void init(point f1, point f2, real a) - {/*<asyxml></code><documentation>Ellipse given by foci and semimajor axis</documentation></method></asyxml>*/ - point[] P = standardizecoordsys(f1, f2); - this.F1 = P[0]; - this.F2 = P[1]; - this.angle = abs(P[1]-P[0]) < 10 * epsgeo ? 0 : degrees(P[1]-P[0]); - this.C = (P[0] + P[1])/2; - this.a = a; - if(!finite(a)) { - this.l = line(P[0], P[1]); - this.b = infinity; - this.e = 0; - this.c = 0; - } else { - this.c = abs(C - P[0]); - this.b = this.c < epsgeo ? a : sqrt(a^2 - c^2); // Handle case of circle. - this.e = this.c < epsgeo ? 0 : this.c/a; // Handle case of circle. - if(this.e >= 1) abort("ellipse.init: wrong parameter: e >= 1."); - this.p = a * (1 - this.e^2); - if (this.c != 0) {// directrix is not set for a circle. - point A = this.C + (a^2/this.c) * unit(P[0]-this.C); - this.D1 = line(A, A + rotateO(90) * unit(A - this.C)); - this.D2 = reverse(rotate(180, C) * D1); - } - } - } -}/*<asyxml></struct></asyxml>*/ - -bool degenerate(ellipse el) -{ - return (!finite(el.a) || !finite(el.b)); -} - -/*<asyxml><struct signature="parabola"><code></asyxml>*/ -struct parabola -{/*<asyxml></code><documentation>Look at <html><a href = "http://mathworld.wolfram.com/Parabola.html">http://mathworld.wolfram.com/Parabola.html</a></html></documentation><property type = "point" signature="F,V"><code></asyxml>*/ - restricted point F,V;/*<asyxml></code><documentation>Focus and vertex</documentation></property><property type = "real" signature="a,p,e = 1"><code></asyxml>*/ - restricted real a,p,e = 1;/*<asyxml></code></property><property type = "real" signature="angle"><code></asyxml>*/ - restricted real angle;/*<asyxml></code><documentation>Angle, in degrees, of the line (FV).</documentation></property><property type = "line" signature="D"><code></asyxml>*/ - restricted line D;/*<asyxml></code><documentation>Directrix</documentation></property><property type = "pair" signature="bmin,bmax"><code></asyxml>*/ - pair bmin, bmax;/*<asyxml></code><documentation>The (left, bottom) and (right, top) coordinates of region bounding box for drawing the parabola. - If unset the current picture bounding box is used instead.</documentation></property></asyxml>*/ - - /*<asyxml><method type = "void" signature="init(point,line)"><code></asyxml>*/ - void init(point F, line directrix) - {/*<asyxml></code><documentation>Parabola given by focus and directrix.</documentation></method></asyxml>*/ - point[] P = standardizecoordsys(F, directrix.A, directrix.B); - line l = line(P[1], P[2]); - this.F = P[0]; - this.D = l; - this.a = distance(P[0], l)/2; - this.p = 2 * a; - this.V = 0.5 * (F + projection(D) * P[0]); - this.angle = degrees(F - V); - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><struct signature="hyperbola"><code></asyxml>*/ -struct hyperbola -{/*<asyxml></code><documentation><html>Look at <a href = "http://mathworld.wolfram.com/Hyperbola.html">http://mathworld.wolfram.com/Hyperbola.html</a></html></documentation><property type = "point" signature="F1,F2"><code></asyxml>*/ - restricted point F1,F2;/*<asyxml></code><documentation>Foci.</documentation></property><property type = "point" signature="C,V1,V2"><code></asyxml>*/ - restricted point C,V1,V2;/*<asyxml></code><documentation>Center and vertices.</documentation></property><property type = "real" signature="a,b,c,e,p"><code></asyxml>*/ - restricted real a,b,c,e,p;/*<asyxml></code><documentation></documentation></property><property type = "real" signature="angle"><code></asyxml>*/ - restricted real angle;/*<asyxml></code><documentation>Angle,in degrees,of the line (F1F2).</documentation></property><property type = "line" signature="D1,D2,A1,A2"><code></asyxml>*/ - restricted line D1,D2,A1,A2;/*<asyxml></code><documentation>Directrices and asymptotes.</documentation></property><property type = "pair" signature="bmin,bmax"><code></asyxml>*/ - pair bmin, bmax; /*<asyxml></code><documentation>The (left, bottom) and (right, top) coordinates of region bounding box for drawing the hyperbola. - If unset the current picture bounding box is used instead.</documentation></property></asyxml>*/ - - /*<asyxml><method type = "void" signature="init(point,point,real)"><code></asyxml>*/ - void init(point f1, point f2, real a) - {/*<asyxml></code><documentation>Hyperbola given by foci and semimajor axis.</documentation></method></asyxml>*/ - point[] P = standardizecoordsys(f1, f2); - this.F1 = P[0]; - this.F2 = P[1]; - this.angle = degrees(F2 - F1); - this.a = a; - this.C = (P[0] + P[1])/2; - this.c = abs(C - P[0]); - this.e = this.c/a; - if(this.e <= 1) abort("hyperbola.init: wrong parameter: e <= 1."); - this.b = a * sqrt(this.e^2 - 1); - this.p = a * (this.e^2 - 1); - point A = this.C + (a^2/this.c) * unit(P[0]-this.C); - this.D1 = line(A, A + rotateO(90) * unit(A - this.C)); - this.D2 = reverse(rotate(180, C) * D1); - this.V1 = C + a * unit(F1 - C); - this.V2 = C + a * unit(F2 - C); - this.A1 = line(C, V1 + b * unit(rotateO(-90) * (C - V1))); - this.A2 = line(C, V1 + b * unit(rotateO(90) * (C - V1))); - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><variable type="int" signature="conicnodesfactor"><code></asyxml>*/ -int conicnodesfactor = 1;/*<asyxml></code><documentation>Factor for the node number of all conics.</documentation></variable></asyxml>*/ - -/*<asyxml><variable type="int" signature="circlenodesnumberfactor"><code></asyxml>*/ -int circlenodesnumberfactor = 100;/*<asyxml></code><documentation>Factor for the node number of circles.</documentation></variable></asyxml>*/ -/*<asyxml><function type="int" signature="circlenodesnumber(real)"><code></asyxml>*/ -int circlenodesnumber(real r) -{/*<asyxml></code><documentation>Return the number of nodes for drawing a circle of radius 'r'.</documentation></function></asyxml>*/ - if (circlenodesnumberfactor < 100) - warning("circlenodesnumberfactor", - "variable 'circlenodesnumberfactor' may be too small."); - int oi = ceil(circlenodesnumberfactor * abs(r)^0.1); - oi = 45 * floor(oi/45); - return oi == 0 ? 4 : conicnodesfactor * oi; -} - -/*<asyxml><function type="int" signature="circlenodesnumber(real,real,real)"><code></asyxml>*/ -int circlenodesnumber(real r, real angle1, real angle2) -{/*<asyxml></code><documentation>Return the number of nodes to draw a circle arc.</documentation></function></asyxml>*/ - return (r > 0) ? - ceil(circlenodesnumber(r) * abs(angle1 - angle2)/360) : - ceil(circlenodesnumber(r) * abs((1 - abs(angle1 - angle2)/360))); -} - -/*<asyxml><variable type="int" signature="ellispenodesnumberfactor"><code></asyxml>*/ -int ellipsenodesnumberfactor = 250;/*<asyxml></code><documentation>Factor for the node number of ellispe (non-circle).</documentation></variable></asyxml>*/ -/*<asyxml><function type="int" signature="ellipsenodesnumber(real,real)"><code></asyxml>*/ -int ellipsenodesnumber(real a, real b) -{/*<asyxml></code><documentation>Return the number of nodes to draw a ellipse of axis 'a' and 'b'.</documentation></function></asyxml>*/ - if (ellipsenodesnumberfactor < 250) - write("ellipsenodesnumberfactor", - "variable 'ellipsenodesnumberfactor' maybe too small."); - int tmp = circlenodesnumberfactor; - circlenodesnumberfactor = ellipsenodesnumberfactor; - int oi = circlenodesnumber(max(abs(a), abs(b))/min(abs(a), abs(b))); - circlenodesnumberfactor = tmp; - return conicnodesfactor * oi; -} - -/*<asyxml><function type="int" signature="ellipsenodesnumber(real,real,real)"><code></asyxml>*/ -int ellipsenodesnumber(real a, real b, real angle1, real angle2, bool dir) -{/*<asyxml></code><documentation>Return the number of nodes to draw an ellipse arc.</documentation></function></asyxml>*/ - real d; - real da = angle2 - angle1; - if(dir) { - d = angle1 < angle2 ? da : 360 + da; - } else { - d = angle1 < angle2 ? -360 + da : da; - } - int n = floor(ellipsenodesnumber(a, b) * abs(d)/360); - return n < 5 ? 5 : n; -} - -/*<asyxml><variable type="int" signature="parabolanodesnumberfactor"><code></asyxml>*/ -int parabolanodesnumberfactor = 100;/*<asyxml></code><documentation>Factor for the number of nodes of parabolas.</documentation></variable></asyxml>*/ -/*<asyxml><function type="int" signature="parabolanodesnumber(parabola,real,real)"><code></asyxml>*/ -int parabolanodesnumber(parabola p, real angle1, real angle2) -{/*<asyxml></code><documentation>Return the number of nodes for drawing a parabola.</documentation></function></asyxml>*/ - return conicnodesfactor * floor(0.01 * parabolanodesnumberfactor * abs(angle1 - angle2)); -} - -/*<asyxml><variable type="int" signature="hyperbolanodesnumberfactor"><code></asyxml>*/ -int hyperbolanodesnumberfactor = 100;/*<asyxml></code><documentation>Factor for the number of nodes of hyperbolas.</documentation></variable></asyxml>*/ -/*<asyxml><function type="int" signature="hyperbolanodesnumber(hyperbola,real,real)"><code></asyxml>*/ -int hyperbolanodesnumber(hyperbola h, real angle1, real angle2) -{/*<asyxml></code><documentation>Return the number of nodes for drawing an hyperbola.</documentation></function></asyxml>*/ - return conicnodesfactor * floor(0.01 * hyperbolanodesnumberfactor * abs(angle1 - angle2)/h.e); -} - -/*<asyxml><operator type = "conic" signature="+(conic,explicit point)"><code></asyxml>*/ -conic operator +(conic c, explicit point M) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - return conic(c.F + M, c.D + M, c.e); -} -/*<asyxml><operator type = "conic" signature="-(conic,explicit point)"><code></asyxml>*/ -conic operator -(conic c, explicit point M) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - return conic(c.F - M, c.D - M, c.e); -} -/*<asyxml><operator type = "conic" signature="+(conic,explicit pair)"><code></asyxml>*/ -conic operator +(conic c, explicit pair m) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - point M = point(c.F.coordsys, m); - return conic(c.F + M, c.D + M, c.e); -} -/*<asyxml><operator type = "conic" signature="-(conic,explicit pair)"><code></asyxml>*/ -conic operator -(conic c, explicit pair m) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - point M = point(c.F.coordsys, m); - return conic(c.F - M, c.D - M, c.e); -} -/*<asyxml><operator type = "conic" signature="+(conic,vector)"><code></asyxml>*/ -conic operator +(conic c, vector v) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - return conic(c.F + v, c.D + v, c.e); -} -/*<asyxml><operator type = "conic" signature="-(conic,vector)"><code></asyxml>*/ -conic operator -(conic c, vector v) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - return conic(c.F - v, c.D - v, c.e); -} - -/*<asyxml><function type="coordsys" signature="coordsys(conic)"><code></asyxml>*/ -coordsys coordsys(conic co) -{/*<asyxml></code><documentation>Return the coordinate system of 'co'.</documentation></function></asyxml>*/ - return co.F.coordsys; -} - -/*<asyxml><function type="conic" signature="changecoordsys(coordsys,conic)"><code></asyxml>*/ -conic changecoordsys(coordsys R, conic co) -{/*<asyxml></code><documentation>Change the coordinate system of 'co' to 'R'</documentation></function></asyxml>*/ - line l = changecoordsys(R, co.D); - point F = changecoordsys(R, co.F); - return conic(F, l, co.e); -} - -/*<asyxml><typedef type = "polarconicroutine" return = "path" params = "conic, real, real, int, bool"><code></asyxml>*/ -typedef path polarconicroutine(conic co, real angle1, real angle2, int n, bool direction);/*<asyxml></code><documentation>Routine type used to draw conics from 'angle1' to 'angle2'</documentation></typedef></asyxml>*/ - -/*<asyxml><function type="path" signature="arcfromfocus(conic,real,real,int,bool)"><code></asyxml>*/ -path arcfromfocus(conic co, real angle1, real angle2, int n = 400, bool direction = CCW) -{/*<asyxml></code><documentation>Return the path of the conic section 'co' from angle1 to angle2 in degrees, - drawing in the given direction, with n nodes.</documentation></function></asyxml>*/ - guide op; - if (n < 1) return op; - if (angle1 > angle2) { - path g = arcfromfocus(co, angle2, angle1, n, !direction); - return g == nullpath ? g : reverse(g); - } - point O = projection(co.D) * co.F; - pair i = unit(locate(co.F) - locate(O)); - pair j = rotate(90) * i; - coordsys Rp = cartesiansystem(co.F, i, j); - real a1 = direction ? radians(angle1) : radians(angle2); - real a2 = direction ? radians(angle2) : radians(angle1) + 2 * pi; - real step = n == 1 ? 0 : (a2 - a1)/(n - 1); - real a, r; - for (int i = 0; i < n; ++i) { - a = a1 + i * step; - if(co.e >= 1) { - r = 1 - co.e * cos(a); - if(r > epsgeo) { - r = co.p/r; - op = op--Rp * Rp.polar(r, a); - } - } else { - r = co.p/(1 - co.e * cos(a)); - op = op..Rp * Rp.polar(r, a); - } - } - if(co.e < 1 && abs(abs(a2 - a1) - 2 * pi) < epsgeo) op = (path)op..cycle; - - return (direction ? op : op == nullpath ? op :reverse(op)); -} - -/*<asyxml><variable type="polarconicroutine" signature="currentpolarconicroutine"><code></asyxml>*/ -polarconicroutine currentpolarconicroutine = arcfromfocus;/*<asyxml></code><documentation>Default routine used to cast conic section to path.</documentation></variable></asyxml>*/ - -/*<asyxml><function type="point" signature="angpoint(conic,real)"><code></asyxml>*/ -point angpoint(conic co, real angle) -{/*<asyxml></code><documentation>Return the point of 'co' whose the angular (in degrees) - coordinate is 'angle' (mesured from the focus of 'co', relatively - to its 'natural coordinate system').</documentation></function></asyxml>*/ - coordsys R = coordsys(co); - return point(R, point(arcfromfocus(co, angle, angle, 1, CCW), 0)/R); -} - -/*<asyxml><operator type = "bool" signature="@(point,conic)"><code></asyxml>*/ -bool operator @(point M, conic co) -{/*<asyxml></code><documentation>Return true iff 'M' on 'co'.</documentation></operator></asyxml>*/ - if(co.e == 0) return abs(abs(co.F - M) - co.p) < 10 * epsgeo; - return abs(co.e * distance(M, co.D) - abs(co.F - M)) < 10 * epsgeo; -} - -/*<asyxml><function type="coordsys" signature="coordsys(ellipse)"><code></asyxml>*/ -coordsys coordsys(ellipse el) -{/*<asyxml></code><documentation>Return the coordinate system of 'el'.</documentation></function></asyxml>*/ - return el.F1.coordsys; -} - -/*<asyxml><function type="coordsys" signature="canonicalcartesiansystem(ellipse)"><code></asyxml>*/ -coordsys canonicalcartesiansystem(ellipse el) -{/*<asyxml></code><documentation>Return the canonical cartesian system of the ellipse 'el'.</documentation></function></asyxml>*/ - if(degenerate(el)) return cartesiansystem(el.l.A, el.l.u, el.l.v); - pair O = locate(el.C); - pair i = el.e == 0 ? el.C.coordsys.i : unit(locate(el.F1) - O); - pair j = rotate(90) * i; - return cartesiansystem(O, i, j); -} - -/*<asyxml><function type="coordsys" signature="canonicalcartesiansystem(parabola)"><code></asyxml>*/ -coordsys canonicalcartesiansystem(parabola p) -{/*<asyxml></code><documentation>Return the canonical cartesian system of a parabola, - so that Origin = vertex of 'p' and directrix: x = -a.</documentation></function></asyxml>*/ - point A = projection(p.D) * p.F; - pair O = locate((A + p.F)/2); - pair i = unit(locate(p.F) - O); - pair j = rotate(90) * i; - return cartesiansystem(O, i, j); -} - -/*<asyxml><function type="coordsys" signature="canonicalcartesiansystem(hyperbola)"><code></asyxml>*/ -coordsys canonicalcartesiansystem(hyperbola h) -{/*<asyxml></code><documentation>Return the canonical cartesian system of an hyperbola.</documentation></function></asyxml>*/ - pair O = locate(h.C); - pair i = unit(locate(h.F2) - O); - pair j = rotate(90) * i; - return cartesiansystem(O, i, j); -} - -/*<asyxml><function type="ellipse" signature="ellipse(point,point,real)"><code></asyxml>*/ -ellipse ellipse(point F1, point F2, real a) -{/*<asyxml></code><documentation>Return the ellipse whose the foci are 'F1' and 'F2' - and the semimajor axis is 'a'.</documentation></function></asyxml>*/ - ellipse oe; - oe.init(F1, F2, a); - return oe; -} - -/*<asyxml><constant type = "bool" signature="byfoci,byvertices"><code></asyxml>*/ -restricted bool byfoci = true, byvertices = false;/*<asyxml></code><documentation>Constants useful for the routine 'hyperbola(point P1, point P2, real ae, bool byfoci = byfoci)'</documentation></constant></asyxml>*/ - -/*<asyxml><function type="hyperbola" signature="hyperbola(point,point,real,bool)"><code></asyxml>*/ -hyperbola hyperbola(point P1, point P2, real ae, bool byfoci = byfoci) -{/*<asyxml></code><documentation>if 'byfoci = true': - return the hyperbola whose the foci are 'P1' and 'P2' - and the semimajor axis is 'ae'. - else return the hyperbola whose vertexes are 'P1' and 'P2' with eccentricity 'ae'.</documentation></function></asyxml>*/ - hyperbola oh; - point[] P = standardizecoordsys(P1, P2); - if(byfoci) { - oh.init(P[0], P[1], ae); - } else { - real a = abs(P[0]-P[1])/2; - vector V = unit(P[0]-P[1]); - point F1 = P[0] + a * (ae - 1) * V; - point F2 = P[1]-a * (ae - 1) * V; - oh.init(F1, F2, a); - } - return oh; -} - -/*<asyxml><function type="ellipse" signature="ellipse(point,point,point)"><code></asyxml>*/ -ellipse ellipse(point F1, point F2, point M) -{/*<asyxml></code><documentation>Return the ellipse passing through 'M' whose the foci are 'F1' and 'F2'.</documentation></function></asyxml>*/ - point P[] = standardizecoordsys(false, F1, F2, M); - real a = abs(F1 - M) + abs(F2 - M); - return ellipse(F1, F2, finite(a) ? a/2 : a); -} - -/*<asyxml><function type="ellipse" signature="ellipse(point,real,real,real)"><code></asyxml>*/ -ellipse ellipse(point C, real a, real b, real angle = 0) -{/*<asyxml></code><documentation>Return the ellipse centered at 'C' with semimajor axis 'a' along C--C + dir(angle), - semiminor axis 'b' along the perpendicular.</documentation></function></asyxml>*/ - ellipse oe; - coordsys R = C.coordsys; - angle += degrees(R.i); - if(a < b) {angle += 90; real tmp = a; a = b; b = tmp;} - if(finite(a) && finite(b)) { - real c = sqrt(abs(a^2 - b^2)); - point f1, f2; - if(abs(a - b) < epsgeo) { - f1 = C; f2 = C; - } else { - f1 = point(R, (locate(C) + rotate(angle) * (-c, 0))/R); - f2 = point(R, (locate(C) + rotate(angle) * (c, 0))/R); - } - oe.init(f1, f2, a); - } else { - if(finite(b) || !finite(a)) oe.init(C, C + R.polar(1, angle), infinity); - else oe.init(C, C + R.polar(1, 90 + angle), infinity); - } - return oe; -} - -/*<asyxml><function type="ellipse" signature="ellipse(bqe)"><code></asyxml>*/ -ellipse ellipse(bqe bqe) -{/*<asyxml></code><documentation>Return the ellipse a[0] * x^2 + a[1] * xy + a[2] * y^2 + a[3] * x + a[4] * y + a[5] = 0 - given in the coordinate system of 'bqe' with a[i] = bque.a[i]. - <url href = "http://mathworld.wolfram.com/QuadraticCurve.html"/> - <url href = "http://mathworld.wolfram.com/Ellipse.html"/>.</documentation></function></asyxml>*/ - bqe lbqe = changecoordsys(defaultcoordsys, bqe); - real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; - coordsys R = bqe.coordsys; - string message = "ellipse: the given equation is not an equation of an ellipse."; - real u = b^2 * g + d^2 * c + f^2 * a; - real delta = a * c * g + b * f * d + d * b * f - u; - if(abs(delta) < epsgeo) abort(message); - real j = b^2 - a * c; - real i = a + c; - real dd = j * (sgnd(c - a) * sqrt((a - c)^2 + 4 * (b^2)) - c-a); - real ddd = j * (-sgnd(c - a) * sqrt((a - c)^2 + 4 * (b^2)) - c-a); - - if(abs(ddd) < epsgeo || abs(dd) < epsgeo || - j >= -epsgeo || delta/sgnd(i) > 0) abort(message); - - real x = (c * d - b * f)/j, y = (a * f - b * d)/j; - // real dir = abs(b) < epsgeo ? 0 : pi/2-0.5 * acot(0.5 * (c-a)/b); - real dir = abs(b) < epsgeo ? 0 : 0.5 * acot(0.5 * (c - a)/b); - if(dir * (c - a) * b < 0) dir = dir < 0 ? dir + pi/2 : dir - pi/2; - real cd = cos(dir), sd = sin(dir); - real t = a * cd^2 - 2 * b * cd * sd + c * sd^2; - real tt = a * sd^2 + 2 * b * cd * sd + c * cd^2; - real gg = -g + ((d * cd - f * sd)^2)/t + ((d * sd + f * cd)^2)/tt; - t = t/gg; tt = tt/gg; - // The equation of the ellipse is t * (x - center.x)^2 + tt * (y - center.y)^2 = 1; - real aa, bb; - aa = sqrt(2 * (u - 2 * b * d * f - a * c * g)/dd); - bb = sqrt(2 * (u - 2 * b * d * f - a * c * g)/ddd); - a = t > tt ? max(aa, bb) : min(aa, bb); - b = t > tt ? min(aa, bb) : max(aa, bb); - return ellipse(point(R, (x, y)/R), - a, b, degrees(pi/2 - dir - angle(R.i))); -} - -/*<asyxml><function type="ellipse" signature="ellipse(point,point,point,point,point)"><code></asyxml>*/ -ellipse ellipse(point M1, point M2, point M3, point M4, point M5) -{/*<asyxml></code><documentation>Return the ellipse passing through the five points (if possible)</documentation></function></asyxml>*/ - return ellipse(bqe(M1, M2, M3, M4, M5)); -} - -/*<asyxml><function type="bool" signature="inside(ellipse,point)"><code></asyxml>*/ -bool inside(ellipse el, point M) -{/*<asyxml></code><documentation>Return 'true' iff 'M' is inside 'el'.</documentation></function></asyxml>*/ - return abs(el.F1 - M) + abs(el.F2 - M) - 2 * el.a < -epsgeo; -} - -/*<asyxml><function type="bool" signature="inside(parabola,point)"><code></asyxml>*/ -bool inside(parabola p, point M) -{/*<asyxml></code><documentation>Return 'true' if 'M' is inside 'p'.</documentation></function></asyxml>*/ - return distance(p.D, M) - abs(p.F - M) > epsgeo; -} - -/*<asyxml><function type="parabola" signature="parabola(point,line)"><code></asyxml>*/ -parabola parabola(point F, line l) -{/*<asyxml></code><documentation>Return the parabola whose focus is 'F' and directrix is 'l'.</documentation></function></asyxml>*/ - parabola op; - op.init(F, l); - return op; -} - -/*<asyxml><function type="parabola" signature="parabola(point,point)"><code></asyxml>*/ -parabola parabola(point F, point vertex) -{/*<asyxml></code><documentation>Return the parabola whose focus is 'F' and vertex is 'vertex'.</documentation></function></asyxml>*/ - parabola op; - point[] P = standardizecoordsys(F, vertex); - point A = rotate(180, P[1]) * P[0]; - point B = A + rotateO(90) * unit(P[1]-A); - op.init(P[0], line(A, B)); - return op; -} - -/*<asyxml><function type="parabola" signature="parabola(point,real,real)"><code></asyxml>*/ -parabola parabola(point F, real a, real angle) -{/*<asyxml></code><documentation>Return the parabola whose focus is F, latus rectum is 4a and - the angle of the axis of symmetry (in the coordinate system of F) is 'angle'.</documentation></function></asyxml>*/ - parabola op; - coordsys R = F.coordsys; - point A = F - point(R, R.polar(2a, radians(angle))); - point B = A + point(R, R.polar(1, radians(90 + angle))); - op.init(F, line(A, B)); - return op; -} - -/*<asyxml><function type="bool" signature="isparabola(bqe)"><code></asyxml>*/ -bool isparabola(bqe bqe) -{/*<asyxml></code><documentation>Return true iff 'bqe' is the equation of a parabola.</documentation></function></asyxml>*/ - bqe lbqe = changecoordsys(defaultcoordsys, bqe); - real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; - real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); - return (abs(delta) > epsgeo && abs(b^2 - a * c) < epsgeo); -} - -/*<asyxml><function type="parabola" signature="parabola(bqe)"><code></asyxml>*/ -parabola parabola(bqe bqe) -{/*<asyxml></code><documentation>Return the parabola a[0]x^2 + a[1]xy + a[2]y^2 + a[3]x + a[4]y + a[5]] = 0 (a[n] means bqe.a[n]). - <url href = "http://mathworld.wolfram.com/QuadraticCurve.html"/> - <url href = "http://mathworld.wolfram.com/Parabola.html"/></documentation></function></asyxml>*/ - bqe lbqe = changecoordsys(defaultcoordsys, bqe); - real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; - string message = "parabola: the given equation is not an equation of a parabola."; - real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); - if(abs(delta) < 10 * epsgeo || abs(b^2 - a * c) > 10 * epsgeo) abort(message); - real dir = abs(b) < epsgeo ? 0 : 0.5 * acot(0.5 * (c - a)/b); - if(dir * (c - a) * b < 0) dir = dir < 0 ? dir + pi/2 : dir - pi/2; - real cd = cos(dir), sd = sin(dir); - real ap = a * cd^2 - 2 * b * cd * sd + c * sd^2; - real cp = a * sd^2 + 2 * b * cd * sd + c * cd^2; - real dp = d * cd - f * sd; - real fp = d * sd + f * cd; - real gp = g; - parabola op; - coordsys R = bqe.coordsys; - // The equation of the parabola is ap * x'^2 + cp * y'^2 + 2dp * x'+2fp * y'+gp = 0 - if (abs(ap) < epsgeo) {/* directrix parallel to the rotated(dir) y-axis - equation: (y-vertex.y)^2 = 4 * a * (x-vertex) - */ - pair pvertex = rotate(degrees(-dir)) * (0.5(-gp + fp^2/cp)/dp, -fp/cp); - real a = -0.5 * dp/cp; - point vertex = point(R, pvertex/R); - point focus = point(R, (pvertex + a * expi(-dir))/R); - op = parabola(focus, vertex); - - } else {/* directrix parallel to the rotated(dir) x-axis - equation: (x-vertex)^2 = 4 * a * (y-vertex.y) - */ - pair pvertex = rotate(degrees(-dir)) * (-dp/ap, 0.5 * (-gp + dp^2/ap)/fp); - real a = -0.5 * fp/ap; - point vertex = point(R, pvertex/R); - point focus = point(R, (pvertex + a * expi(pi/2 - dir))/R); - op = parabola(focus, vertex); - } - return op; -} - -/*<asyxml><function type="parabola" signature="parabola(point,point,point,line)"><code></asyxml>*/ -parabola parabola(point M1, point M2, point M3, line l) -{/*<asyxml></code><documentation>Return the parabola passing through the three points with its directix - parallel to the line 'l'.</documentation></function></asyxml>*/ - coordsys R; - pair[] pts; - if (samecoordsys(M1, M2, M3)) { - R = M1.coordsys; - } else { - R = defaultcoordsys; - } - real gle = degrees(l); - coordsys Rp = cartesiansystem(R.O, rotate(gle) * R.i, rotate(gle) * R.j); - pts = new pair[] {coordinates(changecoordsys(Rp, M1)), - coordinates(changecoordsys(Rp, M2)), - coordinates(changecoordsys(Rp, M3))}; - real[][] M; - real[] x; - for (int i = 0; i < 3; ++i) { - M[i] = new real[] {pts[i].x, pts[i].y, 1}; - x[i] = -pts[i].x^2; - } - real[] coef = solve(M, x); - return parabola(changecoordsys(R, bqe(Rp, 1, 0, 0, coef[0], coef[1], coef[2]))); -} - -/*<asyxml><function type="parabola" signature="parabola(point,point,point,point,point)"><code></asyxml>*/ -parabola parabola(point M1, point M2, point M3, point M4, point M5) -{/*<asyxml></code><documentation>Return the parabola passing through the five points.</documentation></function></asyxml>*/ - return parabola(bqe(M1, M2, M3, M4, M5)); -} - -/*<asyxml><function type="hyperbola" signature="hyperbola(point,real,real,real)"><code></asyxml>*/ -hyperbola hyperbola(point C, real a, real b, real angle = 0) -{/*<asyxml></code><documentation>Return the hyperbola centered at 'C' with semimajor axis 'a' along C--C + dir(angle), - semiminor axis 'b' along the perpendicular.</documentation></function></asyxml>*/ - hyperbola oh; - coordsys R = C.coordsys; - angle += degrees(R.i); - real c = sqrt(a^2 + b^2); - point f1 = point(R, (locate(C) + rotate(angle) * (-c, 0))/R); - point f2 = point(R, (locate(C) + rotate(angle) * (c, 0))/R); - oh.init(f1, f2, a); - return oh; -} - -/*<asyxml><function type="hyperbola" signature="hyperbola(bqe)"><code></asyxml>*/ -hyperbola hyperbola(bqe bqe) -{/*<asyxml></code><documentation>Return the hyperbola a[0]x^2 + a[1]xy + a[2]y^2 + a[3]x + a[4]y + a[5]] = 0 (a[n] means bqe.a[n]). - <url href = "http://mathworld.wolfram.com/QuadraticCurve.html"/> - <url href = "http://mathworld.wolfram.com/Hyperbola.html"/></documentation></function></asyxml>*/ - bqe lbqe = changecoordsys(defaultcoordsys, bqe); - real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; - string message = "hyperbola: the given equation is not an equation of a hyperbola."; - real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); - if(abs(delta) < 10 * epsgeo || abs(b^2 - a * c) < 0) abort(message); - real dir = abs(b) < epsgeo ? 0 : 0.5 * acot(0.5 * (c - a)/b); - real cd = cos(dir), sd = sin(dir); - real ap = a * cd^2 - 2 * b * cd * sd + c * sd^2; - real cp = a * sd^2 + 2 * b * cd * sd + c * cd^2; - real dp = d * cd - f * sd; - real fp = d * sd + f * cd; - real gp = -g + dp^2/ap + fp^2/cp; - hyperbola op; - coordsys R = bqe.coordsys; - real j = b^2 - a * c; - point C = point(R, ((c * d - b * f)/j, (a * f - b * d)/j)/R); - real aa = gp/ap, bb = gp/cp; - real a = sqrt(abs(aa)), b = sqrt(abs(bb)); - if(aa < 0) {dir -= pi/2; aa = a; a = b; b = aa;} - return hyperbola(C, a, b, degrees(-dir - angle(R.i))); -} - -/*<asyxml><function type="hyperbola" signature="hyperbola(point,point,point,point,point)"><code></asyxml>*/ -hyperbola hyperbola(point M1, point M2, point M3, point M4, point M5) -{/*<asyxml></code><documentation>Return the hyperbola passing through the five points (if possible).</documentation></function></asyxml>*/ - return hyperbola(bqe(M1, M2, M3, M4, M5)); -} - -/*<asyxml><function type="hyperbola" signature="conj(hyperbola)"><code></asyxml>*/ -hyperbola conj(hyperbola h) -{/*<asyxml></code><documentation>Conjugate.</documentation></function></asyxml>*/ - return hyperbola(h.C, h.b, h.a, 90 + h.angle); -} - -/*<asyxml><function type="circle" signature="circle(explicit point,real)"><code></asyxml>*/ -circle circle(explicit point C, real r) -{/*<asyxml></code><documentation>Circle given by center and radius.</documentation></function></asyxml>*/ - circle oc = new circle; - oc.C = C; - oc.r = r; - if(!finite(r)) oc.l = line(C, C + vector(C.coordsys, (1, 0))); - return oc; -} - -/*<asyxml><function type="circle" signature="circle(point,point)"><code></asyxml>*/ -circle circle(point A, point B) -{/*<asyxml></code><documentation>Return the circle of diameter AB.</documentation></function></asyxml>*/ - real r; - circle oc; - real a = abs(A), b = abs(B); - if(finite(a) && finite(b)) { - oc = circle((A + B)/2, abs(A - B)/2); - } else { - oc.r = infinity; - if(finite(abs(A))) oc.l = line(A, A + unit(B)); - else { - if(finite(abs(B))) oc.l = line(B, B + unit(A)); - else if(finite(abs(A - B)/2)) oc = circle((A + B)/2, abs(A - B)/2); else - oc.l = line(A, B); - } - } - return oc; -} - -/*<asyxml><function type="circle" signature="circle(segment)"><code></asyxml>*/ -circle circle(segment s) -{/*<asyxml></code><documentation>Return the circle of diameter 's'.</documentation></function></asyxml>*/ - return circle(s.A, s.B); -} - -/*<asyxml><function type="point" signature="circumcenter(point,point,point)"><code></asyxml>*/ -point circumcenter(point A, point B, point C) -{/*<asyxml></code><documentation>Return the circumcenter of triangle ABC.</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A, B, C); - coordsys R = P[0].coordsys; - pair a = A, b = B, c = C; - pair mAB = (a + b)/2; - pair mAC = (a + c)/2; - pair pp = extension(mAB, rotate(90, mAB) * a, mAC, rotate(90, mAC) * c); - return point(R, pp/R); -} - -/*<asyxml><function type="circle" signature="circle(point,point,point)"><code></asyxml>*/ -circle circle(point A, point B, point C) -{/*<asyxml></code><documentation>Return the circumcircle of the triangle ABC.</documentation></function></asyxml>*/ - if(collinear(A - B, A - C)) { - circle oc; - oc.r = infinity; - oc.C = (A + B + C)/3; - oc.l = line(oc.C, oc.C == A ? B : A); - return oc; - } - point c = circumcenter(A, B, C); - return circle(c, abs(c - A)); -} - -/*<asyxml><function type="circle" signature="circumcircle(point,point,point)"><code></asyxml>*/ -circle circumcircle(point A, point B, point C) -{/*<asyxml></code><documentation>Return the circumcircle of the triangle ABC.</documentation></function></asyxml>*/ - return circle(A, B, C); -} - -/*<asyxml><operator type = "circle" signature="*(real,explicit circle)"><code></asyxml>*/ -circle operator *(real x, explicit circle c) -{/*<asyxml></code><documentation>Multiply the radius of 'c'.</documentation></operator></asyxml>*/ - return finite(c.r) ? circle(c.C, x * c.r) : c; -} -circle operator *(int x, explicit circle c) -{ - return finite(c.r) ? circle(c.C, x * c.r) : c; -} -/*<asyxml><operator type = "circle" signature="/(explicit circle,real)"><code></asyxml>*/ -circle operator /(explicit circle c, real x) -{/*<asyxml></code><documentation>Divide the radius of 'c'</documentation></operator></asyxml>*/ - return finite(c.r) ? circle(c.C, c.r/x) : c; -} -circle operator /(explicit circle c, int x) -{ - return finite(c.r) ? circle(c.C, c.r/x) : c; -} -/*<asyxml><operator type = "circle" signature="+(explicit circle,explicit point)"><code></asyxml>*/ -circle operator +(explicit circle c, explicit point M) -{/*<asyxml></code><documentation>Translation of 'c'.</documentation></operator></asyxml>*/ - return circle(c.C + M, c.r); -} -/*<asyxml><operator type = "circle" signature="-(explicit circle,explicit point)"><code></asyxml>*/ -circle operator -(explicit circle c, explicit point M) -{/*<asyxml></code><documentation>Translation of 'c'.</documentation></operator></asyxml>*/ - return circle(c.C - M, c.r); -} -/*<asyxml><operator type = "circle" signature="+(explicit circle,pair)"><code></asyxml>*/ -circle operator +(explicit circle c, pair m) -{/*<asyxml></code><documentation>Translation of 'c'. - 'm' represent coordinates in the coordinate system where 'c' is defined.</documentation></operator></asyxml>*/ - return circle(c.C + m, c.r); -} -/*<asyxml><operator type = "circle" signature="-(explicit circle,pair)"><code></asyxml>*/ -circle operator -(explicit circle c, pair m) -{/*<asyxml></code><documentation>Translation of 'c'. - 'm' represent coordinates in the coordinate system where 'c' is defined.</documentation></operator></asyxml>*/ - return circle(c.C - m, c.r); -} -/*<asyxml><operator type = "circle" signature="+(explicit circle,vector)"><code></asyxml>*/ -circle operator +(explicit circle c, vector m) -{/*<asyxml></code><documentation>Translation of 'c'.</documentation></operator></asyxml>*/ - return circle(c.C + m, c.r); -} -/*<asyxml><operator type = "circle" signature="-(explicit circle,vector)"><code></asyxml>*/ -circle operator -(explicit circle c, vector m) -{/*<asyxml></code><documentation>Translation of 'c'.</documentation></operator></asyxml>*/ - return circle(c.C - m, c.r); -} -/*<asyxml><operator type = "real" signature="^(point,explicit circle)"><code></asyxml>*/ -real operator ^(point M, explicit circle c) -{/*<asyxml></code><documentation>The power of 'M' with respect to the circle 'c'</documentation></operator></asyxml>*/ - return xpart((abs(locate(M) - locate(c.C)), c.r)^2); -} -/*<asyxml><operator type = "bool" signature="@(point,explicit circle)"><code></asyxml>*/ -bool operator @(point M, explicit circle c) -{/*<asyxml></code><documentation>Return true iff 'M' is on the circle 'c'.</documentation></operator></asyxml>*/ - return finite(c.r) ? - abs(abs(locate(M) - locate(c.C)) - abs(c.r)) <= 10 * epsgeo : - M @ c.l; -} - -/*<asyxml><operator type = "ellipse" signature="cast(circle)"><code></asyxml>*/ -ellipse operator cast(circle c) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - return finite(c.r) ? ellipse(c.C, c.r, c.r, 0) : ellipse(c.l.A, c.l.B, infinity); -} - -/*<asyxml><operator type = "circle" signature="cast(ellipse)"><code></asyxml>*/ -circle operator cast(ellipse el) -{/*<asyxml></code><documentation></documentation></operator></asyxml>*/ - circle oc; - bool infb = (!finite(el.a) || !finite(el.b)); - if(!infb && abs(el.a - el.b) > epsgeo) - abort("Can not cast ellipse with different axis values to circle"); - oc = circle(el.C, infb ? infinity : el.a); - oc.l = el.l.copy(); - return oc; -} - -/*<asyxml><operator type = "ellipse" signature="cast(conic)"><code></asyxml>*/ -ellipse operator cast(conic co) -{/*<asyxml></code><documentation>Cast a conic to an ellipse (can be a circle).</documentation></operator></asyxml>*/ - if(degenerate(co) && co.e < 1) return ellipse(co.l[0].A, co.l[0].B, infinity); - ellipse oe; - if(co.e < 1) { - real a = co.p/(1 - co.e^2); - real c = co.e * a; - vector v = co.D.v; - if(!sameside(co.D.A + v, co.F, co.D)) v = -v; - point f2 = co.F + 2 * c * v; - f2 = changecoordsys(co.F.coordsys, f2); - oe = a == 0 ? ellipse(co.F, co.p, co.p, 0) : ellipse(co.F, f2, a); - } else - abort("casting: The conic section is not an ellipse."); - return oe; -} - -/*<asyxml><operator type = "parabola" signature="cast(conic)"><code></asyxml>*/ -parabola operator cast(conic co) -{/*<asyxml></code><documentation>Cast a conic to a parabola.</documentation></operator></asyxml>*/ - parabola op; - if(abs(co.e - 1) > epsgeo) abort("casting: The conic section is not a parabola."); - op.init(co.F, co.D); - return op; -} - -/*<asyxml><operator type = "conic" signature="cast(parabola)"><code></asyxml>*/ -conic operator cast(parabola p) -{/*<asyxml></code><documentation>Cast a parabola to a conic section.</documentation></operator></asyxml>*/ - return conic(p.F, p.D, 1); -} - -/*<asyxml><operator type = "hyperbola" signature="cast(conic)"><code></asyxml>*/ -hyperbola operator cast(conic co) -{/*<asyxml></code><documentation>Cast a conic section to an hyperbola.</documentation></operator></asyxml>*/ - hyperbola oh; - if(co.e > 1) { - real a = co.p/(co.e^2 - 1); - real c = co.e * a; - vector v = co.D.v; - if(sameside(co.D.A + v, co.F, co.D)) v = -v; - point f2 = co.F + 2 * c * v; - f2 = changecoordsys(co.F.coordsys, f2); - oh = hyperbola(co.F, f2, a); - } else - abort("casting: The conic section is not an hyperbola."); - return oh; -} - -/*<asyxml><operator type = "conic" signature="cast(hyperbola)"><code></asyxml>*/ -conic operator cast(hyperbola h) -{/*<asyxml></code><documentation>Hyperbola to conic section.</documentation></operator></asyxml>*/ - return conic(h.F1, h.D1, h.e); -} - -/*<asyxml><operator type = "conic" signature="cast(ellipse)"><code></asyxml>*/ -conic operator cast(ellipse el) -{/*<asyxml></code><documentation>Ellipse to conic section.</documentation></operator></asyxml>*/ - conic oc; - if(abs(el.c) > epsgeo) { - real x = el.a^2/el.c; - point O = (el.F1 + el.F2)/2; - point A = O + x * unit(el.F1 - el.F2); - oc = conic(el.F1, perpendicular(A, line(el.F1, el.F2)), el.e); - } else {//The ellipse is a circle - coordsys R = coordsys(el); - point M = el.F1 + point(R, R.polar(el.a, 0)); - line l = line(rotate(90, M) * el.F1, M); - oc = conic(el.F1, l, 0); - } - if(degenerate(el)) { - oc.p = infinity; - oc.h = infinity; - oc.l = new line[]{el.l}; - } - return oc; -} - -/*<asyxml><operator type = "conic" signature="cast(circle)"><code></asyxml>*/ -conic operator cast(circle c) -{/*<asyxml></code><documentation>Circle to conic section.</documentation></operator></asyxml>*/ - return (conic)((ellipse)c); -} - -/*<asyxml><operator type = "circle" signature="cast(conic)"><code></asyxml>*/ -circle operator cast(conic c) -{/*<asyxml></code><documentation>Conic section to circle.</documentation></operator></asyxml>*/ - ellipse el = (ellipse)c; - circle oc; - if(abs(el.a - el.b) < epsgeo) { - oc = circle(el.C, el.a); - if(degenerate(c)) oc.l = c.l[0]; - } - else abort("Can not cast this conic to a circle"); - return oc; -} - -/*<asyxml><operator type = "ellipse" signature="*(transform,ellipse)"><code></asyxml>*/ -ellipse operator *(transform t, ellipse el) -{/*<asyxml></code><documentation>Provide transform * ellipse.</documentation></operator></asyxml>*/ - if(!degenerate(el)) { - point[] ep; - for (int i = 0; i < 360; i += 72) { - ep.push(t * angpoint(el, i)); - } - ellipse oe = ellipse(ep[0], ep[1], ep[2], ep[3], ep[4]); - if(angpoint(oe, 0) != ep[0]) return ellipse(oe.F2, oe.F1, oe.a); - return oe; - } - return ellipse(t * el.l.A, t * el.l.B, infinity); -} - -/*<asyxml><operator type = "parabola" signature="*(transform,parabola)"><code></asyxml>*/ -parabola operator *(transform t, parabola p) -{/*<asyxml></code><documentation>Provide transform * parabola.</documentation></operator></asyxml>*/ - point[] P; - P.push(t * angpoint(p, 45)); - P.push(t * angpoint(p, -45)); - P.push(t * angpoint(p, 180)); - parabola op = parabola(P[0], P[1], P[2], t * p.D); - op.bmin = p.bmin; - op.bmax = p.bmax; - - return op; -} - -/*<asyxml><operator type = "ellipse" signature="*(transform,circle)"><code></asyxml>*/ -ellipse operator *(transform t, circle c) -{/*<asyxml></code><documentation>Provide transform * circle. - For example, 'circle C = scale(2) * circle' and 'ellipse E = xscale(2) * circle' are valid - but 'circle C = xscale(2) * circle' is invalid.</documentation></operator></asyxml>*/ - return t * ((ellipse)c); -} - -/*<asyxml><operator type = "hyperbola" signature="*(transform,hyperbola)"><code></asyxml>*/ -hyperbola operator *(transform t, hyperbola h) -{/*<asyxml></code><documentation>Provide transform * hyperbola.</documentation></operator></asyxml>*/ - if (t == identity()) { - return h; - } - - point[] ep; - for (int i = 90; i <= 270; i += 45) { - ep.push(t * angpoint(h, i)); - } - - hyperbola oe = hyperbola(ep[0], ep[1], ep[2], ep[3], ep[4]); - if(angpoint(oe, 90) != ep[0]) { - oe = hyperbola(oe.F2, oe.F1, oe.a); - } - - oe.bmin = h.bmin; - oe.bmax = h.bmax; - - return oe; -} - -/*<asyxml><operator type = "conic" signature="*(transform,conic)"><code></asyxml>*/ -conic operator *(transform t, conic co) -{/*<asyxml></code><documentation>Provide transform * conic.</documentation></operator></asyxml>*/ - if(co.e < 1) return (t * ((ellipse)co)); - if(co.e == 1) return (t * ((parabola)co)); - return (t * ((hyperbola)co)); -} - -/*<asyxml><operator type = "ellipse" signature="*(real,ellipse)"><code></asyxml>*/ -ellipse operator *(real x, ellipse el) -{/*<asyxml></code><documentation>Identical but more efficient (rapid) than 'scale(x, el.C) * el'.</documentation></operator></asyxml>*/ - return degenerate(el) ? el : ellipse(el.C, x * el.a, x * el.b, el.angle); -} - -/*<asyxml><operator type = "ellipse" signature="/(ellipse,real)"><code></asyxml>*/ -ellipse operator /(ellipse el, real x) -{/*<asyxml></code><documentation>Identical but more efficient (rapid) than 'scale(1/x, el.C) * el'.</documentation></operator></asyxml>*/ - return degenerate(el) ? el : ellipse(el.C, el.a/x, el.b/x, el.angle); -} - -/*<asyxml><function type="path" signature="arcfromcenter(ellipse,real,real,int,bool)"><code></asyxml>*/ -path arcfromcenter(ellipse el, real angle1, real angle2, - bool direction=CCW, - int n=ellipsenodesnumber(el.a,el.b,angle1,angle2,direction)) -{/*<asyxml></code><documentation>Return the path of the ellipse 'el' from angle1 to angle2 in degrees, - drawing in the given direction, with n nodes. - The angles are mesured relatively to the axis (C,x-axis) where C is - the center of the ellipse.</documentation></function></asyxml>*/ - if(degenerate(el)) abort("arcfromcenter: can not convert degenerated ellipse to path."); - if (angle1 > angle2) - return reverse(arcfromcenter(el, angle2, angle1, !direction, n)); - - guide op; - coordsys Rp=coordsys(el); - if (n < 1) return op; - - interpolate join = operator ..; - real stretch = max(el.a/el.b, el.b/el.a); - - if (stretch > 10) { - n *= floor(stretch/5); - join = operator --; - } - - real a1 = direction ? radians(angle1) : radians(angle2); - real a2 = direction ? radians(angle2) : radians(angle1) + 2 * pi; - real step=(a2 - a1)/(n != 1 ? n-1 : 1); - real a, r; - real da = radians(el.angle); - - for (int i=0; i < n; ++i) { - a = a1 + i * step; - r = el.b/sqrt(1 - (el.e * cos(a))^2); - op = join(op, Rp*Rp.polar(r, da + a)); - } - - return shift(el.C.x*Rp.i + el.C.y*Rp.j) * (direction ? op : reverse(op)); -} - -/*<asyxml><function type="path" signature="arcfromcenter(hyperbola,real,real,int,bool)"><code></asyxml>*/ -path arcfromcenter(hyperbola h, real angle1, real angle2, - int n = hyperbolanodesnumber(h, angle1, angle2), - bool direction = CCW) -{/*<asyxml></code><documentation>Return the path of the hyperbola 'h' from angle1 to angle2 in degrees, - drawing in the given direction, with n nodes. - The angles are mesured relatively to the axis (C, x-axis) where C is - the center of the hyperbola.</documentation></function></asyxml>*/ - guide op; - coordsys Rp = coordsys(h); - if (n < 1) return op; - if (angle1 > angle2) { - path g = reverse(arcfromcenter(h, angle2, angle1, n, !direction)); - return g == nullpath ? g : reverse(g); - } - real a1 = direction ? radians(angle1) : radians(angle2); - real a2 = direction ? radians(angle2) : radians(angle1) + 2 * pi; - real step = (a2 - a1)/(n != 1 ? n - 1 : 1); - real a, r; - typedef guide interpolate(... guide[]); - interpolate join = operator ..; - real da = radians(h.angle); - for (int i = 0; i < n; ++i) { - a = a1 + i * step; - r = (h.b * cos(a))^2 - (h.a * sin(a))^2; - if(r > epsgeo) { - r = sqrt(h.a^2 * h.b^2/r); - op = join(op, Rp * Rp.polar(r, a + da)); - join = operator ..; - } else join = operator --; - } - return shift(h.C.x * Rp.i + h.C.y * Rp.j)* - (direction ? op : op == nullpath ? op : reverse(op)); -} - -/*<asyxml><function type="path" signature="arcfromcenter(explicit conic,real,real,int,bool)"><code></asyxml>*/ -path arcfromcenter(explicit conic co, real angle1, real angle2, - int n, bool direction = CCW) -{/*<asyxml></code><documentation>Use arcfromcenter(ellipse, ...) or arcfromcenter(hyperbola, ...) depending of - the eccentricity of 'co'.</documentation></function></asyxml>*/ - path g; - if(co.e < 1) - g = arcfromcenter((ellipse)co, angle1, - angle2, direction, n); - else if(co.e > 1) - g = arcfromcenter((hyperbola)co, angle1, - angle2, n, direction); - else abort("arcfromcenter: does not exist for a parabola."); - return g; -} - -/*<asyxml><constant type = "polarconicroutine" signature="fromCenter"><code></asyxml>*/ -restricted polarconicroutine fromCenter = arcfromcenter;/*<asyxml></code><documentation></documentation></constant></asyxml>*/ -/*<asyxml><constant type = "polarconicroutine" signature="fromFocus"><code></asyxml>*/ -restricted polarconicroutine fromFocus = arcfromfocus;/*<asyxml></code><documentation></documentation></constant></asyxml>*/ - -/*<asyxml><function type="bqe" signature="equation(ellipse)"><code></asyxml>*/ -bqe equation(ellipse el) -{/*<asyxml></code><documentation>Return the coefficients of the equation of the ellipse in its coordinate system: - bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0. - One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.</documentation></function></asyxml>*/ - pair[] pts; - for (int i = 0; i < 360; i += 72) - pts.push(locate(angpoint(el, i))); - - real[][] M; - real[] x; - for (int i = 0; i < 5; ++i) { - M[i] = new real[] {pts[i].x * pts[i].y, pts[i].y^2, pts[i].x, pts[i].y, 1}; - x[i] = -pts[i].x^2; - } - real[] coef = solve(M, x); - bqe bqe = changecoordsys(coordsys(el), - bqe(defaultcoordsys, - 1, coef[0], coef[1], coef[2], coef[3], coef[4])); - bqe.a = approximate(bqe.a); - return bqe; -} - -/*<asyxml><function type="bqe" signature="equation(parabola)"><code></asyxml>*/ -bqe equation(parabola p) -{/*<asyxml></code><documentation>Return the coefficients of the equation of the parabola in its coordinate system. - bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0 - One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.</documentation></function></asyxml>*/ - coordsys R = canonicalcartesiansystem(p); - parabola tp = changecoordsys(R, p); - point A = projection(tp.D) * point(R, (0, 0)); - real a = abs(A); - return changecoordsys(coordsys(p), - bqe(R, 0, 0, 1, -4 * a, 0, 0)); -} - -/*<asyxml><function type="bqe" signature="equation(hyperbola)"><code></asyxml>*/ -bqe equation(hyperbola h) -{/*<asyxml></code><documentation>Return the coefficients of the equation of the hyperbola in its coordinate system. - bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0 - One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.</documentation></function></asyxml>*/ - coordsys R = canonicalcartesiansystem(h); - return changecoordsys(coordsys(h), - bqe(R, 1/h.a^2, 0, -1/h.b^2, 0, 0, -1)); -} - -/*<asyxml><operator type = "path" signature="cast(ellipse)"><code></asyxml>*/ -path operator cast(ellipse el) -{/*<asyxml></code><documentation>Cast ellipse to path.</documentation></operator></asyxml>*/ - if(degenerate(el)) - abort("Casting degenerated ellipse to path is not possible."); - int n = el.e == 0 ? circlenodesnumber(el.a) : ellipsenodesnumber(el.a, el.b); - return arcfromcenter(el, 0.0, 360, CCW, n)&cycle; -} - -/*<asyxml><operator type = "path" signature="cast(circle)"><code></asyxml>*/ -path operator cast(circle c) -{/*<asyxml></code><documentation>Cast circle to path.</documentation></operator></asyxml>*/ - return (path)((ellipse)c); -} - -/*<asyxml><function type="real[]" signature="bangles(picture,parabola)"><code></asyxml>*/ -real[] bangles(picture pic = currentpicture, parabola p) -{/*<asyxml></code><documentation>Return the array {ma, Ma} where 'ma' and 'Ma' are respectively - the smaller and the larger angles for which the parabola 'p' is included - in the bounding box of the picture 'pic'.</documentation></function></asyxml>*/ - pair bmin, bmax; - pair[] b; - if (p.bmin == p.bmax) { - bmin = pic.userMin(); - bmax = pic.userMax(); - } else { - bmin = p.bmin;bmax = p.bmax; - } - if(bmin.x == bmax.x || bmin.y == bmax.y || !finite(abs(bmin)) || !finite(abs(bmax))) - return new real[] {0, 0}; - b[0] = bmin; - b[1] = (bmax.x, bmin.y); - b[2] = bmax; - b[3] = (bmin.x, bmax.y); - real[] eq = changecoordsys(defaultcoordsys, equation(p)).a; - pair[] inter; - for (int i = 0; i < 4; ++i) { - pair[] tmp = intersectionpoints(b[i], b[(i + 1)%4], eq); - for (int j = 0; j < tmp.length; ++j) { - if(dot(b[i]-tmp[j], b[(i + 1)%4]-tmp[j]) <= epsgeo) - inter.push(tmp[j]); - } - } - pair F = p.F, V = p.V; - real d = degrees(F - V); - real[] a = sequence(new real(int n){ - return (360 - d + degrees(inter[n]-F))%360; - }, inter.length); - real ma = a.length != 0 ? min(a) : 0, Ma= a.length != 0 ? max(a) : 0; - return new real[] {ma, Ma}; -} - -/*<asyxml><function type="real[][]" signature="bangles(picture,hyperbola)"><code></asyxml>*/ -real[][] bangles(picture pic = currentpicture, hyperbola h) -{/*<asyxml></code><documentation>Return the array {{ma1, Ma1}, {ma2, Ma2}} where 'maX' and 'MaX' are respectively - the smaller and the bigger angles (from h.FX) for which the hyperbola 'h' is included - in the bounding box of the picture 'pic'.</documentation></function></asyxml>*/ - pair bmin, bmax; - pair[] b; - if (h.bmin == h.bmax) { - bmin = pic.userMin(); - bmax = pic.userMax(); - } else { - bmin = h.bmin;bmax = h.bmax; - } - if(bmin.x == bmax.x || bmin.y == bmax.y || !finite(abs(bmin)) || !finite(abs(bmax))) - return new real[][] {{0, 0}, {0, 0}}; - b[0] = bmin; - b[1] = (bmax.x, bmin.y); - b[2] = bmax; - b[3] = (bmin.x, bmax.y); - real[] eq = changecoordsys(defaultcoordsys, equation(h)).a; - pair[] inter0, inter1; - pair C = locate(h.C); - pair F1 = h.F1; - for (int i = 0; i < 4; ++i) { - pair[] tmp = intersectionpoints(b[i], b[(i + 1)%4], eq); - for (int j = 0; j < tmp.length; ++j) { - if(dot(b[i]-tmp[j], b[(i + 1)%4]-tmp[j]) <= epsgeo) { - if(dot(F1 - C, tmp[j]-C) > 0) inter0.push(tmp[j]); - else inter1.push(tmp[j]); - } - } - } - real d = degrees(F1 - C); - real[] ma, Ma; - pair[][] inter = new pair[][] {inter0, inter1}; - for (int i = 0; i < 2; ++i) { - real[] a = sequence(new real(int n){ - return (360 - d + degrees(inter[i][n]-F1))%360; - }, inter[i].length); - ma[i] = a.length != 0 ? min(a) : 0; - Ma[i] = a.length != 0 ? max(a) : 0; - } - return new real[][] {{ma[0], Ma[0]}, {ma[1], Ma[1]}}; -} - -/*<asyxml><operator type = "path" signature="cast(parabola)"><code></asyxml>*/ -path operator cast(parabola p) -{/*<asyxml></code><documentation>Cast parabola to path. - If possible, the returned path is restricted to the actual bounding box - of the current picture if the variables 'p.bmin' and 'p.bmax' are not set else - the bounding box of box(p.bmin, p.bmax) is used instead.</documentation></operator></asyxml>*/ - real[] bangles = bangles(p); - int n = parabolanodesnumber(p, bangles[0], bangles[1]); - return arcfromfocus(p, bangles[0], bangles[1], n, CCW); -} - - -/*<asyxml><function type="void" signature="draw(picture,Label,circle,align,pen,arrowbar,arrowbar,margin,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label L = "", circle c, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, arrowbar bar = None, - margin margin = NoMargin, Label legend = "", marker marker = nomarker) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - if(degenerate(c)) draw(pic, L, c.l, align, p, arrow, legend, marker); - else draw(pic, L, (path)c, align, p, arrow, bar, margin, legend, marker); -} - -/*<asyxml><function type="void" signature="draw(picture,Label,ellipse,align,pen,arrowbar,arrowbar,margin,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label L = "", ellipse el, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, arrowbar bar = None, - margin margin = NoMargin, Label legend = "", marker marker = nomarker) -{/*<asyxml></code><documentation></documentation>Draw the ellipse 'el' if it is not degenerated else draw 'el.l'.</function></asyxml>*/ - if(degenerate(el)) draw(pic, L, el.l, align, p, arrow, legend, marker); - else draw(pic, L, (path)el, align, p, arrow, bar, margin, legend, marker); -} - -/*<asyxml><function type="void" signature="draw(picture,Label,parabola,align,pen,arrowbar,arrowbar,margin,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label L = "", parabola parabola, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, arrowbar bar = None, - margin margin = NoMargin, Label legend = "", marker marker = nomarker) -{/*<asyxml></code><documentation>Draw the parabola 'p' on 'pic' without (if possible) altering the - size of picture pic.</documentation></function></asyxml>*/ - pic.add(new void (frame f, transform t, transform T, pair m, pair M) { - // Reduce the bounds by the size of the pen and the margins. - m -= min(p); M -= max(p); - parabola.bmin = inverse(t) * m; - parabola.bmax = inverse(t) * M; - picture tmp; - path pp = t * ((path) (T * parabola)); - - if (pp != nullpath) { - draw(tmp, L, pp, align, p, arrow, bar, NoMargin, legend, marker); - add(f, tmp.fit()); - } - }, true); - - pair m = pic.userMin(), M = pic.userMax(); - if(m != M) { - pic.addBox(truepoint(SW), truepoint(NE)); - } -} - -/*<asyxml><operator type = "path" signature="cast(hyperbola)"><code></asyxml>*/ -path operator cast(hyperbola h) -{/*<asyxml></code><documentation>Cast hyperbola to path. - If possible, the returned path is restricted to the actual bounding box - of the current picture unless the variables 'h.bmin' and 'h.bmax' - are set; in this case the bounding box of box(h.bmin, h.bmax) is used instead. - Only the branch on the side of 'h.F1' is considered.</documentation></operator></asyxml>*/ - real[][] bangles = bangles(h); - int n = hyperbolanodesnumber(h, bangles[0][0], bangles[0][1]); - return arcfromfocus(h, bangles[0][0], bangles[0][1], n, CCW); -} - -/*<asyxml><function type="void" signature="draw(picture,Label,hyperbola,align,pen,arrowbar,arrowbar,margin,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label L = "", hyperbola h, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, arrowbar bar = None, - margin margin = NoMargin, Label legend = "", marker marker = nomarker) -{/*<asyxml></code><documentation>Draw the hyperbola 'h' on 'pic' without (if possible) altering the - size of the picture pic.</documentation></function></asyxml>*/ - pic.add(new void (frame f, transform t, transform T, pair m, pair M) { - // Reduce the bounds by the size of the pen and the margins. - m -= min(p); M -= max(p); - h.bmin = inverse(t) * m; - h.bmax = inverse(t) * M; - path hp; - - picture tmp; - hp = t * ((path) (T * h)); - if (hp != nullpath) { - draw(tmp, L, hp, align, p, arrow, bar, NoMargin, legend, marker); - } - - hyperbola ht = hyperbola(h.F2, h.F1, h.a); - ht.bmin = h.bmin; - ht.bmax = h.bmax; - - hp = t * ((path) (T * ht)); - if (hp != nullpath) { - draw(tmp, "", hp, align, p, arrow, bar, NoMargin, marker); - } - - add(f, tmp.fit()); - }, true); - - pair m = pic.userMin(), M = pic.userMax(); - if(m != M) - pic.addBox(truepoint(SW), truepoint(NE)); -} - -/*<asyxml><function type="void" signature="draw(picture,Label,explicit conic,align,pen,arrowbar,arrowbar,margin,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label L = "", explicit conic co, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, arrowbar bar = None, - margin margin = NoMargin, Label legend = "", marker marker = nomarker) -{/*<asyxml></code><documentation>Use one of the routine 'draw(ellipse, ...)', - 'draw(parabola, ...)' or 'draw(hyperbola, ...)' depending of the value of eccentricity of 'co'.</documentation></function></asyxml>*/ - if(co.e == 0) - draw(pic, L, (circle)co, align, p, arrow, bar, margin, legend, marker); - else - if(co.e < 1) draw(pic, L, (ellipse)co, align, p, arrow, bar, margin, legend, marker); - else - if(co.e == 1) draw(pic, L, (parabola)co, align, p, arrow, bar, margin, legend, marker); - else - if(co.e > 1) draw(pic, L, (hyperbola)co, align, p, arrow, bar, margin, legend, marker); - else abort("draw: unknown conic."); -} - -/*<asyxml><function type="int" signature="conicnodesnumber(conic,real,real)"><code></asyxml>*/ -int conicnodesnumber(conic co, real angle1, real angle2, bool dir = CCW) -{/*<asyxml></code><documentation>Return the number of node to draw a conic arc.</documentation></function></asyxml>*/ - int oi; - if(co.e == 0) { - circle c = (circle)co; - oi = circlenodesnumber(c.r, angle1, angle2); - } else if(co.e < 1) { - ellipse el = (ellipse)co; - oi = ellipsenodesnumber(el.a, el.b, angle1, angle2, dir); - } else if(co.e == 1) { - parabola p = (parabola)co; - oi = parabolanodesnumber(p, angle1, angle2); - } else { - hyperbola h = (hyperbola)co; - oi = hyperbolanodesnumber(h, angle1, angle2); - } - return oi; -} - -/*<asyxml><operator type = "path" signature="cast(conic)"><code></asyxml>*/ -path operator cast(conic co) -{/*<asyxml></code><documentation>Cast conic section to path.</documentation></operator></asyxml>*/ - if(co.e < 1) return (path)((ellipse)co); - if(co.e == 1) return (path)((parabola)co); - return (path)((hyperbola)co); -} - -/*<asyxml><function type="bqe" signature="equation(explicit conic)"><code></asyxml>*/ -bqe equation(explicit conic co) -{/*<asyxml></code><documentation>Return the coefficients of the equation of conic section in its coordinate system: - bqe.a[0] * x^2 + bqe.a[1] * x * y + bqe.a[2] * y^2 + bqe.a[3] * x + bqe.a[4] * y + bqe.a[5] = 0. - One can change the coordinate system of 'bqe' using the routine 'changecoordsys'.</documentation></function></asyxml>*/ - bqe obqe; - if(co.e == 0) - obqe = equation((circle)co); - else - if(co.e < 1) obqe = equation((ellipse)co); - else - if(co.e == 1) obqe = equation((parabola)co); - else - if(co.e > 1) obqe = equation((hyperbola)co); - else abort("draw: unknown conic."); - return obqe; -} - -/*<asyxml><function type="string" signature="conictype(bqe)"><code></asyxml>*/ -string conictype(bqe bqe) -{/*<asyxml></code><documentation>Returned values are "ellipse" or "parabola" or "hyperbola" - depending of the conic section represented by 'bqe'.</documentation></function></asyxml>*/ - bqe lbqe = changecoordsys(defaultcoordsys, bqe); - string os = "degenerated"; - real a = lbqe.a[0], b = lbqe.a[1]/2, c = lbqe.a[2], d = lbqe.a[3]/2, f = lbqe.a[4]/2, g = lbqe.a[5]; - real delta = a * c * g + b * f * d + d * b * f - (b^2 * g + d^2 * c + f^2 * a); - if(abs(delta) < 10 * epsgeo) return os; - real J = a * c - b^2; - real I = a + c; - if(J > epsgeo) { - if(delta/I < -epsgeo); - os = "ellipse"; - } else { - if(abs(J) < epsgeo) os = "parabola"; else os = "hyperbola"; - } - return os; -} - -/*<asyxml><function type="conic" signature="conic(point,point,point,point,point)"><code></asyxml>*/ -conic conic(point M1, point M2, point M3, point M4, point M5) -{/*<asyxml></code><documentation>Return the conic passing through 'M1', 'M2', 'M3', 'M4' and 'M5' if the conic is not degenerated.</documentation></function></asyxml>*/ - bqe bqe = bqe(M1, M2, M3, M4, M5); - string ct = conictype(bqe); - if(ct == "degenerated") abort("conic: degenerated conic passing through five points."); - if(ct == "ellipse") return ellipse(bqe); - if(ct == "parabola") return parabola(bqe); - return hyperbola(bqe); -} - -/*<asyxml><function type="coordsys" signature="canonicalcartesiansystem(hyperbola)"><code></asyxml>*/ -coordsys canonicalcartesiansystem(explicit conic co) -{/*<asyxml></code><documentation>Return the canonical cartesian system of the conic 'co'.</documentation></function></asyxml>*/ - if(co.e < 1) return canonicalcartesiansystem((ellipse)co); - else if(co.e == 1) return canonicalcartesiansystem((parabola)co); - return canonicalcartesiansystem((hyperbola)co); -} - -/*<asyxml><function type="bqe" signature="canonical(bqe)"><code></asyxml>*/ -bqe canonical(bqe bqe) -{/*<asyxml></code><documentation>Return the bivariate quadratic equation relative to the - canonical coordinate system of the conic section represented by 'bqe'.</documentation></function></asyxml>*/ - string type = conictype(bqe); - if(type == "") abort("canonical: the equation can not be performed."); - bqe obqe; - if(type == "ellipse") { - ellipse el = ellipse(bqe); - obqe = changecoordsys(canonicalcartesiansystem(el), equation(el)); - } else { - if(type == "parabola") { - parabola p = parabola(bqe); - obqe = changecoordsys(canonicalcartesiansystem(p), equation(p)); - } else { - hyperbola h = hyperbola(bqe); - obqe = changecoordsys(canonicalcartesiansystem(h), equation(h)); - } - } - return obqe; -} - -/*<asyxml><function type="conic" signature="conic(bqe)"><code></asyxml>*/ -conic conic(bqe bqe) -{/*<asyxml></code><documentation>Return the conic section represented by the bivariate quartic equation 'bqe'.</documentation></function></asyxml>*/ - string type = conictype(bqe); - if(type == "") abort("canonical: the equation can not be performed."); - conic oc; - if(type == "ellipse") { - oc = ellipse(bqe); - } else { - if(type == "parabola") oc = parabola(bqe); else oc = hyperbola(bqe); - } - return oc; -} - -/*<asyxml><function type="real" signature="arclength(circle)"><code></asyxml>*/ -real arclength(circle c) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return c.r * 2 * pi; -} - -/*<asyxml><function type="real" signature="focusToCenter(ellipse,real)"><code></asyxml>*/ -real focusToCenter(ellipse el, real a) -{/*<asyxml></code><documentation>Return the angle relatively to the center of 'el' for the angle 'a' - given relatively to the focus of 'el'.</documentation></function></asyxml>*/ - pair p = point(fromFocus(el, a, a, 1, CCW), 0); - pair c = locate(el.C); - real d = degrees(p - c) - el.angle; - d = abs(d) < epsgeo ? 0 : d; // Avoid -1e-15 - return d%(sgnd(a) * 360); -} - -/*<asyxml><function type="real" signature="centerToFocus(ellipse,real)"><code></asyxml>*/ -real centerToFocus(ellipse el, real a) -{/*<asyxml></code><documentation>Return the angle relatively to the focus of 'el' for the angle 'a' - given relatively to the center of 'el'.</documentation></function></asyxml>*/ - pair P = point(fromCenter(el, a, a, 1, CCW), 0); - pair F1 = locate(el.F1); - pair F2 = locate(el.F2); - real d = degrees(P - F1) - degrees(F2 - F1); - d = abs(d) < epsgeo ? 0 : d; // Avoid -1e-15 - return d%(sgnd(a) * 360); -} - -/*<asyxml><function type="real" signature="arclength(ellipse)"><code></asyxml>*/ -real arclength(ellipse el) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return degenerate(el) ? infinity : 4 * el.a * elle(pi/2, el.e); -} - -/*<asyxml><function type="real" signature="arclength(ellipse,real,real,bool,polarconicroutine)"><code></asyxml>*/ -real arclength(ellipse el, real angle1, real angle2, - bool direction = CCW, - polarconicroutine polarconicroutine = currentpolarconicroutine) -{/*<asyxml></code><documentation>Return the length of the arc of the ellipse between 'angle1' - and 'angle2'. - 'angle1' and 'angle2' must be in the interval ]-360;+oo[ if polarconicroutine = fromFocus, - ]-oo;+oo[ if polarconicroutine = fromCenter.</documentation></function></asyxml>*/ - if(degenerate(el)) return infinity; - if(angle1 > angle2) return arclength(el, angle2, angle1, !direction, polarconicroutine); - // path g;int n = 1000; - // if(el.e == 0) g = arcfromcenter(el, angle1, angle2, n, direction); - // if(el.e != 1) g = polarconicroutine(el, angle1, angle2, n, direction); - // write("with path = ", arclength(g)); - if(polarconicroutine == fromFocus) { - // dot(point(fromFocus(el, angle1, angle1, 1, CCW), 0), 2mm + blue); - // dot(point(fromFocus(el, angle2, angle2, 1, CCW), 0), 2mm + blue); - // write("fromfocus1 = ", angle1); - // write("fromfocus2 = ", angle2); - real gle1 = focusToCenter(el, angle1); - real gle2 = focusToCenter(el, angle2); - if((gle1 - gle2) * (angle1 - angle2) > 0) { - angle1 = gle1; angle2 = gle2; - } else { - angle1 = gle2; angle2 = gle1; - } - // dot(point(fromCenter(el, angle1, angle1, 1, CCW), 0), 1mm + red); - // dot(point(fromCenter(el, angle2, angle2, 1, CCW), 0), 1mm + red); - // write("fromcenter1 = ", angle1); - // write("fromcenter2 = ", angle2); - } - if(angle1 < 0 || angle2 < 0) return arclength(el, 180 + angle1, 180 + angle2, direction, fromCenter); - real a1 = direction ? angle1 : angle2; - real a2 = direction ? angle2 : angle1 + 360; - real elleq = el.a * elle(pi/2, el.e); - real S(real a) - {//Return the arclength from 0 to the angle 'a' (in degrees) - // given form the center of the ellipse. - real gle = atan(el.a * Tan(a)/el.b)+ - pi * (((a%90 == 0 && a != 0) ? floor(a/90) - 1 : floor(a/90)) - - ((a%180 == 0) ? 0 : floor(a/180)) - - (a%360 == 0 ? floor(a/(360)) : 0)); - /* // Uncomment to visualize the used branches - unitsize(2cm, 1cm); - import graph; - - real xmin = 0, xmax = 3pi; - - xlimits( xmin, xmax); - ylimits( 0, 10); - yaxis( "y" , LeftRight(), RightTicks(pTick=.8red, ptick = lightgrey, extend = true)); - xaxis( "x - value", BottomTop(), Ticks(Label("$%.2f$", red), Step = pi/2, step = pi/4, pTick=.8red, ptick = lightgrey, extend = true)); - - real p2 = pi/2; - real f(real t) - { - return atan(0.6 * tan(t))+ - pi * ((t%p2 == 0 && t != 0) ? floor(t/p2) - 1 : floor(t/p2)) - - ((t%pi == 0) ? 0 : pi * floor(t/pi)) - (t%(2pi) == 0 ? pi * floor(t/(2 * pi)) : 0); - } - - draw(graph(f, xmin, xmax, 100)); - write(degrees(f(pi/2))); - write(degrees(f(pi))); - write(degrees(f(3pi/2))); - write(degrees(f(2pi))); - draw(graph(new real(real t){return t;}, xmin, xmax, 3)); - */ - return elleq - el.a * elle(pi/2 - gle, el.e); - } - return S(a2) - S(a1); -} - -/*<asyxml><function type="real" signature="arclength(parabola,real)"><code></asyxml>*/ -real arclength(parabola p, real angle) -{/*<asyxml></code><documentation>Return the arclength from 180 to 'angle' given from focus in the - canonical coordinate system of 'p'.</documentation></function></asyxml>*/ - real a = p.a; /* In canonicalcartesiansystem(p) the equation of p - is x = y^2/(4a) */ - // integrate(sqrt(1 + (x/(2 * a))^2), x); - real S(real t){return 0.5 * t * sqrt(1 + t^2/(4 * a^2)) + a * asinh(t/(2 * a));} - real R(real gle){return 2 * a/(1 - Cos(gle));} - real t = Sin(angle) * R(angle); - return S(t); -} - -/*<asyxml><function type="real" signature="arclength(parabola,real,real)"><code></asyxml>*/ -real arclength(parabola p, real angle1, real angle2) -{/*<asyxml></code><documentation>Return the arclength from 'angle1' to 'angle2' given from - focus in the canonical coordinate system of 'p'</documentation></function></asyxml>*/ - return arclength(p, angle1) - arclength(p, angle2); -} - -/*<asyxml><function type="real" signature="arclength(parabola p)"><code></asyxml>*/ -real arclength(parabola p) -{/*<asyxml></code><documentation>Return the length of the arc of the parabola bounded to the bounding - box of the current picture.</documentation></function></asyxml>*/ - real[] b = bangles(p); - return arclength(p, b[0], b[1]); -} -// *........................CONICS.........................* -// *=======================================================* - -// *=======================================================* -// *.......................ABSCISSA........................* -/*<asyxml><struct signature="abscissa"><code></asyxml>*/ -struct abscissa -{/*<asyxml></code><documentation>Provide abscissa structure on a curve used in the routine-like 'point(object, abscissa)' - where object can be 'line','segment','ellipse','circle','conic'...</documentation><property type = "real" signature="x"><code></asyxml>*/ - real x;/*<asyxml></code><documentation>The abscissa value.</documentation></property><property type = "int" signature="system"><code></asyxml>*/ - int system;/*<asyxml></code><documentation>0 = relativesystem; 1 = curvilinearsystem; 2 = angularsystem; 3 = nodesystem</documentation></property><property type = "polarconicroutine" signature="polarconicroutine"><code></asyxml>*/ - polarconicroutine polarconicroutine = fromCenter;/*<asyxml></code><documentation>The routine used with angular system and two foci conic section. - Possible values are 'formCenter' and 'formFocus'.</documentation></property></asyxml>*/ - /*<asyxml><method type = "abscissa" signature="copy()"><code></asyxml>*/ - abscissa copy() - {/*<asyxml></code><documentation>Return a copy of this abscissa.</documentation></method></asyxml>*/ - abscissa oa = new abscissa; - oa.x = this.x; - oa.system = this.system; - oa.polarconicroutine = this.polarconicroutine; - return oa; - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><constant type = "int" signature="relativesystem,curvilinearsystem,angularsystem,nodesystem"><code></asyxml>*/ -restricted int relativesystem = 0, curvilinearsystem = 1, angularsystem = 2, nodesystem = 3;/*<asyxml></code><documentation>Constant used to set the abscissa system.</documentation></constant></asyxml>*/ - -/*<asyxml><operator type = "abscissa" signature="cast(explicit position)"><code></asyxml>*/ -abscissa operator cast(explicit position position) -{/*<asyxml></code><documentation>Cast position to abscissa. - If 'position' is relative, the abscissa is relative else it's a curvilinear abscissa.</documentation></operator></asyxml>*/ - abscissa oarcc; - oarcc.x = position.position.x; - oarcc.system = position.relative ? relativesystem : curvilinearsystem; - return oarcc; -} - -/*<asyxml><operator type = "abscissa" signature="+(real,explicit abscissa)"><code></asyxml>*/ -abscissa operator +(real x, explicit abscissa a) -{/*<asyxml></code><documentation>Provide 'real + abscissa'. - Return abscissa b so that b.x = a.x + x. - +(explicit abscissa, real), -(real, explicit abscissa) and -(explicit abscissa, real) are also defined.</documentation></operator></asyxml>*/ - abscissa oa = a.copy(); - oa.x = a.x + x; - return oa; -} - -abscissa operator +(explicit abscissa a, real x) -{ - return x + a; -} -abscissa operator +(int x, explicit abscissa a) -{ - return ((real)x) + a; -} - -/*<asyxml><operator type = "abscissa" signature="-(explicit abscissa a)"><code></asyxml>*/ -abscissa operator -(explicit abscissa a) -{/*<asyxml></code><documentation>Return the abscissa b so that b.x = -a.x.</documentation></operator></asyxml>*/ - abscissa oa; - oa.system = a.system; - oa.x = -a.x; - return oa; -} - -abscissa operator -(real x, explicit abscissa a) -{ - abscissa oa; - oa.system = a.system; - oa.x = x - a.x; - return oa; -} -abscissa operator -(explicit abscissa a, real x) -{ - abscissa oa; - oa.system = a.system; - oa.x = a.x - x; - return oa; -} -abscissa operator -(int x, explicit abscissa a) -{ - return ((real)x) - a; -} - -/*<asyxml><operator type = "abscissa" signature="*(real,abscissa)"><code></asyxml>*/ -abscissa operator *(real x, explicit abscissa a) -{/*<asyxml></code><documentation>Provide 'real * abscissa'. - Return abscissa b so that b.x = x * a.x. - *(explicit abscissa, real), /(real, explicit abscissa) and /(explicit abscissa, real) are also defined.</documentation></operator></asyxml>*/ - abscissa oa; - oa.system = a.system; - oa.x = a.x * x; - return oa; -} -abscissa operator *(explicit abscissa a, real x) -{ - return x * a; -} - -abscissa operator /(real x, explicit abscissa a) -{ - abscissa oa; - oa.system = a.system; - oa.x = x/a.x; - return oa; -} -abscissa operator /(explicit abscissa a, real x) -{ - abscissa oa; - oa.system = a.system; - oa.x = a.x/x; - return oa; -} - -abscissa operator /(int x, explicit abscissa a) -{ - return ((real)x)/a; -} - -/*<asyxml><function type="abscissa" signature="relabscissa(real)"><code></asyxml>*/ -abscissa relabscissa(real x) -{/*<asyxml></code><documentation>Return a relative abscissa.</documentation></function></asyxml>*/ - return (abscissa)(Relative(x)); -} -abscissa relabscissa(int x) -{ - return (abscissa)(Relative(x)); -} - -/*<asyxml><function type="abscissa" signature="curabscissa(real)"><code></asyxml>*/ -abscissa curabscissa(real x) -{/*<asyxml></code><documentation>Return a curvilinear abscissa.</documentation></function></asyxml>*/ - return (abscissa)((position)x); -} -abscissa curabscissa(int x) -{ - return (abscissa)((position)x); -} - -/*<asyxml><function type="abscissa" signature="angabscissa(real,polarconicroutine)"><code></asyxml>*/ -abscissa angabscissa(real x, polarconicroutine polarconicroutine = currentpolarconicroutine) -{/*<asyxml></code><documentation>Return a angular abscissa.</documentation></function></asyxml>*/ - abscissa oarcc; - oarcc.x = x; - oarcc.polarconicroutine = polarconicroutine; - oarcc.system = angularsystem; - return oarcc; -} -abscissa angabscissa(int x, polarconicroutine polarconicroutine = currentpolarconicroutine) -{ - return angabscissa((real)x, polarconicroutine); -} - -/*<asyxml><function type="abscissa" signature="nodabscissa(real)"><code></asyxml>*/ -abscissa nodabscissa(real x) -{/*<asyxml></code><documentation>Return an abscissa as time on the path.</documentation></function></asyxml>*/ - abscissa oarcc; - oarcc.x = x; - oarcc.system = nodesystem; - return oarcc; -} -abscissa nodabscissa(int x) -{ - return nodabscissa((real)x); -} - -/*<asyxml><operator type = "abscissa" signature="cast(real)"><code></asyxml>*/ -abscissa operator cast(real x) -{/*<asyxml></code><documentation>Cast real to abscissa, precisely 'nodabscissa'.</documentation></operator></asyxml>*/ - return nodabscissa(x); -} -abscissa operator cast(int x) -{ - return nodabscissa((real)x); -} - -/*<asyxml><function type="point" signature="point(circle,abscissa)"><code></asyxml>*/ -point point(circle c, abscissa l) -{/*<asyxml></code><documentation>Return the point of 'c' which has the abscissa 'l.x' - according to the abscissa system 'l.system'.</documentation></function></asyxml>*/ - coordsys R = c.C.coordsys; - if (l.system == nodesystem) - return point(R, point((path)c, l.x)/R); - if (l.system == relativesystem) - return c.C + point(R, R.polar(c.r, 2 * pi * l.x)); - if (l.system == curvilinearsystem) - return c.C + point(R, R.polar(c.r, l.x/c.r)); - if (l.system == angularsystem) - return c.C + point(R, R.polar(c.r, radians(l.x))); - abort("point: bad abscissa system."); - return (0, 0); -} - -/*<asyxml><function type="point" signature="point(ellipse,abscissa)"><code></asyxml>*/ -point point(ellipse el, abscissa l) -{/*<asyxml></code><documentation>Return the point of 'el' which has the abscissa 'l.x' - according to the abscissa system 'l.system'.</documentation></function></asyxml>*/ - if(el.e == 0) return point((circle)el, l); - coordsys R = coordsys(el); - if (l.system == nodesystem) - return point(R, point((path)el, l.x)/R); - if (l.system == relativesystem) { - return point(el, curabscissa((l.x%1) * arclength(el))); - } - if (l.system == curvilinearsystem) { - real a1 = 0, a2 = 360, cx = 0; - real aout = a1; - real x = abs(l.x)%arclength(el); - while (abs(cx - x) > epsgeo) { - aout = (a1 + a2)/2; - cx = arclength(el, 0, aout, CCW, fromCenter); //fromCenter is speeder - if(cx > x) a2 = (a1 + a2)/2; else a1 = (a1 + a2)/2; - } - path pel = fromCenter(el, sgn(l.x) * aout, sgn(l.x) * aout, 1, CCW); - return point(R, point(pel, 0)/R); - } - if (l.system == angularsystem) { - return point(R, point(l.polarconicroutine(el, l.x, l.x, 1, CCW), 0)/R); - } - abort("point: bad abscissa system."); - return (0, 0); -} - -/*<asyxml><function type="point" signature="point(parabola,abscissa)"><code></asyxml>*/ -point point(parabola p, abscissa l) -{/*<asyxml></code><documentation>Return the point of 'p' which has the abscissa 'l.x' - according to the abscissa system 'l.system'.</documentation></function></asyxml>*/ - coordsys R = coordsys(p); - if (l.system == nodesystem) - return point(R, point((path)p, l.x)/R); - if (l.system == relativesystem) { - real[] b = bangles(p); - real al = sgn(l.x) > 0 ? arclength(p, 180, b[1]) : arclength(p, 180, b[0]); - return point(p, curabscissa(abs(l.x) * al)); - } - if (l.system == curvilinearsystem) { - real a1 = 1e-3, a2 = 360 - 1e-3, cx = infinity; - while (abs(cx - l.x) > epsgeo) { - cx = arclength(p, 180, (a1 + a2)/2); - if(cx > l.x) a2 = (a1 + a2)/2; else a1 = (a1 + a2)/2; - } - path pp = fromFocus(p, a1, a1, 1, CCW); - return point(R, point(pp, 0)/R); - } - if (l.system == angularsystem) { - return point(R, point(fromFocus(p, l.x, l.x, 1, CCW), 0)/R); - } - abort("point: bad abscissa system."); - return (0, 0); -} - -/*<asyxml><function type="point" signature="point(hyperbola,abscissa)"><code></asyxml>*/ -point point(hyperbola h, abscissa l) -{/*<asyxml></code><documentation>Return the point of 'h' which has the abscissa 'l.x' - according to the abscissa system 'l.system'.</documentation></function></asyxml>*/ - coordsys R = coordsys(h); - if (l.system == nodesystem) - return point(R, point((path)h, l.x)/R); - if (l.system == relativesystem) { - abort("point(hyperbola, relativeSystem) is not implemented... -Try relpoint((path)your_hyperbola, x);"); - } - if (l.system == curvilinearsystem) { - abort("point(hyperbola, curvilinearSystem) is not implemented..."); - } - if (l.system == angularsystem) { - return point(R, point(l.polarconicroutine(h, l.x, l.x, 1, CCW), 0)/R); - } - abort("point: bad abscissa system."); - return (0, 0); -} - -/*<asyxml><function type="abscissa" signature="point(conic,point)"><code></asyxml>*/ -point point(explicit conic co, abscissa l) -{/*<asyxml></code><documentation>Return the curvilinear abscissa of 'M' on the conic 'co'.</documentation></function></asyxml>*/ - if(co.e == 0) return point((circle)co, l); - if(co.e < 1) return point((ellipse)co, l); - if(co.e == 1) return point((parabola)co, l); - return point((hyperbola)co, l); -} - - -/*<asyxml><function type="point" signature="point(line,abscissa)"><code></asyxml>*/ -point point(line l, abscissa x) -{/*<asyxml></code><documentation>Return the point of 'l' which has the abscissa 'l.x' according to the abscissa system 'l.system'. - Note that the origin is l.A, and point(l, relabscissa(x)) returns l.A + x.x * vector(l.B - l.A).</documentation></function></asyxml>*/ - coordsys R = l.A.coordsys; - if (x.system == nodesystem) - return l.A + (x.x < 0 ? 0 : x.x > 1 ? 1 : x.x) * vector(l.B - l.A); - if (x.system == relativesystem) - return l.A + x.x * vector(l.B - l.A); - if (x.system == curvilinearsystem) - return l.A + x.x * l.u; - if (x.system == angularsystem) - abort("point: what the meaning of angular abscissa on line ?."); - abort("point: bad abscissa system."); - return (0, 0); -} - -/*<asyxml><function type="point" signature="point(line,real)"><code></asyxml>*/ -point point(line l, explicit real x) -{/*<asyxml></code><documentation>Return the point between node l.A and l.B (x <= 0 means l.A, x >=1 means l.B).</documentation></function></asyxml>*/ - return point(l, nodabscissa(x)); -} -point point(line l, explicit int x) -{ - return point(l, nodabscissa(x)); -} - -/*<asyxml><function type="circle" signature="point(explicit circle,explicit real)"><code></asyxml>*/ -point point(explicit circle c, explicit real x) -{/*<asyxml></code><documentation>Return the point between node floor(x) and floor(x) + 1.</documentation></function></asyxml>*/ - return point(c, nodabscissa(x)); -} -point point(explicit circle c, explicit int x) -{ - return point(c, nodabscissa(x)); -} - -/*<asyxml><function type="point" signature="point(explicit ellipse,explicit real)"><code></asyxml>*/ -point point(explicit ellipse el, explicit real x) -{/*<asyxml></code><documentation>Return the point between node floor(x) and floor(x) + 1.</documentation></function></asyxml>*/ - return point(el, nodabscissa(x)); -} -point point(explicit ellipse el, explicit int x) -{ - return point(el, nodabscissa(x)); -} - -/*<asyxml><function type="point" signature="point(explicit parabola,explicit real)"><code></asyxml>*/ -point point(explicit parabola p, explicit real x) -{/*<asyxml></code><documentation>Return the point between node floor(x) and floor(x) + 1.</documentation></function></asyxml>*/ - return point(p, nodabscissa(x)); -} -point point(explicit parabola p, explicit int x) -{ - return point(p, nodabscissa(x)); -} - -/*<asyxml><function type="point" signature="point(explicit hyperbola,explicit real)"><code></asyxml>*/ -point point(explicit hyperbola h, explicit real x) -{/*<asyxml></code><documentation>Return the point between node floor(x) and floor(x) + 1.</documentation></function></asyxml>*/ - return point(h, nodabscissa(x)); -} -point point(explicit hyperbola h, explicit int x) -{ - return point(h, nodabscissa(x)); -} - -/*<asyxml><function type="point" signature="point(explicit conic,explicit real)"><code></asyxml>*/ -point point(explicit conic co, explicit real x) -{/*<asyxml></code><documentation>Return the point between node floor(x) and floor(x) + 1.</documentation></function></asyxml>*/ - point op; - if(co.e == 0) op = point((circle)co, nodabscissa(x)); - else if(co.e < 1) op = point((ellipse)co, nodabscissa(x)); - else if(co.e == 1) op = point((parabola)co, nodabscissa(x)); - else op = point((hyperbola)co, nodabscissa(x)); - return op; -} -point point(explicit conic co, explicit int x) -{ - return point(co, (real)x); -} - -/*<asyxml><function type="point" signature="relpoint(line,real)"><code></asyxml>*/ -point relpoint(line l, real x) -{/*<asyxml></code><documentation>Return the relative point of 'l' (0 means l.A, - 1 means l.B, x means l.A + x * vector(l.B - l.A) ).</documentation></function></asyxml>*/ - return point(l, Relative(x)); -} - -/*<asyxml><function type="point" signature="relpoint(explicit circle,real)"><code></asyxml>*/ -point relpoint(explicit circle c, real x) -{/*<asyxml></code><documentation>Return the relative point of 'c' (0 means origin, 1 means end). - Origin is c.center + c.r * (1, 0).</documentation></function></asyxml>*/ - return point(c, Relative(x)); -} - -/*<asyxml><function type="point" signature="relpoint(explicit ellipse,real)"><code></asyxml>*/ -point relpoint(explicit ellipse el, real x) -{/*<asyxml></code><documentation>Return the relative point of 'el' (0 means origin, 1 means end).</documentation></function></asyxml>*/ - return point(el, Relative(x)); -} - -/*<asyxml><function type="point" signature="relpoint(explicit parabola,real)"><code></asyxml>*/ -point relpoint(explicit parabola p, real x) -{/*<asyxml></code><documentation>Return the relative point of the path of the parabola - bounded by the bounding box of the current picture. - 0 means origin, 1 means end, where the origin is the vertex of 'p'.</documentation></function></asyxml>*/ - return point(p, Relative(x)); -} - -/*<asyxml><function type="point" signature="relpoint(explicit hyperbola,real)"><code></asyxml>*/ -point relpoint(explicit hyperbola h, real x) -{/*<asyxml></code><documentation>Not yet implemented... <look href = "point(hyperbola, abscissa)"/></documentation></function></asyxml>*/ - return point(h, Relative(x)); -} - -/*<asyxml><function type="point" signature="relpoint(explicit conic,explicit real)"><code></asyxml>*/ -point relpoint(explicit conic co, explicit real x) -{/*<asyxml></code><documentation>Return the relative point of 'co' (0 means origin, 1 means end).</documentation></function></asyxml>*/ - point op; - if(co.e == 0) op = point((circle)co, Relative(x)); - else if(co.e < 1) op = point((ellipse)co, Relative(x)); - else if(co.e == 1) op = point((parabola)co, Relative(x)); - else op = point((hyperbola)co, Relative(x)); - return op; -} -point relpoint(explicit conic co, explicit int x) -{ - return relpoint(co, (real)x); -} - -/*<asyxml><function type="point" signature="angpoint(explicit circle,real)"><code></asyxml>*/ -point angpoint(explicit circle c, real x) -{/*<asyxml></code><documentation>Return the point of 'c' in the direction 'x' measured in degrees.</documentation></function></asyxml>*/ - return point(c, angabscissa(x)); -} - -/*<asyxml><function type="point" signature="angpoint(explicit ellipse,real,polarconicroutine)"><code></asyxml>*/ -point angpoint(explicit ellipse el, real x, - polarconicroutine polarconicroutine = currentpolarconicroutine) -{/*<asyxml></code><documentation>Return the point of 'el' in the direction 'x' - measured in degrees according to 'polarconicroutine'.</documentation></function></asyxml>*/ - return el.e == 0 ? angpoint((circle) el, x) : point(el, angabscissa(x, polarconicroutine)); -} - -/*<asyxml><function type="point" signature="angpoint(explicit parabola,real)"><code></asyxml>*/ -point angpoint(explicit parabola p, real x) -{/*<asyxml></code><documentation>Return the point of 'p' in the direction 'x' measured in degrees.</documentation></function></asyxml>*/ - return point(p, angabscissa(x)); -} - -/*<asyxml><function type="point" signature="angpoint(explicit hyperbola,real,polarconicroutine)"><code></asyxml>*/ -point angpoint(explicit hyperbola h, real x, - polarconicroutine polarconicroutine = currentpolarconicroutine) -{/*<asyxml></code><documentation>Return the point of 'h' in the direction 'x' - measured in degrees according to 'polarconicroutine'.</documentation></function></asyxml>*/ - return point(h, angabscissa(x, polarconicroutine)); -} - -/*<asyxml><function type="point" signature="curpoint(line,real)"><code></asyxml>*/ -point curpoint(line l, real x) -{/*<asyxml></code><documentation>Return the point of 'l' which has the curvilinear abscissa 'x'. - Origin is l.A.</documentation></function></asyxml>*/ - return point(l, curabscissa(x)); -} - -/*<asyxml><function type="point" signature="curpoint(explicit circle,real)"><code></asyxml>*/ -point curpoint(explicit circle c, real x) -{/*<asyxml></code><documentation>Return the point of 'c' which has the curvilinear abscissa 'x'. - Origin is c.center + c.r * (1, 0).</documentation></function></asyxml>*/ - return point(c, curabscissa(x)); -} - -/*<asyxml><function type="point" signature="curpoint(explicit ellipse,real)"><code></asyxml>*/ -point curpoint(explicit ellipse el, real x) -{/*<asyxml></code><documentation>Return the point of 'el' which has the curvilinear abscissa 'el'.</documentation></function></asyxml>*/ - return point(el, curabscissa(x)); -} - -/*<asyxml><function type="point" signature="curpoint(explicit parabola,real)"><code></asyxml>*/ -point curpoint(explicit parabola p, real x) -{/*<asyxml></code><documentation>Return the point of 'p' which has the curvilinear abscissa 'x'. - Origin is the vertex of 'p'.</documentation></function></asyxml>*/ - return point(p, curabscissa(x)); -} - -/*<asyxml><function type="point" signature="curpoint(conic,real)"><code></asyxml>*/ -point curpoint(conic co, real x) -{/*<asyxml></code><documentation>Return the point of 'co' which has the curvilinear abscissa 'x'.</documentation></function></asyxml>*/ - point op; - if(co.e == 0) op = point((circle)co, curabscissa(x)); - else if(co.e < 1) op = point((ellipse)co, curabscissa(x)); - else if(co.e == 1) op = point((parabola)co, curabscissa(x)); - else op = point((hyperbola)co, curabscissa(x)); - return op; -} - -/*<asyxml><function type="abscissa" signature="angabscissa(circle,point)"><code></asyxml>*/ -abscissa angabscissa(circle c, point M) -{/*<asyxml></code><documentation>Return the angular abscissa of 'M' on the circle 'c'.</documentation></function></asyxml>*/ - if(!(M @ c)) abort("angabscissa: the point is not on the circle."); - abscissa oa; - oa.system = angularsystem; - oa.x = degrees(M - c.C); - if(oa.x < 0) oa.x+=360; - return oa; -} - -/*<asyxml><function type="abscissa" signature="angabscissa(ellipse,point,polarconicroutine)"><code></asyxml>*/ -abscissa angabscissa(ellipse el, point M, - polarconicroutine polarconicroutine = currentpolarconicroutine) -{/*<asyxml></code><documentation>Return the angular abscissa of 'M' on the ellipse 'el' according to 'polarconicroutine'.</documentation></function></asyxml>*/ - if(!(M @ el)) abort("angabscissa: the point is not on the ellipse."); - abscissa oa; - oa.system = angularsystem; - oa.polarconicroutine = polarconicroutine; - oa.x = polarconicroutine == fromCenter ? degrees(M - el.C) : degrees(M - el.F1); - oa.x -= el.angle; - if(oa.x < 0) oa.x += 360; - return oa; -} - -/*<asyxml><function type="abscissa" signature="angabscissa(hyperbola,point,polarconicroutine)"><code></asyxml>*/ -abscissa angabscissa(hyperbola h, point M, - polarconicroutine polarconicroutine = currentpolarconicroutine) -{/*<asyxml></code><documentation>Return the angular abscissa of 'M' on the hyperbola 'h' according to 'polarconicroutine'.</documentation></function></asyxml>*/ - if(!(M @ h)) abort("angabscissa: the point is not on the hyperbola."); - abscissa oa; - oa.system = angularsystem; - oa.polarconicroutine = polarconicroutine; - oa.x = polarconicroutine == fromCenter ? degrees(M - h.C) : degrees(M - h.F1) + 180; - oa.x -= h.angle; - if(oa.x < 0) oa.x += 360; - return oa; -} - -/*<asyxml><function type="abscissa" signature="angabscissa(parabola,point)"><code></asyxml>*/ -abscissa angabscissa(parabola p, point M) -{/*<asyxml></code><documentation>Return the angular abscissa of 'M' on the parabola 'p'.</documentation></function></asyxml>*/ - if(!(M @ p)) abort("angabscissa: the point is not on the parabola."); - abscissa oa; - oa.system = angularsystem; - oa.polarconicroutine = fromFocus;// Not used - oa.x = degrees(M - p.F); - oa.x -= p.angle; - if(oa.x < 0) oa.x += 360; - return oa; -} - -/*<asyxml><function type="abscissa" signature="angabscissa(conic,point)"><code></asyxml>*/ -abscissa angabscissa(explicit conic co, point M) -{/*<asyxml></code><documentation>Return the angular abscissa of 'M' on the conic 'co'.</documentation></function></asyxml>*/ - if(co.e == 0) return angabscissa((circle)co, M); - if(co.e < 1) return angabscissa((ellipse)co, M); - if(co.e == 1) return angabscissa((parabola)co, M); - return angabscissa((hyperbola)co, M); -} - -/*<asyxml><function type="abscissa" signature="curabscissa(line,point)"><code></asyxml>*/ -abscissa curabscissa(line l, point M) -{/*<asyxml></code><documentation>Return the curvilinear abscissa of 'M' on the line 'l'.</documentation></function></asyxml>*/ - if(!(M @ extend(l))) abort("curabscissa: the point is not on the line."); - abscissa oa; - oa.system = curvilinearsystem; - oa.x = sgn(dot(M - l.A, l.B - l.A)) * abs(M - l.A); - return oa; -} - -/*<asyxml><function type="abscissa" signature="curabscissa(circle,point)"><code></asyxml>*/ -abscissa curabscissa(circle c, point M) -{/*<asyxml></code><documentation>Return the curvilinear abscissa of 'M' on the circle 'c'.</documentation></function></asyxml>*/ - if(!(M @ c)) abort("curabscissa: the point is not on the circle."); - abscissa oa; - oa.system = curvilinearsystem; - oa.x = pi * angabscissa(c, M).x * c.r/180; - return oa; -} - -/*<asyxml><function type="abscissa" signature="curabscissa(ellipse,point)"><code></asyxml>*/ -abscissa curabscissa(ellipse el, point M) -{/*<asyxml></code><documentation>Return the curvilinear abscissa of 'M' on the ellipse 'el'.</documentation></function></asyxml>*/ - if(!(M @ el)) abort("curabscissa: the point is not on the ellipse."); - abscissa oa; - oa.system = curvilinearsystem; - real a = angabscissa(el, M, fromCenter).x; - oa.x = arclength(el, 0, a, fromCenter); - oa.polarconicroutine = fromCenter; - return oa; -} - -/*<asyxml><function type="abscissa" signature="curabscissa(parabola,point)"><code></asyxml>*/ -abscissa curabscissa(parabola p, point M) -{/*<asyxml></code><documentation>Return the curvilinear abscissa of 'M' on the parabola 'p'.</documentation></function></asyxml>*/ - if(!(M @ p)) abort("curabscissa: the point is not on the parabola."); - abscissa oa; - oa.system = curvilinearsystem; - real a = angabscissa(p, M).x; - oa.x = arclength(p, 180, a); - oa.polarconicroutine = fromFocus; // Not used. - return oa; -} - -/*<asyxml><function type="abscissa" signature="curabscissa(conic,point)"><code></asyxml>*/ -abscissa curabscissa(conic co, point M) -{/*<asyxml></code><documentation>Return the curvilinear abscissa of 'M' on the conic 'co'.</documentation></function></asyxml>*/ - if(co.e > 1) abort("curabscissa: not implemented for this hyperbola."); - if(co.e == 0) return curabscissa((circle)co, M); - if(co.e < 1) return curabscissa((ellipse)co, M); - return curabscissa((parabola)co, M); -} - -/*<asyxml><function type="abscissa" signature="nodabscissa(line,point)"><code></asyxml>*/ -abscissa nodabscissa(line l, point M) -{/*<asyxml></code><documentation>Return the node abscissa of 'M' on the line 'l'.</documentation></function></asyxml>*/ - if(!(M @ (segment)l)) abort("nodabscissa: the point is not on the segment."); - abscissa oa; - oa.system = nodesystem; - oa.x = abs(M - l.A)/abs(l.A - l.B); - return oa; -} - -/*<asyxml><function type="abscissa" signature="nodabscissa(circle,point)"><code></asyxml>*/ -abscissa nodabscissa(circle c, point M) -{/*<asyxml></code><documentation>Return the node abscissa of 'M' on the circle 'c'.</documentation></function></asyxml>*/ - if(!(M @ c)) abort("nodabscissa: the point is not on the circle."); - abscissa oa; - oa.system = nodesystem; - oa.x = intersect((path)c, locate(M))[0]; - return oa; -} - -/*<asyxml><function type="abscissa" signature="nodabscissa(ellipse,point)"><code></asyxml>*/ -abscissa nodabscissa(ellipse el, point M) -{/*<asyxml></code><documentation>Return the node abscissa of 'M' on the ellipse 'el'.</documentation></function></asyxml>*/ - if(!(M @ el)) abort("nodabscissa: the point is not on the ellipse."); - abscissa oa; - oa.system = nodesystem; - oa.x = intersect((path)el, M)[0]; - return oa; -} - -/*<asyxml><function type="abscissa" signature="nodabscissa(parabola,point)"><code></asyxml>*/ -abscissa nodabscissa(parabola p, point M) -{/*<asyxml></code><documentation>Return the node abscissa OF 'M' on the parabola 'p'.</documentation></function></asyxml>*/ - if(!(M @ p)) abort("nodabscissa: the point is not on the parabola."); - abscissa oa; - oa.system = nodesystem; - path pg = p; - real[] t = intersect(pg, M, 1e-5); - if(t.length == 0) abort("nodabscissa: the point is not on the path of the parabola."); - oa.x = t[0]; - return oa; -} - -/*<asyxml><function type="abscissa" signature="nodabscissa(conic,point)"><code></asyxml>*/ -abscissa nodabscissa(conic co, point M) -{/*<asyxml></code><documentation>Return the node abscissa of 'M' on the conic 'co'.</documentation></function></asyxml>*/ - if(co.e > 1) abort("nodabscissa: not implemented for hyperbola."); - if(co.e == 0) return nodabscissa((circle)co, M); - if(co.e < 1) return nodabscissa((ellipse)co, M); - return nodabscissa((parabola)co, M); -} - - -/*<asyxml><function type="abscissa" signature="relabscissa(line,point)"><code></asyxml>*/ -abscissa relabscissa(line l, point M) -{/*<asyxml></code><documentation>Return the relative abscissa of 'M' on the line 'l'.</documentation></function></asyxml>*/ - if(!(M @ extend(l))) abort("relabscissa: the point is not on the line."); - abscissa oa; - oa.system = relativesystem; - oa.x = sgn(dot(M - l.A, l.B - l.A)) * abs(M - l.A)/abs(l.A - l.B); - return oa; -} - -/*<asyxml><function type="abscissa" signature="relabscissa(circle,point)"><code></asyxml>*/ -abscissa relabscissa(circle c, point M) -{/*<asyxml></code><documentation>Return the relative abscissa of 'M' on the circle 'c'.</documentation></function></asyxml>*/ - if(!(M @ c)) abort("relabscissa: the point is not on the circle."); - abscissa oa; - oa.system = relativesystem; - oa.x = angabscissa(c, M).x/360; - return oa; -} - -/*<asyxml><function type="abscissa" signature="relabscissa(ellipse,point)"><code></asyxml>*/ -abscissa relabscissa(ellipse el, point M) -{/*<asyxml></code><documentation>Return the relative abscissa of 'M' on the ellipse 'el'.</documentation></function></asyxml>*/ - if(!(M @ el)) abort("relabscissa: the point is not on the ellipse."); - abscissa oa; - oa.system = relativesystem; - oa.x = curabscissa(el, M).x/arclength(el); - oa.polarconicroutine = fromFocus; - return oa; -} - -/*<asyxml><function type="abscissa" signature="relabscissa(conic,point)"><code></asyxml>*/ -abscissa relabscissa(conic co, point M) -{/*<asyxml></code><documentation>Return the relative abscissa of 'M' - on the conic 'co'.</documentation></function></asyxml>*/ - if(co.e > 1) abort("relabscissa: not implemented for hyperbola and parabola."); - if(co.e == 1) return relabscissa((parabola)co, M); - if(co.e == 0) return relabscissa((circle)co, M); - return relabscissa((ellipse)co, M); -} -// *.......................ABSCISSA........................* -// *=======================================================* - -// *=======================================================* -// *.........................ARCS..........................* -/*<asyxml><struct signature="arc"><code></asyxml>*/ -struct arc { - /*<asyxml></code><documentation>Implement oriented ellipse (included circle) arcs. - All the calculus with this structure will be as exact as Asymptote can do. - For a full precision, you must not cast 'arc' to 'path' excepted for drawing routines. - </documentation><property type = "ellipse" signature="el"><code></asyxml>*/ - ellipse el;/*<asyxml></code><documentation>The support of the arc.</documentation></property><property type = "real" signature="angle0"><code></asyxml>*/ - restricted real angle0 = 0;/*<asyxml></code><documentation>Internal use: rotating a circle does not modify the origin point,this variable stocks the eventual angle rotation. This value is not used for ellipses which are not circles.</documentation></property><property type = "real" signature="angle1,angle2"><code></asyxml>*/ - restricted real angle1, angle2;/*<asyxml></code><documentation>Values (in degrees) in ]-360, 360[.</documentation></property><property type = "bool" signature="direction"><code></asyxml>*/ - bool direction = CCW;/*<asyxml></code><documentation>The arc will be drawn from 'angle1' to 'angle2' rotating in the direction 'direction'.</documentation></property><property type = "polarconicroutine" signature="polarconicroutine"><code></asyxml>*/ - polarconicroutine polarconicroutine = currentpolarconicroutine;/*<asyxml></code><documentation>The routine to which the angles refer. - If 'el' is a circle 'fromCenter' is always used.</documentation></property></asyxml>*/ - - /*<asyxml><method type = "void" signature="setangles(real,real,real)"><code></asyxml>*/ - void setangles(real a0, real a1, real a2) - {/*<asyxml></code><documentation>Set the angles.</documentation></method></asyxml>*/ - if (a1 < 0 && a2 < 0) { - a1 += 360; - a2 += 360; - } - this.angle0 = a0%(sgnd(a0) * 360); - this.angle1 = a1%(sgnd(a1) * 360); - this.angle2 = a2%(sgnd(2) * 360); - } - - /*<asyxml><method type = "void" signature="init(ellipse,real,real,real,polarconicroutine,bool)"><code></asyxml>*/ - void init(ellipse el, real angle0 = 0, real angle1, real angle2, - polarconicroutine polarconicroutine, - bool direction = CCW) - {/*<asyxml></code><documentation>Constructor.</documentation></method></asyxml>*/ - if(abs(angle1 - angle2) > 360) abort("arc: |angle1 - angle2| > 360."); - this.el = el; - this.setangles(angle0, angle1, angle2); - this.polarconicroutine = polarconicroutine; - this.direction = direction; - } - - /*<asyxml><method type = "arc" signature="copy()"><code></asyxml>*/ - arc copy() - {/*<asyxml></code><documentation>Copy the arc.</documentation></method></asyxml>*/ - arc oa = new arc; - oa.el = this.el; - oa.direction = this.direction; - oa.polarconicroutine = this.polarconicroutine; - oa.angle1 = this.angle1; - oa.angle2 = this.angle2; - oa.angle0 = this.angle0; - return oa; - } -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="polarconicroutine" signature="polarconicroutine(ellipse)"><code></asyxml>*/ -polarconicroutine polarconicroutine(conic co) -{/*<asyxml></code><documentation>Return the default routine used to draw a conic.</documentation></function></asyxml>*/ - if(co.e == 0) return fromCenter; - if(co.e == 1) return fromFocus; - return currentpolarconicroutine; -} - -/*<asyxml><function type="arc" signature="arc(ellipse,real,real,polarconicroutine,bool)"><code></asyxml>*/ -arc arc(ellipse el, real angle1, real angle2, - polarconicroutine polarconicroutine = polarconicroutine(el), - bool direction = CCW) -{/*<asyxml></code><documentation>Return the ellipse arc from 'angle1' to 'angle2' with respect to 'polarconicroutine' and rotating in the direction 'direction'.</documentation></function></asyxml>*/ - arc oa; - oa.init(el, 0, angle1, angle2, polarconicroutine, direction); - return oa; -} - -/*<asyxml><function type="arc" signature="complementary(arc)"><code></asyxml>*/ -arc complementary(arc a) -{/*<asyxml></code><documentation>Return the complementary of 'a'.</documentation></function></asyxml>*/ - arc oa; - oa.init(a.el, a.angle0, a.angle2, a.angle1, a.polarconicroutine, a.direction); - return oa; -} - -/*<asyxml><function type="arc" signature="reverse(arc)"><code></asyxml>*/ -arc reverse(arc a) -{/*<asyxml></code><documentation>Return arc 'a' oriented in reverse direction.</documentation></function></asyxml>*/ - arc oa; - oa.init(a.el, a.angle0, a.angle2, a.angle1, a.polarconicroutine, !a.direction); - return oa; -} - -/*<asyxml><function type="real" signature="degrees(arc)"><code></asyxml>*/ -real degrees(arc a) -{/*<asyxml></code><documentation>Return the measure in degrees of the oriented arc 'a'.</documentation></function></asyxml>*/ - real or; - real da = a.angle2 - a.angle1; - if(a.direction) { - or = a.angle1 < a.angle2 ? da : 360 + da; - } else { - or = a.angle1 < a.angle2 ? -360 + da : da; - } - return or; -} - -/*<asyxml><function type="real" signature="angle(a)"><code></asyxml>*/ -real angle(arc a) -{/*<asyxml></code><documentation>Return the measure in radians of the oriented arc 'a'.</documentation></function></asyxml>*/ - return radians(degrees(a)); -} - -/*<asyxml><function type="int" signature="arcnodesnumber(explicit arc)"><code></asyxml>*/ -int arcnodesnumber(explicit arc a) -{/*<asyxml></code><documentation>Return the number of nodes to draw the arc 'a'.</documentation></function></asyxml>*/ - return ellipsenodesnumber(a.el.a, a.el.b, a.angle1, a.angle2, a.direction); -} - -private path arctopath(arc a, int n) -{ - if(a.el.e == 0) return arcfromcenter(a.el, a.angle0 + a.angle1, a.angle0 + a.angle2, a.direction, n); - if(a.el.e != 1) return a.polarconicroutine(a.el, a.angle1, a.angle2, n, a.direction); - return arcfromfocus(a.el, a.angle1, a.angle2, n, a.direction); -} - -/*<asyxml><function type="point" signature="angpoint(arc,real)"><code></asyxml>*/ -point angpoint(arc a, real angle) -{/*<asyxml></code><documentation>Return the point given by its angular position (in degrees) relative to the arc 'a'. - If 'angle > degrees(a)' or 'angle < 0' the returned point is on the extended arc.</documentation></function></asyxml>*/ - pair p; - if(a.el.e == 0) { - real gle = a.angle0 + a.angle1 + (a.direction ? angle : -angle); - p = point(arcfromcenter(a.el, gle, gle, CCW, 1), 0); - } - else { - real gle = a.angle1 + (a.direction ? angle : -angle); - p = point(a.polarconicroutine(a.el, gle, gle, 1, CCW), 0); - } - return point(coordsys(a.el), p/coordsys(a.el)); -} - -/*<asyxml><operator type = "path" signature="cast(explicit arc)"><code></asyxml>*/ -path operator cast(explicit arc a) -{/*<asyxml></code><documentation>Cast arc to path.</documentation></operator></asyxml>*/ - return arctopath(a, arcnodesnumber(a)); -} - -/*<asyxml><operator type = "guide" signature="cast(explicit arc)"><code></asyxml>*/ -guide operator cast(explicit arc a) -{/*<asyxml></code><documentation>Cast arc to guide.</documentation></operator></asyxml>*/ - return arctopath(a, arcnodesnumber(a)); -} - -/*<asyxml><operator type = "arc" signature="*(transform,explicit arc)"><code></asyxml>*/ -arc operator *(transform t, explicit arc a) -{/*<asyxml></code><documentation>Provide transform * arc.</documentation></operator></asyxml>*/ - pair[] P, PP; - path g = arctopath(a, 3); - real a0, a1 = a.angle1, a2 = a.angle2, ap1, ap2; - bool dir = a.direction; - P[0] = t * point(g, 0); - P[1] = t * point(g, 2); - ellipse el = t * a.el; - arc oa; - a0 = (a.angle0 + angle(shiftless(t)))%360; - pair C; - if(a.polarconicroutine == fromCenter) C = el.C; else C = el.F1; - real d = abs(locate(el.F2 - el.F1)) > epsgeo ? - degrees(locate(el.F2 - el.F1)) : a0 + degrees(el.C.coordsys.i); - ap1 = (degrees(P[0]-C, false) - d)%360; - ap2 = (degrees(P[1]-C, false) - d)%360; - oa.init(el, a0, ap1, ap2, a.polarconicroutine, dir); - g = arctopath(oa, 3); - PP[0] = point(g, 0); - PP[1] = point(g, 2); - if((a1 - a2) * (ap1 - ap2) < 0) {// Handle reflection. - dir=!a.direction; - oa.init(el, a0, ap1, ap2, a.polarconicroutine, dir); - } - return oa; -} - -/*<asyxml><operator type = "arc" signature="*(real,explicit arc)"><code></asyxml>*/ -arc operator *(real x, explicit arc a) -{/*<asyxml></code><documentation>Provide real * arc. - Return the arc subtracting and adding '(x - 1) * degrees(a)/2' to 'a.angle1' and 'a.angle2' respectively.</documentation></operator></asyxml>*/ - real a1, a2, gle; - gle = (x - 1) * degrees(a)/2; - a1 = a.angle1 - gle; - a2 = a.angle2 + gle; - arc oa; - oa.init(a.el, a.angle0, a1, a2, a.polarconicroutine, a.direction); - return oa; -} -arc operator *(int x, explicit arc a){return (real)x * a;} -/*<asyxml><operator type = "arc" signature="/(real,explicit arc)"><code></asyxml>*/ -arc operator /(explicit arc a, real x) -{/*<asyxml></code><documentation>Provide arc/real. - Return the arc subtracting and adding '(1/x - 1) * degrees(a)/2' to 'a.angle1' and 'a.angle2' respectively.</documentation></operator></asyxml>*/ - return (1/x) * a; -} -/*<asyxml><operator type = "arc" signature="+(explicit arc,point)"><code></asyxml>*/ -arc operator +(explicit arc a, point M) -{/*<asyxml></code><documentation>Provide arc + point. - Return shifted arc. - 'operator +(explicit arc, point)', 'operator +(explicit arc, vector)' and 'operator -(explicit arc, vector)' are also defined.</documentation></operator></asyxml>*/ - return shift(M) * a; -} -arc operator -(explicit arc a, point M){return a + (-M);} -arc operator +(explicit arc a, vector v){return shift(locate(v)) * a;} -arc operator -(explicit arc a, vector v){return a + (-v);} - - -/*<asyxml><operator type = "bool" signature="@(point,arc)"><code></asyxml>*/ -bool operator @(point M, arc a) -{/*<asyxml></code><documentation>Return true iff 'M' is on the arc 'a'.</documentation></operator></asyxml>*/ - if (!(M @ a.el)) return false; - coordsys R = defaultcoordsys; - path ap = arctopath(a, 3); - line l = line(point(R, point(ap, 0)), point(R, point(ap, 2))); - return sameside(M, point(R, point(ap, 1)), l); -} - -/*<asyxml><function type="void" signature="draw(picture,Label,arc,align,pen,arrowbar,arrowbar,margin,Label,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, Label L = "", arc a, - align align = NoAlign, pen p = currentpen, - arrowbar arrow = None, arrowbar bar = None, margin margin = NoMargin, - Label legend = "", marker marker = nomarker) -{/*<asyxml></code><documentation>Draw 'arc' adding the pen returned by 'addpenarc(p)' to the pen 'p'. - <look href = "#addpenarc"/></documentation></function></asyxml>*/ - draw(pic, L, (path)a, align, addpenarc(p), arrow, bar, margin, legend, marker); -} - -/*<asyxml><function type="real" signature="arclength(arc)"><code></asyxml>*/ -real arclength(arc a) -{/*<asyxml></code><documentation>The arc length of 'a'.</documentation></function></asyxml>*/ - return arclength(a.el, a.angle1, a.angle2, a.direction, a.polarconicroutine); -} - -private point ppoint(arc a, real x) -{// Return the point of the arc proportionally to its length. - point oP; - if(a.el.e == 0) { // Case of circle. - oP = angpoint(a, x * abs(degrees(a))); - } else { // Ellipse and not circle. - if(!a.direction) { - transform t = reflect(line(a.el.F1, a.el.F2)); - return t * ppoint(t * a, x); - } - - real angle1 = a.angle1, angle2 = a.angle2; - if(a.polarconicroutine == fromFocus) { - // dot(point(fromFocus(a.el, angle1, angle1, 1, CCW), 0), 2mm + blue); - // dot(point(fromFocus(a.el, angle2, angle2, 1, CCW), 0), 2mm + blue); - // write("fromfocus1 = ", angle1); - // write("fromfocus2 = ", angle2); - real gle1 = focusToCenter(a.el, angle1); - real gle2 = focusToCenter(a.el, angle2); - if((gle1 - gle2) * (angle1 - angle2) > 0) { - angle1 = gle1; angle2 = gle2; - } else { - angle1 = gle2; angle2 = gle1; - } - // write("fromcenter1 = ", angle1); - // write("fromcenter2 = ", angle2); - // dot(point(fromCenter(a.el, angle1, angle1, 1, CCW), 0), 1mm + red); - // dot(point(fromCenter(a.el, angle2, angle2, 1, CCW), 0), 1mm + red); - } - - if(angle1 > angle2) { - arc ta = a.copy(); - ta.polarconicroutine = fromCenter; - ta.setangles(a0 = a.angle0, a1 = angle1 - 360, a2 = angle2); - return ppoint(ta, x); - } - ellipse co = a.el; - real gle, a1, a2, cx = 0; - bool direction; - if(x >= 0) { - a1 = angle1; - a2 = a1 + 360; - direction = CCW; - } else { - a1 = angle1 - 360; - a2 = a1 - 360; - direction = CW; - } - gle = a1; - real L = arclength(co, angle1, angle2, a.direction, fromCenter); - real tx = L * abs(x)%arclength(co); - real aout = a1; - while(abs(cx - tx) > epsgeo) { - aout = (a1 + a2)/2; - cx = abs(arclength(co, gle, aout, direction, fromCenter)); - if(cx > tx) a2 = (a1 + a2)/2 ; else a1 = (a1 + a2)/2; - } - pair p = point(arcfromcenter(co, aout, aout, CCW, 1), 0); - oP = point(coordsys(co), p/coordsys(co)); - } - return oP; -} - -/*<asyxml><function type="point" signature="point(arc,abscissa)"><code></asyxml>*/ -point point(arc a, abscissa l) -{/*<asyxml></code><documentation>Return the point of 'a' which has the abscissa 'l.x' - according to the abscissa system 'l.system'. - Note that 'a.polarconicroutine' is used instead of 'l.polarconicroutine'. - <look href = "#struct abscissa"/></documentation></function></asyxml>*/ - real posx; - arc ta = a.copy(); - ellipse co = a.el; - if (l.system == relativesystem) { - posx = l.x; - } else - if (l.system == curvilinearsystem) { - real tl; - if(co.e == 0) { - tl = curabscissa(a.el, angpoint(a.el, a.angle0 + a.angle1)).x; - return curpoint(a.el, tl + (a.direction ? l.x : -l.x)); - } else { - tl = curabscissa(a.el, angpoint(a.el, a.angle1, a.polarconicroutine)).x; - return curpoint(a.el, tl + (a.direction ? l.x : -l.x)); - } - } else - if (l.system == nodesystem) { - coordsys R = coordsys(co); - return point(R, point((path)a, l.x)/R); - } else - if (l.system == angularsystem) { - return angpoint(a, l.x); - } else abort("point: bad abscissa system."); - return ppoint(ta, posx); -} - - -/*<asyxml><function type="point" signature="point(arc,real)"><code></asyxml>*/ -point point(arc a, real x) -{/*<asyxml></code><documentation>Return the point between node floor(t) and floor(t) + 1.</documentation></function></asyxml>*/ - return point(a, nodabscissa(x)); -} -pair point(explicit arc a, int x) -{ - return point(a, nodabscissa(x)); -} - -/*<asyxml><function type="point" signature="relpoint(arc,real)"><code></asyxml>*/ -point relpoint(arc a, real x) -{/*<asyxml></code><documentation>Return the relative point of 'a'. - If x > 1 or x < 0, the returned point is on the extended arc.</documentation></function></asyxml>*/ - return point(a, relabscissa(x)); -} - -/*<asyxml><function type="point" signature="curpoint(arc,real)"><code></asyxml>*/ -point curpoint(arc a, real x) -{/*<asyxml></code><documentation>Return the point of 'a' which has the curvilinear abscissa 'x'. - If x < 0 or x > arclength(a), the returned point is on the extended arc.</documentation></function></asyxml>*/ - return point(a, curabscissa(x)); -} - -/*<asyxml><function type="abscissa" signature="angabscissa(arc,point)"><code></asyxml>*/ -abscissa angabscissa(arc a, point M) -{/*<asyxml></code><documentation>Return the angular abscissa of 'M' according to the arc 'a'.</documentation></function></asyxml>*/ - if(!(M @ a.el)) - abort("angabscissa: the point is not on the extended arc."); - abscissa oa; - oa.system = angularsystem; - oa.polarconicroutine = a.polarconicroutine; - real am = angabscissa(a.el, M, a.polarconicroutine).x; - oa.x = (am - a.angle1 - (a.el.e == 0 ? a.angle0 : 0))%360; - oa.x = a.direction ? oa.x : 360 - oa.x; - return oa; -} - -/*<asyxml><function type="abscissa" signature="curabscissa(arc,point)"><code></asyxml>*/ -abscissa curabscissa(arc a, point M) -{/*<asyxml></code><documentation>Return the curvilinear abscissa according to the arc 'a'.</documentation></function></asyxml>*/ - ellipse el = a.el; - if(!(M @ el)) - abort("angabscissa: the point is not on the extended arc."); - abscissa oa; - oa.system = curvilinearsystem; - real xm = curabscissa(el, M).x; - real a0 = el.e == 0 ? a.angle0 : 0; - real am = curabscissa(el, angpoint(el, a.angle1 + a0, a.polarconicroutine)).x; - real l = arclength(el); - oa.x = (xm - am)%l; - oa.x = a.direction ? oa.x : l - oa.x; - return oa; -} - -/*<asyxml><function type="abscissa" signature="nodabscissa(arc,point)"><code></asyxml>*/ -abscissa nodabscissa(arc a, point M) -{/*<asyxml></code><documentation>Return the node abscissa according to the arc 'a'.</documentation></function></asyxml>*/ - if(!(M @ a)) - abort("nodabscissa: the point is not on the arc."); - abscissa oa; - oa.system = nodesystem; - oa.x = intersect((path)a, M)[0]; - return oa; -} - -/*<asyxml><function type="abscissa" signature="relabscissa(arc,point)"><code></asyxml>*/ -abscissa relabscissa(arc a, point M) -{/*<asyxml></code><documentation>Return the relative abscissa according to the arc 'a'.</documentation></function></asyxml>*/ - ellipse el = a.el; - if(!( M @ el)) - abort("relabscissa: the point is not on the prolonged arc."); - abscissa oa; - oa.system = relativesystem; - oa.x = curabscissa(a, M).x/arclength(a); - return oa; -} - -/*<asyxml><function type="void" signature="markarc(picture,Label,int,real,real,arc,arrowbar,pen,pen,margin,marker)"><code></asyxml>*/ -void markarc(picture pic = currentpicture, - Label L = "", - int n = 1, real radius = 0, real space = 0, - arc a, - pen sectorpen = currentpen, - pen markpen = sectorpen, - margin margin = NoMargin, - arrowbar arrow = None, - marker marker = nomarker) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - real Da = degrees(a); - pair p1 = point(a, 0); - pair p2 = relpoint(a, 1); - pair c = a.polarconicroutine == fromCenter ? locate(a.el.C) : locate(a.el.F1); - if(radius == 0) radius = markangleradius(markpen); - if(abs(Da) > 180) radius = -radius; - radius = (a.direction ? 1 : -1) * sgnd(Da) * radius; - draw(c--p1^^c--p2, sectorpen); - markangle(pic = pic, L = L, n = n, radius = radius, space = space, - A = p1, O = c, B = p2, - arrow = arrow, p = markpen, margin = margin, - marker = marker); -} -// *.........................ARCS..........................* -// *=======================================================* - -// *=======================================================* -// *........................MASSES.........................* -/*<asyxml><struct signature="mass"><code></asyxml>*/ -struct mass {/*<asyxml></code><documentation></documentation><property type = "point" signature="M"><code></asyxml>*/ - point M;/*<asyxml></code><documentation></documentation></property><property type = "real" signature="m"><code></asyxml>*/ - real m;/*<asyxml></code><documentation></documentation></property></asyxml>*/ -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="mass" signature="mass(point,real)"><code></asyxml>*/ -mass mass(point M, real m) -{/*<asyxml></code><documentation>Constructor of mass point.</documentation></function></asyxml>*/ - mass om; - om.M = M; - om.m = m; - return om; -} - -/*<asyxml><operator type = "point" signature="cast(mass)"><code></asyxml>*/ -point operator cast(mass m) -{/*<asyxml></code><documentation>Cast mass point to point.</documentation></operator></asyxml>*/ - point op; - op = m.M; - op.m = m.m; - return op; -} -/*<asyxml><function type="point" signature="point(explicit mass)"><code></asyxml>*/ -point point(explicit mass m){return m;}/*<asyxml></code><documentation>Cast - 'm' to point</documentation></function></asyxml>*/ - -/*<asyxml><operator type = "mass" signature="cast(point)"><code></asyxml>*/ -mass operator cast(point M) -{/*<asyxml></code><documentation>Cast point to mass point.</documentation></operator></asyxml>*/ - mass om; - om.M = M; - om.m = M.m; - return om; -} -/*<asyxml><function type="mass" signature="mass(explicit point)"><code></asyxml>*/ -mass mass(explicit point P) -{/*<asyxml></code><documentation>Cast 'P' to mass.</documentation></function></asyxml>*/ - return mass(P, P.m); -} - -/*<asyxml><operator type = "point[]" signature="cast(mass[])"><code></asyxml>*/ -point[] operator cast(mass[] m) -{/*<asyxml></code><documentation>Cast mass[] to point[].</documentation></operator></asyxml>*/ - point[] op; - for(mass am : m) op.push(point(am)); - return op; -} - -/*<asyxml><operator type = "mass[]" signature="cast(point[])"><code></asyxml>*/ -mass[] operator cast(point[] P) -{/*<asyxml></code><documentation>Cast point[] to mass[].</documentation></operator></asyxml>*/ - mass[] om; - for(point op : P) om.push(mass(op)); - return om; -} - -/*<asyxml><function type="mass" signature="mass(coordsys,explicit pair,real)"><code></asyxml>*/ -mass mass(coordsys R, explicit pair p, real m) -{/*<asyxml></code><documentation>Return the mass which has coordinates - 'p' with respect to 'R' and weight 'm'.</documentation></function></asyxml>*/ - return point(R, p, m);// Using casting. -} - -/*<asyxml><operator type = "mass" signature="cast(pair)"><code></asyxml>*/ -mass operator cast(pair m){return mass((point)m, 1);}/*<asyxml></code><documentation>Cast pair to mass point.</documentation></operator></asyxml>*/ -/*<asyxml><operator type = "path" signature="cast(mass)"><code></asyxml>*/ -path operator cast(mass M){return M.M;}/*<asyxml></code><documentation>Cast mass point to path.</documentation></operator></asyxml>*/ -/*<asyxml><operator type = "guide" signature="cast(mass)"><code></asyxml>*/ -guide operator cast(mass M){return M.M;}/*<asyxml></code><documentation>Cast mass to guide.</documentation></operator></asyxml>*/ - -/*<asyxml><operator type = "mass" signature="+(mass,mass)"><code></asyxml>*/ -mass operator +(mass M1, mass M2) -{/*<asyxml></code><documentation>Provide mass + mass. - mass - mass is also defined.</documentation></operator></asyxml>*/ - return mass(M1.M + M2.M, M1.m + M2.m); -} -mass operator -(mass M1, mass M2) -{ - return mass(M1.M - M2.M, M1.m - M2.m); -} - -/*<asyxml><operator type = "mass" signature="*(real,mass)"><code></asyxml>*/ -mass operator *(real x, explicit mass M) -{/*<asyxml></code><documentation>Provide real * mass. - The resulted mass is the mass of 'M' multiplied by 'x' . - mass/real, mass + real and mass - real are also defined.</documentation></operator></asyxml>*/ - return mass(M.M, x * M.m); -} -mass operator *(int x, explicit mass M){return mass(M.M, x * M.m);} -mass operator /(explicit mass M, real x){return mass(M.M, M.m/x);} -mass operator /(explicit mass M, int x){return mass(M.M, M.m/x);} -mass operator +(explicit mass M, real x){return mass(M.M, M.m + x);} -mass operator +(explicit mass M, int x){return mass(M.M, M.m + x);} -mass operator -(explicit mass M, real x){return mass(M.M, M.m - x);} -mass operator -(explicit mass M, int x){return mass(M.M, M.m - x);} -/*<asyxml><operator type = "mass" signature="*(transform,mass)"><code></asyxml>*/ -mass operator *(transform t, mass M) -{/*<asyxml></code><documentation>Provide transform * mass.</documentation></operator></asyxml>*/ - return mass(t * M.M, M.m); -} - -/*<asyxml><function type="mass" signature="masscenter(... mass[])"><code></asyxml>*/ -mass masscenter(... mass[] M) -{/*<asyxml></code><documentation>Return the center of the masses 'M'.</documentation></function></asyxml>*/ - point[] P; - for (int i = 0; i < M.length; ++i) - P.push(M[i].M); - P = standardizecoordsys(currentcoordsys, true ... P); - real m = M[0].m; - point oM = M[0].m * P[0]; - for (int i = 1; i < M.length; ++i) { - oM += M[i].m * P[i]; - m += M[i].m; - } - if (m == 0) abort("masscenter: the sum of masses is null."); - return mass(oM/m, m); -} - -/*<asyxml><function type="string" signature="massformat(string,string,mass)"><code></asyxml>*/ -string massformat(string format = defaultmassformat, - string s, mass M) -{/*<asyxml></code><documentation>Return the string formated by 'format' with the mass value. - In the parameter 'format', %L will be replaced by 's'. - <look href = "#defaultmassformat"/>.</documentation></function></asyxml>*/ - return format == "" ? s : - format(replace(format, "%L", replace(s, "$", "")), M.m); -} - -/*<asyxml><function type="void" signature="label(picture,Label,explicit mass,align,string,pen,filltype)"><code></asyxml>*/ -void label(picture pic = currentpicture, Label L, explicit mass M, - align align = NoAlign, string format = defaultmassformat, - pen p = nullpen, filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw label returned by massformat(format, L, M) at coordinates of M. - <look href = "#massformat(string, string, mass)"/>.</documentation></function></asyxml>*/ - Label lL = L.copy(); - lL.s = massformat(format, lL.s, M); - Label L = Label(lL, M.M, align, p, filltype); - add(pic, L); -} - -/*<asyxml><function type="void" signature="dot(picture,Label,explicit mass,align,string,pen)"><code></asyxml>*/ -void dot(picture pic = currentpicture, Label L, explicit mass M, align align = NoAlign, - string format = defaultmassformat, pen p = currentpen) -{/*<asyxml></code><documentation>Draw a dot with label 'L' as - label(picture, Label, explicit mass, align, string, pen, filltype) does. - <look href = "#label(picture, Label, mass, align, string, pen, filltype)"/>.</documentation></function></asyxml>*/ - Label lL = L.copy(); - lL.s = massformat(format, lL.s, M); - lL.position(locate(M.M)); - lL.align(align, E); - lL.p(p); - dot(pic, M.M, p); - add(pic, lL); -} -// *........................MASSES.........................* -// *=======================================================* - -// *=======================================================* -// *.......................TRIANGLES.......................* -/*<asyxml><function type="point" signature="orthocentercenter(point,point,point)"><code></asyxml>*/ -point orthocentercenter(point A, point B, point C) -{/*<asyxml></code><documentation>Return the orthocenter of the triangle ABC.</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A, B, C); - coordsys R = P[0].coordsys; - pair pp = extension(A, projection(P[1], P[2]) * P[0], B, projection(P[0], P[2]) * P[1]); - return point(R, pp/R); -} - -/*<asyxml><function type="point" signature="centroid(point,point,point)"><code></asyxml>*/ -point centroid(point A, point B, point C) -{/*<asyxml></code><documentation>Return the centroid of the triangle ABC.</documentation></function></asyxml>*/ - return (A + B + C)/3; -} - -/*<asyxml><function type="point" signature="incenter(point,point,point)"><code></asyxml>*/ -point incenter(point A, point B, point C) -{/*<asyxml></code><documentation>Return the center of the incircle of the triangle ABC.</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A, B, C); - coordsys R = P[0].coordsys; - pair a = A, b = B, c = C; - pair pp = extension(a, a + dir(a--b, a--c), b, b + dir(b--a, b--c)); - return point(R, pp/R); -} - -/*<asyxml><function type="real" signature="inradius(point,point,point)"><code></asyxml>*/ -real inradius(point A, point B, point C) -{/*<asyxml></code><documentation>Return the radius of the incircle of the triangle ABC.</documentation></function></asyxml>*/ - point IC = incenter(A, B, C); - return abs(IC - projection(A, B) * IC); -} - -/*<asyxml><function type="circle" signature="incircle(point,point,point)"><code></asyxml>*/ -circle incircle(point A, point B, point C) -{/*<asyxml></code><documentation>Return the incircle of the triangle ABC.</documentation></function></asyxml>*/ - point IC = incenter(A, B, C); - return circle(IC, abs(IC - projection(A, B) * IC)); -} - -/*<asyxml><function type="point" signature="excenter(point,point,point)"><code></asyxml>*/ -point excenter(point A, point B, point C) -{/*<asyxml></code><documentation>Return the center of the excircle of the triangle tangent with (AB).</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A, B, C); - coordsys R = P[0].coordsys; - pair a = A, b = B, c = C; - pair pp = extension(a, a + rotate(90) * dir(a--b, a--c), b, b + rotate(90) * dir(b--a, b--c)); - return point(R, pp/R); -} - -/*<asyxml><function type="real" signature="exradius(point,point,point)"><code></asyxml>*/ -real exradius(point A, point B, point C) -{/*<asyxml></code><documentation>Return the radius of the excircle of the triangle ABC with (AB).</documentation></function></asyxml>*/ - point EC = excenter(A, B, C); - return abs(EC - projection(A, B) * EC); -} - -/*<asyxml><function type="circle" signature="excircle(point,point,point)"><code></asyxml>*/ -circle excircle(point A, point B, point C) -{/*<asyxml></code><documentation>Return the excircle of the triangle ABC tangent with (AB).</documentation></function></asyxml>*/ - point center = excenter(A, B, C); - real radius = abs(center - projection(B, C) * center); - return circle(center, radius); -} - -private int[] numarray = {1, 2, 3}; -numarray.cyclic = true; - -/*<asyxml><struct signature="triangle"><code></asyxml>*/ -struct triangle {/*<asyxml></code><documentation></documentation></asyxml>*/ - - /*<asyxml><struct signature="vertex"><code></asyxml>*/ - struct vertex {/*<asyxml></code><documentation>Structure used to communicate the vertex of a triangle.</documentation><property type = "int" signature="n"><code></asyxml>*/ - int n;/*<asyxml></code><documentation>1 means VA,2 means VB,3 means VC,4 means VA etc...</documentation></property><property type = "triangle" signature="triangle"><code></asyxml>*/ - triangle t;/*<asyxml></code><documentation>The triangle to which the vertex refers.</documentation></property></asyxml>*/ - }/*<asyxml></struct></asyxml>*/ - - /*<asyxml><property type = "point" signature="A,B,C"><code></asyxml>*/ - restricted point A, B, C;/*<asyxml></code><documentation>The vertices of the triangle (as point).</documentation></property><property type = "vertex" signature="VA, VB, VC"><code></asyxml>*/ - restricted vertex VA, VB, VC;/*<asyxml></code><documentation>The vertices of the triangle (as vertex). - Note that the vertex structure contains the triangle to wish it refers.</documentation></property></asyxml>*/ - VA.n = 1;VB.n = 2;VC.n = 3; - - /*<asyxml><method type = "vertex" signature="vertex(int)"><code></asyxml>*/ - vertex vertex(int n) - {/*<asyxml></code><documentation>Return numbered vertex. - 'n' is 1 means VA, 2 means VB, 3 means VC, 4 means VA etc...</documentation></method></asyxml>*/ - n = numarray[n - 1]; - if(n == 1) return VA; - else if(n == 2) return VB; - return VC; - } - - /*<asyxml><method type = "point" signature="point(int)"><code></asyxml>*/ - point point(int n) - {/*<asyxml></code><documentation>Return numbered point. - n is 1 means A, 2 means B, 3 means C, 4 means A etc...</documentation></method></asyxml>*/ - n = numarray[n - 1]; - if(n == 1) return A; - else if(n == 2) return B; - return C; - } - - /*<asyxml><method type = "void" signature="init(point,point,point)"><code></asyxml>*/ - void init(point A, point B, point C) - {/*<asyxml></code><documentation>Constructor.</documentation></method></asyxml>*/ - point[] P = standardizecoordsys(A, B, C); - this.A = P[0]; - this.B = P[1]; - this.C = P[2]; - VA.t = this; VB.t = this; VC.t = this; - } - - /*<asyxml><method type = "void" signature="operator init(point,point,point)"><code></asyxml>*/ - void operator init(point A, point B, point C) - {/*<asyxml></code><documentation>For backward compatibility. - Provide the routine 'triangle(point A, point B, point C)'.</documentation></method></asyxml>*/ - this.init(A, B, C); - } - - /*<asyxml><method type = "void" signature="init(real,real,real,real,point)"><code></asyxml>*/ - void operator init(real b, real alpha, real c, real angle = 0, point A = (0, 0)) - {/*<asyxml></code><documentation>For backward compatibility. - Provide the routine 'triangle(real b, real alpha, real c, real angle = 0, point A = (0, 0)) - which returns the triangle ABC rotated by 'angle' (in degrees) and where b = AC, degrees(A) = alpha, AB = c.</documentation></method></asyxml>*/ - coordsys R = A.coordsys; - this.init(A, A + R.polar(c, radians(angle)), A + R.polar(b, radians(angle + alpha))); - } - - /*<asyxml><method type = "real" signature="a(),b(),c()"><code></asyxml>*/ - real a() - {/*<asyxml></code><documentation>Return the length BC. - b() and c() are also defined and return the length AC and AB respectively.</documentation></method></asyxml>*/ - return length(C - B); - } - real b() {return length(A - C);} - real c() {return length(B - A);} - - private real det(pair a, pair b) {return a.x * b.y - a.y * b.x;} - - /*<asyxml><method type = "real" signature="area()"><code></asyxml>*/ - real area() - {/*<asyxml></code><documentation></documentation></method></asyxml>*/ - pair a = locate(A), b = locate(B), c = locate(C); - return 0.5 * abs(det(a, b) + det(b, c) + det(c, a)); - } - - /*<asyxml><method type = "real" signature="alpha(),beta(),gamma()"><code></asyxml>*/ - real alpha() - {/*<asyxml></code><documentation>Return the measure (in degrees) of the angle A. - beta() and gamma() are also defined and return the measure of the angles B and C respectively.</documentation></method></asyxml>*/ - return degrees(acos((b()^2 + c()^2 - a()^2)/(2b() * c()))); - } - real beta() {return degrees(acos((c()^2 + a()^2 - b()^2)/(2c() * a())));} - real gamma() {return degrees(acos((a()^2 + b()^2 - c()^2)/(2a() * b())));} - - /*<asyxml><method type = "path" signature="Path()"><code></asyxml>*/ - path Path() - {/*<asyxml></code><documentation>The path of the triangle.</documentation></method></asyxml>*/ - return A--C--B--cycle; - } - - /*<asyxml><struct signature="side"><code></asyxml>*/ - struct side - {/*<asyxml></code><documentation>Structure used to communicate the side of a triangle.</documentation><property type = "int" signature="n"><code></asyxml>*/ - int n;/*<asyxml></code><documentation>1 or 0 means [AB],-1 means [BA],2 means [BC],-2 means [CB] etc.</documentation></property><property type = "triangle" signature="triangle"><code></asyxml>*/ - triangle t;/*<asyxml></code><documentation>The triangle to which the side refers.</documentation></property></asyxml>*/ - }/*<asyxml></struct></asyxml>*/ - - /*<asyxml><property type = "side" signature="AB"><code></asyxml>*/ - side AB;/*<asyxml></code><documentation>For the routines using the structure 'side', triangle.AB means 'side AB'. - BA, AC, CA etc are also defined.</documentation></property></asyxml>*/ - AB.n = 1; AB.t = this; - side BA; BA.n = -1; BA.t = this; - side BC; BC.n = 2; BC.t = this; - side CB; CB.n = -2; CB.t = this; - side CA; CA.n = 3; CA.t = this; - side AC; AC.n = -3; AC.t = this; - - /*<asyxml><method type = "side" signature="side(int)"><code></asyxml>*/ - side side(int n) - {/*<asyxml></code><documentation>Return numbered side. - n is 1 means AB, -1 means BA, 2 means BC, -2 means CB, etc.</documentation></method></asyxml>*/ - if(n == 0) abort('Invalid side number.'); - int an = numarray[abs(n)-1]; - if(an == 1) return n > 0 ? AB : BA; - else if(an == 2) return n > 0 ? BC : CB; - return n > 0 ? CA : AC; - } - - /*<asyxml><method type = "line" signature="line(int)"><code></asyxml>*/ - line line(int n) - {/*<asyxml></code><documentation>Return the numbered line.</documentation></method></asyxml>*/ - if(n == 0) abort('Invalid line number.'); - int an = numarray[abs(n)-1]; - if(an == 1) return n > 0 ? line(A, B) : line(B, A); - else if(an == 2) return n > 0 ? line(B, C) : line(C, B); - return n > 0 ? line(C, A) : line(A, C); - } - -}/*<asyxml></struct></asyxml>*/ - -from triangle unravel side; // The structure 'side' is now available outside the triangle structure. -from triangle unravel vertex; // The structure 'vertex' is now available outside the triangle structure. - -triangle[] operator ^^(triangle[] t1, triangle t2) -{ - triangle[] T; - for (int i = 0; i < t1.length; ++i) T.push(t1[i]); - T.push(t2); - return T; -} - -triangle[] operator ^^(... triangle[] t) -{ - triangle[] T; - for (int i = 0; i < t.length; ++i) { - T.push(t[i]); - } - return T; -} - -/*<asyxml><operator type = "line" signature="cast(side)"><code></asyxml>*/ -line operator cast(side side) -{/*<asyxml></code><documentation>Cast side to (infinite) line. - Most routine with line parameters works with side parameters. - One can use the code 'segment(a_side)' to obtain a line segment.</documentation></operator></asyxml>*/ - triangle t = side.t; - return t.line(side.n); -} - -/*<asyxml><function type="line" signature="line(explicit side)"><code></asyxml>*/ -line line(explicit side side) -{/*<asyxml></code><documentation>Return 'side' as line.</documentation></function></asyxml>*/ - return (line)side; -} - -/*<asyxml><function type="segment" signature="segment(explicit side)"><code></asyxml>*/ -segment segment(explicit side side) -{/*<asyxml></code><documentation>Return 'side' as segment.</documentation></function></asyxml>*/ - return (segment)(line)side; -} - -/*<asyxml><operator type = "point" signature="cast(vertex)"><code></asyxml>*/ -point operator cast(vertex V) -{/*<asyxml></code><documentation>Cast vertex to point. - Most routine with point parameters works with vertex parameters.</documentation></operator></asyxml>*/ - return V.t.point(V.n); -} - -/*<asyxml><function type="point" signature="point(explicit vertex)"><code></asyxml>*/ -point point(explicit vertex V) -{/*<asyxml></code><documentation>Return the point corresponding to the vertex 'V'.</documentation></function></asyxml>*/ - return (point)V; -} - -/*<asyxml><function type="side" signature="opposite(vertex)"><code></asyxml>*/ -side opposite(vertex V) -{/*<asyxml></code><documentation>Return the opposite side of vertex 'V'.</documentation></function></asyxml>*/ - return V.t.side(numarray[abs(V.n)]); -} - -/*<asyxml><function type="vertex" signature="opposite(side)"><code></asyxml>*/ -vertex opposite(side side) -{/*<asyxml></code><documentation>Return the opposite vertex of side 'side'.</documentation></function></asyxml>*/ - return side.t.vertex(numarray[abs(side.n) + 1]); -} - -/*<asyxml><function type="point" signature="midpoint(side)"><code></asyxml>*/ -point midpoint(side side) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return midpoint(segment(side)); -} - -/*<asyxml><operator type = "triangle" signature="*(transform,triangle)"><code></asyxml>*/ -triangle operator *(transform T, triangle t) -{/*<asyxml></code><documentation>Provide transform * triangle.</documentation></operator></asyxml>*/ - return triangle(T * t.A, T * t.B, T * t.C); -} - -/*<asyxml><function type="triangle" signature="triangleAbc(real,real,real,real,point)"><code></asyxml>*/ -triangle triangleAbc(real alpha, real b, real c, real angle = 0, point A = (0, 0)) -{/*<asyxml></code><documentation>Return the triangle ABC rotated by 'angle' with BAC = alpha, AC = b and AB = c.</documentation></function></asyxml>*/ - triangle T; - coordsys R = A.coordsys; - T.init(A, A + R.polar(c, radians(angle)), A + R.polar(b, radians(angle + alpha))); - return T; -} - -/*<asyxml><function type="triangle" signature="triangleabc(real,real,real,real,point)"><code></asyxml>*/ -triangle triangleabc(real a, real b, real c, real angle = 0, point A = (0, 0)) -{/*<asyxml></code><documentation>Return the triangle ABC rotated by 'angle' with BC = a, AC = b and AB = c.</documentation></function></asyxml>*/ - triangle T; - coordsys R = A.coordsys; - T.init(A, A + R.polar(c, radians(angle)), A + R.polar(b, radians(angle) + acos((b^2 + c^2 - a^2)/(2 * b * c)))); - return T; -} - -/*<asyxml><function type="triangle" signature="triangle(line,line,line)"><code></asyxml>*/ -triangle triangle(line l1, line l2, line l3) -{/*<asyxml></code><documentation>Return the triangle defined by three line.</documentation></function></asyxml>*/ - point P1, P2, P3; - P1 = intersectionpoint(l1, l2); - P2 = intersectionpoint(l1, l3); - P3 = intersectionpoint(l2, l3); - if(!(defined(P1) && defined(P2) && defined(P3))) abort("triangle: two lines are parallel."); - return triangle(P1, P2, P3); -} - -/*<asyxml><function type="point" signature="foot(vertex)"><code></asyxml>*/ -point foot(vertex V) -{/*<asyxml></code><documentation>Return the endpoint of the altitude from V.</documentation></function></asyxml>*/ - return projection((line)opposite(V)) * ((point)V); -} - -/*<asyxml><function type="point" signature="foot(side)"><code></asyxml>*/ -point foot(side side) -{/*<asyxml></code><documentation>Return the endpoint of the altitude on 'side'.</documentation></function></asyxml>*/ - return projection((line)side) * point(opposite(side)); -} - -/*<asyxml><function type="line" signature="altitude(vertex)"><code></asyxml>*/ -line altitude(vertex V) -{/*<asyxml></code><documentation>Return the altitude passing through 'V'.</documentation></function></asyxml>*/ - return line(point(V), foot(V)); -} - -/*<asyxml><function type="line" signature="altitude(vertex)"><code></asyxml>*/ -line altitude(side side) -{/*<asyxml></code><documentation>Return the altitude cutting 'side'.</documentation></function></asyxml>*/ - return altitude(opposite(side)); -} - -/*<asyxml><function type="point" signature="orthocentercenter(triangle)"><code></asyxml>*/ -point orthocentercenter(triangle t) -{/*<asyxml></code><documentation>Return the orthocenter of the triangle t.</documentation></function></asyxml>*/ - return orthocentercenter(t.A, t.B, t.C); -} - -/*<asyxml><function type="point" signature="centroid(triangle)"><code></asyxml>*/ -point centroid(triangle t) -{/*<asyxml></code><documentation>Return the centroid of the triangle 't'.</documentation></function></asyxml>*/ - return (t.A + t.B + t.C)/3; -} - -/*<asyxml><function type="point" signature="circumcenter(triangle)"><code></asyxml>*/ -point circumcenter(triangle t) -{/*<asyxml></code><documentation>Return the circumcenter of the triangle 't'.</documentation></function></asyxml>*/ - return circumcenter(t.A, t.B, t.C); -} - -/*<asyxml><function type="circle" signature="circle(triangle)"><code></asyxml>*/ -circle circle(triangle t) -{/*<asyxml></code><documentation>Return the circumcircle of the triangle 't'.</documentation></function></asyxml>*/ - return circle(t.A, t.B, t.C); -} - -/*<asyxml><function type="circle" signature="circumcircle(triangle)"><code></asyxml>*/ -circle circumcircle(triangle t) -{/*<asyxml></code><documentation>Return the circumcircle of the triangle 't'.</documentation></function></asyxml>*/ - return circle(t.A, t.B, t.C); -} - -/*<asyxml><function type="point" signature="incenter(triangle)"><code></asyxml>*/ -point incenter(triangle t) -{/*<asyxml></code><documentation>Return the center of the incircle of the triangle 't'.</documentation></function></asyxml>*/ - return incenter(t.A, t.B, t.C); -} - -/*<asyxml><function type="real" signature="inradius(triangle)"><code></asyxml>*/ -real inradius(triangle t) -{/*<asyxml></code><documentation>Return the radius of the incircle of the triangle 't'.</documentation></function></asyxml>*/ - return inradius(t.A, t.B, t.C); -} - -/*<asyxml><function type="circle" signature="incircle(triangle)"><code></asyxml>*/ -circle incircle(triangle t) -{/*<asyxml></code><documentation>Return the the incircle of the triangle 't'.</documentation></function></asyxml>*/ - return incircle(t.A, t.B, t.C); -} - -/*<asyxml><function type="point" signature="excenter(side,triangle)"><code></asyxml>*/ -point excenter(side side) -{/*<asyxml></code><documentation>Return the center of the excircle tangent with the side 'side' of its triangle. - side = 0 means AB, 1 means AC, other means BC. - One must use the predefined sides t.AB, t.AC where 't' is a triangle....</documentation></function></asyxml>*/ - point op; - triangle t = side.t; - int n = numarray[abs(side.n) - 1]; - if(n == 1) op = excenter(t.A, t.B, t.C); - else if(n == 2) op = excenter(t.B, t.C, t.A); - else op = excenter(t.C, t.A, t.B); - return op; -} - -/*<asyxml><function type="real" signature="exradius(side,triangle)"><code></asyxml>*/ -real exradius(side side) -{/*<asyxml></code><documentation>Return radius of the excircle tangent with the side 'side' of its triangle. - side = 0 means AB, 1 means BC, other means CA. - One must use the predefined sides t.AB, t.AC where 't' is a triangle....</documentation></function></asyxml>*/ - real or; - triangle t = side.t; - int n = numarray[abs(side.n) - 1]; - if(n == 1) or = exradius(t.A, t.B, t.C); - else if(n == 2) or = exradius(t.B, t.C, t.A); - else or = exradius(t.A, t.C, t.B); - return or; -} - -/*<asyxml><function type="circle" signature="excircle(side,triangle)"><code></asyxml>*/ -circle excircle(side side) -{/*<asyxml></code><documentation>Return the excircle tangent with the side 'side' of its triangle. - side = 0 means AB, 1 means AC, other means BC. - One must use the predefined sides t.AB, t.AC where 't' is a triangle....</documentation></function></asyxml>*/ - circle oc; - int n = numarray[abs(side.n) - 1]; - triangle t = side.t; - if(n == 1) oc = excircle(t.A, t.B, t.C); - else if(n == 2) oc = excircle(t.B, t.C, t.A); - else oc = excircle(t.A, t.C, t.B); - return oc; -} - -/*<asyxml><struct signature="trilinear"><code></asyxml>*/ -struct trilinear -{/*<asyxml></code><documentation>Trilinear coordinates 'a:b:c' relative to triangle 't'. - <url href = "http://mathworld.wolfram.com/TrilinearCoordinates.html"/></documentation><property type = "real" signature="a,b,c"><code></asyxml>*/ - real a,b,c;/*<asyxml></code><documentation>The trilinear coordinates.</documentation></property><property type = "triangle" signature="t"><code></asyxml>*/ - triangle t;/*<asyxml></code><documentation>The reference triangle.</documentation></property></asyxml>*/ -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="trilinear" signature="trilinear(triangle,real,real,real)"><code></asyxml>*/ -trilinear trilinear(triangle t, real a, real b, real c) -{/*<asyxml></code><documentation>Return the trilinear coordinates relative to 't'. - <url href = "http://mathworld.wolfram.com/TrilinearCoordinates.html"/></documentation></function></asyxml>*/ - trilinear ot; - ot.a = a; ot.b = b; ot.c = c; - ot.t = t; - return ot; -} - -/*<asyxml><function type="trilinear" signature="trilinear(triangle,point)"><code></asyxml>*/ -trilinear trilinear(triangle t, point M) -{/*<asyxml></code><documentation>Return the trilinear coordinates of 'M' relative to 't'. - <url href = "http://mathworld.wolfram.com/TrilinearCoordinates.html"/></documentation></function></asyxml>*/ - trilinear ot; - pair m = locate(M); - int sameside(pair A, pair B, pair m, pair p) - {// Return 1 if 'm' and 'p' are same side of line (AB) else return -1. - pair mil = (A + B)/2; - pair mA = rotate(90, mil) * A; - pair mB = rotate(-90, mil) * A; - return (abs(m - mA) <= abs(m - mB)) == (abs(p - mA) <= abs(p - mB)) ? 1 : -1; - } - real det(pair a, pair b) {return a.x * b.y - a.y * b.x;} - real area(pair a, pair b, pair c){return 0.5 * abs(det(a, b) + det(b, c) + det(c, a));} - pair A = t.A, B = t.B, C = t.C; - real t1 = area(B, C, m), t2 = area(C, A, m), t3 = area(A, B, m); - ot.a = sameside(B, C, A, m) * t1/t.a(); - ot.b = sameside(A, C, B, m) * t2/t.b(); - ot.c = sameside(A, B, C, m) * t3/t.c(); - ot.t = t; - return ot; -} - -/*<asyxml><function type="void" signature="write(trilinear)"><code></asyxml>*/ -void write(trilinear tri) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - write(format("%f : ", tri.a) + format("%f : ", tri.b) + format("%f", tri.c)); -} - -/*<asyxml><function type="point" signature="trilinear(triangle,real,real,real)"><code></asyxml>*/ -point point(trilinear tri) -{/*<asyxml></code><documentation>Return the trilinear coordinates relative to 't'. - <url href = "http://mathworld.wolfram.com/TrilinearCoordinates.html"/></documentation></function></asyxml>*/ - triangle t = tri.t; - return masscenter(0.5 * t.a() * mass(t.A, tri.a), - 0.5 * t.b() * mass(t.B, tri.b), - 0.5 * t.c() * mass(t.C, tri.c)); -} - -/*<asyxml><function type="int[]" signature="tricoef(side)"><code></asyxml>*/ -int[] tricoef(side side) -{/*<asyxml></code><documentation>Return an array of integer (values are 0 or 1) which represents 'side'. - For example, side = t.BC will be represented by {0, 1, 1}.</documentation></function></asyxml>*/ - int[] oi; - int n = numarray[abs(side.n) - 1]; - oi.push((n == 1 || n == 3) ? 1 : 0); - oi.push((n == 1 || n == 2) ? 1 : 0); - oi.push((n == 2 || n == 3) ? 1 : 0); - return oi; -} - -/*<asyxml><operator type = "point" signature="cast(trilinear)"><code></asyxml>*/ -point operator cast(trilinear tri) -{/*<asyxml></code><documentation>Cast trilinear to point. - One may use the routine 'point(trilinear)' to force the casting.</documentation></operator></asyxml>*/ - return point(tri); -} - -/*<asyxml><typedef type = "centerfunction" return = "real" params = "real, real, real"><code></asyxml>*/ -typedef real centerfunction(real, real, real);/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/TriangleCenterFunction.html"/></documentation></typedef></asyxml>*/ - -/*<asyxml><function type="trilinear" signature="trilinear(triangle,centerfunction,real,real,real)"><code></asyxml>*/ -trilinear trilinear(triangle t, centerfunction f, real a = t.a(), real b = t.b(), real c = t.c()) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/TriangleCenterFunction.html"/></documentation></function></asyxml>*/ - return trilinear(t, f(a, b, c), f(b, c, a), f(c, a, b)); -} - -/*<asyxml><function type="point" signature="symmedian(triangle)"><code></asyxml>*/ -point symmedian(triangle t) -{/*<asyxml></code><documentation>Return the symmedian point of 't'.</documentation></function></asyxml>*/ - point A, B, C; - real a = t.a(), b = t.b(), c = t.c(); - A = trilinear(t, 0, b, c); - B = trilinear(t, a, 0, c); - return intersectionpoint(line(t.A, A), line(t.B, B)); -} - -/*<asyxml><function type="point" signature="symmedian(side)"><code></asyxml>*/ -point symmedian(side side) -{/*<asyxml></code><documentation>The symmedian point on the side 'side'.</documentation></function></asyxml>*/ - triangle t = side.t; - int n = numarray[abs(side.n) - 1]; - if(n == 1) return trilinear(t, t.a(), t.b(), 0); - if(n == 2) return trilinear(t, 0, t.b(), t.c()); - return trilinear(t, t.a(), 0, t.c()); -} - -/*<asyxml><function type="line" signature="symmedian(vertex)"><code></asyxml>*/ -line symmedian(vertex V) -{/*<asyxml></code><documentation>Return the symmedian passing through 'V'.</documentation></function></asyxml>*/ - return line(point(V), symmedian(V.t)); -} - -/*<asyxml><function type="triangle" signature="cevian(triangle,point)"><code></asyxml>*/ -triangle cevian(triangle t, point P) -{/*<asyxml></code><documentation>Return the Cevian triangle with respect of 'P' - <url href = "http://mathworld.wolfram.com/CevianTriangle.html"/>.</documentation></function></asyxml>*/ - trilinear tri = trilinear(t, locate(P)); - point A = point(trilinear(t, 0, tri.b, tri.c)); - point B = point(trilinear(t, tri.a, 0, tri.c)); - point C = point(trilinear(t, tri.a, tri.b, 0)); - return triangle(A, B, C); -} - -/*<asyxml><function type="point" signature="cevian(side,point)"><code></asyxml>*/ -point cevian(side side, point P) -{/*<asyxml></code><documentation>Return the Cevian point on 'side' with respect of 'P'.</documentation></function></asyxml>*/ - triangle t = side.t; - trilinear tri = trilinear(t, locate(P)); - int[] s = tricoef(side); - return point(trilinear(t, s[0] * tri.a, s[1] * tri.b, s[2] * tri.c)); -} - -/*<asyxml><function type="line" signature="cevian(vertex,point)"><code></asyxml>*/ -line cevian(vertex V, point P) -{/*<asyxml></code><documentation>Return line passing through 'V' and its Cevian image with respect of 'P'.</documentation></function></asyxml>*/ - return line(point(V), cevian(opposite(V), P)); -} - -/*<asyxml><function type="point" signature="gergonne(triangle)"><code></asyxml>*/ -point gergonne(triangle t) -{/*<asyxml></code><documentation>Return the Gergonne point of 't'.</documentation></function></asyxml>*/ - real f(real a, real b, real c){return 1/(a * (b + c - a));} - return point(trilinear(t, f)); -} - -/*<asyxml><function type="point[]" signature="fermat(triangle)"><code></asyxml>*/ -point[] fermat(triangle t) -{/*<asyxml></code><documentation>Return the Fermat points of 't'.</documentation></function></asyxml>*/ - point[] P; - real A = t.alpha(), B = t.beta(), C = t.gamma(); - P.push(point(trilinear(t, 1/Sin(A + 60), 1/Sin(B + 60), 1/Sin(C + 60)))); - P.push(point(trilinear(t, 1/Sin(A - 60), 1/Sin(B - 60), 1/Sin(C - 60)))); - return P; -} - -/*<asyxml><function type="point" signature="isotomicconjugate(triangle,point)"><code></asyxml>*/ -point isotomicconjugate(triangle t, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsotomicConjugate.html"/></documentation></function></asyxml>*/ - if(!inside(t.Path(), locate(M))) abort("isotomic: the point must be inside the triangle."); - trilinear tr = trilinear(t, M); - return point(trilinear(t, 1/(t.a()^2 * tr.a), 1/(t.b()^2 * tr.b), 1/(t.c()^2 * tr.c))); -} - -/*<asyxml><function type="line" signature="isotomic(vertex,point)"><code></asyxml>*/ -line isotomic(vertex V, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsotomicConjugate.html"/>.</documentation></function></asyxml>*/ - side op = opposite(V); - return line(V, rotate(180, midpoint(op)) * cevian(op, M)); -} - -/*<asyxml><function type="point" signature="isotomic(side,point)"><code></asyxml>*/ -point isotomic(side side, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsotomicConjugate.html"/></documentation></function></asyxml>*/ - return intersectionpoint(isotomic(opposite(side), M), side); -} - -/*<asyxml><function type="triangle" signature="isotomic(triangle,point)"><code></asyxml>*/ -triangle isotomic(triangle t, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsotomicConjugate.html"/></documentation></function></asyxml>*/ - return triangle(isotomic(t.BC, M), isotomic(t.CA, M), isotomic(t.AB, M)); -} - -/*<asyxml><function type="point" signature="isogonalconjugate(triangle,point)"><code></asyxml>*/ -point isogonalconjugate(triangle t, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsogonalConjugate.html"/></documentation></function></asyxml>*/ - trilinear tr = trilinear(t, M); - return point(trilinear(t, 1/tr.a, 1/tr.b, 1/tr.c)); -} - -/*<asyxml><function type="point" signature="isogonal(side,point)"><code></asyxml>*/ -point isogonal(side side, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsogonalConjugate.html"/></documentation></function></asyxml>*/ - return cevian(side, isogonalconjugate(side.t, M)); -} - -/*<asyxml><function type="line" signature="isogonal(vertex,point)"><code></asyxml>*/ -line isogonal(vertex V, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsogonalConjugate.html"/></documentation></function></asyxml>*/ - return line(V, isogonal(opposite(V), M)); -} - -/*<asyxml><function type="triangle" signature="isogonal(triangle,point)"><code></asyxml>*/ -triangle isogonal(triangle t, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/IsogonalConjugate.html"/></documentation></function></asyxml>*/ - return triangle(isogonal(t.BC, M), isogonal(t.CA, M), isogonal(t.AB, M)); -} - -/*<asyxml><function type="triangle" signature="pedal(triangle,point)"><code></asyxml>*/ -triangle pedal(triangle t, point M) -{/*<asyxml></code><documentation>Return the pedal triangle of 'M' in 't'. - <url href = "http://mathworld.wolfram.com/PedalTriangle.html"/></documentation></function></asyxml>*/ - return triangle(projection(t.BC) * M, projection(t.AC) * M, projection(t.AB) * M); -} - -/*<asyxml><function type="triangle" signature="pedal(triangle,point)"><code></asyxml>*/ -line pedal(side side, point M) -{/*<asyxml></code><documentation>Return the pedal line of 'M' cutting 'side'. - <url href = "http://mathworld.wolfram.com/PedalTriangle.html"/></documentation></function></asyxml>*/ - return line(M, projection(side) * M); -} - -/*<asyxml><function type="triangle" signature="antipedal(triangle,point)"><code></asyxml>*/ -triangle antipedal(triangle t, point M) -{/*<asyxml></code><documentation><url href = "http://mathworld.wolfram.com/AntipedalTriangle.html"/></documentation></function></asyxml>*/ - trilinear Tm = trilinear(t, M); - real a = Tm.a, b = Tm.b, c = Tm.c; - real CA = Cos(t.alpha()), CB = Cos(t.beta()), CC = Cos(t.gamma()); - point A = trilinear(t, -(b + a * CC) * (c + a * CB), (c + a * CB) * (a + b * CC), (b + a * CC) * (a + c * CB)); - point B = trilinear(t, (c + b * CA) * (b + a * CC), -(c + b * CA) * (a + b * CC), (a + b * CC) * (b + c * CA)); - point C = trilinear(t, (b + c * CA) * (c + a * CB), (a + c * CB) * (c + b * CA), -(a + c * CB) * (b + c * CA)); - return triangle(A, B, C); -} - -/*<asyxml><function type="triangle" signature="extouch(triangle)"><code></asyxml>*/ -triangle extouch(triangle t) -{/*<asyxml></code><documentation>Return the extouch triangle of the triangle 't'. - The extouch triangle of 't' is the triangle formed by the points - of tangency of a triangle 't' with its excircles.</documentation></function></asyxml>*/ - point A, B, C; - real a = t.a(), b = t.b(), c = t.c(); - A = trilinear(t, 0, (a - b + c)/b, (a + b - c)/c); - B = trilinear(t, (-a + b + c)/a, 0, (a + b - c)/c); - C = trilinear(t, (-a + b + c)/a, (a - b + c)/b, 0); - return triangle(A, B, C); -} - -/*<asyxml><function type="triangle" signature="extouch(triangle)"><code></asyxml>*/ -triangle incentral(triangle t) -{/*<asyxml></code><documentation>Return the incentral triangle of the triangle 't'. - It is the triangle whose vertices are determined by the intersections of the - reference triangle's angle bisectors with the respective opposite sides.</documentation></function></asyxml>*/ - point A, B, C; - // real a = t.a(), b = t.b(), c = t.c(); - A = trilinear(t, 0, 1, 1); - B = trilinear(t, 1, 0, 1); - C = trilinear(t, 1, 1, 0); - return triangle(A, B, C); -} - -/*<asyxml><function type="triangle" signature="extouch(side)"><code></asyxml>*/ -triangle extouch(side side) -{/*<asyxml></code><documentation>Return the triangle formed by the points of tangency of the triangle referenced by 'side' with its excircles. - One vertex of the returned triangle is on the segment 'side'.</documentation></function></asyxml>*/ - triangle t = side.t; - transform p1 = projection((line)t.AB); - transform p2 = projection((line)t.AC); - transform p3 = projection((line)t.BC); - point EP = excenter(side); - return triangle(p3 * EP, p2 * EP, p1 * EP); -} - -/*<asyxml><function type="point" signature="bisectorpoint(side)"><code></asyxml>*/ -point bisectorpoint(side side) -{/*<asyxml></code><documentation>The intersection point of the angle bisector from the - opposite point of 'side' with the side 'side'.</documentation></function></asyxml>*/ - triangle t = side.t; - int n = numarray[abs(side.n) - 1]; - if(n == 1) return trilinear(t, 1, 1, 0); - if(n == 2) return trilinear(t, 0, 1, 1); - return trilinear(t, 1, 0, 1); -} - -/*<asyxml><function type="line" signature="bisector(vertex,real)"><code></asyxml>*/ -line bisector(vertex V, real angle = 0) -{/*<asyxml></code><documentation>Return the interior bisector passing through 'V' rotated by angle (in degrees) - around 'V'.</documentation></function></asyxml>*/ - return rotate(angle, point(V)) * line(point(V), incenter(V.t)); -} - -/*<asyxml><function type="line" signature="bisector(side)"><code></asyxml>*/ -line bisector(side side) -{/*<asyxml></code><documentation>Return the bisector of the line segment 'side'.</documentation></function></asyxml>*/ - return bisector(segment(side)); -} - -/*<asyxml><function type="point" signature="intouch(side)"><code></asyxml>*/ -point intouch(side side) -{/*<asyxml></code><documentation>The point of tangency on the side 'side' of its incircle.</documentation></function></asyxml>*/ - triangle t = side.t; - real a = t.a(), b = t.b(), c = t.c(); - int n = numarray[abs(side.n) - 1]; - if(n == 1) return trilinear(t, b * c/(-a + b + c), a * c/(a - b + c), 0); - if(n == 2) return trilinear(t, 0, a * c/(a - b + c), a * b/(a + b - c)); - return trilinear(t, b * c/(-a + b + c), 0, a * b/(a + b - c)); -} - -/*<asyxml><function type="triangle" signature="intouch(triangle)"><code></asyxml>*/ -triangle intouch(triangle t) -{/*<asyxml></code><documentation>Return the intouch triangle of the triangle 't'. - The intouch triangle of 't' is the triangle formed by the points - of tangency of a triangle 't' with its incircles.</documentation></function></asyxml>*/ - point A, B, C; - real a = t.a(), b = t.b(), c = t.c(); - A = trilinear(t, 0, a * c/(a - b + c), a * b/(a + b - c)); - B = trilinear(t, b * c/(-a + b + c), 0, a * b/(a + b - c)); - C = trilinear(t, b * c/(-a + b + c), a * c/(a - b + c), 0); - return triangle(A, B, C); -} - -/*<asyxml><function type="triangle" signature="tangential(triangle)"><code></asyxml>*/ -triangle tangential(triangle t) -{/*<asyxml></code><documentation>Return the tangential triangle of the triangle 't'. - The tangential triangle of 't' is the triangle formed by the lines - tangent to the circumcircle of the given triangle 't' at its vertices.</documentation></function></asyxml>*/ - point A, B, C; - real a = t.a(), b = t.b(), c = t.c(); - A = trilinear(t, -a, b, c); - B = trilinear(t, a, -b, c); - C = trilinear(t, a, b, -c); - return triangle(A, B, C); -} - -/*<asyxml><function type="triangle" signature="medial(triangle t)"><code></asyxml>*/ -triangle medial(triangle t) -{/*<asyxml></code><documentation>Return the triangle whose vertices are midpoints of the sides of 't'.</documentation></function></asyxml>*/ - return triangle(midpoint(t.BC), midpoint(t.AC), midpoint(t.AB)); -} - -/*<asyxml><function type="line" signature="median(vertex)"><code></asyxml>*/ -line median(vertex V) -{/*<asyxml></code><documentation>Return median from 'V'.</documentation></function></asyxml>*/ - return line(point(V), midpoint(segment(opposite(V)))); -} - -/*<asyxml><function type="line" signature="median(side)"><code></asyxml>*/ -line median(side side) -{/*<asyxml></code><documentation>Return median from the opposite vertex of 'side'.</documentation></function></asyxml>*/ - return median(opposite(side)); -} - -/*<asyxml><function type="triangle" signature="orthic(triangle)"><code></asyxml>*/ -triangle orthic(triangle t) -{/*<asyxml></code><documentation>Return the triangle whose vertices are endpoints of the altitudes from each of the vertices of 't'.</documentation></function></asyxml>*/ - return triangle(foot(t.BC), foot(t.AC), foot(t.AB)); -} - -/*<asyxml><function type="triangle" signature="symmedial(triangle)"><code></asyxml>*/ -triangle symmedial(triangle t) -{/*<asyxml></code><documentation>Return the symmedial triangle of 't'.</documentation></function></asyxml>*/ - point A, B, C; - real a = t.a(), b = t.b(), c = t.c(); - A = trilinear(t, 0, b, c); - B = trilinear(t, a, 0, c); - C = trilinear(t, a, b, 0); - return triangle(A, B, C); -} - -/*<asyxml><function type="triangle" signature="anticomplementary(triangle)"><code></asyxml>*/ -triangle anticomplementary(triangle t) -{/*<asyxml></code><documentation>Return the triangle which has the given triangle 't' as its medial triangle.</documentation></function></asyxml>*/ - real a = t.a(), b = t.b(), c = t.c(); - real ab = a * b, bc = b * c, ca = c * a; - point A = trilinear(t, -bc, ca, ab); - point B = trilinear(t, bc, -ca, ab); - point C = trilinear(t, bc, ca, -ab); - return triangle(A, B, C); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(triangle,line,bool)"><code></asyxml>*/ -point[] intersectionpoints(triangle t, line l, bool extended = false) -{/*<asyxml></code><documentation>Return the intersection points. - If 'extended' is true, the sides are lines else the sides are segments. - intersectionpoints(line, triangle, bool) is also defined.</documentation></function></asyxml>*/ - point[] OP; - void addpoint(point P) - { - if(defined(P)) { - bool exist = false; - for (int i = 0; i < OP.length; ++i) { - if(P == OP[i]) {exist = true; break;} - } - if(!exist) OP.push(P); - } - } - if(extended) { - for (int i = 1; i <= 3; ++i) { - addpoint(intersectionpoint(t.line(i), l)); - } - } else { - for (int i = 1; i <= 3; ++i) { - addpoint(intersectionpoint((segment)t.line(i), l)); - } - } - return OP; -} - -point[] intersectionpoints(line l, triangle t, bool extended = false) -{ - return intersectionpoints(t, l, extended); -} - -/*<asyxml><function type="vector" signature="dir(vertex)"><code></asyxml>*/ -vector dir(vertex V) -{/*<asyxml></code><documentation>The direction (towards the outside of the triangle) of the interior angle bisector of 'V'.</documentation></function></asyxml>*/ - triangle t = V.t; - if(V.n == 1) return vector(defaultcoordsys, (-dir(t.A--t.B, t.A--t.C))); - if(V.n == 2) return vector(defaultcoordsys, (-dir(t.B--t.A, t.B--t.C))); - return vector(defaultcoordsys, (-dir(t.C--t.A, t.C--t.B))); -} - -/*<asyxml><function type="void" signature="lvoid label(picture,Label,vertex,pair,real,pen,filltype)"><code></asyxml>*/ -void label(picture pic = currentpicture, Label L, vertex V, - pair align = dir(V), - real alignFactor = 1, - pen p = nullpen, filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw 'L' on picture 'pic' at vertex 'V' aligned by 'alignFactor * align'.</documentation></function></asyxml>*/ - label(pic, L, locate(point(V)), alignFactor * align, p, filltype); -} - -/*<asyxml><function type="void" signature="label(picture,Label,Label,Label,triangle,real,real,pen,filltype)"><code></asyxml>*/ -void label(picture pic = currentpicture, Label LA = "$A$", - Label LB = "$B$", Label LC = "$C$", - triangle t, - real alignAngle = 0, - real alignFactor = 1, - pen p = nullpen, filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw labels LA, LB and LC aligned in the rotated (by 'alignAngle' in degrees) direction - (towards the outside of the triangle) of the interior angle bisector of vertices. - One can individually modify the alignment by setting the Label parameter 'align'.</documentation></function></asyxml>*/ - Label lla = LA.copy(); - lla.align(lla.align, rotate(alignAngle) * locate(dir(t.VA))); - label(pic, LA, t.VA, align = lla.align.dir, alignFactor = alignFactor, p, filltype); - Label llb = LB.copy(); - llb.align(llb.align, rotate(alignAngle) * locate(dir(t.VB))); - label(pic, llb, t.VB, align = llb.align.dir, alignFactor = alignFactor, p, filltype); - Label llc = LC.copy(); - llc.align(llc.align, rotate(alignAngle) * locate(dir(t.VC))); - label(pic, llc, t.VC, align = llc.align.dir, alignFactor = alignFactor, p, filltype); -} - -/*<asyxml><function type="void" signature="show(picture,Label,Label,Label,Label,Label,Label,triangle,pen,filltype)"><code></asyxml>*/ -void show(picture pic = currentpicture, - Label LA = "$A$", Label LB = "$B$", Label LC = "$C$", - Label La = "$a$", Label Lb = "$b$", Label Lc = "$c$", - triangle t, pen p = currentpen, filltype filltype = NoFill) -{/*<asyxml></code><documentation>Draw triangle and labels of sides and vertices.</documentation></function></asyxml>*/ - pair a = locate(t.A), b = locate(t.B), c = locate(t.C); - draw(pic, a--b--c--cycle, p); - label(pic, LA, a, -dir(a--b, a--c), p, filltype); - label(pic, LB, b, -dir(b--a, b--c), p, filltype); - label(pic, LC, c, -dir(c--a, c--b), p, filltype); - pair aligna = I * unit(c - b), alignb = I * unit(c - a), alignc = I * unit(b - a); - pair mAB = locate(midpoint(t.AB)), mAC = locate(midpoint(t.AC)), mBC = locate(midpoint(t.BC)); - label(pic, La, b--c, align = rotate(dot(a - mBC, aligna) > 0 ? 180 :0) * aligna, p); - label(pic, Lb, a--c, align = rotate(dot(b - mAC, alignb) > 0 ? 180 :0) * alignb, p); - label(pic, Lc, a--b, align = rotate(dot(c - mAB, alignc) > 0 ? 180 :0) * alignc, p); -} - -/*<asyxml><function type="void" signature="draw(picture,triangle,pen,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, triangle t, pen p = currentpen, marker marker = nomarker) -{/*<asyxml></code><documentation>Draw sides of the triangle 't' on picture 'pic' using pen 'p'.</documentation></function></asyxml>*/ - draw(pic, t.Path(), p, marker); -} - -/*<asyxml><function type="void" signature="draw(picture,triangle[],pen,marker)"><code></asyxml>*/ -void draw(picture pic = currentpicture, triangle[] t, pen p = currentpen, marker marker = nomarker) -{/*<asyxml></code><documentation>Draw sides of the triangles 't' on picture 'pic' using pen 'p'.</documentation></function></asyxml>*/ - for(int i = 0; i < t.length; ++i) draw(pic, t[i], p, marker); -} - -/*<asyxml><function type="void" signature="drawline(picture,triangle,pen)"><code></asyxml>*/ -void drawline(picture pic = currentpicture, triangle t, pen p = currentpen) -{/*<asyxml></code><documentation>Draw lines of the triangle 't' on picture 'pic' using pen 'p'.</documentation></function></asyxml>*/ - draw(t, p); - draw(pic, line(t.A, t.B), p); - draw(pic, line(t.A, t.C), p); - draw(pic, line(t.B, t.C), p); -} - -/*<asyxml><function type="void" signature="dot(picture,triangle,pen)"><code></asyxml>*/ -void dot(picture pic = currentpicture, triangle t, pen p = currentpen) -{/*<asyxml></code><documentation>Draw a dot at each vertex of 't'.</documentation></function></asyxml>*/ - dot(pic, t.A^^t.B^^t.C, p); -} -// *.......................TRIANGLES.......................* -// *=======================================================* - -// *=======================================================* -// *.......................INVERSIONS......................* -/*<asyxml><function type="point" signature="inverse(real k,point,point)"><code></asyxml>*/ -point inverse(real k, point A, point M) -{/*<asyxml></code><documentation>Return the inverse point of 'M' with respect to point A and inversion radius 'k'.</documentation></function></asyxml>*/ - return A + k/conj(M - A); -} - -/*<asyxml><function type="point" signature="radicalcenter(circle,circle)"><code></asyxml>*/ -point radicalcenter(circle c1, circle c2) -{/*<asyxml></code><documentation><url href = "http://fr.wikipedia.org/wiki/Puissance_d'un_point_par_rapport_%C3%A0_un_cercle"/></documentation></function></asyxml>*/ - point[] P = standardizecoordsys(c1.C, c2.C); - real k = c1.r^2 - c2.r^2; - pair C1 = locate(c1.C); - pair C2 = locate(c2.C); - pair oop = C2 - C1; - pair K = (abs(oop) == 0) ? - (infinity, infinity) : - midpoint(C1--C2) + 0.5 * k * oop/dot(oop, oop); - return point(P[0].coordsys, K/P[0].coordsys); -} - -/*<asyxml><function type="line" signature="radicalline(circle,circle)"><code></asyxml>*/ -line radicalline(circle c1, circle c2) -{/*<asyxml></code><documentation><url href = "http://fr.wikipedia.org/wiki/Puissance_d'un_point_par_rapport_%C3%A0_un_cercle"/></documentation></function></asyxml>*/ - if (c1.C == c2.C) abort("radicalline: the centers must be distinct"); - return perpendicular(radicalcenter(c1, c2), line(c1.C, c2.C)); -} - -/*<asyxml><function type="point" signature="radicalcenter(circle,circle,circle)"><code></asyxml>*/ -point radicalcenter(circle c1, circle c2, circle c3) -{/*<asyxml></code><documentation><url href = "http://fr.wikipedia.org/wiki/Puissance_d'un_point_par_rapport_%C3%A0_un_cercle"/></documentation></function></asyxml>*/ - return intersectionpoint(radicalline(c1, c2), radicalline(c1, c3)); -} - -/*<asyxml><struct signature="inversion"><code></asyxml>*/ -struct inversion -{/*<asyxml></code><documentation>http://mathworld.wolfram.com/Inversion.html</documentation></asyxml>*/ - point C; - real k; -}/*<asyxml></struct></asyxml>*/ - -/*<asyxml><function type="inversion" signature="inversion(real,point)"><code></asyxml>*/ -inversion inversion(real k, point C) -{/*<asyxml></code><documentation>Return the inversion with respect to 'C' having inversion radius 'k'.</documentation></function></asyxml>*/ - inversion oi; - oi.k = k; - oi.C = C; - return oi; -} -/*<asyxml><function type="inversion" signature="inversion(real,point)"><code></asyxml>*/ -inversion inversion(point C, real k) -{/*<asyxml></code><documentation>Return the inversion with respect to 'C' having inversion radius 'k'.</documentation></function></asyxml>*/ - return inversion(k, C); -} - -/*<asyxml><function type="inversion" signature="inversion(circle,circle)"><code></asyxml>*/ -inversion inversion(circle c1, circle c2, real sgn = 1) -{/*<asyxml></code><documentation>Return the inversion which transforms 'c1' to - . 'c2' and positive inversion radius if 'sgn > 0'; - . 'c2' and negative inversion radius if 'sgn < 0'; - . 'c1' and 'c2' to 'c2' if 'sgn = 0'.</documentation></function></asyxml>*/ - if(sgn == 0) { - point O = radicalcenter(c1, c2); - return inversion(O^c1, O); - } - real a = abs(c1.r/c2.r); - if(sgn > 0) { - point O = c1.C + a/abs(1 - a) * (c2.C - c1.C); - return inversion(a * abs(abs(O - c2.C)^2 - c2.r^2), O); - } - point O = c1.C + a/abs(1 + a) * (c2.C - c1.C); - return inversion(-a * abs(abs(O - c2.C)^2 - c2.r^2), O); -} - -/*<asyxml><function type="inversion" signature="inversion(circle,circle,circle)"><code></asyxml>*/ -inversion inversion(circle c1, circle c2, circle c3) -{/*<asyxml></code><documentation>Return the inversion which transform 'c1' to 'c1', 'c2' to 'c2' and 'c3' to 'c3'.</documentation></function></asyxml>*/ - point Rc = radicalcenter(c1, c2, c3); - return inversion(Rc, Rc^c1); -} - -circle operator cast(inversion i){return circle(i.C, sgn(i.k) * sqrt(abs(i.k)));} -/*<asyxml><function type="circle" signature="circle(inversion)"><code></asyxml>*/ -circle circle(inversion i) -{/*<asyxml></code><documentation>Return the inversion circle of 'i'.</documentation></function></asyxml>*/ - return i; -} - -inversion operator cast(circle c) -{ - return inversion(sgn(c.r) * c.r^2, c.C); -} -/*<asyxml><function type="inversion" signature="inversion(circle)"><code></asyxml>*/ -inversion inversion(circle c) -{/*<asyxml></code><documentation>Return the inversion represented by the circle of 'c'.</documentation></function></asyxml>*/ - return c; -} - -/*<asyxml><operator type = "point" signature="*(inversion,point)"><code></asyxml>*/ -point operator *(inversion i, point P) -{/*<asyxml></code><documentation>Provide inversion * point.</documentation></operator></asyxml>*/ - return inverse(i.k, i.C, P); -} - -void lineinversion() -{ - warning("lineinversion", "the inversion of the line is not a circle. -The returned circle has an infinite radius, circle.l has been set."); -} - - -/*<asyxml><function type="circle" signature="inverse(real,point,line)"><code></asyxml>*/ -circle inverse(real k, point A, line l) -{/*<asyxml></code><documentation>Return the inverse circle of 'l' with - respect to point 'A' and inversion radius 'k'.</documentation></function></asyxml>*/ - if(A @ l) { - lineinversion(); - circle C = circle(A, infinity); - C.l = l; - return C; - } - point Ap = inverse(k, A, l.A), Bp = inverse(k, A, l.B); - return circle(A, Ap, Bp); -} - -/*<asyxml><operator type = "circle" signature="*(inversion,line)"><code></asyxml>*/ -circle operator *(inversion i, line l) -{/*<asyxml></code><documentation>Provide inversion * line for lines that don't pass through the inversion center.</documentation></operator></asyxml>*/ - return inverse(i.k, i.C, l); -} - -/*<asyxml><function type="circle" signature="inverse(real,point,circle)"><code></asyxml>*/ -circle inverse(real k, point A, circle c) -{/*<asyxml></code><documentation>Return the inverse circle of 'c' with - respect to point A and inversion radius 'k'.</documentation></function></asyxml>*/ - if(degenerate(c)) return inverse(k, A, c.l); - if(A @ c) { - lineinversion(); - point M = rotate(180, c.C) * A, Mp = rotate(90, c.C) * A; - circle oc = circle(A, infinity); - oc.l = line(inverse(k, A, M), inverse(k, A, Mp)); - return oc; - } - point[] P = standardizecoordsys(A, c.C); - real s = k/((P[1].x - P[0].x)^2 + (P[1].y - P[0].y)^2 - c.r^2); - return circle(P[0] + s * (P[1]-P[0]), abs(s) * c.r); -} - -/*<asyxml><operator type = "circle" signature="*(inversion,circle)"><code></asyxml>*/ -circle operator *(inversion i, circle c) -{/*<asyxml></code><documentation>Provide inversion * circle.</documentation></operator></asyxml>*/ - return inverse(i.k, i.C, c); -} -// *.......................INVERSIONS......................* -// *=======================================================* - -// *=======================================================* -// *........................FOOTER.........................* -/*<asyxml><function type="point[]" signature="intersectionpoints(line,circle)"><code></asyxml>*/ -point[] intersectionpoints(line l, circle c) -{/*<asyxml></code><documentation>Note that the line 'l' may be a segment by casting. - intersectionpoints(circle, line) is also defined.</documentation></function></asyxml>*/ - if(degenerate(c)) return new point[]{intersectionpoint(l, c.l)}; - point[] op; - coordsys R = samecoordsys(l.A, c.C) ? - l.A.coordsys : defaultcoordsys; - coordsys Rp = defaultcoordsys; - circle cc = circle(changecoordsys(Rp, c.C), c.r); - point proj = projection(l) * c.C; - if(proj @ cc) { // The line is a tangente of the circle. - if(proj @ l) op.push(proj);// line may be a segement... - } else { - coordsys Rc = cartesiansystem(c.C, (1, 0), (0, 1)); - line ll = changecoordsys(Rc, l); - pair[] P = intersectionpoints(ll.A.coordinates, ll.B.coordinates, - 1, 0, 1, 0, 0, -c.r^2); - for (int i = 0; i < P.length; ++i) { - point inter = changecoordsys(R, point(Rc, P[i])); - if(inter @ l) op.push(inter); - } - } - return op; -} - -point[] intersectionpoints(circle c, line l) -{ - return intersectionpoints(l, c); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(line,ellipse)"><code></asyxml>*/ -point[] intersectionpoints(line l, ellipse el) -{/*<asyxml></code><documentation>Note that the line 'l' may be a segment by casting. - intersectionpoints(ellipse, line) is also defined.</documentation></function></asyxml>*/ - if(el.e == 0) return intersectionpoints(l, (circle)el); - if(degenerate(el)) return new point[]{intersectionpoint(l, el.l)}; - point[] op; - coordsys R = samecoordsys(l.A, el.C) ? l.A.coordsys : defaultcoordsys; - coordsys Rp = defaultcoordsys; - line ll = changecoordsys(Rp, l); - ellipse ell = changecoordsys(Rp, el); - circle C = circle(ell.C, ell.a); - point[] Ip = intersectionpoints(ll, C); - if (Ip.length > 0 && - (perpendicular(ll, line(ell.F1, Ip[0])) || - perpendicular(ll, line(ell.F2, Ip[0])))) { - // http://www.mathcurve.com/courbes2d/ellipse/ellipse.shtml - // Définition tangentielle par antipodaire de cercle. - // 'l' is a tangent of 'el' - transform t = scale(el.a/el.b, el.F1, el.F2, el.C, rotate(90, el.C) * el.F1); - point inter = inverse(t) * intersectionpoints(C, t * ll)[0]; - if(inter @ l) op.push(inter); - } else { - coordsys Rc = canonicalcartesiansystem(el); - line ll = changecoordsys(Rc, l); - pair[] P = intersectionpoints(ll.A.coordinates, ll.B.coordinates, - 1/el.a^2, 0, 1/el.b^2, 0, 0, -1); - for (int i = 0; i < P.length; ++i) { - point inter = changecoordsys(R, point(Rc, P[i])); - if(inter @ l) op.push(inter); - } - } - return op; -} - -point[] intersectionpoints(ellipse el, line l) -{ - return intersectionpoints(l, el); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(line,parabola)"><code></asyxml>*/ -point[] intersectionpoints(line l, parabola p) -{/*<asyxml></code><documentation>Note that the line 'l' may be a segment by casting. - intersectionpoints(parabola, line) is also defined.</documentation></function></asyxml>*/ - point[] op; - coordsys R = coordsys(p); - bool tgt = false; - line ll = changecoordsys(R, l), - lv = parallel(p.V, p.D); - point M = intersectionpoint(lv, ll), tgtp; - if(finite(M)) {// Test if 'l' is tangent to 'p' - line l1 = bisector(line(M, p.F)); - line l2 = rotate(90, M) * lv; - point P = intersectionpoint(l1, l2); - tgtp = rotate(180, P) * p.F; - tgt = (tgtp @ l); - } - if(tgt) { - if(tgtp @ l) op.push(tgtp); - } else { - real[] eq = changecoordsys(defaultcoordsys, equation(p)).a; - pair[] tp = intersectionpoints(locate(l.A), locate(l.B), eq); - point inter; - for (int i = 0; i < tp.length; ++i) { - inter = point(R, tp[i]/R); - if(inter @ l) op.push(inter); - } - } - return op; -} - -point[] intersectionpoints(parabola p, line l) -{ - return intersectionpoints(l, p); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(line,hyperbola)"><code></asyxml>*/ -point[] intersectionpoints(line l, hyperbola h) -{/*<asyxml></code><documentation>Note that the line 'l' may be a segment by casting. - intersectionpoints(hyperbola, line) is also defined.</documentation></function></asyxml>*/ - point[] op; - coordsys R = coordsys(h); - point A = intersectionpoint(l, h.A1), B = intersectionpoint(l, h.A2); - point M = midpoint(segment(A, B)); - bool tgt = M @ h; - if(tgt) { - if(M @ l) op.push(M); - } else { - real[] eq = changecoordsys(defaultcoordsys, equation(h)).a; - pair[] tp = intersectionpoints(locate(l.A), locate(l.B), eq); - point inter; - for (int i = 0; i < tp.length; ++i) { - inter = point(R, tp[i]/R); - if(inter @ l) op.push(inter); - } - } - return op; -} - -point[] intersectionpoints(hyperbola h, line l) -{ - return intersectionpoints(l, h); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(line,conic)"><code></asyxml>*/ -point[] intersectionpoints(line l, conic co) -{/*<asyxml></code><documentation>Note that the line 'l' may be a segment by casting. - intersectionpoints(conic, line) is also defined.</documentation></function></asyxml>*/ - point[] op; - if(co.e < 1) op = intersectionpoints((ellipse)co, l); - else - if(co.e == 1) op = intersectionpoints((parabola)co, l); - else op = intersectionpoints((hyperbola)co, l); - return op; -} - -point[] intersectionpoints(conic co, line l) -{ - return intersectionpoints(l, co); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(conic,conic)"><code></asyxml>*/ -point[] intersectionpoints(conic co1, conic co2) -{/*<asyxml></code><documentation>Return the intersection points of the two conics.</documentation></function></asyxml>*/ - if(degenerate(co1)) return intersectionpoints(co1.l[0], co2); - if(degenerate(co2)) return intersectionpoints(co1, co2.l[0]); - return intersectionpoints(equation(co1), equation(co2)); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(triangle,conic,bool)"><code></asyxml>*/ -point[] intersectionpoints(triangle t, conic co, bool extended = false) -{/*<asyxml></code><documentation>Return the intersection points. - If 'extended' is true, the sides are lines else the sides are segments. - intersectionpoints(conic, triangle, bool) is also defined.</documentation></function></asyxml>*/ - if(degenerate(co)) return intersectionpoints(t, co.l[0], extended); - point[] OP; - void addpoint(point P[]) - { - for (int i = 0; i < P.length; ++i) { - if(defined(P[i])) { - bool exist = false; - for (int j = 0; j < OP.length; ++j) { - if(P[i] == OP[j]) {exist = true; break;} - } - if(!exist) OP.push(P[i]); - }}} - if(extended) { - for (int i = 1; i <= 3; ++i) { - addpoint(intersectionpoints(t.line(i), co)); - } - } else { - for (int i = 1; i <= 3; ++i) { - addpoint(intersectionpoints((segment)t.line(i), co)); - } - } - return OP; -} - -point[] intersectionpoints(conic co, triangle t, bool extended = false) -{ - return intersectionpoints(t, co, extended); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(ellipse,ellipse)"><code></asyxml>*/ -point[] intersectionpoints(ellipse a, ellipse b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - // if(degenerate(a)) return intersectionpoints(a.l, b); - // if(degenerate(b)) return intersectionpoints(a, b.l);; - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(ellipse,circle)"><code></asyxml>*/ -point[] intersectionpoints(ellipse a, circle b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - // if(degenerate(a)) return intersectionpoints(a.l, b); - // if(degenerate(b)) return intersectionpoints(a, b.l);; - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(circle,ellipse)"><code></asyxml>*/ -point[] intersectionpoints(circle a, ellipse b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints(b, a); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(ellipse,parabola)"><code></asyxml>*/ -point[] intersectionpoints(ellipse a, parabola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - // if(degenerate(a)) return intersectionpoints(a.l, b); - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(parabola,ellipse)"><code></asyxml>*/ -point[] intersectionpoints(parabola a, ellipse b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints(b, a); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(ellipse,hyperbola)"><code></asyxml>*/ -point[] intersectionpoints(ellipse a, hyperbola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - // if(degenerate(a)) return intersectionpoints(a.l, b); - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(hyperbola,ellipse)"><code></asyxml>*/ -point[] intersectionpoints(hyperbola a, ellipse b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints(b, a); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(circle,parabola)"><code></asyxml>*/ -point[] intersectionpoints(circle a, parabola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(parabola,circle)"><code></asyxml>*/ -point[] intersectionpoints(parabola a, circle b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(circle,hyperbola)"><code></asyxml>*/ -point[] intersectionpoints(circle a, hyperbola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(hyperbola,circle)"><code></asyxml>*/ -point[] intersectionpoints(hyperbola a, circle b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(parabola,parabola)"><code></asyxml>*/ -point[] intersectionpoints(parabola a, parabola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(parabola,hyperbola)"><code></asyxml>*/ -point[] intersectionpoints(parabola a, hyperbola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(hyperbola,parabola)"><code></asyxml>*/ -point[] intersectionpoints(hyperbola a, parabola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} -/*<asyxml><function type="point[]" signature="intersectionpoints(hyperbola,hyperbola)"><code></asyxml>*/ -point[] intersectionpoints(hyperbola a, hyperbola b) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - return intersectionpoints((conic)a, (conic)b); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(circle,circle)"><code></asyxml>*/ -point[] intersectionpoints(circle c1, circle c2) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - if(degenerate(c1)) - return degenerate(c2) ? - new point[]{intersectionpoint(c1.l, c2.l)} : intersectionpoints(c1.l, c2); - if(degenerate(c2)) return intersectionpoints(c1, c2.l); - return (c1.C == c2.C) ? - new point[] : - intersectionpoints(radicalline(c1, c2), c1); -} - -/*<asyxml><function type="line" signature="tangent(circle,abscissa)"><code></asyxml>*/ -line tangent(circle c, abscissa x) -{/*<asyxml></code><documentation>Return the tangent of 'c' at 'point(c, x)'.</documentation></function></asyxml>*/ - if(c.r == 0) abort("tangent: a circle with a radius equals zero has no tangent."); - point M = point(c, x); - return line(rotate(90, M) * c.C, M); -} - -/*<asyxml><function type="line[]" signature="tangents(circle,point)"><code></asyxml>*/ -line[] tangents(circle c, point M) -{/*<asyxml></code><documentation>Return the tangents of 'c' passing through 'M'.</documentation></function></asyxml>*/ - line[] ol; - if(inside(c, M)) return ol; - if(M @ c) { - ol.push(tangent(c, relabscissa(c, M))); - } else { - circle cc = circle(c.C, M); - point[] inter = intersectionpoints(c, cc); - for (int i = 0; i < inter.length; ++i) - ol.push(tangents(c, inter[i])[0]); - } - return ol; -} - -/*<asyxml><function type="point" signature="point(circle,point)"><code></asyxml>*/ -point point(circle c, point M) -{/*<asyxml></code><documentation>Return the intersection point of 'c' - with the half-line '[c.C M)'.</documentation></function></asyxml>*/ - return intersectionpoints(c, line(c.C, false, M))[0]; -} - -/*<asyxml><function type="line" signature="tangent(circle,point)"><code></asyxml>*/ -line tangent(circle c, point M) -{/*<asyxml></code><documentation>Return the tangent of 'c' at the - intersection point of the half-line'[c.C M)'.</documentation></function></asyxml>*/ - return tangents(c, point(c, M))[0]; -} - -/*<asyxml><function type="point" signature="point(circle,explicit vector)"><code></asyxml>*/ -point point(circle c, explicit vector v) -{/*<asyxml></code><documentation>Return the intersection point of 'c' - with the half-line '[c.C v)'.</documentation></function></asyxml>*/ - return point(c, c.C + v); -} - -/*<asyxml><function type="line" signature="tangent(circle,explicit vector)"><code></asyxml>*/ -line tangent(circle c, explicit vector v) -{/*<asyxml></code><documentation>Return the tangent of 'c' at the - point M so that vec(c.C M) is collinear to 'v' with the same sense.</documentation></function></asyxml>*/ - line ol = tangent(c, c.C + v); - return dot(ol.v, v) > 0 ? ol : reverse(ol); -} - -/*<asyxml><function type="line" signature="tangent(ellipse,abscissa)"><code></asyxml>*/ -line tangent(ellipse el, abscissa x) -{/*<asyxml></code><documentation>Return the tangent of 'el' at 'point(el, x)'.</documentation></function></asyxml>*/ - point M = point(el, x); - line l1 = line(el.F1, M); - line l2 = line(el.F2, M); - line ol = (l1 == l2) ? perpendicular(M, l1) : bisector(l1, l2, 90, false); - return ol; -} - -/*<asyxml><function type="line[]" signature="tangents(ellipse,point)"><code></asyxml>*/ -line[] tangents(ellipse el, point M) -{/*<asyxml></code><documentation>Return the tangents of 'el' passing through 'M'.</documentation></function></asyxml>*/ - line[] ol; - if(inside(el, M)) return ol; - if(M @ el) { - ol.push(tangent(el, relabscissa(el, M))); - } else { - point Mp = samecoordsys(M, el.F2) ? - M : changecoordsys(el.F2.coordsys, M); - circle c = circle(Mp, abs(el.F1 - Mp)); - circle cc = circle(el.F2, 2 * el.a); - point[] inter = intersectionpoints(c, cc); - for (int i = 0; i < inter.length; ++i) { - line tl = line(inter[i], el.F2, false); - point[] P = intersectionpoints(tl, el); - ol.push(line(Mp, P[0])); - } - } - return ol; -} - -/*<asyxml><function type="line" signature="tangent(parabola,abscissa)"><code></asyxml>*/ -line tangent(parabola p, abscissa x) -{/*<asyxml></code><documentation>Return the tangent of 'p' at 'point(p, x)' (use the Wells method).</documentation></function></asyxml>*/ - line lt = rotate(90, p.V) * line(p.V, p.F); - point P = point(p, x); - if(P == p.V) return lt; - point M = midpoint(segment(P, p.F)); - line l = rotate(90, M) * line(P, p.F); - return line(P, projection(lt) * M); -} - -/*<asyxml><function type="line[]" signature="tangents(parabola,point)"><code></asyxml>*/ -line[] tangents(parabola p, point M) -{/*<asyxml></code><documentation>Return the tangent of 'p' at 'M' (use the Wells method).</documentation></function></asyxml>*/ - line[] ol; - if(inside(p, M)) return ol; - if(M @ p) { - ol.push(tangent(p, angabscissa(p, M))); - } - else { - point Mt = changecoordsys(coordsys(p), M); - circle c = circle(Mt, p.F); - line l = rotate(90, p.V) * line(p.V, p.F); - point[] R = intersectionpoints(l, c); - for (int i = 0; i < R.length; ++i) { - ol.push(line(Mt, R[i])); - } - // An other method: http://www.du.edu/~jcalvert/math/parabola.htm - // point[] R = intersectionpoints(p.directrix, c); - // for (int i = 0; i < R.length; ++i) { - // ol.push(bisector(segment(p.F, R[i]))); - // } - } - return ol; -} - -/*<asyxml><function type="line" signature="tangent(hyperbola,abscissa)"><code></asyxml>*/ -line tangent(hyperbola h, abscissa x) -{/*<asyxml></code><documentation>Return the tangent of 'h' at 'point(p, x)'.</documentation></function></asyxml>*/ - point M = point(h, x); - line ol = bisector(line(M, h.F1), line(M, h.F2)); - if(sameside(h.F1, h.F2, ol) || ol == line(h.F1, h.F2)) ol = rotate(90, M) * ol; - return ol; -} - -/*<asyxml><function type="line[]" signature="tangents(hyperbola,point)"><code></asyxml>*/ -line[] tangents(hyperbola h, point M) -{/*<asyxml></code><documentation>Return the tangent of 'h' at 'M'.</documentation></function></asyxml>*/ - line[] ol; - if(M @ h) { - ol.push(tangent(h, angabscissa(h, M, fromCenter))); - } else { - coordsys cano = canonicalcartesiansystem(h); - bqe bqe = changecoordsys(cano, equation(h)); - real a = abs(1/(bqe.a[5] * bqe.a[0])), b = abs(1/(bqe.a[5] * bqe.a[2])); - point Mp = changecoordsys(cano, M); - real x0 = Mp.x, y0 = Mp.y; - if(abs(x0) > epsgeo) { - real c0 = a * y0^2/(b * x0)^2 - 1/b, - c1 = 2 * a * y0/(b * x0^2), c2 = a/x0^2 - 1; - real[] sol = quadraticroots(c0, c1, c2); - for (real y:sol) { - point tmp = changecoordsys(coordsys(h), point(cano, (a * (1 + y * y0/b)/x0, y))); - ol.push(line(M, tmp)); - } - } else if(abs(y0) > epsgeo) { - real y = -b/y0, x = sqrt(a * (1 + b/y0^2)); - ol.push(line(M, changecoordsys(coordsys(h), point(cano, (x, y))))); - ol.push(line(M, changecoordsys(coordsys(h), point(cano, (-x, y))))); - }} - return ol; -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(conic,arc)"><code></asyxml>*/ -point[] intersectionpoints(conic co, arc a) -{/*<asyxml></code><documentation>intersectionpoints(arc, circle) is also defined.</documentation></function></asyxml>*/ - point[] op; - point[] tp = intersectionpoints(co, (conic)a.el); - for (int i = 0; i < tp.length; ++i) - if(tp[i] @ a) op.push(tp[i]); - return op; -} - -point[] intersectionpoints(arc a, conic co) -{ - return intersectionpoints(co, a); -} - -/*<asyxml><function type="point[]" signature="intersectionpoints(arc,arc)"><code></asyxml>*/ -point[] intersectionpoints(arc a1, arc a2) -{/*<asyxml></code><documentation></documentation></function></asyxml>*/ - point[] op; - point[] tp = intersectionpoints(a1.el, a2.el); - for (int i = 0; i < tp.length; ++i) - if(tp[i] @ a1 && tp[i] @ a2) op.push(tp[i]); - return op; -} - - -/*<asyxml><function type="point[]" signature="intersectionpoints(line,arc)"><code></asyxml>*/ -point[] intersectionpoints(line l, arc a) -{/*<asyxml></code><documentation>intersectionpoints(arc, line) is also defined.</documentation></function></asyxml>*/ - point[] op; - point[] tp = intersectionpoints(a.el, l); - for (int i = 0; i < tp.length; ++i) - if(tp[i] @ a && tp[i] @ l) op.push(tp[i]); - return op; -} - -point[] intersectionpoints(arc a, line l) -{ - return intersectionpoints(l, a); -} - -/*<asyxml><function type="point" signature="arcsubtendedcenter(point,point,real)"><code></asyxml>*/ -point arcsubtendedcenter(point A, point B, real angle) -{/*<asyxml></code><documentation>Return the center of the arc retuned - by the 'arcsubtended' routine.</documentation></function></asyxml>*/ - point OM; - point[] P = standardizecoordsys(A, B); - angle = angle%(sgnd(angle) * 180); - line bis = bisector(P[0], P[1]); - line AB = line(P[0], P[1]); - return intersectionpoint(bis, rotate(90 - angle, A) * AB); -} - -/*<asyxml><function type="arc" signature="arcsubtended(point,point,real)"><code></asyxml>*/ -arc arcsubtended(point A, point B, real angle) -{/*<asyxml></code><documentation>Return the arc circle from which the segment AB is saw with - the angle 'angle'. - If the point 'M' is on this arc, the oriented angle (MA, MB) is - equal to 'angle'.</documentation></function></asyxml>*/ - point[] P = standardizecoordsys(A, B); - line AB = line(P[0], P[1]); - angle = angle%(sgnd(angle) * 180); - point C = arcsubtendedcenter(P[0], P[1], angle); - real BC = degrees(B - C)%360; - real AC = degrees(A - C)%360; - return arc(circle(C, abs(B - C)), BC, AC, angle > 0 ? CCW : CW); -} - -/*<asyxml><function type="arc" signature="arccircle(point,point,point)"><code></asyxml>*/ -arc arccircle(point A, point M, point B) -{/*<asyxml></code><documentation>Return the CCW arc circle 'AB' passing through 'M'.</documentation></function></asyxml>*/ - circle tc = circle(A, M, B); - real a = degrees(A - tc.C); - real b = degrees(B - tc.C); - real m = degrees(M - tc.C); - - arc oa = arc(tc, a, b); - // TODO : use cross product to determine CWW or CW - if (!(M @ oa)) { - oa.direction = !oa.direction; - } - - return oa; -} - -/*<asyxml><function type="arc" signature="arc(ellipse,abscissa,abscissa,bool)"><code></asyxml>*/ -arc arc(ellipse el, explicit abscissa x1, explicit abscissa x2, bool direction = CCW) -{/*<asyxml></code><documentation>Return the arc from 'point(c, x1)' to 'point(c, x2)' in the direction 'direction'.</documentation></function></asyxml>*/ - real a = degrees(point(el, x1) - el.C); - real b = degrees(point(el, x2) - el.C); - arc oa = arc(el, a - el.angle, b - el.angle, fromCenter, direction); - return oa; -} - -/*<asyxml><function type="arc" signature="arc(ellipse,point,point,bool)"><code></asyxml>*/ -arc arc(ellipse el, point M, point N, bool direction = CCW) -{/*<asyxml></code><documentation>Return the arc from 'M' to 'N' in the direction 'direction'. - The points 'M' and 'N' must belong to the ellipse 'el'.</documentation></function></asyxml>*/ - return arc(el, relabscissa(el, M), relabscissa(el, N), direction); -} - -/*<asyxml><function type="arc" signature="arccircle(point,point,real,bool)"><code></asyxml>*/ -arc arccircle(point A, point B, real angle, bool direction = CCW) -{/*<asyxml></code><documentation>Return the arc circle centered on A - from B to rotate(angle, A) * B in the direction 'direction'.</documentation></function></asyxml>*/ - point M = rotate(angle, A) * B; - return arc(circle(A, abs(A - B)), B, M, direction); -} - -/*<asyxml><function type="arc" signature="arc(explicit arc,abscissa,abscissa)"><code></asyxml>*/ -arc arc(explicit arc a, abscissa x1, abscissa x2) -{/*<asyxml></code><documentation>Return the arc from 'point(a, x1)' to 'point(a, x2)' traversed in the direction of the arc direction.</documentation></function></asyxml>*/ - real a1 = angabscissa(a.el, point(a, x1), a.polarconicroutine).x; - real a2 = angabscissa(a.el, point(a, x2), a.polarconicroutine).x; - return arc(a.el, a1, a2, a.polarconicroutine, a.direction); -} - -/*<asyxml><function type="arc" signature="arc(explicit arc,point,point)"><code></asyxml>*/ -arc arc(explicit arc a, point M, point N) -{/*<asyxml></code><documentation>Return the arc from 'M' to 'N'. - The points 'M' and 'N' must belong to the arc 'a'.</documentation></function></asyxml>*/ - return arc(a, relabscissa(a, M), relabscissa(a, N)); -} - -/*<asyxml><function type="arc" signature="inverse(real,point,segment)"><code></asyxml>*/ -arc inverse(real k, point A, segment s) -{/*<asyxml></code><documentation>Return the inverse arc circle of 's' - with respect to point A and inversion radius 'k'.</documentation></function></asyxml>*/ - point Ap = inverse(k, A, s.A), Bp = inverse(k, A, s.B), - M = inverse(k, A, midpoint(s)); - return arccircle(Ap, M, Bp); -} - -/*<asyxml><operator type = "arc" signature="*(inversion,segment)"><code></asyxml>*/ -arc operator *(inversion i, segment s) -{/*<asyxml></code><documentation>Provide - inversion * segment.</documentation></operator></asyxml>*/ - return inverse(i.k, i.C, s); -} - -/*<asyxml><operator type = "path" signature="*(inversion,triangle)"><code></asyxml>*/ -path operator *(inversion i, triangle t) -{/*<asyxml></code><documentation>Provide inversion * triangle.</documentation></operator></asyxml>*/ - return (path)(i * segment(t.AB))-- - (path)(i * segment(t.BC))-- - (path)(i * segment(t.CA))&cycle; -} - -/*<asyxml><function type="path" signature="compassmark(pair,pair,real,real)"><code></asyxml>*/ -path compassmark(pair O, pair A, real position, real angle = 10) -{/*<asyxml></code><documentation>Return an arc centered on O with the angle 'angle' so that the position - of 'A' on this arc makes an angle 'position * angle'.</documentation></function></asyxml>*/ - real a = degrees(A - O); - real pa = (a - position * angle)%360, - pb = (a - (position - 1) * angle)%360; - real t1 = intersect(unitcircle, (0, 0)--2 * dir(pa))[0]; - real t2 = intersect(unitcircle, (0, 0)--2 * dir(pb))[0]; - int n = length(unitcircle); - if(t1 >= t2) t1 -= n; - return shift(O) * scale(abs(O - A)) * subpath(unitcircle, t1, t2); -} - -/*<asyxml><function type="line" signature="tangent(explicit arc,abscissa)"><code></asyxml>*/ -line tangent(explicit arc a, abscissa x) -{/*<asyxml></code><documentation>Return the tangent of 'a' at 'point(a, x)'.</documentation></function></asyxml>*/ - abscissa ag = angabscissa(a, point(a, x)); - return tangent(a.el, ag + a.angle1 + (a.el.e == 0 ? a.angle0 : 0)); -} - -/*<asyxml><function type="line" signature="tangent(explicit arc,point)"><code></asyxml>*/ -line tangent(explicit arc a, point M) -{/*<asyxml></code><documentation>Return the tangent of 'a' at 'M'. - The points 'M' must belong to the arc 'a'.</documentation></function></asyxml>*/ - return tangent(a, angabscissa(a, M)); -} - -// *=======================================================* -// *.......Routines for compatibility with original geometry module........* - -path square(pair z1, pair z2) -{ - pair v = z2 - z1; - pair z3 = z2 + I * v; - pair z4 = z3 - v; - return z1--z2--z3--z4--cycle; -} - -// Draw a perpendicular symbol at z aligned in the direction align -// relative to the path z--z + dir. -void perpendicular(picture pic = currentpicture, pair z, pair align, - pair dir = E, real size = 0, pen p = currentpen, - margin margin = NoMargin, filltype filltype = NoFill) -{ - perpendicularmark(pic, (point) z, align, dir, size, p, margin, filltype); -} - - -// Draw a perpendicular symbol at z aligned in the direction align -// relative to the path z--z + dir(g, 0) -void perpendicular(picture pic = currentpicture, pair z, pair align, path g, - real size = 0, pen p = currentpen, margin margin = NoMargin, - filltype filltype = NoFill) -{ - perpendicularmark(pic, (point) z, align, dir(g, 0), size, p, margin, filltype); -} - -// Return an interior arc BAC of triangle ABC, given a radius r > 0. -// If r < 0, return the corresponding exterior arc of radius |r|. -path arc(explicit pair B, explicit pair A, explicit pair C, real r) -{ - return arc(A, r, degrees(B - A), degrees(C - A)); -} - -// *.......End of compatibility routines........* -// *=======================================================* - -// *........................FOOTER.........................* -// *=======================================================* |