Updated geometry functions to use Eigen instead of custom Celestia vector

and matrix classes.
sensor-dev
Chris Laurel 2009-07-15 01:05:51 +00:00
parent e2f6953dd2
commit 2427fb8e81
7 changed files with 295 additions and 179 deletions

View File

@ -30,11 +30,12 @@ template<class T> T distance(const Point3<T>& p, const Ellipsoid<T>& e)
template<class T> T distance(const Point3<T>& p, const Ray3<T>& r)
{
T t = ((p - r.origin) * r.direction) / (r.direction * r.direction);
Eigen::Matrix<T, 3, 1> p2(p.x, p.y, p.z);
T t = ((p2 - r.origin).dot(r.direction)) / r.direction.squaredNorm();
if (t <= 0)
return p.distanceTo(r.origin);
return (p2 - r.origin).norm();
else
return p.distanceTo(r.point(t));
return (p2 - r.point(t)).norm();
}
// Distance between a point and a segment defined by orig+dir*t, 0 <= t <= 1

View File

@ -11,57 +11,88 @@
#define _CELMATH_ELLIPSOID_H_
#include "vecmath.h"
#include <Eigen/Core>
template<class T> class Ellipsoid
{
public:
Ellipsoid();
Ellipsoid(const Vector3<T>&);
Ellipsoid(const Point3<T>&, const Vector3<T>&);
bool contains(const Point3<T>& p) const;
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
/*! Default Ellipsoid constructor. Create a unit sphere centered
* at the origin.
*/
Ellipsoid() :
center(0, 0, 0),
axes(1, 1, 1)
{
}
/*! Created an ellipsoid with the specified semiaxes, centered
* at the origin.
*/
Ellipsoid(const Eigen::Matrix<T, 3, 1>& _axes) :
center(0, 0, 0),
axes(_axes)
{
}
/*! Create an ellipsoid with the specified center and semiaxes.
*/
Ellipsoid(const Eigen::Matrix<T, 3, 1>& _center,
const Eigen::Matrix<T, 3, 1>& _axes) :
center(_center),
axes(_axes)
{
}
/*! Test whether the point p lies inside the ellipsoid.
*/
bool contains(const Eigen::Matrix<T, 3, 1>& p) const
{
Eigen::Matrix<T, 3, 1> v = p - center;
v = v.cwise() / axes;
return v * v <= (T) 1.0;
}
/**** Compatibility with old Celestia vectors ****/
/*! Created an ellipsoid with the specified semiaxes, centered
* at the origin.
*/
Ellipsoid(const Vector3<T>& _axes) :
center(0, 0, 0),
axes(_axes.x, _axes.y, _axes.z)
{
}
/*! Create an ellipsoid with the specified center and semiaxes.
*/
Ellipsoid(const Point3<T>& _center,
const Vector3<T>& _axes) :
center(_center.x, _center.y, _center.z),
axes(_axes.x, _axes.y, _axes.z)
{
}
/*! Test whether the point p lies inside the ellipsoid.
*/
bool contains(const Point3<T>& p) const
{
Vector3<T> v = p - center;
v = Vector3<T>(v.x / axes.x, v.y / axes.y, v.z / axes.z);
return v * v <= (T) 1.0;
}
public:
Point3<T> center;
Vector3<T> axes;
Eigen::Matrix<T, 3, 1> center;
Eigen::Matrix<T, 3, 1> axes;
};
typedef Ellipsoid<float> Ellipsoidf;
typedef Ellipsoid<double> Ellipsoidd;
/*! Default Ellipsoid constructor. Create a unit sphere centered
* at the origin.
*/
template<class T> Ellipsoid<T>::Ellipsoid() :
center(0, 0, 0), axes(1, 1, 1)
{
}
/*! Created an ellipsoid with the specified semiaxes, centered
* at the origin.
*/
template<class T> Ellipsoid<T>::Ellipsoid(const Vector3<T>& _axes) :
center(0, 0, 0), axes(_axes)
{
}
/*! Create an ellipsoid with the specified center and semiaxes.
*/
template<class T> Ellipsoid<T>::Ellipsoid(const Point3<T>& _center,
const Vector3<T>& _axes) :
center(_center), axes(_axes)
{
}
/*! Test whether the point p lies inside the ellipsoid.
*/
template<class T> bool Ellipsoid<T>::contains(const Point3<T>& p) const
{
Vector3<T> v = p - center;
v = Vector3<T>(v.x / axes.x, v.y / axes.y, v.z / axes.z);
return v * v <= (T) 1.0;
}
#endif // _CELMATH_ELLIPSOID_H_

View File

@ -8,6 +8,10 @@
// of the License, or (at your option) any later version.
#include "frustum.h"
#include <Eigen/LU>
#include <cmath>
using namespace Eigen;
Frustum::Frustum(float fov, float aspectRatio, float n) :
@ -26,68 +30,97 @@ Frustum::Frustum(float fov, float aspectRatio, float n, float f) :
void Frustum::init(float fov, float aspectRatio, float n, float f)
{
float h = (float) tan(fov / 2.0f);
float h = std::tan(fov / 2.0f);
float w = h * aspectRatio;
Vec3f normals[4];
normals[Bottom] = Vec3f(0, 1, -h);
normals[Top] = Vec3f(0, -1, -h);
normals[Left] = Vec3f(1, 0, -w);
normals[Right] = Vec3f(-1, 0, -w);
for (int i = 0; i < 4; i++)
Vector3f normals[4];
normals[Bottom] = Vector3f( 0.0f, 1.0f, -h);
normals[Top] = Vector3f( 0.0f, -1.0f, -h);
normals[Left] = Vector3f( 1.0f, 0.0f, -w);
normals[Right] = Vector3f(-1.0f, 0.0f, -w);
for (unsigned int i = 0; i < 4; i++)
{
normals[i].normalize();
planes[i] = Planef(normals[i], Point3f(0, 0, 0));
planes[i] = Hyperplane<float, 3>(normals[i].normalized(), 0.0f);
}
planes[Near] = Planef(Vec3f(0, 0, -1), -n);
planes[Far] = Planef(Vec3f(0, 0, 1), f);
planes[Near] = Hyperplane<float, 3>(Vector3f(0.0f, 0.0f, -1.0f), -n);
planes[Far] = Hyperplane<float, 3>(Vector3f(0.0f, 0.0f, 1.0f), f);
}
Frustum::Aspect
Frustum::test(const Eigen::Vector3f& point) const
{
unsigned int nPlanes = infinite ? 5 : 6;
for (unsigned int i = 0; i < nPlanes; i++)
{
if (planes[i].signedDistance(point) < 0.0f)
return Outside;
}
return Inside;
}
Frustum::Aspect
Frustum::testSphere(const Eigen::Vector3f& center, float radius) const
{
unsigned int nPlanes = infinite ? 5 : 6;
unsigned int intersections = 0;
for (unsigned int i = 0; i < nPlanes; i++)
{
float distanceToPlane = planes[i].signedDistance(center);
if (distanceToPlane < -radius)
return Outside;
else if (distanceToPlane <= radius)
intersections |= (1 << i);
}
return (intersections == 0) ? Inside : Intersect;
}
/** Double precision version of testSphere()
*/
Frustum::Aspect
Frustum::testSphere(const Eigen::Vector3d& center, double radius) const
{
int nPlanes = infinite ? 5 : 6;
int intersections = 0;
// IMPORTANT: Celestia relies on this calculation being peformed at double
// precision. Simply converting center to single precision is NOT an
// allowable optimization.
for (int i = 0; i < nPlanes; i++)
{
double distanceToPlane = planes[i].cast<double>().signedDistance(center);
if (distanceToPlane < -radius)
return Outside;
else if (distanceToPlane <= radius)
intersections |= (1 << i);
}
return (intersections == 0) ? Inside : Intersect;
}
Frustum::Aspect Frustum::test(const Point3f& p) const
{
return testSphere(p, 0);
return testSphere(Eigen::Vector3f(p.x, p.y, p.z), 0.0f);
}
Frustum::Aspect Frustum::testSphere(const Point3f& center, float radius) const
{
int nPlanes = infinite ? 5 : 6;
int intersections = 0;
for (int i = 0; i < nPlanes; i++)
{
float distanceToPlane = planes[i].distanceTo(center);
if (distanceToPlane < -radius)
return Outside;
else if (distanceToPlane <= radius)
intersections |= (1 << i);
}
return (intersections == 0) ? Inside : Intersect;
return testSphere(Eigen::Vector3f(center.x, center.y, center.z), radius);
}
Frustum::Aspect Frustum::testSphere(const Point3d& center, double radius) const
{
int nPlanes = infinite ? 5 : 6;
int intersections = 0;
for (int i = 0; i < nPlanes; i++)
{
//TODO: Celestia should incorporate some casting operators overloading to accommodate all this kind of stuff:
Vec3f plNormal = planes[i].normal;
Vec3d plNormalDbl(plNormal.x, plNormal.y, plNormal.z);
double distanceToPlane = plNormalDbl.x * center.x + plNormalDbl.y * center.y + plNormalDbl.z * center.z + planes[i].d;
if (distanceToPlane < -radius)
return Outside;
else if (distanceToPlane <= radius)
intersections |= (1 << i);
}
return (intersections == 0) ? Inside : Intersect;
return testSphere(Eigen::Vector3d(center.x, center.y, center.z), radius);
}
@ -97,10 +130,15 @@ Frustum::Aspect Frustum::testCapsule(const Capsulef& capsule) const
int intersections = 0;
float r2 = capsule.radius * capsule.radius;
// TODO: Unnecessary after Eigen conversion of Capsule class
Vector3f capsuleOrigin(capsule.origin.x, capsule.origin.y, capsule.origin.z);
Vector3f capsuleAxis(capsule.axis.x, capsule.axis.y, capsule.axis.z);
for (int i = 0; i < nPlanes; i++)
{
float signedDist0 = planes[i].normal * Vec3f(capsule.origin.x, capsule.origin.y, capsule.origin.z) + planes[i].d;
float signedDist1 = signedDist0 + planes[i].normal * capsule.axis;
float signedDist0 = planes[i].signedDistance(capsuleOrigin);
float signedDist1 = planes[i].signedDistance(capsuleOrigin + capsuleAxis);
//float signedDist1 = signedDist0 + planes[i].normal * capsule.axis;
if (signedDist0 * signedDist1 > r2)
{
// Endpoints of capsule are on same side of plane; test closest endpoint to see if it
@ -125,58 +163,58 @@ Frustum::Aspect Frustum::testCapsule(const Capsulef& capsule) const
// Capsule endpoints are on different sides of the plane, so we have an intersection
intersections |= (1 << i);
}
#if 0
Vec3f plNormal = planes[i].normal;
Vec3d plNormalDbl(plNormal.x, plNormal.y, plNormal.z);
double distanceToPlane = planes[i].distanceToSegment(capsule.origin, capsule.axis);
if (distanceToPlane < -capsule.radius)
return Outside;
else if (distanceToPlane <= capsule.radius)
intersections |= (1 << i);
#endif
}
return (intersections == 0) ? Inside : Intersect;
}
#if 0
// See if the half space defined by the plane intersects the frustum. For the
// plane equation p(x, y, z) = ax + by + cz + d = 0, the halfspace is
// contains all points p(x, y, z) < 0.
Frustum::Aspect Frustum::testHalfSpace(const Planef& plane)
void
Frustum::transform(const Matrix3f& m)
{
return Intersect;
}
#endif
unsigned int nPlanes = infinite ? 5 : 6;
void Frustum::transform(const Mat3f& m)
{
int nPlanes = infinite ? 5 : 6;
Mat3f invTranspose = m.inverse().transpose();
for (int i = 0; i < nPlanes; i++)
for (unsigned int i = 0; i < nPlanes; i++)
{
planes[i] = planes[i] * invTranspose;
float s = 1.0f / planes[i].normal.length();
planes[i].normal = planes[i].normal * s;
planes[i].d *= s;
planes[i] = planes[i].transform(m, Eigen::Isometry);
}
}
void Frustum::transform(const Mat4f& m)
void
Frustum::transform(const Matrix4f& m)
{
int nPlanes = infinite ? 5 : 6;
Mat4f invTranspose = m.inverse().transpose();
unsigned int nPlanes = infinite ? 5 : 6;
Matrix4f invTranspose = m.inverse().transpose();
for (int i = 0; i < nPlanes; i++)
for (unsigned int i = 0; i < nPlanes; i++)
{
planes[i] = planes[i] * invTranspose;
float s = 1.0f / planes[i].normal.length();
planes[i].normal = planes[i].normal * s;
planes[i].d *= s;
planes[i].coeffs() = invTranspose * planes[i].coeffs();
planes[i].normalize();
//float s = 1.0f / planes[i].normal().norm();
//planes[i].normal() *= s;
//planes[i].offset() *= s;
//planes[i] = planes[i] * invTranspose;
//float s = 1.0f / planes[i].normal().norm();
//planes[i].normal = planes[i].normal * s;
//planes[i].d *= s;
}
}
void
Frustum::transform(const Mat3f& m)
{
Matrix3f m2 = Map<Matrix3f>(&m[0][0]);
transform(m2);
}
void
Frustum::transform(const Mat4f& m)
{
Matrix4f m2 = Map<Matrix4f>(&m[0][0]);
transform(m2);
}

View File

@ -10,20 +10,32 @@
#ifndef _CELMATH_FRUSTUM_H_
#define _CELMATH_FRUSTUM_H_
#include <Eigen/Core>
#include <Eigen/Geometry>
// Compatibility
#include <celmath/plane.h>
#include <celmath/capsule.h>
class Frustum
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
typedef Eigen::Hyperplane<float, 3> PlaneType;
Frustum(float fov, float aspectRatio, float nearDist);
Frustum(float fov, float aspectRatio, float nearDist, float farDist);
void transform(const Mat3f&);
void transform(const Mat4f&);
inline Eigen::Hyperplane<float, 3> plane(unsigned int which) const
{
return planes[which];
}
inline Planef getPlane(int) const;
void transform(const Eigen::Matrix3f& m);
void transform(const Eigen::Matrix4f& m);
enum {
Bottom = 0,
@ -40,21 +52,28 @@ class Frustum
Intersect = 2,
};
Aspect test(const Eigen::Vector3f& point) const;
Aspect testSphere(const Eigen::Vector3f& center, float radius) const;
Aspect testSphere(const Eigen::Vector3d& center, double radius) const;
Aspect testCapsule(const Capsulef&) const;
// Compatibility
inline Planef getPlane(unsigned int which) const
{
PlaneType p = plane(which);
return Planef(Vec3f(p.coeffs().x(), p.coeffs().y(), p.coeffs().z()), p.coeffs().w());
}
void transform(const Mat3f&);
void transform(const Mat4f&);
Aspect test(const Point3f&) const;
Aspect testSphere(const Point3f& center, float radius) const;
Aspect testSphere(const Point3d& center, double radius) const;
Aspect testCapsule(const Capsulef&) const;
private:
void init(float, float, float, float);
Planef planes[6];
Eigen::Hyperplane<float, 3> planes[6];
bool infinite;
};
Planef Frustum::getPlane(int which) const
{
return planes[which];
}
#endif // _CELMATH_FRUSTUM_H_

View File

@ -15,17 +15,19 @@
#include "ray.h"
#include "sphere.h"
#include "ellipsoid.h"
#include <Eigen/Core>
#include <Eigen/Array>
template<class T> bool testIntersection(const Ray3<T>& ray,
const Sphere<T>& sphere,
T& distance)
{
Vector3<T> diff = ray.origin - sphere.center;
Eigen::Matrix<T, 3, 1> diff = ray.origin - sphere.center;
T s = (T) 1.0 / square(sphere.radius);
T a = ray.direction * ray.direction * s;
T b = ray.direction * diff * s;
T c = diff * diff * s - (T) 1.0;
T a = ray.direction.squaredNorm() * s;
T b = ray.direction.dot(diff) * s;
T c = diff.squaredNorm() * s - (T) 1.0;
T disc = b * b - a * c;
if (disc < 0.0)
return false;
@ -61,7 +63,7 @@ template<class T> bool testIntersection(const Ray3<T>& ray,
{
if (testIntersection(ray, sphere, distanceToTester))
{
cosAngleToCenter = (sphere.center - ray.origin)*ray.direction/(sphere.center - ray.origin).length();
cosAngleToCenter = (sphere.center - ray.origin).dot(ray.direction) / (sphere.center - ray.origin).norm();
return true;
}
return false;
@ -72,17 +74,13 @@ template<class T> bool testIntersection(const Ray3<T>& ray,
const Ellipsoid<T>& e,
T& distance)
{
Vector3<T> diff = ray.origin - e.center;
Vector3<T> s((T) 1.0 / square(e.axes.x),
(T) 1.0 / square(e.axes.y),
(T) 1.0 / square(e.axes.z));
Vector3<T> sdir(ray.direction.x * s.x,
ray.direction.y * s.y,
ray.direction.z * s.z);
Vector3<T> sdiff(diff.x * s.x, diff.y * s.y, diff.z * s.z);
T a = ray.direction * sdir;
T b = ray.direction * sdiff;
T c = diff * sdiff - (T) 1.0;
Eigen::Matrix<T, 3, 1> diff = ray.origin - e.center;
Eigen::Matrix<T, 3, 1> s = e.axes.cwise().inverse().cwise().square();
Eigen::Matrix<T, 3, 1> sdir = ray.direction.cwise() * s;
Eigen::Matrix<T, 3, 1> sdiff = diff.cwise() * s;
T a = ray.direction.dot(sdir);
T b = ray.direction.dot(sdiff);
T c = diff.dot(sdiff) - (T) 1.0;
T disc = b * b - a * c;
if (disc < 0.0)
return false;
@ -118,7 +116,7 @@ template<class T> bool testIntersection(const Ray3<T>& ray,
{
if (testIntersection(ray, ellipsoid, distanceToTester))
{
cosAngleToCenter = (ellipsoid.center - ray.origin)*ray.direction/(ellipsoid.center - ray.origin).length();
cosAngleToCenter = (ellipsoid.center - ray.origin).dot(ray.direction) / (ellipsoid.center - ray.origin).norm();
return true;
}
return false;

View File

@ -11,18 +11,28 @@
#define _CELMATH_RAY_H_
#include "vecmath.h"
#include <Eigen/Core>
template<class T> class Ray3
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Ray3();
Ray3(const Eigen::Matrix<T, 3, 1>& origin, const Eigen::Matrix<T, 3, 1>& direction);
// Compatibility
Ray3(const Point3<T>&, const Vector3<T>&);
Point3<T> point(T) const;
Eigen::Matrix<T, 3, 1> point(T) const;
Ray3<T> transform(const Eigen::Matrix<T, 3, 3>& m)
{
return Ray3<T>(m * origin, m * direction);
}
public:
Point3<T> origin;
Vector3<T> direction;
Eigen::Matrix<T, 3, 1> origin;
Eigen::Matrix<T, 3, 1> direction;
};
typedef Ray3<float> Ray3f;
@ -34,26 +44,37 @@ template<class T> Ray3<T>::Ray3() :
{
}
template<class T> Ray3<T>::Ray3(const Point3<T>& _origin,
const Vector3<T>& _direction) :
template<class T> Ray3<T>::Ray3(const Eigen::Matrix<T, 3, 1>& _origin,
const Eigen::Matrix<T, 3, 1>& _direction) :
origin(_origin), direction(_direction)
{
}
template<class T> Point3<T> Ray3<T>::point(T t) const
// Compatibility
template<class T> Ray3<T>::Ray3(const Point3<T>& _origin,
const Vector3<T>& _direction) :
origin(_origin.x, _origin.y, _origin.z),
direction(_direction.x, _direction.y, _direction.z)
{
}
template<class T> Eigen::Matrix<T, 3, 1> Ray3<T>::point(T t) const
{
return origin + direction * t;
}
// Compatibility
template<class T> Ray3<T> operator*(const Ray3<T>& r, const Matrix3<T>& m)
{
return Ray3<T>(r.origin * m, r.direction * m);
Eigen::Map<Eigen::Matrix<T, 3, 3> > m2(&m[0][0]);
return Ray3<T>(m2 * r.origin, m2 * r.direction);
}
// Compatibility
template<class T> Ray3<T> operator*(const Ray3<T>& r, const Matrix4<T>& m)
{
return Ray3<T>(r.origin * m, r.direction * m);
Eigen::Map<Eigen::Matrix<T, 4, 4> > m2(&m[0][0]);
return Ray3<T>(m2 * r.origin, m2 * r.direction);
}
#endif // _CELMATH_RAY_H_

View File

@ -11,37 +11,45 @@
#define _CELMATH_SPHERE_H_
#include "vecmath.h"
#include <Eigen/Core>
template<class T> class Sphere
{
public:
Sphere();
Sphere(T);
Sphere(const Point3<T>&, T);
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Sphere() :
center(0, 0, 0),
radius(1)
{
}
Sphere(T _radius) :
center(0, 0, 0),
radius(_radius)
{
}
Sphere(const Eigen::Matrix<T, 3, 1> _center, T _radius) :
center(_center),
radius(_radius)
{
}
// Compatibility
Sphere(const Point3<T>& _center, T _radius) :
center(_center.x, _center.y, _center.z),
radius(_radius)
{
}
public:
Point3<T> center;
Eigen::Matrix<T, 3, 1> center;
T radius;
};
typedef Sphere<float> Spheref;
typedef Sphere<double> Sphered;
template<class T> Sphere<T>::Sphere() :
center(0, 0, 0), radius(1)
{
}
template<class T> Sphere<T>::Sphere(T _radius) :
center(0, 0, 0), radius(_radius)
{
}
template<class T> Sphere<T>::Sphere(const Point3<T>& _center, T _radius) :
center(_center), radius(_radius)
{
}
#endif // _CELMATH_SPHERE_H_