diff --git a/src/basics/CappedCylinder.cpp b/src/basics/CappedCylinder.cpp index d508284..9cd731e 100644 --- a/src/basics/CappedCylinder.cpp +++ b/src/basics/CappedCylinder.cpp @@ -4,38 +4,44 @@ #include "PackStream.h" CappedCylinder::CappedCylinder(const Vector3 &base, const Vector3 &direction, double radius, double length) - : InfiniteCylinder(InfiniteRay(base, direction), radius), length(length) { + : InfiniteCylinder(InfiniteRay(base, direction), radius), length(length), + container(base.add(direction.scale(length * 0.5)), length * 0.5) { } -int CappedCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, +int CappedCylinder::findRayIntersection(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) { + if (not container.checkRayIntersection(ray)) { + // We don't hit the containing sphere at all return 0; - } else if (count == 2) { - if (checkPointProjection(first_intersection)) { - if (checkPointProjection(second_intersection)) { - return 2; + } else { + // TODO Apply the caps + int count = InfiniteCylinder::findRayIntersection(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 { - return 1; + if (checkPointProjection(second_intersection)) { + *first_intersection = *second_intersection; + return 1; + } else { + return 0; + } } - } else { - if (checkPointProjection(second_intersection)) { - *first_intersection = *second_intersection; + } else // count == 1 + { + if (checkPointProjection(first_intersection)) { return 1; } else { return 0; } } - } else // count == 1 - { - if (checkPointProjection(first_intersection)) { - return 1; - } else { - return 0; - } } } diff --git a/src/basics/CappedCylinder.h b/src/basics/CappedCylinder.h index dddf1b5..185379c 100644 --- a/src/basics/CappedCylinder.h +++ b/src/basics/CappedCylinder.h @@ -4,6 +4,7 @@ #include "basics_global.h" #include "InfiniteCylinder.h" +#include "Sphere.h" namespace paysages { namespace basics { @@ -22,8 +23,10 @@ class BASICSSHARED_EXPORT CappedCylinder : public InfiniteCylinder { /** * 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; + int findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const; /** * Check if a point projects in the length of the finite cylinder. @@ -35,6 +38,7 @@ class BASICSSHARED_EXPORT CappedCylinder : public InfiniteCylinder { private: double length; + Sphere container; }; } } diff --git a/src/basics/InfiniteCylinder.cpp b/src/basics/InfiniteCylinder.cpp index d13e230..b5c2bc9 100644 --- a/src/basics/InfiniteCylinder.cpp +++ b/src/basics/InfiniteCylinder.cpp @@ -8,7 +8,7 @@ InfiniteCylinder::InfiniteCylinder(const InfiniteRay &axis, double radius) : axi validate(); } -int InfiniteCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, +int InfiniteCylinder::findRayIntersection(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. diff --git a/src/basics/InfiniteCylinder.h b/src/basics/InfiniteCylinder.h index affbeca..bcdeef7 100644 --- a/src/basics/InfiniteCylinder.h +++ b/src/basics/InfiniteCylinder.h @@ -28,7 +28,7 @@ class BASICSSHARED_EXPORT InfiniteCylinder { * * 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; + int findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const; virtual void save(PackStream *stream) const; virtual void load(PackStream *stream); diff --git a/src/basics/Sphere.cpp b/src/basics/Sphere.cpp index 5a1a035..2ee9196 100644 --- a/src/basics/Sphere.cpp +++ b/src/basics/Sphere.cpp @@ -7,8 +7,23 @@ Sphere::Sphere(const Vector3 ¢er, double radius) : center(center), radius(ra radius2 = radius * radius; } -int Sphere::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, - Vector3 *second_intersection) const { +int Sphere::checkRayIntersection(const InfiniteRay &ray) 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) { + return 1; + } else { + return 2; + } +} + +int Sphere::findRayIntersection(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; diff --git a/src/basics/Sphere.h b/src/basics/Sphere.h index a9961ca..6067f35 100644 --- a/src/basics/Sphere.h +++ b/src/basics/Sphere.h @@ -24,11 +24,18 @@ class BASICSSHARED_EXPORT Sphere { } /** - * Check the intersection between the sphere and an infinite ray. + * Check for intersections between the sphere and an infinite ray. + * + * Returns the number of intersections (0, 1 or 2). + */ + int checkRayIntersection(const InfiniteRay &ray) const; + + /** + * Get the intersections 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; + int findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const; void save(PackStream *stream) const; void load(PackStream *stream); diff --git a/src/render/software/VegetationModelRenderer.cpp b/src/render/software/VegetationModelRenderer.cpp index 7a1b7f1..987a8e1 100644 --- a/src/render/software/VegetationModelRenderer.cpp +++ b/src/render/software/VegetationModelRenderer.cpp @@ -30,7 +30,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment, for (const auto &branch : model->getSolidVolumes()) { Vector3 near, far; - if (branch.checkRayIntersection(ray, &near, &far)) { + if (branch.findRayIntersection(ray, &near, &far)) { distance = ray.getCursor(near); if (distance >= 0.0 and distance <= maximal) { // Got a branch hit @@ -54,8 +54,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment, } for (const auto &foliage : model->getFoliageGroups()) { - Vector3 near, far; - intersections = foliage.checkRayIntersection(ray, &near, &far); + intersections = foliage.checkRayIntersection(ray); if (intersections == 2) { InfiniteRay subray(ray.getOrigin().sub(foliage.getCenter()).scale(1.0 / foliage.getRadius()), ray.getDirection()); @@ -63,19 +62,19 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment, for (const auto &leaf : model->getFoliageItems()) { Sphere leafcap(leaf.getPoint(), leaf.getRadius() * leaf.getRadius() / foliage.getRadius()); // TODO Add cap intersection to Sphere class - Vector3 capnear, capfar; - if (leafcap.checkRayIntersection(subray, &capnear, &capfar) == 2) { - if (capnear.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) { - if (capfar.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) { + Vector3 near, far; + if (leafcap.findRayIntersection(subray, &near, &far) == 2) { + if (near.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) { + if (far.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) { continue; } else { - capnear = capfar; + near = far; } } - Vector3 capnormal = capnear.sub(leaf.getPoint()).normalize(); - capnear = capnear.scale(foliage.getRadius()).add(foliage.getCenter()); - distance = ray.getCursor(capnear); + Vector3 capnormal = near.sub(leaf.getPoint()).normalize(); + near = near.scale(foliage.getRadius()).add(foliage.getCenter()); + distance = ray.getCursor(near); if (distance >= 0.0 and distance <= maximal) { // Got a foliage hit @@ -88,7 +87,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment, nearest = distance; hit = true; - location = capnear; + location = near; normal = capnormal; if (normal.dotProduct(location.sub(segment.getStart())) > 0.0) { diff --git a/src/tests/CappedCylinder_Test.cpp b/src/tests/CappedCylinder_Test.cpp index 1a04463..a9aa57c 100644 --- a/src/tests/CappedCylinder_Test.cpp +++ b/src/tests/CappedCylinder_Test.cpp @@ -2,43 +2,43 @@ #include "CappedCylinder.h" -TEST(CappedCylinder, checkRayIntersection) { +TEST(CappedCylinder, findRayIntersection) { 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); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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); } diff --git a/src/tests/InfiniteCylinder_Test.cpp b/src/tests/InfiniteCylinder_Test.cpp index 1d836d9..dc3516e 100644 --- a/src/tests/InfiniteCylinder_Test.cpp +++ b/src/tests/InfiniteCylinder_Test.cpp @@ -4,7 +4,7 @@ #include "InfiniteCylinder.h" #include -TEST(InfiniteCylinder, checkRayIntersection) { +TEST(InfiniteCylinder, findRayIntersection) { InfiniteRay ray(VECTOR_ZERO, VECTOR_UP); InfiniteCylinder cylinder(ray, 1.0); @@ -12,29 +12,29 @@ TEST(InfiniteCylinder, checkRayIntersection) { Vector3 p1, p2; intersect_count = - cylinder.checkRayIntersection(InfiniteRay(Vector3(1.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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); + cylinder.findRayIntersection(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) { +TEST(InfiniteCylinder, getRayIntersection2) { 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( + intersect_count = cylinder.findRayIntersection( 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); diff --git a/src/tests/Sphere_Test.cpp b/src/tests/Sphere_Test.cpp index 47a15ea..dd73058 100644 --- a/src/tests/Sphere_Test.cpp +++ b/src/tests/Sphere_Test.cpp @@ -3,20 +3,26 @@ #include "InfiniteRay.h" #include "Sphere.h" -TEST(Sphere, checkRayIntersection) { +TEST(Sphere, findRayIntersection) { 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(0.0, 0.0, 0.0), VECTOR_SOUTH)); + EXPECT_EQ(0, intersect_count); + intersect_count = sphere.findRayIntersection(InfiniteRay(Vector3(0.0, 0.0, 0.0), VECTOR_SOUTH), &p1, &p2); + EXPECT_EQ(0, intersect_count); - intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(1.5, 1.0, 0.0), VECTOR_SOUTH), &p1, &p2); + intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(1.5, 1.0, 0.0), VECTOR_SOUTH)); + EXPECT_EQ(1, intersect_count); + intersect_count = sphere.findRayIntersection(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); + intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(2.0, 1.0, 0.0), VECTOR_SOUTH)); + EXPECT_EQ(2, intersect_count); + intersect_count = sphere.findRayIntersection(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);