/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// Unit tests for src/core/SkPoint3.cpp and its header

#include "include/core/SkPoint3.h"
#include "include/core/SkScalar.h"
#include "src/base/SkRandom.h"
#include "tests/Test.h"

#include <array>
#include <cstddef>

static void test_eq_ops(skiatest::Reporter* reporter) {
    const SkPoint3 p0 = SkPoint3::Make(0, 0, 0);
    const SkPoint3 p1 = SkPoint3::Make(1, 1, 1);
    const SkPoint3 p2 = SkPoint3::Make(1, 1, 1);

    REPORTER_ASSERT(reporter, p0 != p1);
    REPORTER_ASSERT(reporter, p1 == p2);
}

static void test_ops(skiatest::Reporter* reporter) {
    SkPoint3 v = SkPoint3::Make(1, 1, 1);
    v.normalize();
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(v.length(), SK_Scalar1));

    // scale
    SkPoint3 p = v.makeScale(3.0f);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.length(), 3.0f));

    p.scale(1.0f/3.0f);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.length(), SK_Scalar1));

    SkPoint3 p1 = SkPoint3::Make(20.0f, 2.0f, 10.0f);
    SkPoint3 p2 = -p1;

    // -
    p = p1 - p1;
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.x(), 0.0f));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.y(), 0.0f));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.z(), 0.0f));

    // +
    p = p1 + p2;
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.x(), 0.0f));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.y(), 0.0f));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.z(), 0.0f));
}

static void test_dot(skiatest::Reporter* reporter) {
    const SkPoint3 xAxis = SkPoint3::Make(1.0f, 0.0f, 0.0f);
    const SkPoint3 yAxis = SkPoint3::Make(0.0f, 1.0f, 0.0f);
    const SkPoint3 zAxis = SkPoint3::Make(0.0f, 0.0f, 1.0f);

    SkScalar dot = xAxis.dot(yAxis);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 0.0f));

    dot = yAxis.dot(zAxis);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 0.0f));

    dot = zAxis.dot(xAxis);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 0.0f));

    SkPoint3 v = SkPoint3::Make(13.0f, 2.0f, 7.0f);
    v.normalize();

    dot = v.dot(v);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 1.0f));

    v = SkPoint3::Make(SK_ScalarRoot2Over2, SK_ScalarRoot2Over2, 0.0f);

    dot = xAxis.dot(v);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, SK_ScalarRoot2Over2));

    dot = yAxis.dot(v);
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, SK_ScalarRoot2Over2));
}

static void test_length(skiatest::Reporter* reporter,
                        SkScalar x, SkScalar y, SkScalar z, SkScalar expectedLen) {
    SkPoint3 point = SkPoint3::Make(x, y, z);

    SkScalar s1 = point.length();
    SkScalar s2 = SkPoint3::Length(x, y, z);

    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, s2));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, expectedLen));
}

static void test_normalize(skiatest::Reporter* reporter,
                           SkScalar x, SkScalar y, SkScalar z, SkScalar expectedLen) {
    SkPoint3 point = SkPoint3::Make(x, y, z);

    bool result = point.normalize();
    SkScalar newLength = point.length();

    if (0 == expectedLen) {
        const SkPoint3 empty = SkPoint3::Make(0.0f, 0.0f, 0.0f);

        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, 0));
        REPORTER_ASSERT(reporter, !result);
        REPORTER_ASSERT(reporter, point == empty);
    } else {
        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, SK_Scalar1));
        REPORTER_ASSERT(reporter, result);
    }
    SkRandom random;
    random.setSeed(1234);
    SkPoint3 pt3;
    int testCount = 100000;
    for (int index = 0; index < testCount; ++index) {
        SkScalar testVal;
        do {
            testVal = random.nextRangeF(0, 2);
        } while (!testVal);
        pt3.set(testVal, 0, 0);
        REPORTER_ASSERT(reporter, !pt3.normalize() || 1 == pt3.fX);
    }
}

DEF_TEST(Point3, reporter) {
    test_eq_ops(reporter);
    test_ops(reporter);
    test_dot(reporter);

    static const struct {
        SkScalar fX;
        SkScalar fY;
        SkScalar fZ;
        SkScalar fLength;
    } gRec[] = {
        { 0.0f, 0.0f, 0.0f, 0.0f },
        { 0.3f, 0.4f, 0.5f, SK_ScalarRoot2Over2 },
        { 1.0e-37f, 1.0e-37f, 1.0e-37f, 0.0f },  // underflows
        { 3.4e38f, 0.0f, 0.0f, 3.4e38f }         // overflows
    };

    for (size_t i = 0; i < std::size(gRec); ++i) {
        test_length(reporter, gRec[i].fX, gRec[i].fY, gRec[i].fZ, gRec[i].fLength);
        test_normalize(reporter, gRec[i].fX, gRec[i].fY, gRec[i].fZ, gRec[i].fLength);
    }
}
