Simbody  3.4 (development)
ContactSurface.h
Go to the documentation of this file.
00001 #ifndef SimTK_SIMBODY_CONTACT_SURFACE_H_
00002 #define SimTK_SIMBODY_CONTACT_SURFACE_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                               Simbody(tm)                                  *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK biosimulation toolkit originating from           *
00008  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00009  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00010  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
00011  *                                                                            *
00012  * Portions copyright (c) 2008-13 Stanford University and the Authors.        *
00013  * Authors: Peter Eastman, Michael Sherman                                    *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
00017  * not use this file except in compliance with the License. You may obtain a  *
00018  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
00019  *                                                                            *
00020  * Unless required by applicable law or agreed to in writing, software        *
00021  * distributed under the License is distributed on an "AS IS" BASIS,          *
00022  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
00023  * See the License for the specific language governing permissions and        *
00024  * limitations under the License.                                             *
00025  * -------------------------------------------------------------------------- */
00026 
00030 #include "SimTKmath.h"
00031 #include "simbody/internal/common.h"
00032 
00033 #include <algorithm>
00034 
00035 namespace SimTK {
00036 
00037 class ContactGeometry;
00038 
00039 SimTK_DEFINE_UNIQUE_INDEX_TYPE(ContactCliqueId);
00040 
00041 
00042 
00043 //==============================================================================
00044 //                               CONTACT MATERIAL
00045 //==============================================================================
00088 class SimTK_SIMBODY_EXPORT ContactMaterial {
00089 public:
00093 ContactMaterial() {clear();}
00094 
00135 ContactMaterial(Real stiffness, Real dissipation, 
00136                 Real staticFriction, Real dynamicFriction,
00137                 Real viscousFriction = 0) {
00138     setStiffness(stiffness);
00139     setDissipation(dissipation);
00140     setFriction(staticFriction, dynamicFriction, viscousFriction);
00141 }
00142 
00145 bool isValid() const {return m_stiffness > 0;}
00146 
00148 Real getStiffness() const 
00149 {   SimTK_ERRCHK(isValid(), "ContactMaterial::getStiffness()",
00150         "This is an invalid ContactMaterial.");
00151     return m_stiffness; }
00153 Real getStiffness23() const 
00154 {   SimTK_ERRCHK(isValid(), "ContactMaterial::getStiffness23()",
00155         "This is an invalid ContactMaterial.");
00156     return m_stiffness23; }
00158 Real getDissipation() const 
00159 {   SimTK_ERRCHK(isValid(), "ContactMaterial::getDissipation()",
00160         "This is an invalid ContactMaterial.");
00161     return m_dissipation; }
00163 Real getStaticFriction() const 
00164 {   SimTK_ERRCHK(isValid(), "ContactMaterial::getStaticFriction()",
00165         "This is an invalid ContactMaterial.");
00166     return m_staticFriction; }
00168 Real getDynamicFriction() const 
00169 {   SimTK_ERRCHK(isValid(), "ContactMaterial::getDynamicFriction()",
00170         "This is an invalid ContactMaterial.");
00171     return m_dynamicFriction; }
00173 Real getViscousFriction() const 
00174 {   SimTK_ERRCHK(isValid(), "ContactMaterial::getViscousFriction()",
00175         "This is an invalid ContactMaterial.");
00176     return m_viscousFriction; }
00177 
00181 ContactMaterial& setStiffness(Real stiffness) {
00182     SimTK_ERRCHK1_ALWAYS(stiffness >= 0, "ContactMaterial::setStiffness()",
00183         "Stiffness %g is illegal; must be >= 0.", stiffness);
00184     m_stiffness = stiffness;
00185     m_stiffness23 = std::pow(m_stiffness, Real(2./3.));
00186     return *this;
00187 }
00188 
00192 ContactMaterial& setDissipation(Real dissipation) {
00193     SimTK_ERRCHK1_ALWAYS(dissipation >= 0, "ContactMaterial::setDissipation()",
00194         "Dissipation %g (in 1/speed) is illegal; must be >= 0.", dissipation);
00195     m_dissipation = dissipation;
00196     return *this;
00197 }
00198 
00200 ContactMaterial& setFriction(Real staticFriction,
00201                              Real dynamicFriction,
00202                              Real viscousFriction = 0)
00203 {
00204     SimTK_ERRCHK1_ALWAYS(0 <= staticFriction, "ContactMaterial::setFriction()",
00205         "Illegal static friction coefficient %g.", staticFriction);
00206     SimTK_ERRCHK2_ALWAYS(0<=dynamicFriction && dynamicFriction<=staticFriction, 
00207         "ContactMaterial::setFriction()",
00208         "Dynamic coefficient %g illegal; must be between 0 and static"
00209         " coefficient %g.", dynamicFriction, staticFriction);
00210     SimTK_ERRCHK1_ALWAYS(0 <= viscousFriction, "ContactMaterial::setFriction()",
00211         "Illegal viscous friction coefficient %g.", viscousFriction);
00212 
00213     m_staticFriction  = staticFriction;
00214     m_dynamicFriction = dynamicFriction;
00215     m_viscousFriction = viscousFriction;
00216     return *this;
00217 }
00218 
00228 static Real calcPlaneStrainStiffness(Real youngsModulus, 
00229                                      Real poissonsRatio) 
00230 {
00231     SimTK_ERRCHK2_ALWAYS(youngsModulus >= 0 &&
00232                          -1 < poissonsRatio && poissonsRatio <= 0.5,
00233                          "ContactMaterial::calcStiffnessForSolid()",
00234         "Illegal material properties E=%g, v=%g.", 
00235         youngsModulus, poissonsRatio);
00236 
00237     return youngsModulus / (1-square(poissonsRatio)); 
00238 }
00239 
00240 
00249 static Real calcConfinedCompressionStiffness(Real youngsModulus, 
00250                                              Real poissonsRatio) 
00251 {
00252     SimTK_ERRCHK2_ALWAYS(youngsModulus >= 0 &&
00253                          -1 < poissonsRatio && poissonsRatio < 0.5,
00254                          "ContactMaterial::calcStiffnessForSolid()",
00255         "Illegal material properties E=%g, v=%g.", 
00256         youngsModulus, poissonsRatio);
00257 
00258     return youngsModulus*(1-poissonsRatio) 
00259         / ((1+poissonsRatio)*(1-2*poissonsRatio)); 
00260 }
00261 
00273 static Real calcDissipationFromObservedRestitution
00274    (Real restitution, Real speed) {
00275     if (restitution==1) return 0;
00276     SimTK_ERRCHK2_ALWAYS(0<=restitution && restitution<=1 && speed>0,
00277         "ContactMaterial::calcDissipationFromRestitution()",
00278         "Illegal coefficient of restitution or speed (%g,%g).",
00279         restitution, speed);
00280     return (1-restitution)/speed;
00281 }
00282 
00286 void clear() {
00287     m_stiffness   = NaN; // unspecified
00288     m_stiffness23 = NaN;
00289     m_restitution = NaN; // unspecified
00290     m_dissipation = 0;  // default; no dissipation
00291     // default; no friction
00292     m_staticFriction=m_dynamicFriction=m_viscousFriction = 0;
00293 }
00294 
00295 //--------------------------------------------------------------------------
00296 private:
00297 
00298 // For compliant contact models.
00299 Real    m_stiffness;        // k: stress/%strain=(force/area)/%strain
00300 Real    m_stiffness23;      // k^(2/3) in case we need it
00301 Real    m_dissipation;      // c: %normalForce/normalVelocity
00302 
00303 // For impulsive collisions.
00304 Real    m_restitution;      // e: unitless, e=(1-cv)
00305 
00306 // Friction.
00307 Real    m_staticFriction;   // us: unitless
00308 Real    m_dynamicFriction;  // ud: unitless
00309 Real    m_viscousFriction;  // uv: %normalForce/slipVelocity
00310 };
00311 
00312 
00313 
00314 //==============================================================================
00315 //                               CONTACT SURFACE
00316 //==============================================================================
00332 class SimTK_SIMBODY_EXPORT ContactSurface {
00333 public:
00335 ContactSurface() {}
00337 ContactSurface(const ContactGeometry&   shape, 
00338                const ContactMaterial&   material,
00339                Real                     thickness=0)
00340 :   m_shape(shape), m_material(material), m_thickness(thickness) {
00341     SimTK_ERRCHK1_ALWAYS(thickness >= 0, "ContactSurface::ctor()",
00342         "Illegal thickness %g.", thickness);
00343 }
00344 
00346 ContactSurface& setShape(const ContactGeometry& shape) 
00347 {   m_shape = shape; return *this; }
00348 
00351 ContactSurface& setMaterial(const ContactMaterial& material,
00352                             Real thickness = 0) 
00353 {   m_material = material; setThickness(thickness); return *this; }
00354 
00359 ContactSurface& setThickness(Real thickness) {
00360     SimTK_ERRCHK1_ALWAYS(thickness >= 0, "ContactSurface::setThickness()",
00361         "Illegal thickness %g.", thickness);
00362     m_thickness = thickness; 
00363     return *this; 
00364 }
00365 
00367 const ContactGeometry& getShape()    const {return m_shape;}
00368 
00370 const ContactMaterial& getMaterial() const {return m_material;}
00371 
00374 Real getThickness() const {return m_thickness;}
00375 
00377 ContactGeometry& updShape()    {return m_shape;}
00378 
00380 ContactMaterial& updMaterial() {return m_material;}
00381 
00384 ContactSurface& joinClique(ContactCliqueId clique) {
00385     if (!clique.isValid()) return *this;
00386     // Although this is a sorted list, we expect it to be very short so 
00387     // are using linear search to find where this new clique goes.
00388     Array_<ContactCliqueId,short>::iterator p;
00389     for (p = m_cliques.begin(); p != m_cliques.end(); ++p) {   
00390         if (*p==clique) return *this; // already a member
00391         if (*p>clique) break;
00392     }
00393     // insert just before p (might be at the end)
00394     m_cliques.insert(p, clique);
00395     return *this;
00396 }
00397 
00400 void leaveClique(ContactCliqueId clique) {   
00401     if (!clique.isValid()) return;
00402     // We expect this to be a very short list so are using linear search.
00403     Array_<ContactCliqueId,short>::iterator p =
00404         std::find(m_cliques.begin(), m_cliques.end(), clique);
00405     if (p != m_cliques.end()) m_cliques.erase(p); 
00406 }
00407 
00411 bool isInSameClique(const ContactSurface& other) const 
00412 {   if (getCliques().empty() || other.getCliques().empty()) return false;//typical
00413     return cliquesIntersect(getCliques(), other.getCliques()); }
00414 
00417 const Array_<ContactCliqueId,short>& getCliques() const {return m_cliques;}
00418 
00422 static bool cliquesIntersect(const Array_<ContactCliqueId,short>& a,
00423                              const Array_<ContactCliqueId,short>& b)
00424 {
00425     Array_<ContactCliqueId,short>::const_iterator ap = a.begin();
00426     Array_<ContactCliqueId,short>::const_iterator bp = b.begin();
00427     // Quick checks: empty or non-overlapping.
00428     if (ap==a.end() || bp==b.end()) return false;
00429     if (*ap > b.back() || *bp > a.back()) 
00430         return false; // disjoint
00431     // Both lists have elements and the elements overlap numerically.
00432     while (true) {
00433         if (*ap==*bp) return true;
00434         // Increment the list with smaller front element.
00435         if (*ap < *bp) {++ap; if (ap==a.end()) break;}
00436         else           {++bp; if (bp==b.end()) break;}
00437     }
00438     // One of the lists ran out of elements before we found a match.
00439     return false;
00440 }
00441 
00445 static ContactCliqueId createNewContactClique()
00446 {   static AtomicInteger nextAvailableContactClique = 1;
00447     return ContactCliqueId(nextAvailableContactClique++); }
00448 
00449 //----------------------------------------------------------------------
00450                                  private:
00451 
00452 ContactGeometry                 m_shape;
00453 ContactMaterial                 m_material;
00454 Real                            m_thickness; // default=Infinity
00455 Array_<ContactCliqueId,short>   m_cliques;   // sorted
00456 };
00457 
00458 
00459 
00460 } // namespace SimTK
00461 
00462 #endif // SimTK_SIMBODY_CONTACT_SURFACE_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines