Added geometry primitives

This commit is contained in:
Michaël Lemaire 2015-10-15 20:21:32 +02:00
parent 91cd564c59
commit 2b3ecc7e35
20 changed files with 840 additions and 0 deletions

View 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);
}

View 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
View 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
View 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

View 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);
}

View 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

View 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);
}

View 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

View 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
View 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
View file

@ -0,0 +1,62 @@
#include "Sphere.h"
#include "PackStream.h"
#include "InfiniteRay.h"
Sphere::Sphere()
{
}
Sphere::Sphere(const Vector3 &center, 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
View 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 &center, 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

View file

@ -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 {

View file

@ -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;

View 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
View 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);
}

View 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);
}

View 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
View 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);
}

View file

@ -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 += \