00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <physics/Sphere>
00023
00024 #include <base/Externalizer>
00025 #include <gfx/VisualTriangles>
00026 #include <physics/Material>
00027 #include <physics/OBBCollisionModel>
00028 #include <physics/GJKCollisionModel>
00029
00030 #include <osg/Group>
00031 #include <osg/Geode>
00032 #include <osg/ShapeDrawable>
00033 #include <osg/LOD>
00034
00035 using base::dom::DOMNode;
00036 using base::dom::DOMElement;
00037 using gfx::Point2;
00038 using gfx::Point3;
00039 using gfx::Vector3;
00040 using gfx::Segment3;
00041 using gfx::VisualTriangles;
00042 using physics::Sphere;
00043 using physics::MassProperties;
00044 using physics::CollisionModel;
00045 using physics::OBBCollisionModel;
00046 using physics::GJKCollisionModel;
00047
00048
00049 using osg::Node;
00050 using osg::Group;
00051 using osg::Geode;
00052 using osg::LOD;
00053 using osg::Vec3;
00054 using osg::Vec2;
00055
00056
00057 Sphere::Sphere()
00058 : _radius(1.0), massPropertiesCached(false)
00059 {
00060 }
00061
00062 Sphere::Sphere(Real radius)
00063 : _radius(radius), massPropertiesCached(false)
00064 {
00065 }
00066
00067 Sphere::Sphere(const Sphere& s)
00068 : _radius(s._radius), massPropertiesCached(false)
00069 {
00070 }
00071
00072 Sphere::~Sphere()
00073 {
00074 }
00075
00076
00077 const MassProperties& Sphere::getMassProperties(ref<const Material> material) const
00078 {
00079 if (massPropertiesCached && (density == material->density()))
00080 return massProperties;
00081
00082 density = material->density();
00083 Real volume = 4.0*(consts::Pi*Math::cube(radius()))/3.0;
00084 massProperties.mass = volume*density;
00085
00086 Matrix3 Ibody;
00087 Ibody(1,1) = Ibody(2,2) = Ibody(3,3) = (2.0*massProperties.mass*Math::sqr(radius()))/5.0;
00088 massProperties.setIbody(Ibody);
00089
00090 massProperties.centerOfMass = Point3(0.0,0.0,0.0);
00091
00092 massPropertiesCached = true;
00093 return massProperties;
00094 }
00095
00096
00097 Segment3 Sphere::shortestSegmentBetween(const base::Transform& t, const Point3& p) const
00098 {
00099 Point3 c(t.getTranslation());
00100 Vector3 diff( p - c );
00101 Real diffLen = diff.length();
00102 Segment3 seg;
00103 seg.e = p;
00104
00105 if (diffLen > consts::epsilon)
00106 seg.s = c + radius()*diff.normalize();
00107 else
00108 seg.s = c + radius()*Vector3(1,0,0);
00109
00110 return seg;
00111 }
00112
00113
00114
00115 Segment3 Sphere::shortestSegmentBetween(const base::Transform& t, const gfx::Segment3& s) const
00116 {
00117
00118 Point3 c(t.getTranslation());
00119 Vector3 segDir( s.e - s.s );
00120 Real distance = 0;
00121 Point3 p1,p2;
00122 Real DlengthSquared = s.norm();
00123 Real u = 0;
00124 if (DlengthSquared >= consts::epsilon)
00125 u = dot(segDir, c - s.s) / DlengthSquared;
00126
00127 Vector3 R;
00128 if (u <= 0)
00129 R = s.s;
00130 else if (u >= 1)
00131 R = s.e;
00132 else
00133 R = s.s + u * segDir;
00134
00135 Vector3 E = R - c;
00136 Real Elength = E.length();
00137
00138 if (Elength > radius())
00139 {
00140 p1 = R;
00141 p2 = c + (radius() / Elength) * E;
00142 distance = Elength - radius();
00143 }
00144 else
00145 {
00146 Vector3 centerToStart = s.s - c;
00147 Vector3 centerToEnd = s.e - c;
00148 Real centerToStartLength = centerToStart.length();
00149 Real centerToEndLength = centerToEnd.length();
00150
00151 if (centerToStartLength < radius() && centerToEndLength < radius()) {
00152
00153 if (centerToStartLength < radius()) {
00154 p1 = s.e;
00155 p2 = c + radius() * centerToEnd.normalize();
00156 distance = radius() - centerToEndLength;
00157 }
00158 else {
00159 p1 = s.s;
00160 p2 = c + radius() * centerToStart.normalize();
00161 distance = radius() - centerToStartLength;
00162 }
00163 }
00164 else {
00165 Vector3 projCenter = s.s - u * segDir;
00166
00167 Vector3 intersection = projCenter;
00168 if (DlengthSquared >= consts::epsilon)
00169 {
00170
00171 Real s = Math::sqrt(Math::abs( Math::sqr(radius()) - (projCenter - c).norm() ));
00172
00173
00174 if (centerToEndLength < radius())
00175 s = -s;
00176 intersection += (s / Math::sqrt(DlengthSquared)) * segDir;
00177 }
00178
00179 p1 = intersection;
00180 p2 = intersection;
00181 distance = 0;
00182 }
00183 }
00184
00185 return Segment3(p2,p1);
00186 }
00187
00188
00189 Segment3 Sphere::shortestSegmentBetween(const base::Transform& t, const gfx::Triangle3& tri) const
00190 {
00191 Unimplemented;
00192 }
00193
00194
00195 Segment3 Sphere::shortestSegmentBetween(const base::Transform& t, const gfx::Quad3& q) const
00196 {
00197 Unimplemented;
00198 }
00199
00200
00201 Segment3 Sphere::shortestSegmentBetween(const base::Transform& t1, ref<const Shape> s, const base::Transform& t2) const
00202 {
00203 if (instanceof(*s, const Sphere)) {
00204
00205 ref<const Sphere> sphere1(this);
00206 ref<const Sphere> sphere2(narrow_ref<const Sphere>(s));
00207 Point3 c1(t1.getTranslation());
00208 Point3 c2(t2.getTranslation());
00209 Real r1( sphere1->radius() );
00210 Real r2( sphere2->radius() );
00211
00212 Point3 p1,p2;
00213 Vector3 D = c2 - c1;
00214 Real Dlength = D.length();
00215
00216
00217 if (Dlength < consts::epsilon)
00218 D.setZero();
00219 else
00220 D /= Dlength;
00221
00222 if (Dlength > r1 + r2) {
00223 p1 = c1 + r1 * D;
00224 p2 = c2 - r2 * D;
00225 }
00226 else if (Dlength < Math::abs(r1 - r2))
00227 {
00228 p1 = c1 + r1 * D;
00229 p2 = c2 + r2 * D;
00230 }
00231 else if (Dlength < consts::epsilon)
00232 {
00233 Vector3 intersection = c1;
00234 intersection.x += r1;
00235
00236 p1 = intersection;
00237 p2 = intersection;
00238 }
00239 else {
00240 Real t = 0.5 * (1 + (Math::sqr(r1) - Math::sqr(r2)) / Math::sqr(Dlength));
00241 Real r = Math::sqrt(Math::sqr(r1) - Math::sqr(t * Dlength));
00242 Vector3 C = c1 + t * D;
00243
00244 Matrix3 basis;
00245 basis.setOrthonormalBasisOf(D);
00246 Vector3 intersection = C + r * basis.row(1);
00247
00248 p1 = intersection;
00249 p2 = intersection;
00250 }
00251
00252 return Segment3(p1,p2);
00253
00254 }
00255 else if (instanceof(*s, const Box)) {
00256
00257 return s->shortestSegmentBetween(t2,ref<const Shape>(this), t1).swapEnds();
00258
00259 }
00260 else {
00261 Unimplemented;
00262 }
00263 }
00264
00265
00266
00267
00268
00269
00270 gfx::Point3 Sphere::support(const base::Vector3& v) const
00271 {
00272 Real s = v.length();
00273 if (s > consts::epsilon)
00274 return v*(_radius/s);
00275 else
00276 return base::Point3(0,0,0);
00277 }
00278
00279
00280 osg::Node* Sphere::createOSGSphere(Visual::Attributes visualAttributes,
00281 Int slices) const
00282 {
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 osg::Geode* geode = new osg::Geode();
00353
00354 geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0,0,0),radius())));
00355
00356 return geode;
00357 }
00358
00359
00360 osg::Node* Sphere::createOSGVisual(Visual::Attributes visualAttributes) const
00361 {
00362 if ((node!=0) && (attributes==visualAttributes))
00363 return &(*node);
00364
00365 Real d = Math::maximum(radius()*2.0,1.0);
00366
00367 osg::Node* node0 = createOSGSphere(visualAttributes, Int(22*d));
00368 osg::Node* node1 = createOSGSphere(visualAttributes, Int(16*d));
00369 osg::Node* node2 = createOSGSphere(visualAttributes, Int(8*d));
00370 osg::Node* node3 = createOSGSphere(visualAttributes, 8);
00371
00372 osg::LOD* lod = new osg::LOD();
00373 lod->setName("Sphere");
00374 lod->addChild(node0);
00375 lod->addChild(node1);
00376 lod->addChild(node2);
00377 lod->addChild(node3);
00378
00379 lod->setRange(0,0,2.0);
00380 lod->setRange(1,2.0,16.0);
00381 lod->setRange(2,16.0,120.0*d);
00382 lod->setRange(3,120.0*d,consts::Infinity);
00383
00384 if (!(visualAttributes & Visual::ShowAxes))
00385 node = lod;
00386 else {
00387 Group* group = new Group();
00388 group->addChild( lod );
00389 group->addChild( createOSGAxes(base::Dimension3(radius(),radius(),radius())*2.0) );
00390 node = group;
00391 }
00392
00393 attributes = visualAttributes;
00394 return &(*node);
00395 }
00396
00397
00398 base::ref<CollisionModel> Sphere::getCollisionModel(CollisionModel::CollisionModelType modelType) const
00399 {
00400 if ((collisionModel!=0) &&
00401 ((this->modelType==modelType) || (modelType==CollisionModel::AnyModel)))
00402 return collisionModel;
00403
00404 collisionModel = Shape::getCollisionModel(modelType);
00405 this->modelType=modelType;
00406
00407 return collisionModel;
00408 }
00409
00410
00411 void Sphere::serialize(base::Serializer& s)
00412 {
00413 s(_radius);
00414
00415 if (s.isInput()) {
00416 massPropertiesCached = false;
00417 node = 0;
00418 collisionModel = ref<CollisionModel>(0);
00419 }
00420 }
00421
00422
00423
00424 bool Sphere::formatSupported(String format, Real version, ExternalizationType type) const
00425 {
00426 return ( (format=="xml") && (version==1.0) );
00427 }
00428
00429
00430 void Sphere::externalize(base::Externalizer& e, String format, Real version)
00431 {
00432 if (format == "") format = "xml";
00433
00434 if (!formatSupported(format,version,e.ioType()))
00435 throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00436
00437 if (e.isOutput()) {
00438
00439 DOMElement* sphereElem = e.createElement("sphere");
00440 e.setElementAttribute(sphereElem,"radius",base::realToString(_radius));
00441
00442 e.appendElement(sphereElem);
00443 }
00444 else {
00445
00446 massPropertiesCached = false;
00447 node = 0;
00448 collisionModel = ref<CollisionModel>(0);
00449
00450 DOMNode* context = e.context();
00451
00452 DOMElement* sphereElem = e.getFirstElement(context, "sphere");
00453
00454 _radius = e.toReal( e.getDefaultedElementAttribute(sphereElem, "radius", "1") );
00455
00456 e.removeElement(sphereElem);
00457
00458 }
00459 }
00460
00461