Skip to content

TestDirectedConstraints4.kt

src/jvmMain/kotlin/afield/examples/TestDirectedConstraints4.kt · 147 lines

package afield.examples

import afield.simulation.physics.SimdVerlet
import kotlin.math.sqrt

object TestDirectedConstraints4

Simple test to verify DirectedConstraints4 works correctly

object TestDirectedConstraints4 {

fun main(args: Array<String>)

body — 136 lines, from line 11
    @JvmStatic
    fun main(args: Array<String>) {
        println("Testing DirectedConstraints4 implementation...")

        // Create a simple 3x3 grid of particles
        val gridSize = 3
        val spacing = 1f
        val totalParticles = gridSize * gridSize

        val state = SimdVerlet.State3(
            x = FloatArray(0),
            y = FloatArray(0),
            z = FloatArray(0),
            px = FloatArray(0),
            py = FloatArray(0),
            pz = FloatArray(0),
            ax = FloatArray(0),
            ay = FloatArray(0),
            az = FloatArray(0),
            invMass = FloatArray(0)
        )

        val constraints = SimdVerlet.DirectedConstraints4(
            n0 = IntArray(totalParticles) { -1 },
            n1 = IntArray(totalParticles) { -1 },
            n2 = IntArray(totalParticles) { -1 },
            n3 = IntArray(totalParticles) { -1 },
            r0 = FloatArray(totalParticles),
            r1 = FloatArray(totalParticles),
            r2 = FloatArray(totalParticles),
            r3 = FloatArray(totalParticles),
            s0 = FloatArray(totalParticles),
            s1 = FloatArray(totalParticles),
            s2 = FloatArray(totalParticles),
            s3 = FloatArray(totalParticles)
        )

        val sim = SimdVerlet(state, null)

        // Create particles
        val particleIndices = Array(gridSize) { IntArray(gridSize) }
        for (y in 0 until gridSize) {
            for (x in 0 until gridSize) {
                val px = x * spacing
                val py = y * spacing
                val pz = 0f

                val idx = sim.addParticle(
                    x0 = px, y0 = py, z0 = pz,
                    px0 = px, py0 = py, pz0 = pz,
                    invMass0 = if (y == gridSize - 1) 0f else 1f  // Pin top row
                )
                particleIndices[y][x] = idx
            }
        }

        // Set up constraints using all 4 slots
        val stiffness = 0.8f
        var constraintCount = 0
        for (y in 0 until gridSize) {
            for (x in 0 until gridSize) {
                val idx = particleIndices[y][x]
                var slot = 0

                // Right neighbor
                if (x < gridSize - 1) {
                    val rightIdx = particleIndices[y][x + 1]
                    constraints.setSlot(idx, slot++, rightIdx, spacing, stiffness)
                    constraintCount++
                }

                // Bottom neighbor
                if (y > 0) {
                    val bottomIdx = particleIndices[y - 1][x]
                    constraints.setSlot(idx, slot++, bottomIdx, spacing, stiffness)
                    constraintCount++
                }

                // Left neighbor
                if (x > 0) {
                    val leftIdx = particleIndices[y][x - 1]
                    constraints.setSlot(idx, slot++, leftIdx, spacing, stiffness)
                    constraintCount++
                }

                // Top neighbor
                if (y < gridSize - 1) {
                    val topIdx = particleIndices[y + 1][x]
                    constraints.setSlot(idx, slot++, topIdx, spacing, stiffness)
                    constraintCount++
                }
            }
        }

        println("Created ${state.size} particles with $constraintCount constraints")

        // Helper function to calculate distance
        fun dist(i: Int, j: Int): Float {
            val dx = state.x[j] - state.x[i]
            val dy = state.y[j] - state.y[i]
            val dz = state.z[j] - state.z[i]
            return sqrt(dx * dx + dy * dy + dz * dz)
        }

        val dt = 1f / 60f
        val damping = 0.99f
        val gravity = -9.8f

        // Run simulation for a few steps
        println("\nRunning simulation...")
        repeat(10) { step ->
            sim.step(
                dt = dt,
                damping = damping,
                gravity = gravity,
                iterations = 8,
                constraints = constraints
            )

            if (step % 3 == 0) {
                // Check a few distances
                val centerIdx = particleIndices[1][1]
                val rightIdx = particleIndices[1][2]
                val d = dist(centerIdx, rightIdx)

                println("Step $step: Center particle at (${state.x[centerIdx]}, ${state.y[centerIdx]}, ${state.z[centerIdx]})")
                println("  Distance to right neighbor: $d (target: $spacing)")
            }
        }

        println("\n✓ DirectedConstraints4 test passed!")
        println("  - Successfully created particles with 4-slot constraints")
        println("  - Simulation runs without errors")
        println("  - Constraints maintain approximate rest lengths")
    }
}