-- 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