-- tkz_elements-ellipses.lua -- date 2025/02/26 -- version 3.32 -- Copyright 2025 Alain Matthes -- This work may be distributed and/or modified under the -- conditions of the LaTeX Project Public License, either version 1.3 -- of this license or (at your option) any later version. -- The latest version of this license is in -- http://www.latex-project.org/lppl.txt -- and version 1.3 or later is part of all distributions of LaTeX -- version 2005/12/01 or later. -- This work has the LPPL maintenance status “maintained”. -- The Current Maintainer of this work is Alain Matthes. --------------------------------------------------------------------------- -- circles --------------------------------------------------------------------------- -- warning : parabola no center,no second focus, no covertex conic = {} function conic: new (Fa,Di,ecc) -- focus, directrix, eccentricity local type = 'conic' local e = ecc local subtype = get_subtype(e) local K = projection_(Di.pa,Di.pb,Fa) local h = length(K,Fa) local a = get_a(h, e) local b = get_b(h, e) -- only hy and el local c = get_c(h, e) local p = e * h -- demi latus rectum if hy and el b^2/a local slope = slope_(K, Fa) local major_axis = line : new (K, Fa) local directrix = Di local vertex = get_vertex(Fa, K, e, h) -- pb No center, no covertex, no Fb with parabola local center = conic_center(Fa, K, e, h ) local Fb = next_focus(Fa, K, e, h) local covertex = get_covertex(Fa, K ,e, h) local minor_axis = get_minor_axis(Fa, K ,e, h) local o = { type = type, subtype = subtype, K = K, e = e, h = h , a = a, b = b, c = c, p = p, Rx = a, Ry = b, Fa = Fa, Fb = Fb, center = center, vertex = vertex, covertex = covertex, major_axis = major_axis, minor_axis = minor_axis, directrix = directrix, slope = slope } setmetatable(o, self) self.__index = self return o end function conic: points(ta, tb, nb,swap) if not swap then return get_points_conic_(self, ta, tb, nb) else return get_points_sym_conic_(self, ta, tb, nb) end end -- function conic : points_sym (ta,tb,nb) -- return get_points_sym_conic_ (self,ta,tb,nb) -- end function conic : point (t,swap) if not swap then return get_one_point_conic_ (self,t) else return get_one_point_hyperbola_ii (self,t) end end function conic: antipode (pt) if self.e ~= 1 then return 2 * self.center - pt else -- traitement erreur end end function conic:tangent_at(pt) -- actually only parabola local u, v if self.e == 1 then -- Parabola local h = self.directrix:projection(pt) u = self.vertex:identity(pt) and ll_from_(pt, self.directrix.pa, self.directrix.pb) or in_center_(pt, h, self.Fa) elseif self.e > 1 then -- Hyperbola u = self.vertex:identity(pt) and ll_from_(pt, self.directrix.pa, self.directrix.pb) or in_center_(pt, self.Fb, self.Fa) elseif self.e < 1 then -- Ellipse local zi = in_center_(self.Fa, pt, self.Fb) u = pt + (zi - pt) * point(0, 1) end u = normalize_(pt, u) v = pt:symmetry(u) return line:new(u, v) end -- intersection line parabola function conic : inter_Pa_line (pa,pb) local sys = occs : new (self.major_axis ,self.vertex) local Xa,Ya = sys : coordinates (pa) local Xb,Yb = sys : coordinates (pb) local r1,r2 = solve_para_line (self.h,param_line (Xa,Ya,Xb,Yb)) if r1 ==false then local s1= false local s2 =false return s1,s2 else local s1,s2 = self : point(r1) , self : point(r2) if length(pa,s1) < length(pa,s2) then return s1,s2 else return s2,s1 end end end function conic:tangent_from(pt) if self.e == 1 then -- Parabola local sys = occs : new (self.major_axis ,self.vertex) local Xb,Yb = sys : coordinates (pt) local p1, p2 = solve_quadratic(self.h, -2 * Xb, 2 * Yb) local s1 = self:point(self.h * p1) local s2 = self:point(self.h * p2) return line:new(pt, s1), line:new(pt, s2) elseif self.e > 1 then -- Hyperbola local C = circle:radius(self.Fb, 2 * self.a) local m, n = intersection_cc_(pt, self.Fa, self.Fb, C.through) local u, v = mediator_(m, self.Fa) local x, y = mediator_(n, self.Fa) local T1, T2 = line:new(u, v), line:new(x, y) local d1, d2 = T1:distance(self.Fa), T2:distance(self.Fa) if d2 < d1 then T2, T1 = T1, T2 end local Fbsym = symmetry_axial_(T1.pa, T1.pb, self.Fb) local t1 = intersection_ll_(Fbsym, self.Fa, T1.pa, T1.pb) local Fasym = symmetry_axial_(T2.pa, T2.pb, self.Fa) local t2 = intersection_ll_(Fasym, self.Fb, T2.pa, T2.pb) return line:new(pt, t1), line:new(pt, t2) elseif self.e < 1 then -- Ellipse local w = report_(self.Fb, self.Fa, 2 * self.a) local s1, s2 = intersection_cc_(pt, self.Fa, self.Fb, w) local u, v = mediator_(s1, self.Fa) local U = intersection_ll_(u, v, self.Fb, s1) u, v = mediator_(s2, self.Fa) local V = intersection_ll_(u, v, self.Fb, s2) return line:new(pt, U), line:new(pt, V) end end -- intersection line hyperbola function conic:inter_Hy_line(pa, pb) local function hyp_fct (x) return self.a * math.sqrt(1 + (x^2) / (self.b)^2) end local sys = occs : new (self.major_axis,self.center) local XA,YA = sys : coordinates (pa) local XB,YB = sys : coordinates (pb) if math.abs(XA - XB) < tkz_epsilon then local xs = XA local fa, c = self.Fa, self.center local s1, s2 = hyp_fct(xs), -hyp_fct(xs) local wx = report_(self.directrix.pa, self.directrix.pb, xs, report_(c, fa, s1)) local wy = report_(self.directrix.pa, self.directrix.pb, xs, report_(c, fa, s2)) return wx, wy else local r, s = param_line(XA, YA, XB, YB) local t1, t2 = solve_hyper_line(self.a, self.b, r, s) if t1 ==false then return pa,pb else local s1, s2 = self : point(t1), self : point(t2) if r * t2 + s < 0 then s2 = self:point(t2,swap) end if r * t1 + s < 0 then s1 = self:point(t1,swap) end if length(pa,s1) < length(pa,s2) then return s1,s2 else return s2,s1 end end end end function conic : in_out(pt) if self.e == 1 then -- Parabola return PA_in_out (self,pt) elseif self.e > 1 then -- Hyperbola return HY_in_out (self,pt) elseif self.e < 1 then -- Ellipse return EL_in_out (self,pt) end end function conic: orthoptic () if self.e == 1 then -- Parabola return self.directrix elseif self.e > 1 and self.e < math.sqrt(2) then -- Hyperbola local r = math.sqrt(self.a * self.a - self.b * self.b) local th = report_(self.center,self.vertex,r) return circle : new (self.center, th) elseif self.e < 1 then -- Ellipse local r = math.sqrt(self.a * self.a + self.b * self.b) local th = report_(self.center,self.vertex,r) return circle : new (self.center, th) end end function conic : asymptotes () if self.e >1 then local pa = report_(self.Fa,self.Fb,self.a,self.center) local p1 = (pa-self.center) : orthogonal (self.b) : at (pa) local p2 = (pa-self.center) : orthogonal (-self.b) : at (pa) local q1 = symmetry_(self.center,p1) local q2 = symmetry_(self.center,p2) return line :new (p1,q1), line : new (p2,q2) else tex.error("An error has occurred", {"It's not an hyperbola"}) return end end return conic