Skip to content

linalg_mesh.kt

src/jvmMain/kotlin/afield/geometry/mesh/linalg_mesh.kt · 101 lines

package and imports — 53 lines, from line 1
@file:afield.runtime.completion.CompletionCategory("Math")

package afield.geometry.mesh

import afield.data.collections.get
import afield.data.collections.invoke
import afield.data.collections.s
import afield.data.collections.times
import afield.document.graph.minusAssign
import afield.document.graph.plusAssign
import afield.document.properties.compareTo
import afield.document.workspace.file
import afield.geometry.spatial.Cuboid
import afield.geometry.spatial.aabbBounds
import afield.geometry.spatial.center
import afield.geometry.spatial.convexHullPeelingMedian
import afield.geometry.spatial.medianVec
import afield.geometry.spatial.obbBounds
import afield.graphics.render.rangeTo
import afield.graphics.text.layout
import afield.math.autodiff.compareTo
import afield.math.autodiff.div
import afield.math.autodiff.minus
import afield.math.autodiff.plus
import afield.math.autodiff.times
import afield.math.units.div
import afield.math.units.minus
import afield.math.units.plus
import afield.math.units.times
import afield.media.image.median
import afield.study.ui.numbers

import afield.audio.synth.*
import afield.math.linalg.Vec3
import afield.math.linalg.i
import afield.math.linalg.x
import com.github.quickhull3d.QuickHull3D
import afield.math.linalg.Vector2f
import afield.math.linalg.Vector2fc
import afield.math.linalg.Vector3f
import afield.math.linalg.Vector3fc
import afield.math.linalg.Vector4f
import afield.math.linalg.Vector4fc
import afield.math.linalg.Quaternionf
import afield.math.linalg.Quaternionfc
import afield.math.linalg.Matrix3f
import afield.math.linalg.Matrix3fc
import afield.math.linalg.Matrix4f
import afield.math.linalg.Matrix4fc
import afield.math.linalg.DualQuaternionf
import afield.math.linalg.*
import kotlin.math.max
import kotlin.math.min

The 3D convex hull of a list of Vec3, computed with the QuickHull3D library.

One function, convexHull, which keeps the vertices on the outside of the cloud and drops the interior ones. Vertices only, in the library's own order, with no faces and no winding. Fewer than four points, or a cloud QuickHull cannot triangulate, returns the input unchanged rather than throwing, so a result the same size as the input may be a hull or a refusal and the two cannot be told apart from the return value.

The vector types themselves are in linalg.kt. Centroids, medians and bounding boxes for the same point collections are in linalg_spatial.kt, which also holds convexHullPeelingMedian and the asQuickHullPoints packer.

fun List<Vec3>.convexHull(): List<Vec3>

The vertices of the 3D convex hull, via QuickHull3D — the points on the outside, with the interior ones dropped.

Vertices only, in the library's own order, with no faces or winding; and they are fresh Vec3s, not the receiver's instances. Fewer than four points, or a degenerate cloud QuickHull cannot triangulate (all coplanar, all collinear, duplicates), returns the input unchanged rather than throwing — so a result the same size as the input means "hull, or gave up", and the two are not distinguishable from the return value alone.

fun List<Vec3>.convexHull(): List<Vec3> {
    if (size < 4) return this.toList()  // Need at least 4 non-coplanar points

    val points = DoubleArray(size * 3)
    for (i in indices) {
        points[i * 3] = this[i].x.toDouble()
        points[i * 3 + 1] = this[i].y.toDouble()
        points[i * 3 + 2] = this[i].z.toDouble()
    }

    return try {
        val qh = QuickHull3D()
        qh.build(points)

        val hullVerts = qh.vertices
        hullVerts.map { Vec3(it[0].toFloat(), it[1].toFloat(), it[2].toFloat()) }
    } catch (e: Exception) {
        // If hull computation fails (coplanar points, etc.), return original
        this.toList()
    }
}