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

--------------------------------------------------------------------------- 
 -- triangle center with circle
--------------------------------------------------------------------------- 
------------------------
--     Points --
------------------------
function circum_center_ ( a,b,c )
   local ka = math.sin (2 * get_angle_ ( a,b,c )) 
   local kb = math.sin (2 * get_angle_ ( b,c,a )) 
   local kc = math.sin (2 * get_angle_ ( c,a,b ))
   return  barycenter_ ( {a,ka} , {b,kb} , {c,kc} ) 
end

function in_center_ ( a,b,c )
   local ka = point.abs (b-c)
   local kc = point.abs (b-a)
   local kb = point.abs (c-a)
   return    barycenter_ ( {a,ka} , {b,kb} , {c,kc} )
end

function ex_center_ ( a,b,c )
   local ka  = point.abs (b-c)
   local kc  = point.abs (b-a)
   local kb  = point.abs (c-a)
   return     barycenter_ ( {a,-ka} , {b,kb} , {c,kc} )
 end 
 
function centroid_ (a,b,c)
  return    barycenter_ ( {a,1} , {b,1} , {c,1} )
end
centroid_center_ = centroid_

function ortho_center_ (a,b,c)
    local ka = math.tan (get_angle_ ( a,b,c ))
    local kb = math.tan (get_angle_ ( b,c,a ))
    local kc = math.tan (get_angle_ ( c,a,b ))
    return     barycenter_ ( {a,ka} , {b,kb} , {c,kc} )
end

function euler_center_ (a,b,c)
   local ma,mb,mc = medial_tr_ ( a,b,c)
   return circum_center_ (ma,mb,mc)
end

function gergonne_point_ (a,b,c)
   local u,v,w
   u,v,w = intouch_tr_ (a,b,c)
   return intersection_ll_ ( a,u , b,v)
end

function  lemoine_point_(a,b,c)
local ma,mb,mc,ha,hb,hc,u,v,w
u = point.abs(c-b)
v = point.abs(a-c)
w = point.abs(b-a)
 return   barycenter_ ({a,u*u},{b,v*v},{c,w*w})
end

function nagel_point_ (a, b, c)
   -- Calculate the excircle tangency points (u, v, w)
   local u, v, w = extouch_tr_ (a, b, c)

   -- Find the intersection of lines through a and u, and through b and v
   return intersection_ll_ (a, u, b, v)
end


function feuerbach_point_ (a, b, c)
   local i, h, e, ma

   -- Calculate the incenter and some related point (likely the orthocenter or another center)
   i, h = in_circle_ (a, b, c)
   
   -- Calculate the Euler center (center of the nine-point circle)
   e = euler_center_ (a, b, c)
   
   -- Calculate the midpoint of side BC
   ma = (b + c) / 2
   
   -- Find the intersection of the circles at (i, h) and (e, ma), which gives the Feuerbach point
   return intersection_cc_ (i, h, e, ma)
end


function spieker_center_ (a,b,c)
return in_center_ (medial_tr_ ( a,b,c))
end

function euler_points_ (a,b,c)
   local H
   H = ortho_center_ ( a , b , c )
   return midpoint_ ( H,a ), midpoint_ ( H,b ), midpoint_ ( H,c )
end
--------------------
-- lines --
--------------------
-- N,G,H,O
function euler_line_ (a,b,c)
   check_equilateral_ (a,b,c)
   local A = math.tan( get_angle_ ( a,b,c )) 
   local B = math.tan( get_angle_ ( b,c,a )) 
   local C = math.tan( get_angle_ ( c,a,b ))
       
   return     euler_center_ (a,b,c),
              barycenter_ ( {a,1} , {b,1} , {c,1} ) ,
              barycenter_ ( {a,A} , {b,B} , {c,C} ) ,
              barycenter_ ( {a,B+C} , {b,A+C} , {c,A+B} )
end

function bisector_ (a,b,c) -- possible intersection bisector with side
  return in_center_ (a,b,c)
end

function bisector_ext_ (a,b,c)
   local i
   i = in_center_ (a,b,c)
  return rotation_ (a,math.pi/2,i)
end

function mediators_ (a,b,c) 
  local o = circum_center (a,b,c)
  return    o ,
     projection_ (b,c,o) ,
     projection_ (a,c,o) ,
     projection_ (a,b,o) 
end
--------------------
-- circles --
--------------------
function circum_circle_ ( a,b,c )
   local ka = math.sin (2 * get_angle_ ( a,b,c )) 
   local kb = math.sin (2 * get_angle_ ( b,c,a )) 
   local kc = math.sin (2 * get_angle_ ( c,a,b ))
   return barycenter_ ( {a,ka} , {b,kb} , {c,kc} )
end

function in_circle_ ( a,b,c )
   local ka,kb,kc,o
     ka = point.abs (b-c)
     kc = point.abs (b-a)
     kb = point.abs (c-a)
     o  =   barycenter_ ( {a,ka} , {b,kb} , {c,kc} ) 
    return    o ,
              projection_ (b,c,o) ,
              projection_ (a,c,o) ,
              projection_ (a,b,o)
end

function ex_circle_ ( a,b,c )
     local ka,kb,kc,o
       ka = point.abs (b-c)
       kc = point.abs (b-a)
       kb = point.abs (c-a)
        o = barycenter_ ( {a,-ka} , {b,kb} , {c,kc} )
     return      o ,
                 projection_ (b,c,o) ,
                 projection_ (a,c,o) ,
                 projection_ (b,a,o)
end

function euler_circle_ (a, b, c)
   local o, ma, mb, mc, H, ha, hb, hc
   -- Compute the Euler center (center of the nine-point circle)
   o = euler_center_ (a, b, c)

   -- Calculate the medial triangle (midpoints of the sides)
   ma, mb, mc = medial_tr_ (a, b, c)

   -- Calculate the orthic triangle (feet of the altitudes)
   ha, hb, hc = orthic_tr_ (a, b, c)

   -- Get the Euler line and midpoint (H) on the Euler line
   _, _, H, _ = euler_line_ (a, b, c)

   -- Return all relevant geometric elements
   return 
      o, ma, mb, mc, ha, hb, hc,
      midpoint_ (H, a),  -- Midpoint between H and vertex a
      midpoint_ (H, b),  -- Midpoint between H and vertex b
      midpoint_ (H, c)   -- Midpoint between H and vertex c
end

--------------------
-- triangles --
--------------------
function orthic_tr_ (a,b,c)
  local o = ortho_center_ (a,b,c)
    return  projection_ (b,c,o) ,
            projection_ (a,c,o) ,
            projection_ (b,a,o)
end

function medial_tr_ (a,b,c)
  return      barycenter_ ( {a,0} , {b,1} , {c,1} ) ,
              barycenter_ ( {a,1} , {b,0} , {c,1} ) ,
              barycenter_ ( {a,1} , {b,1} , {c,0} )
end

function anti_tr_(a,b,c)
  return barycenter_ ( {a,-1} , {b,1} , {c,1} ) ,
         barycenter_ ( {a,1} , {b,-1} , {c,1} ) ,
         barycenter_ ( {a,1} , {b,1} , {c,-1} )
end

function incentral_tr_ (a, b, c)
    local i, r, s, t
    -- Compute the incenter (center of the incircle)
    i = in_center_ (a, b, c)
    
    -- Calculate the points of tangency where the incircle touches the sides
    r = intersection_ll_ (a, i, b, c)  -- Intersection of lines a-i and b-c
    s = intersection_ll_ (b, i, a, c)  -- Intersection of lines b-i and a-c
    t = intersection_ll_ (c, i, a, b)  -- Intersection of lines c-i and a-b
    
    -- Return the points of tangency that form the incentral triangle
    return r, s, t
end


function excentral_tr_(a, b, c)
    -- Calculate distances between points
    local ka = point.abs(b - c) -- Distance between b and c
    local kb = point.abs(c - a) -- Distance between c and a
    local kc = point.abs(b - a) -- Distance between b and a

    -- Compute barycentric points
    local r = barycenter_({a, -ka}, {b, kb}, {c, kc})
    local s = barycenter_({a, ka}, {b, -kb}, {c, kc})
    local t = barycenter_({a, ka}, {b, kb}, {c, -kc})

    -- Return the computed points
    return r, s, t
end


function intouch_tr_ (a,b,c)
   local i
   i = in_center_ (a , b , c)
    return  projection_ (b,c,i),
            projection_ (a,c,i),
            projection_ (a,b,i)
end

function cevian_ (a,b,c,p)
     return   intersection_ll_ (a,p,b,c),
              intersection_ll_ (b,p,a,c),
              intersection_ll_ (c,p,a,b)
end

function extouch_tr_ (a,b,c)
    local u,v,w
    u,v,w =  excentral_tr_ (a,b,c)
    return  projection_ (b,c,u) ,
            projection_ (a,c,v) ,
            projection_ (a,b,w)
end

function  tangential_tr_ (a,b,c)
  local u,v,w,x,y,z,xx,yy,zz
  u,v,w = orthic_tr_ (a,b,c)
  x = ll_from_ ( a , v , w )
  y = ll_from_ ( b , u , w )
  z = ll_from_ ( c , u , v )
  xx =  intersection_ll_ (c,z,b,y)
  yy =  intersection_ll_ (a,x,c,z)
  zz =  intersection_ll_ (a,x,b,y)
return  xx,yy,zz
end

function feuerbach_tr_ (a,b,c)
   local e,m,ja,ha,jb,hb,jc,hc
   e   =  euler_center_ (a,b,c)
   m = midpoint_( b , c )
   ja,ha = ex_circle_ ( a , b , c )
   jb,hb = ex_circle_ ( b , c , a )
   jc,hc = ex_circle_ ( c  , a , b )
    return  intersection_cc_ (e,m,ja,ha),
    intersection_cc_ (e,m,jb,hb),
    intersection_cc_ (e,m,jc,hc)
end

function similar_ (a,b,c)
  local x,y,z,g
   g = centroid_ (a,b,c)
   x = homothety_ (g,-2,a)
   y = homothety_ (g,-2,b)
   z = homothety_ (g,-2,c)
   return x,y,z
end

function orthic_axis_ (a,b,c) 
  local  ha, hb, hc = orthic_tr_(a, b, c)
  local z = intersection_ll_ (ha, hb, a, b)
  local y = intersection_ll_ (ha, hc, a, c)
  local x = intersection_ll_ (hb, hc, b, c)
  return x,y,z
end
--------------------
-- ellipse --
--------------------
function steiner_ (a,b,c)
   local g = centroid_ (a,b,c)
   local delta = a*a+b*b+c*c -a*b-a*c-b*c
   local fa = (a+b+c - point.sqrt(delta))/3
   local fb = (a+b+c + point.sqrt(delta))/3
   local m = midpoint_(b,c)
   local r = (length(fa,m)+length(fb,m))/2
   return conic : new (EL_bifocal (fb,fa,r))
end
--------------------
-- miscellanous --
--------------------

function area_ (a,b,c)
    return  point.mod(a - projection_(b,c,a))*point.mod (b - c)/2
end

function check_equilateral_(A, B, C)
  local a, b, c = length(B, C), length(A, C), length(A, B)

  -- Vérifie que les trois longueurs sont égales à epsilon près
  if math.abs(a - b) < tkz_epsilon 
  and math.abs(a - c) < tkz_epsilon 
  and math.abs(b - c) < tkz_epsilon then
    return true
  else
    return false
  end
end

function parallelogram_ (a,b,c)
    local x = c + a - b
  return  x
end

function barycentric_coordinates_ (a,b,c,pt)
    local AT,AA,AB,AC,x,y,z
    AT = area_(a,b,c)
    AA = area_(pt,b,c)
    AB = area_(a,pt,c)
    AC = area_(a,b,pt)
    x = AA/AT
    y = AB/AT
    z = AC/AT
   return x,y,z
end

function  in_out_ (a,b,c,pt)
    local cba,cbb,cbc,TT,AT,AA,AB,AC
    AT = area_(a,b,c)
    AA = area_(pt,b,c)
    AB = area_(a,pt,c)
    AC = area_(a,b,pt)
    cba = AA/AT
    cbb = AB/AT
    cbc = AC/AT
    if (cba >= 0 and cba <= 1) and (cbb >= 0 and cbb <= 1) and (cbc >= 0 and cbc <= 1)
     then
       return true
    else
       return false
    end
end

function soddy_center_ (a,b,c)
    -- Step 1: Compute the incenter and excircle centers
    local i,e,f,g = in_circle_ (a,b,c)
    local ha,hb,hc = orthic_tr_ (a,b,c)

    -- Step 2: Find the intersection points for the tangent lines
    local x,xp = intersection_lc_ (a,ha,a,g)
    if (point.mod(ha-x) < point.mod(ha-xp)) then else x,xp = xp,x end
    
    local y,yp = intersection_lc_ (b,hb,b,e)
    if (point.mod(hb-y) < point.mod(hb-yp)) then else y,yp = yp,y end
    
    local z,zp = intersection_lc_ (c,hc,c,f)
    if (point.mod(hc-z) < point.mod(hc-zp)) then else z,zp = zp,z end
    
    -- Step 3: Calculate the intersections with the opposite triangle sides
    local xi,t = intersection_lc_ (xp,e,a,g)
    if in_out_ (a,b,c,xi) then else xi,t = t,xi end
    
    local yi,t = intersection_lc_ (yp,f,b,e)
    if in_out_ (a,b,c,yi) then else yi,t = t,yi end
    
    local zi,t = intersection_lc_ (zp,g,c,f)
    if in_out_ (a,b,c,zi) then else zi,t = t,zi end
    
    -- Step 4: Calculate the circumcenter of the triangle formed by the tangent points
    local s = circum_center_ (xi,yi,zi)

    return s,xi,yi,zi -- Return the Soddy center and the tangent points
end

