Quickhull is a computational geometry algorithm used to compute the convex hull of a set of points. The convex hull is the smallest convex set that contains all the points in the set. In three dimensions, this is the smallest convex polyhedron that encloses all the points, essentially forming the "outer boundary" of the points.

Quickhull is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Problem Description

The Quickhull algorithm, also known as the "divide-and-conquer" convex hull algorithm, efficiently constructs the convex hull by recursively partitioning the point set. It is named for its similarity to the Quicksort algorithm due to its use of pivoting and partitioning.

Input
  • A set of points in 3D space, where each point is represented by its coordinates .
Output
  • The surface area of the convex hull of the given set of points.
Algorithm Overview (for 3D)

1. Find Initial Tetrahedron: Identify a set of four points that form a tetrahedron and are likely to be part of the convex hull. A common approach is to find the two points with minimum and maximum x-coordinates, and then find a point farthest from the line segment connecting them. Then, find a fourth point farthest from the plane defined by these three points. These four points form an initial tetrahedron that is guaranteed to be inside the convex hull.

2. Initialize Faces and Point Sets: The initial tetrahedron has four triangular faces. For each face, maintain a list of points that are *outside* the plane of that face.

3. Recursively Build the Hull: While there are faces with points outside:

  • Select a face that has points outside.
  • Find the point farthest from the plane of this face. This point is guaranteed to be on the convex hull.
  • Identify all faces that are "visible" from this farthest point. A face is visible if the point is on the "outside" of the face's plane.
  • Remove the visible faces and the points associated with them (those previously outside those faces).
  • Create new triangular faces by connecting the farthest point to the edges of the horizon. The horizon is the boundary of the visible faces on the existing hull.
  • For each new face, determine which of the previously outside points are now outside the plane of this new face.

4. Termination: The process terminates when no faces have points outside their respective planes.

5. Calculate Surface Area: Once the convex hull (represented by a set of triangular faces) is constructed, calculate the area of each triangular face and sum them up to get the total surface area of the convex hull. The area of a triangle in 3D can be calculated using the magnitude of the cross product of two of its edge vectors.

Applications
  • Collision Detection: Used in computer graphics and game development to simplify bounding shapes for efficient collision checks.
  • Shape Analysis: Helps in analyzing the shape and extent of 3D datasets, useful in fields like medical imaging and scientific simulations.
  • Path Planning: Assists in robotics and 3D mapping for navigating complex environments by defining the outer boundaries of obstacles.
  • Data Visualization: Simplifies the representation of complex 3D data by outlining their extremities.
Task

Given n points in 3D space, calculate the surface area of the convex hull formed by these points.


Translation of: Go
using System;
using System.Collections.Generic;

namespace QuickHull3D
{
    class Program
    {
        const int MAXN = 2500;
        const double EPS = 1e-8;

        // Globals
        static List<Facet> FAC = new List<Facet>();
        static List<List<Vect>> pts = new List<List<Vect>>();
        static int TIME = 0;
        static Edge[,] e = new Edge[2, MAXN];
        static int[] vistime = new int[MAXN];
        static List<int> queue = new List<int>();
        static List<int> resfnew = new List<int>();
        static List<int> resfdel = new List<int>();
        static List<Vect> respt = new List<Vect>();

        static void Main(string[] args)
        {
            PreConvexHulls();

            // Example: unit tetrahedron
            int n = 4;
            var point = new Vect[n + 1];
            point[1] = new Vect(0, 0, 0, 1);
            point[2] = new Vect(1, 0, 0, 2);
            point[3] = new Vect(0, 1, 0, 3);
            point[4] = new Vect(0, 0, 1, 4);

            var hull = QuickHull3D(point, n);
            Console.WriteLine("{0:F3}", hull.GetSurfaceArea());
        }

        static void PreConvexHulls()
        {
            // Reserve index 0
            pts.Add(new List<Vect>());
            FAC.Add(new Facet()); // dummy facet[0]
            // Initialize edge array
            for (int i = 0; i < 2; i++)
                for (int j = 0; j < MAXN; j++)
                    e[i, j] = new Edge();
        }

        class Vect
        {
            public double X, Y, Z;
            public int Id;
            public Vect(double x = 0, double y = 0, double z = 0, int id = 0)
            {
                X = x; Y = y; Z = z; Id = id;
            }
            public Vect Sub(Vect b) => new Vect(X - b.X, Y - b.Y, Z - b.Z);
            public Vect Cross(Vect b) => new Vect(
                Y * b.Z - Z * b.Y,
                Z * b.X - X * b.Z,
                X * b.Y - Y * b.X);
            public double Dot(Vect b) => X * b.X + Y * b.Y + Z * b.Z;
            public double Mag() => Math.Sqrt(X * X + Y * Y + Z * Z);
            public bool Eq(Vect b) => eq(X, b.X) && eq(Y, b.Y) && eq(Z, b.Z);
        }

        class Line
        {
            public Vect U, V;
            public Line(Vect u, Vect v) { U = u; V = v; }
        }

        class Plane
        {
            public Vect U, V, W;
            public Plane() { }
            public Plane(Vect u, Vect v, Vect w) { U = u; V = v; W = w; }
            public Vect Normal() => V.Sub(U).Cross(W.Sub(U));
            public Vect VecAt(int i)
            {
                if (i == 0) return U;
                if (i == 1) return V;
                return W;
            }
            public int VecId(int i) => VecAt(i).Id;
        }

        class Facet
        {
            public int[] N = new int[3];
            public int Id;
            public int VisitTime;
            public bool IsDeleted;
            public Plane P = new Plane();
            public Facet() { }
            public Facet(int id, Plane p)
            {
                Id = id; P = p;
            }
        }

        class Edge
        {
            public int NetId, FacetId;
            public Edge() { }
        }

        class ConvexHulls3d
        {
            public int Index;
            double surfaceArea = 0.0;
            public ConvexHulls3d(int idx) { Index = idx; }

            void DfsArea(int f)
            {
                if (FAC[f].VisitTime == TIME) return;
                FAC[f].VisitTime = TIME;
                var nrm = FAC[f].P.Normal();
                surfaceArea += nrm.Mag() / 2.0;
                for (int i = 0; i < 3; i++)
                    DfsArea(FAC[f].N[i]);
            }

            public double GetSurfaceArea()
            {
                if (gtr(surfaceArea, 0.0)) return surfaceArea;
                TIME++;
                DfsArea(Index);
                return surfaceArea;
            }

            public int GetHorizon(int f, Vect p, List<int> resDel)
            {
                if (!isAbove(p, FAC[f].P)) return 0;
                if (FAC[f].VisitTime == TIME) return -1;
                FAC[f].VisitTime = TIME;
                FAC[f].IsDeleted = true;
                resDel.Add(FAC[f].Id);
                int ret = -2;
                for (int i = 0; i < 3; i++)
                {
                    int r = GetHorizon(FAC[f].N[i], p, resDel);
                    if (r == 0)
                    {
                        int a = FAC[f].P.VecId(i);
                        int b = FAC[f].P.VecId((i + 1) % 3);
                        foreach (var pair in new[]{(pt:a, idx:0),(pt:b, idx:1)})
                        {
                            int pt = pair.pt; int idx = pair.idx;
                            if (vistime[pt] != TIME)
                            {
                                vistime[pt] = TIME;
                                e[0, pt].NetId = idx == 0 ? b : a;
                                e[0, pt].FacetId = FAC[f].N[i];
                            }
                            else
                            {
                                e[1, pt].NetId = idx == 0 ? b : a;
                                e[1, pt].FacetId = FAC[f].N[i];
                            }
                        }
                        ret = a;
                    }
                    else if (r != -1 && r != -2)
                    {
                        ret = r;
                    }
                }
                return ret;
            }
        }

        // Utilities
        static bool eq(double a, double b) => Math.Abs(a - b) < EPS;
        static bool gtr(double a, double b) => a - b > EPS;
        static double Abs(double x) => x < 0 ? -x : x;

        static double DistPointPlane(Vect v, Plane p)
        {
            double num = v.Sub(p.U).Dot(p.Normal());
            double den = p.Normal().Mag();
            return num / den;
        }

        static double DistPointLine(Vect v, Line l)
        {
            double d = v.Sub(l.U).Mag();
            if (d == 0) return 0;
            return l.V.Sub(l.U).Cross(v.Sub(l.U)).Mag() / l.V.Sub(l.U).Mag();
        }

        static double DistPointPoint(Vect a, Vect b) => a.Sub(b).Mag();

        static bool isAbove(Vect v, Plane p) =>
            gtr(v.Sub(p.U).Dot(p.Normal()), 0);

        static ConvexHulls3d GetStart(Vect[] point, int totp)
        {
            Vect[] extremes = new Vect[6];
            for (int i = 0; i < 6; i++) extremes[i] = point[1];
            for (int i = 1; i <= totp; i++)
            {
                var v = point[i];
                if (gtr(v.X, extremes[0].X)) extremes[0] = v;
                if (gtr(extremes[1].X, v.X)) extremes[1] = v;
                if (gtr(v.Y, extremes[2].Y)) extremes[2] = v;
                if (gtr(extremes[3].Y, v.Y)) extremes[3] = v;
                if (gtr(v.Z, extremes[4].Z)) extremes[4] = v;
                if (gtr(extremes[5].Z, v.Z)) extremes[5] = v;
            }

            // Furthest pair
            Vect s0 = extremes[0], s1 = extremes[1];
            for (int i = 0; i < 6; i++)
                for (int j = i + 1; j < 6; j++)
                {
                    var d = DistPointPoint(extremes[i], extremes[j]);
                    if (gtr(d, DistPointPoint(s0, s1)))
                    {
                        s0 = extremes[i];
                        s1 = extremes[j];
                    }
                }

            // Furthest from line
            var line = new Line(s0, s1);
            Vect s2 = extremes[0];
            for (int i = 0; i < 6; i++)
            {
                if (gtr(DistPointLine(extremes[i], line),
                        DistPointLine(s2, line)))
                    s2 = extremes[i];
            }

            // Furthest from plane
            Vect s3 = point[1];
            var basePlane = new Plane(s0, s1, s2);
            for (int i = 1; i <= totp; i++)
            {
                var d1 = Abs(DistPointPlane(point[i], basePlane));
                var d2 = Abs(DistPointPlane(s3, basePlane));
                if (gtr(d1, d2)) s3 = point[i];
            }

            if (gtr(0, DistPointPlane(s3, basePlane)))
                (s1, s2) = (s2, s1);

            // Create 4 initial facets
            int[] f = new int[4];
            for (int i = 0; i < 4; i++)
            {
                FAC.Add(new Facet { Id = FAC.Count });
                f[i] = FAC.Count - 1;
            }
            FAC[f[0]].P = new Plane(s0, s2, s1);
            FAC[f[1]].P = new Plane(s0, s1, s3);
            FAC[f[2]].P = new Plane(s1, s2, s3);
            FAC[f[3]].P = new Plane(s2, s0, s3);

            FAC[f[0]].N = new[] { f[3], f[2], f[1] };
            FAC[f[1]].N = new[] { f[0], f[2], f[3] };
            FAC[f[2]].N = new[] { f[0], f[3], f[1] };
            FAC[f[3]].N = new[] { f[0], f[1], f[2] };

            // Prepare pts lists
            for (int i = 0; i < 4; i++)
                pts.Add(new List<Vect>());

            // Assign points
            for (int i = 1; i <= totp; i++)
            {
                var v = point[i];
                if (v.Eq(s0) || v.Eq(s1) || v.Eq(s2) || v.Eq(s3))
                    continue;
                for (int j = 0; j < 4; j++)
                    if (isAbove(v, FAC[f[j]].P))
                    {
                        pts[f[j]].Add(v);
                        break;
                    }
            }

            return new ConvexHulls3d(f[0]);
        }

        static ConvexHulls3d QuickHull3D(Vect[] point, int totp)
        {
            var hull = GetStart(point, totp);

            // Initialize queue
            queue.Clear();
            queue.Add(hull.Index);
            for (int i = 0; i < 3; i++)
                queue.Add(FAC[hull.Index].N[i]);

            int snew = 0;

            while (queue.Count > 0)
            {
                int nf = queue[0];
                queue.RemoveAt(0);
                if (FAC[nf].IsDeleted || pts[nf].Count == 0)
                {
                    if (!FAC[nf].IsDeleted)
                        snew = nf;
                    continue;
                }

                // Farthest point
                var p = pts[nf][0];
                foreach (var v in pts[nf])
                {
                    if (gtr(DistPointPlane(v, FAC[nf].P),
                            DistPointPlane(p, FAC[nf].P)))
                        p = v;
                }

                // Find horizon
                TIME++;
                resfdel.Clear();
                int s = hull.GetHorizon(nf, p, resfdel);

                // Build new faces
                resfnew.Clear();
                TIME++;
                int from = -1, lastf = -1, fstf = -1;
                while (vistime[s] != TIME)
                {
                    vistime[s] = TIME;
                    int net, f, fnew;
                    if (e[0, s].NetId == from)
                    {
                        net = e[1, s].NetId;
                        f = e[1, s].FacetId;
                    }
                    else
                    {
                        net = e[0, s].NetId;
                        f = e[0, s].FacetId;
                    }

                    // Find indices on facet f
                    int pt1 = 0, pt2 = 0;
                    for (int i = 0; i < 3; i++)
                    {
                        if (point[s].Eq(FAC[f].P.VecAt(i)))
                            pt1 = i;
                        if (point[net].Eq(FAC[f].P.VecAt(i)))
                            pt2 = i;
                    }
                    if ((pt1 + 1) % 3 != pt2)
                        (pt1, pt2) = (pt2, pt1);

                    // Create new facet
                    FAC.Add(new Facet
                    {
                        Id = FAC.Count,
                        P = new Plane(FAC[f].P.VecAt(pt2),
                                      FAC[f].P.VecAt(pt1),
                                      p)
                    });
                    fnew = FAC.Count - 1;
                    pts.Add(new List<Vect>());
                    resfnew.Add(fnew);

                    FAC[fnew].N[0] = f;
                    FAC[f].N[pt1] = fnew;

                    if (lastf >= 0)
                    {
                        // Link with previous new facet
                        if (FAC[fnew].P.VecAt(1).Eq(FAC[lastf].P.U))
                        {
                            FAC[fnew].N[1] = lastf;
                            FAC[lastf].N[2] = fnew;
                        }
                        else
                        {
                            FAC[fnew].N[2] = lastf;
                            FAC[lastf].N[1] = fnew;
                        }
                    }
                    else
                    {
                        fstf = fnew;
                    }

                    lastf = fnew;
                    from = s;
                    s = net;
                }

                // Close the loop
                if (FAC[fstf].P.VecAt(1).Eq(FAC[lastf].P.U))
                {
                    FAC[fstf].N[1] = lastf;
                    FAC[lastf].N[2] = fstf;
                }
                else
                {
                    FAC[fstf].N[2] = lastf;
                    FAC[lastf].N[1] = fstf;
                }

                // Collect deleted points
                respt.Clear();
                foreach (var fid in resfdel)
                {
                    respt.AddRange(pts[fid]);
                    pts[fid].Clear();
                }

                // Reassign
                foreach (var v in respt)
                {
                    if (v == p) continue;
                    foreach (var fid in resfnew)
                    {
                        if (isAbove(v, FAC[fid].P))
                        {
                            pts[fid].Add(v);
                            break;
                        }
                    }
                }

                // Enqueue new faces
                foreach (var fid in resfnew)
                    queue.Add(fid);
            }

            hull.Index = snew;
            return hull;
        }
    }
}
Output:
2.366
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <vector>

constexpr uint32_t MAX_SIZE = 2'500;
constexpr double EPSILON = 0.000'000'01;

// Numerical utilities
bool is_greater_than(const double& a, const double& b) {
	return ( a - b ) > EPSILON;
}

bool is_equal(const double& a, const double& b) {
	return std::abs(a - b) < EPSILON;
}

class Vector {
public:
   Vector(const double& x = 0, const double& y = 0, const double& z = 0, const uint32_t& id = 0)
   	   : x(x), y(y), z(z), id(id) {}

   Vector subtract(const Vector& other) const {
	   return Vector(x - other.x, y - other.y, z - other.z);
   }

   Vector vector_product(const Vector& other) const {
	   return Vector(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x);
   }

   double scalar_product(const Vector& other) const {
	   return x * other.x + y * other.y + z * other.z;
   }

   double magnitude() const {
	   return std::sqrt(x * x + y * y + z * z);
   }

   bool equals(const Vector& b) const {
	   return is_equal(x, b.x) && is_equal(y, b.y) && is_equal(z, b.z);
   }

   double x, y, z;
   uint32_t id;
};

class Line {
public:
    Line(const Vector& u, const Vector& v) : u(u), v(v) {}

	Vector u, v;
};

class Plane {
public:
   Plane(const Vector& u, const Vector& v, const Vector& w) : u(u), v(v), w(w) {}

   Plane() {}

   Vector normal() const {
	   return v.subtract(u).vector_product(w.subtract(u));
   }

   Vector vector_at_index(const uint32_t& i) const {
	   if ( i == 0 ) { return u; }
	   if ( i == 1 ) { return v; }
	   if ( i == 2 ) { return w; }
	   return 0;
   }

   uint32_t vector_id(const uint32_t& i) const {
	   return vector_at_index(i).id;
   }

   Vector u, v, w;
};

class Facet {
public:
	Facet(const uint32_t& id, const Plane& p) : id(id), plane(p) {}

	Facet(const uint32_t& id) : id(id) {}

	Facet() {}

	std::vector<uint32_t> N;
	uint32_t id = 0;
	uint32_t visited_time = 0;
	bool is_deleted = false;
	Plane plane;
};

class Edge {
public:
	Edge() {}

	uint32_t netID = 0;
	uint32_t faceID = 0;
};

// Global variables
std::vector<Facet> facets;
std::vector<std::vector<Vector>> hull_points;
uint32_t time_step = 0;
std::vector<std::vector<Edge>> edges = { 2, std::vector<Edge>(MAX_SIZE) };
std::vector<uint32_t> visit_time(MAX_SIZE, 0);
std::vector<uint32_t> queue;
std::vector<uint32_t> resfnew;
std::vector<uint32_t> resfdel;
std::vector<Vector> respt;

// Geometric utilities
double distance_point_plane(const Vector& vec, const Plane& plane) {
	const double num = vec.subtract(plane.u).scalar_product(plane.normal());
	const double den = plane.normal().magnitude();
	return num / den;
}

double distance_point_line(const Vector& vec, const Line& line) {
	const double length = vec.subtract(line.u).magnitude();
	return ( length == 0.0 ) ? 0.0 :
		line.v.subtract(line.u).vector_product(vec.subtract(line.u)).magnitude() / line.v.subtract(line.u).magnitude();
}

double distance_point_point(const Vector& a, const Vector& b) {
	return a.subtract(b).magnitude();
}

bool is_above(const Vector& point, const Plane& plane) {
    return is_greater_than(point.subtract(plane.u).scalar_product(plane.normal()), 0.0);
}

class ConvexHulls3d {
public:
	ConvexHulls3d(const uint32_t& index) : index(index) {}

	double get_surface_area() {
		if ( is_greater_than(surface_area, 0.0) ) {
			return surface_area;
		}

		time_step++;
		dfs_area(index);
		return surface_area;
	}

	uint32_t get_horizon(const uint32_t& f, const Vector& point, std::vector<uint32_t> resDel) const {
		Facet Ff = facets[f];
		if ( ! is_above(point, Ff.plane) ) {
			return 0;
		}
		if ( Ff.visited_time == time_step ) {
			return -1;
		}

		Ff.visited_time = time_step;
		Ff.is_deleted = true;
		resDel.emplace_back(Ff.id);
		uint32_t result = -2;
		for ( uint32_t i = 0; i < 3; ++i ) {
			const uint32_t ni = Ff.N[i];
			const int32_t horizon = get_horizon(ni, point, resDel);
			if ( horizon == 0 ) {
				const uint32_t a = facets[f].plane.vector_id(i);
				const uint32_t b = facets[f].plane.vector_id((i + 1) % 3);
				for ( uint32_t idx = 0; idx < 2; ++idx ) {
					const uint32_t pt = ( idx == 0 ) ? a : b;
					const uint32_t facet = ni;
					if ( visit_time[pt] != time_step ) {
						visit_time[pt] = time_step;
						edges[0][pt].netID = ( idx == 0 ) ? b : a;
						edges[0][pt].faceID = facet;
					} else {
						edges[1][pt].netID = ( idx == 0 ) ? b : a;
						edges[1][pt].faceID = facet;
					}
				}
				result = a;
			} else if ( horizon != -1 && horizon != -2 ) {
				result = horizon;
			}
		}
		return result;
	}

	uint32_t index;
	double surface_area = 0.0;

private:
	void dfs_area(const uint32_t& f) {
		if ( facets[f].visited_time == time_step ) {
			return;
		}

		facets[f].visited_time = time_step;
		const Vector normal = facets[f].plane.normal();
		surface_area += normal.magnitude() / 2.0;
		for ( uint32_t i = 0; i < 3; ++i ) {
			dfs_area(facets[f].N[i]);
		}
	}
};

void prepareConvexHulls() {
   // Reserve index 0
   hull_points.emplace_back(std::vector<Vector>());
   facets.emplace_back(Facet());

   // Initialize edge vector
   for ( uint32_t i = 0; i < 2; ++i ) {
	   for ( uint32_t j = 0; j < MAX_SIZE; ++j ) {
		   edges[i][j] = Edge();
	   }
   }
}

ConvexHulls3d get_initial_hull(const std::vector<Vector>& points, const uint32_t& total_points) {
	std::vector<Vector> extremes(6);
	for ( uint32_t i = 0; i < 6; ++i ) { extremes[i] = points[1]; }
	for ( uint32_t i = 1; i <= total_points; ++i ) {
		Vector point = points[i];
		if ( is_greater_than(point.x, extremes[0].x) ) { extremes[0] = point; }
		if ( is_greater_than(extremes[1].x, point.x) ) { extremes[1] = point; }
		if ( is_greater_than(point.y, extremes[2].y) ) { extremes[2] = point; }
		if ( is_greater_than(extremes[3].y, point.y) ) { extremes[3] = point; }
		if ( is_greater_than(point.z, extremes[4].z) ) { extremes[4] = point; }
		if ( is_greater_than(extremes[5].z, point.z) ) { extremes[5] = point; }
	}

	// Furthest pair
	Vector extreme0 = extremes[0];
	Vector extreme1 = extremes[1];
	for ( uint32_t i = 0; i < 6; ++i ) {
		for ( uint32_t j = i + 1; j < 6; ++j ) {
			const double distance = distance_point_point(extremes[i], extremes[j]);
			if ( is_greater_than(distance, distance_point_point(extreme0, extreme1)) ) {
				extreme0 = extremes[i];
				extreme1 = extremes[j];
			}
		}
	}

	// Furthest from line
	const Line line(extreme0, extreme1);
	Vector extreme2 = extremes[0];
	for ( uint32_t i = 0; i < 6; ++i ) {
		if ( is_greater_than(distance_point_line(extremes[i], line), distance_point_line(extreme2, line)) ) {
			extreme2 = extremes[i];
		}
	}

	// Furthest from plane
	Vector extreme3 = points[1];
	const Plane basePlane(extreme0, extreme1, extreme2);
	for ( uint32_t i = 1; i <= total_points; ++i ) {
		const double distance1 = std::fabs(distance_point_plane(points[i], basePlane));
		const double distance2 = std::fabs(distance_point_plane(extreme3, basePlane));
		if ( is_greater_than(distance1, distance2) ) {
			extreme3 = points[i];
		}
	}

	if ( is_greater_than(0, distance_point_plane(extreme3, basePlane)) ) {
		std::swap(extreme1, extreme2);
	}

	// Create 4 initial facets
	std::vector<uint32_t> f(4);
	for ( uint32_t i = 0; i < 4; ++i ) {
		facets.emplace_back(Facet(facets.size()));
		f[i] = facets.size() - 1;
	}

	facets[f[0]].plane = Plane(extreme0, extreme2, extreme1);
	facets[f[1]].plane = Plane(extreme0, extreme1, extreme3);
	facets[f[2]].plane = Plane(extreme1, extreme2, extreme3);
	facets[f[3]].plane = Plane(extreme2, extreme0, extreme3);

	facets[f[0]].N = { f[3], f[2], f[1] };
	facets[f[1]].N = { f[0], f[2], f[3] };
	facets[f[2]].N = { f[0], f[3], f[1] };
	facets[f[3]].N = { f[0], f[1], f[2] };

	// Prepare hull_points vector
	for ( uint32_t i = 0; i < 4; ++i ) {
		hull_points.emplace_back(std::vector<Vector>());
	}

	// Assign points
	for ( uint32_t i = 1; i <= total_points; ++i ) {
		const Vector point = points[i];
		if ( point.equals(extreme0) || point.equals(extreme1) || point.equals(extreme2) || point.equals(extreme3) ) {
			continue;
		}

		for ( uint32_t j = 0; j < 4; ++j ) {
			if ( is_above(point, facets[f[j]].plane) ) {
				hull_points[f[j]].emplace_back(point);
				break;
			}
		}
	}

	return ConvexHulls3d(f[0]);
}

ConvexHulls3d QuickHull3D(const std::vector<Vector>& points, const uint32_t& total_points) {
	ConvexHulls3d hull = get_initial_hull(points, total_points);

	// Initialize queue
	queue.clear();
	queue.emplace_back(hull.index);
	for ( uint32_t i = 0; i < 3; ++i ) {
		queue.emplace_back(facets[hull.index].N[i]);
	}

	uint32_t new_horizon = 0;

	while ( ! queue.empty() ) {
		uint32_t nf = queue.front();
		queue.erase(queue.begin());
		if ( facets[nf].is_deleted || hull_points[nf].empty()) {
			if ( ! facets[nf].is_deleted ) {
				new_horizon = nf;
			}
			continue;
		}

		// Farthest point
		Vector point = hull_points[nf][0];
		for ( const Vector& vec : hull_points[nf] ) {
			if ( is_greater_than(distance_point_plane(vec, facets[nf].plane),
								 distance_point_plane(point, facets[nf].plane)) ) {
				point = vec;
			}
		}

		// Find horizon
		time_step++;
		resfdel.clear();
		uint32_t horizon = hull.get_horizon(nf, point, resfdel);

		// Build new faces
		resfnew.clear();
		time_step++;
		uint32_t from = -1;
		uint32_t last_f = -1;
		uint32_t first_f = -1;
		while ( visit_time[horizon] != time_step ) {
			visit_time[horizon] = time_step;
			uint32_t net;
			uint32_t f;
			uint32_t new_f;
			if ( edges[0][horizon].netID == from ) {
				net = edges[1][horizon].netID;
				f = edges[1][horizon].faceID;
			} else {
				net = edges[0][horizon].netID;
				f = edges[0][horizon].faceID;
			}

			// Find indices on facet f
			uint32_t pt1 = 0;
			uint32_t pt2 = 0;
			for ( uint32_t i = 0; i < 3; ++i ) {
				if ( points[horizon].equals(facets[f].plane.vector_at_index(i)) ) {
					pt1 = i;
				}
				if ( points[net].equals(facets[f].plane.vector_at_index(i)) ) {
					pt2 = i;
				}
			}
			if ( ( pt1 + 1 ) % 3 != pt2 ) {
				std::swap(pt1, pt2);
			}

			// Create new facet
			facets.emplace_back(Facet(
					facets.size(),
					Plane(facets[f].plane.vector_at_index(pt2),
					facets[f].plane.vector_at_index(pt1), point)));
			new_f = facets.size() - 1;
			hull_points.emplace_back(std::vector<Vector>());
			resfnew.emplace_back(new_f);

			facets[new_f].N[0] = f;
			facets[f].N[pt1] = new_f;

			if ( last_f >= 0 ) {
				// Link with previous new facet
				if ( facets[new_f].plane.vector_at_index(1).equals(facets[last_f].plane.u) ) {
					facets[new_f].N[1] = last_f;
					facets[last_f].N[2] = new_f;
				} else {
					facets[new_f].N[2] = last_f;
					facets[last_f].N[1] = new_f;
				}
			} else {
				first_f = new_f;
			}

			last_f = new_f;
			from = horizon;
			horizon = net;
		}

		// Close the loop
		if ( facets[first_f].plane.vector_at_index(1).equals(facets[last_f].plane.u) ) {
			facets[first_f].N[1] = last_f;
			facets[last_f].N[2] = first_f;
		} else {
			facets[first_f].N[2] = last_f;
			facets[last_f].N[1] = first_f;
		}

		// Collect deleted points
		respt.clear();
		for ( const uint32_t& f_id : resfdel ) {
			respt.insert(respt.end(), hull_points[f_id].begin(), hull_points[f_id].end());
			hull_points[f_id].clear();
		}

		// Reassign
		for ( const Vector& vec : respt ) {
			if ( vec.equals(point) ) {
				continue;
			}
			for ( const uint32_t& f_id : resfnew ) {
				if ( is_above(vec, facets[f_id].plane) ) {
					hull_points[f_id].emplace_back(vec);
					break;
				}
			}
		}

		// Enqueue new faces
		for ( const uint32_t& f_id : resfnew ) {
			queue.emplace_back(f_id);
		}
	}

	hull.index = new_horizon;
	return hull;
}

int main() {
	prepareConvexHulls();

	// Example: a tetrahedron
	constexpr uint32_t n = 4;
	std::vector<Vector> points(n + 1);
	// An empty or placeholder value for points[0] is required for all examples
	points[1] = Vector(0, 0, 0, 1); // The last argument of each vector is its index
	points[2] = Vector(1, 0, 0, 2);
	points[3] = Vector(0, 1, 0, 3);
	points[4] = Vector(0, 0, 1, 4);

	ConvexHulls3d hull = QuickHull3D(points, n);
	std::cout << std::fixed << std::setprecision(3) << hull.get_surface_area() << std::endl;
}
Output:
2.366
Works with: Dart version 3.6.1
Translation of: C++
import 'dart:math';
import 'dart:io';

// ---------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------
const int MAX_SIZE = 2500;
const double EPSILON = 1e-8;

// ---------------------------------------------------------------------
// Numerical utilities (exact copy of the C++ helpers)
// ---------------------------------------------------------------------
bool isGreaterThan(double a, double b) => (a - b) > EPSILON;

bool isEqual(double a, double b) => (a - b).abs() < EPSILON;

// ---------------------------------------------------------------------
// Geometry primitives
// ---------------------------------------------------------------------
class Vector {
  double x, y, z;
  int id; // (in C++ it is uint32_t, here we use int)

  Vector([this.x = 0, this.y = 0, this.z = 0, this.id = 0]);

  Vector subtract(Vector other) =>
      Vector(x - other.x, y - other.y, z - other.z);

  Vector vectorProduct(Vector other) => Vector(
        y * other.z - z * other.y,
        z * other.x - x * other.z,
        x * other.y - y * other.x,
      );

  double scalarProduct(Vector other) =>
      x * other.x + y * other.y + z * other.z;

  double magnitude() => sqrt(x * x + y * y + z * z);

  bool equals(Vector b) =>
      isEqual(x, b.x) && isEqual(y, b.y) && isEqual(z, b.z);
}

// ---------------------------------------------------------------------
// Line and Plane
// ---------------------------------------------------------------------
class Line {
  Vector u, v;
  Line(this.u, this.v);
}

class Plane {
  Vector u, v, w;

  Plane([Vector? a, Vector? b, Vector? c])
      : u = a ?? Vector(),
        v = b ?? Vector(),
        w = c ?? Vector();

  Vector normal() => v.subtract(u).vectorProduct(w.subtract(u));

  Vector vectorAtIndex(int i) {
    switch (i) {
      case 0:
        return u;
      case 1:
        return v;
      case 2:
        return w;
      default:
        throw RangeError('Plane only has three vectors');
    }
  }

  int vectorId(int i) => vectorAtIndex(i).id;
}

// ---------------------------------------------------------------------
// Facet and Edge
// ---------------------------------------------------------------------
class Facet {
  List<int> N = List.filled(3, 0);
  int id = 0;
  int visitedTime = 0;
  bool isDeleted = false;
  Plane plane = Plane();

  Facet([this.id = 0, Plane? p]) {
    if (p != null) plane = p;
  }
}

class Edge {
  int netID = 0;
  int faceID = 0;
}

// ---------------------------------------------------------------------
// Global containers (exactly the same layout as the C++ version)
// ---------------------------------------------------------------------
class _Globals {
  static List<Facet> facets = <Facet>[];
  static List<List<Vector>> hullPoints = <List<Vector>>[];
  static int timeStep = 0;

  // edges[2][MAX_SIZE]
  static List<List<Edge>> edges = List.generate(
      2, (_) => List.generate(MAX_SIZE, (_) => Edge()));

  static List<int> visitTime = List.filled(MAX_SIZE, 0);
  static List<int> queue = <int>[];
  static List<int> resFNew = <int>[];
  static List<int> resFDel = <int>[];
  static List<Vector> resPt = <Vector>[];
}

// ---------------------------------------------------------------------
// Geometry helpers (distance, above‑test …)
// ---------------------------------------------------------------------
double distancePointPlane(Vector vec, Plane plane) {
  final num = vec.subtract(plane.u).scalarProduct(plane.normal());
  final den = plane.normal().magnitude();
  return num / den;
}

double distancePointLine(Vector vec, Line line) {
  final length = vec.subtract(line.u).magnitude();
  if (length == 0.0) return 0.0;
  final cross = line.v
      .subtract(line.u)
      .vectorProduct(vec.subtract(line.u))
      .magnitude();
  final denom = line.v.subtract(line.u).magnitude();
  return cross / denom;
}

double distancePointPoint(Vector a, Vector b) => a.subtract(b).magnitude();

bool isAbove(Vector point, Plane plane) =>
    isGreaterThan(point.subtract(plane.u).scalarProduct(plane.normal()), 0.0);

// ---------------------------------------------------------------------
// Convex‑Hull wrapper (the class that contains the surface‑area routine)
// ---------------------------------------------------------------------
class ConvexHulls3d {
  int index; // the facet that currently holds the hull
  double surfaceArea = 0.0;

  ConvexHulls3d(this.index);

  double getSurfaceArea() {
    if (isGreaterThan(surfaceArea, 0.0)) return surfaceArea;

    _Globals.timeStep++;
    _dfsArea(index);
    return surfaceArea;
  }

  // -----------------------------------------------------------------
  // Recursive horizon search – returns the first point of the horizon
  // (or –1 / –2 as sentinel values, exactly like the C++ code)
  // -----------------------------------------------------------------
  int getHorizon(int f, Vector point, List<int> resDel) {
    final Facet Ff = _Globals.facets[f];
    if (!isAbove(point, Ff.plane)) return 0;
    if (Ff.visitedTime == _Globals.timeStep) return -1;

    Ff.visitedTime = _Globals.timeStep;
    Ff.isDeleted = true;
    resDel.add(Ff.id);
    int result = -2; // “not decided yet”

    for (int i = 0; i < 3; ++i) {
      final int ni = Ff.N[i];
      final int horizon = getHorizon(ni, point, resDel);
      if (horizon == 0) {
        // Horizon edge – store it in the global “edges” table
        final int a = _Globals.facets[f].plane.vectorId(i);
        final int b = _Globals.facets[f].plane.vectorId((i + 1) % 3);
        for (int idx = 0; idx < 2; ++idx) {
          final int pt = (idx == 0) ? a : b;
          final int facet = ni;
          if (_Globals.visitTime[pt] != _Globals.timeStep) {
            _Globals.visitTime[pt] = _Globals.timeStep;
            _Globals.edges[0][pt].netID = (idx == 0) ? b : a;
            _Globals.edges[0][pt].faceID = facet;
          } else {
            _Globals.edges[1][pt].netID = (idx == 0) ? b : a;
            _Globals.edges[1][pt].faceID = facet;
          }
        }
        result = a;
      } else if (horizon != -1 && horizon != -2) {
        result = horizon;
      }
    }
    return result;
  }

  // -----------------------------------------------------------------
  // Depth‑first search for surface area (exact copy of the C++ code)
  // -----------------------------------------------------------------
  void _dfsArea(int f) {
    if (_Globals.facets[f].visitedTime == _Globals.timeStep) return;
    _Globals.facets[f].visitedTime = _Globals.timeStep;
    final Vector normal = _Globals.facets[f].plane.normal();
    surfaceArea += normal.magnitude() / 2.0;
    for (int i = 0; i < 3; ++i) {
      _dfsArea(_Globals.facets[f].N[i]);
    }
  }
}

// ---------------------------------------------------------------------
// Helper that creates the four‑point seed tetrahedron
// ---------------------------------------------------------------------
ConvexHulls3d getInitialHull(List<Vector> points, int totalPoints) {
  // -------------------------------------------------
  // 1️⃣ Find the 6 extreme points (min / max on each axis)
  // -------------------------------------------------
  final List<Vector> extremes = List.filled(6, points[1]);
  for (int i = 1; i <= totalPoints; ++i) {
    final Vector p = points[i];
    if (isGreaterThan(p.x, extremes[0].x)) extremes[0] = p;
    if (isGreaterThan(extremes[1].x, p.x)) extremes[1] = p;
    if (isGreaterThan(p.y, extremes[2].y)) extremes[2] = p;
    if (isGreaterThan(extremes[3].y, p.y)) extremes[3] = p;
    if (isGreaterThan(p.z, extremes[4].z)) extremes[4] = p;
    if (isGreaterThan(extremes[5].z, p.z)) extremes[5] = p;
  }

  // -------------------------------------------------
  // 2️⃣ Furthest pair among the six extremes → line
  // -------------------------------------------------
  Vector extreme0 = extremes[0];
  Vector extreme1 = extremes[1];
  for (int i = 0; i < 6; ++i) {
    for (int j = i + 1; j < 6; ++j) {
      final d = distancePointPoint(extremes[i], extremes[j]);
      if (isGreaterThan(d, distancePointPoint(extreme0, extreme1))) {
        extreme0 = extremes[i];
        extreme1 = extremes[j];
      }
    }
  }

  // -------------------------------------------------
  // 3️⃣ Furthest point from that line → third vertex
  // -------------------------------------------------
  final line = Line(extreme0, extreme1);
  Vector extreme2 = extremes[0];
  for (int i = 0; i < 6; ++i) {
    if (isGreaterThan(
        distancePointLine(extremes[i], line),
        distancePointLine(extreme2, line))) {
      extreme2 = extremes[i];
    }
  }

  // -------------------------------------------------
  // 4️⃣ Furthest point from the plane defined by the three above
  // -------------------------------------------------
  final basePlane = Plane(extreme0, extreme1, extreme2);
  Vector extreme3 = points[1];
  for (int i = 1; i <= totalPoints; ++i) {
    final d1 = distancePointPlane(points[i], basePlane).abs();
    final d2 = distancePointPlane(extreme3, basePlane).abs();
    if (isGreaterThan(d1, d2)) extreme3 = points[i];
  }

  // If the point lies under the plane we have to flip two vertices
  if (isGreaterThan(0.0, distancePointPlane(extreme3, basePlane))) {
    final tmp = extreme1;
    extreme1 = extreme2;
    extreme2 = tmp;
  }

  // -------------------------------------------------
  // 5️⃣ Create the first four facets (the seed tetrahedron)
  // -------------------------------------------------
  final List<int> f = List.filled(4, 0);
  for (int i = 0; i < 4; ++i) {
    _Globals.facets.add(Facet(_Globals.facets.length));
    f[i] = _Globals.facets.length - 1;
  }

  _Globals.facets[f[0]].plane = Plane(extreme0, extreme2, extreme1);
  _Globals.facets[f[1]].plane = Plane(extreme0, extreme1, extreme3);
  _Globals.facets[f[2]].plane = Plane(extreme1, extreme2, extreme3);
  _Globals.facets[f[3]].plane = Plane(extreme2, extreme0, extreme3);

  _Globals.facets[f[0]].N = [f[3], f[2], f[1]];
  _Globals.facets[f[1]].N = [f[0], f[2], f[3]];
  _Globals.facets[f[2]].N = [f[0], f[3], f[1]];
  _Globals.facets[f[3]].N = [f[0], f[1], f[2]];

  // -------------------------------------------------
  // 6️⃣ Allocate hull‑point containers (one per facet)
  // -------------------------------------------------
  for (int i = 0; i < 4; ++i) {
    _Globals.hullPoints.add(<Vector>[]);
  }

  // -------------------------------------------------
  // 7️⃣ Distribute the remaining points to the facet they lie “above”
  // -------------------------------------------------
  for (int i = 1; i <= totalPoints; ++i) {
    final Vector p = points[i];
    if (p.equals(extreme0) ||
        p.equals(extreme1) ||
        p.equals(extreme2) ||
        p.equals(extreme3)) continue;

    for (int j = 0; j < 4; ++j) {
      if (isAbove(p, _Globals.facets[f[j]].plane)) {
        _Globals.hullPoints[f[j]].add(p);
        break;
      }
    }
  }

  return ConvexHulls3d(f[0]);
}

// ---------------------------------------------------------------------
// Main Quick‑Hull driver (exact port of the C++ `QuickHull3D` function)
// ---------------------------------------------------------------------
ConvexHulls3d quickHull3D(List<Vector> points, int totalPoints) {
  ConvexHulls3d hull = getInitialHull(points, totalPoints);

  // ---- initialise the processing queue --------------------------------
  _Globals.queue.clear();
  _Globals.queue.add(hull.index);
  for (int i = 0; i < 3; ++i) {
    _Globals.queue.add(_Globals.facets[hull.index].N[i]);
  }

  int newHorizon = 0;

  while (_Globals.queue.isNotEmpty) {
    final int nf = _Globals.queue.removeAt(0);

    // facet already deleted or empty → skip (but remember the last non‑deleted)
    if (_Globals.facets[nf].isDeleted || _Globals.hullPoints[nf].isEmpty) {
      if (!_Globals.facets[nf].isDeleted) newHorizon = nf;
      continue;
    }

    // -------------------------------------------------
    // 1️⃣ Find the furthest point of the current facet
    // -------------------------------------------------
    Vector point = _Globals.hullPoints[nf][0];
    for (final vec in _Globals.hullPoints[nf]) {
      if (isGreaterThan(
          distancePointPlane(vec, _Globals.facets[nf].plane),
          distancePointPlane(point, _Globals.facets[nf].plane))) {
        point = vec;
      }
    }

    // -------------------------------------------------
    // 2️⃣ Determine the horizon (all facets that will be removed)
    // -------------------------------------------------
    _Globals.timeStep++;
    _Globals.resFDel.clear();
    final int horizon = hull.getHorizon(nf, point, _Globals.resFDel);

    // -------------------------------------------------
    // 3️⃣ Build the new faces that replace the deleted ones
    // -------------------------------------------------
    _Globals.resFNew.clear();
    _Globals.timeStep++;
    int from = -1;
    int lastF = -1;
    int firstF = -1;

    int cur = horizon;
    while (_Globals.visitTime[cur] != _Globals.timeStep) {
      // mark as visited in this sweep
      _Globals.visitTime[cur] = _Globals.timeStep;

      // ----- find the "next" edge on the horizon -----
      int net, f;
      if (_Globals.edges[0][cur].netID == from) {
        net = _Globals.edges[1][cur].netID;
        f = _Globals.edges[1][cur].faceID;
      } else {
        net = _Globals.edges[0][cur].netID;
        f = _Globals.edges[0][cur].faceID;
      }

      // ----- locate the two vertices of the old facet that belong to this edge -----
      int pt1 = 0, pt2 = 0;
      for (int i = 0; i < 3; ++i) {
        if (points[cur].equals(_Globals.facets[f].plane.vectorAtIndex(i))) pt1 = i;
        if (points[net].equals(_Globals.facets[f].plane.vectorAtIndex(i))) pt2 = i;
      }
      // guarantee (pt1,pt2) are oriented consistently
      if ((pt1 + 1) % 3 != pt2) {
        final tmp = pt1;
        pt1 = pt2;
        pt2 = tmp;
      }

      // ----- create the new facet -----
      final Plane newPlane = Plane(
          _Globals.facets[f].plane.vectorAtIndex(pt2),
          _Globals.facets[f].plane.vectorAtIndex(pt1),
          point);
      _Globals.facets.add(Facet(_Globals.facets.length, newPlane));
      final int newF = _Globals.facets.length - 1;
      _Globals.hullPoints.add(<Vector>[]);
      _Globals.resFNew.add(newF);

      // ----- link the new facet with the old neighbour -----
      _Globals.facets[newF].N[0] = f;
      _Globals.facets[f].N[pt1] = newF;

      // ----- link consecutive new facets together (forming a fan) -----
      if (lastF >= 0) {
        // the orientation of the shared edge decides which N‑slot to fill
        if (_Globals.facets[newF].plane.vectorAtIndex(1).equals(_Globals.facets[lastF].plane.u)) {
          _Globals.facets[newF].N[1] = lastF;
          _Globals.facets[lastF].N[2] = newF;
        } else {
          _Globals.facets[newF].N[2] = lastF;
          _Globals.facets[lastF].N[1] = newF;
        }
      } else {
        firstF = newF;
      }

      lastF = newF;
      from = cur;
      cur = net;
    }

    // ---- close the fan (first ↔ last) ----
    if (_Globals.facets[firstF].plane.vectorAtIndex(1).equals(_Globals.facets[lastF].plane.u)) {
      _Globals.facets[firstF].N[1] = lastF;
      _Globals.facets[lastF].N[2] = firstF;
    } else {
      _Globals.facets[firstF].N[2] = lastF;
      _Globals.facets[lastF].N[1] = firstF;
    }

    // -------------------------------------------------
    // 4️⃣ Re‑assign points that were stored in the deleted facets
    // -------------------------------------------------
    _Globals.resPt.clear();
    for (final int fId in _Globals.resFDel) {
      _Globals.resPt.addAll(_Globals.hullPoints[fId]);
      _Globals.hullPoints[fId].clear();
    }

    for (final Vector vec in _Globals.resPt) {
      if (vec.equals(point)) continue;
      for (final int fId in _Globals.resFNew) {
        if (isAbove(vec, _Globals.facets[fId].plane)) {
          _Globals.hullPoints[fId].add(vec);
          break;
        }
      }
    }

    // -------------------------------------------------
    // 5️⃣ Queue the new facets for further processing
    // -------------------------------------------------
    for (final int fId in _Globals.resFNew) {
      _Globals.queue.add(fId);
    }
  }

  // The last facet that still holds a point becomes the new “starting” facet.
  hull.index = newHorizon;
  return hull;
}

// ---------------------------------------------------------------------
// Helper that prepares the static containers (exact copy of C++ `prepareConvexHulls`)
// ---------------------------------------------------------------------
void prepareConvexHulls() {
  // reserve index 0 (as the C++ code does)
  _Globals.hullPoints.add(<Vector>[]);
  _Globals.facets.add(Facet());

  // initialise the edge matrix (already allocated, just reset the fields)
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < MAX_SIZE; ++j) {
      _Globals.edges[i][j] = Edge();
    }
  }
}

// ---------------------------------------------------------------------
// Example driver (exactly the same points as the C++ main)
// ---------------------------------------------------------------------
void main() {
  prepareConvexHulls();

  const int n = 4;
  // points[0] is a dummy placeholder – the original algorithm expects 1‑based indexing
  final List<Vector> points = List.filled(n + 1, Vector());

  points[1] = Vector(0, 0, 0, 1);
  points[2] = Vector(1, 0, 0, 2);
  points[3] = Vector(0, 1, 0, 3);
  points[4] = Vector(0, 0, 1, 4);

  final ConvexHulls3d hull = quickHull3D(points, n);
  // three decimal places, same as the C++ `cout << fixed << setprecision(3)`
  print(hull.getSurfaceArea().toStringAsFixed(3));
}
Output:
2.366



Translation of: Go
Const NULL As Any Ptr = 0
Const MAXN = 2500
Const EPS = 1e-8

' Vect represents a 3D point/vector
Type Vect
    x As Single
    y As Single
    z As Single
    id As Integer
End Type

' Linea is the segment u->v
Type Linea
    u As Vect Ptr
    v As Vect Ptr
End Type

' Plano is defined by three points u, v, w
Type Plano
    u As Vect Ptr
    v As Vect Ptr
    w As Vect Ptr
End Type

' Faceta is a face in the hull
Type Faceta
    n(2) As Integer
    id As Integer
    vistime As Integer
    isdel As Integer       ' 0 = false, 1 = true
    p As Plano
End Type

' Edge on the horizon
Type Edge
    netid As Integer
    facetid As Integer
End Type

' ConvexHulls3d manages hull construction
Type ConvexHulls3d
    index As Integer
    surfacearea As Single
End Type

' Global variables
Dim Shared FAC() As Faceta Ptr
Dim Shared pts(MAXN, MAXN) As Vect Ptr
Dim Shared G_TIME As Integer
Dim Shared e(1, MAXN-1) As Edge
Dim Shared vistimeArr(MAXN-1) As Integer
Dim Shared que() As Integer
Dim Shared resfnew() As Integer
Dim Shared resfdel() As Integer
Dim Shared respt() As Vect Ptr

'' Auxiliary vector functions
Function Vect_Sub(a As Vect Ptr, b As Vect Ptr) As Vect
    Dim res As Vect
    res.x = a->x - b->x
    res.y = a->y - b->y
    res.z = a->z - b->z
    res.id = 0
    Return res
End Function

Function Vect_Cross(a As Vect Ptr, b As Vect Ptr) As Vect
    Dim res As Vect
    res.x = a->y * b->z - a->z * b->y
    res.y = a->z * b->x - a->x * b->z
    res.z = a->x * b->y - a->y * b->x
    res.id = 0
    Return res
End Function

Function Vect_Dot(a As Vect Ptr, b As Vect Ptr) As Single
    Return a->x * b->x + a->y * b->y + a->z * b->z
End Function

Function Vect_Mag(a As Vect Ptr) As Single
    Return Sqr(a->x * a->x + a->y * a->y + a->z * a->z)
End Function

Function Vect_Eq(a As Vect Ptr, b As Vect Ptr) As Integer
    Return Abs(a->x - b->x) < EPS And Abs(a->y - b->y) < EPS And Abs(a->z - b->z) < EPS
End Function

'' Operations with planes
Function Plano_Normal(p As Plano Ptr) As Vect
    Dim ab As Vect = Vect_Sub(p->v, p->u)
    Dim ac As Vect = Vect_Sub(p->w, p->u)
    Return Vect_Cross(@ab, @ac)
End Function

Function distPuntoPlano(v As Vect Ptr, p As Plano) As Single
    Dim tmp_sub As Vect = Vect_Sub(v, p.u)
    Dim n As Vect = Plano_Normal(@p)
    Dim num As Single = Vect_Dot(@tmp_sub, @n)
    Dim den As Single = Vect_Mag(@n)
    Return num / den
End Function

Function distPuntoLinea(v As Vect Ptr, f As Linea) As Single
    Dim sub_fu As Vect = Vect_Sub(f.v, f.u)
    Dim sub_vu As Vect = Vect_Sub(v, f.u)
    Dim cross As Vect = Vect_Cross(@sub_fu, @sub_vu)
    Return Vect_Mag(@cross) / Vect_Mag(@sub_fu)
End Function

Function distPuntoPunto(u As Vect Ptr, v As Vect Ptr) As Single
    Dim tmp_sub As Vect = Vect_Sub(u, v)
    Return Vect_Mag(@tmp_sub)
End Function

Function isAbove(v As Vect Ptr, p As Plano) As Integer
    Dim tmp_sub As Vect = Vect_Sub(v, p.u)
    Dim n As Vect = Plano_Normal(@p)
    Return (Vect_Dot(@tmp_sub, @n) > EPS)
End Function

' Initialize globals
Sub preConvexHulls()
    Redim FAC(0)
    FAC(0) = Callocate(Sizeof(Faceta))  ' dummy facet
    G_TIME = 0
End Sub

' DFS to accumulate area
Sub dfsArea(h As ConvexHulls3d Ptr, nf As Integer)
    If FAC(nf)->vistime = G_TIME Then Exit Sub
    FAC(nf)->vistime = G_TIME
    
    Dim nrm As Vect = Plano_Normal(@FAC(nf)->p)
    h->surfacearea += Vect_Mag(@nrm) / 2.0
    
    For i As Integer = 0 To 2
        dfsArea(h, FAC(nf)->n(i))
    Next
End Sub

' GetSurfaceArea returns (and caches) the hull surface area
Function GetSurfaceArea(h As ConvexHulls3d Ptr) As Single
    If h->surfacearea > EPS Then Return h->surfacearea
    
    G_TIME += 1
    dfsArea(h, h->index)
    Return h->surfacearea
End Function

' Recursively find the horizon around point p
Function getHorizon(nf As Integer, p As Vect Ptr, resfdel() As Integer) As Integer
    FAC(nf)->vistime = G_TIME
    FAC(nf)->isdel = 1
    
    Redim Preserve resfdel(Ubound(resfdel) + 1)
    resfdel(Ubound(resfdel)) = nf
    
    Dim s As Integer = 0
    
    For i As Integer = 0 To 2
        Dim nei As Integer = FAC(nf)->n(i)
        
        If FAC(nei)->vistime = G_TIME Then Continue For
        
        If isAbove(p, FAC(nei)->p) Then
            Dim result As Integer = getHorizon(nei, p, resfdel())
            s += result
        Else
            s += 1
            
            Redim Preserve FAC(Ubound(FAC) + 1)
            FAC(Ubound(FAC)) = Callocate(Sizeof(Faceta))
            FAC(Ubound(FAC))->id = Ubound(FAC)
            
            Dim newf As Integer = Ubound(FAC)
            
            Redim Preserve resfnew(Ubound(resfnew) + 1)
            resfnew(Ubound(resfnew)) = newf
        End If
    Next
    
    Return s
End Function

Sub AsignarPuntoFacetaa(nf As Integer, v As Vect Ptr)
    Dim i As Integer = 0
    While pts(nf, i) <> 0 And i < MAXN
        i += 1
    Wend
    
    If i < MAXN Then pts(nf, i) = v
End Sub

Sub ActualizarCola()
    If Ubound(que) >= 1 Then
        Dim tmp() As Integer
        Redim tmp(Ubound(que) - 1)
        For i As Integer = 0 To Ubound(tmp)
            tmp(i) = que(i + 1)
        Next
        Redim que(Ubound(tmp))
        For i As Integer = 0 To Ubound(tmp)
            que(i) = tmp(i)
        Next
    Else
        Redim que(-1)
    End If
End Sub

' Build the initial tetrahedron
Function getStart(punto() As Vect Ptr, totp As Integer) As ConvexHulls3d Ptr
    Dim As Vect Ptr pt(5), s(3)
    Dim As Integer i, j
    
    For i = 0 To 5
        pt(i) = punto(1)
    Next
    
    ' pick extreme coords
    For i = 1 To totp
        Dim v As Vect Ptr = punto(i)
        If v->x > pt(0)->x Then pt(0) = v
        If v->x < pt(1)->x Then pt(1) = v
        If v->y > pt(2)->y Then pt(2) = v
        If v->y < pt(3)->y Then pt(3) = v
        If v->z > pt(4)->z Then pt(4) = v
        If v->z < pt(5)->z Then pt(5) = v
    Next
    
    ' Take the two points with the largest distance
    s(0) = pt(0): s(1) = pt(1)
    For i = 0 To 5
        For j = i + 1 To 5
            If distPuntoPunto(pt(i), pt(j)) > distPuntoPunto(s(0), s(1)) Then
                s(0) = pt(i): s(1) = pt(j)
            End If
        Next
    Next
    
    ' Take the point farthest from the line connecting the two points
    Dim L As Linea
    L.u = s(0): L.v = s(1)
    s(2) = pt(0)
    For i = 0 To 5
        If distPuntoLinea(pt(i), L) > distPuntoLinea(s(2), L) Then s(2) = pt(i)
    Next
    
    ' Take the point farthest from the face
    Dim basePlano As Plano
    basePlano.u = s(0): basePlano.v = s(1): basePlano.w = s(2)
    s(3) = punto(1)
    For i = 1 To totp
        If Abs(distPuntoPlano(punto(i), basePlano)) > Abs(distPuntoPlano(s(3), basePlano)) Then
            s(3) = punto(i)
        End If
    Next
    
    ' Ensure that the constructed face faces outwards
    If distPuntoPlano(s(3), basePlano) < 0 Then Swap s(1), s(2)
    
    ' Make 4 facets
    Dim f(3) As Integer
    For i = 0 To 3
        Redim Preserve FAC(Ubound(FAC) + 1)
        FAC(Ubound(FAC)) = Callocate(Sizeof(Faceta))
        FAC(Ubound(FAC))->id = Ubound(FAC)
        f(i) = Ubound(FAC)
    Next
    
    FAC(f(0))->p.u = s(0): FAC(f(0))->p.v = s(2): FAC(f(0))->p.w = s(1)
    FAC(f(1))->p.u = s(0): FAC(f(1))->p.v = s(1): FAC(f(1))->p.w = s(3)
    FAC(f(2))->p.u = s(1): FAC(f(2))->p.v = s(2): FAC(f(2))->p.w = s(3)
    FAC(f(3))->p.u = s(2): FAC(f(3))->p.v = s(0): FAC(f(3))->p.w = s(3)
    
    FAC(f(0))->n(0) = f(3): FAC(f(0))->n(1) = f(2): FAC(f(0))->n(2) = f(1)
    FAC(f(1))->n(0) = f(0): FAC(f(1))->n(1) = f(2): FAC(f(1))->n(2) = f(3)
    FAC(f(2))->n(0) = f(0): FAC(f(2))->n(1) = f(3): FAC(f(2))->n(2) = f(1)
    FAC(f(3))->n(0) = f(0): FAC(f(3))->n(1) = f(1): FAC(f(3))->n(2) = f(2)
    
    
    ' Assign point set space to four faces
    For i = 0 To MAXN
        For j = 0 To MAXN
            pts(i, j) = NULL
        Next
    Next
    
    ' Assign points to four faces
    For i = 1 To totp
        Dim v As Vect Ptr = punto(i)
        If Vect_Eq(v, s(0)) Or Vect_Eq(v, s(1)) Or Vect_Eq(v, s(2)) Or Vect_Eq(v, s(3)) Then Continue For
        
        For j = 0 To 3
            If isAbove(v, FAC(f(j))->p) Then
                AsignarPuntoFacetaa(f(j), v)
                Exit For
            End If
        Next
    Next
    
    ' Return the initial simplex, using a face as index
    Dim hull As ConvexHulls3d Ptr = Callocate(Sizeof(ConvexHulls3d))
    hull->index = f(0)
    Return hull
End Function

'' The main QuickHull3D loop
Function quickHull3d(punto() As Vect Ptr, totp As Integer) As ConvexHulls3d Ptr
    Dim As Integer i, j, k
    Dim hull As ConvexHulls3d Ptr = getStart(punto(), totp)
    
    ' Add the face of initial simplex to queue
    Redim que(0)
    que(0) = hull->index
    For i = 0 To 2
        Redim Preserve que(Ubound(que) + 1)
        que(Ubound(que)) = FAC(hull->index)->n(i)
    Next
    
    ' snew saves index face of the final convex hull
    Dim snew As Integer = 0
    
    While Ubound(que) >= 0
        Dim nf As Integer = que(0)
        ActualizarCola()
        
        ' Skip if the current face has been deleted
        If FAC(nf)->isdel Then  Continue While
        
        ' Find the farthest point from the face
        Dim p As Vect Ptr = NULL
        For i = 0 To MAXN
            If pts(nf, i) <> 0 Then
                p = pts(nf, i)
                Exit For
            End If
        Next
        
        If p = NULL Then
            If FAC(nf)->isdel = 0 Then snew = nf
            Continue While
        End If
        
        ' Find the horizon
        G_TIME += 1
        Redim resfdel(0)
        resfdel(0) = 0
        Redim resfdel(-1)
        
        Redim resfnew(0)
        resfnew(0) = 0
        Redim resfnew(-1)
        
        ' The current face must be deleted, so start dfs from current face
        Dim s As Integer = getHorizon(nf, p, resfdel())
        
        For i = 0 To Ubound(resfdel)
            Dim fid As Integer = resfdel(i)
            
            For j = 0 To MAXN
                Dim pt As Vect Ptr = pts(fid, j)
                If pt = NULL Then Continue For
                
                If Vect_Eq(pt, p) Then Continue For
                
                ' reassign them
                For k = 0 To Ubound(resfnew)
                    Dim nfid As Integer = resfnew(k)
                    If isAbove(pt, FAC(nfid)->p) Then
                        AsignarPuntoFacetaa(nfid, pt)
                        Exit For
                    End If
                Next
            Next
        Next
        
        ' enqueue new faces
        For i = 0 To Ubound(resfnew)
            Redim Preserve que(Ubound(que) + 1)
            que(Ubound(que)) = resfnew(i)
        Next
    Wend
    
    If snew = 0 And Ubound(FAC) > 0 Then
        For i = 1 To Ubound(FAC)
            If FAC(i) <> NULL And FAC(i)->isdel = 0 Then
                snew = i
                Exit For
            End If
        Next
    End If
    
    hull->index = snew
    Return hull
End Function

Sub main()
    Dim As Integer i
    preConvexHulls()
    
    ' Example: a unit tetrahedron
    Dim As Vect Ptr punto(1 To 4)
    For i = 1 To 4
        punto(i) = Callocate(Sizeof(Vect))
    Next
    
    punto(1)->x = 0: punto(1)->y = 0: punto(1)->z = 0
    punto(2)->x = 1: punto(2)->y = 0: punto(2)->z = 0
    punto(3)->x = 0: punto(3)->y = 1: punto(3)->z = 0
    punto(4)->x = 0: punto(4)->y = 0: punto(4)->z = 1
    
    Dim As ConvexHulls3d Ptr hull = quickHull3d(punto(), 4)
    Print Using "##.###"; GetSurfaceArea(hull)
    
    ' Free memory
    For i = 1 To 4
        Deallocate(punto(i))
    Next
    For i = 0 To Ubound(FAC)
        If FAC(i) <> NULL Then Deallocate(FAC(i))
    Next    
    Deallocate(hull)
End Sub

main()

Sleep
Output:
 2.366
Translation of: Python
package main

import (
    "fmt"
    "math"
)

const (
    MAXN = 2500
    EPS  = 1e-8
)

// Globals
var (
    FAC        []*Facet
    pts        [][]*Vect
    TIME       int
    e          [2][MAXN]Edge
    vistimeArr [MAXN]int
    que        []int
    resfnew    []int
    resfdel    []int
    respt      []*Vect
)

// Vect represents a 3D point/vector
type Vect struct {
    x, y, z float64
    id      int
}

func (a *Vect) Sub(b *Vect) *Vect {
    return &Vect{a.x - b.x, a.y - b.y, a.z - b.z, 0}
}

func (a *Vect) Cross(b *Vect) *Vect {
    return &Vect{
        a.y*b.z - a.z*b.y,
        a.z*b.x - a.x*b.z,
        a.x*b.y - a.y*b.x,
        0,
    }
}

func (a *Vect) Dot(b *Vect) float64 {
    return a.x*b.x + a.y*b.y + a.z*b.z
}

func (a *Vect) Mag() float64 {
    return math.Sqrt(a.x*a.x + a.y*a.y + a.z*a.z)
}

func (a *Vect) Eq(b *Vect) bool {
    return eq(a.x, b.x) && eq(a.y, b.y) && eq(a.z, b.z)
}

// Line is the segment u->v
type Line struct {
    u, v *Vect
}

// Plane is defined by three points u, v, w
type Plane struct {
    u, v, w *Vect
}

// Normal vector of the plane
func (p *Plane) Normal() *Vect {
    return p.v.Sub(p.u).Cross(p.w.Sub(p.u))
}

// vecAt returns the i-th defining point of the plane (0=u,1=v,2=w)
func (p *Plane) vecAt(i int) *Vect {
    switch i {
    case 0:
        return p.u
    case 1:
        return p.v
    default:
        return p.w
    }
}

// vecID returns the id of the i-th plane point
func (p *Plane) vecID(i int) int {
    return p.vecAt(i).id
}

// Facet is a face in the hull
type Facet struct {
    n       [3]int // neighbor facet indices
    id      int
    vistime int
    isdel   bool
    p       Plane
}

// Edge on the horizon
type Edge struct {
    netid, facetid int
}

// ConvexHulls3d manages hull construction
type ConvexHulls3d struct {
    index       int
    surfacearea float64
}

// Basic floating comparisons
func eq(a, b float64) bool { return math.Abs(a-b) < EPS }
func gtr(a, b float64) bool { return a-b > EPS }
func Abs(x float64) float64 { if x < 0 { return -x }; return x }

// Distances
func distPointPlane(v *Vect, p Plane) float64 {
    num := v.Sub(p.u).Dot(p.Normal())
    den := p.Normal().Mag()
    return num / den
}
func distPointLine(v *Vect, f Line) float64 {
    d := v.Sub(f.u).Mag()
    if d == 0 {
        return 0
    }
    return f.v.Sub(f.u).Cross(v.Sub(f.u)).Mag() / f.v.Sub(f.u).Mag()
}
func distPointPoint(u, v *Vect) float64 {
    return u.Sub(v).Mag()
}
func isAbove(v *Vect, p Plane) bool {
    return gtr(v.Sub(p.u).Dot(p.Normal()), 0)
}

// Initialize globals
func preConvexHulls() {
    pts = append(pts, nil)      // reserve index 0
    FAC = append(FAC, &Facet{}) // dummy facet at 0
}

// DFS to accumulate area
func (h *ConvexHulls3d) dfsArea(nf int) {
    if FAC[nf].vistime == TIME {
        return
    }
    FAC[nf].vistime = TIME
    nrm := FAC[nf].p.Normal()
    h.surfacearea += nrm.Mag() / 2
    for i := 0; i < 3; i++ {
        h.dfsArea(FAC[nf].n[i])
    }
}

// GetSurfaceArea returns (and caches) the hull surface area
func (h *ConvexHulls3d) GetSurfaceArea() float64 {
    if gtr(h.surfacearea, 0) {
        return h.surfacearea
    }
    TIME++
    h.dfsArea(h.index)
    return h.surfacearea
}

// Recursively find the horizon around point p
func (h *ConvexHulls3d) getHorizon(f int, p *Vect, resfdel *[]int) int {
    if !isAbove(p, FAC[f].p) {
        return 0
    }
    if FAC[f].vistime == TIME {
        return -1
    }
    FAC[f].vistime = TIME
    FAC[f].isdel = true
    *resfdel = append(*resfdel, FAC[f].id)
    ret := -2
    for i := 0; i < 3; i++ {
        r := h.getHorizon(FAC[f].n[i], p, resfdel)
        if r == 0 {
            a := FAC[f].p.vecID(i)
            b := FAC[f].p.vecID((i + 1) % 3)
            for j, pt := range []int{a, b} {
                if vistimeArr[pt] != TIME {
                    vistimeArr[pt] = TIME
                    e[0][pt] = Edge{netid: []int{b, a}[j], facetid: FAC[f].n[i]}
                } else {
                    e[1][pt] = Edge{netid: []int{b, a}[j], facetid: FAC[f].n[i]}
                }
            }
            ret = a
        } else if r != -1 && r != -2 {
            ret = r
        }
    }
    return ret
}

// Build the initial tetrahedron
func getStart(point []*Vect, totp int) *ConvexHulls3d {
    var pt [6]*Vect
    var s [4]*Vect
    for i := range pt {
        pt[i] = point[1]
    }
    // pick extreme coords
    for i := 1; i <= totp; i++ {
        v := point[i]
        if gtr(v.x, pt[0].x) {
            pt[0] = v
        }
        if gtr(pt[1].x, v.x) {
            pt[1] = v
        }
        if gtr(v.y, pt[2].y) {
            pt[2] = v
        }
        if gtr(pt[3].y, v.y) {
            pt[3] = v
        }
        if gtr(v.z, pt[4].z) {
            pt[4] = v
        }
        if gtr(pt[5].z, v.z) {
            pt[5] = v
        }
    }
    // take furthest pair
    s[0], s[1] = pt[0], pt[1]
    for i := 0; i < 6; i++ {
        for j := i + 1; j < 6; j++ {
            d := distPointPoint(pt[i], pt[j])
            if gtr(d, distPointPoint(s[0], s[1])) {
                s[0], s[1] = pt[i], pt[j]
            }
        }
    }
    // furthest from that line
    L := Line{s[0], s[1]}
    s[2] = pt[0]
    for i := 0; i < 6; i++ {
        if gtr(distPointLine(pt[i], L), distPointLine(s[2], L)) {
            s[2] = pt[i]
        }
    }
    // furthest from the plane
    s[3] = point[1]
    base := Plane{s[0], s[1], s[2]}
    for i := 1; i <= totp; i++ {
        d1 := Abs(distPointPlane(point[i], base))
        d2 := Abs(distPointPlane(s[3], base))
        if gtr(d1, d2) {
            s[3] = point[i]
        }
    }
    if gtr(0, distPointPlane(s[3], base)) {
        s[1], s[2] = s[2], s[1]
    }
    // make 4 facets
    f := make([]int, 4)
    for i := 0; i < 4; i++ {
        FAC = append(FAC, &Facet{id: len(FAC)})
        f[i] = len(FAC) - 1
    }
    FAC[f[0]].p = Plane{s[0], s[2], s[1]}
    FAC[f[1]].p = Plane{s[0], s[1], s[3]}
    FAC[f[2]].p = Plane{s[1], s[2], s[3]}
    FAC[f[3]].p = Plane{s[2], s[0], s[3]}
    FAC[f[0]].n = [3]int{f[3], f[2], f[1]}
    FAC[f[1]].n = [3]int{f[0], f[2], f[3]}
    FAC[f[2]].n = [3]int{f[0], f[3], f[1]}
    FAC[f[3]].n = [3]int{f[0], f[1], f[2]}

    // prepare point‐lists
    for i := 0; i < 4; i++ {
        pts = append(pts, nil)
    }
    // assign remaining points
    for i := 1; i <= totp; i++ {
        v := point[i]
        if v.Eq(s[0]) || v.Eq(s[1]) || v.Eq(s[2]) || v.Eq(s[3]) {
            continue
        }
        for j := 0; j < 4; j++ {
            if isAbove(v, FAC[f[j]].p) {
                pts[f[j]] = append(pts[f[j]], v)
                break
            }
        }
    }
    return &ConvexHulls3d{index: f[0]}
}

// The main QuickHull3D loop
func quickHull3d(point []*Vect, totp int) *ConvexHulls3d {
    hull := getStart(point, totp)
    que = []int{hull.index}
    for i := 0; i < 3; i++ {
        que = append(que, FAC[hull.index].n[i])
    }
    snew := 0

    for len(que) > 0 {
        nf := que[0]
        que = que[1:]
        if FAC[nf].isdel || len(pts[nf]) == 0 {
            if !FAC[nf].isdel {
                snew = nf
            }
            continue
        }
        // find farthest point
        p := pts[nf][0]
        for _, v := range pts[nf][1:] {
            if gtr(distPointPlane(v, FAC[nf].p), distPointPlane(p, FAC[nf].p)) {
                p = v
            }
        }
        // find horizon
        TIME++
        resfdel = resfdel[:0]
        s := hull.getHorizon(nf, p, &resfdel)

        // build new faces around the horizon
        resfnew = resfnew[:0]
        TIME++
        from := -1
        lastf := -1
        fstf := -1
        for vistimeArr[s] != TIME {
            vistimeArr[s] = TIME
            var net, f, fnew int
            if e[0][s].netid == from {
                net, f = e[1][s].netid, e[1][s].facetid
            } else {
                net, f = e[0][s].netid, e[0][s].facetid
            }
            // find indices of s and net on facet f
            pt1, pt2 := 0, 0
            for i := 0; i < 3; i++ {
                if point[s].Eq(FAC[f].p.vecAt(i)) {
                    pt1 = i
                }
                if point[net].Eq(FAC[f].p.vecAt(i)) {
                    pt2 = i
                }
            }
            if (pt1+1)%3 != pt2 {
                pt1, pt2 = pt2, pt1
            }
            // create new facet facing outwards
            FAC = append(FAC, &Facet{
                id: len(FAC),
                p:  Plane{FAC[f].p.vecAt(pt2), FAC[f].p.vecAt(pt1), p},
            })
            fnew = len(FAC) - 1
            pts = append(pts, nil)
            resfnew = append(resfnew, fnew)

            FAC[fnew].n[0] = f
            FAC[f].n[pt1] = fnew
            if lastf >= 0 {
                // link with previous new facet
                if FAC[fnew].p.vecAt(1).Eq(FAC[lastf].p.u) {
                    FAC[fnew].n[1], FAC[lastf].n[2] = lastf, fnew
                } else {
                    FAC[fnew].n[2], FAC[lastf].n[1] = lastf, fnew
                }
            } else {
                fstf = fnew
            }
            lastf = fnew
            from = s
            s = net
        }
        // close the loop
        if FAC[fstf].p.v.Eq(FAC[lastf].p.u) {
            FAC[fstf].n[1], FAC[lastf].n[2] = lastf, fstf
        } else {
            FAC[fstf].n[2], FAC[lastf].n[1] = lastf, fstf
        }
        // collect points from deleted faces
        respt = respt[:0]
        for _, fid := range resfdel {
            respt = append(respt, pts[fid]...)
            pts[fid] = nil
        }
        // reassign them
        for _, v := range respt {
            if v == p {
                continue
            }
            for _, fid := range resfnew {
                if isAbove(v, FAC[fid].p) {
                    pts[fid] = append(pts[fid], v)
                    break
                }
            }
        }
        // enqueue new faces
        for _, fid := range resfnew {
            que = append(que, fid)
        }
    }

    hull.index = snew
    return hull
}

func main() {
    preConvexHulls()
    // Example: a unit tetrahedron
    point := []*Vect{
        nil,
        {0, 0, 0, 1},
        {1, 0, 0, 2},
        {0, 1, 0, 3},
        {0, 0, 1, 4},
    }
    hull := quickHull3d(point, 4)
    fmt.Printf("%.3f\n", hull.GetSurfaceArea())
}
Output:
2.366
Translation of: C#
import java.util.*;

public class QuickHull3D {
    static final int MAXN = 2500;
    static final double EPS = 1e-8;

    // Globals
    static List<Facet> FAC = new ArrayList<>();
    static List<List<Vect>> pts = new ArrayList<>();
    static int TIME = 0;
    static Edge[][] e = new Edge[2][MAXN];
    static int[] vistime = new int[MAXN];
    static List<Integer> queue = new ArrayList<>();
    static List<Integer> resfnew = new ArrayList<>();
    static List<Integer> resfdel = new ArrayList<>();
    static List<Vect> respt = new ArrayList<>();

    public static void main(String[] args) {
        preConvexHulls();

        // Example: unit tetrahedron
        int n = 4;
        Vect[] point = new Vect[n + 1];
        point[1] = new Vect(0, 0, 0, 1);
        point[2] = new Vect(1, 0, 0, 2);
        point[3] = new Vect(0, 1, 0, 3);
        point[4] = new Vect(0, 0, 1, 4);

        ConvexHulls3d hull = quickHull3D(point, n);
        System.out.printf("%.3f%n", hull.getSurfaceArea());
    }

    static void preConvexHulls() {
        // Reserve index 0
        pts.add(new ArrayList<>());      // dummy point list[0]
        FAC.add(new Facet());            // dummy facet[0]
        // Initialize edge array
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < MAXN; j++) {
                e[i][j] = new Edge();
            }
        }
    }

    static class Vect {
        double X, Y, Z;
        int Id;
        Vect(double x, double y, double z, int id) { X = x; Y = y; Z = z; Id = id; }
        Vect sub(Vect b) { return new Vect(X - b.X, Y - b.Y, Z - b.Z, 0); }
        Vect cross(Vect b) {
            return new Vect(
                Y * b.Z - Z * b.Y,
                Z * b.X - X * b.Z,
                X * b.Y - Y * b.X,
                0
            );
        }
        double dot(Vect b) { return X * b.X + Y * b.Y + Z * b.Z; }
        double mag() { return Math.sqrt(X * X + Y * Y + Z * Z); }
        boolean eq(Vect b) {
            // Qualify eq to the outer class's static method:
            return QuickHull3D.eq(X, b.X)
                && QuickHull3D.eq(Y, b.Y)
                && QuickHull3D.eq(Z, b.Z);
        }
    }

    static class Line {
        Vect U, V;
        Line(Vect u, Vect v) { U = u; V = v; }
    }

    static class Plane {
        Vect U, V, W;
        Plane() {}
        Plane(Vect u, Vect v, Vect w) { U = u; V = v; W = w; }
        Vect normal() { return V.sub(U).cross(W.sub(U)); }
        Vect vecAt(int i) {
            if (i == 0) return U;
            if (i == 1) return V;
            return W;
        }
        int vecId(int i) { return vecAt(i).Id; }
    }

    static class Facet {
        int[] N = new int[3];
        int Id;
        int visitTime;
        boolean isDeleted;
        Plane P = new Plane();
    }

    static class Edge {
        int netId, facetId;
    }

    static class ConvexHulls3d {
        int Index;
        double surfaceArea = 0.0;

        ConvexHulls3d(int idx) { Index = idx; }

        void dfsArea(int f) {
            Facet F = FAC.get(f);
            if (F.visitTime == TIME) return;
            F.visitTime = TIME;
            Vect nrm = F.P.normal();
            surfaceArea += nrm.mag() / 2.0;
            for (int i = 0; i < 3; i++) {
                dfsArea(F.N[i]);
            }
        }

        public double getSurfaceArea() {
            if (gtr(surfaceArea, 0.0)) return surfaceArea;
            TIME++;
            dfsArea(Index);
            return surfaceArea;
        }

        public int getHorizon(int f, Vect p, List<Integer> resDel) {
            Facet Ff = FAC.get(f);
            if (!isAbove(p, Ff.P)) return 0;
            if (Ff.visitTime == TIME) return -1;
            Ff.visitTime = TIME;
            Ff.isDeleted = true;
            resDel.add(Ff.Id);
            int ret = -2;
            for (int i = 0; i < 3; i++) {
                int ni = Ff.N[i];
                int r = getHorizon(ni, p, resDel);
                if (r == 0) {
                    int a = Ff.P.vecId(i);
                    int b = Ff.P.vecId((i + 1) % 3);
                    for (int idx = 0; idx < 2; idx++) {
                        int pt = (idx == 0 ? a : b);
                        int facet = ni;
                        if (vistime[pt] != TIME) {
                            vistime[pt] = TIME;
                            e[0][pt].netId = (idx == 0 ? b : a);
                            e[0][pt].facetId = facet;
                        } else {
                            e[1][pt].netId = (idx == 0 ? b : a);
                            e[1][pt].facetId = facet;
                        }
                    }
                    ret = a;
                } else if (r != -1 && r != -2) {
                    ret = r;
                }
            }
            return ret;
        }
    }

    // Utilities
    static boolean eq(double a, double b) { return Math.abs(a - b) < EPS; }
    static boolean gtr(double a, double b) { return a - b > EPS; }
    static double abs(double x) { return x < 0 ? -x : x; }

    static double distPointPlane(Vect v, Plane p) {
        double num = v.sub(p.U).dot(p.normal());
        double den = p.normal().mag();
        return num / den;
    }

    static double distPointLine(Vect v, Line l) {
        double d = v.sub(l.U).mag();
        if (d == 0) return 0;
        return l.V.sub(l.U).cross(v.sub(l.U)).mag() / l.V.sub(l.U).mag();
    }

    static double distPointPoint(Vect a, Vect b) { return a.sub(b).mag(); }
    static boolean isAbove(Vect v, Plane p) {
        return gtr(v.sub(p.U).dot(p.normal()), 0);
    }

    static ConvexHulls3d getStart(Vect[] point, int totp) {
        Vect[] extremes = new Vect[6];
        for (int i = 0; i < 6; i++) extremes[i] = point[1];
        for (int i = 1; i <= totp; i++) {
            Vect v = point[i];
            if (gtr(v.X, extremes[0].X)) extremes[0] = v;
            if (gtr(extremes[1].X, v.X)) extremes[1] = v;
            if (gtr(v.Y, extremes[2].Y)) extremes[2] = v;
            if (gtr(extremes[3].Y, v.Y)) extremes[3] = v;
            if (gtr(v.Z, extremes[4].Z)) extremes[4] = v;
            if (gtr(extremes[5].Z, v.Z)) extremes[5] = v;
        }
        // Furthest pair
        Vect s0 = extremes[0], s1 = extremes[1];
        for (int i = 0; i < 6; i++) {
            for (int j = i + 1; j < 6; j++) {
                double d = distPointPoint(extremes[i], extremes[j]);
                if (gtr(d, distPointPoint(s0, s1))) {
                    s0 = extremes[i];
                    s1 = extremes[j];
                }
            }
        }
        // Furthest from line
        Line line = new Line(s0, s1);
        Vect s2 = extremes[0];
        for (int i = 0; i < 6; i++) {
            if (gtr(distPointLine(extremes[i], line),
                    distPointLine(s2, line)))
                s2 = extremes[i];
        }
        // Furthest from plane
        Vect s3 = point[1];
        Plane basePlane = new Plane(s0, s1, s2);
        for (int i = 1; i <= totp; i++) {
            double d1 = abs(distPointPlane(point[i], basePlane));
            double d2 = abs(distPointPlane(s3, basePlane));
            if (gtr(d1, d2)) s3 = point[i];
        }
        if (gtr(0, distPointPlane(s3, basePlane))) {
            Vect tmp = s1; s1 = s2; s2 = tmp;
        }
        // Create 4 initial facets
        int[] f = new int[4];
        for (int i = 0; i < 4; i++) {
            Facet F = new Facet();
            F.Id = FAC.size();
            FAC.add(F);
            f[i] = FAC.size() - 1;
        }
        FAC.get(f[0]).P = new Plane(s0, s2, s1);
        FAC.get(f[1]).P = new Plane(s0, s1, s3);
        FAC.get(f[2]).P = new Plane(s1, s2, s3);
        FAC.get(f[3]).P = new Plane(s2, s0, s3);

        FAC.get(f[0]).N = new int[]{f[3], f[2], f[1]};
        FAC.get(f[1]).N = new int[]{f[0], f[2], f[3]};
        FAC.get(f[2]).N = new int[]{f[0], f[3], f[1]};
        FAC.get(f[3]).N = new int[]{f[0], f[1], f[2]};

        // Prepare pts lists for the 4 facets
        for (int i = 0; i < 4; i++) {
            pts.add(new ArrayList<>());
        }
        // Assign points to facets
        for (int i = 1; i <= totp; i++) {
            Vect v = point[i];
            if (v.eq(s0) || v.eq(s1) || v.eq(s2) || v.eq(s3)) continue;
            for (int j = 0; j < 4; j++) {
                if (isAbove(v, FAC.get(f[j]).P)) {
                    pts.get(f[j]).add(v);
                    break;
                }
            }
        }
        return new ConvexHulls3d(f[0]);
    }

    static ConvexHulls3d quickHull3D(Vect[] point, int totp) {
        ConvexHulls3d hull = getStart(point, totp);
        queue.clear();
        queue.add(hull.Index);
        for (int i = 0; i < 3; i++) {
            queue.add(FAC.get(hull.Index).N[i]);
        }
        int snew = 0;
        while (!queue.isEmpty()) {
            int nf = queue.remove(0);
            Facet Fnf = FAC.get(nf);
            if (Fnf.isDeleted || pts.get(nf).isEmpty()) {
                if (!Fnf.isDeleted) snew = nf;
                continue;
            }
            // Farthest point from facet plane
            Vect p = pts.get(nf).get(0);
            for (Vect v : pts.get(nf)) {
                if (gtr(distPointPlane(v, Fnf.P), distPointPlane(p, Fnf.P))) {
                    p = v;
                }
            }
            // Find horizon
            TIME++;
            resfdel.clear();
            int s = hull.getHorizon(nf, p, resfdel);

            // Build new faces
            resfnew.clear();
            TIME++;
            int from = -1, lastf = -1, fstf = -1;
            while (vistime[s] != TIME) {
                vistime[s] = TIME;
                int net, fidx;
                if (e[0][s].netId == from) {
                    net = e[1][s].netId;
                    fidx = e[1][s].facetId;
                } else {
                    net = e[0][s].netId;
                    fidx = e[0][s].facetId;
                }
                // Find indices on facet fidx
                Facet Ff = FAC.get(fidx);
                int pt1 = 0, pt2 = 0;
                for (int i = 0; i < 3; i++) {
                    if (point[s].eq(Ff.P.vecAt(i))) pt1 = i;
                    if (point[net].eq(Ff.P.vecAt(i))) pt2 = i;
                }
                if ((pt1 + 1) % 3 != pt2) {
                    int tmp = pt1; pt1 = pt2; pt2 = tmp;
                }
                // Create new facet
                Facet newF = new Facet();
                newF.Id = FAC.size();
                newF.P = new Plane(
                    Ff.P.vecAt(pt2),
                    Ff.P.vecAt(pt1),
                    p
                );
                FAC.add(newF);
                pts.add(new ArrayList<>());
                int fnew = FAC.size() - 1;
                resfnew.add(fnew);

                // Link neighborhoods
                newF.N[0] = fidx;
                Ff.N[pt1] = fnew;

                if (lastf >= 0) {
                    Plane Pf1 = newF.P, Plast = FAC.get(lastf).P;
                    if (Pf1.vecAt(1).eq(Plast.U)) {
                        newF.N[1] = lastf;
                        FAC.get(lastf).N[2] = fnew;
                    } else {
                        newF.N[2] = lastf;
                        FAC.get(lastf).N[1] = fnew;
                    }
                } else {
                    fstf = fnew;
                }

                lastf = fnew;
                from = s;
                s = net;
            }
            // Close the loop
            Facet Ffst = FAC.get(fstf), Flast = FAC.get(lastf);
            if (Ffst.P.vecAt(1).eq(Flast.P.U)) {
                Ffst.N[1] = lastf;
                Flast.N[2] = fstf;
            } else {
                Ffst.N[2] = lastf;
                Flast.N[1] = fstf;
            }

            // Collect deleted points
            respt.clear();
            for (int fid : resfdel) {
                respt.addAll(pts.get(fid));
                pts.get(fid).clear();
            }
            // Reassign points
            for (Vect v : respt) {
                if (v == p) continue;
                for (int fid : resfnew) {
                    if (isAbove(v, FAC.get(fid).P)) {
                        pts.get(fid).add(v);
                        break;
                    }
                }
            }
            // Enqueue new faces
            for (int fid : resfnew) {
                queue.add(fid);
            }
        }
        hull.Index = snew;
        return hull;
    }
}
Output:
2.366


Translation of: Python
// Constants
const MAXN = 2500;
const EPS = 1e-8;

function gtr(a, b) {
  return a - b > EPS;
}

function eq(a, b) {
  return Math.abs(a - b) < EPS;
}

function Abs(x) {
  return x < 0 ? -x : x;
}

// 3D Vector
class Vect {
  constructor(x = 0.0, y = 0.0, z = 0.0, id = 0) {
    this.x = x;
    this.y = y;
    this.z = z;
    this.id = id;
  }

  subtract(o) {
    return new Vect(this.x - o.x, this.y - o.y, this.z - o.z);
  }

  // cross product
  cross(o) {
    return new Vect(
      this.y * o.z - this.z * o.y,
      this.z * o.x - this.x * o.z,
      this.x * o.y - this.y * o.x
    );
  }

  // dot product
  dot(o) {
    return this.x * o.x + this.y * o.y + this.z * o.z;
  }

  magnitude() {
    return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
  }

  equals(o) {
    return eq(this.x, o.x) && eq(this.y, o.y) && eq(this.z, o.z);
  }

  toString() {
    return `Vect(${this.x}, ${this.y}, ${this.z}, ${this.id})`;
  }
}

// Line from u to v
class Line {
  constructor(u = null, v = null) {
    this.u = u;
    this.v = v;
  }
}

// Plane through three points u,v,w
class Plane {
  constructor(u = null, v = null, w = null) {
    this.vec = (u && v && w) ? [u, v, w] : [null, null, null];
  }

  // normal vector = (v - u) × (w - u)
  normal() {
    const [u, v, w] = this.vec;
    return v.subtract(u).cross(w.subtract(u));
  }

  // one point on plane
  u() {
    return this.vec[0];
  }
}

// Signed distance point-plane
function distPointPlane(pt, pl) {
  const n = pl.normal();
  return pt.subtract(pl.u()).dot(n) / n.magnitude();
}

// Unsigned distance point-line
function distPointLine(pt, ln) {
  const u_to_pt = pt.subtract(ln.u);
  const dir = ln.v.subtract(ln.u);
  if (u_to_pt.magnitude() === 0) return 0;
  return u_to_pt.cross(dir).magnitude() / dir.magnitude();
}

// Distance point-point
function distPointPoint(a, b) {
  return a.subtract(b).magnitude();
}

// is pt strictly above plane?
function isAbove(pt, pl) {
  const n = pl.normal();
  return gtr(pt.subtract(pl.u()).dot(n), 0);
}

// Facet (triangle face of hull)
class Facet {
  constructor(id = 0, p = null) {
    this.n = [0, 0, 0];    // neighbors
    this.id = id;
    this.vistime = 0;
    this.isdel = false;
    this.p = p || new Plane();
  }
  setNeighbors(n1, n2, n3) {
    this.n = [n1, n2, n3];
  }
  toString() {
    return `Facet(id=${this.id}, isdel=${this.isdel}, vistime=${this.vistime})`;
  }
}

// Edge info for horizon detection
class Edge {
  constructor() {
    this.netid = 0;
    this.facetid = 0;
  }
}

// Global variables
let FAC = [];
let pts = [];     // points assigned to each face
let TIME = 0;

// Convex hull wrapper
class ConvexHulls3d {
  constructor(index) {
    this.index = index;
    this.surfaceArea = 0.0;
  }

  dfsArea(fidx) {
    if (FAC[fidx].vistime === TIME) return;
    FAC[fidx].vistime = TIME;
    const n = FAC[fidx].p.normal();
    this.surfaceArea += n.magnitude() / 2;
    for (let i = 0; i < 3; i++) {
      this.dfsArea(FAC[fidx].n[i]);
    }
  }

  getSurfaceArea() {
    if (gtr(this.surfaceArea, 0)) {
      return this.surfaceArea;
    }
    TIME++;
    this.dfsArea(this.index);
    return this.surfaceArea;
  }

  getHorizon(f, p, vistime, e1, e2, resfdel) {
    if (!isAbove(p, FAC[f].p)) return 0;
    if (FAC[f].vistime === TIME) return -1;
    FAC[f].vistime = TIME;
    FAC[f].isdel = true;
    resfdel.push(FAC[f].id);
    let ret = -2;
    for (let i = 0; i < 3; i++) {
      const res = this.getHorizon(FAC[f].n[i], p, vistime, e1, e2, resfdel);
      if (res === 0) {
        const ptIds = [
          FAC[f].p.vec[i].id,
          FAC[f].p.vec[(i + 1) % 3].id
        ];
        for (let j = 0; j < 2; j++) {
          const pid = ptIds[j];
          if (vistime[pid] !== TIME) {
            vistime[pid] = TIME;
            e1[pid].netid = ptIds[(j + 1) % 2];
            e1[pid].facetid = FAC[f].n[i];
          } else {
            e2[pid].netid = ptIds[(j + 1) % 2];
            e2[pid].facetid = FAC[f].n[i];
          }
        }
        ret = ptIds[0];
      } else if (res !== -1 && res !== -2) {
        ret = res;
      }
    }
    return ret;
  }
}

// Initialize convex hull system
function preConvexHulls() {
  pts = [[]];
  FAC = [ new Facet() ];
}

// Build initial tetrahedron (simplex)
function getStart(point, totp) {
  // pick extreme points along axes
  let pt = Array(6).fill(point[1]);
  let s = Array(4).fill(point[1]);

  for (let i = 2; i <= totp; i++) {
    if (gtr(point[i].x, pt[0].x)) pt[0] = point[i];
    if (gtr(pt[1].x, point[i].x)) pt[1] = point[i];
    if (gtr(point[i].y, pt[2].y)) pt[2] = point[i];
    if (gtr(pt[3].y, point[i].y)) pt[3] = point[i];
    if (gtr(point[i].z, pt[4].z)) pt[4] = point[i];
    if (gtr(pt[5].z, point[i].z)) pt[5] = point[i];
  }

  // farthest pair among these 6
  for (let i = 0; i < 6; i++) {
    for (let j = i + 1; j < 6; j++) {
      if (gtr(distPointPoint(pt[i], pt[j]), distPointPoint(s[0], s[1]))) {
        s[0] = pt[i];
        s[1] = pt[j];
      }
    }
  }

  // farthest point from line s[0]-s[1]
  for (let i = 0; i < 6; i++) {
    if (gtr(
      distPointLine(pt[i], new Line(s[0], s[1])),
      distPointLine(s[2], new Line(s[0], s[1]))
    )) {
      s[2] = pt[i];
    }
  }

  // farthest point from plane through s[0],s[1],s[2]
  for (let i = 1; i <= totp; i++) {
    if (gtr(
      Abs(distPointPlane(point[i], new Plane(s[0], s[1], s[2]))),
      Abs(distPointPlane(s[3], new Plane(s[0], s[1], s[2])))
    )) {
      s[3] = point[i];
    }
  }

  // ensure correct orientation
  if (gtr(0, distPointPlane(s[3], new Plane(s[0], s[1], s[2])))) {
    [s[1], s[2]] = [s[2], s[1]];
  }

  // create 4 faces
  let f = new Array(4);
  for (let i = 0; i < 4; i++) {
    FAC.push(new Facet(FAC.length));
    f[i] = FAC.length - 1;
  }

  FAC[f[0]].p = new Plane(s[0], s[2], s[1]);
  FAC[f[1]].p = new Plane(s[0], s[1], s[3]);
  FAC[f[2]].p = new Plane(s[1], s[2], s[3]);
  FAC[f[3]].p = new Plane(s[2], s[0], s[3]);

  FAC[f[0]].setNeighbors(f[3], f[2], f[1]);
  FAC[f[1]].setNeighbors(f[0], f[2], f[3]);
  FAC[f[2]].setNeighbors(f[0], f[3], f[1]);
  FAC[f[3]].setNeighbors(f[0], f[1], f[2]);

  // allocate point lists
  for (let i = 0; i < 4; i++) pts.push([]);

  // assign remaining points to faces
  for (let i = 1; i <= totp; i++) {
    const pi = point[i];
    if (pi.equals(s[0]) || pi.equals(s[1]) || pi.equals(s[2]) || pi.equals(s[3])) continue;
    for (let j = 0; j < 4; j++) {
      if (isAbove(pi, FAC[f[j]].p)) {
        pts[f[j]].push(pi);
        break;
      }
    }
  }

  return new ConvexHulls3d(f[0]);
}

// QuickHull main routine
function quickHull3d(point, totp) {
  let hull = getStart(point, totp);
  let queue = [hull.index, 
               ...FAC[hull.index].n];
  let snew = 0;

  // horizon data
  const e = [ Array(MAXN).fill().map(() => new Edge()),
              Array(MAXN).fill().map(() => new Edge()) ];
  const vistime = Array(MAXN).fill(0);

  while (queue.length > 0) {
    const nf = queue.shift();
    if (FAC[nf].isdel) continue;
    if (pts[nf].length === 0) {
      snew = nf;
      continue;
    }

    // farthest point from face
    let p = pts[nf][0];
    for (let pt of pts[nf]) {
      if (gtr(distPointPlane(pt, FAC[nf].p), distPointPlane(p, FAC[nf].p))) {
        p = pt;
      }
    }

    // find horizon
    TIME++;
    let resfdel = [];
    const startEdge = hull.getHorizon(nf, p, vistime, e[0], e[1], resfdel);

    // build new faces around horizon
    let resfnew = [];
    TIME++;
    let from = 0, lastf = 0, fstf = 0, s = startEdge;

    while (vistime[s] !== TIME) {
      vistime[s] = TIME;
      let net, adjF;
      if (e[0][s].netid === from) {
        net = e[1][s].netid; adjF = e[1][s].facetid;
      } else {
        net = e[0][s].netid; adjF = e[0][s].facetid;
      }

      // find indices of s and net in adj face
      let pt1 = -1, pt2 = -1;
      for (let i = 0; i < 3; i++) {
        if (point[s] === FAC[adjF].p.vec[i]) pt1 = i;
        if (point[net] === FAC[adjF].p.vec[i]) pt2 = i;
      }
      if ((pt1 + 1) % 3 !== pt2) [pt1, pt2] = [pt2, pt1];

      // new face [pt2, pt1, p]
      FAC.push(new Facet(FAC.length, new Plane(
        FAC[adjF].p.vec[pt2],
        FAC[adjF].p.vec[pt1],
        p
      )));
      const fnew = FAC.length - 1;
      pts.push([]);
      resfnew.push(fnew);

      // link adjacency
      FAC[fnew].n[0] = adjF;
      FAC[adjF].n[pt1] = fnew;
      if (lastf) {
        if (FAC[fnew].p.vec[1] === FAC[lastf].p.vec[0]) {
          FAC[fnew].n[1] = lastf;
          FAC[lastf].n[2] = fnew;
        } else {
          FAC[fnew].n[2] = lastf;
          FAC[lastf].n[1] = fnew;
        }
      } else {
        fstf = fnew;
      }

      lastf = fnew;
      from = s;
      s = net;
    }

    // close the loop
    if (FAC[fstf].p.vec[1] === FAC[lastf].p.vec[0]) {
      FAC[fstf].n[1] = lastf;
      FAC[lastf].n[2] = fstf;
    } else {
      FAC[fstf].n[2] = lastf;
      FAC[lastf].n[1] = fstf;
    }

    // collect and reassign points
    let respt = [];
    for (let fid of resfdel) {
      respt.push(...pts[fid]);
      pts[fid] = [];
    }
    for (let qpt of respt) {
      if (qpt === p) continue;
      for (let nfnew of resfnew) {
        if (isAbove(qpt, FAC[nfnew].p)) {
          pts[nfnew].push(qpt);
          break;
        }
      }
    }

    // enqueue new faces
    queue.push(...resfnew);
  }

  hull.index = snew;
  return hull;
}

// Example usage
(function main() {
  preConvexHulls();
  const n = 4;
  const input = [
    [0.0, 0.0, 0.0],
    [1.0, 0.0, 0.0],
    [0.0, 1.0, 0.0],
    [0.0, 0.0, 1.0]
  ];
  const point = Array(n + 1);
  for (let i = 1; i <= n; i++) {
    const [x, y, z] = input[i - 1];
    point[i] = new Vect(x, y, z, i);
  }
  const hull = quickHull3d(point, n);
  console.log(hull.getSurfaceArea().toFixed(3));
})();
Output:
2.366


Translation of: C++
# QuickHull3D.jl

using Printf

const MAXN = 2500
const EPS  = 1e-8

# Tell Julia we intend to extend these Base methods
import Base: -, ==

# 3D vector with an ID
mutable struct Vect
    x::Float64; y::Float64; z::Float64; id::Int
end

# Subtract two Vect’s
function -(a::Vect, b::Vect)
    Vect(a.x - b.x, a.y - b.y, a.z - b.z, 0)
end

# Equality of two Vect’s (approximate)
function ==(a::Vect, b::Vect)
    abs(a.x-b.x)<EPS && abs(a.y-b.y)<EPS && abs(a.z-b.z)<EPS
end

# Cross, dot, magnitude
function cross(a::Vect, b::Vect)
    Vect(
        a.y*b.z - a.z*b.y,
        a.z*b.x - a.x*b.z,
        a.x*b.y - a.y*b.x,
        0
    )
end

dot(a::Vect, b::Vect) = a.x*b.x + a.y*b.y + a.z*b.z
mag(a::Vect) = sqrt(a.x^2 + a.y^2 + a.z^2)

# Line and Plane types
struct Line
    u::Vect; v::Vect
end

struct Plane
    u::Vect; v::Vect; w::Vect
end

normal(p::Plane) = cross(p.v - p.u, p.w - p.u)
vecAt(p::Plane, i::Int) = (i==1 ? p.u : i==2 ? p.v : p.w)
vecId(p::Plane, i::Int) = vecAt(p, i).id

# Floating‐point comparison
gtr(a,b) = a - b > EPS

# Distances
dist_point_plane(v::Vect, p::Plane) = dot(v - p.u, normal(p)) / mag(normal(p))
dist_point_line(v::Vect, l::Line) = begin
    d = mag(v - l.u)
    d>0 ? mag(cross(l.v - l.u, v - l.u)) / mag(l.v - l.u) : 0.0
end
dist_point_point(a::Vect, b::Vect) = mag(a - b)
isabove(v::Vect, p::Plane) = gtr(dot(v - p.u, normal(p)), 0)

# Facet and Edge
mutable struct Facet
    n::NTuple{3,Int}      # neighbor facet indices
    id::Int               # facet ID
    vistime::Int          # timestamp for DFS
    isdel::Bool           # deleted?
    p::Plane              # supporting plane
end
Facet() = Facet((0,0,0),0,0,false,Plane(Vect(0,0,0,0),Vect(0,0,0,0),Vect(0,0,0,0)))

mutable struct Edge
    netid::Int
    facetid::Int
end
Edge() = Edge(0,0)

mutable struct ConvexHulls3d
    index::Int
    surfacearea::Float64
end
ConvexHulls3d(idx::Int) = ConvexHulls3d(idx, 0.0)

# Globals
FAC      = Facet[]
pts      = Vector{Vect}[]
TIME     = 0
e        = [ Edge() for i in 1:2, j in 1:MAXN ]
vistime  = zeros(Int, MAXN)
queue    = Int[]
resfnew  = Int[]
resfdel  = Int[]
respt    = Vect[]

# Initialize
function preConvexHulls()
    push!(pts, Vect[])    # reserve index 1
    push!(FAC, Facet())   # dummy facet[1]
end

# DFS for surface area
function dfsArea(h::ConvexHulls3d, fidx::Int)
    f = FAC[fidx]
    if f.vistime == TIME return end
    f.vistime = TIME
    nrm = normal(f.p)
    h.surfacearea += mag(nrm)/2
    for i in 1:3
        dfsArea(h, f.n[i])
    end
end

function getSurfaceArea(h::ConvexHulls3d)
    if h.surfacearea > 0
        return h.surfacearea
    end
    global TIME
    TIME += 1
    dfsArea(h, h.index)
    return h.surfacearea
end

# Horizon search
function getHorizon(h::ConvexHulls3d, fidx::Int, p::Vect, resdel::Vector{Int})
    f = FAC[fidx]
    if !isabove(p, f.p) return 0 end
    if f.vistime == TIME return -1 end
    f.vistime = TIME
    f.isdel   = true
    push!(resdel, fidx)
    ret = -2
    for i in 1:3
        r = getHorizon(h, f.n[i], p, resdel)
        if r == 0
            a = vecId(f.p, i)
            b = vecId(f.p, (i % 3) + 1)
            for (j, pt) in enumerate((a,b))
                slot = vistime[pt] != TIME ? 1 : 2
                vistime[pt] = TIME
                e[slot, pt] = Edge(j==1 ? b : a, f.n[i])
            end
            ret = a
        elseif r != -1 && r != -2
            ret = r
        end
    end
    return ret
end

# Build initial tetrahedron
function getStart(point::Vector{Vect}, totp::Int)
    # pick extremes
    pt = [ point[1] for _ in 1:6 ]
    for i in 1:totp
        v = point[i]
        if gtr(v.x, pt[1].x) pt[1] = v end
        if gtr(pt[2].x, v.x) pt[2] = v end
        if gtr(v.y, pt[3].y) pt[3] = v end
        if gtr(pt[4].y, v.y) pt[4] = v end
        if gtr(v.z, pt[5].z) pt[5] = v end
        if gtr(pt[6].z, v.z) pt[6] = v end
    end
    # furthest pair
    s = [pt[1], pt[2], point[1], point[1]]
    for i in 1:6, j in i+1:6
        d = dist_point_point(pt[i], pt[j])
        if gtr(d, dist_point_point(s[1], s[2]))
            s[1], s[2] = pt[i], pt[j]
        end
    end
    # furthest from line
    L = Line(s[1], s[2])
    s[3] = pt[1]
    for i in 1:6
        if gtr(dist_point_line(pt[i], L), dist_point_line(s[3], L))
            s[3] = pt[i]
        end
    end
    # furthest from plane
    s[4] = point[1]
    base = Plane(s[1], s[2], s[3])
    for i in 1:totp
        if gtr(abs(dist_point_plane(point[i], base)),
               abs(dist_point_plane(s[4],     base)))
            s[4] = point[i]
        end
    end
    if gtr(0, dist_point_plane(s[4], base))
        s[2], s[3] = s[3], s[2]
    end

    # create 4 facets
    fidx = Int[]
    for i in 1:4
        push!(FAC, Facet())
        FAC[end].id = length(FAC)
        push!(fidx, length(FAC))
    end
    FAC[fidx[1]].p = Plane(s[1], s[3], s[2])
    FAC[fidx[2]].p = Plane(s[1], s[2], s[4])
    FAC[fidx[3]].p = Plane(s[2], s[3], s[4])
    FAC[fidx[4]].p = Plane(s[3], s[1], s[4])

    FAC[fidx[1]].n = (fidx[4], fidx[3], fidx[2])
    FAC[fidx[2]].n = (fidx[1], fidx[3], fidx[4])
    FAC[fidx[3]].n = (fidx[1], fidx[4], fidx[2])
    FAC[fidx[4]].n = (fidx[1], fidx[2], fidx[3])

    # prepare pts lists
    for _ in 1:4
        push!(pts, Vect[])
    end

    # assign points
    for i in 1:totp
        v = point[i]
        if v == s[1] || v == s[2] || v == s[3] || v == s[4]
            continue
        end
        for j in 1:4
            if isabove(v, FAC[fidx[j]].p)
                push!(pts[fidx[j]], v)
                break
            end
        end
    end

    return ConvexHulls3d(fidx[1])
end

# Main QuickHull3D
function quickHull3d(point::Vector{Vect}, totp::Int)
    hull = getStart(point, totp)

    empty!(queue)
    push!(queue, hull.index)
    for i in 1:3
        push!(queue, FAC[hull.index].n[i])
    end
    snew = hull.index

    while !isempty(queue)
        nf = popfirst!(queue)
        if FAC[nf].isdel || isempty(pts[nf])
            if !FAC[nf].isdel
                snew = nf
            end
            continue
        end

        # farthest point
        p = pts[nf][1]
        for v in pts[nf]
            if gtr(dist_point_plane(v, FAC[nf].p),
                   dist_point_plane(p, FAC[nf].p))
                p = v
            end
        end

        # find horizon
        TIME += 1
        empty!(resfdel)
        s = getHorizon(hull, nf, p, resfdel)

        # build around horizon
        empty!(resfnew)
        TIME += 1
        from = -1; lastf = -1; fstf = -1
        while vistime[s] != TIME
            vistime[s] = TIME
            e1, e2 = e[1,s], e[2,s]
            net, adj = (e1.netid==from ? (e2.netid, e2.facetid)
                                       : (e1.netid, e1.facetid))
            # find edge orientation
            pt1 = findfirst(i->vecAt(FAC[adj].p,i)==point[s], 1:3)
            pt2 = findfirst(i->vecAt(FAC[adj].p,i)==point[net], 1:3)
            if (pt1 % 3) + 1 != pt2
                pt1, pt2 = pt2, pt1
            end

            newp = Plane(vecAt(FAC[adj].p,pt2),
                         vecAt(FAC[adj].p,pt1),
                         p)
            push!(FAC, Facet(length(FAC)+1, newp))
            fnew = length(FAC)
            push!(pts, Vect[])
            push!(resfnew, fnew)

            FAC[fnew].n = (adj,0,0)
            FAC[adj].n = setindex(FAC[adj].n, fnew, pt1)

            if lastf != -1
                if vecAt(FAC[fnew].p,2) == vecAt(FAC[lastf].p,1)
                    FAC[fnew].n = (FAC[fnew].n[1], lastf, FAC[fnew].n[3])
                    FAC[lastf].n = (FAC[lastf].n[1], FAC[lastf].n[2], fnew)
                else
                    FAC[fnew].n = (FAC[fnew].n[1], FAC[fnew].n[2], lastf)
                    FAC[lastf].n = (FAC[lastf].n[1], fnew, FAC[lastf].n[3])
                end
            else
                fstf = fnew
            end

            lastf, from, s = fnew, s, net
        end

        # close loop
        if vecAt(FAC[fstf].p,2) == vecAt(FAC[lastf].p,1)
            FAC[fstf].n = (FAC[fstf].n[1], lastf, FAC[fstf].n[3])
            FAC[lastf].n = (FAC[lastf].n[1], FAC[lastf].n[2], fstf)
        else
            FAC[fstf].n = (FAC[fstf].n[1], FAC[fstf].n[2], lastf)
            FAC[lastf].n = (FAC[lastf].n[1], fstf, FAC[lastf].n[3])
        end

        # collect and reassign points
        empty!(respt)
        for fid in resfdel
            append!(respt, pts[fid])
            empty!(pts[fid])
        end
        for v in respt
            if v != p
                for fid in resfnew
                    if isabove(v, FAC[fid].p)
                        push!(pts[fid], v)
                        break
                    end
                end
            end
        end

        for fid in resfnew
            push!(queue, fid)
        end
    end

    hull.index = snew
    return hull
end

# Example: unit tetrahedron
preConvexHulls()
points = [
    Vect(0.0,0.0,0.0,1),
    Vect(1.0,0.0,0.0,2),
    Vect(0.0,1.0,0.0,3),
    Vect(0.0,0.0,1.0,4),
]
hull = quickHull3d(points, length(points))
@printf("%.3f\n", getSurfaceArea(hull))
Output:
2.366


Works with: Kotlin version 1.3.31
Translation of: Java
/*  QuickHull3D – Kotlin version (fixed + wrapper)
    -------------------------------------------------
    No algorithmic changes – only the two fixes explained above.
*/

import kotlin.math.abs
import kotlin.math.sqrt

private const val MAXN = 2500
private const val EPS = 1e-8

object QuickHull3D {

    // -----------------------------------------------------------------
    // Global structures (static fields in Java)
    // -----------------------------------------------------------------
    val FAC = mutableListOf<Facet>()                     // facets (index 0 is dummy)
    val pts = mutableListOf<MutableList<Vect>>()         // points belonging to each facet
    var TIME = 0                                         // global timestamp
    val e = Array(2) { Array(MAXN) { Edge() } }          // adjacency edges (two per vertex)
    val vistime = IntArray(MAXN)                         // used while walking the horizon
    val queue = mutableListOf<Int>()                     // processing queue
    val resfnew = mutableListOf<Int>()                   // new facets (temp)
    val resfdel = mutableListOf<Int>()                   // deleted facets (temp)
    val respt = mutableListOf<Vect>()                    // points to be reassigned (temp)

    // -----------------------------------------------------------------
    // Entry point – same test as the Java version
    // -----------------------------------------------------------------
    @JvmStatic
    fun main(args: Array<String>) {
        preConvexHulls()

        // Example: unit tetrahedron (1‑based indexing, point[0] is a dummy)
        val n = 4
        val point = arrayOfNulls<Vect>(n + 1)
        point[0] = Vect(0.0, 0.0, 0.0, 0)        // dummy, never used by the algorithm
        point[1] = Vect(0.0, 0.0, 0.0, 1)
        point[2] = Vect(1.0, 0.0, 0.0, 2)
        point[3] = Vect(0.0, 1.0, 0.0, 3)
        point[4] = Vect(0.0, 0.0, 1.0, 4)

        // “requireNoNulls” is now safe because point[0] is filled
        val hull = quickHull3D(point.requireNoNulls(), n)
        System.out.printf("%.3f%n", hull.surfaceArea())
    }

    // -----------------------------------------------------------------
    private fun preConvexHulls() {
        pts.add(mutableListOf())    // pts[0] – dummy list
        FAC.add(Facet())            // FAC[0] – dummy facet
        for (i in 0..1) {
            for (j in 0 until MAXN) {
                e[i][j] = Edge()
            }
        }
    }

    // -----------------------------------------------------------------
    // Geometry primitives
    // -----------------------------------------------------------------
    data class Vect(
        var X: Double,
        var Y: Double,
        var Z: Double,
        var Id: Int
    ) {
        fun sub(b: Vect) = Vect(X - b.X, Y - b.Y, Z - b.Z, 0)
        fun cross(b: Vect) = Vect(
            Y * b.Z - Z * b.Y,
            Z * b.X - X * b.Z,
            X * b.Y - Y * b.X,
            0
        )
        fun dot(b: Vect) = X * b.X + Y * b.Y + Z * b.Z
        fun mag() = sqrt(X * X + Y * Y + Z * Z)
        fun eq(b: Vect) = eq(X, b.X) && eq(Y, b.Y) && eq(Z, b.Z)
    }

    data class Line(val U: Vect, val V: Vect)

    class Plane() {
        lateinit var U: Vect
        lateinit var V: Vect
        lateinit var W: Vect

        constructor(u: Vect, v: Vect, w: Vect) : this() {
            U = u; V = v; W = w
        }

        fun normal(): Vect = V.sub(U).cross(W.sub(U))
        fun vecAt(i: Int): Vect = when (i) {
            0 -> U
            1 -> V
            else -> W
        }

        fun vecId(i: Int) = vecAt(i).Id
    }

    class Facet {
        var N = IntArray(3)                 // neighbour facet indices
        var Id = 0
        var visitTime = 0
        var isDeleted = false
        var P = Plane()
    }

    class Edge {
        var netId = 0
        var facetId = 0
    }

    // -----------------------------------------------------------------
    // Convex hull container (same as Java inner class)
    // -----------------------------------------------------------------
    class ConvexHulls3d(var index: Int) {

        var surfaceArea = 0.0

        private fun dfsArea(f: Int) {
            val F = FAC[f]
            if (F.visitTime == TIME) return
            F.visitTime = TIME
            val nrm = F.P.normal()
            surfaceArea += nrm.mag() / 2.0
            for (i in 0..2) dfsArea(F.N[i])
        }

        fun surfaceArea(): Double {
            if (gtr(surfaceArea, 0.0)) return surfaceArea
            TIME++
            dfsArea(index)
            return surfaceArea
        }

        /** Horizon detection – returns one vertex of the horizon (or sentinel) */
        fun getHorizon(f: Int, p: Vect, resDel: MutableList<Int>): Int {
            val Ff = FAC[f]
            if (!isAbove(p, Ff.P)) return 0
            if (Ff.visitTime == TIME) return -1

            Ff.visitTime = TIME
            Ff.isDeleted = true
            resDel.add(Ff.Id)

            var ret = -2
            for (i in 0..2) {
                val ni = Ff.N[i]
                val r = getHorizon(ni, p, resDel)
                if (r == 0) {
                    val a = Ff.P.vecId(i)
                    val b = Ff.P.vecId((i + 1) % 3)
                    for (idx in 0..1) {
                        val pt = if (idx == 0) a else b
                        val facet = ni
                        if (vistime[pt] != TIME) {
                            vistime[pt] = TIME
                            e[0][pt].netId = if (idx == 0) b else a
                            e[0][pt].facetId = facet
                        } else {
                            e[1][pt].netId = if (idx == 0) b else a
                            e[1][pt].facetId = facet
                        }
                    }
                    ret = a
                } else if (r != -1 && r != -2) {
                    ret = r
                }
            }
            return ret
        }
    }

    // -----------------------------------------------------------------
    // Utility functions (same as Java static helpers)
    // -----------------------------------------------------------------
    private fun eq(a: Double, b: Double) = kotlin.math.abs(a - b) < EPS
    private fun gtr(a: Double, b: Double) = a - b > EPS
    private fun abs(x: Double) = kotlin.math.abs(x)

    private fun distPointPlane(v: Vect, p: Plane): Double {
        val num = v.sub(p.U).dot(p.normal())
        val den = p.normal().mag()
        return num / den
    }

    private fun distPointLine(v: Vect, l: Line): Double {
        val d = v.sub(l.U).mag()
        if (d == 0.0) return 0.0
        return l.V.sub(l.U).cross(v.sub(l.U)).mag() / l.V.sub(l.U).mag()
    }

    private fun distPointPoint(a: Vect, b: Vect) = a.sub(b).mag()
    private fun isAbove(v: Vect, p: Plane) = gtr(v.sub(p.U).dot(p.normal()), 0.0)

    // -----------------------------------------------------------------
    // Core algorithm (unchanged apart from the two fixes)
    // -----------------------------------------------------------------
    private fun getStart(point: Array<Vect>, totp: Int): ConvexHulls3d {
        // ---- extremes in each coordinate direction ----
        val extremes = Array(6) { point[0] }
        for (i in 1..totp) {
            val v = point[i]
            if (gtr(v.X, extremes[0].X)) extremes[0] = v
            if (gtr(extremes[1].X, v.X)) extremes[1] = v
            if (gtr(v.Y, extremes[2].Y)) extremes[2] = v
            if (gtr(extremes[3].Y, v.Y)) extremes[3] = v
            if (gtr(v.Z, extremes[4].Z)) extremes[4] = v
            if (gtr(extremes[5].Z, v.Z)) extremes[5] = v
        }

        // ---- furthest pair among extremes ------------
        var s0 = extremes[0]
        var s1 = extremes[1]
        for (i in 0 until 6) {
            for (j in i + 1 until 6) {
                val d = distPointPoint(extremes[i], extremes[j])
                if (gtr(d, distPointPoint(s0, s1))) {
                    s0 = extremes[i]; s1 = extremes[j]
                }
            }
        }

        // ---- furthest point from that line ------------
        val line = Line(s0, s1)
        var s2 = extremes[0]
        for (i in 0 until 6) {
            if (gtr(distPointLine(extremes[i], line), distPointLine(s2, line))) {
                s2 = extremes[i]
            }
        }

        // ---- furthest point from the plane s0,s1,s2 ---
        var s3 = point[1]
        val basePlane = Plane(s0, s1, s2)
        for (i in 1..totp) {
            val d1 = abs(distPointPlane(point[i], basePlane))
            val d2 = abs(distPointPlane(s3, basePlane))
            if (gtr(d1, d2)) s3 = point[i]
        }

        // ---- fix orientation if needed ---------------
        if (gtr(0.0, distPointPlane(s3, basePlane))) {
            val tmp = s1; s1 = s2; s2 = tmp
        }

        // ---- create the 4 initial facets ---------------
        val f = IntArray(4)
        repeat(4) {
            val F = Facet()
            F.Id = FAC.size
            FAC.add(F)
            f[it] = FAC.size - 1
        }

        FAC[f[0]].P = Plane(s0, s2, s1)
        FAC[f[1]].P = Plane(s0, s1, s3)
        FAC[f[2]].P = Plane(s1, s2, s3)
        FAC[f[3]].P = Plane(s2, s0, s3)

        FAC[f[0]].N = intArrayOf(f[3], f[2], f[1])
        FAC[f[1]].N = intArrayOf(f[0], f[2], f[3])
        FAC[f[2]].N = intArrayOf(f[0], f[3], f[1])
        FAC[f[3]].N = intArrayOf(f[0], f[1], f[2])

        // ---- allocate point buckets for these facets ---
        repeat(4) { pts.add(mutableListOf()) }

        // ---- assign each non‑extreme point to a visible facet --
        for (i in 1..totp) {
            val v = point[i]
            if (v.eq(s0) || v.eq(s1) || v.eq(s2) || v.eq(s3)) continue
            for (j in 0..3) {
                if (isAbove(v, FAC[f[j]].P)) {
                    pts[f[j]].add(v)
                    break
                }
            }
        }

        return ConvexHulls3d(f[0])
    }

    private fun quickHull3D(point: Array<Vect>, totp: Int): ConvexHulls3d {
        val hull = getStart(point, totp)

        // initialise queue with the starting facet and its three neighbours
        queue.clear()
        queue.add(hull.index)
        repeat(3) { queue.add(FAC[hull.index].N[it]) }

        var snew = 0

        while (queue.isNotEmpty()) {
            val nf = queue.removeAt(0)
            val Fnf = FAC[nf]

            // skip deleted facets or empty point sets
            if (Fnf.isDeleted || pts[nf].isEmpty()) {
                if (!Fnf.isDeleted) snew = nf
                continue
            }

            // ---- farthest point of the current bucket ----
            var p = pts[nf][0]
            for (v in pts[nf]) {
                if (gtr(distPointPlane(v, Fnf.P), distPointPlane(p, Fnf.P))) {
                    p = v
                }
            }

            // ---- horizon detection -----------------------
            TIME++
            resfdel.clear()
            val s = hull.getHorizon(nf, p, resfdel)

            // ---- build new faces attached to the horizon ----
            resfnew.clear()
            TIME++
            var from = -1
            var lastf = -1
            var fstf = -1
            var cur = s
            while (vistime[cur] != TIME) {
                vistime[cur] = TIME
                val (net, fIdx) = if (e[0][cur].netId == from) {
                    e[1][cur].netId to e[1][cur].facetId
                } else {
                    e[0][cur].netId to e[0][cur].facetId
                }

                // locate the two vertices of facet fIdx that correspond to cur / net
                val Ff = FAC[fIdx]
                var pt1 = -1
                var pt2 = -1
                for (i in 0..2) {
                    if (point[cur].eq(Ff.P.vecAt(i))) pt1 = i
                    if (point[net].eq(Ff.P.vecAt(i))) pt2 = i
                }
                if ((pt1 + 1) % 3 != pt2) {
                    val tmp = pt1; pt1 = pt2; pt2 = tmp
                }

                // ---- create the new facet --------------------
                val newF = Facet()
                newF.Id = FAC.size
                newF.P = Plane(Ff.P.vecAt(pt2), Ff.P.vecAt(pt1), p)
                FAC.add(newF)
                pts.add(mutableListOf())
                val fnew = FAC.size - 1
                resfnew.add(fnew)

                // ---- neighbour links -------------------------
                newF.N[0] = fIdx
                Ff.N[pt1] = fnew

                if (lastf >= 0) {
                    val Pf1 = newF.P
                    val Plast = FAC[lastf].P
                    if (Pf1.vecAt(1).eq(Plast.U)) {
                        newF.N[1] = lastf
                        FAC[lastf].N[2] = fnew
                    } else {
                        newF.N[2] = lastf
                        FAC[lastf].N[1] = fnew
                    }
                } else {
                    fstf = fnew
                }

                // advance on the horizon loop
                lastf = fnew
                from = cur
                cur = net
            }

            // ---- close the horizon loop (first ↔ last) ----
            val Ffst = FAC[fstf]
            val Flast = FAC[lastf]
            // *** FIXED LINE *** – correct access to the vertex of the plane
            if (Ffst.P.vecAt(1).eq(Flast.P.U)) {
                Ffst.N[1] = lastf
                Flast.N[2] = fstf
            } else {
                Ffst.N[2] = lastf
                Flast.N[1] = fstf
            }

            // ---- collect points that disappeared with deleted facets ----
            respt.clear()
            for (fid in resfdel) {
                respt.addAll(pts[fid])
                pts[fid].clear()
            }

            // ---- re‑assign those points to the newly created facets ----
            for (v in respt) {
                if (v === p) continue
                for (fid in resfnew) {
                    if (isAbove(v, FAC[fid].P)) {
                        pts[fid].add(v)
                        break
                    }
                }
            }

            // ---- enqueue the new facets for later processing ------------
            for (fid in resfnew) queue.add(fid)
        }

        hull.index = snew
        return hull
    }
}

/* -----------------------------------------------------------------
   Tiny top‑level wrapper so that the JVM can find “main” in MainKt.
   You can delete this function if you prefer to launch the program
   with “java QuickHull3D” instead of “java MainKt”.
----------------------------------------------------------------- */
fun main(args: Array<String>) = QuickHull3D.main(args)
Output:
2.366




Translation of: C++
-- QuickHull3D in Lua

local MAXN = 2500
local EPS  = 1e-8

-- Globals
local FAC = {}           -- list of facets
local pts = {}           -- points assigned to each facet
local TIME = 0
local e   = { {}, {} }   -- horizon edges: e[1][ptid], e[2][ptid]
local vistime = {}       -- per‐point visit timestamp
local queue = {}         -- facet queue
local resfnew, resfdel, respt = {}, {}, {}  -- temp lists

-- Initialize edge table and vistime
for k = 1,2 do
  e[k] = {}
  for i = 1, MAXN do
    e[k][i] = { netid = 0, facetid = 0 }
  end
end
for i = 1, MAXN do vistime[i] = 0 end

-- Vector class
local Vect = {}
Vect.__index = Vect
function Vect.new(x,y,z,id)
  return setmetatable({ x=x, y=y, z=z, id=id }, Vect)
end
function Vect:sub(o)
  return Vect.new(self.x-o.x, self.y-o.y, self.z-o.z, 0)
end
function Vect:cross(o)
  return Vect.new(
    self.y*o.z - self.z*o.y,
    self.z*o.x - self.x*o.z,
    self.x*o.y - self.y*o.x,
    0
  )
end
function Vect:dot(o)
  return self.x*o.x + self.y*o.y + self.z*o.z
end
function Vect:mag()
  return math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z)
end
function Vect:eq(o)
  local function eq(a,b) return math.abs(a-b)<EPS end
  return eq(self.x,o.x) and eq(self.y,o.y) and eq(self.z,o.z)
end

-- Line and Plane
local Line = {}
function Line.new(u,v) return { u=u, v=v } end

local Plane = {}
Plane.__index = Plane
function Plane.new(u,v,w)
  return setmetatable({ u=u, v=v, w=w }, Plane)
end
function Plane:normal()
  return self.v:sub(self.u):cross(self.w:sub(self.u))
end
function Plane:vecAt(i)
  -- i = 1,2,3
  if i==1 then return self.u
  elseif i==2 then return self.v
  else return self.w
  end
end
function Plane:vecId(i)
  return self:vecAt(i).id
end

-- Facet class
local Facet = {}
Facet.__index = Facet
function Facet.new()
  return setmetatable({ n={0,0,0}, id=0, vistime=0, isdel=false, p=Plane.new(nil,nil,nil) }, Facet)
end

-- Convex hull manager
local ConvexHulls3d = {}
ConvexHulls3d.__index = ConvexHulls3d
function ConvexHulls3d.new(idx)
  return setmetatable({ index=idx, surfacearea=0.0 }, ConvexHulls3d)
end

-- Utilities
local function gtr(a,b) return a-b>EPS end
local function ABS(x) return x<0 and -x or x end

-- Distances
local function distPointPlane(v,p)
  local n = p:normal()
  return (v:sub(p.u):dot(n)) / n:mag()
end
local function distPointLine(v,l)
  local d = v:sub(l.u):mag()
  if d==0 then return 0 end
  return l.v:sub(l.u):cross(v:sub(l.u)):mag() / l.v:sub(l.u):mag()
end
local function distPointPoint(a,b)
  return a:sub(b):mag()
end
local function isAbove(v,p)
  return gtr(v:sub(p.u):dot(p:normal()), 0)
end

-- Pre‐initialize
local function preConvexHulls()
  table.insert(pts,{})
  table.insert(FAC,Facet.new())  -- dummy at index 1
end

-- DFS for surface area
function ConvexHulls3d:dfsArea(fidx)
  local f = FAC[fidx]
  if f.vistime == TIME then return end
  f.vistime = TIME
  local n = f.p:normal()
  self.surfacearea = self.surfacearea + n:mag()/2
  for i=1,3 do self:dfsArea(f.n[i]) end
end

function ConvexHulls3d:getSurfaceArea()
  if self.surfacearea>0 then return self.surfacearea end
  TIME = TIME + 1
  self:dfsArea(self.index)
  return self.surfacearea
end

-- Find the horizon from facet fidx looking toward point p
function ConvexHulls3d:getHorizon(fidx,p,resfdel)
  local f = FAC[fidx]
  if not isAbove(p,f.p) then return 0 end
  if f.vistime==TIME then return -1 end
  f.vistime = TIME
  f.isdel = true
  table.insert(resfdel, fidx)
  local ret = -2
  for i=1,3 do
    local r = self:getHorizon(f.n[i], p, resfdel)
    if r==0 then
      local a = f.p:vecId(i)
      local b = f.p:vecId((i%3)+1)
      for j,pt in ipairs{a,b} do
        if vistime[pt]~=TIME then
          vistime[pt]=TIME
          e[1][pt] = { netid = (j==1 and b or a), facetid = f.n[i] }
        else
          e[2][pt] = { netid = (j==1 and b or a), facetid = f.n[i] }
        end
      end
      ret = a
    elseif r~=-1 and r~=-2 then
      ret = r
    end
  end
  return ret
end

-- Build initial tetrahedron
local function getStart(point, totp)
  -- pick 6 extremes
  local pt = {}
  for i=1,6 do pt[i]=point[1] end
  for i=1,totp do
    local v = point[i]
    if gtr(v.x,pt[1].x) then pt[1]=v end
    if gtr(pt[2].x,v.x) then pt[2]=v end
    if gtr(v.y,pt[3].y) then pt[3]=v end
    if gtr(pt[4].y,v.y) then pt[4]=v end
    if gtr(v.z,pt[5].z) then pt[5]=v end
    if gtr(pt[6].z,v.z) then pt[6]=v end
  end
  -- furthest pair
  local s = { pt[1], pt[2], point[1], point[1] }
  for i=1,6 do
    for j=i+1,6 do
      if gtr(distPointPoint(pt[i],pt[j]), distPointPoint(s[1],s[2])) then
        s[1],s[2]=pt[i],pt[j]
      end
    end
  end
  -- furthest from line
  local L = Line.new(s[1],s[2])
  s[3]=pt[1]
  for i=1,6 do
    if gtr(distPointLine(pt[i],L), distPointLine(s[3],L)) then
      s[3]=pt[i]
    end
  end
  -- furthest from plane
  s[4]=point[1]
  local base = Plane.new(s[1],s[2],s[3])
  for i=1,totp do
    if gtr(ABS(distPointPlane(point[i],base)), ABS(distPointPlane(s[4],base))) then
      s[4]=point[i]
    end
  end
  if gtr(0, distPointPlane(s[4],base)) then
    s[2],s[3]=s[3],s[2]
  end
  -- make 4 facets
  local fidx = {}
  for i=1,4 do
    local f = Facet.new()
    table.insert(FAC,f)
    f.id = #FAC
    fidx[i] = #FAC
  end
  FAC[fidx[1]].p = Plane.new(s[1],s[3],s[2])
  FAC[fidx[2]].p = Plane.new(s[1],s[2],s[4])
  FAC[fidx[3]].p = Plane.new(s[2],s[3],s[4])
  FAC[fidx[4]].p = Plane.new(s[3],s[1],s[4])
  -- neighbors
  FAC[fidx[1]].n = { fidx[4], fidx[3], fidx[2] }
  FAC[fidx[2]].n = { fidx[1], fidx[3], fidx[4] }
  FAC[fidx[3]].n = { fidx[1], fidx[4], fidx[2] }
  FAC[fidx[4]].n = { fidx[1], fidx[2], fidx[3] }
  -- prepare pts lists
  for i=1,4 do pts[fidx[i]] = {} end
  -- assign points above each face
  for i=1,totp do
    local v = point[i]
    if not (v:eq(s[1]) or v:eq(s[2]) or v:eq(s[3]) or v:eq(s[4])) then
      for j=1,4 do
        if isAbove(v,FAC[fidx[j]].p) then
          table.insert(pts[fidx[j]], v)
          break
        end
      end
    end
  end
  return ConvexHulls3d.new(fidx[1])
end

-- Main QuickHull3D
local function quickHull3d(point, totp)
  local hull = getStart(point, totp)
  -- init queue
  queue = { hull.index }
  for _,nbr in ipairs(FAC[hull.index].n) do
    table.insert(queue, nbr)
  end
  local snew = hull.index

  while #queue>0 do
    local nf = table.remove(queue,1)
    local face = FAC[nf]
    if face.isdel or #pts[nf]==0 then
      if not face.isdel then snew = nf end
    else
      -- farthest point from face
      local p = pts[nf][1]
      for i=2,#pts[nf] do
        local v = pts[nf][i]
        if gtr(distPointPlane(v,face.p), distPointPlane(p,face.p)) then
          p = v
        end
      end
      -- find horizon
      TIME = TIME + 1
      resfdel = {}
      local s = hull:getHorizon(nf, p, resfdel)

      -- build new faces around horizon
      resfnew = {}
      TIME = TIME + 1
      local from = -1
      local lastf, fstf = -1, -1
      while vistime[s] ~= TIME do
        vistime[s] = TIME
        local net, adj = 0,0
        if e[1][s].netid == from then
          net = e[2][s].netid; adj = e[2][s].facetid
        else
          net = e[1][s].netid; adj = e[1][s].facetid
        end
        -- find indices of s and net on face adj
        local pt1,pt2 = 1,1
        for i=1,3 do
          if point[s]:eq(FAC[adj].p:vecAt(i)) then pt1=i end
          if point[net]:eq(FAC[adj].p:vecAt(i)) then pt2=i end
        end
        if (pt1%3)+1 ~= pt2 then pt1,pt2 = pt2,pt1 end
        -- create new facet
        local nfnew = Facet.new()
        nfnew.p = Plane.new(FAC[adj].p:vecAt(pt2),
                            FAC[adj].p:vecAt(pt1), p)
        table.insert(FAC,nfnew)
        nfnew.id = #FAC
        table.insert(pts,{})
        table.insert(resfnew, nfnew.id)

        -- link adjacency
        nfnew.n[1] = adj
        FAC[adj].n[pt1] = nfnew.id
        if lastf~=-1 then
          local A1,A2 = nfnew.p:vecAt(2), FAC[lastf].p.u
          if A1:eq(A2) then
            nfnew.n[2], FAC[lastf].n[3] = lastf, nfnew.id
          else
            nfnew.n[3], FAC[lastf].n[2] = lastf, nfnew.id
          end
        else
          fstf = nfnew.id
        end
        lastf = nfnew.id
        from, s = s, net
      end

      -- close loop
      local A1,A2 = FAC[fstf].p:vecAt(2), FAC[lastf].p.u
      if A1:eq(A2) then
        FAC[fstf].n[2], FAC[lastf].n[3] = lastf, fstf
      else
        FAC[fstf].n[3], FAC[lastf].n[2] = lastf, fstf
      end

      -- collect deleted points
      respt = {}
      for _,fid in ipairs(resfdel) do
        for _,v in ipairs(pts[fid]) do
          table.insert(respt, v)
        end
        pts[fid] = {}
      end

      -- reassign
      for _,v in ipairs(respt) do
        if v~=p then
          for _,fid in ipairs(resfnew) do
            if isAbove(v,FAC[fid].p) then
              table.insert(pts[fid], v)
              break
            end
          end
        end
      end

      -- enqueue new faces
      for _,fid in ipairs(resfnew) do
        table.insert(queue, fid)
      end
    end
  end

  hull.index = snew
  return hull
end

-- Example usage
preConvexHulls()
local n = 4
local point = {}
local coords = {
  {0,0,0}, {1,0,0}, {0,1,0}, {0,0,1}
}
for i=1,n do
  local c = coords[i]
  point[i] = Vect.new(c[1],c[2],c[3], i)
end
local hull = quickHull3d(point, n)
print(string.format("%.3f", hull:getSurfaceArea()))
Output:
2.366


Works with: Perl version 5.22.1
Translation of: C++
#!/usr/bin/env perl
use strict;
use warnings;
use List::Util qw(first);

# Constants
use constant MAX_SIZE => 2500;
use constant EPSILON => 0.00000001;

# Numerical utilities
sub is_greater_than {
    my ($a, $b) = @_;
    return ($a - $b) > EPSILON;
}

sub is_equal {
    my ($a, $b) = @_;
    return abs($a - $b) < EPSILON;
}

# Vector class
package Vector {
    sub new {
        my ($class, $x, $y, $z, $id) = @_;
        $x //= 0;
        $y //= 0;
        $z //= 0;
        $id //= 0;
        
        return bless {
            x => $x,
            y => $y,
            z => $z,
            id => $id
        }, $class;
    }
    
    sub subtract {
        my ($self, $other) = @_;
        return Vector->new(
            $self->{x} - $other->{x},
            $self->{y} - $other->{y},
            $self->{z} - $other->{z}
        );
    }
    
    sub vector_product {
        my ($self, $other) = @_;
        return Vector->new(
            $self->{y} * $other->{z} - $self->{z} * $other->{y},
            $self->{z} * $other->{x} - $self->{x} * $other->{z},
            $self->{x} * $other->{y} - $self->{y} * $other->{x}
        );
    }
    
    sub scalar_product {
        my ($self, $other) = @_;
        return $self->{x} * $other->{x} + $self->{y} * $other->{y} + $self->{z} * $other->{z};
    }
    
    sub magnitude {
        my ($self) = @_;
        return sqrt($self->{x} * $self->{x} + $self->{y} * $self->{y} + $self->{z} * $self->{z});
    }
    
    sub equals {
        my ($self, $other) = @_;
        return main::is_equal($self->{x}, $other->{x}) && 
               main::is_equal($self->{y}, $other->{y}) && 
               main::is_equal($self->{z}, $other->{z});
    }
}

# Line class
package Line {
    sub new {
        my ($class, $u, $v) = @_;
        return bless {
            u => $u,
            v => $v
        }, $class;
    }
}

# Plane class
package Plane {
    sub new {
        my ($class, $u, $v, $w) = @_;
        return bless {
            u => $u,
            v => $v,
            w => $w
        }, $class;
    }
    
    sub normal {
        my ($self) = @_;
        return $self->{v}->subtract($self->{u})->vector_product($self->{w}->subtract($self->{u}));
    }
    
    sub vector_at_index {
        my ($self, $i) = @_;
        return $self->{u} if $i == 0;
        return $self->{v} if $i == 1;
        return $self->{w} if $i == 2;
        return 0;
    }
    
    sub vector_id {
        my ($self, $i) = @_;
        return $self->vector_at_index($i)->{id};
    }
}

# Facet class
package Facet {
    sub new {
        my ($class, $id, $plane) = @_;
        return bless {
            id => $id // 0,
            plane => $plane,
            N => [],
            visited_time => 0,
            is_deleted => 0
        }, $class;
    }
}

# Edge class
package Edge {
    sub new {
        my ($class) = @_;
        return bless {
            netID => 0,
            faceID => 0
        }, $class;
    }
}

# ConvexHulls3d class
package ConvexHulls3d {
    sub new {
        my ($class, $index) = @_;
        return bless {
            index => $index,
            surface_area => 0.0
        }, $class;
    }
    
    sub get_surface_area {
        my ($self) = @_;
        if (main::is_greater_than($self->{surface_area}, 0.0)) {
            return $self->{surface_area};
        }
        
        $main::time_step++;
        $self->dfs_area($self->{index});
        return $self->{surface_area};
    }
    
    sub dfs_area {
        my ($self, $f) = @_;
        if (($main::facets[$f]->{visited_time} // 0) == $main::time_step) {
            return;
        }
        
        $main::facets[$f]->{visited_time} = $main::time_step;
        my $normal = $main::facets[$f]->{plane}->normal();
        $self->{surface_area} += $normal->magnitude() / 2.0;
        
        for my $i (0..2) {
            $self->dfs_area($main::facets[$f]->{N}->[$i]);
        }
    }
    
    sub get_horizon {
        my ($self, $f, $point, $resDel) = @_;
        my $Ff = $main::facets[$f];
        
        if (!main::is_above($point, $Ff->{plane})) {
            return 0;
        }
        
        if (($Ff->{visited_time} // 0) == $main::time_step) {
            return -1;
        }
        
        $Ff->{visited_time} = $main::time_step;
        $Ff->{is_deleted} = 1;
        push @$resDel, $Ff->{id};
        
        my $result = -2;
        for my $i (0..2) {
            my $ni = $Ff->{N}->[$i];
            my $horizon = $self->get_horizon($ni, $point, $resDel);
            
            if ($horizon == 0) {
                my $a = $main::facets[$f]->{plane}->vector_id($i);
                my $b = $main::facets[$f]->{plane}->vector_id(($i + 1) % 3);
                
                for my $idx (0..1) {
                    my $pt = ($idx == 0) ? $a : $b;
                    my $facet = $ni;
                    
                    if (($main::visit_time[$pt] // 0) != $main::time_step) {
                        $main::visit_time[$pt] = $main::time_step;
                        $main::edges->[0]->[$pt]->{netID} = ($idx == 0) ? $b : $a;
                        $main::edges->[0]->[$pt]->{faceID} = $facet;
                    } else {
                        $main::edges->[1]->[$pt]->{netID} = ($idx == 0) ? $b : $a;
                        $main::edges->[1]->[$pt]->{faceID} = $facet;
                    }
                }
                $result = $a;
            } elsif ($horizon != -1 && $horizon != -2) {
                $result = $horizon;
            }
        }
        return $result;
    }
}

# Global variables
our @facets;
our @hull_points;
our $time_step = 0;
our $edges;
our @visit_time;
our @queue;
our @resfnew;
our @resfdel;
our @respt;

# Geometric utilities
sub distance_point_plane {
    my ($vec, $plane) = @_;
    my $num = $vec->subtract($plane->{u})->scalar_product($plane->normal());
    my $den = $plane->normal()->magnitude();
    return $num / $den;
}

sub distance_point_line {
    my ($vec, $line) = @_;
    my $length = $vec->subtract($line->{u})->magnitude();
    return 0.0 if $length == 0.0;
    
    return $line->{v}->subtract($line->{u})->vector_product($vec->subtract($line->{u}))->magnitude() / 
           $line->{v}->subtract($line->{u})->magnitude();
}

sub distance_point_point {
    my ($a, $b) = @_;
    return $a->subtract($b)->magnitude();
}

sub is_above {
    my ($point, $plane) = @_;
    return is_greater_than($point->subtract($plane->{u})->scalar_product($plane->normal()), 0.0);
}

sub prepare_convex_hulls {
    # Reserve index 0
    push @hull_points, [];
    push @facets, Facet->new();
    
    # Initialize edge vector
    $edges = [];
    for my $i (0..1) {
        $edges->[$i] = [];
        for my $j (0..MAX_SIZE-1) {
            $edges->[$i]->[$j] = Edge->new();
        }
    }
    
    # Initialize visit_time array
    @visit_time = (0) x MAX_SIZE;
}

sub get_initial_hull {
    my ($points, $total_points) = @_;
    
    my @extremes = ($points->[1]) x 6;
    
    for my $i (1..$total_points) {
        my $point = $points->[$i];
        $extremes[0] = $point if is_greater_than($point->{x}, $extremes[0]->{x});
        $extremes[1] = $point if is_greater_than($extremes[1]->{x}, $point->{x});
        $extremes[2] = $point if is_greater_than($point->{y}, $extremes[2]->{y});
        $extremes[3] = $point if is_greater_than($extremes[3]->{y}, $point->{y});
        $extremes[4] = $point if is_greater_than($point->{z}, $extremes[4]->{z});
        $extremes[5] = $point if is_greater_than($extremes[5]->{z}, $point->{z});
    }
    
    # Furthest pair
    my $extreme0 = $extremes[0];
    my $extreme1 = $extremes[1];
    for my $i (0..5) {
        for my $j ($i+1..5) {
            my $distance = distance_point_point($extremes[$i], $extremes[$j]);
            if (is_greater_than($distance, distance_point_point($extreme0, $extreme1))) {
                $extreme0 = $extremes[$i];
                $extreme1 = $extremes[$j];
            }
        }
    }
    
    # Furthest from line
    my $line = Line->new($extreme0, $extreme1);
    my $extreme2 = $extremes[0];
    for my $i (0..5) {
        if (is_greater_than(distance_point_line($extremes[$i], $line), distance_point_line($extreme2, $line))) {
            $extreme2 = $extremes[$i];
        }
    }
    
    # Furthest from plane
    my $extreme3 = $points->[1];
    my $basePlane = Plane->new($extreme0, $extreme1, $extreme2);
    for my $i (1..$total_points) {
        my $distance1 = abs(distance_point_plane($points->[$i], $basePlane));
        my $distance2 = abs(distance_point_plane($extreme3, $basePlane));
        if (is_greater_than($distance1, $distance2)) {
            $extreme3 = $points->[$i];
        }
    }
    
    if (is_greater_than(0, distance_point_plane($extreme3, $basePlane))) {
        ($extreme1, $extreme2) = ($extreme2, $extreme1);
    }
    
    # Create 4 initial facets
    my @f;
    for my $i (0..3) {
        push @facets, Facet->new(scalar @facets);
        $f[$i] = $#facets;
    }
    
    $facets[$f[0]]->{plane} = Plane->new($extreme0, $extreme2, $extreme1);
    $facets[$f[1]]->{plane} = Plane->new($extreme0, $extreme1, $extreme3);
    $facets[$f[2]]->{plane} = Plane->new($extreme1, $extreme2, $extreme3);
    $facets[$f[3]]->{plane} = Plane->new($extreme2, $extreme0, $extreme3);
    
    $facets[$f[0]]->{N} = [$f[3], $f[2], $f[1]];
    $facets[$f[1]]->{N} = [$f[0], $f[2], $f[3]];
    $facets[$f[2]]->{N} = [$f[0], $f[3], $f[1]];
    $facets[$f[3]]->{N} = [$f[0], $f[1], $f[2]];
    
    # Prepare hull_points array
    for my $i (0..3) {
        push @hull_points, [];
    }
    
    # Assign points
    for my $i (1..$total_points) {
        my $point = $points->[$i];
        next if ($point->equals($extreme0) || $point->equals($extreme1) || 
                $point->equals($extreme2) || $point->equals($extreme3));
        
        for my $j (0..3) {
            if (is_above($point, $facets[$f[$j]]->{plane})) {
                push @{$hull_points[$f[$j]]}, $point;
                last;
            }
        }
    }
    
    return ConvexHulls3d->new($f[0]);
}

sub QuickHull3D {
    my ($points, $total_points) = @_;
    my $hull = get_initial_hull($points, $total_points);
    
    # Initialize queue
    @queue = ();
    push @queue, $hull->{index};
    for my $i (0..2) {
        push @queue, $facets[$hull->{index}]->{N}->[$i];
    }
    
    my $new_horizon = 0;
    
    while (@queue) {
        my $nf = shift @queue;
        
        if ($facets[$nf]->{is_deleted} || !@{$hull_points[$nf]}) {
            if (!$facets[$nf]->{is_deleted}) {
                $new_horizon = $nf;
            }
            next;
        }
        
        # Farthest point
        my $point = $hull_points[$nf]->[0];
        for my $vec (@{$hull_points[$nf]}) {
            if (is_greater_than(distance_point_plane($vec, $facets[$nf]->{plane}),
                              distance_point_plane($point, $facets[$nf]->{plane}))) {
                $point = $vec;
            }
        }
        
        # Find horizon
        $time_step++;
        @resfdel = ();
        my $horizon = $hull->get_horizon($nf, $point, \@resfdel);
        
        # Build new faces
        @resfnew = ();
        $time_step++;
        my $from = -1;
        my $last_f = -1;
        my $first_f = -1;
        
        while (($visit_time[$horizon] // 0) != $time_step) {
            $visit_time[$horizon] = $time_step;
            my ($net, $f, $new_f);
            
            if ($edges->[0]->[$horizon]->{netID} == $from) {
                $net = $edges->[1]->[$horizon]->{netID};
                $f = $edges->[1]->[$horizon]->{faceID};
            } else {
                $net = $edges->[0]->[$horizon]->{netID};
                $f = $edges->[0]->[$horizon]->{faceID};
            }
            
            # Find indices on facet f
            my ($pt1, $pt2) = (0, 0);
            for my $i (0..2) {
                $pt1 = $i if $points->[$horizon]->equals($facets[$f]->{plane}->vector_at_index($i));
                $pt2 = $i if $points->[$net]->equals($facets[$f]->{plane}->vector_at_index($i));
            }
            if (($pt1 + 1) % 3 != $pt2) {
                ($pt1, $pt2) = ($pt2, $pt1);
            }
            
            # Create new facet
            push @facets, Facet->new(
                scalar @facets,
                Plane->new(
                    $facets[$f]->{plane}->vector_at_index($pt2),
                    $facets[$f]->{plane}->vector_at_index($pt1),
                    $point
                )
            );
            $new_f = $#facets;
            push @hull_points, [];
            push @resfnew, $new_f;
            
            $facets[$new_f]->{N}->[0] = $f;
            $facets[$f]->{N}->[$pt1] = $new_f;
            
            if ($last_f >= 0) {
                # Link with previous new facet
                if ($facets[$new_f]->{plane}->vector_at_index(1)->equals($facets[$last_f]->{plane}->{u})) {
                    $facets[$new_f]->{N}->[1] = $last_f;
                    $facets[$last_f]->{N}->[2] = $new_f;
                } else {
                    $facets[$new_f]->{N}->[2] = $last_f;
                    $facets[$last_f]->{N}->[1] = $new_f;
                }
            } else {
                $first_f = $new_f;
            }
            
            $last_f = $new_f;
            $from = $horizon;
            $horizon = $net;
        }
        
        # Close the loop
        if ($facets[$first_f]->{plane}->vector_at_index(1)->equals($facets[$last_f]->{plane}->{u})) {
            $facets[$first_f]->{N}->[1] = $last_f;
            $facets[$last_f]->{N}->[2] = $first_f;
        } else {
            $facets[$first_f]->{N}->[2] = $last_f;
            $facets[$last_f]->{N}->[1] = $first_f;
        }
        
        # Collect deleted points
        @respt = ();
        for my $f_id (@resfdel) {
            push @respt, @{$hull_points[$f_id]};
            $hull_points[$f_id] = [];
        }
        
        # Reassign
        for my $vec (@respt) {
            next if $vec->equals($point);
            for my $f_id (@resfnew) {
                if (is_above($vec, $facets[$f_id]->{plane})) {
                    push @{$hull_points[$f_id]}, $vec;
                    last;
                }
            }
        }
        
        # Enqueue new faces
        push @queue, @resfnew;
    }
    
    $hull->{index} = $new_horizon;
    return $hull;
}

# Main program
prepare_convex_hulls();

# Example: a tetrahedron
my $n = 4;
my @points = (undef); # Index 0 is unused
push @points, Vector->new(0, 0, 0, 1);
push @points, Vector->new(1, 0, 0, 2);
push @points, Vector->new(0, 1, 0, 3);
push @points, Vector->new(0, 0, 1, 4);

my $hull = QuickHull3D(\@points, $n);
printf "%.3f\n", $hull->get_surface_area();
Output:
2.366




Translation of: Go
constant MAXN = 2500,
         EPS  = 1e-8

// Globals
integer TIME = 0

sequence Facets = {},
         pts = {},  // vect
         e = repeat(repeat(0,MAXN),2), // Edge
         vistimeArr = repeat(0,MAXN),
         resfnew,
         resfdel

// Basic floating comparisons
function eq(atom a, b) return abs(a-b) < EPS end function
function gtr(atom a, b) return a-b > EPS end function

// Vect represents a 3D point/vector
enum X, Y, Z, VECID
type vect(sequence s)
    return length(s)=VECID
       and atom(s[X])
       and atom(s[Y])
       and atom(s[Z])
       and integer(s[VECID])
end type

function Sub(vect a, b)
    vect res = {a[X]-b[X], a[Y]-b[Y], a[Z]-b[Z], 0}
    return res
end function

function Cross(vect a, b)
    vect res = {a[Y]*b[Z] - a[Z]*b[Y],
                a[Z]*b[X] - a[X]*b[Z],
                a[X]*b[Y] - a[Y]*b[X],
                0}
    return res
end function

function Dot(vect a, b)
    return a[X]*b[X] + a[Y]*b[Y] + a[Z]*b[Z]
end function

function Mag(vect a)
    return sqrt(a[X]*a[X] + a[Y]*a[Y] + a[Z]*a[Z])
end function

function Eq(vect a, b)
    return eq(a[X], b[X])
       and eq(a[Y], b[Y])
       and eq(a[Z], b[Z])
end function

// line is the segment u->v
enum U, V, W
type line(sequence l)
    return length(l)=V
       and vect(l[U])
       and vect(l[V])
end type

// Plane is defined by three points u, v, w
type plane(sequence p)
    return length(p)=W
       and vect(p[U])
       and vect(p[V])
       and vect(p[W])
end type

// Normal vector of the plane
function Normal(plane p)
    vect res = Cross(Sub(p[V],p[U]),Sub(p[W],p[U]))
    return res
end function

// Facet is a face in the hull
enum NEIGH, /*FACET_ID,*/ VISTIME, ISDEL, P
type Facet(sequence f)
    return length(f)=P
       and sequence(f[NEIGH]) -- 3 ints
--     and integer(f[FACET_ID])
       and integer(f[VISTIME])
       and bool(f[ISDEL])
       and plane(f[P])
end type

// Edge on the horizon
enum NETID, FACET_ID
type Edge(sequence e)
    return length(e)=FACET_ID
       and integer(e[NETID])
       and integer(e[FACET_ID])
end type

// ConvexHulls3d manages hull construction
enum HULLID, SURFACEAREA
type ConvexHulls3d(sequence h)
    return length(h)=SURFACEAREA
       and integer(h[HULLID])
       and atom(h[SURFACEAREA])
end type

// Distances
function distPointPlane(vect v, plane p)
    vect np = Normal(p)
    atom num := Dot(Sub(v,p[U]),np),
         den := Mag(np)
    return num / den
end function

function distPointLine(vect v, line f)
    atom d := Mag(Sub(v,f[U]))
    if d == 0 then return 0 end if
    return Mag(Cross(Sub(f[V],f[U]),Sub(v,f[U]))) / Mag(Sub(f[V],f[U]))
end function

function distPointPoint(vect u, v)
    return Mag(Sub(u,v))
end function

function isAbove(vect v, plane p)
    return gtr(Dot(Sub(v,p[U]),Normal(p)), 0)
end function

// DFS to accumulate area
function dfsArea(ConvexHulls3d h, integer nf)
    if Facets[nf][VISTIME] != TIME then
        Facets[nf][VISTIME] = TIME
        vect nrm := Normal(Facets[nf][P])
        h[SURFACEAREA] += Mag(nrm) / 2
        for i=1 to 3 do
            h = dfsArea(h,Facets[nf][NEIGH][i])
        end for
    end if
    return h
end function

// GetSurfaceArea returns (and caches) the hull surface area
function GetSurfaceArea(ConvexHulls3d h)
    if not gtr(h[SURFACEAREA], 0) then
        TIME += 1
        h = dfsArea(h,h[HULLID])
    end if
    return h[SURFACEAREA]
end function

// Recursively find the horizon around point p
function getHorizon(ConvexHulls3d h, integer f, vect p)
    if not isAbove(p, Facets[f][P]) then
        return 0
    end if
    if Facets[f][VISTIME] == TIME then
        return -1
    end if
    Facets[f][VISTIME] = TIME
    Facets[f][ISDEL] = true
    resfdel = append(resfdel, f)
    integer ret := -2
    for i=1 to 3 do
        integer r := getHorizon(h,Facets[f][NEIGH][i], p)
        if r == 0 then
            integer j = {2,3,1}[i],
                    a := Facets[f][P][i][VECID],
                    b := Facets[f][P][j][VECID]
            for j, pt in {a, b} do
                integer edgedx = 2
                if vistimeArr[pt] != TIME then
                    vistimeArr[pt] = TIME
                    edgedx = 1
                end if
                e[edgedx][pt] = {{b,a}[j], Facets[f][NEIGH][i]}
            end for
            ret = a
        elsif r != -1 and r != -2 then
            ret = r
        end if
    end for
    return ret
end function

// Build the initial tetrahedron
function getStart(sequence points)
    sequence pt = repeat(points[1],6)
    vect s1,s2,s3,s4
    // pick extreme coords
    for v in points do
        if gtr(v[X], pt[1][X]) then pt[1] = v end if
        if gtr(pt[2][X], v[X]) then pt[2] = v end if
        if gtr(v[Y], pt[3][Y]) then pt[3] = v end if
        if gtr(pt[4][Y], v[Y]) then pt[4] = v end if
        if gtr(v[Z], pt[5][Z]) then pt[5] = v end if
        if gtr(pt[6][Z], v[Z]) then pt[6] = v end if
    end for
    // take furthest pair
    {s1,s2} = pt[1..2]
    for i,pi in pt do
        for pj in pt from i+1 do
            if gtr(distPointPoint(pi, pj),
                   distPointPoint(s1, s2)) then
                {s1, s2} = {pi, pj}
            end if
        end for
    end for
    // furthest from that line
    line L := {s1, s2}
    s3 = pt[1]
    for pi in pt from 2 do
        if gtr(distPointLine(pi, L), 
               distPointLine(s3, L)) then
            s3 = pi
        end if
    end for
    // furthest from the plane
    s4 = points[1]
    plane base := {s1, s2, s3}
    for p in points do
        if gtr(abs(distPointPlane(p, base)),
               abs(distPointPlane(s4, base))) then
            s4 = p
        end if
    end for
    if gtr(0, distPointPlane(s4, base)) then
        {s2, s3} = {s3, s2}
    end if
    // make 4 facets
    Facets = {{{4, 3, 2},0,0,{s1, s3, s2}},
              {{1, 3, 4},0,0,{s1, s2, s4}},
              {{1, 4, 2},0,0,{s2, s3, s4}},
              {{1, 2, 3},0,0,{s3, s1, s4}}}
    // prepare point-lists
    for i=1 to 4 do
        pts = append(pts, {})
    end for
    // assign remaining points
    for v in points do
        if not Eq(v,s1)
        and not Eq(v,s2)
        and not Eq(v,s3)
        and not Eq(v,s4) then
            for j=1 to 4 do
                if isAbove(v, Facets[j][P]) then
                    pts[j] = append(pts[j], v)
                    exit
                end if
            end for
        end if
    end for
    ConvexHulls3d res = {1,0}
    return res
end function

// The main QuickHull3D loop
function quickHull3d(sequence points)
    ConvexHulls3d hull := getStart(points)
    sequence queue = hull[HULLID]&Facets[hull[HULLID]][NEIGH]
    integer snew := 0

    while length(queue) do
        integer nf := queue[1]
        queue = queue[2..$]
        if Facets[nf][ISDEL] or length(pts[nf]) == 0 then
            if not Facets[nf][ISDEL] then
                snew = nf
            end if
        else
            // find farthest point
            vect p := pts[nf][1]
            for v in pts[nf] from 2 do
                if gtr(distPointPlane(v, Facets[nf][P]), 
                       distPointPlane(p, Facets[nf][P])) then
                    p = v
                end if
            end for
            // find horizon
            TIME += 1
            resfdel = {}
            integer s := getHorizon(hull,nf, p)

            // build new faces around the horizon
            resfnew = {}
            TIME += 1
            integer frm := -1,
                  lastf := -1,
                   fstf := -1
            while vistimeArr[s] != TIME do
                vistimeArr[s] = TIME
                integer net, f, fnew
                if e[0][s][NETID] == frm then
                    {net, f} = {e[1][s][NETID], e[1][s][FACET_ID]}
                else
                    {net, f} = {e[0][s][NETID], e[0][s][FACET_ID]}
                end if
                // find indices of s and net on facet f
                integer pt1, pt2
                for i=1 to 3 do
                    if Eq(points[s],Facets[f][P][i]) then
                        pt1 = i
                    end if
                    if Eq(points[net],Facets[f][P][i]) then
                        pt2 = i
                    end if
                end for
                if {2,3,1}[pt1] != pt2 then
                    {pt1, pt2} = {pt2, pt1}
                end if
                // create new facet facing outwards
                Facets = append(Facets, {{0,0,0},0,0,{Facets[f][P][pt2], Facets[f][P][pt1], p}})
                fnew = length(Facets)
                pts = append(pts, {})
                resfnew = append(resfnew, fnew)

                Facets[fnew][NEIGH][1] = f
                Facets[f][NEIGH][pt1] = fnew
                if lastf >= 0 then
                    // link with previous new facet
                    if Eq(Facets[fnew][P][2],Facets[lastf][P][U]) then
                        {Facets[fnew][NEIGH][1], Facets[lastf][NEIGH][2]} = {lastf, fnew}
                    else
                        {Facets[fnew][NEIGH][2], Facets[lastf][NEIGH][1]} = {lastf, fnew}
                    end if
                else
                    fstf = fnew
                end if
                lastf = fnew
                frm = s
                s = net
            end while
            // close the loop
            if Eq(Facets[fstf][P][V],Facets[lastf][P][U]) then
                {Facets[fstf][NEIGH][1], Facets[lastf][NEIGH][2]} = {lastf, fstf}
            else
                {Facets[fstf][NEIGH][2], Facets[lastf][NEIGH][1]} = {lastf, fstf}
            end if
            // collect points from deleted faces
            sequence respt = {}
            for fid in resfdel do
                respt &= pts[fid]
                pts[fid] = {}
            end for
            // reassign them
            for v in respt do
                if v != p then
                    for fid in resfnew do
                        if isAbove(v, Facets[fid][P]) then
                            pts[fid] = append(pts[fid], v)
                            exit
                        end if
                    end for
                end if
            end for
            // enqueue new faces
            queue &= resfnew
        end if
    end while

    hull[HULLID] = snew
    return hull
end function

// Example: a unit tetrahedron
constant unit_tetrahedron = {{0, 0, 0, 1},
                             {1, 0, 0, 2},
                             {0, 1, 0, 3},
                             {0, 0, 1, 4}}
printf(1,"%.3f\n", GetSurfaceArea(quickHull3d(unit_tetrahedron)))
Output:
2.366
import math

# Constants
MAXN = 2500
EPS = 1e-8


class Vect:
    def __init__(self, x=0.0, y=0.0, z=0.0, id=0):
        self.x = x
        self.y = y
        self.z = z
        self.id = id

    def __sub__(self, other):
        return Vect(self.x - other.x, self.y - other.y, self.z - other.z)

    def __truediv__(self, other):
        return Vect(self.y * other.z - self.z * other.y,
                    self.z * other.x - self.x * other.z,
                    self.x * other.y - self.y * other.x)

    def __mul__(self, other):
        return self.x * other.x + self.y * other.y + self.z * other.z

    def m(self):
        return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)

    def __eq__(self, other):
        return eq(self.x, other.x) and eq(self.y, other.y) and eq(self.z, other.z)

    def __repr__(self):
        return f"Vect({self.x}, {self.y}, {self.z}, {self.id})"


class Line:
    def __init__(self, u=None, v=None):
        self.u = u
        self.v = v


class Plane:
    def __init__(self, u=None, v=None, w=None):
        self.vec = [u, v, w] if u is not None and v is not None and w is not None else [None, None, None]

    def normal(self):
        return (self.vec[1] - self.vec[0]) / (self.vec[2] - self.vec[0])

    def u(self):
        return self.vec[0]


def gtr(a, b):
    return a - b > EPS


def eq(a, b):
    return -EPS < a - b < EPS


def Abs(x):
    return -x if gtr(0, x) else x


# Signed distance
def dist_point_plane(v, p):
    return (v - p.u()) * p.normal() / p.normal().m()


# Unsigned distance
def dist_point_line(v, f):
    return (((f.v - f.u) / (v - f.u)).m() / (f.v - f.u).m()) if (v - f.u).m() > 0 else 0


def dist_point_point(u, v):
    return (u - v).m()


def isabove(v, p):
    return gtr((v - p.u()) * p.normal(), 0)


# Convex Hull Structures
TIME = 0


class Facet:
    def __init__(self, id=0, p=None):
        # neighbor,correspond to point (u->v, v->w, w->u)
        self.n = [0, 0, 0]
        self.id = id
        # access timestamp
        self.vistime = 0
        self.isdel = False
        self.p = p if p is not None else Plane()

    def in_(self, n1, n2, n3):
        self.n = [n1, n2, n3]

    def __repr__(self):
        return f"Facet(id={self.id}, isdel={self.isdel}, vistime={self.vistime})"


# Edge of the horizon
class Edge:
    def __init__(self):
        self.netid = 0
        self.facetid = 0


# Store all faces
FAC = []


class ConvexHulls3d:
    def __init__(self, index):
        # Index face
        self.index = index
        self.surfacearea = 0.0

    def dfsArea(self, nf):
        global TIME, FAC
        # Already visited in current timestamp
        if FAC[nf].vistime == TIME:
            return
        FAC[nf].vistime = TIME
        if FAC[nf].p.normal() is not None:  # check if plane is initialized
            self.surfacearea += FAC[nf].p.normal().m() / 2
        for i in range(3):
            self.dfsArea(FAC[nf].n[i])

    def getSurfaceArea(self):
        global TIME, FAC
        if gtr(self.surfacearea, 0):
            return self.surfacearea
        TIME += 1
        self.dfsArea(self.index)
        return self.surfacearea

    def getHorizon(self, f, p, vistime, e1, e2, resfdel):
        global TIME, FAC
        if not isabove(p, FAC[f].p):
            return 0
        if FAC[f].vistime == TIME:
            return -1
        FAC[f].vistime = TIME
        # Mark the deleted face
        FAC[f].isdel = True
        resfdel.append(FAC[f].id)
        ret = -2
        for i in range(3):
            res = self.getHorizon(FAC[f].n[i], p, vistime, e1, e2, resfdel)
            if res == 0:
                pt = [FAC[f].p.vec[i].id, FAC[f].p.vec[(i + 1) % 3].id]
                for j in range(2):
                    if vistime[pt[j]] != TIME:
                        vistime[pt[j]] = TIME
                        e1[pt[j]].netid = pt[(j + 1) % 2]
                        e1[pt[j]].facetid = FAC[f].n[i]
                    else:
                        e2[pt[j]].netid = pt[(j + 1) % 2]
                        e2[pt[j]].facetid = FAC[f].n[i]
                ret = pt[0]
            elif res != -1 and res != -2:
                # The face is enclosed in the middle
                ret = res
        return ret


# Global Variables
# Global points
pts = []


# Construct initial simplex
def getStart(point, totp):
    global FAC, pts
    pt = [point[1]] * 6
    s = [point[1]] * 4

    # Find the maximum point of the coordinate axis
    for i in range(2, totp + 1):
        if gtr(point[i].x, pt[0].x):
            pt[0] = point[i]
        if gtr(pt[1].x, point[i].x):
            pt[1] = point[i]
        if gtr(point[i].y, pt[2].y):
            pt[2] = point[i]
        if gtr(pt[3].y, point[i].y):
            pt[3] = point[i]
        if gtr(point[i].z, pt[4].z):
            pt[4] = point[i]
        if gtr(pt[5].z, point[i].z):
            pt[5] = point[i]

    # Take the two points with the largest distance
    for i in range(6):
        for j in range(i + 1, 6):
            if gtr(dist_point_point(pt[i], pt[j]), dist_point_point(s[0], s[1])):
                s[0] = pt[i]
                s[1] = pt[j]

    # Take the point farthest from the line connecting the two points
    for i in range(6):
        if gtr(dist_point_line(pt[i], Line(s[0], s[1])), dist_point_line(s[2], Line(s[0], s[1]))):
            s[2] = pt[i]

    # Take the point farthest from the face
    for i in range(1, totp + 1):  # !!
        if gtr(Abs(dist_point_plane(point[i], Plane(s[0], s[1], s[2]))),
               Abs(dist_point_plane(s[3], Plane(s[0], s[1], s[2])))):
            s[3] = point[i]

    # Ensure that the constructed face faces outwards
    if gtr(0, dist_point_plane(s[3], Plane(s[0], s[1], s[2]))):
        s[1], s[2] = s[2], s[1]

    # Construct simplex
    f = [0] * 4
    for i in range(4):
        FAC.append(Facet(id=len(FAC)))
        f[i] = len(FAC) - 1

    FAC[f[0]].p = Plane(s[0], s[2], s[1])  # Bottom face
    FAC[f[1]].p = Plane(s[0], s[1], s[3])
    FAC[f[2]].p = Plane(s[1], s[2], s[3])
    FAC[f[3]].p = Plane(s[2], s[0], s[3])

    FAC[f[0]].in_(f[3], f[2], f[1])
    FAC[f[1]].in_(f[0], f[2], f[3])
    FAC[f[2]].in_(f[0], f[3], f[1])
    FAC[f[3]].in_(f[0], f[1], f[2])

    # Assign point set space to four faces
    for i in range(4):
        pts.append([])

    # Assign points to four faces
    for i in range(1, totp + 1):
        if point[i] == s[0] or point[i] == s[1] or point[i] == s[2] or point[i] == s[3]:
            continue
        for j in range(4):
            if isabove(point[i], FAC[f[j]].p):
                pts[f[j]].append(point[i])
                break

    # Return the initial simplex, using a face as index
    return ConvexHulls3d(f[0])


# Border line graph information
e = [[Edge() for _ in range(MAXN)] for _ in range(2)]
# Timestamp of each point access
vistime = [0] * MAXN
que = []
# Save the newly constructed face
resfnew = []
# Save the deleted face
resfdel = []
# Save the point to be allocated
respt = []


def quickHull3d(point, totp):
    global FAC, pts, TIME, e, vistime, que, resfnew, resfdel, respt
    hull = getStart(point, totp)
    # Add the face of initial simplex to queue
    que = [hull.index]
    for i in range(3):
        que.append(FAC[hull.index].n[i])
    # snew saves index face of the final convex hull
    snew = 0

    while que:
        nf = que.pop(0)
        # Skip if the current face has been deleted
        if FAC[nf].isdel:
            continue
        # Skip if no vertices are allocated to the current face
        if not pts[nf]:
            snew = nf
            continue

        # Find the farthest point from the face
        p = pts[nf][0]
        for i in range(1, len(pts[nf])):
            if gtr(dist_point_plane(pts[nf][i], FAC[nf].p), dist_point_plane(p, FAC[nf].p)):
                p = pts[nf][i]

        # Find the horizon
        TIME += 1
        resfdel = []
        # The current face must be deleted, so start dfs from current face
        s = hull.getHorizon(nf, p, vistime, e[0], e[1], resfdel)

        # Iterate over horizon(go around a circle), construct new face
        # When finding horizon, we can't know whether an edge is clockwise or counterclockwise, so it needs to be judged here
        resfnew = []
        TIME += 1
        from_ = 0  # The previous visited point
        lastf = 0  # The last created face
        fstf = 0  # The first created face
        while vistime[s] != TIME:
            # Record whether the current point has been visited with timestamp
            vistime[s] = TIME
            net = 0  # Next point
            f = 0  # The unseen face connected to the current edge on horizon
            fnew = 0  # New face

            # Make sure the traversal direction is correct
            if e[0][s].netid == from_:
                net = e[1][s].netid
                f = e[1][s].facetid
            else:
                net = e[0][s].netid
                f = e[0][s].facetid

            # Find the counterclockwise information of these two points on the adjacent face
            pt1 = -1
            pt2 = -1
            for i in range(3):
                if point[s] == FAC[f].p.vec[i]:
                    pt1 = i
                if point[net] == FAC[f].p.vec[i]:
                    pt2 = i

            # Make sure pt1->pt2 is arranged counterclockwise by adjacent face points
            if (pt1 + 1) % 3 != pt2:
                pt1, pt2 = pt2, pt1  # swap

            # The face constructed in this way faces outward
            FAC.append(Facet(id=len(FAC), p=Plane(FAC[f].p.vec[pt2], FAC[f].p.vec[pt1], p)))
            fnew = len(FAC) - 1
            pts.append([])
            resfnew.append(fnew)

            # Maintain adjacency information
            FAC[fnew].n[0] = f
            FAC[f].n[pt1] = fnew
            if lastf:
                # Can't determine whether to traverse clockwise or counterclockwise in advance
                # Maintain adjacency information between new faces
                if FAC[fnew].p.vec[1] == FAC[lastf].p.vec[0]:
                    FAC[fnew].n[1] = lastf
                    FAC[lastf].n[2] = fnew
                else:
                    FAC[fnew].n[2] = lastf
                    FAC[lastf].n[1] = fnew
            else:
                fstf = fnew  # No new face yet
            lastf = fnew
            from_ = s
            s = net

        # Give the new face head and tail maintenance critical information
        if FAC[fstf].p.vec[1] == FAC[lastf].p.vec[0]:
            FAC[fstf].n[1] = lastf
            FAC[lastf].n[2] = fstf
        else:
            FAC[fstf].n[2] = lastf
            FAC[lastf].n[1] = fstf

        # Get all the points to be assigned
        respt = []
        for i in range(len(resfdel)):
            for j in range(len(pts[resfdel[i]])):
                respt.append(pts[resfdel[i]][j])
            pts[resfdel[i]] = []

        # Assign points
        for i in range(len(respt)):
            if respt[i] == p:
                continue  # Skip the points used to create the new face
            for j in range(len(resfnew)):
                if isabove(respt[i], FAC[resfnew[j]].p):
                    pts[resfnew[j]].append(respt[i])
                    break  # Make sure the points are not reassigned

        # Add the new face to queue
        for i in range(len(resfnew)):
            que.append(resfnew[i])
    hull.index = snew
    return hull


def preConvexHulls():
    global pts, FAC
    # 0 for reservation
    pts.append([])
    FAC.append(Facet())


if __name__ == "__main__":
    preConvexHulls()
    n = 4 # number of points
    point = [None] * (n + 1)  # 1-indexed to match original code
    my_input=[[0.0,0.0,0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0] ]

    for i in range(1, n + 1):
        x, y, z = my_input[i-1]
        point[i] = Vect(x, y, z, id=i)
    hull = quickHull3d(point, n)
    print(f"{hull.getSurfaceArea():.3f}")
Output:
2.366
Translation of: C++
Translation of: Go
# 20250710 Raku programming solution

constant MAX_SIZE = 2500;
constant EPSILON = 1e-8;

sub        is-equal($a, $b, :$eps = EPSILON) { abs($a - $b) < $eps }
sub is-greater-than($a, $b, :$eps = EPSILON) {    ($a - $b) > $eps }

class Vector {
   has Real ($.x, $.y, $.z) is rw;
   has  Int  $.id           is rw;

   method subtract(Vector $other) {
      Vector.new( :x($!x - $other.x), :y($!y - $other.y), :z($!z - $other.z) )
   }
   method cross-product(Vector $other) {
      Vector.new(
         x => $!y * $other.z - $!z * $other.y,
         y => $!z * $other.x - $!x * $other.z,
         z => $!x * $other.y - $!y * $other.x
      )
   }
   method dot-product(Vector $other) { 
      $!x, $!y, $!z Z*+ $other.x, $other.y, $other.z # Seq 
   }
   method magnitude { sqrt($!x² + $!y² + $!z²) }
   method equals(Vector $other) {
      all (($!x, $other.x),($!y,$other.y),($!z,$other.z)).map: { is-equal |$_ }
   }
   method gist { "Vector({$!x}, {$!y}, {$!z}, id={$!id})" }
}
class Line { has Vector ($.u, $.v) is rw }
class Plane {
   has Vector ($.u, $.v, $.w) is rw;
   method normal { $!v.subtract($!u).cross-product($!w.subtract($!u)) }
   method vector-at(Int $i) { ($!u, $!v, $!w)[$i] // Vector.new }
   method vector-id(Int $i) { self.vector-at($i).id }
}
class Facet {
   has Int $.id is rw = 0;
   has Int $.visited-time is rw = 0;
   has Bool $.is-deleted is rw = False;
   has Plane $.plane is rw;
   has @.neighbors is rw;
}
class Edge { has Int ($.net-id, $.face-id) is rw }

# Global state variables
my ( @facets, @hull-points, @edges, @visit-time, @queue );
my ( @res-facets-new, @res-facets-deleted, @res-points, $time-step );

# Geometric utilities
sub distance-point-plane(Vector $vec, Plane $plane) {
   $vec.subtract($plane.u).dot-product($plane.normal) / $plane.normal.magnitude
}
sub distance-point-line(Vector $vec, Line $line) {
   return 0 if my $length = $vec.subtract($line.u).magnitude == 0;
   $line.v.subtract($line.u).cross-product($vec.subtract($line.u)).magnitude /
   $line.v.subtract($line.u).magnitude
}
sub distance-point-point(Vector $a, Vector $b) { $a.subtract($b).magnitude }
sub is-above(Vector $point, Plane $plane) {
   is-greater-than($point.subtract($plane.u).dot-product($plane.normal), 0)
}

class ConvexHull3D {
   has Int         $.index is rw;
   has Real $.surface-area is rw = 0;

   method get-surface-area {
      return $!surface-area if is-greater-than($!surface-area, 0);
      $time-step++;
      self!dfs-area($!index);
      return $!surface-area
   }
   method !dfs-area(Int $facet-index) {
      return if @facets[$facet-index].visited-time == $time-step;

      @facets[$facet-index].visited-time = $time-step;
      $!surface-area += ( @facets[$facet-index].plane.normal ).magnitude / 2;

      do for ^3 -> $i { self!dfs-area(@facets[$facet-index].neighbors[$i]) }
   }
   method get-horizon(Int $facet-index, Vector $point, @res-deleted) {
      return 0 unless is-above($point, @facets[$facet-index].plane);
      return -1 if @facets[$facet-index].visited-time == $time-step;

      @facets[$facet-index].visited-time = $time-step;
      @facets[$facet-index].is-deleted = True;
      @res-deleted.push(@facets[$facet-index].id);

      my $result = -2;
      for 0..2 -> $neighbor-index {
         my $neighbor-facet-index = @facets[$facet-index].neighbors[$neighbor-index];
         my $horizon = self.get-horizon($neighbor-facet-index, $point, @res-deleted);

         if $horizon == 0 {
            my $a = @facets[$facet-index].plane.vector-id($neighbor-index);
            my $b = @facets[$facet-index].plane.vector-id(($neighbor-index + 1) % 3);

            for (0, 1) -> $idx {
               my $point-id = $idx == 0 ?? $a !! $b;
               my $neighbor-facet = $neighbor-facet-index;

               if @visit-time[$point-id] != $time-step {
                  @visit-time[$point-id] = $time-step;
                  @edges[0][$point-id].net-id = $idx == 0 ?? $b !! $a;
                  @edges[0][$point-id].face-id = $neighbor-facet;
               } else {
                  @edges[1][$point-id].net-id = $idx == 0 ?? $b !! $a;
                  @edges[1][$point-id].face-id = $neighbor-facet;
               }
            }
            $result = $a;
         } elsif $horizon != -1 && $horizon != -2 {
            $result = $horizon;
         }
      }
      return $result
   }
}

sub get-initial-hull(@points, Int $total-points) {
    # Find extreme points in each dimension
    my @extremes = @points[1] xx 6;

   for @points[1..$total-points] -> $point {
      @extremes[0] = $point if is-greater-than($point.x, @extremes[0].x);
      @extremes[1] = $point if is-greater-than(@extremes[1].x, $point.x);
      @extremes[2] = $point if is-greater-than($point.y, @extremes[2].y);
      @extremes[3] = $point if is-greater-than(@extremes[3].y, $point.y);
      @extremes[4] = $point if is-greater-than($point.z, @extremes[4].z);
      @extremes[5] = $point if is-greater-than(@extremes[5].z, $point.z);
   }
   # Find furthest pair
   my ($extreme0, $extreme1) = @extremes[0,1];
   for ^6 -> $i {
      for $i+1..^6 -> $j {
         my $distance = distance-point-point(@extremes[$i], @extremes[$j]);
         if is-greater-than($distance, distance-point-point($extreme0, $extreme1)) {
            ($extreme0, $extreme1) = @extremes[$i], @extremes[$j]
         }
      }
   }
   # Find furthest point from line
   my $line = Line.new(u => $extreme0, v => $extreme1);
   my $extreme2 = @extremes[0];
   for @extremes -> $point {
      if is-greater-than(distance-point-line($point, $line), distance-point-line($extreme2, $line)) {
         $extreme2 = $point;
      }
   }
   # Find furthest point from plane
   my $extreme3 = @points[1];
   my $base-plane = Plane.new(u => $extreme0, v => $extreme1, w => $extreme2);
   for 1..$total-points -> $i {
      my $dist1 = abs(distance-point-plane(@points[$i], $base-plane));
      my $dist2 = abs(distance-point-plane($extreme3, $base-plane));
      if is-greater-than($dist1, $dist2) { $extreme3 = @points[$i] }
   }
   # Ensure proper orientation
   if is-greater-than(0, distance-point-plane($extreme3, $base-plane)) {
      ($extreme1, $extreme2) = $extreme2, $extreme1;
   }
   # Create 4 initial facets
   my @facet-indices = ^4;
   for ^4 -> $i {
      @facets.push(Facet.new(id => @facets.elems));
      @facet-indices[$i] = @facets.end;
   }
   @facets[@facet-indices[0]].plane = Plane.new(u => $extreme0, v => $extreme2, w => $extreme1);
   @facets[@facet-indices[1]].plane = Plane.new(u => $extreme0, v => $extreme1, w => $extreme3);
   @facets[@facet-indices[2]].plane = Plane.new(u => $extreme1, v => $extreme2, w => $extreme3);
   @facets[@facet-indices[3]].plane = Plane.new(u => $extreme2, v => $extreme0, w => $extreme3);
   @facets[@facet-indices[0]].neighbors = [@facet-indices[3], @facet-indices[2], @facet-indices[1]];
   @facets[@facet-indices[1]].neighbors = [@facet-indices[0], @facet-indices[2], @facet-indices[3]];
   @facets[@facet-indices[2]].neighbors = [@facet-indices[0], @facet-indices[3], @facet-indices[1]];
   @facets[@facet-indices[3]].neighbors = [@facet-indices[0], @facet-indices[1], @facet-indices[2]];
   # Assign remaining points to facets
   for @points[1..$total-points] -> $point {
      next if any(($extreme0,$extreme1,$extreme2,$extreme3)>>.&{$point.equals($_)});  
      for ^4 -> $j {
         if is-above($point, @facets[@facet-indices[$j]].plane) {
            @hull-points[@facet-indices[$j]].push($point);
            last;
         }
      }
   }
   return ConvexHull3D.new(index => @facet-indices[0])
}
sub quick-hull-Td(@points, Int $total-points) {
   my $hull = get-initial-hull(@points, $total-points);

   # Initialize processing queue
   @queue = [$hull.index];
   @queue.append(@facets[$hull.index].neighbors[^3]);

   my $new-horizon = 0;
   while @queue {
      my $next-facet-index = @queue.shift;
      if @facets[$next-facet-index].is-deleted || !@hull-points[$next-facet-index] {
         $new-horizon = $next-facet-index unless @facets[$next-facet-index].is-deleted;
         next;
      }
      # Find furthest point from current facet
      my $point = @hull-points[$next-facet-index][0];
      for @hull-points[$next-facet-index] -> $vec {
         if is-greater-than(distance-point-plane($vec, @facets[$next-facet-index].plane), distance-point-plane($point, @facets[$next-facet-index].plane)) {
            $point = $vec;
         }
      }
      # Find horizon
      $time-step++;
      @res-facets-deleted = ();
      my $horizon = $hull.get-horizon($next-facet-index, $point, @res-facets-deleted);
      # Build new faces around horizon
      $time-step++;
      my ($from, $last-facet-index, $first-facet-index) = -1 xx 3;

      while @visit-time[$horizon] != $time-step {
         @visit-time[$horizon] = $time-step;
         my ($net, $facet-index, $new-facet-index);

         if @edges[0][$horizon].net-id == $from {
            $net = @edges[1][$horizon].net-id;
            $facet-index = @edges[1][$horizon].face-id;
         } else {
            $net = @edges[0][$horizon].net-id;
            $facet-index = @edges[0][$horizon].face-id;
         }
         # Find indices on facet f
         my ($point-index1, $point-index2) = 0, 0;
         for ^3 -> $i {
            $point-index1 = $i if @points[$horizon].equals(@facets[$facet-index].plane.vector-at($i));
            $point-index2 = $i if @points[$net].equals(@facets[$facet-index].plane.vector-at($i));
         }
         ($point-index1, $point-index2) = $point-index2, $point-index1 if ($point-index1 + 1) % 3 != $point-index2;
         # Create new facet
         @facets.push(Facet.new(
            id    => @facets.elems,
            plane => Plane.new(
               u  => @facets[$facet-index].plane.vector-at($point-index2),
               v  => @facets[$facet-index].plane.vector-at($point-index1),
               w  => $point
            )
         ));
         $new-facet-index = @facets.end;
         @res-facets-new.push($new-facet-index);
         @facets[$new-facet-index].neighbors[0] = $facet-index;
         @facets[$facet-index].neighbors[$point-index1] = $new-facet-index;
         if $last-facet-index >= 0 { # Link with previous new facet
            if @facets[$new-facet-index].plane.vector-at(1).equals(@facets[$last-facet-index].plane.u) {
               @facets[$new-facet-index].neighbors[1] = $last-facet-index;
               @facets[$last-facet-index].neighbors[2] = $new-facet-index;
            } else {
               @facets[$new-facet-index].neighbors[2] = $last-facet-index;
               @facets[$last-facet-index].neighbors[1] = $new-facet-index;
            }
         } else {
            $first-facet-index = $new-facet-index;
         }
         ($last-facet-index, $from, $horizon) = $new-facet-index, $horizon, $net
      }
      # Close the loop
      if @facets[$first-facet-index].plane.vector-at(1).equals(@facets[$last-facet-index].plane.u) {
         @facets[$first-facet-index].neighbors[1] = $last-facet-index;
         @facets[$last-facet-index].neighbors[2] = $first-facet-index;
      } else {
         @facets[$first-facet-index].neighbors[2] = $last-facet-index;
         @facets[$last-facet-index].neighbors[1] = $first-facet-index;
      }
      # Collect points from deleted facets
      @res-points = gather for @res-facets-deleted -> $facet-id {
         take @hull-points[$facet-id];
         @hull-points[$facet-id] = [];
      } 
      # Reassign points to new facets
      for @res-points -> $vec {
         next if $vec.equals($point);
         for @res-facets-new -> $facet-id {
            if is-above($vec, @facets[$facet-id].plane) {
               @hull-points[$facet-id].push($vec) and last
            }
         }
      }
      @queue.append(@res-facets-new); # Enqueue new faces for processing
   }
   $hull.index = $new-horizon;
   return $hull
}
                                  # Example: a tetrahedron
(my @points = Vector.new).append( # placeholder at index 0
   Vector.new(x => 0, y => 0, z => 0, id => 1),
   Vector.new(x => 1, y => 0, z => 0, id => 2),
   Vector.new(x => 0, y => 1, z => 0, id => 3),
   Vector.new(x => 0, y => 0, z => 1, id => 4)
);
say quick-hull-Td(@points, 4).get-surface-area.fmt('%.3f');

You may Attempt This Online!

Run it on Rust Playground!

Translation of: Python
use std::f64;

const MAXN: usize = 2500;
const EPS: f64 = 1e-8;

#[derive(Clone, Copy, Debug)]
struct Vect {
    x: f64,
    y: f64,
    z: f64,
    id: usize,
}

impl Vect {
    fn new(x: f64, y: f64, z: f64, id: usize) -> Self {
        Vect { x, y, z, id }
    }

    fn sub(&self, other: &Vect) -> Vect {
        Vect::new(self.x - other.x, self.y - other.y, self.z - other.z, 0)
    }

    fn cross(&self, other: &Vect) -> Vect {
        Vect::new(
            self.y * other.z - self.z * other.y,
            self.z * other.x - self.x * other.z,
            self.x * other.y - self.y * other.x,
            0,
        )
    }

    fn dot(&self, other: &Vect) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }

    fn m(&self) -> f64 {
        f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
    }

    fn eq(&self, other: &Vect) -> bool {
        eq(self.x, other.x) && eq(self.y, other.y) && eq(self.z, other.z)
    }
}

struct Line {
    u: Vect,
    v: Vect,
}

impl Line {
    fn new(u: Vect, v: Vect) -> Self {
        Line { u, v }
    }
}

#[derive(Clone)]
struct Plane {
    vec: [Vect; 3],
}

impl Plane {
    fn new(u: Vect, v: Vect, w: Vect) -> Self {
        Plane { vec: [u, v, w] }
    }

    fn normal(&self) -> Vect {
        self.vec[1].sub(&self.vec[0]).cross(&self.vec[2].sub(&self.vec[0]))
    }

    fn u(&self) -> Vect {
        self.vec[0]
    }
}

fn gtr(a: f64, b: f64) -> bool {
    a - b > EPS
}

fn eq(a: f64, b: f64) -> bool {
    -EPS < a - b && a - b < EPS
}

fn abs(x: f64) -> f64 {
    if gtr(0.0, x) { -x } else { x }
}

// Signed distance
fn dist_point_plane(v: &Vect, p: &Plane) -> f64 {
    let normal = p.normal();
    v.sub(&p.u()).dot(&normal) / normal.m()
}

// Unsigned distance
fn dist_point_line(v: &Vect, f: &Line) -> f64 {
    if v.sub(&f.u).m() > 0.0 {
        f.v.sub(&f.u).cross(&v.sub(&f.u)).m() / f.v.sub(&f.u).m()
    } else {
        0.0
    }
}

fn dist_point_point(u: &Vect, v: &Vect) -> f64 {
    u.sub(v).m()
}

fn isabove(v: &Vect, p: &Plane) -> bool {
    gtr(v.sub(&p.u()).dot(&p.normal()), 0.0)
}

// Convex Hull Structures
#[derive(Clone)]
struct Facet {
    n: [usize; 3],   // neighbors, correspond to point (u->v, v->w, w->u)
    id: usize,
    vistime: usize,  // access timestamp
    isdel: bool,
    p: Plane,
}

impl Facet {
    fn new(id: usize, p: Plane) -> Self {
        Facet {
            n: [0, 0, 0],
            id,
            vistime: 0,
            isdel: false,
            p,
        }
    }

    fn set_neighbors(&mut self, n1: usize, n2: usize, n3: usize) {
        self.n = [n1, n2, n3];
    }
}

// Edge of the horizon
#[derive(Clone)]
struct Edge {
    netid: usize,
    facetid: usize,
}

impl Edge {
    fn new() -> Self {
        Edge { netid: 0, facetid: 0 }
    }
}

struct ConvexHulls3d {
    index: usize,      // Index face
    surfacearea: f64,
}

impl ConvexHulls3d {
    fn new(index: usize) -> Self {
        ConvexHulls3d {
            index,
            surfacearea: 0.0,
        }
    }

    fn dfs_area(&mut self, nf: usize, fac: &mut Vec<Facet>, time: &mut usize) {
        // Already visited in current timestamp
        if fac[nf].vistime == *time {
            return;
        }
        
        fac[nf].vistime = *time;
        
        self.surfacearea += fac[nf].p.normal().m() / 2.0;
        
        // Make a copy of neighbors to avoid borrow issues
        let neighbors = fac[nf].n;
        for i in 0..3 {
            self.dfs_area(neighbors[i], fac, time);
        }
    }

    fn get_surface_area(&mut self, fac: &mut Vec<Facet>, time: &mut usize) -> f64 {
        if gtr(self.surfacearea, 0.0) {
            return self.surfacearea;
        }
        *time += 1;
        self.dfs_area(self.index, fac, time);
        self.surfacearea
    }

    fn get_horizon(
        &self,
        f: usize,
        p: Vect,
        vistime: &mut [usize],
        e1: &mut [Edge],
        e2: &mut [Edge],
        resfdel: &mut Vec<usize>,
        fac: &mut Vec<Facet>,
        time: usize,
    ) -> isize {
        if !isabove(&p, &fac[f].p) {
            return 0;
        }
        
        if fac[f].vistime == time {
            return -1;
        }
        
        fac[f].vistime = time;
        // Mark the deleted face
        fac[f].isdel = true;
        resfdel.push(fac[f].id);
        
        let mut ret: isize = -2;
        
        // Make a copy of neighbors to avoid borrow issues
        let neighbors = fac[f].n;
        for i in 0..3 {
            let res = self.get_horizon(
                neighbors[i],
                p,
                vistime,
                e1,
                e2,
                resfdel,
                fac,
                time,
            );
            
            if res == 0 {
                let pt = [
                    fac[f].p.vec[i].id,
                    fac[f].p.vec[(i + 1) % 3].id
                ];
                
                for j in 0..2 {
                    if vistime[pt[j]] != time {
                        vistime[pt[j]] = time;
                        e1[pt[j]].netid = pt[(j + 1) % 2];
                        e1[pt[j]].facetid = neighbors[i];
                    } else {
                        e2[pt[j]].netid = pt[(j + 1) % 2];
                        e2[pt[j]].facetid = neighbors[i];
                    }
                }
                ret = pt[0] as isize;
            } else if res != -1 && res != -2 {
                // The face is enclosed in the middle
                ret = res;
            }
        }
        
        ret
    }
}

// Construct initial simplex
fn get_start(point: &[Vect], totp: usize) -> (ConvexHulls3d, Vec<Facet>, Vec<Vec<Vect>>) {
    let mut fac = Vec::new();
    let mut pts = Vec::new();
    
    // Add a dummy facet at index 0
    fac.push(Facet::new(0, Plane::new(
        Vect::new(0.0, 0.0, 0.0, 0),
        Vect::new(0.0, 0.0, 0.0, 0),
        Vect::new(0.0, 0.0, 0.0, 0)
    )));
    
    let mut pt = [point[1]; 6];
    let mut s = [point[1]; 4];

    // Find the maximum point of the coordinate axis
    for i in 2..=totp {
        if gtr(point[i].x, pt[0].x) {
            pt[0] = point[i];
        }
        if gtr(pt[1].x, point[i].x) {
            pt[1] = point[i];
        }
        if gtr(point[i].y, pt[2].y) {
            pt[2] = point[i];
        }
        if gtr(pt[3].y, point[i].y) {
            pt[3] = point[i];
        }
        if gtr(point[i].z, pt[4].z) {
            pt[4] = point[i];
        }
        if gtr(pt[5].z, point[i].z) {
            pt[5] = point[i];
        }
    }

    // Take the two points with the largest distance
    for i in 0..6 {
        for j in (i+1)..6 {
            if gtr(dist_point_point(&pt[i], &pt[j]), dist_point_point(&s[0], &s[1])) {
                s[0] = pt[i];
                s[1] = pt[j];
            }
        }
    }

    // Take the point farthest from the line connecting the two points
    for i in 0..6 {
        if gtr(
            dist_point_line(&pt[i], &Line::new(s[0], s[1])),
            dist_point_line(&s[2], &Line::new(s[0], s[1]))
        ) {
            s[2] = pt[i];
        }
    }

    // Take the point farthest from the face
    for i in 1..=totp {
        if gtr(
            abs(dist_point_plane(&point[i], &Plane::new(s[0], s[1], s[2]))),
            abs(dist_point_plane(&s[3], &Plane::new(s[0], s[1], s[2])))
        ) {
            s[3] = point[i];
        }
    }

    // Ensure that the constructed face faces outwards
    if gtr(0.0, dist_point_plane(&s[3], &Plane::new(s[0], s[1], s[2]))) {
        // Use the array swap method instead of std::mem::swap
        s.swap(1, 2);
    }

    // Construct simplex
    let mut f = [0; 4];
    for i in 0..4 {
        fac.push(Facet::new(
            fac.len(),
            Plane::new(
                Vect::new(0.0, 0.0, 0.0, 0),
                Vect::new(0.0, 0.0, 0.0, 0),
                Vect::new(0.0, 0.0, 0.0, 0)
            )
        ));
        f[i] = fac.len() - 1;
    }

    fac[f[0]].p = Plane::new(s[0], s[2], s[1]);  // Bottom face
    fac[f[1]].p = Plane::new(s[0], s[1], s[3]);
    fac[f[2]].p = Plane::new(s[1], s[2], s[3]);
    fac[f[3]].p = Plane::new(s[2], s[0], s[3]);

    fac[f[0]].set_neighbors(f[3], f[2], f[1]);
    fac[f[1]].set_neighbors(f[0], f[2], f[3]);
    fac[f[2]].set_neighbors(f[0], f[3], f[1]);
    fac[f[3]].set_neighbors(f[0], f[1], f[2]);

    // Assign point set space
    for _ in 0..5 {
        pts.push(Vec::new());
    }

    // Assign points to four faces
    for i in 1..=totp {
        if point[i].eq(&s[0]) || point[i].eq(&s[1]) || point[i].eq(&s[2]) || point[i].eq(&s[3]) {
            continue;
        }
        for j in 0..4 {
            if isabove(&point[i], &fac[f[j]].p) {
                pts[f[j]].push(point[i]);
                break;
            }
        }
    }

    // Return the initial simplex, using a face as index
    (ConvexHulls3d::new(f[0]), fac, pts)
}

fn quick_hull_3d(point: &[Vect], totp: usize) -> (ConvexHulls3d, Vec<Facet>) {
    let (mut hull, mut fac, mut pts) = get_start(point, totp);
    
    // Add the face of initial simplex to queue
    let mut que = Vec::new();
    que.push(hull.index);
    for i in 0..3 {
        que.push(fac[hull.index].n[i]);
    }
    
    // snew saves index face of the final convex hull
    let mut snew = 0;
    let mut time = 0;
    
    // Border line graph information
    let mut e1 = vec![Edge::new(); MAXN];
    let mut e2 = vec![Edge::new(); MAXN];
    
    // Timestamp of each point access
    let mut vistime = vec![0; MAXN];
    
    while !que.is_empty() {
        let nf = que.remove(0);
        
        // Skip if the current face has been deleted
        if fac[nf].isdel {
            continue;
        }
        
        // Skip if no vertices are allocated to the current face
        if pts[nf].is_empty() {
            snew = nf;
            continue;
        }

        // Find the farthest point from the face
        let mut p = pts[nf][0];
        for i in 1..pts[nf].len() {
            if gtr(
                dist_point_plane(&pts[nf][i], &fac[nf].p),
                dist_point_plane(&p, &fac[nf].p)
            ) {
                p = pts[nf][i];
            }
        }

        // Find the horizon
        time += 1;
        let mut resfdel = Vec::new();
        
        // The current face must be deleted, so start dfs from current face
        let s = hull.get_horizon(
            nf,
            p,
            &mut vistime,
            &mut e1,
            &mut e2,
            &mut resfdel,
            &mut fac,
            time,
        );

        // Iterate over horizon(go around a circle), construct new face
        let mut resfnew = Vec::new();
        time += 1;
        let mut from = 0;  // The previous visited point
        let mut lastf = 0;  // The last created face
        let mut fstf = 0;  // The first created face
        let mut s = s as usize;
        
        while vistime[s] != time {
            // Record whether the current point has been visited with timestamp
            vistime[s] = time;
            let  net ;  // Next point
            let  f ;  // The unseen face connected to the current edge on horizon
            let fnew;  // New face

            // Make sure the traversal direction is correct
            if e1[s].netid == from {
                net = e2[s].netid;
                f = e2[s].facetid;
            } else {
                net = e1[s].netid;
                f = e1[s].facetid;
            }

            // Find the counterclockwise information of these two points on the adjacent face
            let mut pt1 = -1;
            let mut pt2 = -1;
            for i in 0..3 {
                if point[s].eq(&fac[f].p.vec[i]) {
                    pt1 = i as isize;
                }
                if point[net].eq(&fac[f].p.vec[i]) {
                    pt2 = i as isize;
                }
            }

            // Make sure pt1->pt2 is arranged counterclockwise by adjacent face points
            if (pt1 + 1) % 3 != pt2 {
                let temp = pt1;
                pt1 = pt2;
                pt2 = temp;
            }

            // The face constructed in this way faces outward
            fac.push(Facet::new(
                fac.len(),
                Plane::new(
                    fac[f].p.vec[pt2 as usize],
                    fac[f].p.vec[pt1 as usize],
                    p
                ),
            ));
            
            fnew = fac.len() - 1;
            pts.push(Vec::new());
            resfnew.push(fnew);

            // Maintain adjacency information
            fac[fnew].n[0] = f;
            fac[f].n[pt1 as usize] = fnew;
            
            if lastf != 0 {
                // Can't determine whether to traverse clockwise or counterclockwise in advance
                // Maintain adjacency information between new faces
                if fac[fnew].p.vec[1].eq(&fac[lastf].p.vec[0]) {
                    fac[fnew].n[1] = lastf;
                    fac[lastf].n[2] = fnew;
                } else {
                    fac[fnew].n[2] = lastf;
                    fac[lastf].n[1] = fnew;
                }
            } else {
                fstf = fnew;  // No new face yet
            }
            
            lastf = fnew;
            from = s;
            s = net;
        }

        // Give the new face head and tail maintenance critical information
        if fac[fstf].p.vec[1].eq(&fac[lastf].p.vec[0]) {
            fac[fstf].n[1] = lastf;
            fac[lastf].n[2] = fstf;
        } else {
            fac[fstf].n[2] = lastf;
            fac[lastf].n[1] = fstf;
        }

        // Get all the points to be assigned
        let mut respt = Vec::new();
        for i in 0..resfdel.len() {
            for j in 0..pts[resfdel[i]].len() {
                respt.push(pts[resfdel[i]][j]);
            }
            pts[resfdel[i]].clear();
        }

        // Assign points
        for i in 0..respt.len() {
            if respt[i].eq(&p) {
                continue;  // Skip the points used to create the new face
            }
            for j in 0..resfnew.len() {
                if isabove(&respt[i], &fac[resfnew[j]].p) {
                    pts[resfnew[j]].push(respt[i]);
                    break;  // Make sure the points are not reassigned
                }
            }
        }

        // Add the new face to queue
        for i in 0..resfnew.len() {
            que.push(resfnew[i]);
        }
    }
    
    hull.index = snew;
    (hull, fac)
}

fn main() {
    let n = 4; // number of points
    let mut point = vec![Vect::new(0.0, 0.0, 0.0, 0)]; // 0th element is a placeholder
    
    let my_input = vec![
        [0.0, 0.0, 0.0],
        [1.0, 0.0, 0.0],
        [0.0, 1.0, 0.0],
        [0.0, 0.0, 1.0]
    ];

    for i in 1..=n {
        let (x, y, z) = (my_input[i-1][0], my_input[i-1][1], my_input[i-1][2]);
        point.push(Vect::new(x, y, z, i));
    }
    
    let (mut hull, mut fac) = quick_hull_3d(&point, n);
    let mut time = 0;
    
    println!("{:.3}", hull.get_surface_area(&mut fac, &mut time));
}
Output:
2.366


You may Attempt This Online!

Works with: Scala version 3
Translation of: Java
import scala.collection.mutable
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.math._
import scala.util.control.Breaks._

object QuickHull3D {
  private val MAXN = 2500
  private val EPS = 1e-8

  // Mutable state (keeping similar structure to original)
  private val facets = ArrayBuffer[Facet]()
  private val pointsPerFacet = ArrayBuffer[ArrayBuffer[Vect]]()
  private var TIME = 0
  private val edges = Array.ofDim[Edge](2, MAXN)
  private val vistime = Array.ofDim[Int](MAXN)
  private val queue = mutable.Queue[Int]()
  private val resfnew = ArrayBuffer[Int]()
  private val resfdel = ArrayBuffer[Int]()
  private val respt = ArrayBuffer[Vect]()

  // Utility functions (moved up so they're available to case classes)
  private def eq(a: Double, b: Double): Boolean = abs(a - b) < EPS
  private def gtr(a: Double, b: Double): Boolean = a - b > EPS
  private def abs(x: Double): Double = if (x < 0) -x else x

  def main(args: Array[String]): Unit = {
    preConvexHulls()

    // Example: unit tetrahedron
    val points = Array(
      null, // index 0 unused
      Vect(0, 0, 0, 1),
      Vect(1, 0, 0, 2),
      Vect(0, 1, 0, 3),
      Vect(0, 0, 1, 4)
    )

    val hull = quickHull3D(points, 4)
    println(f"${hull.getSurfaceArea}%.3f")
  }

  private def preConvexHulls(): Unit = {
    // Reserve index 0
    pointsPerFacet += ArrayBuffer[Vect]() // dummy point list[0]
    facets += Facet() // dummy facet[0]
    
    // Initialize edge array
    for (i <- 0 until 2; j <- 0 until MAXN) {
      edges(i)(j) = Edge()
    }
  }

  case class Vect(x: Double, y: Double, z: Double, id: Int) {
    def -(other: Vect): Vect = Vect(x - other.x, y - other.y, z - other.z, 0)
    
    def cross(other: Vect): Vect = Vect(
      y * other.z - z * other.y,
      z * other.x - x * other.z,
      x * other.y - y * other.x,
      0
    )
    
    def dot(other: Vect): Double = x * other.x + y * other.y + z * other.z
    
    def magnitude: Double = sqrt(x * x + y * y + z * z)
    
    def ~=(other: Vect): Boolean = 
      QuickHull3D.eq(x, other.x) && QuickHull3D.eq(y, other.y) && QuickHull3D.eq(z, other.z)
  }

  case class Line(u: Vect, v: Vect)

  case class Plane(u: Vect = Vect(0, 0, 0, 0), v: Vect = Vect(0, 0, 0, 0), w: Vect = Vect(0, 0, 0, 0)) {
    def normal: Vect = (v - u).cross(w - u)
    
    def vecAt(i: Int): Vect = i match {
      case 0 => u
      case 1 => v
      case _ => w
    }
    
    def vecId(i: Int): Int = vecAt(i).id
  }

  case class Facet(
    var neighbors: Array[Int] = Array(0, 0, 0),
    var id: Int = 0,
    var visitTime: Int = 0,
    var isDeleted: Boolean = false,
    var plane: Plane = Plane()
  )

  case class Edge(var netId: Int = 0, var facetId: Int = 0)

  class ConvexHulls3d(var index: Int) {
    private var surfaceArea: Double = 0.0

    private def dfsArea(f: Int): Unit = {
      val facet = facets(f)
      if (facet.visitTime == TIME) return
      facet.visitTime = TIME
      val nrm = facet.plane.normal
      surfaceArea += nrm.magnitude / 2.0
      facet.neighbors.foreach(dfsArea)
    }

    def getSurfaceArea: Double = {
      if (gtr(surfaceArea, 0.0)) return surfaceArea
      TIME += 1
      dfsArea(index)
      surfaceArea
    }

    def getHorizon(f: Int, p: Vect, resDel: ArrayBuffer[Int]): Int = {
      val facet = facets(f)
      if (!isAbove(p, facet.plane)) return 0
      if (facet.visitTime == TIME) return -1
      
      facet.visitTime = TIME
      facet.isDeleted = true
      resDel += facet.id
      
      var ret = -2
      for (i <- facet.neighbors.indices) {
        val ni = facet.neighbors(i)
        val r = getHorizon(ni, p, resDel)
        if (r == 0) {
          val a = facet.plane.vecId(i)
          val b = facet.plane.vecId((i + 1) % 3)
          for (idx <- 0 until 2) {
            val pt = if (idx == 0) a else b
            val facetId = ni
            if (vistime(pt) != TIME) {
              vistime(pt) = TIME
              edges(0)(pt).netId = if (idx == 0) b else a
              edges(0)(pt).facetId = facetId
            } else {
              edges(1)(pt).netId = if (idx == 0) b else a
              edges(1)(pt).facetId = facetId
            }
          }
          ret = a
        } else if (r != -1 && r != -2) {
          ret = r
        }
      }
      ret
    }
  }

  private def distPointPlane(v: Vect, p: Plane): Double = {
    val num = (v - p.u).dot(p.normal)
    val den = p.normal.magnitude
    num / den
  }

  private def distPointLine(v: Vect, l: Line): Double = {
    val d = (v - l.u).magnitude
    if (d == 0) return 0
    (l.v - l.u).cross(v - l.u).magnitude / (l.v - l.u).magnitude
  }

  private def distPointPoint(a: Vect, b: Vect): Double = (a - b).magnitude

  private def isAbove(v: Vect, p: Plane): Boolean = 
    gtr((v - p.u).dot(p.normal), 0)

  private def getStart(points: Array[Vect], totalPoints: Int): ConvexHulls3d = {
    // Find extreme points
    val extremes = Array.fill(6)(points(1))
    for (i <- 1 to totalPoints) {
      val v = points(i)
      if (gtr(v.x, extremes(0).x)) extremes(0) = v
      if (gtr(extremes(1).x, v.x)) extremes(1) = v
      if (gtr(v.y, extremes(2).y)) extremes(2) = v
      if (gtr(extremes(3).y, v.y)) extremes(3) = v
      if (gtr(v.z, extremes(4).z)) extremes(4) = v
      if (gtr(extremes(5).z, v.z)) extremes(5) = v
    }

    // Find furthest pair
    var (s0, s1) = (extremes(0), extremes(1))
    for (i <- extremes.indices; j <- i + 1 until extremes.length) {
      val d = distPointPoint(extremes(i), extremes(j))
      if (gtr(d, distPointPoint(s0, s1))) {
        s0 = extremes(i)
        s1 = extremes(j)
      }
    }

    // Find point furthest from line
    val line = Line(s0, s1)
    var s2 = extremes(0)
    for (extreme <- extremes) {
      if (gtr(distPointLine(extreme, line), distPointLine(s2, line))) {
        s2 = extreme
      }
    }

    // Find point furthest from plane
    var s3 = points(1)
    val basePlane = Plane(s0, s1, s2)
    for (i <- 1 to totalPoints) {
      val d1 = abs(distPointPlane(points(i), basePlane))
      val d2 = abs(distPointPlane(s3, basePlane))
      if (gtr(d1, d2)) s3 = points(i)
    }

    if (gtr(0, distPointPlane(s3, basePlane))) {
      val tmp = s1; s1 = s2; s2 = tmp
    }

    // Create 4 initial facets
    val f = Array.ofDim[Int](4)
    for (i <- 0 until 4) {
      val facet = Facet()
      facet.id = facets.length
      facets += facet
      f(i) = facets.length - 1
    }

    facets(f(0)).plane = Plane(s0, s2, s1)
    facets(f(1)).plane = Plane(s0, s1, s3)
    facets(f(2)).plane = Plane(s1, s2, s3)
    facets(f(3)).plane = Plane(s2, s0, s3)

    facets(f(0)).neighbors = Array(f(3), f(2), f(1))
    facets(f(1)).neighbors = Array(f(0), f(2), f(3))
    facets(f(2)).neighbors = Array(f(0), f(3), f(1))
    facets(f(3)).neighbors = Array(f(0), f(1), f(2))

    // Prepare point lists for the 4 facets
    for (_ <- 0 until 4) {
      pointsPerFacet += ArrayBuffer[Vect]()
    }

    // Assign points to facets
    for (i <- 1 to totalPoints) {
      val v = points(i)
      if (!(v ~= s0) && !(v ~= s1) && !(v ~= s2) && !(v ~= s3)) {
        breakable({
        for (j <- 0 until 4) {
          if (isAbove(v, facets(f(j)).plane)) {
            pointsPerFacet(f(j)) += v
            break
          }
        }
        });
      }
    }

    new ConvexHulls3d(f(0))
  }

  def quickHull3D(points: Array[Vect], totalPoints: Int): ConvexHulls3d = {
    val hull = getStart(points, totalPoints)
    queue.clear()
    queue.enqueue(hull.index)
    facets(hull.index).neighbors.foreach(queue.enqueue)

    var snew = 0
    while (queue.nonEmpty) {
    breakable({
      val nf = queue.dequeue()
      val facet = facets(nf)
      if (facet.isDeleted || pointsPerFacet(nf).isEmpty) {
        if (!facet.isDeleted) snew = nf
          break//continue
      }

      // Find farthest point from facet plane
      var p = pointsPerFacet(nf).head
      for (v <- pointsPerFacet(nf)) {
        if (gtr(distPointPlane(v, facet.plane), distPointPlane(p, facet.plane))) {
          p = v
        }
      }

      // Find horizon
      TIME += 1
      resfdel.clear()
      val s = hull.getHorizon(nf, p, resfdel)

      // Build new faces
      resfnew.clear()
      TIME += 1
      var from = -1
      var lastf = -1
      var fstf = -1
      var currentS = s

      while (vistime(currentS) != TIME) {
        vistime(currentS) = TIME
        val (net, fidx) = if (edges(0)(currentS).netId == from) {
          (edges(1)(currentS).netId, edges(1)(currentS).facetId)
        } else {
          (edges(0)(currentS).netId, edges(0)(currentS).facetId)
        }

        // Find indices on facet fidx
        val facetFidx = facets(fidx)
        var (pt1, pt2) = (0, 0)
        for (i <- 0 until 3) {
          if (points(currentS) ~= facetFidx.plane.vecAt(i)) pt1 = i
          if (points(net) ~= facetFidx.plane.vecAt(i)) pt2 = i
        }
        if ((pt1 + 1) % 3 != pt2) {
          val tmp = pt1; pt1 = pt2; pt2 = tmp
        }

        // Create new facet
        val newFacet = Facet()
        newFacet.id = facets.length
        newFacet.plane = Plane(
          facetFidx.plane.vecAt(pt2),
          facetFidx.plane.vecAt(pt1),
          p
        )
        facets += newFacet
        pointsPerFacet += ArrayBuffer[Vect]()
        val fnew = facets.length - 1
        resfnew += fnew

        // Link neighborhoods
        newFacet.neighbors(0) = fidx
        facetFidx.neighbors(pt1) = fnew

        if (lastf >= 0) {
          val newPlane = newFacet.plane
          val lastPlane = facets(lastf).plane
          if (newPlane.vecAt(1) ~= lastPlane.u) {
            newFacet.neighbors(1) = lastf
            facets(lastf).neighbors(2) = fnew
          } else {
            newFacet.neighbors(2) = lastf
            facets(lastf).neighbors(1) = fnew
          }
        } else {
          fstf = fnew
        }

        lastf = fnew
        from = currentS
        currentS = net
      }

      // Close the loop
      val firstFacet = facets(fstf)
      val lastFacet = facets(lastf)
      if (firstFacet.plane.vecAt(1) ~= lastFacet.plane.u) {
        firstFacet.neighbors(1) = lastf
        lastFacet.neighbors(2) = fstf
      } else {
        firstFacet.neighbors(2) = lastf
        lastFacet.neighbors(1) = fstf
      }

      // Collect deleted points
      respt.clear()
      for (fid <- resfdel) {
        respt ++= pointsPerFacet(fid)
        pointsPerFacet(fid).clear()
      }

      // Reassign points
      for (v <- respt if v != p) {
        for (fid <- resfnew) {
          if (isAbove(v, facets(fid).plane)) {
            pointsPerFacet(fid) += v
            break
          }
        }
      }

      // Enqueue new faces
      resfnew.foreach(queue.enqueue)
    });
    }

    hull.index = snew
    hull
  }
}
Output:
2.366


Works with: Swift
Translation of: C++
import Foundation

// ------------------------------------------------------------
// MARK: - Constants & helpers
// ------------------------------------------------------------
let MAX_SIZE = 2_500
let EPSILON = 1e-8

@inline(__always) func isGreaterThan(_ a: Double, _ b: Double) -> Bool {
    a - b > EPSILON
}
@inline(__always) func isEqual(_ a: Double, _ b: Double) -> Bool {
    abs(a - b) < EPSILON
}

// ------------------------------------------------------------
// MARK: - Basic geometry
// ------------------------------------------------------------
struct Vector {
    var x: Double
    var y: Double
    var z: Double
    var id: Int            // the original index of the point

    init(_ x: Double = 0, _ y: Double = 0, _ z: Double = 0, _ id: Int = 0) {
        self.x = x; self.y = y; self.z = z; self.id = id
    }

    func subtract(_ other: Vector) -> Vector {
        Vector(x - other.x, y - other.y, z - other.z)
    }
    func vectorProduct(_ other: Vector) -> Vector {
        Vector(
            y * other.z - z * other.y,
            z * other.x - x * other.z,
            x * other.y - y * other.x
        )
    }
    func scalarProduct(_ other: Vector) -> Double {
        x * other.x + y * other.y + z * other.z
    }
    func magnitude() -> Double {
        sqrt(x * x + y * y + z * z)
    }
    func equals(_ other: Vector) -> Bool {
        isEqual(x, other.x) && isEqual(y, other.y) && isEqual(z, other.z)
    }
}

struct Line {
    var u: Vector
    var v: Vector
    init(_ u: Vector, _ v: Vector) {
        self.u = u; self.v = v
    }
}

struct Plane {
    var u: Vector
    var v: Vector
    var w: Vector

    init(_ u: Vector = Vector(),
         _ v: Vector = Vector(),
         _ w: Vector = Vector()) {
        self.u = u; self.v = v; self.w = w
    }

    func normal() -> Vector {
        v.subtract(u).vectorProduct(w.subtract(u))
    }

    func vector(at i: Int) -> Vector {
        switch i {
        case 0: return u
        case 1: return v
        case 2: return w
        default: return Vector()
        }
    }
    func vectorID(at i: Int) -> Int {
        vector(at: i).id
    }
}

// ------------------------------------------------------------
// MARK: - Facet, Edge and global containers
// ------------------------------------------------------------
class Facet {
    var N: [Int]                // neighbour facet indices (always size 3)
    var id: Int
    var visitedTime: Int = 0
    var isDeleted: Bool = false
    var plane: Plane

    init(id: Int) {
        self.id = id
        self.N = [Int](repeating: 0, count: 3)
        self.plane = Plane()
    }

    init(id: Int, plane: Plane) {
        self.id = id
        self.N = [Int](repeating: 0, count: 3)
        self.plane = plane
    }

    init() {
        self.id = 0
        self.N = [Int](repeating: 0, count: 3)
        self.plane = Plane()
    }
}

struct Edge {
    var netID: Int = 0
    var faceID: Int = 0
}

// Global containers (mirroring the C++ version)
var facets: [Facet] = []
var hullPoints: [[Vector]] = []          // points that belong to each facet
var timeStep: Int = 0

var edges: [[Edge]] = Array(
    repeating: Array(repeating: Edge(), count: MAX_SIZE),
    count: 2
)

var visitTime: [Int] = Array(repeating: 0, count: MAX_SIZE)

var queue: [Int] = []
var resFNew: [Int] = []
var resFDel: [Int] = []
var resPt: [Vector] = []

// ------------------------------------------------------------
// MARK: - Distance / side tests
// ------------------------------------------------------------
func distancePointPlane(_ pt: Vector, _ plane: Plane) -> Double {
    let num = pt.subtract(plane.u).scalarProduct(plane.normal())
    let den = plane.normal().magnitude()
    return num / den
}
func distancePointLine(_ pt: Vector, _ line: Line) -> Double {
    let len = pt.subtract(line.u).magnitude()
    if len == 0 { return 0.0 }
    return line.v.subtract(line.u)
        .vectorProduct(pt.subtract(line.u))
        .magnitude() / line.v.subtract(line.u).magnitude()
}
func distancePointPoint(_ a: Vector, _ b: Vector) -> Double {
    a.subtract(b).magnitude()
}
func isAbove(_ point: Vector, _ plane: Plane) -> Bool {
    isGreaterThan(point.subtract(plane.u).scalarProduct(plane.normal()), 0.0)
}

// ------------------------------------------------------------
// MARK: - Convex hull object (the driver)
// ------------------------------------------------------------
final class ConvexHulls3D {
    var index: Int          // the “seed” facet for surface‑area computation
    private var surfaceArea: Double = 0.0

    init(index: Int) {
        self.index = index
    }

    // ----------------------------------------------------------------
    // public: surface area – cached after first computation
    // ----------------------------------------------------------------
    func getSurfaceArea() -> Double {
        if isGreaterThan(surfaceArea, 0.0) { return surfaceArea }

        timeStep += 1
        dfsArea(from: index)
        return surfaceArea
    }

    // ----------------------------------------------------------------
    // private: depth‑first search of the facet adjacency graph
    // ----------------------------------------------------------------
    private func dfsArea(from f: Int) {
        if facets[f].visitedTime == timeStep { return }

        facets[f].visitedTime = timeStep
        let normal = facets[f].plane.normal()
        surfaceArea += normal.magnitude() / 2.0

        for i in 0..<3 { dfsArea(from: facets[f].N[i]) }
    }

    // ----------------------------------------------------------------
    // Horizon discovery – returns the first horizon edge (or 0 / -1 / -2)
    // ----------------------------------------------------------------
    func getHorizon(_ f: Int, _ point: Vector, _ resDel: inout [Int]) -> Int {
        let facet = facets[f]
        if !isAbove(point, facet.plane) { return 0 }
        if facet.visitedTime == timeStep { return -1 }

        facet.visitedTime = timeStep
        facet.isDeleted = true
        resDel.append(facet.id)

        var result = -2

        for i in 0..<3 {
            let neigh = facet.N[i]
            let horizon = getHorizon(neigh, point, &resDel)

            if horizon == 0 {
                // edge (a,b) of facet f opposite vertex i
                let a = facet.plane.vectorID(at: i)
                let b = facet.plane.vectorID(at: (i + 1) % 3)

                for idx in 0..<2 {
                    let pt = (idx == 0) ? a : b
                    let fID = neigh
                    if visitTime[pt] != timeStep {
                        visitTime[pt] = timeStep
                        edges[0][pt].netID = (idx == 0) ? b : a
                        edges[0][pt].faceID = fID
                    } else {
                        edges[1][pt].netID = (idx == 0) ? b : a
                        edges[1][pt].faceID = fID
                    }
                }
                result = a
            } else if horizon != -1 && horizon != -2 {
                result = horizon
            }
        }
        return result
    }
}

// ------------------------------------------------------------
// MARK: - Preparations (allocate structures)
// ------------------------------------------------------------
func prepareConvexHulls() {
    // reserve index 0 – the dummy entry used by the C++ program
    hullPoints.append([])
    facets.append(Facet())

    // initialise edges matrix
    for i in 0..<2 {
        for j in 0..<MAX_SIZE {
            edges[i][j] = Edge()
        }
    }
}

// ------------------------------------------------------------
// MARK: - Build the initial tetrahedron
// ------------------------------------------------------------
func getInitialHull(_ points: [Vector], _ totalPoints: Int) -> ConvexHulls3D {
    // ---- 1. extreme points on each axis -----------------------------------------
    var extremes = Array(repeating: points[1], count: 6)

    for i in 1...totalPoints {
        let p = points[i]
        if isGreaterThan(p.x, extremes[0].x) { extremes[0] = p }
        if isGreaterThan(extremes[1].x, p.x) { extremes[1] = p }
        if isGreaterThan(p.y, extremes[2].y) { extremes[2] = p }
        if isGreaterThan(extremes[3].y, p.y) { extremes[3] = p }
        if isGreaterThan(p.z, extremes[4].z) { extremes[4] = p }
        if isGreaterThan(extremes[5].z, p.z) { extremes[5] = p }
    }

    // ---- 2. farthest pair -------------------------------------------------------
    var extreme0 = extremes[0]
    var extreme1 = extremes[1]

    for i in 0..<6 {
        for j in i+1..<6 {
            let d = distancePointPoint(extremes[i], extremes[j])
            if isGreaterThan(d, distancePointPoint(extreme0, extreme1)) {
                extreme0 = extremes[i]
                extreme1 = extremes[j]
            }
        }
    }

    // ---- 3. farthest from that line ---------------------------------------------
    let line = Line(extreme0, extreme1)
    var extreme2 = extremes[0]
    for i in 0..<6 {
        if isGreaterThan(distancePointLine(extremes[i], line),
                         distancePointLine(extreme2, line)) {
            extreme2 = extremes[i]
        }
    }

    // ---- 4. farthest from the plane formed by the three points ------------------
    var extreme3 = points[1]                // any point that is not a dummy
    let basePlane = Plane(extreme0, extreme1, extreme2)

    for i in 1...totalPoints {
        let d1 = abs(distancePointPlane(points[i], basePlane))
        let d2 = abs(distancePointPlane(extreme3, basePlane))
        if isGreaterThan(d1, d2) { extreme3 = points[i] }
    }

    // Ensure the orientation of the base plane is outward
    if isGreaterThan(0.0, distancePointPlane(extreme3, basePlane)) {
        swap(&extreme1, &extreme2)
    }

    // ---- 5. create the four seed facets -----------------------------------------
    var f = [Int](repeating: 0, count: 4)
    for i in 0..<4 {
        facets.append(Facet(id: facets.count))
        f[i] = facets.count - 1
    }

    facets[f[0]].plane = Plane(extreme0, extreme2, extreme1)
    facets[f[1]].plane = Plane(extreme0, extreme1, extreme3)
    facets[f[2]].plane = Plane(extreme1, extreme2, extreme3)
    facets[f[3]].plane = Plane(extreme2, extreme0, extreme3)

    facets[f[0]].N = [f[3], f[2], f[1]]
    facets[f[1]].N = [f[0], f[2], f[3]]
    facets[f[2]].N = [f[0], f[3], f[1]]
    facets[f[3]].N = [f[0], f[1], f[2]]

    // ---- 6. allocate a hull‑point list for each facet ---------------------------
    for _ in 0..<4 { hullPoints.append([]) }

    // ---- 7. distribute every remaining point to the facet that sees it ---------
    for i in 1...totalPoints {
        let p = points[i]
        if p.equals(extreme0) || p.equals(extreme1) ||
           p.equals(extreme2) || p.equals(extreme3) { continue }

        for j in 0..<4 {
            if isAbove(p, facets[f[j]].plane) {
                hullPoints[f[j]].append(p)
                break
            }
        }
    }

    return ConvexHulls3D(index: f[0])
}

// ------------------------------------------------------------
// MARK: - Main QuickHull driver
// ------------------------------------------------------------
func quickHull3D(_ points: [Vector], _ totalPoints: Int) -> ConvexHulls3D {
    var hull = getInitialHull(points, totalPoints)

    // initialise the processing queue
    queue.removeAll()
    queue.append(hull.index)
    for i in 0..<3 { queue.append(facets[hull.index].N[i]) }

    var newHorizon = 0

    while !queue.isEmpty {
        let nf = queue.removeFirst()
        if facets[nf].isDeleted || hullPoints[nf].isEmpty {
            if !facets[nf].isDeleted { newHorizon = nf }
            continue
        }

        // ----- farthest point of the current facet ------------------------------
        var farthest = hullPoints[nf][0]
        for v in hullPoints[nf] {
            if isGreaterThan(
                distancePointPlane(v, facets[nf].plane),
                distancePointPlane(farthest, facets[nf].plane)) {
                farthest = v
            }
        }

        // ----- horizon -----------------------------------------------------------
        timeStep += 1
        resFDel.removeAll()
        let horizon = hull.getHorizon(nf, farthest, &resFDel)

        // ----- build new facets --------------------------------------------------
        resFNew.removeAll()
        timeStep += 1

        var from = -1
        var lastF = -1
        var firstF = -1
        var curHorizon = horizon

        while visitTime[curHorizon] != timeStep {
            visitTime[curHorizon] = timeStep

            // decide which edge instance (0/1) belongs to the current direction
            let net: Int
            let fID: Int
            if edges[0][curHorizon].netID == from {
                net = edges[1][curHorizon].netID
                fID = edges[1][curHorizon].faceID
            } else {
                net = edges[0][curHorizon].netID
                fID = edges[0][curHorizon].faceID
            }

            // locate the two vertices of facet f that correspond to
            //   - curHorizon   (the “horizon” vertex)
            //   - net          (the neighbour vertex)
            var pt1 = 0
            var pt2 = 0
            for i in 0..<3 {
                if points[curHorizon].equals(facets[fID].plane.vector(at: i)) {
                    pt1 = i
                }
                if points[net].equals(facets[fID].plane.vector(at: i)) {
                    pt2 = i
                }
            }
            // make sure that (pt1,pt2) are ordered clockwise as in the C++ code
            if (pt1 + 1) % 3 != pt2 {
                swap(&pt1, &pt2)
            }

            // create the new facet
            let newPlane = Plane(
                facets[fID].plane.vector(at: pt2),
                facets[fID].plane.vector(at: pt1),
                farthest
            )
            facets.append(Facet(id: facets.count, plane: newPlane))
            let newF = facets.count - 1
            hullPoints.append([])            // allocate its point list
            resFNew.append(newF)

            // link the new facet with the old one
            facets[newF].N[0] = fID
            facets[fID].N[pt1] = newF

            if lastF >= 0 {
                // connect to the previous new facet (closing the fan)
                if facets[newF].plane.vector(at: 1).equals(facets[lastF].plane.u) {
                    facets[newF].N[1] = lastF
                    facets[lastF].N[2] = newF
                } else {
                    facets[newF].N[2] = lastF
                    facets[lastF].N[1] = newF
                }
            } else {
                firstF = newF
            }

            lastF = newF
            from = curHorizon
            curHorizon = net
        }

        // ----- close the fan ----------------------------------------------------
        if facets[firstF].plane.vector(at: 1).equals(facets[lastF].plane.u) {
            facets[firstF].N[1] = lastF
            facets[lastF].N[2] = firstF
        } else {
            facets[firstF].N[2] = lastF
            facets[lastF].N[1] = firstF
        }

        // ----- collect all points that were attached to deleted facets ----------
        resPt.removeAll()
        for fID in resFDel {
            resPt.append(contentsOf: hullPoints[fID])
            hullPoints[fID].removeAll()
        }

        // ----- re‑assign those points to the newly created facets ---------------
        for p in resPt where !p.equals(farthest) {
            for fID in resFNew {
                if isAbove(p, facets[fID].plane) {
                    hullPoints[fID].append(p)
                    break
                }
            }
        }

        // ----- enqueue newly created facets --------------------------------------
        for fID in resFNew { queue.append(fID) }
    }

    hull.index = newHorizon
    return hull
}

// ------------------------------------------------------------
// MARK: - Example / entry point
// ------------------------------------------------------------
func runExample() {
    prepareConvexHulls()

    // Example: a tetrahedron (the same data as the C++ main)
    let n = 4
    var points = [Vector](repeating: Vector(), count: n + 1)   // points[0] unused
    points[1] = Vector(0, 0, 0, 1)
    points[2] = Vector(1, 0, 0, 2)
    points[3] = Vector(0, 1, 0, 3)
    points[4] = Vector(0, 0, 1, 4)

    let hull = quickHull3D(points, n)
    let area = hull.getSurfaceArea()
    print(String(format: "%.3f", area))
}

// ------------------------------------------------------------
// MARK: - Run
// ------------------------------------------------------------
runExample()
Output:
2.366


Works with: Tcl version 8.6
Translation of: C++
#!/usr/bin/env tclsh

# Constants
set MAX_SIZE 2500
set EPSILON 0.00000001

# Global variables
set facets [list]
set hull_points [list]
set time_step 0
set edges [list [list] [list]]
set visit_time [list]
set queue [list]
set resfnew [list]
set resfdel [list]
set respt [list]

# Numerical utilities
proc is_greater_than {a b} {
    global EPSILON
    return [expr {($a - $b) > $EPSILON}]
}

proc is_equal {a b} {
    global EPSILON
    return [expr {abs($a - $b) < $EPSILON}]
}

# Vector class implementation
proc vector_create {x y z id} {
    return [dict create x $x y $y z $z id $id]
}

proc vector_subtract {vec1 vec2} {
    set x1 [dict get $vec1 x]
    set y1 [dict get $vec1 y] 
    set z1 [dict get $vec1 z]
    set x2 [dict get $vec2 x]
    set y2 [dict get $vec2 y]
    set z2 [dict get $vec2 z]
    return [vector_create [expr {$x1 - $x2}] [expr {$y1 - $y2}] [expr {$z1 - $z2}] 0]
}

proc vector_cross_product {vec1 vec2} {
    set x1 [dict get $vec1 x]
    set y1 [dict get $vec1 y]
    set z1 [dict get $vec1 z]
    set x2 [dict get $vec2 x]
    set y2 [dict get $vec2 y]
    set z2 [dict get $vec2 z]
    
    set x [expr {$y1 * $z2 - $z1 * $y2}]
    set y [expr {$z1 * $x2 - $x1 * $z2}]
    set z [expr {$x1 * $y2 - $y1 * $x2}]
    return [vector_create $x $y $z 0]
}

proc vector_dot_product {vec1 vec2} {
    set x1 [dict get $vec1 x]
    set y1 [dict get $vec1 y]
    set z1 [dict get $vec1 z]
    set x2 [dict get $vec2 x]
    set y2 [dict get $vec2 y]
    set z2 [dict get $vec2 z]
    return [expr {$x1 * $x2 + $y1 * $y2 + $z1 * $z2}]
}

proc vector_magnitude {vec} {
    set x [dict get $vec x]
    set y [dict get $vec y]
    set z [dict get $vec z]
    return [expr {sqrt($x * $x + $y * $y + $z * $z)}]
}

proc vector_equals {vec1 vec2} {
    set x1 [dict get $vec1 x]
    set y1 [dict get $vec1 y]
    set z1 [dict get $vec1 z]
    set x2 [dict get $vec2 x]
    set y2 [dict get $vec2 y]
    set z2 [dict get $vec2 z]
    return [expr {[is_equal $x1 $x2] && [is_equal $y1 $y2] && [is_equal $z1 $z2]}]
}

# Line class implementation
proc line_create {u v} {
    return [dict create u $u v $v]
}

# Plane class implementation
proc plane_create {u v w} {
    return [dict create u $u v $v w $w]
}

proc plane_normal {plane} {
    set u [dict get $plane u]
    set v [dict get $plane v]
    set w [dict get $plane w]
    set vec1 [vector_subtract $v $u]
    set vec2 [vector_subtract $w $u]
    return [vector_cross_product $vec1 $vec2]
}

proc plane_vector_at_index {plane i} {
    switch $i {
        0 { return [dict get $plane u] }
        1 { return [dict get $plane v] }
        2 { return [dict get $plane w] }
        default { return [vector_create 0 0 0 0] }
    }
}

proc plane_vector_id {plane i} {
    set vec [plane_vector_at_index $plane $i]
    return [dict get $vec id]
}

# Facet class implementation
proc facet_create {id plane} {
    return [dict create id $id plane $plane N [list] visited_time 0 is_deleted false]
}

# Edge class implementation
proc edge_create {} {
    return [dict create netID 0 faceID 0]
}

# Geometric utilities
proc distance_point_plane {vec plane} {
    set u [dict get $plane u]
    set normal [plane_normal $plane]
    set diff [vector_subtract $vec $u]
    set num [vector_dot_product $diff $normal]
    set den [vector_magnitude $normal]
    return [expr {$num / $den}]
}

proc distance_point_line {vec line} {
    set u [dict get $line u]
    set v [dict get $line v]
    set diff1 [vector_subtract $vec $u]
    set length [vector_magnitude $diff1]
    
    if {$length == 0.0} {
        return 0.0
    }
    
    set diff2 [vector_subtract $v $u]
    set cross [vector_cross_product $diff2 $diff1]
    set cross_mag [vector_magnitude $cross]
    set line_mag [vector_magnitude $diff2]
    return [expr {$cross_mag / $line_mag}]
}

proc distance_point_point {a b} {
    set diff [vector_subtract $a $b]
    return [vector_magnitude $diff]
}

proc is_above {point plane} {
    set u [dict get $plane u]
    set normal [plane_normal $plane]
    set diff [vector_subtract $point $u]
    set dot [vector_dot_product $diff $normal]
    return [is_greater_than $dot 0.0]
}

# ConvexHull3d class implementation
proc convex_hull_create {index} {
    return [dict create index $index surface_area 0.0]
}

proc get_surface_area {hull_ref} {
    upvar $hull_ref hull
    set surface_area [dict get $hull surface_area]
    
    if {[is_greater_than $surface_area 0.0]} {
        return $surface_area
    }
    
    global time_step
    incr time_step
    set index [dict get $hull index]
    set area [dfs_area $index]
    dict set hull surface_area $area
    return $area
}

proc dfs_area {f} {
    global facets time_step
    set facet [lindex $facets $f]
    
    if {[dict get $facet visited_time] == $time_step} {
        return 0.0
    }
    
    dict set facet visited_time $time_step
    lset facets $f $facet
    
    set plane [dict get $facet plane]
    set normal [plane_normal $plane]
    set area [expr {[vector_magnitude $normal] / 2.0}]
    
    set N [dict get $facet N]
    foreach neighbor $N {
        set area [expr {$area + [dfs_area $neighbor]}]
    }
    
    return $area
}

proc get_horizon {f point resDel_ref} {
    upvar $resDel_ref resDel
    global facets time_step
    
    set facet [lindex $facets $f]
    set plane [dict get $facet plane]
    
    if {![is_above $point $plane]} {
        return 0
    }
    
    if {[dict get $facet visited_time] == $time_step} {
        return -1
    }
    
    dict set facet visited_time $time_step
    dict set facet is_deleted true
    lset facets $f $facet
    lappend resDel [dict get $facet id]
    
    set result -2
    set N [dict get $facet N]
    
    for {set i 0} {$i < 3} {incr i} {
        set ni [lindex $N $i]
        set horizon [get_horizon $ni $point resDel]
        
        if {$horizon == 0} {
            set a [plane_vector_id $plane $i]
            set b [plane_vector_id $plane [expr {($i + 1) % 3}]]
            
            # Handle edges
            global edges visit_time
            for {set idx 0} {$idx < 2} {incr idx} {
                set pt [expr {$idx == 0 ? $a : $b}]
                set facet_id $ni
                
                if {[lindex $visit_time $pt] != $time_step} {
                    lset visit_time $pt $time_step
                    set edge [edge_create]
                    dict set edge netID [expr {$idx == 0 ? $b : $a}]
                    dict set edge faceID $facet_id
                    lset edges 0 $pt $edge
                } else {
                    set edge [edge_create]
                    dict set edge netID [expr {$idx == 0 ? $b : $a}]
                    dict set edge faceID $facet_id
                    lset edges 1 $pt $edge
                }
            }
            set result $a
        } elseif {$horizon != -1 && $horizon != -2} {
            set result $horizon
        }
    }
    
    return $result
}

proc prepareConvexHulls {} {
    global hull_points facets edges MAX_SIZE
    
    # Reserve index 0
    lappend hull_points [list]
    lappend facets [facet_create 0 [plane_create [vector_create 0 0 0 0] [vector_create 0 0 0 0] [vector_create 0 0 0 0]]]
    
    # Initialize edge vectors
    for {set i 0} {$i < 2} {incr i} {
        set edge_list [list]
        for {set j 0} {$j < $MAX_SIZE} {incr j} {
            lappend edge_list [edge_create]
        }
        lset edges $i $edge_list
    }
    
    # Initialize visit_time
    global visit_time
    for {set i 0} {$i < $MAX_SIZE} {incr i} {
        lappend visit_time 0
    }
}

proc get_initial_hull {points total_points} {
    global facets hull_points
    
    # Find extreme points
    set extremes [list]
    for {set i 0} {$i < 6} {incr i} {
        lappend extremes [lindex $points 1]
    }
    
    for {set i 1} {$i <= $total_points} {incr i} {
        set point [lindex $points $i]
        set x [dict get $point x]
        set y [dict get $point y]
        set z [dict get $point z]
        
        if {[is_greater_than $x [dict get [lindex $extremes 0] x]]} {
            lset extremes 0 $point
        }
        if {[is_greater_than [dict get [lindex $extremes 1] x] $x]} {
            lset extremes 1 $point
        }
        if {[is_greater_than $y [dict get [lindex $extremes 2] y]]} {
            lset extremes 2 $point
        }
        if {[is_greater_than [dict get [lindex $extremes 3] y] $y]} {
            lset extremes 3 $point
        }
        if {[is_greater_than $z [dict get [lindex $extremes 4] z]]} {
            lset extremes 4 $point
        }
        if {[is_greater_than [dict get [lindex $extremes 5] z] $z]} {
            lset extremes 5 $point
        }
    }
    
    # Find furthest pair
    set extreme0 [lindex $extremes 0]
    set extreme1 [lindex $extremes 1]
    for {set i 0} {$i < 6} {incr i} {
        for {set j [expr {$i + 1}]} {$j < 6} {incr j} {
            set distance [distance_point_point [lindex $extremes $i] [lindex $extremes $j]]
            if {[is_greater_than $distance [distance_point_point $extreme0 $extreme1]]} {
                set extreme0 [lindex $extremes $i]
                set extreme1 [lindex $extremes $j]
            }
        }
    }
    
    # Find furthest from line
    set line [line_create $extreme0 $extreme1]
    set extreme2 [lindex $extremes 0]
    for {set i 0} {$i < 6} {incr i} {
        if {[is_greater_than [distance_point_line [lindex $extremes $i] $line] [distance_point_line $extreme2 $line]]} {
            set extreme2 [lindex $extremes $i]
        }
    }
    
    # Find furthest from plane
    set extreme3 [lindex $points 1]
    set basePlane [plane_create $extreme0 $extreme1 $extreme2]
    for {set i 1} {$i <= $total_points} {incr i} {
        set distance1 [expr {abs([distance_point_plane [lindex $points $i] $basePlane])}]
        set distance2 [expr {abs([distance_point_plane $extreme3 $basePlane])}]
        if {[is_greater_than $distance1 $distance2]} {
            set extreme3 [lindex $points $i]
        }
    }
    
    if {[is_greater_than 0 [distance_point_plane $extreme3 $basePlane]]} {
        set temp $extreme1
        set extreme1 $extreme2
        set extreme2 $temp
    }
    
    # Create 4 initial facets
    set f [list]
    for {set i 0} {$i < 4} {incr i} {
        set facet_id [llength $facets]
        set plane [plane_create $extreme0 $extreme1 $extreme2]
        lappend facets [facet_create $facet_id $plane]
        lappend f $facet_id
    }
    
    # Set up planes
    set f0 [lindex $f 0]
    set f1 [lindex $f 1]
    set f2 [lindex $f 2]
    set f3 [lindex $f 3]
    
    set facet0 [lindex $facets $f0]
    dict set facet0 plane [plane_create $extreme0 $extreme2 $extreme1]
    lset facets $f0 $facet0
    
    set facet1 [lindex $facets $f1]
    dict set facet1 plane [plane_create $extreme0 $extreme1 $extreme3]
    lset facets $f1 $facet1
    
    set facet2 [lindex $facets $f2]
    dict set facet2 plane [plane_create $extreme1 $extreme2 $extreme3]
    lset facets $f2 $facet2
    
    set facet3 [lindex $facets $f3]
    dict set facet3 plane [plane_create $extreme2 $extreme0 $extreme3]
    lset facets $f3 $facet3
    
    # Set neighbors
    set facet0 [lindex $facets $f0]
    dict set facet0 N [list $f3 $f2 $f1]
    lset facets $f0 $facet0
    
    set facet1 [lindex $facets $f1]
    dict set facet1 N [list $f0 $f2 $f3]
    lset facets $f1 $facet1
    
    set facet2 [lindex $facets $f2]
    dict set facet2 N [list $f0 $f3 $f1]
    lset facets $f2 $facet2
    
    set facet3 [lindex $facets $f3]
    dict set facet3 N [list $f0 $f1 $f2]
    lset facets $f3 $facet3
    
    # Prepare hull_points
    for {set i 0} {$i < 4} {incr i} {
        lappend hull_points [list]
    }
    
    # Assign points
    for {set i 1} {$i <= $total_points} {incr i} {
        set point [lindex $points $i]
        if {[vector_equals $point $extreme0] || [vector_equals $point $extreme1] || 
            [vector_equals $point $extreme2] || [vector_equals $point $extreme3]} {
            continue
        }
        
        for {set j 0} {$j < 4} {incr j} {
            set fj [lindex $f $j]
            set facet [lindex $facets $fj]
            set plane [dict get $facet plane]
            if {[is_above $point $plane]} {
                set current_points [lindex $hull_points $fj]
                lappend current_points $point
                lset hull_points $fj $current_points
                break
            }
        }
    }
    
    return [convex_hull_create $f0]
}

proc QuickHull3D {points total_points} {
    global queue facets hull_points time_step resfdel resfnew respt edges visit_time
    
    set hull [get_initial_hull $points $total_points]
    
    # Initialize queue
    set queue [list]
    set hull_index [dict get $hull index]
    lappend queue $hull_index
    
    set facet [lindex $facets $hull_index]
    set N [dict get $facet N]
    foreach neighbor $N {
        lappend queue $neighbor
    }
    
    set new_horizon 0
    
    while {[llength $queue] > 0} {
        set nf [lindex $queue 0]
        set queue [lrange $queue 1 end]
        
        set facet [lindex $facets $nf]
        if {[dict get $facet is_deleted] || [llength [lindex $hull_points $nf]] == 0} {
            if {![dict get $facet is_deleted]} {
                set new_horizon $nf
            }
            continue
        }
        
        # Find farthest point
        set point_list [lindex $hull_points $nf]
        set point [lindex $point_list 0]
        set plane [dict get $facet plane]
        
        foreach vec $point_list {
            if {[is_greater_than [distance_point_plane $vec $plane] [distance_point_plane $point $plane]]} {
                set point $vec
            }
        }
        
        # Find horizon
        incr time_step
        set resfdel [list]
        set horizon [get_horizon $nf $point resfdel]
        
        # Build new faces
        set resfnew [list]
        incr time_step
        set from -1
        set last_f -1
        set first_f -1
        
        while {[lindex $visit_time $horizon] != $time_step} {
            lset visit_time $horizon $time_step
            
            if {[dict get [lindex $edges 0 $horizon] netID] == $from} {
                set net [dict get [lindex $edges 1 $horizon] netID]
                set f [dict get [lindex $edges 1 $horizon] faceID]
            } else {
                set net [dict get [lindex $edges 0 $horizon] netID]
                set f [dict get [lindex $edges 0 $horizon] faceID]
            }
            
            # Create new facet
            set new_f [llength $facets]
            set facet_f [lindex $facets $f]
            set plane_f [dict get $facet_f plane]
            
            # Find indices
            set pt1 0
            set pt2 0
            for {set i 0} {$i < 3} {incr i} {
                set vec_at_i [plane_vector_at_index $plane_f $i]
                if {[vector_equals [lindex $points $horizon] $vec_at_i]} {
                    set pt1 $i
                }
                if {[vector_equals [lindex $points $net] $vec_at_i]} {
                    set pt2 $i
                }
            }
            if {[expr {($pt1 + 1) % 3}] != $pt2} {
                set temp $pt1
                set pt1 $pt2
                set pt2 $temp
            }
            
            set new_plane [plane_create [plane_vector_at_index $plane_f $pt2] [plane_vector_at_index $plane_f $pt1] $point]
            lappend facets [facet_create $new_f $new_plane]
            lappend hull_points [list]
            lappend resfnew $new_f
            
            # Set neighbors
            set new_facet [lindex $facets $new_f]
            set N [dict get $new_facet N]
            lset N 0 $f
            dict set new_facet N $N
            lset facets $new_f $new_facet
            
            set facet_f [lindex $facets $f]
            set N_f [dict get $facet_f N]
            lset N_f $pt1 $new_f
            dict set facet_f N $N_f
            lset facets $f $facet_f
            
            if {$last_f >= 0} {
                # Link with previous new facet
                set new_facet [lindex $facets $new_f]
                set last_facet [lindex $facets $last_f]
                set new_plane [dict get $new_facet plane]
                set last_plane [dict get $last_facet plane]
                
                if {[vector_equals [plane_vector_at_index $new_plane 1] [dict get $last_plane u]]} {
                    set N [dict get $new_facet N]
                    lset N 1 $last_f
                    dict set new_facet N $N
                    lset facets $new_f $new_facet
                    
                    set N [dict get $last_facet N]
                    lset N 2 $new_f
                    dict set last_facet N $N
                    lset facets $last_f $last_facet
                } else {
                    set N [dict get $new_facet N]
                    lset N 2 $last_f
                    dict set new_facet N $N
                    lset facets $new_f $new_facet
                    
                    set N [dict get $last_facet N]
                    lset N 1 $new_f
                    dict set last_facet N $N
                    lset facets $last_f $last_facet
                }
            } else {
                set first_f $new_f
            }
            
            set last_f $new_f
            set from $horizon
            set horizon $net
        }
        
        # Close the loop
        if {$first_f >= 0 && $last_f >= 0} {
            set first_facet [lindex $facets $first_f]
            set last_facet [lindex $facets $last_f]
            set first_plane [dict get $first_facet plane]
            set last_plane [dict get $last_facet plane]
            
            if {[vector_equals [plane_vector_at_index $first_plane 1] [dict get $last_plane u]]} {
                set N [dict get $first_facet N]
                lset N 1 $last_f
                dict set first_facet N $N
                lset facets $first_f $first_facet
                
                set N [dict get $last_facet N]
                lset N 2 $first_f
                dict set last_facet N $N
                lset facets $last_f $last_facet
            } else {
                set N [dict get $first_facet N]
                lset N 2 $last_f
                dict set first_facet N $N
                lset facets $first_f $first_facet
                
                set N [dict get $last_facet N]
                lset N 1 $first_f
                dict set last_facet N $N
                lset facets $last_f $last_facet
            }
        }
        
        # Collect deleted points
        set respt [list]
        foreach f_id $resfdel {
            set deleted_points [lindex $hull_points $f_id]
            set respt [concat $respt $deleted_points]
            lset hull_points $f_id [list]
        }
        
        # Reassign points
        foreach vec $respt {
            if {[vector_equals $vec $point]} {
                continue
            }
            foreach f_id $resfnew {
                set facet [lindex $facets $f_id]
                set plane [dict get $facet plane]
                if {[is_above $vec $plane]} {
                    set current_points [lindex $hull_points $f_id]
                    lappend current_points $vec
                    lset hull_points $f_id $current_points
                    break
                }
            }
        }
        
        # Enqueue new faces
        foreach f_id $resfnew {
            lappend queue $f_id
        }
    }
    
    dict set hull index $new_horizon
    return $hull
}

# Main execution
proc main {} {
    prepareConvexHulls
    
    # Example: a tetrahedron
    set n 4
    set points [list]
    
    # points[0] is placeholder
    lappend points [vector_create 0 0 0 0]
    lappend points [vector_create 0 0 0 1]
    lappend points [vector_create 1 0 0 2]
    lappend points [vector_create 0 1 0 3]
    lappend points [vector_create 0 0 1 4]
    
    set hull [QuickHull3D $points $n]
    set surface_area [get_surface_area hull]
    puts [format "%.3f" $surface_area]
}

# Run the main function
main
Output:
2.366


Translation of: Python
var MAXN = 2500
var EPS  = 1e-8

class Vect {
    construct new(x, y, z, id) {
        _x  = x
        _y  = y
        _z  = z
        _id = id
    }

    static new(x, y, z) { new(x, y, z, 0) }

    x      { _x      }
    x=(v)  { _x = v  }
    y      { _y      }
    y=(v)  { _y = v  }
    z      { _z      }
    z=(v)  { _z = v  }
    id     { _id     }
    id=(v) { _id = v }

    -(other) { Vect.new(_x - other.x, _y - other.y, _z - other.z) }

    /(other) { 
        return Vect.new(_y * other.z - _z * other.y,
                        _z * other.x - _x * other.z,
                        _x * other.y - _y * other.x)
    }

    *(other) { _x * other.x + _y * other.y + _z * other.z }

    m { (this * this).sqrt }

    ==(other) { _x == other.x && _y == other.y && _z == other.z }

    toString { "Vect(%(_x), %(_y), %(_z), %(_id))" }
}

class Line {
    construct new(u, v) {
        _u = u
        _v = v
    }

    u     { _u     }
    u=(x) { _u = x }
    v     { _v     }
    v=(x) { _v = x }
} 

class Plane {
    construct new(u, v, w) {
        _vec = (u && v && w) ? [u, v, w] : [null, null, null]
    }

    static new() { new(null, null, null) }

    normal { (_vec[1] - _vec[0]) / (_vec[2] - _vec[0]) }

    u { _vec[0] }
    v { _vec[1] }
    w { _vec[2] }
}

var Gtr = Fn.new { |a, b| a - b > EPS }

var eq  = Fn.new { |a, b| -EPS < a - b && a - b < EPS }

var abs = Fn.new { |x| Gtr.call(0, x) ? -x : x }

// Signed distance.
var distPointPlane = Fn.new { |v, p| (v - p.u) * p.normal / p.normal.m }

// Unsigned distance
var distPointLine = Fn.new { |v, f|
    if ((v - f.u).m > 0) {
        return ((f.v - f.u) / (v - f.u)).m / (f.v - f.u).m
    }
    return 0
}

var distPointPoint = Fn.new { |u, v| (u - v).m }

var isAbove = Fn.new { |v, p| Gtr.call((v - p.u) * p.normal, 0) }

// Convex Hull Structures

var TIME = 0

class Facet {
    construct new(id, p) {
        // neighbor,corresponds to point (u->v, v->w, w->u)
        _n = [0, 0, 0]
        _id = id
        // access timestamp
        _vistime = 0
        _isdel = false
        _p = p ? p : Plane.new()
    }

    static new() { new(0, null) }

    n       { _n      }
    id      { _id     }
    id =(i) { _id = i }
    p       { _p      }
    p =(v)  { _p  = v }

    vistime     { _vistime     }
    vistime=(v) { _vistime = v }
    isdel       { _isdel       }
    isdel=(v)   { _isdel = v   }

    setN(n1, n2, n3) { _n = [n1, n2, n3] }

    toString { "Facet(id=%(_id), isdel=%(_isdel), vistime=%(_vistime))" }
}

// Edge of the horizon.
class Edge {
    construct new() {
        _netid = 0
        _facetid = 0
    }

    netid       { _netid       }
    netid=(v)   { _netid = v   }
    facetid     { _facetid     }
    facetid=(v) { _facetid = v }
}

// Store all faces.
var FAC = []

class ConvexHulls3d {
    construct new(index) {
        // Index face.
        _index = index
        _surfaceArea = 0
    }

    index     { _index     }
    index=(i) { _index = i }

    dfsArea(nf) {
        // Already visited in current timestamp.
        if (FAC[nf].vistime == TIME) return
        FAC[nf].vistime = TIME
        // Check if plane is intialized.
        if (FAC[nf].p.normal) _surfaceArea = _surfaceArea + FAC[nf].p.normal.m / 2
        for (i in 0..2) dfsArea(FAC[nf].n[i])
    }

    getSurfaceArea() {
        if (Gtr.call(_surfaceArea, 0)) return _surfaceArea
        TIME = TIME + 1
        dfsArea(_index)
        return _surfaceArea
    }

    getHorizon(f, p, vistime, e1, e2, resfdel) {
        if (!isAbove.call(p, FAC[f].p)) return 0
        if (FAC[f].vistime == TIME) return -1
        FAC[f].vistime = TIME
        // Mark the deleted face.
        FAC[f].isdel = true
        resfdel.add(FAC[f].id)
        var ret = -2
        for (i in 0..2) {
            var res = getHorizon(FAC[f].n[i], p, vistime, e1, e2, resfdel)
            if (res == 0) {
                var pt = [FAC[f].p.vec[i].id, FAC[f].p.vec[(i + 1) % 3].id]
                for (j in 0..1) {
                    if (vistime[pt[j]] != TIME) {
                        vistime[pt[j]] = TIME
                        e1[pt[j]].netid = pt[(j + 1) % 2]
                        e1[pt[j]].facetid = FAC[f].n[i]
                    } else {
                        e2[pt[j]].netid = pt[(j + 1) % 2]
                        e2[pt[j]].facetid = FAC[f].n[i]
                    }
                }
                ret = pt[0]
            } else if (res != -1 && res != -2) {
                // The face is enclosed in the middle.
                ret = res
            }
        }
        return ret
    }
}

// Global points.
var pts = []

// Construct initial simplex.
var getStart = Fn.new { |point, totp|
    var pt = [point[1]] * 6
    var s  = [point[1]] * 4

    // Find the maximum point of the coordinate axis.
    var i = 2
    while (i < totp + 1) {
        if (Gtr.call(point[i].x, pt[0].x)) pt[0] = point[i]
        if (Gtr.call(pt[1].x, point[i].x)) pt[1] = point[i]
        if (Gtr.call(point[i].y, pt[2].y)) pt[2] = point[i]
        if (Gtr.call(pt[3].y, point[i].y)) pt[3] = point[i]
        if (Gtr.call(point[i].z, pt[4].z)) pt[4] = point[i]
        if (Gtr.call(pt[5].z, point[i].z)) pt[5] = point[i]
        i = i + 1
    }

    // Take the two points with the largest distance.
    for (i in 0..5) {
        var j = i + 1
        while (j < 6) {
            if (Gtr.call(distPointPoint.call(pt[i], pt[j]), distPointPoint.call(s[0], s[1]))) {
                s[0] = pt[i]
                s[1] = pt[j]
            }
            j = j + 1
        }
    }

    // Take the point farthest from the line connecting the two points.
    for (i in 0..5) {
        if (Gtr.call(distPointLine.call(pt[i], Line.new(s[0], s[1])),
                     distPointLine.call(s[2], Line.new(s[0], s[1])))) {
            s[2] = pt[i]
        }
    }

    // Take the point farthest from the face.
    for (i in 1...totp + 1){
        if (Gtr.call(abs.call(distPointPlane.call(point[i], Plane.new(s[0], s[1], s[2]))),
                     abs.call(distPointPlane.call(s[3], Plane.new(s[0], s[1], s[2]))))) {
            s[3] = point[i]
        }
    }

    // Ensure that the constructed face faces outwards.
    if (Gtr.call(0, distPointPlane.call(s[3], Plane.new(s[0], s[1], s[2])))) {
        s.swap(1, 2)
    }

    // Construct simplex
    var f = List.filled(4, 0)
    for (i in 0..3) {
        FAC.add(Facet.new(FAC.count, null))
        f[i] = FAC.count - 1
    }

    FAC[f[0]].p = Plane.new(s[0], s[2], s[1])  // Bottom face
    FAC[f[1]].p = Plane.new(s[0], s[1], s[3])
    FAC[f[2]].p = Plane.new(s[1], s[2], s[3])
    FAC[f[3]].p = Plane.new(s[2], s[0], s[3])

    FAC[f[0]].setN(f[3], f[2], f[1])
    FAC[f[1]].setN(f[0], f[2], f[3])
    FAC[f[2]].setN(f[0], f[3], f[1])
    FAC[f[3]].setN(f[0], f[1], f[2])

    // Assign point set space to four faces.
    for (i in 0..3) pts.add([])

    // Assign points to four faces.
    for (i in 1...totp + 1) {
        if (point[i] == s[0] || point[i] == s[1] || point[i] == s[2] || point[i] == s[3]) {
            continue
        }
        for (j in 0..3) {
            if (isAbove.call(point[i], FAC[f[j]].p)) {
                pts[f[j]].add(point[i])
                break
            }
        }
    }

    // Return the initial simplex, using a face as index.
    return ConvexHulls3d.new(f[0])
}

// Border line graph information.
var e = List.filled(2, null)
for (i in 0..1) {
    e[i] = List.filled(MAXN, null)
    for (j in 0...MAXN) e[i][j] = Edge.new()
}

// Timestamp of each point access.
var vistime = List.filled(MAXN, 0)
var que = []

// Save the newly constructed face.
var resfnew = []

// Save the deleted face
var resfdel = []

// Save the point to be allocated
var respt = []

var quickHull3d = Fn.new { |point, totp|
    var hull = getStart.call(point, totp)
    // Add the face of initial simplex to queue.
    var que = [hull.index]
    for (i in 0..2) que.add(FAC[hull.index].n[i])
    // snew saves index face of the final convex hull.
    var snew = 0

    while (!que.isEmpty) {

        var nf = que.removeAt(0)
        // Skip if the current face has been deleted.
        if (FAC[nf].isdel) continue
        // Skip if no vertices are allocated to the current face.
        if (pts[nf].isEmpty) {
            snew = nf
            continue
        }
        // Find the farthest point from the face.
        var p = pts[nf][0]
        for (i in 1...pts[nf].count) {
            if (Gtr.call(distPointPlane.call(pts[nf][i], FAC[nf].p), distPointPlane.call(p, FAC[nf].p))) {
                p = pts[nf][i]
            }
        }

        // Find the horizon
        TIME = TIME + 1
        resfdel = []
        // The current face must be deleted, so start dfs from current face
        var s = hull.getHorizon(nf, p, vistime, e[0], e[1], resfdel)

        // Iterate over horizon(go around a circle), construct new face.
        // When finding horizon, we can't know whether an edge is clockwise
        // or counterclockwise, so it needs to be judged here.
        resfnew = []
        TIME = TIME + 1
        var from  = 0  // the previous visited point
        var lastf = 0  // the last created face
        var fstf  = 0  // the first created face

        while (vistime[s] != TIME) {
            // Record whether the current point has been visited with timestamp.
            vistime[s] = TIME
            var net  = 0  // next point
            var f    = 0  // the unseen face connected to the current edge on horizon
            var fnew = 0  // new face

            // Make sure the traversal direction is correct.
            if (e[0][s].netid == from) {
                net = e[1][s].netid
                f   = e[1][s].facetid
            } else {
                net = e[0][s].netid
                f   = e[0][s].facetid
            }

            // Find the counterclockwise information of these two points on the adjacent face.
            var pt1 = -1
            var pt2 = -1
            for (i in 0..2) {
                if (point[s] == FAC[f].p.vec[i])   pt1 = i
                if (point[net] == FAC[f].p.vec[i]) pt2 = i
            }

            // Make sure pt1->pt2 is arranged counterclockwise by adjacent face points.
            if ((pt1 + 1) % 3 != pt2) {
                var t = pt1
                pt1 = pt2
                pt2 = t
            }

            // The face constructed in this way faces outward
            FAC.add(Facet.new(FAC.count, Plane.new(FAC[f].p.vec[pt2], FAC[f].p.vec[pt1], p)))
            fnew = FAC.count - 1
            pts.add([])
            resfnew.add(fnew)

            // Maintain adjacency information.
            FAC[fnew].n[0] = f
            FAC[f].n[pt1] = fnew
            if (lastf != 0) {
                // Can't determine whether to traverse clockwise or counterclockwise in advance.
                // Maintain adjacency information between new faces.
                if (FAC[fnew].p.vec[1] == FAC[lastf].p.vec[0]) {
                    FAC[fnew].n[1]  = lastf
                    FAC[lastf].n[2] = fnew
                } else {
                    FAC[fnew].n[2]  = lastf
                    FAC[lastf].n[1] = fnew
                }
            } else {
                fstf = fnew  // no new face yet
            }
            lastf = fnew
            from = s
            s = net
        }

        // Give the new face head and tail maintenance critical information.
        if (FAC[fstf].p.vec[1] == FAC[lastf].p.vec[0]) {
            FAC[fstf].n[1]  = lastf
            FAC[lastf].n[2] = fstf
        } else {
            FAC[fstf].n[2]  = lastf
            FAC[lastf].n[1] = fstf
        }

        // Get all the points to be assigned.
        respt = []
        for (i in 0...resfdel.count) {
            for (j in 0...pts[resfdel[i]].count) respt.add(pts[resfdel[i]][j])
            pts[resfdel[i]] = []
        }

        // Assign points.
        for (i in 0...respt.count) {
            if (respt[i] == p) continue  // skip the points used to create the new face
            for (j in 0...resfnew.count) {
                if (isAbove.call(respt[i], FAC[resfnew[j]].p)) {
                    pts[resfnew[j]].add(respt[i])
                    break  // make sure the points are not reassigned
                }
            }
        }

        // Add the new face to queue.
        for (i in 0...resfnew.count) que.add(resfnew[i])
    }
    hull.index = snew
    return hull
}

var preConvexHulls = Fn.new {
    // 0 for reservation
    pts.add([])
    FAC.add(Facet.new())
}

preConvexHulls.call()
var n = 4  // number of points
var point = List.filled(n + 1, null)  // 1-indexed to match original code
var myInput = [ [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1] ]

for (i in 1..n) {
    var x = myInput[i-1][0]
    var y = myInput[i-1][1]
    var z = myInput[i-1][2]
    point[i] = Vect.new(x, y, z, i)
}
var hull = quickHull3d.call(point, n)
var sa = hull.getSurfaceArea()
System.print((sa * 1000).round / 1000)
Output:
2.366



Works with: Zig version 0.14.1
Translation of: Rust
const std = @import("std");
const print = std.debug.print;
const ArrayList = std.ArrayList;
const Allocator = std.mem.Allocator;
const math = std.math;

const MAXN: usize = 2500;
const EPS: f64 = 1e-8;

const Vect = struct {
    x: f64,
    y: f64,
    z: f64,
    id: usize,

    fn init(x: f64, y: f64, z: f64, id: usize) Vect {
        return Vect{ .x = x, .y = y, .z = z, .id = id };
    }

    fn sub(self: Vect, other: Vect) Vect {
        return Vect.init(self.x - other.x, self.y - other.y, self.z - other.z, 0);
    }

    fn cross(self: Vect, other: Vect) Vect {
        return Vect.init(
            self.y * other.z - self.z * other.y,
            self.z * other.x - self.x * other.z,
            self.x * other.y - self.y * other.x,
            0,
        );
    }

    fn dot(self: Vect, other: Vect) f64 {
        return self.x * other.x + self.y * other.y + self.z * other.z;
    }

    fn magnitude(self: Vect) f64 {
        return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
    }

    fn eq(self: Vect, other: Vect) bool {
        return floatEq(self.x, other.x) and floatEq(self.y, other.y) and floatEq(self.z, other.z);
    }
};

const Line = struct {
    u: Vect,
    v: Vect,

    fn init(u: Vect, v: Vect) Line {
        return Line{ .u = u, .v = v };
    }
};

const Plane = struct {
    vec: [3]Vect,

    fn init(my_u: Vect, my_v: Vect, my_w: Vect) Plane {
        return Plane{ .vec = [3]Vect{ my_u, my_v, my_w } };
    }

    fn normal(self: Plane) Vect {
        return self.vec[1].sub(self.vec[0]).cross(self.vec[2].sub(self.vec[0]));
    }

    fn u(self: Plane) Vect {
        return self.vec[0];
    }
};

fn gtr(a: f64, b: f64) bool {
    return a - b > EPS;
}

fn floatEq(a: f64, b: f64) bool {
    return -EPS < a - b and a - b < EPS;
}

fn absFloat(x: f64) f64 {
    return if (gtr(0.0, x)) -x else x;
}

// Signed distance
fn distPointPlane(v: Vect, p: Plane) f64 {
    const norm = p.normal();
    return v.sub(p.u()).dot(norm) / norm.magnitude();
}

// Unsigned distance
fn distPointLine(v: Vect, f: Line) f64 {
    if (v.sub(f.u).magnitude() > 0.0) {
        return f.v.sub(f.u).cross(v.sub(f.u)).magnitude() / f.v.sub(f.u).magnitude();
    } else {
        return 0.0;
    }
}

fn distPointPoint(u: Vect, v: Vect) f64 {
    return u.sub(v).magnitude();
}

fn isAbove(v: Vect, p: Plane) bool {
    return gtr(v.sub(p.u()).dot(p.normal()), 0.0);
}

const Facet = struct {
    n: [3]usize, // neighbors, correspond to point (u->v, v->w, w->u)
    id: usize,
    vistime: usize, // access timestamp
    isdel: bool,
    p: Plane,

    fn init(id: usize, p: Plane) Facet {
        return Facet{
            .n = [3]usize{ 0, 0, 0 },
            .id = id,
            .vistime = 0,
            .isdel = false,
            .p = p,
        };
    }

    fn setNeighbors(self: *Facet, n1: usize, n2: usize, n3: usize) void {
        self.n = [3]usize{ n1, n2, n3 };
    }
};

const Edge = struct {
    netid: usize,
    facetid: usize,

    fn init() Edge {
        return Edge{ .netid = 0, .facetid = 0 };
    }
};

const ConvexHulls3d = struct {
    index: usize, // Index face
    surfacearea: f64,

    fn init(index: usize) ConvexHulls3d {
        return ConvexHulls3d{
            .index = index,
            .surfacearea = 0.0,
        };
    }

    fn dfsArea(self: *ConvexHulls3d, nf: usize, fac: []Facet, time: *usize) void {
        // Already visited in current timestamp
        if (fac[nf].vistime == time.*) {
            return;
        }

        fac[nf].vistime = time.*;
        self.surfacearea += fac[nf].p.normal().magnitude() / 2.0;

        // Make a copy of neighbors to avoid borrow issues
        const neighbors = fac[nf].n;
        for (neighbors) |neighbor| {
            self.dfsArea(neighbor, fac, time);
        }
    }

    fn getSurfaceArea(self: *ConvexHulls3d, fac: []Facet, time: *usize) f64 {
        if (gtr(self.surfacearea, 0.0)) {
            return self.surfacearea;
        }
        time.* += 1;
        self.dfsArea(self.index, fac, time);
        return self.surfacearea;
    }

    fn getHorizon(
        self: ConvexHulls3d,
        f: usize,
        p: Vect,
        vistime: []usize,
        e1: []Edge,
        e2: []Edge,
        resfdel: *ArrayList(usize),
        fac: []Facet,
        time: usize,
    ) !i32 {
        if (!isAbove(p, fac[f].p)) {
            return 0;
        }

        if (fac[f].vistime == time) {
            return -1;
        }

        fac[f].vistime = time;
        // Mark the deleted face
        fac[f].isdel = true;
        try resfdel.append(fac[f].id);

        var ret: i32 = -2;

        // Make a copy of neighbors to avoid borrow issues
        const neighbors = fac[f].n;
        for (neighbors, 0..) |neighbor, i| {
            const res = try self.getHorizon(
                neighbor,
                p,
                vistime,
                e1,
                e2,
                resfdel,
                fac,
                time,
            );

            if (res == 0) {
                const pt = [2]usize{
                    fac[f].p.vec[i].id,
                    fac[f].p.vec[(i + 1) % 3].id,
                };

                for (pt, 0..) |point_id, j| {
                    if (vistime[point_id] != time) {
                        vistime[point_id] = time;
                        e1[point_id].netid = pt[(j + 1) % 2];
                        e1[point_id].facetid = neighbor;
                    } else {
                        e2[point_id].netid = pt[(j + 1) % 2];
                        e2[point_id].facetid = neighbor;
                    }
                }
                ret = @intCast(pt[0]);
            } else if (res != -1 and res != -2) {
                // The face is enclosed in the middle
                ret = res;
            }
        }

        return ret;
    }
};

// Construct initial simplex
fn getStart(allocator: Allocator, point: []Vect, totp: usize) !struct { ConvexHulls3d, ArrayList(Facet), ArrayList(ArrayList(Vect)) } {
    var fac = ArrayList(Facet).init(allocator);
    var pts = ArrayList(ArrayList(Vect)).init(allocator);

    // Add a dummy facet at index 0
    try fac.append(Facet.init(0, Plane.init(
        Vect.init(0.0, 0.0, 0.0, 0),
        Vect.init(0.0, 0.0, 0.0, 0),
        Vect.init(0.0, 0.0, 0.0, 0),
    )));

    var pt = [_]Vect{point[1]} ** 6;
    var s = [_]Vect{point[1]} ** 4;


    // Find the maximum point of the coordinate axis
    for (2..totp + 1) |i| {
        if (gtr(point[i].x, pt[0].x)) {
            pt[0] = point[i];
        }
        if (gtr(pt[1].x, point[i].x)) {
            pt[1] = point[i];
        }
        if (gtr(point[i].y, pt[2].y)) {
            pt[2] = point[i];
        }
        if (gtr(pt[3].y, point[i].y)) {
            pt[3] = point[i];
        }
        if (gtr(point[i].z, pt[4].z)) {
            pt[4] = point[i];
        }
        if (gtr(pt[5].z, point[i].z)) {
            pt[5] = point[i];
        }
    }

    // Take the two points with the largest distance
    for (0..6) |i| {
        for (i + 1..6) |j| {
            if (gtr(distPointPoint(pt[i], pt[j]), distPointPoint(s[0], s[1]))) {
                s[0] = pt[i];
                s[1] = pt[j];
            }
        }
    }

    // Take the point farthest from the line connecting the two points
    for (0..6) |i| {
        if (gtr(
            distPointLine(pt[i], Line.init(s[0], s[1])),
            distPointLine(s[2], Line.init(s[0], s[1])),
        )) {
            s[2] = pt[i];
        }
    }

    // Take the point farthest from the face
    for (1..totp + 1) |i| {
        if (gtr(
            absFloat(distPointPlane(point[i], Plane.init(s[0], s[1], s[2]))),
            absFloat(distPointPlane(s[3], Plane.init(s[0], s[1], s[2]))),
        )) {
            s[3] = point[i];
        }
    }

    // Ensure that the constructed face faces outwards
    if (gtr(0.0, distPointPlane(s[3], Plane.init(s[0], s[1], s[2])))) {
        // Swap s[1] and s[2]
        const temp = s[1];
        s[1] = s[2];
        s[2] = temp;
    }

    // Construct simplex
    var f = [4]usize{ 0, 0, 0, 0 };
    for (0..4) |i| {
        try fac.append(Facet.init(
            fac.items.len,
            Plane.init(
                Vect.init(0.0, 0.0, 0.0, 0),
                Vect.init(0.0, 0.0, 0.0, 0),
                Vect.init(0.0, 0.0, 0.0, 0),
            ),
        ));
        f[i] = fac.items.len - 1;
    }

    fac.items[f[0]].p = Plane.init(s[0], s[2], s[1]); // Bottom face
    fac.items[f[1]].p = Plane.init(s[0], s[1], s[3]);
    fac.items[f[2]].p = Plane.init(s[1], s[2], s[3]);
    fac.items[f[3]].p = Plane.init(s[2], s[0], s[3]);

    fac.items[f[0]].setNeighbors(f[3], f[2], f[1]);
    fac.items[f[1]].setNeighbors(f[0], f[2], f[3]);
    fac.items[f[2]].setNeighbors(f[0], f[3], f[1]);
    fac.items[f[3]].setNeighbors(f[0], f[1], f[2]);

    // Assign point set space
    for (0..5) |_| {
        try pts.append(ArrayList(Vect).init(allocator));
    }

    // Assign points to four faces
    for (1..totp + 1) |i| {
        if (point[i].eq(s[0]) or point[i].eq(s[1]) or point[i].eq(s[2]) or point[i].eq(s[3])) {
            continue;
        }
        for (0..4) |j| {
            if (isAbove(point[i], fac.items[f[j]].p)) {
                try pts.items[f[j]].append(point[i]);
                break;
            }
        }
    }

    // Return the initial simplex, using a face as index
    return .{ ConvexHulls3d.init(f[0]), fac, pts };
}

fn quickHull3d(allocator: Allocator, point: []Vect, totp: usize) !struct { ConvexHulls3d, ArrayList(Facet) } {
    const result = try getStart(allocator, point, totp);
    var hull = result[0];
    var fac = result[1];
    var pts = result[2];
    defer {
        for (pts.items) |*pt_list| {
            pt_list.deinit();
        }
        pts.deinit();
    }

    // Add the face of initial simplex to queue
    var que = ArrayList(usize).init(allocator);
    defer que.deinit();

    try que.append(hull.index);
    for (fac.items[hull.index].n) |neighbor| {
        try que.append(neighbor);
    }

    // snew saves index face of the final convex hull
    var snew: usize = 0;
    var time: usize = 0;

    // Border line graph information
    var e1 = try allocator.alloc(Edge, MAXN);
    defer allocator.free(e1);
    var e2 = try allocator.alloc(Edge, MAXN);
    defer allocator.free(e2);

    for (0..MAXN) |i| {
        e1[i] = Edge.init();
        e2[i] = Edge.init();
    }

    // Timestamp of each point access
    var vistime = try allocator.alloc(usize, MAXN);
    defer allocator.free(vistime);
    @memset(vistime, 0);

    while (que.items.len > 0) {
        const nf = que.orderedRemove(0);

        // Skip if the current face has been deleted
        if (fac.items[nf].isdel) {
            continue;
        }

        // Skip if no vertices are allocated to the current face
        if (pts.items[nf].items.len == 0) {
            snew = nf;
            continue;
        }

        // Find the farthest point from the face
        var p = pts.items[nf].items[0];
        for (1..pts.items[nf].items.len) |i| {
            if (gtr(
                distPointPlane(pts.items[nf].items[i], fac.items[nf].p),
                distPointPlane(p, fac.items[nf].p),
            )) {
                p = pts.items[nf].items[i];
            }
        }

        // Find the horizon
        time += 1;
        var resfdel = ArrayList(usize).init(allocator);
        defer resfdel.deinit();

        // The current face must be deleted, so start dfs from current face
        const s_result = try hull.getHorizon(
            nf,
            p,
            vistime,
            e1,
            e2,
            &resfdel,
            fac.items,
            time,
        );

        // Iterate over horizon(go around a circle), construct new face
        var resfnew = ArrayList(usize).init(allocator);
        defer resfnew.deinit();

        time += 1;
        var from: usize = 0; // The previous visited point
        var lastf: usize = 0; // The last created face
        var fstf: usize = 0; // The first created face
        var s: usize = @intCast(s_result);

        while (vistime[s] != time) {
            // Record whether the current point has been visited with timestamp
            vistime[s] = time;
            var net: usize = 0; // Next point
            var f: usize = 0; // The unseen face connected to the current edge on horizon
            var fnew: usize = 0; // New face

            // Make sure the traversal direction is correct
            if (e1[s].netid == from) {
                net = e2[s].netid;
                f = e2[s].facetid;
            } else {
                net = e1[s].netid;
                f = e1[s].facetid;
            }

            // Find the counterclockwise information of these two points on the adjacent face
            var pt1: i32 = -1;
            var pt2: i32 = -1;
            for (0..3) |i| {
                if (point[s].eq(fac.items[f].p.vec[i])) {
                    pt1 = @intCast(i);
                }
                if (point[net].eq(fac.items[f].p.vec[i])) {
                    pt2 = @intCast(i);
                }
            }

            // Make sure pt1->pt2 is arranged counterclockwise by adjacent face points
            if ((@rem(pt1 + 1, 3)) != pt2) {
                const temp = pt1;
                pt1 = pt2;
                pt2 = temp;
            }

            // The face constructed in this way faces outward
            try fac.append(Facet.init(
                fac.items.len,
                Plane.init(
                    fac.items[f].p.vec[@intCast(pt2)],
                    fac.items[f].p.vec[@intCast(pt1)],
                    p,
                ),
            ));

            fnew = fac.items.len - 1;
            try pts.append(ArrayList(Vect).init(allocator));
            try resfnew.append(fnew);

            // Maintain adjacency information
            fac.items[fnew].n[0] = f;
            fac.items[f].n[@intCast(pt1)] = fnew;

            if (lastf != 0) {
                // Can't determine whether to traverse clockwise or counterclockwise in advance
                // Maintain adjacency information between new faces
                if (fac.items[fnew].p.vec[1].eq(fac.items[lastf].p.vec[0])) {
                    fac.items[fnew].n[1] = lastf;
                    fac.items[lastf].n[2] = fnew;
                } else {
                    fac.items[fnew].n[2] = lastf;
                    fac.items[lastf].n[1] = fnew;
                }
            } else {
                fstf = fnew; // No new face yet
            }

            lastf = fnew;
            from = s;
            s = net;
        }

        // Give the new face head and tail maintenance critical information
        if (fac.items[fstf].p.vec[1].eq(fac.items[lastf].p.vec[0])) {
            fac.items[fstf].n[1] = lastf;
            fac.items[lastf].n[2] = fstf;
        } else {
            fac.items[fstf].n[2] = lastf;
            fac.items[lastf].n[1] = fstf;
        }

        // Get all the points to be assigned
        var respt = ArrayList(Vect).init(allocator);
        defer respt.deinit();

        for (resfdel.items) |deleted_face| {
            for (pts.items[deleted_face].items) |pt| {
                try respt.append(pt);
            }
            pts.items[deleted_face].clearAndFree();
        }

        // Assign points
        for (respt.items) |pt| {
            if (pt.eq(p)) {
                continue; // Skip the points used to create the new face
            }
            for (resfnew.items) |new_face| {
                if (isAbove(pt, fac.items[new_face].p)) {
                    try pts.items[new_face].append(pt);
                    break; // Make sure the points are not reassigned
                }
            }
        }

        // Add the new face to queue
        for (resfnew.items) |new_face| {
            try que.append(new_face);
        }
    }

    hull.index = snew;
    return .{ hull, fac };
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const n = 4; // number of points
    var point = try allocator.alloc(Vect, n + 1); // 0th element is a placeholder
    defer allocator.free(point);

    point[0] = Vect.init(0.0, 0.0, 0.0, 0); // placeholder

    const my_input = [_][3]f64{
        [_]f64{ 0.0, 0.0, 0.0 },
        [_]f64{ 1.0, 0.0, 0.0 },
        [_]f64{ 0.0, 1.0, 0.0 },
        [_]f64{ 0.0, 0.0, 1.0 },
    };

    for (1..n + 1) |i| {
        const x = my_input[i - 1][0];
        const y = my_input[i - 1][1];
        const z = my_input[i - 1][2];
        point[i] = Vect.init(x, y, z, i);
    }

    const result = try quickHull3d(allocator, point, n);
    var hull = result[0];
    var fac = result[1];
    defer fac.deinit();

    var time: usize = 0;

    print("{d:.3}\n", .{hull.getSurfaceArea(fac.items, &time)});
}
Output:
2.366