OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain / test / test_simplify.cpp

131 lines · cpp ref:
// Test MCA mesh simplification
// Build: g++ -std=c++17 -O2 -I src test/test_simplify.cpp src/dc_simplify.cpp -o test/test_simplify
// Run: ./test/test_simplify

#include "dc_simplify.h"
#include <cstdio>
#include <cassert>
#include <cmath>

// Create a simple box mesh (12 triangles, 8 vertices)
static DCMeshData make_box(float size = 1.0f) {
    DCMeshData m;
    float s = size * 0.5f;
    // 8 corners
    float verts[][3] = {
        {-s,-s,-s}, { s,-s,-s}, { s, s,-s}, {-s, s,-s},  // front face
        {-s,-s, s}, { s,-s, s}, { s, s, s}, {-s, s, s},  // back face
    };
    for (int i = 0; i < 8; i++) {
        m.positions.push_back(verts[i][0]);
        m.positions.push_back(verts[i][1]);
        m.positions.push_back(verts[i][2]);
        // Simple normals (will be averaged)
        float nx = verts[i][0], ny = verts[i][1], nz = verts[i][2];
        float len = std::sqrt(nx*nx + ny*ny + nz*nz);
        m.normals.push_back(nx/len); m.normals.push_back(ny/len); m.normals.push_back(nz/len);
    }
    // 6 faces x 2 triangles
    int faces[][4] = {
        {0,1,2,3}, {5,4,7,6}, {1,5,6,2}, {4,0,3,7}, {3,2,6,7}, {4,5,1,0}
    };
    for (int f = 0; f < 6; f++) {
        m.indices.push_back(faces[f][0]);
        m.indices.push_back(faces[f][1]);
        m.indices.push_back(faces[f][2]);
        m.indices.push_back(faces[f][0]);
        m.indices.push_back(faces[f][2]);
        m.indices.push_back(faces[f][3]);
    }
    return m;
}

// Create a subdivided plane mesh
static DCMeshData make_plane(int res = 10) {
    DCMeshData m;
    for (int z = 0; z <= res; z++) {
        for (int x = 0; x <= res; x++) {
            float fx = static_cast<float>(x) / res - 0.5f;
            float fz = static_cast<float>(z) / res - 0.5f;
            m.positions.push_back(fx);
            m.positions.push_back(0.0f);
            m.positions.push_back(fz);
            m.normals.push_back(0); m.normals.push_back(1); m.normals.push_back(0);
        }
    }
    for (int z = 0; z < res; z++) {
        for (int x = 0; x < res; x++) {
            int i = z * (res+1) + x;
            m.indices.push_back(i);
            m.indices.push_back(i+1);
            m.indices.push_back(i+res+1);
            m.indices.push_back(i+1);
            m.indices.push_back(i+res+2);
            m.indices.push_back(i+res+1);
        }
    }
    return m;
}

int main() {
    printf("=== MCA Mesh Simplification Tests ===\n\n");

    // Test 1: Box simplification
    {
        DCMeshData box = make_box();
        int orig_tris = static_cast<int>(box.indices.size()) / 3;
        printf("Test 1: Box mesh (%d verts, %d tris)\n",
               static_cast<int>(box.positions.size())/3, orig_tris);

        int collapses = dc_simplify_mca(box, 6);  // target: 6 triangles
        int new_tris = static_cast<int>(box.indices.size()) / 3;
        int new_verts = static_cast<int>(box.positions.size()) / 3;
        printf("  After: %d verts, %d tris (%d collapses)\n", new_verts, new_tris, collapses);
        assert(new_tris <= orig_tris);
        assert(collapses > 0);
        printf("  PASS\n\n");
    }

    // Test 2: Plane simplification (200 tris -> 50)
    {
        DCMeshData plane = make_plane(10);
        int orig_tris = static_cast<int>(plane.indices.size()) / 3;
        int orig_verts = static_cast<int>(plane.positions.size()) / 3;
        printf("Test 2: Plane mesh (%d verts, %d tris)\n", orig_verts, orig_tris);

        int collapses = dc_simplify_mca(plane, 50);
        int new_tris = static_cast<int>(plane.indices.size()) / 3;
        int new_verts = static_cast<int>(plane.positions.size()) / 3;
        printf("  After: %d verts, %d tris (%d collapses)\n", new_verts, new_tris, collapses);
        assert(new_tris <= 50 + 10);  // allow small overshoot due to MCA randomness
        assert(new_tris < orig_tris);
        printf("  PASS\n\n");
    }

    // Test 3: No-op (already below target)
    {
        DCMeshData box = make_box();
        int collapses = dc_simplify_mca(box, 100);  // target > current
        assert(collapses == 0);
        printf("Test 3: No-op when below target: PASS\n\n");
    }

    // Test 4: Large plane (50x50 = 5000 tris -> 500)
    {
        DCMeshData plane = make_plane(50);
        int orig_tris = static_cast<int>(plane.indices.size()) / 3;
        printf("Test 4: Large plane (%d verts, %d tris) -> target 500\n",
               static_cast<int>(plane.positions.size())/3, orig_tris);

        int collapses = dc_simplify_mca(plane, 500);
        int new_tris = static_cast<int>(plane.indices.size()) / 3;
        printf("  After: %d verts, %d tris (%d collapses)\n",
               static_cast<int>(plane.positions.size())/3, new_tris, collapses);
        assert(new_tris < orig_tris);
        printf("  PASS\n\n");
    }

    printf("All tests passed!\n");
    return 0;
}