void T71::sphereEnter(Sphere &s){ /**********************************/ if (related) s.setSize(3.f); // make the sphere bigger else s.setSize(1.f); //make the sphere smaller /**********************************/ this->texture=driver->getTexture(texturepath+"won.png"); // build a block and paint it with texture block = smgr->addCubeSceneNode(fieldsize); block->setMaterialTexture(0,texture); block->setPosition(cubePosition(x,y,true)); block->setMaterialFlag(video::EMF_LIGHTING, false); cerr<<"you have won"; }

bool Ellipsoid::SweepAgainst( const CollisionTriangle& t, const Vector& v, const AABB& SweepAABB, CollisionInfo* const pInfo ) const { if( SweepAABB.Intersects( t.m_AABB ) ) // Broad phase: test sweep bounds against precomputed triangle bounds { const Vector InvExtents = 1.0f / m_Extents; const Triangle ESpaceTri( t.m_Triangle.m_Vec1 * InvExtents, t.m_Triangle.m_Vec2 * InvExtents, t.m_Triangle.m_Vec3 * InvExtents ); const Sphere UnitSphere( m_Center * InvExtents, 1.0f ); const Vector ESpaceOffset = v * InvExtents; if( UnitSphere.SweepAgainst( ESpaceTri, ESpaceOffset, pInfo ) ) { if( pInfo ) { pInfo->m_Intersection *= m_Extents; pInfo->m_Plane = Plane( ( pInfo->m_Plane.m_Normal * InvExtents ).GetNormalized(), pInfo->m_Intersection ); } return true; } } return false; }

std::vector<SPHParticle*> PhysicsObject::createParticles(const Sphere<float>& sphere, const float divideLength) { std::vector<SPHParticle*> newParticles; const auto points = sphere.toPoints(divideLength); for (const auto& pos : points) { SPHParticle* p = new SPHParticle(pos, divideLength*0.5f, &this->constant, nextId++); particles.push_back(p); newParticles.push_back(p); } return newParticles; }

void Collide::raySphereCollide(const Body * ray_, const Body * sphere_) { Ray *ray = (Ray*)ray_; Sphere *sphere = (Sphere*)sphere_; Vector3 vec = ray->getStart() - sphere->getCenter(); setCollide(true); setDistance(0.0f); float fB = vec.Dot(ray->getDir()); float fC = vec.Dot(vec) - sphere->getRadius()*sphere->getRadius(); if (fC > 0.0f && fB > 0.0f) setCollide(false); float fDisc = fB*fB - fC; if (fDisc < 0.0f) setCollide(false); // compute the response vectors Vector3 responseObject1 = ray_->getCenter()- sphere_->getCenter(); Vector3 responseObject2 = sphere_->getCenter() - ray_->getCenter(); setResponseObject1(responseObject1); setResponseObject2(responseObject2); }

bool PCZFrustum::isVisible( const Sphere & bound) const { // Check originplane if told to if (mUseOriginPlane) { Plane::Side side = mOriginPlane.getSide(bound.getCenter()); if (side == Plane::NEGATIVE_SIDE) { Real dist = mOriginPlane.getDistance(bound.getCenter()); if (dist > bound.getRadius()) { return false; } } } // For each extra active culling plane, see if the entire sphere is on the negative side // If so, object is not visible PCPlaneList::const_iterator pit = mActiveCullingPlanes.begin(); while ( pit != mActiveCullingPlanes.end() ) { PCPlane * plane = *pit; Plane::Side xside = plane->getSide(bound.getCenter()); if (xside == Plane::NEGATIVE_SIDE) { Real dist = plane->getDistance(bound.getCenter()); if (dist > bound.getRadius()) { return false; } } pit++; } return true; }

/* special function that returns true only when sphere fully fits inside the frustum. */ bool PCZFrustum::isFullyVisible(const Sphere& bound) const { // Check originplane if told to if (mUseOriginPlane) { if (mOriginPlane.getDistance(bound.getCenter()) <= bound.getRadius() || mOriginPlane.getSide(bound.getCenter()) != Plane::POSITIVE_SIDE) { return false; } } // For each extra active culling plane, // see if the sphere is not on the positive side // If so, object is not fully visible PCPlaneList::const_iterator pit = mActiveCullingPlanes.begin(); while ( pit != mActiveCullingPlanes.end() ) { PCPlane* plane = *pit; if (plane->getDistance(bound.getCenter()) <= bound.getRadius() || plane->getSide(bound.getCenter()) != Plane::POSITIVE_SIDE) { return false; } pit++; } return true; }

Sphere Sphere::OptimalEnclosingSphere(const vec &a, const vec &b, const vec &c, const vec &d, const vec &e, int &redundantPoint) { Sphere s = OptimalEnclosingSphere(b,c,d,e); if (s.Contains(a, sEpsilon)) { redundantPoint = 0; return s; } s = OptimalEnclosingSphere(a,c,d,e); if (s.Contains(b, sEpsilon)) { redundantPoint = 1; return s; } s = OptimalEnclosingSphere(a,b,d,e); if (s.Contains(c, sEpsilon)) { redundantPoint = 2; return s; } s = OptimalEnclosingSphere(a,b,c,e); if (s.Contains(d, sEpsilon)) { redundantPoint = 3; return s; } s = OptimalEnclosingSphere(a,b,c,d); mathassert(s.Contains(e, sEpsilon)); redundantPoint = 4; return s; }

void MyApp::setupScene() { int N_SPHERES = 8; float SKY_HEIGHT = 175.0f; float MIN_RAD = 5; float MAX_RAD = 15; int MIN_TESSFACTOR = 2; int MAX_TESSFACTOR = 7; float spheres_area = GRID_WIDTH; for (int i=0; i<N_SPHERES; i++) { Sphere s; s.setPos( rand() % (unsigned int)spheres_area - spheres_area / 2.0f, SKY_HEIGHT, rand() % (unsigned int)spheres_area - spheres_area / 2.0f ); s.setTargetPos(s.getPos().x, 25.0f, s.getPos().z); float rnd = rand() / (float)RAND_MAX; s.radius = MIN_RAD + rnd * (MAX_RAD - MIN_RAD); s.tessFactor = rand() % (MAX_TESSFACTOR - MIN_TESSFACTOR + 1) + MIN_TESSFACTOR; m_spheres.push_back(s); } // tess objects parameters for (int i=0; i<4; i++) { tessObjects[i].bWireframe = false; tessObjects[i].iEdgeFactor = 10; tessObjects[i].iInsideFactor = 10; tessObjects[i].partitioning = TessPartitioning::INTEGER; } }

static void generate_shadow_cameras( Slice<ShadowCamera> out, const PlayerCamera &view, float near, float far, float fov, float aspect, const Vec3 &lightdir, float ratio) { Sphere spheres[4]; generate_frustum_split_spheres(spheres, fov, aspect, near, far, ratio); for (int i = 0; i < 4; i++) { const Sphere sphere = transform(spheres[i], view.transform); ShadowCamera &outcam = out[i]; outcam.transform.orientation = Quat_LookAt(lightdir); const Vec2 texel = Vec2(sphere.diameter()) / Vec2(1024); Vec3 center = inverse(outcam.transform.orientation).rotate(sphere.center); center.x = std::floor(center.x / texel.x) * texel.x; center.y = std::floor(center.y / texel.y) * texel.y; center.z += sphere.radius + sphere.radius; outcam.transform.translation = outcam.transform.orientation.rotate(center); outcam.set_from_sphere(sphere, sphere.radius); outcam.apply_transform(); } }

void ArcballTestApp::setup() { gl::enableDepthRead(); gl::enableDepthWrite(); mZLookAt = 0.5f; mCam.setPerspective( 45.0f, getWindowAspectRatio(), 0.1f, 1000.0f ); mCam.lookAt( vec3( 0,3, 5 ), vec3( mZLookAt ) ); mDebugCam = mCam; mEarthSphere = Sphere( vec3( 0, 0, -3 ), 1.5f ); mEarth = gl::Batch::create( geom::Sphere( Sphere( vec3(0), mEarthSphere.getRadius() ) ).subdivisions( 50 ), gl::getStockShader( gl::ShaderDef().texture() ) ); mEarthTex = gl::Texture::create( loadImage( loadResource( EARTH_TEX_RES ) ) ); mMarker = gl::Batch::create( geom::Sphere().radius(0.1f).subdivisions( 50 ), gl::getStockShader( gl::ShaderDef().color() ) ); auto cylinder = geom::Cylinder().radius(0.05f).height( mEarthSphere.getRadius() * 3.5 ) >> geom::Translate( 0, -1.75 * mEarthSphere.getRadius(), 0 ); mConstraintAxis = gl::Batch::create( cylinder, gl::getStockShader( gl::ShaderDef().color() ) ); mArcball = Arcball( &mCam, mEarthSphere ); mCamUi = CameraUi( &mDebugCam ); }

inline void Exhaustive(vector<BoundedRay> &rays, vector<int> &rayIndices, const int indexOffset, const int indexCount, const vector<Sphere> &spheres, vector<int> &sphereIDs, const int sphereOffset, const int sphereCount, vector<Hit> &hits) { for (int i = indexOffset; i < indexOffset + indexCount; ++i) { const int rayID = rayIndices[i]; const Ray charles = rays[rayID].ToRay(); float tHit = rays[rayID].t == 0.0f ? 1e30 : rays[rayID].t; Hit hit = hits[rayID]; for (int s = sphereOffset; s < sphereOffset + sphereCount; ++s) { ++exhaustives; const Sphere sphere = spheres[sphereIDs[s]]; const float t = sphere.Intersect(charles); if (0 < t && t < tHit) { hit = Hit(sphereIDs[s]); tHit = t; } } hits[rayID] = hit; rays[rayID].t = tHit; } }

//static bool Intersections::sphereAABBIntersection(Sphere s, AABB a){ Vector3 sphere_pos = s.getPos(); double sphere_radius = s.getRadius(); Vector3 aabb_bmin = a.getBmin(); Vector3 aabb_bmax = a.getBmax(); double r2 = sphere_radius * sphere_radius; double dmin = 0.0; //3 dimensions for( int i = 0; i < 3; i++ ) { if( sphere_pos[i] < aabb_bmin[i] ) { dmin += square( sphere_pos[i] - aabb_bmin[i] ); } else if( sphere_pos[i] > aabb_bmax[i] ) { dmin += square( sphere_pos[i] - aabb_bmax[i] ); } } return dmin <= r2; }

Assembly *GraspGLObjects::CreateRoom( void ) { Assembly *structure = new Assembly(); structure->SetColor( BLACK ); // Tunnel tunnel = new Assembly(); Cylinder *cylinder = new Cylinder( room_radius, room_radius, room_length, room_facets ); cylinder->SetColor( WHITE ); cylinder->SetTexture( wall_texture ); cylinder->SetOrientation( 90.0, 0.0, 0.0 ); tunnel->AddComponent( cylinder ); // Reference Bars double bar_length = room_length - 5.0 * reference_bar_radius; for (int i=0; i < reference_bars; i++ ){ Cylinder *referenceBar = new Cylinder( reference_bar_radius, reference_bar_radius, bar_length, reference_bar_facets ); referenceBar->SetOffset( room_radius, 0.0, 0.0 ); referenceBar->SetOrientation( 90.0 + 180 * (float) i / (float) reference_bars, referenceBar->kVector ); referenceBar->SetColor( 1.0 - (double) i / reference_bars, 1.0f - (double) i / reference_bars, 1.0f - (double) i / reference_bars, 1.0 ); // The texturing on the bars may be commented out for the moment because it lengthens the rendering time too much. referenceBar->SetTexture( references_texture ); tunnel->AddComponent( referenceBar ); referenceBar = new Cylinder( reference_bar_radius, reference_bar_radius, bar_length, reference_bar_facets ); referenceBar->SetOffset( room_radius, 0.0, 0.0 ); referenceBar->SetOrientation( - 90.0 + 180 * (float) i / (float) reference_bars, referenceBar->kVector ); referenceBar->SetColor( (double) i / reference_bars, (double) i / reference_bars, (double) i / reference_bars, 1.0 ); // See above. referenceBar->SetTexture( references_texture ); tunnel->AddComponent( referenceBar ); } structure->AddComponent( tunnel ); Sphere *sphere = new Sphere( target_ball_radius ); sphere->SetPosition( 0.0, 0.0, room_length / 2.0 ); sphere->SetColor( RED ); structure->AddComponent( sphere ); return structure; }

void Sphere_Enclose(Sphere &s, const T &obj) { PointWithDistance corners[n]; for(int i = 0; i < n; ++i) { corners[i].pt = obj.CornerPoint(i); corners[i].d = s.pos.DistanceSq(corners[i].pt); } std::sort(corners, corners+n); for(int i = n-1; i >= 0; --i) s.Enclose(corners[i].pt); }

//----------------------------------------------------------------------------- //! 衝突計算 //! 視錐台 vs 球 //! @param [in] sphere 当たり判定のしたい球 //----------------------------------------------------------------------------- bool Frustum::isHit(Sphere& sphere) { // 視錐台の面の更新 updateFrustumPlane(); // 球の座標 Vector3 spherePos = sphere.getPosition(); // 球の半径 f32 sphereRad = sphere.getRadius(); // 面との距離がすべての面の内側にあればあたっている for (s32 i = 0; i < 6; ++i){ f32 distance = _plane[i].getDistance(spherePos); // 裏面の場合距離はマイナスなので半径を足しても // 負の場合視錐台の外側で且つ半径以上離れている if (distance + sphereRad < 0.0f){ return false; } } return true; }

//============================================================================== static Bool test(const Aabb& aabb, const Sphere& s) { const Vec4& c = s.getCenter(); // find the box's closest point to the sphere Vec4 cp(0.0); // Closest Point for(U i = 0; i < 3; i++) { // if the center is greater than the max then the closest // point is the max if(c[i] > aabb.getMax()[i]) { cp[i] = aabb.getMax()[i]; } else if(c[i] < aabb.getMin()[i]) // relative to the above { cp[i] = aabb.getMin()[i]; } else { // the c lies between min and max cp[i] = c[i]; } } F32 rsq = s.getRadius() * s.getRadius(); // if the c lies totally inside the box then the sub is the zero, // this means that the length is also zero and thus its always smaller // than rsq Vec4 sub = c - cp; if(sub.getLengthSquared() <= rsq) { return true; } return false; }

CameraPersp CameraPersp::getFrameSphere( const Sphere &worldSpaceSphere, int maxIterations ) const { CameraPersp result = *this; result.setEyePoint( worldSpaceSphere.getCenter() - result.mViewDirection * getCenterOfInterest() ); float minDistance = 0.01f, maxDistance = 100000.0f; float curDistance = getCenterOfInterest(); for( int i = 0; i < maxIterations; ++i ) { float curRadius = result.getScreenRadius( worldSpaceSphere, 2.0f, 2.0f ); if( curRadius < 1.0f ) { // we should get closer maxDistance = curDistance; curDistance = ( curDistance + minDistance ) * 0.5f; } else { // we should get farther minDistance = curDistance; curDistance = ( curDistance + maxDistance ) * 0.5f; } result.setEyePoint( worldSpaceSphere.getCenter() - result.mViewDirection * curDistance ); } result.setCenterOfInterest( result.getEyePoint().distance( worldSpaceSphere.getCenter() ) ); return result; }

bool Cone::intersects(const Sphere& b) const { // If the bounding sphere contains the tip, then // they definitely touch. if (b.contains(this->tip)) { return true; } // Move the tip backwards, effectively making the cone bigger // to account for the radius of the sphere. Vector3 tip = this->tip - direction * b.radius / sinf(angle); return Cone(tip, direction, angle).contains(b.center); }

/* ....................................................................... */ Sphere::Sphere(const Sphere& other, const osg::CopyOp& copyop): Collidable(other, copyop) { m_ODE_geom = dCreateSphere(NULL, REAL(1.0)) ; _cloneODESphere(other.m_ODE_geom, m_ODE_geom) ; dGeomSetBody(m_ODE_geom, m_ODE_body) ; dGeomSetData(m_ODE_geom, this) ; setCollidableOffset(other.getCollidableOffset()) ; }

void Cloth::apply_sphere_constraints() { for (World::sphere_array_t::const_iterator it = m_world.spheres.begin(); it != m_world.spheres.end(); ++it) { Sphere *sp = *it; float r = sp->r; float r2 = r * r; for (size_t idx = 0; idx < m_num_points; ++idx) { if (m_invmass[idx] == 0.0f) continue; Point &p = m_points[idx]; float d = sp->equ(p.pos); if (d < 0) { glm::vec3 v = p.pos - sp->origin; p.pos = (r / sqrtf(r2 + d)) * v + sp->origin; } } } }

//----------------------------------------------------------------------------- void Camera::computeNearFarOptimizedProjMatrix(const Sphere& scene_bounding_sphere) { // near/far clipping planes optimization if (!scene_bounding_sphere.isNull()) { // compute the sphere in camera coordinates Sphere camera_sphere; scene_bounding_sphere.transformed(camera_sphere, viewMatrix()); mNearPlane = -(camera_sphere.center().z() + camera_sphere.radius() * (Real)1.01); mFarPlane = -(camera_sphere.center().z() - camera_sphere.radius() * (Real)1.01); #if 0 far = max(far, (Real)1.0e-5); near = max(near, (Real)1.0e-6); #else // prevents z-thrashing when very large objects are zoomed a lot Real ratio = camera_sphere.radius() * (Real)2.01 / (Real)2000.0; mNearPlane = max(mNearPlane, ratio*1); mFarPlane = max(mFarPlane, ratio*2); #endif // supports only perspective projection matrices setProjectionAsPerspective(); } }

void drawSoundSphere(Sphere& s){ if (Calc_Hit(s, Hand)){ PlaySound(s.sound_src, NULL, SND_ASYNC); s.flag = false; } glLoadIdentity(); //視点の設定 gluLookAt(0.0, 0.0, -500.0, //カメラの座標 0.0, 0.0, 0.0, // 注視点の座標 0.0, 1.0, 0.0); // 画面の上方向を指すベクトル s.Draw(); }

int Line::intersect(std::list<Kernel::V3D> &PntOut, const Sphere &Sph) const /** For the line that intersects the cylinder generate add the point to the VecOut, return number of points added. It does not check the points for validity. @param PntOut :: Vector of points found by the line/sphere intersection @param Sph :: Sphere to intersect line with @return Number of points found by intersection */ { // Nasty stripping of useful stuff from sphere const Kernel::V3D Ax = Origin - Sph.getCentre(); const double R = Sph.getRadius(); // First solve the equation of intersection double C[3]; C[0] = 1; C[1] = 2.0 * Ax.scalar_prod(Direct); C[2] = Ax.scalar_prod(Ax) - R * R; std::pair<std::complex<double>, std::complex<double>> SQ; const int ix = solveQuadratic(C, SQ); return lambdaPair(ix, SQ, PntOut); }

/** For reference, see http://realtimecollisiondetection.net/blog/?p=20 . */ Sphere Sphere::FitThroughPoints(const vec &a, const vec &b, const vec &c, const vec &d) { Sphere sphere; float s,t,u; const vec ab = b-a; const vec ac = c-a; const vec ad = d-a; bool success = FitSphereThroughPoints(ab, ac, ad, s, t, u); if (success) { const vec center = s*ab + t*ac + u*ad; sphere.r = center.Length(); sphere.pos = a + center; } else { LOGW("Sphere::FitThroughPoints through four points failed! The points lie on the same plane!"); sphere.SetDegenerate(); } return sphere; }

//THIS NEEDS TESTING MAJORLY void Sphere::ResolveCollision(Sphere& rhs, const float& time){ //Calculate the depth of the penetration float penDepth = this->radius + rhs.radius - this->position.GetDistance(rhs.position); //Calculate the contact normal Vector3 conNormal = (this->position - rhs.position).GetNormalised(); //Calculate the point of contact Vector3 conPoint = this->position - conNormal * (this->radius - penDepth); //Calculate the rough combined elasticity of the two spheres in //the collision. An application of the smoke and mirrors technique! float elasticity = (this->elasticity + rhs.elasticity) * 0.5f; //Calculate the velocities of both spheres Vector3 va = this->getVelocity(time); Vector3 vb = rhs.getVelocity(time); //Calculate the Vn of the collision float veloNormal = (va - vb).DotProduct(conNormal); //Calculate the impulse of the collision float impulse = ( -(1 + elasticity) * veloNormal ) / conNormal.DotProduct(conNormal * ( (1 / this->mass) + (1 / rhs.mass) )); //Calculate the resultant velocties of the collision Vector3 vaAfter = va + ((impulse/this->mass) * conNormal); Vector3 vbAfter = vb - ((impulse/rhs.mass) * conNormal); //Translate the shapes out of contact with each other this->translate(conNormal * (penDepth*0.5f)); rhs.translate(0.0f - (conNormal * (penDepth*0.5f))); //Apply the calculated velocties to them this->setVelocity(vaAfter, time); rhs.setVelocity(vbAfter, time); }

bool oiExchangeASCII::importSphere(oiExchangeObject& data){ //open and check device if (!data.device->open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } QTextStream in(data.device); while(!in.atEnd()) { QString line = in.readLine(); QStringList list = line.split(QRegExp("\\s+")); FeatureWrapper *geom = new FeatureWrapper(); Sphere *s = new Sphere(true); s->setFeatureName(list.at(0)); s->setNominalSystem(data.nominalCoordSys); s->xyz.setAt(0,list.at(1).toDouble()); s->xyz.setAt(1,list.at(2).toDouble()); s->xyz.setAt(2,list.at(3).toDouble()); s->radius=list.at(4).toDouble(); s->setIsSolved(true); geom->setSphere(s); //data.nominalCoordSys->nominals.append(s); data.features.append(geom); } return true; }

//Add an asteroid to the world void Scene7::SpawnAsteroid(){ //get a random offset float rndX = (float) rand() / (float)RAND_MAX; float rndY = (float) rand() / (float)RAND_MAX; float rndZ = (float) rand() / (float)RAND_MAX; Sphere* asteroid = new Sphere(); asteroid->worldPosition = vec3(-.5f + rndX, -.5f + rndY, 1 + rndZ); asteroid->Initialize(5,5,.3f); asteroid->Paint(vec3(.5f,.5f,.5f)); asteroid->randomizeSurface(.01f); //Squish / stretch it along all axes float xSquish = float(.5 + Window::Random()); float ySquish = float(.5 + Window::Random()); float zSquish = float(.5 + Window::Random()); asteroid->squish = vec3(xSquish, ySquish, zSquish); asteroid->update_gpu(); this->asteroids.push_back(asteroid); return; }

DTboolean PrimitiveCollisions::sphere_intersect_sphere ( const Vector3 &from1, const Vector3 &dir1, const Sphere &s1, const Vector3 &from2, const Vector3 &dir2, const Sphere &s2, DTfloat &t1, DTfloat &t2) { Vector3 vab = dir1 - dir2; Vector3 l = from1 - from2; DTfloat a = Vector3::dot(vab,vab); DTfloat b = 2.0F * Vector3::dot(l, vab); DTfloat r = s1.radius() + s2.radius(); DTfloat c = Vector3::dot(l,l) - r*r; DTfloat d = b*b-4.0F*a*c; if (d < 0.0F) return false; DTfloat q = -0.5F * (b + (b>=0.0F ? 1.0F : -1.0F) * std::sqrt(d)); t1 = q/a; t2 = c/q; return true; }

// Encloses n points into the Sphere s, in the order of farthest first, in order to // generate the tightest resulting enclosure. void Sphere_Enclose_pts(Sphere &s, const vec *pts, int n) { AutoArrayPtr<PointWithDistance> cornersPtr(AlignedNew<PointWithDistance>(n, 16)); PointWithDistance *corners = cornersPtr.ptr; for(int i = 0; i < n; ++i) { corners[i].pt = pts[i]; corners[i].d = s.pos.DistanceSq(corners[i].pt); } std::sort(corners, corners+n); for(int i = n-1; i >= 0; --i) s.Enclose(corners[i].pt); }

//============================================================================== Bool test(const LineSegment& ls, const Sphere& s) { const Vec4& v = ls.getDirection(); Vec4 w0 = s.getCenter() - ls.getOrigin(); F32 w0dv = w0.dot(v); F32 rsq = s.getRadius() * s.getRadius(); if(w0dv < 0.0) // if the ang is >90 { return w0.getLengthSquared() <= rsq; } Vec4 w1 = w0 - v; // aka center - P1, where P1 = seg.origin + seg.dir F32 w1dv = w1.dot(v); if(w1dv > 0.0) // if the ang is <90 { return w1.getLengthSquared() <= rsq; } // the big parenthesis is the projection of w0 to v Vec4 tmp = w0 - (v * (w0.dot(v) / v.getLengthSquared())); return tmp.getLengthSquared() <= rsq; }