Skip to content
Snippets Groups Projects
intersections.cpp 4.75 KiB
#include "intersections.h"
#include <optional>
#include <triangle_edges.h>
#include <triangle.h>
#include <constants.h>
#include <edge.h>
#include <interpolate_z.h>

std::optional<float> getB(std::optional<float> slope, Point p)
{
    if (!slope.has_value())
    {
        return {};
    }

    return p.y - slope.value() * p.x;
}

std::optional<float> getSlope(Edge e)
{
    if (e.p2.x - e.p1.x == 0)
    {
        return {};
    }
    return (e.p2.y - e.p1.y) / (e.p2.x - e.p1.x);
}

bool withinEdge(Edge e, Point p)
{
    float minX = std::min(e.p1.x, e.p2.x) - EPSILON;
    float maxX = std::max(e.p1.x, e.p2.x) + EPSILON;

    float minY = std::min(e.p1.y, e.p2.y) - EPSILON;
    float maxY = std::max(e.p1.y, e.p2.y) + EPSILON;

    return minX <= p.x && p.x <= maxX && minY <= p.y && p.y <= maxY;
}

void intersection(Edge e1, Edge e2, std::vector<Point> &results)
{
    auto point = intersectionWithinEdge(e1, e2);
    if (point.has_value())
    {
        results.push_back(point.value());
    }
}

std::optional<Point> intersectionWithinEdge(const Edge &e1, const Edge &e2)
{
    std::optional<Point> candPoint = intersection(e1, e2);
    if (candPoint.has_value() &&
        withinEdge(e1, candPoint.value()) &&
        withinEdge(e2, candPoint.value()))
    {
        return candPoint;
    }
    return {};
}

// intersection with first edge being considered infinite in length
std::optional<Point> intersectionFirstSide(const Edge &e1, const Edge &e2) {
    auto candPoint = intersection(e1, e2);

    if (candPoint.has_value() && withinEdge(e2, candPoint.value())) {
        return candPoint;
    }
    return {};
}

// returns intersection with e1 being extended infinitly in its direction
std::optional<Point> intersectionWithinEdgeDirection(const Edge &e1, const Edge &e2)
{
    auto candPoint = intersection(e1, e2);

    if (candPoint.has_value() && withinEdge(e2, candPoint.value()))
    {

        // check if in direction e1 is pointing at
        // case where e1 is pointing towards positive x axis
        if (e1.p1.x < e1.p2.x && candPoint.value().x >= e1.p1.x)
        {
            return candPoint;
        }

        // case where e1 is pointing towards negative x axis
        if (e1.p1.x > e1.p2.x && candPoint.value().x <= e1.p1.x)
        {
            return candPoint;
        }

        // edge case where p1 and p2 form a vertical line
        // case where e1 is pointing towards positive y axis
        if (e1.p1.y < e1.p2.y && candPoint.value().y >= e1.p1.y)
        {
            return candPoint;
        }

        // case where e1 is pointing towards negative axis
        if (e1.p1.y > e1.p2.y && candPoint.value().y <= e1.p1.y)
        {
            return candPoint;
        }
    }
    return {};
}

std::optional<Point> intersection(const Edge &e1, const Edge &e2)
{
    auto slope1 = getSlope(e1);
    auto slope2 = getSlope(e2);

    auto b1 = getB(slope1, e1.p1);
    auto b2 = getB(slope2, e2.p1);

    // ignore overlapping case
    if (!slope1.has_value() && !slope2.has_value())
    {
        return {};
    }

    if (!slope1.has_value())
    {
        return Point{e1.p1.x, slope2.value() * e1.p1.x + b2.value()};
    }

    if (!slope2.has_value())
    {
        return Point{e2.p1.x, slope1.value() * e2.p1.x + b1.value()};
    }
    float candX = (b2.value() - b1.value()) / (slope1.value() - slope2.value());
    auto candPoint = Point{candX, slope1.value() * candX + b1.value()};

    // ignore case where intersection is at an endpoint
    /*
    if (candPoint == e1.p1 || candPoint == e1.p2 || candPoint == e2.p1 || candPoint == e2.p2) {
        return {};
    }*/
    if (candPoint.x > MAX_POINT || candPoint.y > MAX_POINT || candPoint.x < MIN_POINT || candPoint.y < MIN_POINT)
    {
        return {};
    }
    return candPoint;
}
void intersections(const Edge &e1, const TriangleEdges &te, std::vector<Point> &results)
{
    for (int i = 0; i < NB_TRIANGLE_SIDES; i++)
    {
        intersection(e1, te.edges[i], results);
    }
}
std::vector<Point> intersections(const Triangle &t1, const Triangle &t2)
{
    TriangleEdges t1Edges = TriangleEdges(t1);

    TriangleEdges t2Edges = TriangleEdges(t2);
    std::vector<Point> results;

    for (int i = 0; i < NB_TRIANGLE_SIDES; i++)
    {
        intersections(t1Edges.edges[i], t2Edges, results);
    }

    return results;
}

std::vector<Point> intersections(const std::vector<Point> &points, const Edge &line)
{
    std::vector<Point> result;
    std::vector<Edge> es = makeEdges(points);
    for (int i = 0; i < es.size(); i++)
    {
        auto cand = intersectionFirstSide(line, es[i]);
        if (cand.has_value())
        {
            // add depth information
            float z = interpolateZ(es[i], cand.value());
            cand.value().z = z;
            result.push_back(cand.value());
        }
    }
    return result;
}