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