BoundingSphere LOD::computeBound() const { if (_centerMode==USER_DEFINED_CENTER && _radius>=0.0f) { return BoundingSphere(_userDefinedCenter,_radius); } else if (_centerMode==UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED && _radius>=0.0f) { BoundingSphere bs = BoundingSphere(_userDefinedCenter,_radius); bs.expandBy(Group::computeBound()); //alternative (used in TxpPagedLOD) // bs.expandRadiusBy(Group::computeBound()); return bs; } else { return Group::computeBound(); } }
IntersectData BoundingSphere::IntersectBoundingSphere(const BoundingSphere& other) const { //The radius is the distance from any point on the sphere to the center. // //Therefore, by adding the radius of two spheres together, the result is //the distance between the centers of the spheres when they are touching. float radiusDistance = m_radius + other.GetRadius(); float centerDistance = (other.GetCenter() - m_center).Length(); //Since the radiusDistance is the distance bwteen the centers of the //spheres are when they're touching, you can subtract that from the //distance between the centers of the spheres to get the actual distance //between the two spheres. float distance = centerDistance - radiusDistance; //Spheres can only be intersecting if the distance between them is less //than 0. return IntersectData(distance < 0, distance); }
ModelEntitySP PrimitiveEntityFactory::createConePrimitiveEntity(const string& name, float scaleX, float scaleY, float scaleZ, const SurfaceMaterialSP& surfaceMaterial, const vector<AnimationStackSP>& allAnimStacks) const { ModelFactory modelFactory; GLUSshape shape; float halfExtend = 0.5f; float radius = 0.5f; uint32_t numberSlices = 32; uint32_t numberStacks = 32; glusCreateConef(&shape, halfExtend, radius, numberSlices, numberStacks); BoundingSphere boundingSphere; boundingSphere.setRadius(glusLengthf(halfExtend, radius, 0.0f)); return ModelEntitySP(new ModelEntity(name, modelFactory.createModel(name, boundingSphere, shape, surfaceMaterial, allAnimStacks), scaleX, scaleY, scaleZ)); }
ModelEntitySP PrimitiveEntityFactory::createTorusPrimitiveEntity(const string& name, float scaleX, float scaleY, float scaleZ, const SurfaceMaterialSP& surfaceMaterial, const vector<AnimationStackSP>& allAnimStacks) const { ModelFactory modelFactory; GLUSshape shape; float innerRadius = 0.25f; float outerRadius = 0.5f; uint32_t numberSlices = 32; uint32_t numberStacks = 32; glusCreateTorusf(&shape, innerRadius, outerRadius, numberSlices, numberStacks); BoundingSphere boundingSphere; boundingSphere.setRadius(outerRadius); return ModelEntitySP(new ModelEntity(name, modelFactory.createModel(name, boundingSphere, shape, surfaceMaterial, allAnimStacks), scaleX, scaleY, scaleZ)); }
BoundingSphere Transform::computeBound() const { BoundingSphere bsphere = Group::computeBound(); if (!bsphere.valid()) return bsphere; // note, NULL pointer for NodeVisitor, so compute's need // to handle this case gracefully, normally this should not be a problem. Matrix l2w; computeLocalToWorldMatrix(l2w,NULL); Vec3 xdash = bsphere._center; xdash.x() += bsphere._radius; xdash = xdash*l2w; Vec3 ydash = bsphere._center; ydash.y() += bsphere._radius; ydash = ydash*l2w; Vec3 zdash = bsphere._center; zdash.z() += bsphere._radius; zdash = zdash*l2w; bsphere._center = bsphere._center*l2w; xdash -= bsphere._center; float len_xdash = xdash.length(); ydash -= bsphere._center; float len_ydash = ydash.length(); zdash -= bsphere._center; float len_zdash = zdash.length(); bsphere._radius = len_xdash; if (bsphere._radius<len_ydash) bsphere._radius = len_ydash; if (bsphere._radius<len_zdash) bsphere._radius = len_zdash; return bsphere; }
BoundingSphere Switch::computeBound() const { BoundingSphere bsphere; if (_children.empty()) { return bsphere; } // note, special handling of the case when a child is an Transform, // such that only Transforms which are relative to their parents coordinates frame (i.e this group) // are handled, Transform relative to and absolute reference frame are ignored. BoundingBox bb; bb.init(); for(unsigned int pos=0;pos<_children.size();++pos) { const osg::Transform* transform = _children[pos]->asTransform(); if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF) { if( _values[pos] == true ) bb.expandBy(_children[pos]->getBound()); } } if (!bb.valid()) { return bsphere; } bsphere._center = bb.center(); bsphere._radius = 0.0f; for(unsigned int pos=0;pos<_children.size();++pos) { const osg::Transform* transform = _children[pos]->asTransform(); if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF) { if( _values[pos] == true ) bsphere.expandRadiusBy(_children[pos]->getBound()); } } return bsphere; }
/*! * creates a BoundingSphere which encloses all given bvhNodes and adds all children * to this parent */ void DeformableBvhNode::createBoundingSphere(const std::list<DeformableBvhNode*>& bvhNodes) { //std::cout << "DeformableBvhNode::createBoundingSphere(const std::list<DeformableBvhNode*>& bvhNodes)" << std::endl; BoundingSphere* bv = 0; for (std::list<DeformableBvhNode*>::const_iterator iter = bvhNodes.begin(); iter != bvhNodes.end(); ++iter) { if (bv == 0) { bv = new BoundingSphere(*((BoundingSphere*)((*iter)->getBoundingVolume()))); } else { bv->mergeWith((BoundingSphere*)((*iter)->getBoundingVolume())); } } mBoundingVolume = bv; }
BoundingSphere Geode::computeBound() const { BoundingSphere bsphere; _bbox.init(); DrawableList::const_iterator itr; for(itr=_drawables.begin(); itr!=_drawables.end(); ++itr) { _bbox.expandBy((*itr)->getBound()); } if (_bbox.valid()) { bsphere.expandBy(_bbox); } return bsphere; }
Node* PatchSet::createPatchGroup(const std::string& filename, PatchOptions* poptions) { PatchGroup* pgroup = new PatchGroup; pgroup->setOptions(poptions); Transform* patch = createPatch(filename, poptions); BoundingSphere bsphere = patch->getBound(); pgroup->setCenter(bsphere.center()); if (poptions->getPatchLevel() >= _maxLevel) { pgroup->addChild(patch, 0.0, 1e10); } else { pgroup->addChild(patch, 0.0, 1.0); pgroup->setRange(1, 1.0, 1e10); pgroup->setFileName(1, "foo.osgearth_engine_seamless_patch"); } return pgroup; }
bool sphereSphereCollision(const BoundingSphere &M, const Vec3f &vel, const BoundingSphere &S) { const Vec3f e = M.center() - S.center(); const float r = S.radius() + M.radius(); if ( vecLength(e) < r ) return true; const float delta = Math::square(vecDot(e, vel)) - vecDot(vel, vel) * (vecDot(e, e) - r*r); if ( delta < 0.0f ) return false; const float t = (-vecDot(e, vel) - std::sqrt(delta)) / vecDot(vel, vel); if ( t < 0.0f || t > 1.0f ) return false; return true; }
bool BasicPrimitiveTests::IntersectingRayAgainstSphere(const Ray & ray, const BoundingSphere & sphere, float & rtn_t) { /* Main idea: - Ray is substituted into sphere equation. Then solve quadratic formula for intersection. - Test if intersection is within segment/ray endpoints -> Use dot(X-C, X-C) = exp(r, 2) -> As sphere equation. Solving for "t": -> Quadratic equation in "t" encountered. -> where b = dot(m, d) -> where c = dot(m, m) - r*r -> where m = P-C -> t = -b + sqrt(exp(b, 2) - c) -> t = -b - sqrt(exp(b, 2) - c) Notes: -> Number of real roots => number of intersections: -> Categorized by discriminant d = exp(b, 2) - c -> May have false intersection with t < 0 when ray starts from inside sphere. */ Eigen::Vector3f m = ray.GetOrigin() - sphere.GetCenter(); float b = (m).dot(ray.GetDirection()); float c = m.dot(m); if (c > 0.0f && b > 0.0f) { //Case: Ray origin outside of sphere and points away. => No Intersections. return false; } float discriminant = b * b - c; if (discriminant < 0.0f) { //Case: Misses sphere return false; } else { //Case: Hits sphere. Calculate smallest t. rtn_t = -b - sqrt(discriminant); if (rtn_t < 0.0f) { rtn_t = 0.0f; } return true; } }
//---------------------------------------------------------------------------- bool Culler::IsVisible (BoundingSphere const& sphere) { if (sphere.GetRadius() == 0.0f) { // The node is a dummy node and cannot be visible. return false; } // Start with the last pushed plane, which is potentially the most // restrictive plane. int index = mPlaneQuantity - 1; unsigned int mask = (1u << index); for (int i = 0; i < mPlaneQuantity; ++i, --index, mask >>= 1) { if (mPlaneState & mask) { int side = sphere.WhichSide(mPlane[index]); if (side < 0) { // The object is on the negative side of the plane, so // cull it. return false; } if (side > 0) { // The object is on the positive side of plane. There is // no need to compare subobjects against this plane, so // mark it as inactive. mPlaneState &= ~mask; } } } return true; }
float sphereEdgeDistance( const BoundingSphere &sphere, const Vec3f &D, const Vec3f &A, const Vec3f &B, Vec3f *contactPoint) { const Vec3f AB = B - A; const Vec3f C = sphere.center() - A; const float AB2 = vecDot(AB, AB); const float AB_dot_C = vecDot(C, AB); const float AB_dot_D = vecDot(AB, D); float minR; if ( !Math::lowestPositiveQuadraticRoot( vecDot(D, D) - Math::square(AB_dot_D)/AB2, 2.0f*(vecDot(C, D) - (AB_dot_D*AB_dot_C)/AB2), vecDot(C, C) - Math::square(sphere.radius()) - Math::square(AB_dot_C)/AB2, &minR) ) { return NoIntersection; } const ud::Vec3f intersect = sphere.center() + D*minR - A; const float t = vecDot(AB, intersect); if ( 0.0f <= t && t <= AB2 ) { *contactPoint = A + AB * t; return minR; } else { return NoIntersection; } }
IntersectData Plane::IntersectSphere(const BoundingSphere& other) const { //Calculating the dot product between the Plane's normal and the Sphere's //center gets how far the sphere's center is along the Plane's normal. // //Adding the distance adjusts this value based on how far the Plane itself //is along the normal. // //The end result of this is how far the Sphere's center is from the Plane. //The absolute value is taken so that this result is always positive. float distanceFromSphereCenter = (float)fabs(m_normal.Dot(other.GetCenter()) + m_distance); //As long as the distanceFromSphereCenter is valid and positive, then //the distance from the sphere can be calculated simply by subtracting //it's radius. float distanceFromSphere = distanceFromSphereCenter - other.GetRadius(); //The only time the plane can be intersecting the sphere is if the sphere //has less than 0 distance from the plane. Otherwise, if there is distance //between the plane and sphere, then there must be a gap between the //plane and sphere, and they cannot be intersecting. return IntersectData(distanceFromSphere < 0, m_normal * distanceFromSphere); }
void BoundingSphere::expandBy(const BoundingSphere& sh) { // ignore operation if incomming BoundingSphere is invalid. if (!sh.valid()) return; // This sphere is not set so use the inbound sphere if (!valid()) { _center = sh._center; _radius = sh._radius; return; } // Calculate d == The distance between the sphere centers double d = ( _center - sh.center() ).length(); // New sphere is already inside this one if ( d + sh.radius() <= _radius ) { return; } // New sphere completely contains this one if ( d + _radius <= sh.radius() ) { _center = sh._center; _radius = sh._radius; return; } // Build a new sphere that completely contains the other two: // // The center point lies halfway along the line between the furthest // points on the edges of the two spheres. // // Computing those two points is ugly - so we'll use similar triangles double new_radius = (_radius + d + sh.radius() ) * 0.5; double ratio = ( new_radius - _radius ) / d ; _center[0] += ( sh.center()[0] - _center[0] ) * ratio; _center[1] += ( sh.center()[1] - _center[1] ) * ratio; _center[2] += ( sh.center()[2] - _center[2] ) * ratio; _radius = new_radius; }
void BoundingSphere::expandRadiusBy(const BoundingSphere& sh) { if (sh.valid()) { if (valid()) { value_type r = (sh._center-_center).length()+sh._radius; if (r>_radius) _radius = r; // else do nothing as vertex is within sphere. } else { _center = sh._center; _radius = sh._radius; } } }
void BoundingSphere::merge(const BoundingSphere& sphere) { if (sphere.isEmpty()) return; // Calculate the distance between the two centers. float vx = center.x - sphere.center.x; float vy = center.y - sphere.center.y; float vz = center.z - sphere.center.z; float d = sqrt(vx * vx + vy * vy + vz * vz); // If one sphere is contained inside the other, set to the larger sphere. if (d <= (sphere.radius - radius)) { center = sphere.center; radius = sphere.radius; return; } else if (d <= (radius - sphere.radius)) { return; } // Calculate the unit vector between the two centers. GP_ASSERT(d != 0.0f); float dI = 1.0f / d; vx *= dI; vy *= dI; vz *= dI; // Calculate the new radius. float r = (radius + sphere.radius + d) * 0.5f; // Calculate the new center. float scaleFactor = (r - sphere.radius); vx = vx * scaleFactor + sphere.center.x; vy = vy * scaleFactor + sphere.center.y; vz = vz * scaleFactor + sphere.center.z; // Set the new center and radius. center.x = vx; center.y = vy; center.z = vz; radius = r; }
bool RayIntersector::intersects(const BoundingSphere& bs) { // if bs not valid then return false based on the assumption that the node is empty. if (!bs.valid()) return false; // test for _start inside the bounding sphere Vec3d sm = _start - bs._center; double c = sm.length2() - bs._radius * bs._radius; if (c<0.0) return true; // solve quadratic equation double a = _direction.length2(); double b = (sm * _direction) * 2.0; double d = b * b - 4.0 * a * c; // no intersections if d<0 if (d<0.0) return false; // compute two solutions of quadratic equation d = sqrt(d); double div = 1.0/(2.0*a); double r1 = (-b-d)*div; double r2 = (-b+d)*div; // return false if both intersections are before the ray start if (r1<=0.0 && r2<=0.0) return false; // if LIMIT_NEAREST and closest point of bounding sphere is further than already found intersection, return false if (_intersectionLimit == LIMIT_NEAREST && !getIntersections().empty()) { double minDistance = sm.length() - bs._radius; if (minDistance >= getIntersections().begin()->distance) return false; } // passed all the rejection tests so line must intersect bounding sphere, return true. return true; }
float sphereTriangleCollision( const BoundingSphere &sphere, const Vec3f &dir, const Vec3f &p0, const Vec3f &p1, const Vec3f &p2, Vec3f *contactPoint) { Planef trigPlane(p0, p1, p2); float d = vecDot(dir, trigPlane.normal); float minDist = NoIntersection; if ( vecDot(dir, trigPlane.normal) > 0.0 ) { return NoIntersection; } if ( d == 0.0f ) { if ( trigPlane.distance(sphere.center()) < sphere.radius() ) return NoIntersection; } else { const Vec3f orign = sphere.center() - sphere.radius()*vecNormal(trigPlane.normal); const float t = -(trigPlane.d + vecDot(orign, trigPlane.normal)) / d; if ( t >= 0.0f ) { const Vec3f planePoint = orign + dir * t; if ( pointInTriangle(planePoint, vecNormal(trigPlane.normal), p0, p1, p2) ) { *contactPoint = planePoint; return t; } } } float dist = spherePointDistance(sphere, dir, p0); if ( dist < minDist ) { minDist = dist; *contactPoint = p0; } dist = spherePointDistance(sphere, dir, p1); if ( dist < minDist ) { minDist = dist; *contactPoint = p1; } dist = spherePointDistance(sphere, dir, p2); if ( dist < minDist ) { minDist = dist; *contactPoint = p2; } Vec3f edgeContactPoint; dist = sphereEdgeDistance(sphere, dir, p1, p0, &edgeContactPoint); if ( dist < minDist ) { minDist = dist; *contactPoint = edgeContactPoint; } dist = sphereEdgeDistance(sphere, dir, p2, p1, &edgeContactPoint); if ( dist < minDist ) { minDist = dist; *contactPoint = edgeContactPoint; } dist = sphereEdgeDistance(sphere, dir, p0, p2, &edgeContactPoint); if ( dist < minDist ) { minDist = dist; *contactPoint = edgeContactPoint; } return minDist; }
Pollen() noexcept : type((Type)Random<uint32_t>(0u,3u)) { { Lock lock(mxCounter); if ((++counter) == 1) { //create an icosphere of radius 1.0f std::vector<Vec3> spherePositions; { Mesh mesh; auto data(mesh.Sphere({}, 1.0f, YGG_DEBUG_CONDITIONAL(2,4), true).Decompose()); for (auto i : data->Indices) spherePositions.push_back(data->Positions[i]); } //deform a copy of the sphere once for each type for (Type t = Type::Linear; t < Type::Count; t = (Type)((uint32_t)t + 1u)) { uint32_t spikeCount(40); switch (t) { case Type::Linear: spikeCount = 3 * spikeCount / 4; break; case Type::Square: spikeCount = 2 * spikeCount / 3; break; case Type::Circular: spikeCount = spikeCount / 2; break; } //pick equidistant points around unit sphere (see http://www.cmu.edu/biolphys/deserno/pdf/sphere_equi.pdf) std::vector<Vec3> spikes; float a((4.0f * Pi) / (float)spikeCount); float d(sqrtf(a)); uint32_t mTheta(Round<uint32_t>(Pi / d)); float dTheta(Pi / (float)mTheta); float dAlpha(a / dTheta); for (uint32_t m = 0; m < mTheta; ++m) { float theta((Pi*((float)m + 0.5f)) / (float)mTheta); uint32_t mAlpha(Round<uint32_t>((2.0f * Pi * sinf(theta)) / dAlpha)); for (uint32_t n = 0; n < mAlpha; ++n) { float alpha((2.0f * Pi * (float)n) / (float)mAlpha); spikes.emplace_back(sinf(theta) * cosf(alpha), sinf(theta)*sinf(alpha), cos(theta)); } } //minimum distance to consider a spike as being "in range" float rad = d / 2.1f; //loop through the vertices and deform the sphere based //on proximity to nearest spike std::vector<Vec3> positions(spherePositions); for (size_t v = 0; v < positions.size(); ++v) { //find closest spike float dist(Vec3::DistanceSquared(positions[v], spikes[0])); for (size_t s = 1; s < spikes.size(); ++s) dist = std::min(dist, Vec3::DistanceSquared(positions[v], spikes[s])); //convert distance into a proximity function & deform dist = ((rad - sqrtf(dist)) / rad); positions[v] *= metrics.Radius + metrics.Radius * 0.25f * ApplyDeformation(t, dist); } //create static mesh Mesh mesh; meshes.emplace_back(new StaticMesh(mesh.AddPositions(std::move(positions)).GenerateIndices().GenerateNormals())); } } if (Game::Physics()->Started() && !rigidBodyMesh) rigidBodyMesh = Game::Physics()->CreateSphereMesh(metrics.Radius); } entity.reset(Game::Scene()->Create("", this)); auto _position(PickSpawnLocation(true)); transform = entity->Add<Transform>(_position); transform->Forward(Random<Vec3>()); static std::vector<Colour> colours { Yellow, Olive, BlanchedAlmond, YellowGreen }; material.reset(new Phong(Colour(colours[Random<size_t>(0, colours.size() - 1)],0.0f))); entity->Add<MeshRenderer>(meshes[Random<size_t>(0, meshes.size() - 1)], material); if (Game::Physics()->Started()) rigidBody.reset(Game::Physics()->Create(rigidBodyMesh, true, _position, transform->Orientation(), metrics.Density)); entity->Add<Ticker>()->OnTick += [](Ticker* t, float deltaTime) { auto pollen(static_cast<Pollen*>(t->Entity()->Data)); if (Game::Physics()->Started()) pollen->transform->Pose(pollen->rigidBody->Position(), pollen->rigidBody->Orientation()); if (!world.Contains(pollen->transform->Position())) { Vec3 newPos(PickSpawnLocation(false)); pollen->transform->Position(newPos); if (Game::Physics()->Started()) pollen->rigidBody->Position(newPos).Stop(); pollen->spawnTime = 0.0f; } pollen->spawnTime += deltaTime; float alpha(std::min(pollen->spawnTime * 0.33f,1.0f)); if (!spawnBounds.Contains(pollen->transform->Position())) { alpha = std::min(1.0f - Clamp((Vec3::Distance(spawnBounds.Center, pollen->transform->Position()) - spawnBounds.Radius) / (world.Radius - spawnBounds.Radius), 0.0f, 1.0f), alpha); } pollen->material->Colour(Colour(pollen->material->Colour(), alpha)); }; }
bool BoundingBox::intersect(BoundingSphere& boundingSphere) { return boundingSphere.intersect(*this); }
bool BoundingPolyhedron::intersects (BoundingSphere &bs) { return bs.intersects (*this); }
bool Drone::SelectionTest(GLVector3f w) { float distance = (mPosition - w).length(); BoundingSphere* bSphere = (BoundingSphere*) mBoundingShape.GetPtr(); return (distance <= bSphere->GetRadius()); }
TEST(BoundingSphere, Contains_BoundingBox) { BoundingSphere sphere; sphere.Center = Vector3::Zero; sphere.Radius = 42.0f; auto min = Vector3::Normalize({-1.f, -1.f, -1.f}) * 42.0f; auto max = Vector3::Normalize({1.f, 1.f, 1.f}) * 42.0f; auto unit = Vector3::Normalize({1.f, 1.f, 1.f}) * 42.0f; EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{Vector3::Zero, max})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{Vector3::Zero - unit * Vector3::UnitX, max - unit * Vector3::UnitX})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{Vector3::Zero - unit * Vector3::UnitY, max - unit * Vector3::UnitY})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{Vector3::Zero - unit * Vector3::UnitZ, max - unit * Vector3::UnitZ})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{min, Vector3::Zero})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{min + unit * Vector3::UnitX, Vector3::Zero + unit * Vector3::UnitX})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{min + unit * Vector3::UnitY, Vector3::Zero + unit * Vector3::UnitY})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingBox{min + unit * Vector3::UnitZ, Vector3::Zero + unit * Vector3::UnitZ})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{Vector3::Zero, max * 1.01f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{Vector3::Zero - unit * Vector3::UnitX, max * 1.01f - unit * Vector3::UnitX})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{Vector3::Zero - unit * Vector3::UnitY, max * 1.01f - unit * Vector3::UnitY})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{Vector3::Zero - unit * Vector3::UnitZ, max * 1.01f - unit * Vector3::UnitZ})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{min * 1.01f, Vector3::Zero})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{min * 1.01f + unit * Vector3::UnitX, Vector3::Zero + unit * Vector3::UnitX})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{min * 1.01f + unit * Vector3::UnitY, Vector3::Zero + unit * Vector3::UnitY})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingBox{min * 1.01f + unit * Vector3::UnitZ, Vector3::Zero + unit * Vector3::UnitZ})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(BoundingBox{max * 1.01f, max * 1.01f + unit})); }
TEST(BoundingSphere, Contains_BoundingSphere) { BoundingSphere sphere; sphere.Center = Vector3::Zero; sphere.Radius = 42.0f; EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(sphere)); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3::Zero, 43.0f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingSphere{Vector3::Zero, 41.0f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingSphere{Vector3{40.f, 0.f, 0.f}, 1.9f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingSphere{Vector3{0.f, 40.f, 0.f}, 1.9f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, 40.f}, 1.9f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingSphere{Vector3{-40.f, 0.f, 0.f}, 1.9f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingSphere{Vector3{0.f, -40.f, 0.f}, 1.9f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, -40.f}, 1.9f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{42.f, 0.f, 0.f}, 1.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, 42.f, 0.f}, 1.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, 42.f}, 1.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{-42.f, 0.f, 0.f}, 1.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, -42.f, 0.f}, 1.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, -42.f}, 1.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{43.f, 0.f, 0.f}, 2.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, 43.f, 0.f}, 2.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, 43.f}, 2.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{-43.f, 0.f, 0.f}, 2.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, -43.f, 0.f}, 2.0f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, -43.f}, 2.0f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(BoundingSphere{Vector3{43.f, 0.f, 0.f}, 0.5f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(BoundingSphere{Vector3{0.f, 43.f, 0.f}, 0.5f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, 43.f}, 0.5f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(BoundingSphere{Vector3{-43.f, 0.f, 0.f}, 0.5f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(BoundingSphere{Vector3{0.f, -43.f, 0.f}, 0.5f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(BoundingSphere{Vector3{0.f, 0.f, -43.f}, 0.5f})); }
TEST(BoundingSphere, Contains_Vector3) { BoundingSphere sphere; sphere.Center = Vector3::Zero; sphere.Radius = 42.0f; EXPECT_EQ(ContainmentType::Contains, sphere.Contains(Vector3::Zero)); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(Vector3{41.f, 0.f, 0.f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(Vector3{0.f, 41.f, 0.f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(Vector3{0.f, 0.f, 41.f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(Vector3{-41.f, 0.f, 0.f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(Vector3{0.f, -41.f, 0.f})); EXPECT_EQ(ContainmentType::Contains, sphere.Contains(Vector3{0.f, 0.f, -41.f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(Vector3{42.f, 0.f, 0.f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(Vector3{0.f, 42.f, 0.f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(Vector3{0.f, 0.f, 42.f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(Vector3{-42.f, 0.f, 0.f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(Vector3{0.f, -42.f, 0.f})); EXPECT_EQ(ContainmentType::Intersects, sphere.Contains(Vector3{0.f, 0.f, -42.f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(Vector3{43.f, 0.f, 0.f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(Vector3{0.f, 43.f, 0.f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(Vector3{0.f, 0.f, 43.f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(Vector3{-43.f, 0.f, 0.f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(Vector3{0.f, -43.f, 0.f})); EXPECT_EQ(ContainmentType::Disjoint, sphere.Contains(Vector3{0.f, 0.f, -43.f})); }
TEST(BoundingSphere, Intersects_BoundingSphere) { BoundingSphere sphere; sphere.Center = Vector3::Zero; sphere.Radius = 42.0f; EXPECT_TRUE(sphere.Intersects(sphere)); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3::Zero, 43.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3::Zero, 41.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{40.f, 0.f, 0.f}, 1.9f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 40.f, 0.f}, 1.9f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, 40.f}, 1.9f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{-40.f, 0.f, 0.f}, 1.9f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, -40.f, 0.f}, 1.9f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, -40.f}, 1.9f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{42.f, 0.f, 0.f}, 1.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 42.f, 0.f}, 1.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, 42.f}, 1.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{-42.f, 0.f, 0.f}, 1.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, -42.f, 0.f}, 1.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, -42.f}, 1.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{43.f, 0.f, 0.f}, 2.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 43.f, 0.f}, 2.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, 43.f}, 2.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{-43.f, 0.f, 0.f}, 2.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, -43.f, 0.f}, 2.0f})); EXPECT_TRUE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, -43.f}, 2.0f})); EXPECT_FALSE(sphere.Intersects(BoundingSphere{Vector3{43.f, 0.f, 0.f}, 0.5f})); EXPECT_FALSE(sphere.Intersects(BoundingSphere{Vector3{0.f, 43.f, 0.f}, 0.5f})); EXPECT_FALSE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, 43.f}, 0.5f})); EXPECT_FALSE(sphere.Intersects(BoundingSphere{Vector3{-43.f, 0.f, 0.f}, 0.5f})); EXPECT_FALSE(sphere.Intersects(BoundingSphere{Vector3{0.f, -43.f, 0.f}, 0.5f})); EXPECT_FALSE(sphere.Intersects(BoundingSphere{Vector3{0.f, 0.f, -43.f}, 0.5f})); }
TEST(BoundingSphere, Intersects_BoundingBox) { BoundingSphere sphere; sphere.Center = Vector3::Zero; sphere.Radius = 42.0f; auto min = Vector3::Normalize({-1.f, -1.f, -1.f}) * 42.0f; auto max = Vector3::Normalize({1.f, 1.f, 1.f}) * 42.0f; auto unit = Vector3::Normalize({1.f, 1.f, 1.f}) * 42.0f; EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero, max})); EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero - unit * Vector3::UnitX, max - unit * Vector3::UnitX})); EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero - unit * Vector3::UnitY, max - unit * Vector3::UnitY})); EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero - unit * Vector3::UnitZ, max - unit * Vector3::UnitZ})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min, Vector3::Zero})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min + unit * Vector3::UnitX, Vector3::Zero + unit * Vector3::UnitX})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min + unit * Vector3::UnitY, Vector3::Zero + unit * Vector3::UnitY})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min + unit * Vector3::UnitZ, Vector3::Zero + unit * Vector3::UnitZ})); EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero, max * 1.01f})); EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero - unit * Vector3::UnitX, max * 1.01f - unit * Vector3::UnitX})); EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero - unit * Vector3::UnitY, max * 1.01f - unit * Vector3::UnitY})); EXPECT_TRUE(sphere.Intersects(BoundingBox{Vector3::Zero - unit * Vector3::UnitZ, max * 1.01f - unit * Vector3::UnitZ})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min * 1.01f, Vector3::Zero})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min * 1.01f + unit * Vector3::UnitX, Vector3::Zero + unit * Vector3::UnitX})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min * 1.01f + unit * Vector3::UnitY, Vector3::Zero + unit * Vector3::UnitY})); EXPECT_TRUE(sphere.Intersects(BoundingBox{min * 1.01f + unit * Vector3::UnitZ, Vector3::Zero + unit * Vector3::UnitZ})); EXPECT_FALSE(sphere.Intersects(BoundingBox{max * 1.01f, max * 1.01f + unit})); }
bool BoundingBox::intersects(const BoundingSphere& sphere) const { return sphere.intersects(*this); }
std::unique_ptr<float> Ray::Intersects(const BoundingSphere& bs) { return bs.Intersects(*this); }