Added geometry primitives
This commit is contained in:
parent
91cd564c59
commit
2b3ecc7e35
20 changed files with 840 additions and 0 deletions
79
src/basics/CappedCylinder.cpp
Normal file
79
src/basics/CappedCylinder.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#include "CappedCylinder.h"
|
||||||
|
|
||||||
|
#include "Vector3.h"
|
||||||
|
#include "PackStream.h"
|
||||||
|
|
||||||
|
CappedCylinder::CappedCylinder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CappedCylinder::CappedCylinder(const Vector3 &base, const Vector3 &direction, double radius, double length):
|
||||||
|
InfiniteCylinder(InfiniteRay(base, direction), radius), length(length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CappedCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const
|
||||||
|
{
|
||||||
|
// TODO Apply the caps
|
||||||
|
int count = InfiniteCylinder::checkRayIntersection(ray, first_intersection, second_intersection);
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (count == 2)
|
||||||
|
{
|
||||||
|
if (checkPointProjection(first_intersection))
|
||||||
|
{
|
||||||
|
if (checkPointProjection(second_intersection))
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (checkPointProjection(second_intersection))
|
||||||
|
{
|
||||||
|
*first_intersection = *second_intersection;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // count == 1
|
||||||
|
{
|
||||||
|
if (checkPointProjection(first_intersection))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CappedCylinder::checkPointProjection(Vector3 *point) const
|
||||||
|
{
|
||||||
|
double proj_length = axis.getDirection().dotProduct(point->sub(axis.getOrigin()));
|
||||||
|
return 0.0 <= proj_length && proj_length <= length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CappedCylinder::save(PackStream *stream) const
|
||||||
|
{
|
||||||
|
InfiniteCylinder::save(stream);
|
||||||
|
stream->write(&length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CappedCylinder::load(PackStream *stream)
|
||||||
|
{
|
||||||
|
InfiniteCylinder::load(stream);
|
||||||
|
stream->read(&length);
|
||||||
|
}
|
42
src/basics/CappedCylinder.h
Normal file
42
src/basics/CappedCylinder.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef CAPPEDCYLINDER_H
|
||||||
|
#define CAPPEDCYLINDER_H
|
||||||
|
|
||||||
|
#include "basics_global.h"
|
||||||
|
|
||||||
|
#include "InfiniteCylinder.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace basics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geometric cylinder, with capped ends (not infinite).
|
||||||
|
*/
|
||||||
|
class BASICSSHARED_EXPORT CappedCylinder: public InfiniteCylinder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CappedCylinder();
|
||||||
|
CappedCylinder(const Vector3 &base, const Vector3 &direction, double radius, double length);
|
||||||
|
|
||||||
|
inline double getLength() const {return length;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the intersection between the cylinder and an infinite ray.
|
||||||
|
*/
|
||||||
|
int checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a point projects in the length of the finite cylinder.
|
||||||
|
*/
|
||||||
|
bool checkPointProjection(Vector3 *point) const;
|
||||||
|
|
||||||
|
virtual void save(PackStream *stream) const override;
|
||||||
|
virtual void load(PackStream *stream) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double length;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CAPPEDCYLINDER_H
|
43
src/basics/Disk.cpp
Normal file
43
src/basics/Disk.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include "Disk.h"
|
||||||
|
|
||||||
|
#include "PackStream.h"
|
||||||
|
|
||||||
|
Disk::Disk()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Disk::Disk(const Vector3 &point, const Vector3 &normal, double radius):
|
||||||
|
InfinitePlane(point, normal), radius(radius)
|
||||||
|
{
|
||||||
|
radius2 = radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Disk::checkRayIntersection(const InfiniteRay &ray, Vector3 *intersection) const
|
||||||
|
{
|
||||||
|
int result = InfinitePlane::checkRayIntersection(ray, intersection);
|
||||||
|
|
||||||
|
if (result == 1)
|
||||||
|
{
|
||||||
|
Vector3 v = intersection->sub(getPoint());
|
||||||
|
double d2 = v.dotProduct(v);
|
||||||
|
return (d2 <= radius2) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disk::save(PackStream *stream) const
|
||||||
|
{
|
||||||
|
InfinitePlane::save(stream);
|
||||||
|
stream->write(&radius);
|
||||||
|
stream->write(&radius2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disk::load(PackStream *stream)
|
||||||
|
{
|
||||||
|
InfinitePlane::load(stream);
|
||||||
|
stream->read(&radius);
|
||||||
|
stream->read(&radius2);
|
||||||
|
}
|
42
src/basics/Disk.h
Normal file
42
src/basics/Disk.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef DISK_H
|
||||||
|
#define DISK_H
|
||||||
|
|
||||||
|
#include "basics_global.h"
|
||||||
|
|
||||||
|
#include "InfinitePlane.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace basics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geometric plane disk.
|
||||||
|
*/
|
||||||
|
class BASICSSHARED_EXPORT Disk: public InfinitePlane
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Disk();
|
||||||
|
Disk(const Vector3 &point, const Vector3 &normal, double radius);
|
||||||
|
|
||||||
|
inline double getRadius() const {return radius;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the intersection between the disk and an infinite ray.
|
||||||
|
*
|
||||||
|
* Returns the number of intersections (0, 1), and fill the intersection point.
|
||||||
|
*
|
||||||
|
* Returns -1 if the ray shares a segment with the disk.
|
||||||
|
*/
|
||||||
|
int checkRayIntersection(const InfiniteRay& ray, Vector3 *intersection) const;
|
||||||
|
|
||||||
|
void save(PackStream *stream) const override;
|
||||||
|
void load(PackStream *stream) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double radius;
|
||||||
|
double radius2;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DISK_H
|
149
src/basics/InfiniteCylinder.cpp
Normal file
149
src/basics/InfiniteCylinder.cpp
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#include "InfiniteCylinder.h"
|
||||||
|
|
||||||
|
#include "PackStream.h"
|
||||||
|
|
||||||
|
#define EPS 1E-8
|
||||||
|
|
||||||
|
InfiniteCylinder::InfiniteCylinder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InfiniteCylinder::InfiniteCylinder(const InfiniteRay &axis, double radius):
|
||||||
|
axis(axis), radius(radius)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int InfiniteCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Original algorithm has been altered, because it didn't work with non-(0,0,0) axis origin.
|
||||||
|
* Maybe some optimizations could be made from this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Vector3 U, V, F = axis.getDirection(), P, B, Q, G, AG, AQ;
|
||||||
|
double length, invLength, prod;
|
||||||
|
double R[3][3], A[3][3];
|
||||||
|
double e0, e1, C, c0, c1, c2, discr, invC2, root0, root1, root;
|
||||||
|
|
||||||
|
/* choose U, V so that U,V,F is orthonormal set */
|
||||||
|
|
||||||
|
if ( fabs(F.x) > fabs(F.y) && fabs(F.x) > fabs(F.z) )
|
||||||
|
{
|
||||||
|
length = sqrt(F.x*F.x+F.y*F.y);
|
||||||
|
invLength = 1.0/length;
|
||||||
|
U.x = -F.y*invLength;
|
||||||
|
U.y = +F.x*invLength;
|
||||||
|
U.z = 0.0;
|
||||||
|
prod = -F.z*invLength;
|
||||||
|
V.x = F.x*prod;
|
||||||
|
V.y = F.y*prod;
|
||||||
|
V.z = length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
length = sqrt(F.y*F.y+F.z*F.z);
|
||||||
|
invLength = 1.0/length;
|
||||||
|
U.x = 0.0;
|
||||||
|
U.y = -F.z*invLength;
|
||||||
|
U.z = +F.y*invLength;
|
||||||
|
prod = -F.x*invLength;
|
||||||
|
V.x = length;
|
||||||
|
V.y = F.y*prod;
|
||||||
|
V.z = F.z*prod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* orthonormal matrix */
|
||||||
|
R[0][0] = U.x; R[0][1] = U.y; R[0][2] = U.z;
|
||||||
|
R[1][0] = V.x; R[1][1] = V.y; R[1][2] = V.z;
|
||||||
|
R[2][0] = F.x; R[2][1] = F.y; R[2][2] = F.z;
|
||||||
|
|
||||||
|
/* matrix A */
|
||||||
|
A[0][0] = R[0][0]*R[0][0]+R[1][0]*R[1][0];
|
||||||
|
A[0][1] = R[0][0]*R[0][1]+R[1][0]*R[1][1];
|
||||||
|
A[0][2] = R[0][0]*R[0][2]+R[1][0]*R[1][2];
|
||||||
|
|
||||||
|
A[1][0] = R[0][1]*R[0][0]+R[1][1]*R[1][0];
|
||||||
|
A[1][1] = R[0][1]*R[0][1]+R[1][1]*R[1][1];
|
||||||
|
A[1][2] = R[0][1]*R[0][2]+R[1][1]*R[1][2];
|
||||||
|
|
||||||
|
A[2][0] = R[0][2]*R[0][0]+R[1][2]*R[1][0];
|
||||||
|
A[2][1] = R[0][2]*R[0][1]+R[1][2]*R[1][1];
|
||||||
|
A[2][2] = R[0][2]*R[0][2]+R[1][2]*R[1][2];
|
||||||
|
|
||||||
|
/* vector B */
|
||||||
|
P = Vector3(0.0, 0.0, 0.0);
|
||||||
|
B.x = -2.0*P.x; B.y = -2.0*P.y; B.z = -2.0*P.z;
|
||||||
|
|
||||||
|
/* constant C */
|
||||||
|
e0 = -2.0*(R[0][0]*P.x+R[0][1]*P.y+R[0][2]*P.z);
|
||||||
|
e1 = -2.0*(R[1][0]*P.x+R[1][1]*P.y+R[1][2]*P.z);
|
||||||
|
C = 0.25*(e0*e0+e1*e1) - radius*radius;
|
||||||
|
|
||||||
|
/* line */
|
||||||
|
Q = ray.getOrigin().sub(axis.getOrigin());
|
||||||
|
G = ray.getDirection();
|
||||||
|
|
||||||
|
/* compute A*G */
|
||||||
|
AG.x = A[0][0]*G.x+A[0][1]*G.y+A[0][2]*G.z;
|
||||||
|
AG.y = A[1][0]*G.x+A[1][1]*G.y+A[1][2]*G.z;
|
||||||
|
AG.z = A[2][0]*G.x+A[2][1]*G.y+A[2][2]*G.z;
|
||||||
|
|
||||||
|
/* compute A*Q */
|
||||||
|
AQ.x = A[0][0]*Q.x+A[0][1]*Q.y+A[0][2]*Q.z;
|
||||||
|
AQ.y = A[1][0]*Q.x+A[1][1]*Q.y+A[1][2]*Q.z;
|
||||||
|
AQ.z = A[2][0]*Q.x+A[2][1]*Q.y+A[2][2]*Q.z;
|
||||||
|
|
||||||
|
/* compute quadratic equation c0+c1*t+c2*t^2 = 0 */
|
||||||
|
c2 = G.x*AG.x+G.y*AG.y+G.z*AG.z;
|
||||||
|
c1 = B.x*G.x+B.y*G.y+B.z*G.z+2.0f*(Q.x*AG.x+Q.y*AG.y+Q.z*AG.z);
|
||||||
|
c0 = Q.x*AQ.x+Q.y*AQ.y+Q.z*AQ.z+B.x*Q.x+B.y*Q.y+B.z*Q.z+C;
|
||||||
|
|
||||||
|
/* solve for intersections */
|
||||||
|
int numIntersections;
|
||||||
|
discr = c1*c1-4.0*c0*c2;
|
||||||
|
if ( discr > EPS )
|
||||||
|
{
|
||||||
|
numIntersections = 2;
|
||||||
|
discr = sqrt(discr);
|
||||||
|
invC2 = 1.0/c2;
|
||||||
|
root0 = -0.5*(c1+discr)*invC2;
|
||||||
|
root1 = -0.5*(c1-discr)*invC2;
|
||||||
|
first_intersection->x = Q.x+root0*G.x;
|
||||||
|
first_intersection->y = Q.y+root0*G.y;
|
||||||
|
first_intersection->z = Q.z+root0*G.z;
|
||||||
|
second_intersection->x = Q.x+root1*G.x;
|
||||||
|
second_intersection->y = Q.y+root1*G.y;
|
||||||
|
second_intersection->z = Q.z+root1*G.z;
|
||||||
|
|
||||||
|
*first_intersection = first_intersection->add(axis.getOrigin());
|
||||||
|
*second_intersection = second_intersection->add(axis.getOrigin());
|
||||||
|
}
|
||||||
|
else if ( discr < -EPS )
|
||||||
|
{
|
||||||
|
numIntersections = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
numIntersections = 1;
|
||||||
|
root = -0.5*c1/c2;
|
||||||
|
first_intersection->x = Q.x+root*G.x;
|
||||||
|
first_intersection->y = Q.y+root*G.y;
|
||||||
|
first_intersection->z = Q.z+root*G.z;
|
||||||
|
|
||||||
|
*first_intersection = first_intersection->add(axis.getOrigin());
|
||||||
|
}
|
||||||
|
|
||||||
|
return numIntersections;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfiniteCylinder::save(PackStream *stream) const
|
||||||
|
{
|
||||||
|
axis.save(stream);
|
||||||
|
stream->write(&radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfiniteCylinder::load(PackStream *stream)
|
||||||
|
{
|
||||||
|
axis.load(stream);
|
||||||
|
stream->read(&radius);
|
||||||
|
}
|
41
src/basics/InfiniteCylinder.h
Normal file
41
src/basics/InfiniteCylinder.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef INFINITECYLINDER_H
|
||||||
|
#define INFINITECYLINDER_H
|
||||||
|
|
||||||
|
#include "basics_global.h"
|
||||||
|
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace basics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geometric cylinder, with infinite length.
|
||||||
|
*/
|
||||||
|
class BASICSSHARED_EXPORT InfiniteCylinder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InfiniteCylinder();
|
||||||
|
InfiniteCylinder(const InfiniteRay &axis, double radius);
|
||||||
|
|
||||||
|
inline const InfiniteRay& getAxis() const {return axis;}
|
||||||
|
inline double getRadius() const {return radius;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the intersection between the cylinder and an infinite ray.
|
||||||
|
*
|
||||||
|
* Returns the number of intersections (0, 1 or 2) and fill the intersection points.
|
||||||
|
*/
|
||||||
|
int checkRayIntersection(const InfiniteRay& ray, Vector3 *first_intersection, Vector3 *second_intersection) const;
|
||||||
|
|
||||||
|
virtual void save(PackStream *stream) const;
|
||||||
|
virtual void load(PackStream *stream);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
InfiniteRay axis;
|
||||||
|
double radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // INFINITECYLINDER_H
|
48
src/basics/InfinitePlane.cpp
Normal file
48
src/basics/InfinitePlane.cpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#include "InfinitePlane.h"
|
||||||
|
|
||||||
|
#include "PackStream.h"
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
|
||||||
|
InfinitePlane::InfinitePlane()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InfinitePlane::InfinitePlane(const Vector3 &point, const Vector3 &normal):
|
||||||
|
point(point), normal(normal)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int InfinitePlane::checkRayIntersection(const InfiniteRay &ray, Vector3 *intersection) const
|
||||||
|
{
|
||||||
|
Vector3 p1 = ray.getDirection();
|
||||||
|
double d = normal.dotProduct(p1);
|
||||||
|
|
||||||
|
if (fabs(d) < 1e-8)
|
||||||
|
{
|
||||||
|
if (normal.dotProduct(ray.getPointAtCursor(1.0).sub(point)) == 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double u = point.sub(ray.getOrigin()).dotProduct(normal) / d;
|
||||||
|
*intersection = ray.getPointAtCursor(u);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfinitePlane::save(PackStream *stream) const
|
||||||
|
{
|
||||||
|
point.save(stream);
|
||||||
|
normal.save(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfinitePlane::load(PackStream *stream)
|
||||||
|
{
|
||||||
|
point.load(stream);
|
||||||
|
normal.load(stream);
|
||||||
|
}
|
||||||
|
|
43
src/basics/InfinitePlane.h
Normal file
43
src/basics/InfinitePlane.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef INFINITEPLANE_H
|
||||||
|
#define INFINITEPLANE_H
|
||||||
|
|
||||||
|
#include "basics_global.h"
|
||||||
|
|
||||||
|
#include "Vector3.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace basics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infinite 3d geometric plane.
|
||||||
|
*/
|
||||||
|
class BASICSSHARED_EXPORT InfinitePlane
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InfinitePlane();
|
||||||
|
InfinitePlane(const Vector3 &point, const Vector3 &normal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the intersection between the plane and an infinite ray.
|
||||||
|
*
|
||||||
|
* Returns the number of intersections (0, 1), and fill the intersection point.
|
||||||
|
*
|
||||||
|
* Returns -1 if the ray is on the plane, and make for an infinite number of intersection points.
|
||||||
|
*/
|
||||||
|
int checkRayIntersection(const InfiniteRay& ray, Vector3 *intersection) const;
|
||||||
|
|
||||||
|
inline const Vector3 &getPoint() const {return point;}
|
||||||
|
inline const Vector3 &getNormal() const {return normal;}
|
||||||
|
|
||||||
|
virtual void save(PackStream *stream) const;
|
||||||
|
virtual void load(PackStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 point;
|
||||||
|
Vector3 normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // INFINITEPLANE_H
|
27
src/basics/InfiniteRay.cpp
Normal file
27
src/basics/InfiniteRay.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
|
||||||
|
InfiniteRay::InfiniteRay()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InfiniteRay::InfiniteRay(const Vector3 &origin, const Vector3 &direction):
|
||||||
|
origin(origin), direction(direction.normalize())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InfiniteRay InfiniteRay::fromPoints(const Vector3 &point1, const Vector3 &point2)
|
||||||
|
{
|
||||||
|
return InfiniteRay(point1, point2.sub(point1).normalize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfiniteRay::save(PackStream *stream) const
|
||||||
|
{
|
||||||
|
origin.save(stream);
|
||||||
|
direction.save(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfiniteRay::load(PackStream *stream)
|
||||||
|
{
|
||||||
|
origin.load(stream);
|
||||||
|
direction.load(stream);
|
||||||
|
}
|
39
src/basics/InfiniteRay.h
Normal file
39
src/basics/InfiniteRay.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef INFINITERAY_H
|
||||||
|
#define INFINITERAY_H
|
||||||
|
|
||||||
|
#include "basics_global.h"
|
||||||
|
|
||||||
|
#include "Vector3.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace basics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infinite ray (line).
|
||||||
|
*/
|
||||||
|
class BASICSSHARED_EXPORT InfiniteRay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InfiniteRay();
|
||||||
|
InfiniteRay(const Vector3 &origin, const Vector3 &direction);
|
||||||
|
|
||||||
|
static InfiniteRay fromPoints(const Vector3 &point1, const Vector3 &point2);
|
||||||
|
|
||||||
|
inline const Vector3 &getOrigin() const {return origin;}
|
||||||
|
inline const Vector3 &getDirection() const {return direction;}
|
||||||
|
|
||||||
|
inline double getCursor(const Vector3 &point) const {return point.sub(origin).dotProduct(direction);}
|
||||||
|
inline Vector3 getPointAtCursor(double distance) const {return origin.add(direction.scale(distance));}
|
||||||
|
|
||||||
|
void save(PackStream *stream) const;
|
||||||
|
void load(PackStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 origin;
|
||||||
|
Vector3 direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // INFINITERAY_H
|
62
src/basics/Sphere.cpp
Normal file
62
src/basics/Sphere.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include "Sphere.h"
|
||||||
|
|
||||||
|
#include "PackStream.h"
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
|
||||||
|
Sphere::Sphere()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Sphere::Sphere(const Vector3 ¢er, double radius):
|
||||||
|
center(center), radius(radius)
|
||||||
|
{
|
||||||
|
radius2 = radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Sphere::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const
|
||||||
|
{
|
||||||
|
Vector3 L = ray.getOrigin().sub(center);
|
||||||
|
double b = 2.0 * ray.getDirection().dotProduct(L);
|
||||||
|
double c = L.dotProduct(L) - radius2;
|
||||||
|
|
||||||
|
double discr = b * b - 4.0 * c;
|
||||||
|
if (discr < 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (discr == 0)
|
||||||
|
{
|
||||||
|
*first_intersection = ray.getPointAtCursor(-0.5 * b);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double x0 = (b > 0.0) ? -0.5 * (b + sqrt(discr)) : -0.5 * (b - sqrt(discr));
|
||||||
|
double x1 = c / x0;
|
||||||
|
if (x0 > x1)
|
||||||
|
{
|
||||||
|
*first_intersection = ray.getPointAtCursor(x1);
|
||||||
|
*second_intersection = ray.getPointAtCursor(x0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*first_intersection = ray.getPointAtCursor(x0);
|
||||||
|
*second_intersection = ray.getPointAtCursor(x1);
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sphere::save(PackStream *stream) const
|
||||||
|
{
|
||||||
|
center.save(stream);
|
||||||
|
stream->write(&radius);
|
||||||
|
stream->write(&radius2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sphere::load(PackStream *stream)
|
||||||
|
{
|
||||||
|
center.load(stream);
|
||||||
|
stream->read(&radius);
|
||||||
|
stream->read(&radius2);
|
||||||
|
}
|
42
src/basics/Sphere.h
Normal file
42
src/basics/Sphere.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef SPHERE_H
|
||||||
|
#define SPHERE_H
|
||||||
|
|
||||||
|
#include "basics_global.h"
|
||||||
|
|
||||||
|
#include "Vector3.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace basics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geometric sphere.
|
||||||
|
*/
|
||||||
|
class BASICSSHARED_EXPORT Sphere
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sphere();
|
||||||
|
Sphere(const Vector3 ¢er, double radius);
|
||||||
|
|
||||||
|
inline const Vector3 &getCenter() const {return center;}
|
||||||
|
inline const double &getRadius() const {return radius;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the intersection between the sphere and an infinite ray.
|
||||||
|
*
|
||||||
|
* Returns the number of intersections (0, 1 or 2) and fill the intersection points.
|
||||||
|
*/
|
||||||
|
int checkRayIntersection(const InfiniteRay& ray, Vector3 *first_intersection, Vector3 *second_intersection) const;
|
||||||
|
|
||||||
|
void save(PackStream *stream) const;
|
||||||
|
void load(PackStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 center;
|
||||||
|
double radius;
|
||||||
|
double radius2;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SPHERE_H
|
|
@ -34,6 +34,12 @@ SOURCES += \
|
||||||
Texture4D.cpp \
|
Texture4D.cpp \
|
||||||
NoiseState.cpp \
|
NoiseState.cpp \
|
||||||
FractalNoise.cpp \
|
FractalNoise.cpp \
|
||||||
|
CappedCylinder.cpp \
|
||||||
|
InfiniteCylinder.cpp \
|
||||||
|
InfiniteRay.cpp \
|
||||||
|
Sphere.cpp \
|
||||||
|
InfinitePlane.cpp \
|
||||||
|
Disk.cpp \
|
||||||
SpaceGridIterator.cpp
|
SpaceGridIterator.cpp
|
||||||
|
|
||||||
HEADERS +=\
|
HEADERS +=\
|
||||||
|
@ -56,6 +62,12 @@ HEADERS +=\
|
||||||
Texture4D.h \
|
Texture4D.h \
|
||||||
NoiseState.h \
|
NoiseState.h \
|
||||||
FractalNoise.h \
|
FractalNoise.h \
|
||||||
|
CappedCylinder.h \
|
||||||
|
InfiniteCylinder.h \
|
||||||
|
InfiniteRay.h \
|
||||||
|
Sphere.h \
|
||||||
|
InfinitePlane.h \
|
||||||
|
Disk.h \
|
||||||
SpaceGridIterator.h
|
SpaceGridIterator.h
|
||||||
|
|
||||||
unix:!symbian {
|
unix:!symbian {
|
||||||
|
|
|
@ -26,6 +26,10 @@ namespace basics {
|
||||||
class Texture2D;
|
class Texture2D;
|
||||||
class Texture3D;
|
class Texture3D;
|
||||||
class Texture4D;
|
class Texture4D;
|
||||||
|
class CappedCylinder;
|
||||||
|
class InfiniteRay;
|
||||||
|
class Sphere;
|
||||||
|
class InfinitePlane;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
using namespace paysages::basics;
|
using namespace paysages::basics;
|
||||||
|
|
38
src/tests/CappedCylinder_Test.cpp
Normal file
38
src/tests/CappedCylinder_Test.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
|
||||||
|
#include "CappedCylinder.h"
|
||||||
|
|
||||||
|
TEST(CappedCylinder, checkRayIntersection)
|
||||||
|
{
|
||||||
|
CappedCylinder cylinder(VECTOR_DOWN, VECTOR_UP, 1.0, 2.0);
|
||||||
|
|
||||||
|
int intersect_count;
|
||||||
|
Vector3 p1, p2;
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(1.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(0, intersect_count);
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(1.0, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(1, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(2, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 0.5, 0.0, -cos(asin(0.5)));
|
||||||
|
EXPECT_VECTOR3_COORDS(p2, 0.5, 0.0, cos(asin(0.5)));
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, -2.1, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(0, intersect_count);
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, 2.1, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(0, intersect_count);
|
||||||
|
|
||||||
|
// diagonal cases (through a cap)
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(-2.0, -1.0, 0.0), Vector3(1.0, 1.0, 0.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(1, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, -1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(-2.0, 3.0, 0.0), Vector3(1.0, -1.0, 0.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(1, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
|
||||||
|
}
|
25
src/tests/Disk_Test.cpp
Normal file
25
src/tests/Disk_Test.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
#include "Disk.h"
|
||||||
|
|
||||||
|
TEST(Disk, checkRayIntersection)
|
||||||
|
{
|
||||||
|
Disk disk(VECTOR_UP, VECTOR_UP, 0.8);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
Vector3 point;
|
||||||
|
|
||||||
|
result = disk.checkRayIntersection(InfiniteRay(Vector3(0.0, 2.0, 0.0), VECTOR_SOUTH), &point);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
|
||||||
|
result = disk.checkRayIntersection(InfiniteRay(Vector3(1.5, 2.0, -1.0), VECTOR_DOWN), &point);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
|
||||||
|
result = disk.checkRayIntersection(InfiniteRay(Vector3(0.5, 2.0, 0.0), VECTOR_DOWN), &point);
|
||||||
|
ASSERT_EQ(1, result);
|
||||||
|
EXPECT_VECTOR3_COORDS(point, 0.5, 1.0, 0.0);
|
||||||
|
|
||||||
|
result = disk.checkRayIntersection(InfiniteRay(Vector3(1.0, 1.0, 0.0), VECTOR_EAST), &point);
|
||||||
|
ASSERT_EQ(-1, result);
|
||||||
|
}
|
41
src/tests/InfiniteCylinder_Test.cpp
Normal file
41
src/tests/InfiniteCylinder_Test.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
#include "InfiniteCylinder.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
TEST(InfiniteCylinder, checkRayIntersection)
|
||||||
|
{
|
||||||
|
InfiniteRay ray(VECTOR_ZERO, VECTOR_UP);
|
||||||
|
InfiniteCylinder cylinder(ray, 1.0);
|
||||||
|
|
||||||
|
int intersect_count;
|
||||||
|
Vector3 p1, p2;
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(1.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(0, intersect_count);
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(1.0, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(1, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(2, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 0.5, 0.0, -cos(asin(0.5)));
|
||||||
|
EXPECT_VECTOR3_COORDS(p2, 0.5, 0.0, cos(asin(0.5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InfiniteCylinder, checkRayIntersection2)
|
||||||
|
{
|
||||||
|
InfiniteRay ray(Vector3(-1.4, 1.5, 1.0), Vector3(1.0, 0.0, 0.0));
|
||||||
|
InfiniteCylinder cylinder(ray, 0.5);
|
||||||
|
|
||||||
|
int intersect_count;
|
||||||
|
Vector3 p1, p2;
|
||||||
|
|
||||||
|
intersect_count = cylinder.checkRayIntersection(InfiniteRay::fromPoints(Vector3(0.0, 1.5, 0.0), Vector3(0.0, 1.5, 2.0)), &p1, &p2);
|
||||||
|
EXPECT_EQ(2, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 0.0, 1.5, 0.5);
|
||||||
|
EXPECT_VECTOR3_COORDS(p2, 0.0, 1.5, 1.5);
|
||||||
|
}
|
||||||
|
|
34
src/tests/InfinitePlane_Test.cpp
Normal file
34
src/tests/InfinitePlane_Test.cpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
#include "InfinitePlane.h"
|
||||||
|
|
||||||
|
TEST(InfinitePlane, checkRayIntersection)
|
||||||
|
{
|
||||||
|
InfinitePlane plane(VECTOR_UP, VECTOR_UP);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
Vector3 point;
|
||||||
|
|
||||||
|
result = plane.checkRayIntersection(InfiniteRay(Vector3(0.0, 2.0, 0.0), VECTOR_SOUTH), &point);
|
||||||
|
ASSERT_EQ(0, result);
|
||||||
|
|
||||||
|
result = plane.checkRayIntersection(InfiniteRay(Vector3(1.5, 2.0, -1.0), VECTOR_DOWN), &point);
|
||||||
|
ASSERT_EQ(1, result);
|
||||||
|
EXPECT_VECTOR3_COORDS(point, 1.5, 1.0, -1.0);
|
||||||
|
|
||||||
|
result = plane.checkRayIntersection(InfiniteRay(Vector3(1.0, 1.0, 0.0), VECTOR_EAST), &point);
|
||||||
|
ASSERT_EQ(-1, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InfinitePlane, checkRayIntersection_oblique)
|
||||||
|
{
|
||||||
|
InfinitePlane plane(Vector3(14.0, -5.0, 3.5), Vector3(1.0, 0.0, 0.0));
|
||||||
|
InfiniteRay ray(Vector3(2.0, 2.0, 2.0), Vector3(1.0, 1.0, 1.0).normalize());
|
||||||
|
int result;
|
||||||
|
Vector3 point;
|
||||||
|
|
||||||
|
result = plane.checkRayIntersection(ray, &point);
|
||||||
|
ASSERT_EQ(1, result);
|
||||||
|
EXPECT_VECTOR3_COORDS(point, 14.0, 14.0, 14.0);
|
||||||
|
}
|
24
src/tests/Sphere_Test.cpp
Normal file
24
src/tests/Sphere_Test.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
|
||||||
|
#include "InfiniteRay.h"
|
||||||
|
#include "Sphere.h"
|
||||||
|
|
||||||
|
TEST(Sphere, checkRayIntersection)
|
||||||
|
{
|
||||||
|
Sphere sphere(Vector3(2.0, 1.0, 1.0), 0.5);
|
||||||
|
|
||||||
|
int intersect_count;
|
||||||
|
Vector3 p1, p2;
|
||||||
|
|
||||||
|
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(0.0, 0.0, 0.0), VECTOR_SOUTH), &p1, &p2);
|
||||||
|
ASSERT_EQ(0, intersect_count);
|
||||||
|
|
||||||
|
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(1.5, 1.0, 0.0), VECTOR_SOUTH), &p1, &p2);
|
||||||
|
ASSERT_EQ(1, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 1.5, 1.0, 1.0);
|
||||||
|
|
||||||
|
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(2.0, 1.0, 0.0), VECTOR_SOUTH), &p1, &p2);
|
||||||
|
ASSERT_EQ(2, intersect_count);
|
||||||
|
EXPECT_VECTOR3_COORDS(p1, 2.0, 1.0, 0.5);
|
||||||
|
EXPECT_VECTOR3_COORDS(p2, 2.0, 1.0, 1.5);
|
||||||
|
}
|
|
@ -34,6 +34,11 @@ SOURCES += main.cpp \
|
||||||
GodRaysSampler_Test.cpp \
|
GodRaysSampler_Test.cpp \
|
||||||
Interpolation_Test.cpp \
|
Interpolation_Test.cpp \
|
||||||
Rasterizer_Test.cpp \
|
Rasterizer_Test.cpp \
|
||||||
|
CappedCylinder_Test.cpp \
|
||||||
|
InfiniteCylinder_Test.cpp \
|
||||||
|
Sphere_Test.cpp \
|
||||||
|
InfinitePlane_Test.cpp \
|
||||||
|
Disk_Test.cpp \
|
||||||
Vector3_Test.cpp
|
Vector3_Test.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
|
Loading…
Reference in a new issue