summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assetFactory/faceController.cpp2
-rw-r--r--assetFactory/faceController.h2
-rw-r--r--game/geoData.cpp14
-rw-r--r--game/geoData.h4
-rw-r--r--game/network/link.cpp9
-rw-r--r--game/network/link.h8
-rw-r--r--game/network/network.cpp7
-rw-r--r--game/network/network.h8
-rw-r--r--game/network/network.impl.h2
-rw-r--r--game/selectable.h5
-rw-r--r--game/vehicles/railVehicle.cpp27
-rw-r--r--game/vehicles/railVehicle.h4
-rw-r--r--game/vehicles/train.cpp4
-rw-r--r--game/vehicles/train.h4
-rw-r--r--gfx/gl/camera.cpp6
-rw-r--r--gfx/gl/camera.h2
-rw-r--r--lib/basicShapes.h19
-rw-r--r--lib/geometricPlane.cpp20
-rw-r--r--lib/geometricPlane.h37
-rw-r--r--lib/maths.h20
-rw-r--r--lib/ray.cpp35
-rw-r--r--lib/ray.h78
-rw-r--r--test/test-geoData.cpp4
-rw-r--r--test/test-maths.cpp2
-rw-r--r--ui/builders/freeExtend.cpp6
-rw-r--r--ui/builders/freeExtend.h6
-rw-r--r--ui/builders/join.cpp5
-rw-r--r--ui/builders/join.h6
-rw-r--r--ui/builders/straight.cpp6
-rw-r--r--ui/builders/straight.h6
-rw-r--r--ui/editNetwork.cpp4
-rw-r--r--ui/editNetwork.h10
-rw-r--r--ui/gameMainSelector.cpp6
-rw-r--r--ui/gameMainSelector.h8
34 files changed, 227 insertions, 159 deletions
diff --git a/assetFactory/faceController.cpp b/assetFactory/faceController.cpp
index d045b3c..10a0c1e 100644
--- a/assetFactory/faceController.cpp
+++ b/assetFactory/faceController.cpp
@@ -90,7 +90,7 @@ FaceController::split(
const size_t nextIdx = (curIdx + 1) % vertexRelations.size();
const auto &current = vertexRelations[curIdx], next = vertexRelations[nextIdx];
if (GeometricPlane::isIntersect(current.second, next.second)) {
- const auto ray = Ray::fromPoints(mesh.point(current.first), mesh.point(next.first));
+ const auto ray = RayFactory::fromPoints(mesh.point(current.first), mesh.point(next.first));
const auto intersect = split.getRayIntersectPosition(ray);
assert(intersect);
const auto newv = mesh.add_vertex(intersect->position);
diff --git a/assetFactory/faceController.h b/assetFactory/faceController.h
index fb89d25..e940640 100644
--- a/assetFactory/faceController.h
+++ b/assetFactory/faceController.h
@@ -11,7 +11,7 @@
class FaceController : public Mutation, public Style, public Persistence::Persistable {
public:
- class Split : public Persistable, public GeometricPlane {
+ class Split : public Persistable, public GeometricPlaneT<RelativePosition3D> {
public:
std::string id;
diff --git a/game/geoData.cpp b/game/geoData.cpp
index 97f4a26..b30a35b 100644
--- a/game/geoData.cpp
+++ b/game/geoData.cpp
@@ -161,7 +161,7 @@ namespace {
positionOnTriangle(const GlobalPosition2D point, const GeoData::Triangle<3> & t)
{
const CalcPosition3D a = t[1] - t[0], b = t[2] - t[0];
- const auto n = crossInt(a, b);
+ const auto n = crossProduct(a, b);
return {point, ((n.x * t[0].x) + (n.y * t[0].y) + (n.z * t[0].z) - (n.x * point.x) - (n.y * point.y)) / n.z};
}
@@ -194,23 +194,23 @@ GeoData::positionAt(const PointFace & p) const
}
[[nodiscard]] std::optional<GlobalPosition3D>
-GeoData::intersectRay(const Ray & ray) const
+GeoData::intersectRay(const Ray<GlobalPosition3D> & ray) const
{
return intersectRay(ray, findPoint(ray.start));
}
[[nodiscard]] std::optional<GlobalPosition3D>
-GeoData::intersectRay(const Ray & ray, FaceHandle face) const
+GeoData::intersectRay(const Ray<GlobalPosition3D> & ray, FaceHandle face) const
{
std::optional<GlobalPosition3D> out;
walkUntil(PointFace {ray.start, face},
- ray.start.xy() + (ray.direction.xy() * RelativePosition2D(upperExtent.xy() - lowerExtent.xy())),
+ ray.start.xy()
+ + GlobalPosition2D(ray.direction.xy() * RelativePosition2D(upperExtent.xy() - lowerExtent.xy())),
[&out, &ray, this](FaceHandle face) {
BaryPosition bari {};
- float dist {};
+ RelativeDistance dist {};
const auto t = triangle<3>(face);
- if (glm::intersectRayTriangle<RelativePosition3D::value_type, glm::defaultp>(
- ray.start, ray.direction, t[0], t[1], t[2], bari, dist)) {
+ if (ray.intersectTriangle(t.x, t.y, t.z, bari, dist)) {
out = t * bari;
return true;
}
diff --git a/game/geoData.h b/game/geoData.h
index d4d0fb3..e234bfe 100644
--- a/game/geoData.h
+++ b/game/geoData.h
@@ -74,8 +74,8 @@ public:
[[nodiscard]] FaceHandle findPoint(GlobalPosition2D, FaceHandle start) const;
[[nodiscard]] GlobalPosition3D positionAt(const PointFace &) const;
- [[nodiscard]] std::optional<GlobalPosition3D> intersectRay(const Ray &) const;
- [[nodiscard]] std::optional<GlobalPosition3D> intersectRay(const Ray &, FaceHandle start) const;
+ [[nodiscard]] std::optional<GlobalPosition3D> intersectRay(const Ray<GlobalPosition3D> &) const;
+ [[nodiscard]] std::optional<GlobalPosition3D> intersectRay(const Ray<GlobalPosition3D> &, FaceHandle start) const;
void walk(const PointFace & from, const GlobalPosition2D to, const std::function<void(FaceHandle)> & op) const;
void walkUntil(const PointFace & from, const GlobalPosition2D to, const std::function<bool(FaceHandle)> & op) const;
diff --git a/game/network/link.cpp b/game/network/link.cpp
index 703a1ca..e8eaea2 100644
--- a/game/network/link.cpp
+++ b/game/network/link.cpp
@@ -33,9 +33,10 @@ LinkStraight::positionAt(float dist, unsigned char start) const
}
bool
-LinkStraight::intersectRay(const Ray & ray) const
+LinkStraight::intersectRay(const Ray<GlobalPosition3D> & ray) const
{
- return ray.passesCloseToEdges(std::array {ends.front().node->pos, ends.back().node->pos}, 1.F);
+ return ray.passesCloseToEdges(
+ std::array {GlobalPosition3D {ends.front().node->pos}, GlobalPosition3D {ends.back().node->pos}}, 1000);
}
Location
@@ -54,7 +55,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const
}
bool
-LinkCurve::intersectRay(const Ray & ray) const
+LinkCurve::intersectRay(const Ray<GlobalPosition3D> & ray) const
{
const auto & e0p {ends[0].node->pos};
const auto & e1p {ends[1].node->pos};
@@ -64,7 +65,7 @@ LinkCurve::intersectRay(const Ray & ray) const
const auto trans {glm::translate(centreBase)};
auto segCount = static_cast<std::size_t>(std::lround(segs)) + 1;
- std::vector<Position3D> points;
+ std::vector<GlobalPosition3D> points;
points.reserve(segCount);
for (Position3D swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) {
const auto t {trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})};
diff --git a/game/network/link.h b/game/network/link.h
index 78d3e91..95c141e 100644
--- a/game/network/link.h
+++ b/game/network/link.h
@@ -10,7 +10,7 @@
#include <utility>
#include <vector>
-class Ray;
+template<typename> class Ray;
// Generic network node
// something that can be travelled to
@@ -45,7 +45,7 @@ public:
NO_MOVE(Link);
[[nodiscard]] virtual Location positionAt(float dist, unsigned char start) const = 0;
- [[nodiscard]] virtual bool intersectRay(const Ray &) const = 0;
+ [[nodiscard]] virtual bool intersectRay(const Ray<GlobalPosition3D> &) const = 0;
std::array<End, 2> ends;
float length;
@@ -69,7 +69,7 @@ public:
NO_MOVE(LinkStraight);
[[nodiscard]] Location positionAt(float dist, unsigned char start) const override;
- [[nodiscard]] bool intersectRay(const Ray &) const override;
+ [[nodiscard]] bool intersectRay(const Ray<GlobalPosition3D> &) const override;
};
LinkStraight::~LinkStraight() = default;
@@ -82,7 +82,7 @@ public:
NO_MOVE(LinkCurve);
[[nodiscard]] Location positionAt(float dist, unsigned char start) const override;
- [[nodiscard]] bool intersectRay(const Ray &) const override;
+ [[nodiscard]] bool intersectRay(const Ray<GlobalPosition3D> &) const override;
Position3D centreBase;
float radius;
diff --git a/game/network/network.cpp b/game/network/network.cpp
index 1ff5b26..d52e804 100644
--- a/game/network/network.cpp
+++ b/game/network/network.cpp
@@ -49,13 +49,14 @@ Network::candidateNodeAt(Position3D pos) const
}
Node::Ptr
-Network::intersectRayNodes(const Ray & ray) const
+Network::intersectRayNodes(const Ray<GlobalPosition3D> & ray) const
{
// Click within 2m of a node
if (const auto node = std::find_if(nodes.begin(), nodes.end(),
[&ray](const Node::Ptr & node) {
- Position3D ipos, inorm;
- return glm::intersectRaySphere(ray.start, ray.direction, node->pos, 2.F, ipos, inorm);
+ GlobalPosition3D ipos;
+ Normal3D inorm;
+ return ray.intersectSphere(node->pos, 2000, ipos, inorm);
});
node != nodes.end()) {
return *node;
diff --git a/game/network/network.h b/game/network/network.h
index 8af06a9..9ce6e81 100644
--- a/game/network/network.h
+++ b/game/network/network.h
@@ -14,7 +14,7 @@
class Texture;
class SceneShader;
-class Ray;
+template<typename> class Ray;
template<size_t... n> using GenDef = std::tuple<glm::vec<n, Distance>...>;
using GenCurveDef = GenDef<3, 3, 2>;
@@ -32,8 +32,8 @@ public:
using NodeInsertion = std::pair<Node::Ptr, NodeIs>;
[[nodiscard]] NodeInsertion newNodeAt(Position3D);
[[nodiscard]] NodeInsertion candidateNodeAt(Position3D) const;
- [[nodiscard]] virtual Link::Ptr intersectRayLinks(const Ray &) const = 0;
- [[nodiscard]] virtual Node::Ptr intersectRayNodes(const Ray &) const;
+ [[nodiscard]] virtual Link::Ptr intersectRayLinks(const Ray<GlobalPosition3D> &) const = 0;
+ [[nodiscard]] virtual Node::Ptr intersectRayNodes(const Ray<GlobalPosition3D> &) const;
[[nodiscard]] Link::Nexts routeFromTo(const Link::End &, Position3D) const;
[[nodiscard]] Link::Nexts routeFromTo(const Link::End &, const Node::Ptr &) const;
@@ -66,7 +66,7 @@ protected:
void joinLinks(const Link::Ptr &) const;
protected:
- [[nodiscard]] Link::Ptr intersectRayLinks(const Ray &) const override;
+ [[nodiscard]] Link::Ptr intersectRayLinks(const Ray<GlobalPosition3D> &) const override;
public:
template<typename L, typename... Params>
diff --git a/game/network/network.impl.h b/game/network/network.impl.h
index 8e9e85c..4acbb6d 100644
--- a/game/network/network.impl.h
+++ b/game/network/network.impl.h
@@ -24,7 +24,7 @@ NetworkOf<T>::joinLinks(const Link::Ptr & l) const
template<typename T>
Link::Ptr
-NetworkOf<T>::intersectRayLinks(const Ray & ray) const
+NetworkOf<T>::intersectRayLinks(const Ray<GlobalPosition3D> & ray) const
{
// Click link
if (const auto link = std::find_if(links.objects.begin(), links.objects.end(),
diff --git a/game/selectable.h b/game/selectable.h
index c794461..fc6af4e 100644
--- a/game/selectable.h
+++ b/game/selectable.h
@@ -4,7 +4,7 @@
#include <glm/glm.hpp>
#include <special_members.h>
-class Ray;
+template<typename> class Ray;
class Selectable {
public:
@@ -12,5 +12,6 @@ public:
virtual ~Selectable() = default;
DEFAULT_MOVE_COPY(Selectable);
- [[nodiscard]] virtual bool intersectRay(const Ray &, BaryPosition &, RelativeDistance &) const = 0;
+ [[nodiscard]] virtual bool intersectRay(const Ray<GlobalPosition3D> &, BaryPosition &, RelativeDistance &) const
+ = 0;
};
diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp
index 6653333..4a1fdab 100644
--- a/game/vehicles/railVehicle.cpp
+++ b/game/vehicles/railVehicle.cpp
@@ -3,12 +3,12 @@
#include "train.h"
#include <algorithm>
#include <array>
+#include <basicShapes.h>
#include <glm/glm.hpp>
#include <glm/gtx/intersect.hpp>
#include <glm/gtx/transform.hpp>
#include <location.h>
#include <maths.h>
-#include <memory>
#include <ray.h>
RailVehicle::RailVehicle(RailVehicleClassPtr rvc) :
@@ -22,12 +22,12 @@ RailVehicle::RailVehicle(RailVehicleClassPtr rvc) :
this->get()->front = l->getRotationTransform();
this->get()->frontPos = l->position();
},
- Position3D {0, rvClass->wheelBase / 2.F, 0}},
+ GlobalPosition3D {0, rvClass->wheelBase / 2.F, 0}},
{[this](const BufferedLocation * l) {
this->get()->back = l->getRotationTransform();
this->get()->backPos = l->position();
},
- Position3D {0, -rvClass->wheelBase / 2.F, 0}},
+ GlobalPosition3D {0, -rvClass->wheelBase / 2.F, 0}},
}}
{
}
@@ -44,22 +44,15 @@ RailVehicle::move(const Train * t, float & trailBy)
}
bool
-RailVehicle::intersectRay(const Ray & ray, BaryPosition & baryPos, RelativeDistance & distance) const
+RailVehicle::intersectRay(const Ray<GlobalPosition3D> & ray, BaryPosition & baryPos, RelativeDistance & distance) const
{
constexpr const auto X = 1350.F;
const auto Y = this->rvClass->length / 2.F;
constexpr const auto Z = 3900.F;
- const auto moveBy = location.getRotationTransform();
- const std::array<Position3D, 8> cornerVertices {{
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, Y, 0, 1}).xyz(), // LFB
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, Y, 0, 1}).xyz(), // RFB
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, Y, Z, 1}).xyz(), // LFT
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, Y, Z, 1}).xyz(), // RFT
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, -Y, 0, 1}).xyz(), // LBB
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, -Y, 0, 1}).xyz(), // RBB
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, -Y, Z, 1}).xyz(), // LBT
- location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, -Y, Z, 1}).xyz(), // RBT
- }};
+ const glm::mat3 moveBy = location.getRotationTransform();
+ const auto cornerVertices = cuboidCorners(-X, X, -Y, Y, 0.F, Z) * [&moveBy, this](const auto & corner) {
+ return location.position() + GlobalPosition3D(moveBy * corner);
+ };
static constexpr const std::array<glm::vec<3, uint8_t>, 10> triangles {{
// Front
{0, 1, 2},
@@ -79,7 +72,7 @@ RailVehicle::intersectRay(const Ray & ray, BaryPosition & baryPos, RelativeDista
}};
return std::any_of(
triangles.begin(), triangles.end(), [&cornerVertices, &ray, &baryPos, &distance](const auto & idx) {
- return glm::intersectRayTriangle(ray.start, ray.direction, cornerVertices[idx[0]],
- cornerVertices[idx[1]], cornerVertices[idx[2]], baryPos, distance);
+ return ray.intersectTriangle(
+ cornerVertices[idx[0]], cornerVertices[idx[1]], cornerVertices[idx[2]], baryPos, distance);
});
}
diff --git a/game/vehicles/railVehicle.h b/game/vehicles/railVehicle.h
index f6e4764..bf1e782 100644
--- a/game/vehicles/railVehicle.h
+++ b/game/vehicles/railVehicle.h
@@ -7,7 +7,7 @@
#include <glm/glm.hpp>
#include <memory>
-class Ray;
+template<typename> class Ray;
class Train;
class RailVehicle : Selectable, RailVehicleClass::Instance {
@@ -16,7 +16,7 @@ public:
void move(const Train *, float & trailBy);
- [[nodiscard]] bool intersectRay(const Ray &, BaryPosition &, RelativeDistance &) const override;
+ [[nodiscard]] bool intersectRay(const Ray<GlobalPosition3D> &, BaryPosition &, RelativeDistance &) const override;
RailVehicleClassPtr rvClass;
using LV = RailVehicleClass::LocationVertex;
diff --git a/game/vehicles/train.cpp b/game/vehicles/train.cpp
index 05b2d8a..5bddd61 100644
--- a/game/vehicles/train.cpp
+++ b/game/vehicles/train.cpp
@@ -9,7 +9,7 @@
#include <optional>
#include <utility>
-class Ray;
+template<typename> class Ray;
Location
Train::getBogiePosition(float linkDist, float dist) const
@@ -20,7 +20,7 @@ Train::getBogiePosition(float linkDist, float dist) const
}
bool
-Train::intersectRay(const Ray & ray, BaryPosition & baryPos, RelativeDistance & distance) const
+Train::intersectRay(const Ray<GlobalPosition3D> & ray, BaryPosition & baryPos, RelativeDistance & distance) const
{
return applyOne(&RailVehicle::intersectRay, ray, baryPos, distance) != end();
}
diff --git a/game/vehicles/train.h b/game/vehicles/train.h
index bb668ed..4320103 100644
--- a/game/vehicles/train.h
+++ b/game/vehicles/train.h
@@ -13,7 +13,7 @@
class SceneShader;
class ShadowMapper;
-class Ray;
+template<typename> class Ray;
class Train : public Vehicle, public Collection<RailVehicle, false>, public Can<Go>, public Can<Idle> {
public:
@@ -25,7 +25,7 @@ public:
return objects.front()->location;
}
- [[nodiscard]] bool intersectRay(const Ray &, BaryPosition &, RelativeDistance &) const override;
+ [[nodiscard]] bool intersectRay(const Ray<GlobalPosition3D> &, BaryPosition &, RelativeDistance &) const override;
void tick(TickDuration elapsed) override;
void doActivity(Go *, TickDuration) override;
diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp
index d362b94..fb711dd 100644
--- a/gfx/gl/camera.cpp
+++ b/gfx/gl/camera.cpp
@@ -13,7 +13,7 @@ Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance zNe
updateView();
}
-Ray
+Ray<GlobalPosition3D>
Camera::unProject(const ScreenRelCoord & mouse) const
{
static constexpr const glm::vec4 screen {0, 0, 1, 1};
@@ -31,8 +31,8 @@ Camera::updateView()
Direction3D
Camera::upFromForward(const Direction3D & forward)
{
- const auto right = glm::cross(forward, ::down);
- return glm::cross(forward, right);
+ const auto right = crossProduct(forward, ::down);
+ return crossProduct(forward, right);
}
std::array<GlobalPosition4D, 4>
diff --git a/gfx/gl/camera.h b/gfx/gl/camera.h
index eca7b8f..8d53261 100644
--- a/gfx/gl/camera.h
+++ b/gfx/gl/camera.h
@@ -15,7 +15,7 @@ public:
return viewProjection;
}
- [[nodiscard]] Ray unProject(const ScreenRelCoord &) const;
+ [[nodiscard]] Ray<GlobalPosition3D> unProject(const ScreenRelCoord &) const;
void
setPosition(const GlobalPosition3D & p)
diff --git a/lib/basicShapes.h b/lib/basicShapes.h
new file mode 100644
index 0000000..183863e
--- /dev/null
+++ b/lib/basicShapes.h
@@ -0,0 +1,19 @@
+#pragma once
+#include <array>
+#include <glm/vec3.hpp>
+
+template<typename T, glm::qualifier Q = glm::defaultp>
+constexpr std::array<glm::vec<3, T, Q>, 8>
+cuboidCorners(T lx, T ux, T ly, T uy, T lz, T uz)
+{
+ return {{
+ {lx, uy, lz}, // LFB
+ {ux, uy, lz}, // RFB
+ {lx, uy, uz}, // LFT
+ {ux, uy, uz}, // RFT
+ {lx, ly, lz}, // LBB
+ {ux, ly, lz}, // RBB
+ {lx, ly, uz}, // LBT
+ {ux, ly, uz}, // RBT
+ }};
+}
diff --git a/lib/geometricPlane.cpp b/lib/geometricPlane.cpp
index 567f98a..7aadf6a 100644
--- a/lib/geometricPlane.cpp
+++ b/lib/geometricPlane.cpp
@@ -1,14 +1,4 @@
#include "geometricPlane.h"
-#include "ray.h"
-#include <glm/geometric.hpp>
-#include <glm/gtx/intersect.hpp>
-
-GeometricPlane::PlaneRelation
-GeometricPlane::getRelation(Position3D p) const
-{
- const auto d = glm::dot(normal, p - origin);
- return d < 0.F ? PlaneRelation::Below : d > 0.F ? PlaneRelation::Above : PlaneRelation::On;
-}
bool
GeometricPlane::isIntersect(PlaneRelation a, PlaneRelation b)
@@ -16,13 +6,3 @@ GeometricPlane::isIntersect(PlaneRelation a, PlaneRelation b)
return ((a == PlaneRelation::Above && b == PlaneRelation::Below)
|| (a == PlaneRelation::Below && b == PlaneRelation::Above));
}
-
-std::optional<GeometricPlane::DistAndPosition>
-GeometricPlane::getRayIntersectPosition(const Ray & ray) const
-{
- float dist {};
- if (!glm::intersectRayPlane(ray.start, ray.direction, origin, normal, dist)) {
- return {};
- }
- return DistAndPosition {dist, ray.start + (ray.direction * dist)};
-}
diff --git a/lib/geometricPlane.h b/lib/geometricPlane.h
index c74beff..3f95d3c 100644
--- a/lib/geometricPlane.h
+++ b/lib/geometricPlane.h
@@ -1,24 +1,43 @@
#pragma once
#include "config/types.h"
+#include "ray.h"
+#include <glm/geometric.hpp>
+#include <glm/gtx/intersect.hpp>
#include <glm/vec3.hpp>
#include <optional>
-class Ray;
-
class GeometricPlane {
public:
+ enum class PlaneRelation { Above, Below, On };
+
+ static bool isIntersect(PlaneRelation a, PlaneRelation b);
+};
+
+template<typename PositionType> class GeometricPlaneT : public GeometricPlane {
+public:
struct DistAndPosition {
- float dist;
- Position3D position;
+ PositionType::value_type dist;
+ PositionType position;
};
- enum class PlaneRelation { Above, Below, On };
- Position3D origin;
+ PositionType origin;
Normal3D normal;
- [[nodiscard]] PlaneRelation getRelation(Position3D point) const;
- [[nodiscard]] std::optional<DistAndPosition> getRayIntersectPosition(const Ray &) const;
+ [[nodiscard]] inline PlaneRelation
+ getRelation(PositionType point) const
+ {
+ const auto d = glm::dot(normal, point - origin);
+ return d < 0.F ? PlaneRelation::Below : d > 0.F ? PlaneRelation::Above : PlaneRelation::On;
+ }
- static bool isIntersect(PlaneRelation a, PlaneRelation b);
+ [[nodiscard]] inline std::optional<DistAndPosition>
+ getRayIntersectPosition(const Ray<PositionType> & ray) const
+ {
+ float dist {};
+ if (!glm::intersectRayPlane(ray.start, ray.direction, origin, normal, dist)) {
+ return {};
+ }
+ return DistAndPosition {dist, ray.start + (ray.direction * dist)};
+ }
};
diff --git a/lib/maths.h b/lib/maths.h
index c1bf61a..b5af9ca 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -68,9 +68,9 @@ sq(T v)
return v * v;
}
-template<std::integral T, glm::qualifier Q>
-inline constexpr glm::vec<3, T, Q>
-crossInt(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b)
+template<glm::qualifier Q>
+inline constexpr glm::vec<3, int64_t, Q>
+crossProduct(const glm::vec<3, int64_t, Q> a, const glm::vec<3, int64_t, Q> b)
{
return {
(a.y * b.z) - (a.z * b.y),
@@ -79,6 +79,20 @@ crossInt(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b)
};
}
+template<std::integral T, glm::qualifier Q>
+inline constexpr glm::vec<3, T, Q>
+crossProduct(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b)
+{
+ return crossProduct<int64_t, Q>(a, b);
+}
+
+template<std::floating_point T, glm::qualifier Q>
+inline constexpr glm::vec<3, T, Q>
+crossProduct(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b)
+{
+ return glm::cross(a, b);
+}
+
template<typename R = float, typename Ta, typename Tb>
inline constexpr auto
ratio(Ta a, Tb b)
diff --git a/lib/ray.cpp b/lib/ray.cpp
deleted file mode 100644
index 9fb3648..0000000
--- a/lib/ray.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "ray.h"
-#include <algorithm>
-
-Ray
-Ray::fromPoints(Position3D start, Position3D p)
-{
- return {start, glm::normalize(p - start)};
-}
-
-float
-Ray::distanceToLine(const Position3D & p1, const Position3D & e1) const
-{
- // https://en.wikipedia.org/wiki/Skew_lines
- const auto diff = p1 - e1;
- const auto d1 = glm::normalize(diff);
- const auto &p2 = start, &d2 = direction;
- const auto n = glm::cross(d1, d2);
- const auto n2 = glm::cross(d2, n);
- const auto c1 = p1 + (glm::dot((p2 - p1), n2) / glm::dot(d1, n2)) * d1;
- const auto difflength = glm::length(diff);
- if (glm::length(c1 - p1) > difflength || glm::length(c1 - e1) > difflength) {
- return std::numeric_limits<float>::infinity();
- }
- return glm::abs(glm::dot(n, p1 - p2));
-}
-
-bool
-Ray::passesCloseToEdges(const std::span<const Position3D> positions, float distance) const
-{
- return std::adjacent_find(positions.begin(), positions.end(),
- [this, distance](const Position3D & a, const Position3D & b) {
- return distanceToLine(a, b) <= distance;
- })
- != positions.end();
-}
diff --git a/lib/ray.h b/lib/ray.h
index bc70c74..e1f43c3 100644
--- a/lib/ray.h
+++ b/lib/ray.h
@@ -1,20 +1,84 @@
#pragma once
#include "config/types.h"
+#include "maths.h"
+
+#include <algorithm>
#include <glm/glm.hpp>
+#include <glm/gtx/intersect.hpp>
#include <span>
-class Ray {
+template<typename PositionType> class Ray {
public:
#ifndef __cpp_aggregate_paren_init
- Ray(Position3D start, Direction3D direction) : start {start}, direction {direction} { }
+ Ray(PositionType start, Direction3D direction) : start {start}, direction {direction} { }
#endif
- static Ray fromPoints(Position3D, Position3D);
-
- Position3D start;
+ PositionType start;
Direction3D direction;
- [[nodiscard]] float distanceToLine(const Position3D & a, const Position3D & b) const;
- [[nodiscard]] bool passesCloseToEdges(const std::span<const Position3D> positions, float distance) const;
+ [[nodiscard]] PositionType::value_type
+ distanceToLine(const PositionType & p1, const PositionType & e1) const
+ {
+ // https://en.wikipedia.org/wiki/Skew_lines
+ const RelativePosition3D diff = p1 - e1;
+ const auto d1 = glm::normalize(diff);
+ const auto n = crossProduct(d1, direction);
+ const auto n2 = crossProduct(direction, n);
+ const auto c1 = p1 + PositionType((glm::dot(RelativePosition3D(start - p1), n2) / glm::dot(d1, n2)) * d1);
+ const auto difflength = glm::length(diff);
+ if (glm::length(RelativePosition3D(c1 - p1)) > difflength
+ || glm::length(RelativePosition3D(c1 - e1)) > difflength) {
+ return std::numeric_limits<typename PositionType::value_type>::infinity();
+ }
+ return static_cast<PositionType::value_type>(glm::abs(glm::dot(n, RelativePosition3D(p1 - start))));
+ }
+
+ [[nodiscard]] bool
+ passesCloseToEdges(const std::span<const PositionType> positions, const PositionType::value_type distance) const
+ {
+ return std::adjacent_find(positions.begin(), positions.end(), [this, distance](const auto & a, const auto & b) {
+ return distanceToLine(a, b) <= distance;
+ }) != positions.end();
+ }
+
+ bool
+ intersectTriangle(const PositionType t0, const PositionType t1, const PositionType t2, BaryPosition & bary,
+ RelativeDistance & distance) const
+ {
+ if constexpr (std::is_floating_point_v<typename PositionType::value_type>) {
+ return glm::intersectRayTriangle(start, direction, t0, t1, t2, bary, distance);
+ }
+ else {
+ const RelativePosition3D t0r = t0 - start, t1r = t1 - start, t2r = t2 - start;
+ return glm::intersectRayTriangle({}, direction, t0r, t1r, t2r, bary, distance);
+ }
+ }
+
+ bool
+ intersectSphere(const PositionType centre, const PositionType::value_type size, PositionType & position,
+ Normal3D & normal) const
+ {
+ if constexpr (std::is_floating_point_v<typename PositionType::value_type>) {
+ return glm::intersectRaySphere(start, direction, centre, size, position, normal);
+ }
+ else {
+ const RelativePosition3D cr = centre - start;
+ RelativePosition3D positionF {};
+ const auto r = glm::intersectRaySphere(
+ {}, direction, cr, static_cast<RelativeDistance>(size), positionF, normal);
+ position = GlobalPosition3D(positionF) + start;
+ return r;
+ }
+ }
+};
+
+class RayFactory {
+public:
+ template<typename PositionType>
+ static Ray<PositionType>
+ fromPoints(PositionType start, PositionType p)
+ {
+ return {start, glm::normalize(p - start)};
+ }
};
diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp
index d1c6b8b..efe845c 100644
--- a/test/test-geoData.cpp
+++ b/test/test-geoData.cpp
@@ -109,8 +109,8 @@ using FindRayIntersectData = std::tuple<GlobalPosition3D, Direction3D, GlobalPos
BOOST_DATA_TEST_CASE(findRayIntersect,
boost::unit_test::data::make<FindRayIntersectData>({
- {{310000000, 490000000, 50000}, {1, 1, -2}, {310008585, 490008585, 32834}},
- {{310000000, 490000000, 50000}, {1, 1, -1}, {310017136, 490017136, 32868}},
+ {{310000000, 490000000, 50000}, {1, 1, -2}, {310008582, 490008582, 32834}},
+ {{310000000, 490000000, 50000}, {1, 1, -1}, {310017131, 490017131, 32868}},
}),
p, d, i)
{
diff --git a/test/test-maths.cpp b/test/test-maths.cpp
index b363c17..8680409 100644
--- a/test/test-maths.cpp
+++ b/test/test-maths.cpp
@@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(camera_clicks)
Camera camera {{}, ::half_pi, 1.25F, 1000, 10000000};
constexpr float centre {0.5F}, right {0.9F}, left {0.1F}, top {1.F}, bottom {0.F};
camera.setForward(::north);
- BOOST_CHECK_EQUAL(camera.unProject({centre, centre}).start, RelativePosition3D {});
+ BOOST_CHECK_EQUAL(camera.unProject({centre, centre}).start, GlobalPosition3D {});
BOOST_CHECK_CLOSE_VEC(camera.unProject({centre, centre}).direction, ::north);
BOOST_CHECK_CLOSE_VEC(camera.unProject({left, centre}).direction, glm::normalize(::north + ::west));
BOOST_CHECK_CLOSE_VEC(camera.unProject({right, centre}).direction, glm::normalize(::north + ::east));
diff --git a/ui/builders/freeExtend.cpp b/ui/builders/freeExtend.cpp
index 1520421..47356c3 100644
--- a/ui/builders/freeExtend.cpp
+++ b/ui/builders/freeExtend.cpp
@@ -11,7 +11,8 @@ BuilderFreeExtend::hint() const
}
void
-BuilderFreeExtend::move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent &, const Ray & ray)
+BuilderFreeExtend::move(
+ Network * network, const GeoData * geoData, const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> & ray)
{
if (p1) {
if (const auto p = network->intersectRayNodes(ray)) {
@@ -30,7 +31,8 @@ BuilderFreeExtend::move(Network * network, const GeoData * geoData, const SDL_Mo
}
void
-BuilderFreeExtend::click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray & ray)
+BuilderFreeExtend::click(
+ Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> & ray)
{
switch (e.button) {
case SDL_BUTTON_LEFT:
diff --git a/ui/builders/freeExtend.h b/ui/builders/freeExtend.h
index b276426..127fdc6 100644
--- a/ui/builders/freeExtend.h
+++ b/ui/builders/freeExtend.h
@@ -6,8 +6,10 @@ class GeoData;
class BuilderFreeExtend : public EditNetwork::Builder {
std::string hint() const override;
- void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray & ray) override;
- void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e, const Ray & ray) override;
+ void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e,
+ const Ray<GlobalPosition3D> & ray) override;
+ void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e,
+ const Ray<GlobalPosition3D> & ray) override;
std::optional<Position3D> p1;
};
diff --git a/ui/builders/join.cpp b/ui/builders/join.cpp
index caa635f..7474c5b 100644
--- a/ui/builders/join.cpp
+++ b/ui/builders/join.cpp
@@ -11,7 +11,7 @@ BuilderJoin::hint() const
}
void
-BuilderJoin::move(Network * network, const GeoData *, const SDL_MouseMotionEvent &, const Ray & ray)
+BuilderJoin::move(Network * network, const GeoData *, const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> & ray)
{
if (p1) {
if (const auto p = network->intersectRayNodes(ray)) {
@@ -24,7 +24,8 @@ BuilderJoin::move(Network * network, const GeoData *, const SDL_MouseMotionEvent
}
void
-BuilderJoin::click(Network * network, const GeoData *, const SDL_MouseButtonEvent & e, const Ray & ray)
+BuilderJoin::click(
+ Network * network, const GeoData *, const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> & ray)
{
switch (e.button) {
case SDL_BUTTON_LEFT:
diff --git a/ui/builders/join.h b/ui/builders/join.h
index bb0bd4c..dd57895 100644
--- a/ui/builders/join.h
+++ b/ui/builders/join.h
@@ -6,8 +6,10 @@ class GeoData;
class BuilderJoin : public EditNetwork::Builder {
std::string hint() const override;
- void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray & ray) override;
- void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e, const Ray & ray) override;
+ void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e,
+ const Ray<GlobalPosition3D> & ray) override;
+ void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e,
+ const Ray<GlobalPosition3D> & ray) override;
void create(Network * network, const Node::Ptr & p1, const Node::Ptr & p2) const;
diff --git a/ui/builders/straight.cpp b/ui/builders/straight.cpp
index 9b262bb..866705a 100644
--- a/ui/builders/straight.cpp
+++ b/ui/builders/straight.cpp
@@ -11,7 +11,8 @@ BuilderStraight::hint() const
}
void
-BuilderStraight::move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent &, const Ray & ray)
+BuilderStraight::move(
+ Network * network, const GeoData * geoData, const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> & ray)
{
if (p1) {
if (const auto p = geoData->intersectRay(ray)) {
@@ -24,7 +25,8 @@ BuilderStraight::move(Network * network, const GeoData * geoData, const SDL_Mous
}
void
-BuilderStraight::click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray & ray)
+BuilderStraight::click(
+ Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> & ray)
{
switch (e.button) {
case SDL_BUTTON_LEFT:
diff --git a/ui/builders/straight.h b/ui/builders/straight.h
index cf99a1d..63f9a40 100644
--- a/ui/builders/straight.h
+++ b/ui/builders/straight.h
@@ -6,8 +6,10 @@ class GeoData;
class BuilderStraight : public EditNetwork::Builder {
std::string hint() const override;
- void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e, const Ray & ray) override;
- void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e, const Ray & ray) override;
+ void click(Network * network, const GeoData * geoData, const SDL_MouseButtonEvent & e,
+ const Ray<GlobalPosition3D> & ray) override;
+ void move(Network * network, const GeoData * geoData, const SDL_MouseMotionEvent & e,
+ const Ray<GlobalPosition3D> & ray) override;
void create(Network * network, Position3D p1, Position3D p2) const;
diff --git a/ui/editNetwork.cpp b/ui/editNetwork.cpp
index 754053b..7fbde32 100644
--- a/ui/editNetwork.cpp
+++ b/ui/editNetwork.cpp
@@ -22,7 +22,7 @@ EditNetwork::EditNetwork(Network * n) :
}
bool
-EditNetwork::click(const SDL_MouseButtonEvent & e, const Ray & ray)
+EditNetwork::click(const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> & ray)
{
if (builder && (e.button == SDL_BUTTON_LEFT || e.button == SDL_BUTTON_MIDDLE)) {
builder->click(network, gameState->geoData.get(), e, ray);
@@ -32,7 +32,7 @@ EditNetwork::click(const SDL_MouseButtonEvent & e, const Ray & ray)
}
bool
-EditNetwork::move(const SDL_MouseMotionEvent & e, const Ray & ray)
+EditNetwork::move(const SDL_MouseMotionEvent & e, const Ray<GlobalPosition3D> & ray)
{
if (builder) {
builder->move(network, gameState->geoData.get(), e, ray);
diff --git a/ui/editNetwork.h b/ui/editNetwork.h
index e1aaa61..c8a2f13 100644
--- a/ui/editNetwork.h
+++ b/ui/editNetwork.h
@@ -9,14 +9,14 @@
#include <gfx/models/texture.h>
#include <optional>
-class Ray;
+template<typename> class Ray;
class EditNetwork : public GameMainSelector::Component, public WorldOverlay {
public:
explicit EditNetwork(Network *);
- bool click(const SDL_MouseButtonEvent & e, const Ray &) override;
- bool move(const SDL_MouseMotionEvent & e, const Ray &) override;
+ bool click(const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> &) override;
+ bool move(const SDL_MouseMotionEvent & e, const Ray<GlobalPosition3D> &) override;
bool handleInput(const SDL_Event & e, const UIComponent::Position &) override;
void render(const SceneShader &) const override;
void render(const UIShader & shader, const UIComponent::Position & pos) const override;
@@ -28,8 +28,8 @@ public:
virtual ~Builder() = default;
virtual void render(const SceneShader & shader) const;
virtual std::string hint() const = 0;
- virtual void click(Network *, const GeoData *, const SDL_MouseButtonEvent &, const Ray &) = 0;
- virtual void move(Network *, const GeoData *, const SDL_MouseMotionEvent &, const Ray &) = 0;
+ virtual void click(Network *, const GeoData *, const SDL_MouseButtonEvent &, const Ray<GlobalPosition3D> &) = 0;
+ virtual void move(Network *, const GeoData *, const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> &) = 0;
using Ptr = std::unique_ptr<Builder>;
diff --git a/ui/gameMainSelector.cpp b/ui/gameMainSelector.cpp
index 703cfab..a577838 100644
--- a/ui/gameMainSelector.cpp
+++ b/ui/gameMainSelector.cpp
@@ -71,7 +71,7 @@ GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos)
}
void
-GameMainSelector::defaultClick(const Ray & ray)
+GameMainSelector::defaultClick(const Ray<GlobalPosition3D> & ray)
{
BaryPosition baryPos {};
RelativeDistance distance {};
@@ -90,13 +90,13 @@ GameMainSelector::defaultClick(const Ray & ray)
}
bool
-GameMainSelector::Component::click(const SDL_MouseButtonEvent &, const Ray &)
+GameMainSelector::Component::click(const SDL_MouseButtonEvent &, const Ray<GlobalPosition3D> &)
{
return false;
}
bool
-GameMainSelector::Component::move(const SDL_MouseMotionEvent &, const Ray &)
+GameMainSelector::Component::move(const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> &)
{
return false;
}
diff --git a/ui/gameMainSelector.h b/ui/gameMainSelector.h
index 88db34b..cc30707 100644
--- a/ui/gameMainSelector.h
+++ b/ui/gameMainSelector.h
@@ -10,7 +10,7 @@
#include <string>
class SceneShader;
-class Ray;
+template<typename> class Ray;
class UIShader;
class Camera;
@@ -20,8 +20,8 @@ public:
public:
virtual ~Component() = default;
- virtual bool click(const SDL_MouseButtonEvent &, const Ray &);
- virtual bool move(const SDL_MouseMotionEvent &, const Ray &);
+ virtual bool click(const SDL_MouseButtonEvent &, const Ray<GlobalPosition3D> &);
+ virtual bool move(const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> &);
virtual bool handleInput(const SDL_Event &, const Position & pos);
virtual void render(const UIShader & shader, const Position & pos) const;
virtual void render(const SceneShader &) const;
@@ -34,7 +34,7 @@ public:
bool handleInput(const SDL_Event & e, const Position &) override;
- void defaultClick(const Ray & ray);
+ void defaultClick(const Ray<GlobalPosition3D> & ray);
std::unique_ptr<Component> target;