usdrt/gf/range.h

File members: usdrt/gf/range.h

// Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once

#include <carb/Defines.h>

#include <usdrt/gf/vec.h>

namespace omni
{
namespace math
{
namespace linalg
{

// specializing range for 1 dimensions to use float and match GfRange1(d|f)
template <typename T>
class range1
{
public:
    static const size_t dimension = 1;
    using MinMaxType = T;
    using ScalarType = T;
    using ThisType = range1<T>;

    // TODO check whether this can be deprecated.
    void inline SetEmpty()
    {
        _min = std::numeric_limits<ScalarType>::max();
        _max = -std::numeric_limits<ScalarType>::max();
    }

    range1()
    {
        SetEmpty();
    }
    constexpr range1(const ThisType&) = default;

    constexpr explicit range1(ScalarType size) : _min(-size), _max(size)
    {
    }

    constexpr range1(ScalarType min, ScalarType max) : _min(min), _max(max)
    {
    }

    ScalarType GetMin() const
    {
        return _min;
    }

    ScalarType GetMax() const
    {
        return _max;
    }

    ScalarType GetSize() const
    {
        return _max - _min;
    }

    ScalarType GetMidpoint() const
    {
        return static_cast<ScalarType>(0.5) * _min + static_cast<ScalarType>(0.5) * _max;
    }

    void SetMin(ScalarType min)
    {
        _min = min;
    }

    void SetMax(ScalarType max)
    {
        _max = max;
    }

    bool IsEmpty() const
    {
        return _min > _max;
    }

    void ExtendBy(ScalarType point)
    {
        UnionWith(point);
    }

    void ExtendBy(const ThisType& range)
    {
        UnionWith(range);
    }

    bool Contains(const ScalarType& point) const
    {
        return (point >= _min && point <= _max);
    }

    bool Contains(const ThisType& range) const
    {
        return Contains(range._min) && Contains(range._max);
    }

    bool IsInside(ScalarType point) const
    {
        return Contains(point);
    }

    bool IsInside(const ThisType& range) const
    {
        return Contains(range);
    }

    bool IsOutside(const ThisType& range) const
    {
        return (range._max < _min || range._min > _max);
    }

    static ThisType GetUnion(const ThisType& a, const ThisType& b)
    {
        auto res = a;
        _FindMin(res._min, b._min);
        _FindMax(res._max, b._max);
        return res;
    }

    const ThisType& UnionWith(const ThisType& b)
    {
        _FindMin(_min, b._min);
        _FindMax(_max, b._max);
        return *this;
    }

    const ThisType& UnionWith(const ScalarType& b)
    {
        _FindMin(_min, b);
        _FindMax(_max, b);
        return *this;
    }

    static ThisType Union(const ThisType& a, const ThisType& b)
    {
        return GetUnion(a, b);
    }

    const ThisType& Union(const ThisType& b)
    {
        return UnionWith(b);
    }

    const ThisType& Union(ScalarType b)
    {
        return UnionWith(b);
    }

    static ThisType GetIntersection(const ThisType& a, const ThisType& b)
    {
        auto res = a;
        _FindMax(res._min, b._min);
        _FindMin(res._max, b._max);
        return res;
    }

    static ThisType Intersection(const ThisType& a, const ThisType& b)
    {
        return GetIntersection(a, b);
    }

    const ThisType& IntersectWith(const ThisType& b)
    {
        _FindMax(_min, b._min);
        _FindMin(_max, b._max);
        return *this;
    }

    const ThisType& Intersection(const ThisType& b)
    {
        return IntersectWith(b);
    }

    ThisType operator+=(const ThisType& b)
    {
        _min += b._min;
        _max += b._max;
        return *this;
    }

    ThisType operator-=(const ThisType& b)
    {
        _min -= b._max;
        _max -= b._min;
        return *this;
    }

    ThisType operator*=(double m)
    {
        if (m > 0)
        {
            _min *= m;
            _max *= m;
        }
        else
        {
            float tmp = _min;
            _min = _max * m;
            _max = tmp * m;
        }
        return *this;
    }

    ThisType operator/=(double m)
    {
        return *this *= (1.0 / m);
    }

    ThisType operator+(const ThisType& b) const
    {
        return ThisType(_min + b._min, _max + b._max);
    }

    ThisType operator-(const ThisType& b) const
    {
        return ThisType(_min - b._max, _max - b._min);
    }

    friend ThisType operator*(double m, const ThisType& r)
    {
        return (m > 0 ? ThisType(r._min * m, r._max * m) : ThisType(r._max * m, r._min * m));
    }

    friend ThisType operator*(const ThisType& r, double m)
    {
        return (m > 0 ? ThisType(r._min * m, r._max * m) : ThisType(r._max * m, r._min * m));
    }

    friend ThisType operator/(const ThisType& r, double m)
    {
        return r * (1.0 / m);
    }

    inline bool operator==(const ThisType& other) const
    {
        return _min == static_cast<ScalarType>(other.GetMin()) && _max == static_cast<ScalarType>(other.GetMax());
    }
    inline bool operator!=(const ThisType& other) const
    {
        return !(*this == other);
    }

    double GetDistanceSquared(ScalarType p) const
    {
        double dist = 0.0;

        if (p < _min)
        {
            // p is left of box
            dist += GfSqr(_min - p);
        }
        else if (p > _max)
        {
            // p is right of box
            dist += GfSqr(p - _max);
        }

        return dist;
    }

private:
    ScalarType _min, _max;

    static void _FindMin(ScalarType& dest, ScalarType point)
    {
        if (point < dest)
        {
            dest = point;
        }
    }

    static void _FindMax(ScalarType& dest, ScalarType point)
    {
        if (point > dest)
        {
            dest = point;
        }
    }
};

template <typename T>
class range2
{
public:
    static const size_t dimension = 2;
    using ScalarType = T;
    using MinMaxType = omni::math::linalg::vec2<T>;
    using ThisType = range2<T>;

    range2()
    {
        SetEmpty();
    }
    constexpr range2(const ThisType&) = default;

    constexpr explicit range2(ScalarType size) : _min(-size), _max(size)
    {
    }

    // TODO check whether this can be deprecated.
    constexpr void inline SetEmpty()
    {
        _min = MinMaxType(std::numeric_limits<ScalarType>::max());
        _max = MinMaxType(-std::numeric_limits<ScalarType>::max());
    }

    constexpr range2(const MinMaxType& min, const MinMaxType& max) : _min(min), _max(max)
    {
    }

    const MinMaxType& GetMin() const
    {
        return _min;
    }

    const MinMaxType& GetMax() const
    {
        return _max;
    }

    MinMaxType GetSize() const
    {
        return _max - _min;
    }

    MinMaxType GetMidpoint() const
    {
        return static_cast<ScalarType>(0.5) * _min + static_cast<ScalarType>(0.5) * _max;
    }

    void SetMin(const MinMaxType& min)
    {
        _min = min;
    }

    void SetMax(const MinMaxType& max)
    {
        _max = max;
    }

    bool IsEmpty() const
    {
        return _min[0] > _max[0] || _min[1] > _max[1];
    }

    void ExtendBy(const MinMaxType& point)
    {
        UnionWith(point);
    }

    void ExtendBy(const ThisType& range)
    {
        UnionWith(range);
    }

    bool Contains(const MinMaxType& point) const
    {
        return (point[0] >= _min[0] && point[0] <= _max[0] && point[1] >= _min[1] && point[1] <= _max[1]);
    }

    bool Contains(const ThisType& range) const
    {
        return Contains(range._min) && Contains(range._max);
    }

    bool IsInside(const MinMaxType& point) const
    {
        return Contains(point);
    }

    bool IsInside(const ThisType& range) const
    {
        return Contains(range);
    }

    bool IsOutside(const ThisType& range) const
    {
        return ((range._max[0] < _min[0] || range._min[0] > _max[0]) ||
                (range._max[1] < _min[1] || range._min[1] > _max[1]));
    }

    static ThisType GetUnion(const ThisType& a, const ThisType& b)
    {
        auto res = a;
        _FindMin(res._min, b._min);
        _FindMax(res._max, b._max);
        return res;
    }

    const ThisType& UnionWith(const ThisType& b)
    {
        _FindMin(_min, b._min);
        _FindMax(_max, b._max);
        return *this;
    }

    const ThisType& UnionWith(const MinMaxType& b)
    {
        _FindMin(_min, b);
        _FindMax(_max, b);
        return *this;
    }

    static ThisType Union(const ThisType& a, const ThisType& b)
    {
        return GetUnion(a, b);
    }

    const ThisType& Union(const ThisType& b)
    {
        return UnionWith(b);
    }

    const ThisType& Union(const MinMaxType& b)
    {
        return UnionWith(b);
    }

    static ThisType GetIntersection(const ThisType& a, const ThisType& b)
    {
        auto res = a;
        _FindMax(res._min, b._min);
        _FindMin(res._max, b._max);
        return res;
    }

    static ThisType Intersection(const ThisType& a, const ThisType& b)
    {
        return GetIntersection(a, b);
    }

    const ThisType& IntersectWith(const ThisType& b)
    {
        _FindMax(_min, b._min);
        _FindMin(_max, b._max);
        return *this;
    }

    const ThisType& Intersection(const ThisType& b)
    {
        return IntersectWith(b);
    }

    ThisType& operator+=(const ThisType& b)
    {
        _min += b._min;
        _max += b._max;
        return *this;
    }

    ThisType& operator-=(const ThisType& b)
    {
        _min -= b._max;
        _max -= b._min;
        return *this;
    }

    ThisType& operator*=(double m)
    {
        if (m > 0)
        {
            _min *= m;
            _max *= m;
        }
        else
        {
            auto tmp = _min;
            _min = _max * m;
            _max = tmp * m;
        }
        return *this;
    }

    ThisType& operator/=(double m)
    {
        return *this *= (1.0 / m);
    }

    ThisType operator+(const ThisType& b) const
    {
        return ThisType(_min + b._min, _max + b._max);
    }

    ThisType operator-(const ThisType& b) const
    {
        return ThisType(_min - b._max, _max - b._min);
    }

    friend ThisType operator*(double m, const ThisType& r)
    {
        return (m > 0 ? ThisType(r._min * m, r._max * m) : ThisType(r._max * m, r._min * m));
    }

    friend ThisType operator*(const ThisType& r, double m)
    {
        return (m > 0 ? ThisType(r._min * m, r._max * m) : ThisType(r._max * m, r._min * m));
    }

    friend ThisType operator/(const ThisType& r, double m)
    {
        return r * (1.0 / m);
    }

    bool operator==(const ThisType& b) const
    {
        return (_min == b._min && _max == b._max);
    }

    bool operator!=(const ThisType& b) const
    {
        return !(*this == b);
    }

    double GetDistanceSquared(const MinMaxType& p) const
    {
        double dist = 0.0;

        if (p[0] < _min[0])
        {
            // p is left of box
            dist += GfSqr(_min[0] - p[0]);
        }
        else if (p[0] > _max[0])
        {
            // p is right of box
            dist += GfSqr(p[0] - _max[0]);
        }
        if (p[1] < _min[1])
        {
            // p is front of box
            dist += GfSqr(_min[1] - p[1]);
        }
        else if (p[1] > _max[1])
        {
            // p is back of box
            dist += GfSqr(p[1] - _max[1]);
        }

        return dist;
    }

    MinMaxType GetCorner(size_t i) const
    {
        if (i > 3)
        {
            return _min;
        }

        return MinMaxType((i & 1 ? _max : _min)[0], (i & 2 ? _max : _min)[1]);
    }

    ThisType GetQuadrant(size_t i) const
    {
        if (i > 3)
        {
            return {};
        }

        auto a = GetCorner(i);
        auto b = .5 * (_min + _max);

        return ThisType(
            MinMaxType(GfMin(a[0], b[0]), GfMin(a[1], b[1])), MinMaxType(GfMax(a[0], b[0]), GfMax(a[1], b[1])));
    }

    static constexpr ThisType UnitSquare()
    {
        return ThisType(MinMaxType(0), MinMaxType(1));
    }

private:
    MinMaxType _min, _max;

    static void _FindMin(MinMaxType& dest, const MinMaxType& point)
    {
        if (point[0] < dest[0])
        {
            dest[0] = point[0];
        }
        if (point[1] < dest[1])
        {
            dest[1] = point[1];
        }
    }

    static void _FindMax(MinMaxType& dest, const MinMaxType& point)
    {
        if (point[0] > dest[0])
        {
            dest[0] = point[0];
        }
        if (point[1] > dest[1])
        {
            dest[1] = point[1];
        }
    }
};

template <typename T>
class range3
{
public:
    static const size_t dimension = 3;
    using ScalarType = T;
    using MinMaxType = omni::math::linalg::vec3<T>;
    using ThisType = range3<T>;

    range3()
    {
        SetEmpty();
    }
    constexpr range3(const ThisType&) = default;

    constexpr explicit range3(ScalarType size) : _min(-size), _max(size)
    {
    }

    // TODO check whether this can be deprecated.
    constexpr void inline SetEmpty()
    {
        _min = MinMaxType(std::numeric_limits<ScalarType>::max());
        _max = MinMaxType(-std::numeric_limits<ScalarType>::max());
    }

    constexpr range3(const MinMaxType& min, const MinMaxType& max) : _min(min), _max(max)
    {
    }

    const MinMaxType& GetMin() const
    {
        return _min;
    }

    const MinMaxType& GetMax() const
    {
        return _max;
    }

    MinMaxType GetSize() const
    {
        return _max - _min;
    }

    MinMaxType GetMidpoint() const
    {
        return static_cast<ScalarType>(0.5) * _min + static_cast<ScalarType>(0.5) * _max;
    }

    void SetMin(const MinMaxType& min)
    {
        _min = min;
    }

    void SetMax(const MinMaxType& max)
    {
        _max = max;
    }

    bool IsEmpty() const
    {
        return _min[0] > _max[0] || _min[1] > _max[1] || _min[2] > _max[2];
    }

    void ExtendBy(const MinMaxType& point)
    {
        UnionWith(point);
    }

    void ExtendBy(const ThisType& range)
    {
        UnionWith(range);
    }

    bool Contains(const MinMaxType& point) const
    {
        return (point[0] >= _min[0] && point[0] <= _max[0] && point[1] >= _min[1] && point[1] <= _max[1] &&
                point[2] >= _min[2] && point[2] <= _max[2]);
    }

    bool Contains(const ThisType& range) const
    {
        return Contains(range._min) && Contains(range._max);
    }

    bool IsInside(const MinMaxType& point) const
    {
        return Contains(point);
    }

    bool IsInside(const ThisType& range) const
    {
        return Contains(range);
    }

    bool IsOutside(const ThisType& range) const
    {
        return ((range._max[0] < _min[0] || range._min[0] > _max[0]) ||
                (range._max[1] < _min[1] || range._min[1] > _max[1]) ||
                (range._max[2] < _min[2] || range._min[2] > _max[2]));
    }

    static ThisType GetUnion(const ThisType& a, const ThisType& b)
    {
        ThisType res = a;
        _FindMin(res._min, b._min);
        _FindMax(res._max, b._max);
        return res;
    }

    const ThisType& UnionWith(const ThisType& b)
    {
        _FindMin(_min, b._min);
        _FindMax(_max, b._max);
        return *this;
    }

    const ThisType& UnionWith(const MinMaxType& b)
    {
        _FindMin(_min, b);
        _FindMax(_max, b);
        return *this;
    }

    static ThisType Union(const ThisType& a, const ThisType& b)
    {
        return GetUnion(a, b);
    }

    const ThisType& Union(const ThisType& b)
    {
        return UnionWith(b);
    }

    const ThisType& Union(const MinMaxType& b)
    {
        return UnionWith(b);
    }

    static ThisType GetIntersection(const ThisType& a, const ThisType& b)
    {
        ThisType res = a;
        _FindMax(res._min, b._min);
        _FindMin(res._max, b._max);
        return res;
    }

    static ThisType Intersection(const ThisType& a, const ThisType& b)
    {
        return GetIntersection(a, b);
    }

    const ThisType& IntersectWith(const ThisType& b)
    {
        _FindMax(_min, b._min);
        _FindMin(_max, b._max);
        return *this;
    }

    const ThisType& Intersection(const ThisType& b)
    {
        return IntersectWith(b);
    }

    ThisType& operator+=(const ThisType& b)
    {
        _min += b._min;
        _max += b._max;
        return *this;
    }

    ThisType& operator-=(const ThisType& b)
    {
        _min -= b._max;
        _max -= b._min;
        return *this;
    }

    ThisType& operator*=(double m)
    {
        if (m > 0)
        {
            _min *= m;
            _max *= m;
        }
        else
        {
            MinMaxType tmp = _min;
            _min = _max * m;
            _max = tmp * m;
        }
        return *this;
    }

    ThisType& operator/=(double m)
    {
        return *this *= (1.0 / m);
    }

    ThisType operator+(const ThisType& b) const
    {
        return ThisType(_min + b._min, _max + b._max);
    }

    ThisType operator-(const ThisType& b) const
    {
        return ThisType(_min - b._max, _max - b._min);
    }

    friend ThisType operator*(double m, const ThisType& r)
    {
        return (m > 0 ? ThisType(r._min * m, r._max * m) : ThisType(r._max * m, r._min * m));
    }

    friend ThisType operator*(const ThisType& r, double m)
    {
        return (m > 0 ? ThisType(r._min * m, r._max * m) : ThisType(r._max * m, r._min * m));
    }

    friend ThisType operator/(const ThisType& r, double m)
    {
        return r * (1.0 / m);
    }

    bool operator==(const ThisType& b) const
    {
        return (_min == b._min && _max == b._max);
    }

    bool operator!=(const ThisType& b) const
    {
        return !(*this == b);
    }

    double GetDistanceSquared(const MinMaxType& p) const
    {
        double dist = 0.0;

        if (p[0] < _min[0])
        {
            // p is left of box
            dist += GfSqr(_min[0] - p[0]);
        }
        else if (p[0] > _max[0])
        {
            // p is right of box
            dist += GfSqr(p[0] - _max[0]);
        }
        if (p[1] < _min[1])
        {
            // p is front of box
            dist += GfSqr(_min[1] - p[1]);
        }
        else if (p[1] > _max[1])
        {
            // p is back of box
            dist += GfSqr(p[1] - _max[1]);
        }
        if (p[2] < _min[2])
        {
            // p is below of box
            dist += GfSqr(_min[2] - p[2]);
        }
        else if (p[2] > _max[2])
        {
            // p is above of box
            dist += GfSqr(p[2] - _max[2]);
        }

        return dist;
    }

    MinMaxType GetCorner(size_t i) const
    {
        if (i > 7)
        {
            return _min;
        }
        return MinMaxType((i & 1 ? _max : _min)[0], (i & 2 ? _max : _min)[1], (i & 4 ? _max : _min)[2]);
    }

    ThisType GetOctant(size_t i) const
    {
        if (i > 7)
        {
            return {};
        }

        auto a = GetCorner(i);
        auto b = .5 * (_min + _max);

        return ThisType(MinMaxType(GfMin(a[0], b[0]), GfMin(a[1], b[1]), GfMin(a[2], b[2])),
                        MinMaxType(GfMax(a[0], b[0]), GfMax(a[1], b[1]), GfMax(a[2], b[2])));
    }

    static constexpr const ThisType UnitCube()
    {
        return ThisType(MinMaxType(0), MinMaxType(1));
    }

private:
    MinMaxType _min, _max;

    static void _FindMin(MinMaxType& dest, const MinMaxType& point)
    {
        if (point[0] < dest[0])
        {
            dest[0] = point[0];
        }
        if (point[1] < dest[1])
        {
            dest[1] = point[1];
        }
        if (point[2] < dest[2])
        {
            dest[2] = point[2];
        }
    }

    static void _FindMax(MinMaxType& dest, const MinMaxType& point)
    {
        if (point[0] > dest[0])
        {
            dest[0] = point[0];
        }
        if (point[1] > dest[1])
        {
            dest[1] = point[1];
        }
        if (point[2] > dest[2])
        {
            dest[2] = point[2];
        }
    }
};

}
}
}

namespace usdrt
{

using GfRange1d = omni::math::linalg::range1<double>;
using GfRange1f = omni::math::linalg::range1<float>;
using GfRange2d = omni::math::linalg::range2<double>;
using GfRange2f = omni::math::linalg::range2<float>;
using GfRange3d = omni::math::linalg::range3<double>;
using GfRange3f = omni::math::linalg::range3<float>;

template <>
struct GfIsGfRange<GfRange1d>
{
    static const bool value = true;
};

template <>
struct GfIsGfRange<GfRange1f>
{
    static const bool value = true;
};

template <>
struct GfIsGfRange<GfRange2d>
{
    static const bool value = true;
};

template <>
struct GfIsGfRange<GfRange2f>
{
    static const bool value = true;
};

template <>
struct GfIsGfRange<GfRange3d>
{
    static const bool value = true;
};

template <>
struct GfIsGfRange<GfRange3f>
{
    static const bool value = true;
};

}