//package top.r3944realms.lib39;
//
//import org.joml.*;
//import org.joml.Math;
//import org.junit.jupiter.api.*;
//import org.junit.jupiter.params.*;
//import org.junit.jupiter.params.provider.*;
//
//import static org.assertj.core.api.Assertions.*;
//
//public class CoordinateTransformTest {
//    private static final float EPSILON = 0.0001f;
//
//    // ==================== 基础变换测试 ====================
//
//    @Test
//    void testWorldToLocalTransform() {
//        // 创建一个变换：先缩放，再旋转，最后平移
//        Matrix4f transform = new Matrix4f()
//                .translate(10, 5, 0)    // 平移
//                .rotateY((float) Math.PI / 2)  // 绕Y轴旋转90度
//                .scale(2, 1, 1);        // X轴缩放2倍
//
//        // 世界坐标 (0,0,0) 应该变换到 (10,5,0)
//        Vector4f worldPoint = new Vector4f(0, 0, 0, 1);
//        Vector4f localPoint = transform.transform(worldPoint);
//
//        assertThat(localPoint.x()).isCloseTo(10.0f, within(EPSILON));
//        assertThat(localPoint.y()).isCloseTo(5.0f, within(EPSILON));
//        assertThat(localPoint.z()).isCloseTo(0.0f, within(EPSILON));
//    }
//
//    @Test
//    void testLocalToWorldTransform() {
//        // 创建一个变换
//        Matrix4f localToWorld = new Matrix4f()
//                .translate(5, 3, 2)
//                .rotateX((float)Math.PI / 4);
//
//        // 逆变换：世界到局部
//        Matrix4f worldToLocal = new Matrix4f(localToWorld).invert();
//
//        // 测试点
//        Vector4f localPoint = new Vector4f(1, 0, 0, 1);
//
//        // 局部 -> 世界
//        Vector4f worldPoint = localToWorld.transform(localPoint);
//        // 世界 -> 局部
//        Vector4f backToLocal = worldToLocal.transform(worldPoint);
//
//        // 应该能回到原点
//        assertThat(backToLocal.x()).isCloseTo(localPoint.x(), within(EPSILON));
//        assertThat(backToLocal.y()).isCloseTo(localPoint.y(), within(EPSILON));
//        assertThat(backToLocal.z()).isCloseTo(localPoint.z(), within(EPSILON));
//    }
//
//    // ==================== 旋转测试 ====================
//
//    @ParameterizedTest
//    @CsvSource({
//            "0, 1, 0, 0",      // 0度旋转
//            "90, 0, 0, -1",    // 90度旋转
//            "180, -1, 0, 0",   // 180度旋转
//            "270, 0, 0, 1"     // 270度旋转
//    })
//    void testRotationAroundYAxis(float degrees, float expectedX, float expectedY, float expectedZ) {
//        float radians = (float)Math.toRadians(degrees);
//        Matrix4f rotation = new Matrix4f().rotateY(radians);
//
//        // 原始点 (1, 0, 0)
//        Vector4f point = new Vector4f(1, 0, 0, 1);
//        Vector4f rotated = rotation.transform(point);
//
//        assertThat(rotated.x()).isCloseTo(expectedX, within(EPSILON));
//        assertThat(rotated.y()).isCloseTo(expectedY, within(EPSILON));
//        assertThat(rotated.z()).isCloseTo(expectedZ, within(EPSILON));
//    }
//
//    @Test
//    void testRotationComposition() {
//        // 绕X轴旋转90度
//        Matrix4f rotX = new Matrix4f().rotateX((float)Math.PI / 2);
//        // 绕Z轴旋转90度
//        Matrix4f rotZ = new Matrix4f().rotateZ((float)Math.PI / 2);
//
//        // 组合旋转：先X后Z
//        Matrix4f combined = rotZ.mul(rotX);
//
//        // 点 (1, 0, 0)
//        Vector4f point = new Vector4f(1, 0, 0, 1);
//        Vector4f transformed = combined.transform(point);
//
//        // 手动计算验证
//        // (1,0,0) 绕X转90度 -> (1,0,0) 实际上X轴旋转不影响X轴上的点
//        // 再绕Z转90度 -> (0,1,0)
//        assertThat(transformed.x()).isCloseTo(0.0f, within(EPSILON));
//        assertThat(transformed.y()).isCloseTo(1.0f, within(EPSILON));
//        assertThat(transformed.z()).isCloseTo(0.0f, within(EPSILON));
//    }
//
//    // ==================== 缩放测试 ====================
//
//    @Test
//    void testNonUniformScaling() {
//        Matrix4f scale = new Matrix4f().scale(2, 0.5f, 3);
//
//        Vector4f point = new Vector4f(1, 2, 3, 1);
//        Vector4f scaled = scale.transform(point);
//
//        assertThat(scaled.x()).isCloseTo(2.0f, within(EPSILON));   // 1 * 2
//        assertThat(scaled.y()).isCloseTo(1.0f, within(EPSILON));   // 2 * 0.5
//        assertThat(scaled.z()).isCloseTo(9.0f, within(EPSILON));   // 3 * 3
//    }
//
//    // ==================== 平移测试 ====================
//
//    @Test
//    void testTranslation() {
//        Matrix4f translation = new Matrix4f().translate(5, -3, 2.5f);
//
//        Vector4f point = new Vector4f(1, 2, 3, 1);
//        Vector4f translated = translation.transform(point);
//
//        assertThat(translated.x()).isCloseTo(6.0f, within(EPSILON));   // 1 + 5
//        assertThat(translated.y()).isCloseTo(-1.0f, within(EPSILON));  // 2 - 3
//        assertThat(translated.z()).isCloseTo(5.5f, within(EPSILON));   // 3 + 2.5
//    }
//
//    // ==================== 变换顺序测试 ====================
//
//    @Test
//    void testTransformOrderMatters() {
//        Vector4f point = new Vector4f(1, 0, 0, 1);
//
//        // 顺序1：先平移后旋转
//        Matrix4f translateThenRotate = new Matrix4f()
//                .rotateY((float)Math.PI / 2)  // 旋转90度
//                .translate(5, 0, 0);          // 平移
//
//        // 顺序2：先旋转后平移
//        Matrix4f rotateThenTranslate = new Matrix4f()
//                .translate(5, 0, 0)
//                .rotateY((float)Math.PI / 2);
//
//        Vector4f result1 = translateThenRotate.transform(point);
//        Vector4f result2 = rotateThenTranslate.transform(point);
//
//        // 两个结果应该不同
//        assertThat(result1.x()).isNotCloseTo(result2.x(), within(EPSILON));
//        assertThat(result1.z()).isNotCloseTo(result2.z(), within(EPSILON));
//
//        // 验证具体值
//        // 顺序1：点(1,0,0) 先平移->(6,0,0) 再旋转90度->(0,0,-6)
//        assertThat(result1.x()).isCloseTo(0.0f, within(EPSILON));
//        assertThat(result1.z()).isCloseTo(-6.0f, within(EPSILON));
//
//        // 顺序2：点(1,0,0) 先旋转90度->(0,0,-1) 再平移->(5,0,-1)
//        assertThat(result2.x()).isCloseTo(5.0f, within(EPSILON));
//        assertThat(result2.z()).isCloseTo(-1.0f, within(EPSILON));
//    }
//
//    // ==================== 相机视图变换测试 ====================
//
//    @Test
//    void testViewTransform() {
//        // 相机在 (0,0,5)，看向原点 (0,0,0)，上方向为Y轴
//        Matrix4f viewMatrix = new Matrix4f()
//                .lookAt(0, 0, 5,   // 相机位置
//                        0, 0, 0,   // 看向的点
//                        0, 1, 0);  // 上方向
//
//        // 世界坐标的原点 (0,0,0) 在相机空间中应该在 (0,0,-5)
//        Vector4f worldPoint = new Vector4f(0, 0, 0, 1);
//        Vector4f viewPoint = viewMatrix.transform(worldPoint);
//
//        assertThat(viewPoint.x()).isCloseTo(0.0f, within(EPSILON));
//        assertThat(viewPoint.y()).isCloseTo(0.0f, within(EPSILON));
//        assertThat(viewPoint.z()).isCloseTo(-5.0f, within(EPSILON));  // 相机看向-Z方向
//    }
//
//    @Test
//    void testLookAtMatrixProperties() {
//        Vector3f eye = new Vector3f(10, 5, 10);
//        Vector3f center = new Vector3f(0, 0, 0);
//        Vector3f up = new Vector3f(0, 1, 0);
//
//        Matrix4f view = new Matrix4f().lookAt(eye, center, up);
//
//        // 1. 视图矩阵应该是正交矩阵（逆等于转置）
//        Matrix4f invView = new Matrix4f(view).invert();
//        Matrix4f transposeView = new Matrix4f(view).transpose();
//
//        for (int i = 0; i < 4; i++) {
//            for (int j = 0; j < 4; j++) {
//                assertThat(invView.get(i, j)).isCloseTo(transposeView.get(i, j), within(EPSILON));
//            }
//        }
//
//        // 2. 相机位置在视图空间应该是原点
//        Vector4f eyeHomogeneous = new Vector4f(eye, 1);
//        Vector4f eyeInView = view.transform(eyeHomogeneous);
//        assertThat(eyeInView.x()).isCloseTo(0.0f, within(EPSILON));
//        assertThat(eyeInView.y()).isCloseTo(0.0f, within(EPSILON));
//        assertThat(eyeInView.z()).isCloseTo(0.0f, within(EPSILON));
//    }
//
//    // ==================== 投影变换测试 ====================
//
//    @Test
//    void testPerspectiveProjection() {
//        float fov = (float)Math.toRadians(60);
//        float aspect = 16.0f / 9.0f;
//        float near = 0.1f;
//        float far = 100.0f;
//
//        Matrix4f projection = new Matrix4f().perspective(fov, aspect, near, far);
//
//        // 测试近平面上的点 (0,0,-near) 应该映射到 NDC 的 z = -1
//        Vector4f nearPoint = new Vector4f(0, 0, -near, 1);
//        Vector4f projected = projection.transform(nearPoint);
//        projected.div(projected.w);  // 透视除法
//
//        assertThat(projected.z()).isCloseTo(-1.0f, within(EPSILON));
//
//        // 测试远平面上的点 (0,0,-far) 应该映射到 NDC 的 z = 1
//        Vector4f farPoint = new Vector4f(0, 0, -far, 1);
//        projected = projection.transform(farPoint);
//        projected.div(projected.w);
//
//        assertThat(projected.z()).isCloseTo(1.0f, within(EPSILON));
//    }
//
//    @Test
//    void testOrthographicProjection() {
//        float left = -10, right = 10;
//        float bottom = -5, top = 5;
//        float near = 0.1f, far = 100.0f;
//
//        Matrix4f ortho = new Matrix4f().ortho(left, right, bottom, top, near, far);
//
//        // 测试边界映射
//        Vector4f leftBottomNear = new Vector4f(left, bottom, -near, 1);
//        Vector4f projected = ortho.transform(leftBottomNear);
//
//        // 正交投影没有透视除法，直接映射到NDC [-1,1]
//        assertThat(projected.x()).isCloseTo(-1.0f, within(EPSILON));
//        assertThat(projected.y()).isCloseTo(-1.0f, within(EPSILON));
//        assertThat(projected.z()).isCloseTo(-1.0f, within(EPSILON));
//    }
//
//    // ==================== MVP变换链测试 ====================
//
//    @Test
//    void testMVPChain() {
//        // 模型变换
//        Matrix4f model = new Matrix4f()
//                .translate(5, 0, 0)
//                .rotateY((float)Math.PI / 4);
//
//        // 视图变换（相机）
//        Matrix4f view = new Matrix4f()
//                .lookAt(0, 2, 10, 0, 0, 0, 0, 1, 0);
//
//        // 投影变换
//        Matrix4f projection = new Matrix4f()
//                .perspective((float)Math.toRadians(60), 16.0f/9.0f, 0.1f, 100.0f);
//
//        // 完整的MVP矩阵
//        Matrix4f mvp = projection.mul(view.mul(model));
//
//        // 测试局部坐标 (0,0,0)
//        Vector4f localPoint = new Vector4f(0, 0, 0, 1);
//        Vector4f clipPoint = mvp.transform(localPoint);
//
//        // 执行透视除法
//        clipPoint.div(clipPoint.w());
//
//        // 结果应该在NDC范围内 [-1, 1]
//        assertThat(clipPoint.x()).isBetween(-1.0f - EPSILON, 1.0f + EPSILON);
//        assertThat(clipPoint.y()).isBetween(-1.0f - EPSILON, 1.0f + EPSILON);
//        assertThat(clipPoint.z()).isBetween(-1.0f - EPSILON, 1.0f + EPSILON);
//    }
//
//    // ==================== 法线变换测试 ====================
//
//    @Test
//    void testNormalTransformation() {
//        // 创建一个包含非均匀缩放的变换
//        Matrix4f model = new Matrix4f()
//                .scale(2, 1, 1)  // 只在X轴缩放
//                .rotateY((float)Math.PI / 6);
//
//        // 原始法线 (1,0,0)
//        Vector3f normal = new Vector3f(1, 0, 0);
//
//        // 错误的做法：直接使用模型矩阵的3x3部分
//        Matrix3f wrongTransform = new Matrix3f(model);
//        Vector3f wrongResult = wrongTransform.transform(normal);
//
//        // 正确的做法：使用逆转置矩阵
//        Matrix3f normalMatrix = new Matrix3f(model).invert().transpose();
//        Vector3f correctResult = normalMatrix.transform(normal).normalize();
//
//        // 两个结果应该不同（因为缩放不是均匀的）
//        assertThat(wrongResult.x()).isNotCloseTo(correctResult.x(), within(EPSILON));
//        assertThat(wrongResult.y()).isNotCloseTo(correctResult.y(), within(EPSILON));
//        assertThat(wrongResult.z()).isNotCloseTo(correctResult.z(), within(EPSILON));
//
//        // 验证法线变换后仍保持垂直性（简化测试）
//        Vector3f vertex = new Vector3f(1, 0, 0);
//        Vector3f transformedVertex = new Vector3f(vertex).mul(normalMatrix);
//
//        // 法线和顶点变换后的点积应该接近0（垂直）
//        float dot = correctResult.dot(transformedVertex);
//        assertThat(Math.abs(dot)).isCloseTo(0.0f, within(0.1f));
//    }
//
//    // ==================== 四元数旋转测试 ====================
//
//    @Test
//    void testQuaternionRotation() {
//        // 创建绕Y轴旋转90度的四元数
//        Quaternionf quat = new Quaternionf()
//                .rotateY((float)Math.PI / 2);
//
//        // 转换为矩阵
//        Matrix4f matrixFromQuat = new Matrix4f().rotation(quat);
//
//        // 直接创建矩阵
//        Matrix4f matrixDirect = new Matrix4f().rotateY((float)Math.PI / 2);
//
//        // 两个矩阵应该相同
//        for (int i = 0; i < 4; i++) {
//            for (int j = 0; j < 4; j++) {
//                assertThat(matrixFromQuat.get(i, j))
//                        .isCloseTo(matrixDirect.get(i, j), within(EPSILON));
//            }
//        }
//
//        // 测试四元数旋转点
//        Vector3f point = new Vector3f(1, 0, 0);
//        Vector3f rotatedByQuat = quat.transform(point);
//        Vector3f rotatedByMatrix = matrixDirect.transformPosition(point, new Vector3f());
//
//        assertThat(rotatedByQuat.x()).isCloseTo(rotatedByMatrix.x(), within(EPSILON));
//        assertThat(rotatedByQuat.y()).isCloseTo(rotatedByMatrix.y(), within(EPSILON));
//        assertThat(rotatedByQuat.z()).isCloseTo(rotatedByMatrix.z(), within(EPSILON));
//    }
//
//    // ==================== 性能测试 ====================
//
//    @RepeatedTest(3)
//    @DisplayName("变换矩阵性能测试")
//    void testTransformPerformance() {
//        int iterations = 100000;
//        Matrix4f transform = new Matrix4f()
//                .translate(1, 2, 3)
//                .rotateXYZ(0.1f, 0.2f, 0.3f)
//                .scale(1.5f);
//
//        Vector4f point = new Vector4f(1, 2, 3, 1);
//
//        long startTime = System.nanoTime();
//
//        for (int i = 0; i < iterations; i++) {
//            Vector4f result = transform.transform(point);
//            // 确保结果被使用（防止被优化掉）
//            if (Float.isNaN(result.x())) {
//                Assertions.fail("不应该发生");
//            }
//        }
//
//        long endTime = System.nanoTime();
//        long durationMs = (endTime - startTime) / 1_000_000;
//
//        System.out.printf("Transform %d points in %d ms%n", iterations, durationMs);
//        assertThat(durationMs).isLessThan(1000);  // 应该在1秒内完成
//    }
//
//    // ==================== 边缘情况测试 ====================
//
//    @Test
//    void testZeroScaling() {
//        Matrix4f scale = new Matrix4f().scale(0, 1, 1);
//        Vector4f point = new Vector4f(1, 2, 3, 1);
//        Vector4f result = scale.transform(point);
//
//        assertThat(result.x()).isCloseTo(0.0f, within(EPSILON));
//        assertThat(result.y()).isCloseTo(2.0f, within(EPSILON));
//        assertThat(result.z()).isCloseTo(3.0f, within(EPSILON));
//    }
//
//    @Test
//    void testNegativeScaling() {
//        Matrix4f scale = new Matrix4f().scale(-1, 1, 1);
//        Vector4f point = new Vector4f(1, 2, 3, 1);
//        Vector4f result = scale.transform(point);
//
//        assertThat(result.x()).isCloseTo(-1.0f, within(EPSILON));
//        assertThat(result.y()).isCloseTo(2.0f, within(EPSILON));
//        assertThat(result.z()).isCloseTo(3.0f, within(EPSILON));
//    }
//
//    @Test
//    void testIdentityTransform() {
//        Matrix4f identity = new Matrix4f().identity();
//        Vector4f point = new Vector4f(1, 2, 3, 1);
//        Vector4f result = identity.transform(point);
//
//        assertThat(result.x()).isCloseTo(point.x(), within(EPSILON));
//        assertThat(result.y()).isCloseTo(point.y(), within(EPSILON));
//        assertThat(result.z()).isCloseTo(point.z(), within(EPSILON));
//    }
//}
