\section{Geometric Constructions}

This section groups together functions that construct geometric figures without dedicated graphics methods.

\subsection{Circumscribed circle, incircle: circumcircle3d(), incircle3d()}

\begin{itemize}
    \item The function \cmd{ld.circumcircle3d(A, B, C)}, where \argu{A}, \argu{B} and \argu{C} are three non-aligned 3D points, returns the circumcircle of the triangle formed by these three points, in the form of a sequence: $O,R,n$, where $O$ is the center of the circle, $R$ its radius, and $n$ a normal vector to the plane of the circle.
     \item The function \cmd{ld.incircle3d(A, B, C)}, where \argu{A}, \argu{B} and \argu{C} are three non-aligned 3D points, returns the circle inscribed in the triangle formed by these three points, as a sequence: $I,R,n$, where $I$ is the center of the circle, $R$ its radius, and $n$ a normal vector to the plane of the circle.
\end{itemize}

\subsection{Convex Hull: cvx\_hull3d()}

The function \cmd{ld.cvx\_hull3d(L)}, where \argu{L} is a list of \textbf{distinct} 3D points, calculates and returns the convex hull of \argu{L} as a list of facets.

\begin{demo}{Using cvx\_hull3d()}
\begin{luadraw}{name=cvx_hull3d}
local ld = luadraw
local pt3d = ld.pt3d
local Origin, vecI, vecJ, vecK, M = pt3d.Origin, pt3d.vecI, pt3d.vecJ, pt3d.vecK, pt3d.M

local g = ld.graph3d:new{window={-2,4,-6,1},bbox=false,size={10,10}}
local L = {Origin, 4*vecI, M(4,4,0), 4*vecJ}
ld.insert(L, ld.shift3d(L,-3*vecK))
ld.insert(L, {M(2,1,2), M(2,3,2)})
local V = ld.cvx_hull3d(L)
local P = ld.facet2poly(V)
g:Dpoly(P , {color="cyan",mode=ld.mShadedHidden})
g:Show()
\end{luadraw}
\end{demo}

\paragraph{Special case}: when all points of \argu{L} are in the same plane, we can use the function \cmd{ld.cvx\_hull3dcoplanar(L, n)} where \argu{n} is a vector orthogonal to the plane. This function returns a facet (list of 3D points).

\subsection{Planes: plane(), planeEq(), orthoframe(), plane2ABC()}

A plane in space is a table of the form $\{A,n\}$ where $A$ is a point in the plane (3D point) and $n$ is a normal vector to the plane (non-zero 3D point).
\begin{itemize}
    \item The function \cmd{ld.plane(A, B, C)} returns the plane passing through the three 3D points \argu{A}, \argu{B} and \argu{C} (if they are not aligned, otherwise the result is \nil).

    \item The function \cmd{ld.planeEq(a, b, c, d \fac{, inequality})} returns the plane whose Cartesian equation is $ax+by+cz+d=0$ (if the coefficients \argu{a}, \argu{a} and \argu{b} are not all zero, otherwise the result is \nil). The optional argument \argu{inequality} (\nil by default) can also take the value \val{'<'} or \val{'>'}, the normal vector to the plane is then chosen so that it is in the half-space satisfying the inequality $ax+by+c<0$ (or $ax+by+c>0$ in the other case).

    \item The function \cmd{ld.plane2ABC(P)}, where \argu{P}$=\{A,n\}$ denotes a plane, returns a sequence of three 3D points $A,B,C$, belonging to the plane, and such that $(A,\vec{AB},\vec{AC})$ is a direct orthonormal frame of this plane.

    \item The function \cmd{ld.orthoframe(P \fac{, u})} where \argu{P}$=\{A,n\}$ denotes a plane, returns a sequence of three 3D points $A,u,v$, such that $(A,u,v)$ is a direct orthonormal coordinate system of this plane. The optional argument \argu{u}, if present, must be a non-zero vector of the plane; this will be the first basis vector after normalization.
\end{itemize}

\begin{demo}{Faces of a cube with holes in it and a regular hexagon}
\begin{luadraw}{name=plans}
local ld = luadraw
local pt3d = ld.pt3d
local Origin, vecI, vecJ, vecK, M = pt3d.Origin, pt3d.vecI, pt3d.vecJ, pt3d.vecK, pt3d.M

local g = ld.graph3d:new{window={-3,3,-3.25,3.25}, margin={0,0,0,0},
    viewdir={"central",20,60}, bg="LightGray", size={10,10}}
ld.Hiddenlines = true; ld.Hiddenlinestyle = "dashed"
local p = ld.polyreg(0,1,6)
local P = ld.parallelep(M(-2,-2,-2),4*vecI,4*vecJ,4*vecK)
local V = g:Sortpolyfacet(P)
local list = {}
g:Filloptions("full","Crimson",1,true); -- true for even odd rule
g:Lineoptions("solid","Gold",8)
for _, F in ipairs(V) do
    local P1 = ld.plane(pt3d.isobar3d(F),F[1],F[2]) -- plane of facet F
    local A, u, v = ld.orthoframe(P1) -- orthonormal coordinate system on the facet with center of gravity as the origin
    local p1 = ld.map(function(z) return A+z.re*u+z.im*v end,p) -- hexagon reproduced on the facet
    table.insert(p1,2,"m")
    local color = "Crimson"
    if not g:Isvisible(F) then color = "Crimson!60!black" end
    g:Dpath3d( ld.concat(F,{"l"},p1,{"l","cl"}),"fill="..color ) -- drawing of the "perforated" facet with the hexagon
end
g:Show()
\end{luadraw}
\end{demo}

\subsection{Circumscribed Sphere, Inscribed Sphere: circumsphere(), insphere()}

\begin{itemize}
    \item The function \cmd{ld.circumsphere(A, B, C, D)}, where \argu{A}, \argu{B}, \argu{C} and \argu{D} are four non-coplanar 3D points, returns the sphere circumscribed about the tetrahedron formed by these four points, as a sequence: $I,R$, where $I$ is the center of the sphere, and $R$ its radius.

    \item The function \cmd{ld.insphere(A, B, C, D)}, where \argu{A}, \argu{B}, \argu{C} and \argu{D} are four non-coplanar 3D points, returns the sphere inscribed within the tetrahedron formed by these four points, as a sequence: $I,R$, where $I$ is the center of the sphere, and $R$ its radius.
\end{itemize}

\subsection{Fixed-length tetrahedron: tetra\_len()}

The function \cmd{ld.tetra\_len(ab, ac, ad, bc, bd, cd)} calculates the vertices $A,B,C,D$ of a tetrahedron whose edge lengths are given, i.e., such that $AB=$\argu{ab}, $AC=$\argu{ac}, $AD=$\argu{ad}, $BC=$\argu{bc}, $BD=$\argu{bd} and $CD=$\argu{cd}. The function returns the sequence of four points $A,B,C,D$. Vertex $A$ is always the point $M(0,0,0)$ (\varglob{pt3d.Origin}) and vertex $B$ is always the point \code{ab*pt3d.vecI} and vertex $C$ in the $xy$ plane. The tetrahedron as a polyhedron can then be constructed with the function \cmd{ld.tetra(A, B-A, C-A, D-A)}.

\begin{demo}{A tetrahedron with fixed edge lengths}
\begin{luadraw}{name=tetra_len}
local ld = luadraw
local g = ld.graph3d:new{window={-4,4,-4,4},margin={0,0,0,0},viewdir={25,65},size={10,10}}
ld.Hiddenlines = true; ld.Hiddenlinestyle = "dashed"
require 'luadraw_spherical'
local R = 4
local A,B,C,D = ld.tetra_len(R,R,R,R,R,R)
local T = ld.tetra(A,B-A,C-A,D-A)
g:Define_sphere({radius=R})
g:DSpolyline( ld.facetedges(T), {color="DarkGreen"})
g:DSbigcircle( {B,C},{color="Blue"} )
g:DSbigcircle( {B,D},{color="Blue"} )
g:DSbigcircle( {C,D},{color="Blue"}  )
g:DSlabel("$R$",(2*A+C)/3,{pos="S"})
g:Dspherical()
g:Ddots3d({A,B,C,D})
g:Dlabel3d("$A$",A,{pos="S"},"$B$",B,{pos="SW"},"$C$",C,{},"$D$",D,{pos="N"} )
g:Show()
\end{luadraw}
\end{demo}

\subsection{Triangles: sss\_triangle3d(), sas\_triangle3d(), asa\_triangle3d()}

These functions are the 3D version of the sss\_triangle(), sas\_triangle(), and asa\_triangle() functions already described.
\begin{itemize}
    \item The function \cmd{ld.sss\_triangle3d(ab, bc, ca)}, where \argu{ab}, \argu{bc}, and \argu{ca} are three lengths, computes and returns a list of three 3D points $\{A,B,C\}$ forming the vertices of a direct triangle in the $xOy$ plane, whose side lengths are the arguments, i.e., $AB=$\argu{ab}, $BC=$\argu{bc} and $CA=$\argu{ca}, when possible. Vertex $A$ is always point $M(0,0,0)$ (\varglob{pt3d.Origin}) and vertex $B$ is always point \code{ab*pt3d.vecI}. This triangle can be drawn with the method \cmd{g:Dpolyline3d()}.

    \item The function \cmd{ld.sas\_triangle3d(ab, alpha, ca)} where \argu{ab} and \argu{ca} are two lengths, \argu{alpha} an angle in degrees, computes and returns a list of three 3D points $\{A,B,C\}$ forming the vertices of a triangle in the plane $xOy$ such that $AB=$\argu{ab}, $CA=$\argu{ca}, and such that the angle $(\vec{AB},\vec{AC})$ has measure \argu{alpha}, when possible. Vertex $A$ is always point $M(0,0,0)$ (\varglob{pt3d.Origin}) and vertex $B$ is always point \code{ab*pt3d.vecI}. This triangle can be drawn with the method \cmd{g:Dpolyline3d()}.

    \item The function \cmd{ld.asa\_triangle3d(alpha, ab, beta)} where \argu{ab} is a length, \argu{alpha} and \argu{beta} are two angles in degrees, computes and returns a list of three 3D points $\{A,B,C\}$ forming the vertices of a triangle in the $xOy$ plane such that $AB=$\argu{ab}, such that angle $(\vec{AB},\vec{AC})$ has measure \argu{alpha}, and such that angle $(\vec{BA},\vec{BC})$ has measure \argu{beta}, when possible. Vertex $A$ is always point $M(0,0,0)$ (\varglob{pt3d.Origin}) and vertex $B$ is always point \code{ab*pt3d.vecI}. This triangle can be drawn with the method \cmd{g:Dpolyline3d()}.
\end{itemize}
