-
Brandon Lai-Cheong authoredBrandon Lai-Cheong authored
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;
}