Simbody
3.4 (development)
|
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_