Simbody
|
00001 #ifndef SimTK_SIMBODY_CONTACT_SURFACE_H_ 00002 #define SimTK_SIMBODY_CONTACT_SURFACE_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTK Simbody(tm) * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core 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. * 00011 * * 00012 * Portions copyright (c) 2008 Stanford University and the Authors. * 00013 * Authors: Peter Eastman * 00014 * Contributors: * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00038 #include "SimTKcommon.h" 00039 #include "simbody/internal/common.h" 00040 #include "simbody/internal/ContactGeometry.h" 00041 00042 #include <algorithm> 00043 00044 namespace SimTK { 00045 00046 class ContactGeometry; 00047 00048 SimTK_DEFINE_UNIQUE_INDEX_TYPE(ContactCliqueId); 00049 00050 00051 00052 //============================================================================== 00053 // CONTACT MATERIAL 00054 //============================================================================== 00095 class SimTK_SIMBODY_EXPORT ContactMaterial { 00096 public: 00100 ContactMaterial() {clear();} 00101 00106 ContactMaterial(Real stiffness, Real dissipation, 00107 Real staticFriction, Real dynamicFriction, 00108 Real viscousFriction = 0) { 00109 setStiffness(stiffness); 00110 setDissipation(dissipation); 00111 setFriction(staticFriction, dynamicFriction, viscousFriction); 00112 } 00113 00116 bool isValid() const {return m_stiffness > 0;} 00117 00119 Real getStiffness() const 00120 { SimTK_ERRCHK(isValid(), "ContactMaterial::getStiffness()", 00121 "This is an invalid ContactMaterial."); 00122 return m_stiffness; } 00124 Real getStiffness23() const 00125 { SimTK_ERRCHK(isValid(), "ContactMaterial::getStiffness23()", 00126 "This is an invalid ContactMaterial."); 00127 return m_stiffness23; } 00129 Real getDissipation() const 00130 { SimTK_ERRCHK(isValid(), "ContactMaterial::getDissipation()", 00131 "This is an invalid ContactMaterial."); 00132 return m_dissipation; } 00134 Real getStaticFriction() const 00135 { SimTK_ERRCHK(isValid(), "ContactMaterial::getStaticFriction()", 00136 "This is an invalid ContactMaterial."); 00137 return m_staticFriction; } 00139 Real getDynamicFriction() const 00140 { SimTK_ERRCHK(isValid(), "ContactMaterial::getDynamicFriction()", 00141 "This is an invalid ContactMaterial."); 00142 return m_dynamicFriction; } 00144 //TODO: should this be (force/area)/velocity? 00145 Real getViscousFriction() const 00146 { SimTK_ERRCHK(isValid(), "ContactMaterial::getViscousFriction()", 00147 "This is an invalid ContactMaterial."); 00148 return m_viscousFriction; } 00149 00153 ContactMaterial& setStiffness(Real stiffness) { 00154 SimTK_ERRCHK1_ALWAYS(stiffness >= 0, "ContactMaterial::setStiffness()", 00155 "Stiffness %g is illegal; must be >= 0.", stiffness); 00156 m_stiffness = stiffness; 00157 m_stiffness23 = std::pow(m_stiffness, Real(2./3.)); 00158 return *this; 00159 } 00160 00164 ContactMaterial& setDissipation(Real dissipation) { 00165 SimTK_ERRCHK1_ALWAYS(dissipation >= 0, "ContactMaterial::setDissipation()", 00166 "Dissipation %g (in 1/speed) is illegal; must be >= 0.", dissipation); 00167 m_dissipation = dissipation; 00168 return *this; 00169 } 00170 00172 ContactMaterial& setFriction(Real staticFriction, 00173 Real dynamicFriction, 00174 Real viscousFriction = 0) 00175 { 00176 SimTK_ERRCHK1_ALWAYS(0 <= staticFriction, "ContactMaterial::setFriction()", 00177 "Illegal static friction coefficient %g.", staticFriction); 00178 SimTK_ERRCHK2_ALWAYS(0<=dynamicFriction && dynamicFriction<=staticFriction, 00179 "ContactMaterial::setFriction()", 00180 "Dynamic coefficient %g illegal; must be between 0 and static" 00181 " coefficient %g.", dynamicFriction, staticFriction); 00182 SimTK_ERRCHK1_ALWAYS(0 <= viscousFriction, "ContactMaterial::setFriction()", 00183 "Illegal viscous friction coefficient %g.", viscousFriction); 00184 00185 m_staticFriction = staticFriction; 00186 m_dynamicFriction = dynamicFriction; 00187 m_viscousFriction = viscousFriction; 00188 return *this; 00189 } 00190 00200 static Real calcPlaneStrainStiffness(Real youngsModulus, 00201 Real poissonsRatio) 00202 { 00203 SimTK_ERRCHK2_ALWAYS(youngsModulus >= 0 && 00204 -1 < poissonsRatio && poissonsRatio < 0.5, 00205 "ContactMaterial::calcStiffnessForSolid()", 00206 "Illegal material properties E=%g, v=%g.", 00207 youngsModulus, poissonsRatio); 00208 00209 return youngsModulus / (1-square(poissonsRatio)); 00210 } 00211 00212 00221 static Real calcConfinedCompressionStiffness(Real youngsModulus, 00222 Real poissonsRatio) 00223 { 00224 SimTK_ERRCHK2_ALWAYS(youngsModulus >= 0 && 00225 -1 < poissonsRatio && poissonsRatio < 0.5, 00226 "ContactMaterial::calcStiffnessForSolid()", 00227 "Illegal material properties E=%g, v=%g.", 00228 youngsModulus, poissonsRatio); 00229 00230 return youngsModulus*(1-poissonsRatio) 00231 / ((1+poissonsRatio)*(1-2*poissonsRatio)); 00232 } 00233 00245 static Real calcDissipationFromObservedRestitution 00246 (Real restitution, Real speed) { 00247 if (restitution==1) return 0; 00248 SimTK_ERRCHK2(0<=restitution && restitution<=1 && speed>0, 00249 "ContactMaterial::calcDissipationFromRestitution()", 00250 "Illegal coefficient of restitution or speed (%g,%g).", 00251 restitution, speed); 00252 return (1-restitution)/speed; 00253 } 00254 00258 void clear() { 00259 m_stiffness = NaN; // unspecified 00260 m_stiffness23 = NaN; 00261 m_restitution = NaN; // unspecified 00262 m_dissipation = 0; // default; no dissipation 00263 // default; no friction 00264 m_staticFriction=m_dynamicFriction=m_viscousFriction = 0; 00265 } 00266 00267 //-------------------------------------------------------------------------- 00268 private: 00269 00270 // For compliant contact models. 00271 Real m_stiffness; // k: stress/%strain=(force/area)/%strain 00272 Real m_stiffness23; // k^(2/3) in case we need it 00273 Real m_dissipation; // c: %normalForce/normalVelocity 00274 00275 // For impulsive collisions. 00276 Real m_restitution; // e: unitless, e=(1-cv) 00277 00278 // Friction. 00279 Real m_staticFriction; // us: unitless 00280 Real m_dynamicFriction; // ud: unitless 00281 Real m_viscousFriction; // uv: %normalForce/slipVelocity 00282 }; 00283 00284 00285 00286 //============================================================================== 00287 // CONTACT SURFACE 00288 //============================================================================== 00302 class SimTK_SIMBODY_EXPORT ContactSurface { 00303 public: 00305 ContactSurface() {} 00307 ContactSurface(const ContactGeometry& shape, const ContactMaterial& material) 00308 : m_shape(shape), m_material(material) {} 00309 00311 ContactSurface& setShape(const ContactGeometry& shape) 00312 { m_shape = shape; return *this; } 00313 00316 ContactSurface& setMaterial(const ContactMaterial& material, 00317 Real thickness = Infinity) 00318 { m_material = material; setThickness(thickness); return *this; } 00319 00324 ContactSurface& setThickness(Real thickness) 00325 { m_thickness = thickness; return *this; } 00326 00328 const ContactGeometry& getShape() const {return m_shape;} 00329 00331 const ContactMaterial& getMaterial() const {return m_material;} 00332 00336 Real getThickness() const {return m_thickness;} 00337 00339 ContactGeometry& updShape() {return m_shape;} 00340 00342 ContactMaterial& updMaterial() {return m_material;} 00343 00345 ContactSurface& joinClique(ContactCliqueId clique) { 00346 // Although this is a sorted list, we expect it to be very short so 00347 // are using linear search to find where this new clique goes. 00348 Array_<ContactCliqueId,short>::iterator p; 00349 for (p = m_cliques.begin(); p != m_cliques.end(); ++p) { 00350 if (*p==clique) return *this; // already a member 00351 if (*p>clique) break; 00352 } 00353 // insert just before p (might be at the end) 00354 m_cliques.insert(p, clique); 00355 return *this; 00356 } 00357 00359 void leaveClique(ContactCliqueId clique) { 00360 // We expect this to be a very short list so are using linear search. 00361 Array_<ContactCliqueId,short>::iterator p = 00362 std::find(m_cliques.begin(), m_cliques.end(), clique); 00363 if (p != m_cliques.end()) m_cliques.erase(p); 00364 } 00365 00369 bool isInSameClique(const ContactSurface& other) const 00370 { if (getCliques().empty() || other.getCliques().empty()) return false;//typical 00371 return cliquesIntersect(getCliques(), other.getCliques()); } 00372 00375 const Array_<ContactCliqueId,short>& getCliques() const {return m_cliques;} 00376 00380 static bool cliquesIntersect(const Array_<ContactCliqueId,short>& a, 00381 const Array_<ContactCliqueId,short>& b) 00382 { 00383 Array_<ContactCliqueId,short>::const_iterator ap = a.begin(); 00384 Array_<ContactCliqueId,short>::const_iterator bp = b.begin(); 00385 // Quick checks: empty or non-overlapping. 00386 if (ap==a.end() || bp==b.end()) return false; 00387 if (*ap > b.back() || *bp > a.back()) 00388 return false; // disjoint 00389 // Both lists have elements and the elements overlap numerically. 00390 while (true) { 00391 if (*ap==*bp) return true; 00392 // Increment the list with smaller front element. 00393 if (*ap < *bp) {++ap; if (ap==a.end()) break;} 00394 else {++bp; if (bp==b.end()) break;} 00395 } 00396 // One of the lists ran out of elements before we found a match. 00397 return false; 00398 } 00399 00403 static ContactCliqueId createNewContactClique() 00404 { static AtomicInteger nextAvailableContactClique = 1; 00405 return ContactCliqueId(nextAvailableContactClique++); } 00406 00407 //---------------------------------------------------------------------- 00408 private: 00409 00410 ContactGeometry m_shape; 00411 ContactMaterial m_material; 00412 Real m_thickness; // default=Infinity 00413 Array_<ContactCliqueId,short> m_cliques; // sorted 00414 }; 00415 00416 00417 00418 } // namespace SimTK 00419 00420 #endif // SimTK_SIMBODY_CONTACT_SURFACE_H_