remesh 0.0.5

Isotropic remeshing library
Documentation
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2025 lacklustr@protonmail.com https://github.com/eadf

use crate::common::macros::integrity_assert_eq;
use crate::corner_table::CornerIndex;
use crate::isotropic_remesh::IsotropicRemeshAlgo;
use std::fmt::Debug;
use vector_traits::num_traits::AsPrimitive;
use vector_traits::prelude::SimdUpgradable;

impl<S, V, const ENABLE_UNSAFE: bool> IsotropicRemeshAlgo<S, V, ENABLE_UNSAFE>
where
    S: crate::common::sealed::ScalarType,
    f64: AsPrimitive<S>,
    V: Debug + Copy + From<[S; 3]> + Into<[S; 3]> + Sync + 'static,
{
    /// Split an edge in a manifold mesh (everything is CCW)
    ///
    /// ```text
    /// Notation: cₓ = corner, Vₓ = vertex, tₓ = triangle
    /// cₓn = cₓ.next, cₓp = cₓ.prev, cₓo = cₓ.opposite
    ///
    /// Input: corner 'c₀' with vertex 'V₀', where edge to split is V₀->V₂
    ///              c₀o
    ///      V₃ ─────────────── V₂        V₃ ─────────────── V₂
    ///      │c₀p         c₀n / │         │ \ c₃p      c₃n / │
    ///      │              /   │         │c₀p\    t₃    /c₂p│
    ///      │     t₀     / c₁  │         │     \      /     │
    ///      │          /       │    =>   │  t₀   \c₃/   t₂  │
    ///  c₀no│        /         │c₁no     │   c₀n  M c₂      │
    ///      │      /           │         │       /  \       │
    ///      │    /      t₁     │         │     /  c₁  \     │
    ///      │c₀/               │         │c₀ /    t₁    \c₂n│
    ///      │/ c₁n         c₁p │         │ / c₁n      c₁p \ │
    ///      V₀ ────────────── V₁         V₀ ────────────── V₁
    ///              c₁o
    ///
    /// A new vertex M is placed at the center of the V₀->V₂ edge.
    /// Triangles:
    /// - Original triangle t₀ (V₀,V₂,V₃) is split into t₀ (V₀,M,V₃) and t₃ (M,V₂,V₃)
    /// - Original triangle t₁ (V₂,V₀,V₁) is split into t₁ (M,V₀,V₁) and t₂ (M,V₁,V₂)
    /// ```
    pub(crate) fn split_manifold_edge(&mut self, c0: CornerIndex) {
        // 1. Extract the structure: c0 points to V0, edge to split is V0->V2
        let v0 = self.corner_table.vertex(c0);
        let (c0n, c0p) = self.corner_table.next_prev(c0);

        let v2 = self.corner_table.vertex(c0n); // c0.next points to V2
        let v3 = self.corner_table.vertex(c0p); // c0.prev points to V3

        // Get opposite corner c1 (must exist in manifold)
        let c1p = self.corner_table.opposite(c0p); // opposite of edge V0->V2
        let (c1, c1n) = self.corner_table.next_prev(c1p);

        let v1 = self.corner_table.vertex(c1p); // c1.prev points to V1

        // Verify the quad structure (V0, V2, V3, V1)
        integrity_assert_eq!(self.corner_table.vertex(c1), v2); // c1 points to V2
        integrity_assert_eq!(self.corner_table.vertex(c1n), v0); // c1.next points to V0

        // 2. Find the opposing corners for the outer edges
        let c0no = self.corner_table.opposite(c0n);
        let c0o = self.corner_table.opposite(c0);
        let c1no = self.corner_table.opposite(c1n);
        let c1o = self.corner_table.opposite(c1);

        #[cfg(feature = "integrity_check")]
        {
            println!("c0:{c0:?} c0n: {c0n:?}, c0p: {c0p:?}");
            self.corner_table.dbg_triangle_context("c0 (t0)", c0);

            println!("c1:{c1:?} c1n: {c1n:?}, c1p: {c1p:?}");
            self.corner_table.dbg_triangle_context("c1 (t1)", c1);

            //println!("v0:{v0} v1:{v1}, v2:{v2} v3:{v3}");
            //println!("c0no:{c0no} c1no:{c1no}");
            //self.corner_table.dbg_triangle_context("c0", c0);
            //self.corner_table.dbg_triangle_context("c1", c1);
        }

        // 3. Create new midpoint vertex M between V0 and V2
        let pos_v0 = self.vertex(v0).to_simd();
        let pos_v2 = self.vertex(v2).to_simd();
        let midpoint = (pos_v0 + pos_v2) * (S::ONE / S::TWO);
        let vm = self.add_vertex(midpoint);

        // 4. Split into 4 triangles:
        // - t0 remains: V0, M, V3 (original corners c0, c0n, c0p)
        // - t1 remains: M, V0, V1 (original corners c1, c1n, c1p)
        // - t3 new: M, V2, V3
        // - t2 new: M, V1, V2

        let (c3, c3n, c3p) = self.corner_table.allocate_triangle(vm, v2, v3);
        let (c2, c2n, c2p) = self.corner_table.allocate_triangle(vm, v1, v2);

        // Update vertices: c0n and c1 now point to M instead of V2
        self.corner_table.link_corner_vertex(c0n, vm); // t0: V0, M, V3
        self.corner_table.link_corner_vertex(c1, vm); // t1: M, V0, V1

        // Set opposite relationships
        self.corner_table.set_dual_opposite(c0n, c0no); // same
        self.corner_table.set_dual_opposite(c1, c1o); // same
        self.corner_table.set_dual_opposite(c2, c1no);
        self.corner_table.set_dual_opposite(c3, c0o);
        self.corner_table.set_dual_opposite(c0, c3n);
        self.corner_table.set_dual_opposite(c3p, c2n);
        self.corner_table.set_dual_opposite(c2p, c1n);

        #[cfg(feature = "integrity_check")]
        {
            self.corner_table.assert_valid_corner(c0);
            self.corner_table.assert_valid_corner(c0n);
            self.corner_table.assert_valid_corner(c0p);
            self.corner_table.assert_valid_corner(c1);
            self.corner_table.assert_valid_corner(c1n);
            self.corner_table.assert_valid_corner(c1p);
            self.corner_table.assert_valid_corner(c3);
            self.corner_table.assert_valid_corner(c3n);
            self.corner_table.assert_valid_corner(c3p);
            self.corner_table.assert_valid_corner(c2);
            self.corner_table.assert_valid_corner(c2n);
            self.corner_table.assert_valid_corner(c2p);

            println!("after split:");
            self.corner_table.dbg_triangle_context("c0 (t0)", c0);
            self.corner_table.dbg_triangle_context("c1 (t1)", c1);
            self.corner_table.dbg_triangle_context("c3 (t3)", c3);
            self.corner_table.dbg_triangle_context("c2 (t2)", c2);
        }
    }
}