Program Listing for File mesh_half_edge.hpp

Return to documentation for file (/home/runner/work/Legion-Engine/Legion-Engine/legion/engine/physics/mesh_splitter_utils/mesh_half_edge.hpp)

#pragma once
#include <core/core.hpp>
#include <physics/mesh_splitter_utils/splittable_polygon.hpp>
#include <physics/physics_statics.hpp>
#include <rendering/debugrendering.hpp>

namespace legion::physics
{
    struct MeshHalfEdge : std::enable_shared_from_this<MeshHalfEdge>
    {
        math::vec3 position;
        math::vec2 uv;

        std::shared_ptr<MeshHalfEdge> nextEdge = nullptr;
        std::shared_ptr<MeshHalfEdge> pairingEdge = nullptr;
        std::shared_ptr<MeshHalfEdge> shadowEdge = nullptr;

        std::weak_ptr<SplittablePolygon> owner;

        //TODO: these bools should probably be stored as an array in SplittablePolygon
        bool isVisited = false;
        bool isBoundary = false;

        MeshHalfEdge(const math::vec3& pPosition, const math::vec2& pUVs, std::weak_ptr<SplittablePolygon> pOwner) : position(pPosition), uv(pUVs),owner(pOwner)
        {

        }

        MeshHalfEdge(const math::vec3& pPosition,const math::vec2& pUVs) : position(pPosition),uv(pUVs)
        {

        }

        MeshHalfEdge(const math::vec3& pPosition) : position(pPosition)
        {

        }

        auto getTriangle()
        {
            return std::make_tuple(shared_from_this(), nextEdge, nextEdge->nextEdge);
        }

        auto getShadowTriangle()
        {
            return std::make_tuple(shadowEdge, nextEdge->shadowEdge, nextEdge->nextEdge->shadowEdge);
        }

        void setPairing(std::shared_ptr<MeshHalfEdge>& newPairing)
        {
            pairingEdge = newPairing;
            newPairing->pairingEdge = shared_from_this();
        }

        void cloneOnShadowEdge()
        {
            shadowEdge = std::make_shared<MeshHalfEdge>(position, uv);
            shadowEdge->isBoundary = isBoundary;
        }

        static void connectIntoTriangle(std::shared_ptr<MeshHalfEdge> first
            , std::shared_ptr<MeshHalfEdge> second,
            std::shared_ptr<MeshHalfEdge> third)
        {
            first->nextEdge = second;
            second->nextEdge = third;
            third->nextEdge = first;
        }


        bool isSplitByPlane(const math::mat4& transform
            , const math::vec3& planePosition
            ,const  math::vec3& planeNormal)
        {
            int x = 0;
            int y = 0;

            auto [currentDistFromPlane, nextDistFromPlane] = getEdgeDistancesFromPlane(transform, planePosition, planeNormal);

            static float splitEpsilon = math::sqrt(math::epsilon<float>());

            if (currentDistFromPlane > splitEpsilon)
            {
                x = 1;
            }
            else if (currentDistFromPlane < -splitEpsilon)
            {
                x = -1;
            }


            if (nextDistFromPlane > splitEpsilon)
            {
                y = 1;
            }
            else if (nextDistFromPlane < -splitEpsilon)
            {
                y = -1;
            }
            //log::debug("x {} y {}", x, y);
            int edgeSplitState = x * y;


            return edgeSplitState < 0;


        }

        math::vec3 getWorldCentroid(const math::mat4& transform) const
        {
            return transform * math::vec4((position + nextEdge->position) * 0.5f, 1);
        }

        bool isEdgePartlyAbovePlane(const math::mat4& transform, const math::vec3& planePosition, const math::vec3& planeNormal)
        {
            auto [currentDistFromPlane, nextDistFromPlane] = getEdgeDistancesFromPlane(transform, planePosition, planeNormal);

            bool currentAbovePlane = currentDistFromPlane > constants::polygonSplitterEpsilon;
            bool nextAbovePlane = nextDistFromPlane > constants::polygonSplitterEpsilon;

            return currentAbovePlane || nextAbovePlane;
        }

        bool isEdgePartlyBelowPlane(const math::mat4& transform, const math::vec3& planePosition, const math::vec3& planeNormal)
        {
            auto [currentDistFromPlane, nextDistFromPlane] = getEdgeDistancesFromPlane(transform, planePosition, planeNormal);

            bool currentBelowPlane = currentDistFromPlane < -constants::polygonSplitterEpsilon;
            bool nextBelowPlane = nextDistFromPlane < -constants::polygonSplitterEpsilon;

            return currentBelowPlane || nextBelowPlane;
        }

        std::tuple<float, float> getEdgeDistancesFromPlane(const math::mat4& transform, const math::vec3& planePosition, const math::vec3& planeNormal)
        {
            auto [currentWorldPos, nextWorldPos] = getEdgeWorldPositions(transform);

            float currentDistFromPlane = PhysicsStatics::PointDistanceToPlane(planeNormal, planePosition,  currentWorldPos);
            float nextDistFromPlane = PhysicsStatics::PointDistanceToPlane(planeNormal, planePosition,  nextWorldPos);

            return std::make_tuple(currentDistFromPlane, nextDistFromPlane);
        }

        std::tuple<math::vec3, math::vec3> getEdgeWorldPositions(const math::mat4& transform)
        {
            math::vec3 currentWorldPos = getEdgeWorldPosition(transform);
            math::vec3 nextWorldPos = nextEdge->getEdgeWorldPosition(transform);

            return std::make_tuple(currentWorldPos, nextWorldPos);
        }

        math::vec3 getEdgeWorldPosition(const math::mat4& transform)
        {
            return transform * math::vec4(position, 1);
        }

        bool attemptGetTrianglesInEdges
        (std::shared_ptr<MeshHalfEdge>& nextEdge, std::shared_ptr<MeshHalfEdge>& prevEdge)
        {
            if (!this->nextEdge)
            {
                return false;
            }

            nextEdge = this->nextEdge;

            if (!nextEdge->nextEdge)
            {
                return false;
            }

            prevEdge = nextEdge->nextEdge;

            return true;
        }

        void markTriangleEdgeVisited()
        {
            isVisited = true;
            nextEdge->isVisited = true;
            nextEdge->nextEdge->isVisited = true;
        }

        void populateQueueWithTriangleNeighbor(std::queue<std::shared_ptr<MeshHalfEdge>>& edgeQueue)
        {
            if (pairingEdge)
            {
                edgeQueue.push(pairingEdge);
            }

            if (nextEdge->pairingEdge)
            {
                edgeQueue.push(nextEdge->pairingEdge);
            }

            if (nextEdge->nextEdge->pairingEdge)
            {
                edgeQueue.push(nextEdge->nextEdge->pairingEdge);
            }

        }

        void populateVectorWithTriangle(std::vector<std::shared_ptr<MeshHalfEdge>>& edgeVector)
        {
            edgeVector.push_back(shared_from_this());
            edgeVector.push_back(nextEdge);
            edgeVector.push_back(nextEdge->nextEdge);
        }

        bool isTriangleValid()
        {
            std::shared_ptr<MeshHalfEdge> nextEdge = nullptr;
            std::shared_ptr<MeshHalfEdge> prevEdge = nullptr;
            return attemptGetTrianglesInEdges( nextEdge, prevEdge);
        }

        math::vec3 calculateEdgeNormal(const math::mat4& transform)
        {
            math::vec3 firstDir = transform * math::vec4(nextEdge->position - position,0);
            math::vec3 secondDir = transform * math::vec4(nextEdge->nextEdge->position - position,0);

            return math::normalize(math::cross(firstDir, secondDir));
        }

        bool isNormalCloseEnough(const math::vec3& comparisonNormal, const math::mat4& transform)
        {
            return compareNormals(calculateEdgeNormal(transform), comparisonNormal);
        }

        static bool compareNormals(const math::vec3& comparisonNormal, const math::vec3& otherNormal)
        {
            static float toleranceDot = math::cos(math::deg2rad(5.0f));

            float dotResult = math::dot(otherNormal, comparisonNormal);

            return dotResult > toleranceDot;
        }

        void DEBUG_drawInsetEdge(const math::mat4& transform,
            math::vec3& worldCentroid,float insetInterpolant)
        {
            auto [start, end] = getEdgeWorldPositions(transform);
            math::vec3 toCentroidStart = worldCentroid - start;
            math::vec3 toCentroidEnd = worldCentroid - end;

            debug::drawLine(start + toCentroidStart * insetInterpolant
                , end + toCentroidEnd * insetInterpolant, owner.lock()->debugColor, 8.0f, 0.0f);

        }

    };
}