From 307c125eba4db6ce73e8d72442a99bb1bf5e44ff Mon Sep 17 00:00:00 2001 From: Godzil Date: Fri, 28 Feb 2020 18:33:59 +0000 Subject: [PATCH] More bounding boxes --- source/include/cone.h | 2 +- source/include/cylinder.h | 2 +- source/include/group.h | 1 + source/include/plane.h | 2 +- source/include/shape.h | 1 + source/include/triangle.h | 2 +- source/shapes/cone.cpp | 9 +++------ source/shapes/cylinder.cpp | 9 +++------ source/shapes/group.cpp | 5 +++++ source/shapes/plane.cpp | 9 +++------ source/shapes/shape.cpp | 17 +++++++++++++++-- source/shapes/triangle.cpp | 11 ++++------- source/tuple.cpp | 4 ++-- tests/boundingbox_test.cpp | 32 ++++++++++++++++++++++---------- tests/cone_test.cpp | 7 +++++-- tests/cube_test.cpp | 7 ++++--- tests/cylinder_test.cpp | 8 +++++--- tests/sphere_test.cpp | 7 ++++--- tests/triangle_test.cpp | 12 +++++++++++- 19 files changed, 92 insertions(+), 55 deletions(-) diff --git a/source/include/cone.h b/source/include/cone.h index 9a3e707..c004838 100644 --- a/source/include/cone.h +++ b/source/include/cone.h @@ -30,7 +30,7 @@ public: double maxCap; Cone() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(SHAPE_CONE) { stats.addCone(); }; - BoundingBox getBounds(); + BoundingBox getLocalBounds(); bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); }; void dumpMe(FILE *fp); diff --git a/source/include/cylinder.h b/source/include/cylinder.h index 2cee64e..33576aa 100644 --- a/source/include/cylinder.h +++ b/source/include/cylinder.h @@ -31,7 +31,7 @@ public: Cylinder() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(SHAPE_CYLINDER) { stats.addCylinder(); }; - BoundingBox getBounds(); + BoundingBox getLocalBounds(); bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); }; void dumpMe(FILE *fp); diff --git a/source/include/group.h b/source/include/group.h index dcbfd8b..fefacad 100644 --- a/source/include/group.h +++ b/source/include/group.h @@ -38,6 +38,7 @@ public: Shape *operator[](const int p) { return this->objectList[p]; } Intersect intersect(Ray r); + BoundingBox getLocalBounds(); BoundingBox getBounds(); void updateBoundingBox(); diff --git a/source/include/plane.h b/source/include/plane.h index ee52008..638b2da 100644 --- a/source/include/plane.h +++ b/source/include/plane.h @@ -19,7 +19,7 @@ private: public: Plane() : Shape(SHAPE_PLANE) { stats.addPlane(); }; - BoundingBox getBounds(); + BoundingBox getLocalBounds(); bool haveFiniteBounds() { return false; }; }; diff --git a/source/include/shape.h b/source/include/shape.h index 16c3163..11c6f0c 100644 --- a/source/include/shape.h +++ b/source/include/shape.h @@ -59,6 +59,7 @@ public: Tuple normalAt(Tuple point); /* Bounding box points are always world value */ + virtual BoundingBox getLocalBounds(); virtual BoundingBox getBounds(); virtual bool haveFiniteBounds() { return true; }; diff --git a/source/include/triangle.h b/source/include/triangle.h index 7c0862f..f813853 100644 --- a/source/include/triangle.h +++ b/source/include/triangle.h @@ -24,7 +24,7 @@ public: public: Triangle(Point p1, Point p2, Point p3); - BoundingBox getBounds(); + BoundingBox getLocalBounds(); void dumpMe(FILE *fp); diff --git a/source/shapes/cone.cpp b/source/shapes/cone.cpp index dd9a660..7172584 100644 --- a/source/shapes/cone.cpp +++ b/source/shapes/cone.cpp @@ -122,7 +122,7 @@ Tuple Cone::localNormalAt(Tuple point) return Vector(point.x, y, point.z); } -BoundingBox Cone::getBounds() +BoundingBox Cone::getLocalBounds() { BoundingBox ret; @@ -130,11 +130,8 @@ BoundingBox Cone::getBounds() double b = fabs(this->maxCap); double limit = (a > b)?a:b; - ret.min = this->objectToWorld(Point(-limit, this->minCap, -limit)); - ret.max = this->objectToWorld(Point(limit, this->maxCap, limit)); - - ret.min.fixPoint(); - ret.max.fixPoint(); + ret | Point(-limit, this->minCap, -limit); + ret | Point(limit, this->maxCap, limit); return ret; } diff --git a/source/shapes/cylinder.cpp b/source/shapes/cylinder.cpp index 8a6800e..07f3509 100644 --- a/source/shapes/cylinder.cpp +++ b/source/shapes/cylinder.cpp @@ -108,15 +108,12 @@ Tuple Cylinder::localNormalAt(Tuple point) return Vector(point.x, 0, point.z); } -BoundingBox Cylinder::getBounds() +BoundingBox Cylinder::getLocalBounds() { BoundingBox ret; - ret.min = this->objectToWorld(Point(-1, this->minCap, -1)); - ret.max = this->objectToWorld(Point(1, this->maxCap, 1)); - - ret.min.fixPoint(); - ret.max.fixPoint(); + ret | Point(-1, this->minCap, -1); + ret | Point(1, this->maxCap, 1); return ret; } diff --git a/source/shapes/group.cpp b/source/shapes/group.cpp index 10b3c8b..0861941 100644 --- a/source/shapes/group.cpp +++ b/source/shapes/group.cpp @@ -116,6 +116,11 @@ bool Group::isEmpty() return (this->objectCount == 0) && (this->unboxableObjectCount == 0); } +BoundingBox Group::getLocalBounds() +{ + return this->bounds; +} + BoundingBox Group::getBounds() { if (this->bounds.isEmpty()) { this->updateBoundingBox(); } diff --git a/source/shapes/plane.cpp b/source/shapes/plane.cpp index 26518ca..74f37ca 100644 --- a/source/shapes/plane.cpp +++ b/source/shapes/plane.cpp @@ -35,15 +35,12 @@ Tuple Plane::localNormalAt(Tuple point) return Vector(0, 1, 0); } -BoundingBox Plane::getBounds() +BoundingBox Plane::getLocalBounds() { BoundingBox ret; - ret.min = this->objectToWorld(Point(-INFINITY, 0-getEpsilon(), -INFINITY)); - ret.max = this->objectToWorld(Point(INFINITY, 0+getEpsilon(), INFINITY)); - - ret.min.fixPoint(); - ret.max.fixPoint(); + ret | Point(-INFINITY, 0-getEpsilon(), -INFINITY); + ret | Point(INFINITY, 0+getEpsilon(), INFINITY); return ret; } \ No newline at end of file diff --git a/source/shapes/shape.cpp b/source/shapes/shape.cpp index 2b09e0f..5259b27 100644 --- a/source/shapes/shape.cpp +++ b/source/shapes/shape.cpp @@ -66,12 +66,25 @@ void Shape::setTransform(Matrix transform) this->updateTransform(); } +BoundingBox Shape::getLocalBounds() +{ + return BoundingBox(Point(-1, -1, -1), Point(1,1,1)); +} + BoundingBox Shape::getBounds() { BoundingBox ret; + BoundingBox me = this->getLocalBounds(); + + ret | this->objectToWorld(Point(me.min.x, me.min.y, me.min.z)); + ret | this->objectToWorld(Point(me.min.x, me.min.y, me.max.z)); + ret | this->objectToWorld(Point(me.min.x, me.max.y, me.min.z)); + ret | this->objectToWorld(Point(me.max.x, me.min.y, me.min.z)); + ret | this->objectToWorld(Point(me.max.x, me.max.y, me.min.z)); + ret | this->objectToWorld(Point(me.max.x, me.min.y, me.max.z)); + ret | this->objectToWorld(Point(me.min.x, me.max.y, me.max.z)); + ret | this->objectToWorld(Point(me.max.x, me.max.y, me.max.z)); - ret.min = this->objectToWorld(Point(-1, -1, -1)); - ret.max = this->objectToWorld(Point(1, 1, 1)); return ret; } diff --git a/source/shapes/triangle.cpp b/source/shapes/triangle.cpp index 22c5c18..e286b50 100644 --- a/source/shapes/triangle.cpp +++ b/source/shapes/triangle.cpp @@ -59,16 +59,13 @@ Tuple Triangle::localNormalAt(Tuple point) return this->normal; } -BoundingBox Triangle::getBounds() +BoundingBox Triangle::getLocalBounds() { BoundingBox ret; - ret | p1; - ret | p2; - ret | p3; - - ret.min = this->objectToWorld(ret.min); - ret.max = this->objectToWorld(ret.max); + ret | this->objectToWorld(p1); + ret | this->objectToWorld(p2); + ret | this->objectToWorld(p3); return ret; } diff --git a/source/tuple.cpp b/source/tuple.cpp index 9249e34..54bea00 100644 --- a/source/tuple.cpp +++ b/source/tuple.cpp @@ -56,7 +56,6 @@ void Tuple::fixPoint() void Tuple::fixVector() { - if (isnan(this->x) || isnan(this->y) || isnan(this->z)) { /* w is probably broken, so fix it */ @@ -66,5 +65,6 @@ void Tuple::fixVector() bool Tuple::isRepresentable() { - return !(isnan(this->x) || isnan(this->y) || isnan(this->z)); + return !(isnan(this->x) || isnan(this->y) || isnan(this->z) || + isinf(this->x) || isinf(this->y) || isinf(this->z)); } \ No newline at end of file diff --git a/tests/boundingbox_test.cpp b/tests/boundingbox_test.cpp index 9b32ca9..6400c5b 100644 --- a/tests/boundingbox_test.cpp +++ b/tests/boundingbox_test.cpp @@ -22,7 +22,7 @@ #include #include -TEST(BoundingBox, Default_boundingbox_is_not_set) +TEST(BoundingBoxTest, Creating_an_empty_bounding_box) { BoundingBox bb; @@ -31,16 +31,16 @@ TEST(BoundingBox, Default_boundingbox_is_not_set) ASSERT_EQ(bb.max, Point(-INFINITY, -INFINITY, -INFINITY)); } -TEST(BoundingBox, Bounding_box_can_be_created_with_values) +TEST(BoundingBoxTest, Crteating_a_bounding_box_with_volume) { - BoundingBox bb = BoundingBox(Point(-1, -1, -1), Point(1, 1, 1)); + BoundingBox bb = BoundingBox(Point(-1, -2, -3), Point(3, 2, 1)); ASSERT_FALSE(bb.isEmpty()); - ASSERT_EQ(bb.min, Point(-1, -1, -1)); - ASSERT_EQ(bb.max, Point(1, 1, 1)); + ASSERT_EQ(bb.min, Point(-1, -2, -3)); + ASSERT_EQ(bb.max, Point(3, 2, 1)); } -TEST(BoundingBox, Cating_a_bb_to_an_empty_bb_reset_the_original_one) +TEST(BoundingBoxTest, Adding_on_bouding_to_an_empty_bounding_box) { BoundingBox bb; @@ -51,9 +51,9 @@ TEST(BoundingBox, Cating_a_bb_to_an_empty_bb_reset_the_original_one) ASSERT_EQ(bb.max, Point(1, 1, 1)); } -TEST(BoundingBox, Cating_a_bb_to_another_bb_expand_the_original_one_if_needed) +TEST(BoundingBoxTest, Adding_boudingbox_to_another) { - BoundingBox bb(Point(-1, -1, -1), Point(1, 1, 1)); + BoundingBox bb(Point(-1, -1, 0), Point(4, 0, 1)); bb | BoundingBox(Point(-2, 0, -5), Point(4, 5, 0.5)); @@ -62,7 +62,19 @@ TEST(BoundingBox, Cating_a_bb_to_another_bb_expand_the_original_one_if_needed) ASSERT_EQ(bb.max, Point(4, 5, 1)); } -TEST(BoundingBox, A_smaller_bb_should_fit_in_a_bigger) +TEST(BoundingBoxTest, Adding_points_to_an_empty_bounding_box) +{ + BoundingBox bb; + + bb | Point(-5, 2, 0); + bb | Point(7, 0, -3); + + ASSERT_FALSE(bb.isEmpty()); + ASSERT_EQ(bb.min, Point(-5, 0, -3)); + ASSERT_EQ(bb.max, Point(7, 2, 0)); +} + +TEST(BoundingBoxTest, A_smaller_bb_should_fit_in_a_bigger) { BoundingBox bigBb = BoundingBox(Point(-10, -10, -10), Point(10, 10, 10)); @@ -71,7 +83,7 @@ TEST(BoundingBox, A_smaller_bb_should_fit_in_a_bigger) ASSERT_TRUE(bigBb.fitsIn(smallBb)); } -TEST(BoundingBox, A_big_bb_should_not_fit_in_a_smaller) +TEST(BoundingBoxTest, A_big_bb_should_not_fit_in_a_smaller) { BoundingBox bigBb = BoundingBox(Point(-10, -10, -10), Point(10, 10, 10)); diff --git a/tests/cone_test.cpp b/tests/cone_test.cpp index 9855cd6..0a74989 100644 --- a/tests/cone_test.cpp +++ b/tests/cone_test.cpp @@ -163,8 +163,11 @@ TEST(ConeTest, An_uncut_cone_have_infinite_bounds) TEST(ConeTest, A_cut_cone_have_finite_bounds) { Cone t = Cone(); - t.minCap = -1; - t.maxCap = 1; + t.minCap = -5; + t.maxCap = 3; + BoundingBox res = t.getBounds(); ASSERT_TRUE(t.haveFiniteBounds()); + ASSERT_EQ(res.min, Point(-5, -5, -5)); + ASSERT_EQ(res.max, Point(5, 3, 5)); } \ No newline at end of file diff --git a/tests/cube_test.cpp b/tests/cube_test.cpp index 6b2a735..4a74803 100644 --- a/tests/cube_test.cpp +++ b/tests/cube_test.cpp @@ -119,12 +119,13 @@ TEST(CubeTest, The_normal_on_the_surface_of_a_cube) TEST(CubeTest, The_bounding_box_of_a_cube) { Cube t = Cube(); - BoundingBox b = BoundingBox(Point(-1, -1, -1), Point(1, 1, 1)); + Tuple boxMin = Point(-1, -1, -1); + Tuple boxMax = Point(1, 1, 1); BoundingBox res = t.getBounds(); - ASSERT_EQ(res.min, b.min); - ASSERT_EQ(res.max, b.max); + ASSERT_EQ(res.min, boxMin); + ASSERT_EQ(res.max, boxMax); } TEST(CubeTest, A_cube_have_finite_bounds) diff --git a/tests/cylinder_test.cpp b/tests/cylinder_test.cpp index 9b4bc39..c99ba0b 100644 --- a/tests/cylinder_test.cpp +++ b/tests/cylinder_test.cpp @@ -254,8 +254,10 @@ TEST(CylinderTest, An_uncut_cylinder_have_infinite_bounds) TEST(CylinderTest, A_cut_cylinder_have_finite_bounds) { Cylinder t = Cylinder(); - t.minCap = -1; - t.maxCap = 1; - + t.minCap = -5; + t.maxCap = 3; + BoundingBox res = t.getBounds(); ASSERT_TRUE(t.haveFiniteBounds()); + ASSERT_EQ(res.min, Point(-1, -5, -1)); + ASSERT_EQ(res.max, Point(1, 3, 1)); } \ No newline at end of file diff --git a/tests/sphere_test.cpp b/tests/sphere_test.cpp index 7918d17..a5ee786 100644 --- a/tests/sphere_test.cpp +++ b/tests/sphere_test.cpp @@ -212,12 +212,13 @@ TEST(SphereTest, A_helper_for_producing_a_sphere_with_a_glassy_material) TEST(SphereTest, The_bounding_box_of_a_sphere) { Sphere t = Sphere(); - BoundingBox b = BoundingBox(Point(-1, -1, -1), Point(1, 1, 1)); + Tuple sphereMin = Point(-1, -1, -1); + Tuple sphereMax = Point(1, 1, 1); BoundingBox res = t.getBounds(); - ASSERT_EQ(res.min, b.min); - ASSERT_EQ(res.max, b.max); + ASSERT_EQ(res.min, sphereMin); + ASSERT_EQ(res.max, sphereMax); } TEST(SphereTest, A_sphere_have_finite_bounds) diff --git a/tests/triangle_test.cpp b/tests/triangle_test.cpp index 37490ba..e54f427 100644 --- a/tests/triangle_test.cpp +++ b/tests/triangle_test.cpp @@ -88,4 +88,14 @@ TEST(TriangleTest, A_ray_strikes_a_triangle) ASSERT_EQ(xs.count(), 1); EXPECT_EQ(xs[0].t, 2); -} \ No newline at end of file +} + +TEST(TriangleTest, A_triangle_has_a_bounding_box) +{ + Triangle t = Triangle(Point(-3, 7, 2), Point(6, 2, -4), Point(2, -1, -1)); + + BoundingBox res = t.getBounds(); + + ASSERT_EQ(res.min, Point(-3, -1, -4)); + ASSERT_EQ(res.max, Point(6, 7, 2)); +}