1 // ============================================================================= 2 // PROJECT CHRONO - http://projectchrono.org 3 // 4 // Copyright (c) 2014 projectchrono.org 5 // All rights reserved. 6 // 7 // Use of this source code is governed by a BSD-style license that can be found 8 // in the LICENSE file at the top level of the distribution and at 9 // http://projectchrono.org/license-chrono.txt. 10 // 11 // ============================================================================= 12 // Authors: Alessandro Tasora, Radu Serban, Jay Taves 13 // ============================================================================= 14 // 15 // Deformable terrain based on SCM (Soil Contact Model) from DLR 16 // (Krenn & Hirzinger) 17 // 18 // ============================================================================= 19 20 #ifndef SCM_DEFORMABLE_TERRAIN_H 21 #define SCM_DEFORMABLE_TERRAIN_H 22 23 #include <string> 24 #include <ostream> 25 #include <unordered_map> 26 27 #include "chrono/assets/ChColorAsset.h" 28 #include "chrono/assets/ChTriangleMeshShape.h" 29 #include "chrono/physics/ChBody.h" 30 #include "chrono/physics/ChLoadContainer.h" 31 #include "chrono/physics/ChLoadsBody.h" 32 #include "chrono/physics/ChSystem.h" 33 #include "chrono/core/ChTimer.h" 34 35 #include "chrono_vehicle/ChApiVehicle.h" 36 #include "chrono_vehicle/ChSubsysDefs.h" 37 #include "chrono_vehicle/ChTerrain.h" 38 #include "chrono_vehicle/ChWorldFrame.h" 39 40 namespace chrono { 41 namespace vehicle { 42 43 class SCMDeformableSoil; 44 45 /// @addtogroup vehicle_terrain 46 /// @{ 47 48 /// Deformable terrain model. 49 /// This class implements a deformable terrain based on the Soil Contact Model. 50 /// Unlike RigidTerrain, the vertical coordinates of this terrain mesh can be deformed 51 /// due to interaction with ground vehicles or other collision shapes. 52 class CH_VEHICLE_API SCMDeformableTerrain : public ChTerrain { 53 public: 54 enum DataPlotType { 55 PLOT_NONE, 56 PLOT_LEVEL, 57 PLOT_LEVEL_INITIAL, 58 PLOT_SINKAGE, 59 PLOT_SINKAGE_ELASTIC, 60 PLOT_SINKAGE_PLASTIC, 61 PLOT_STEP_PLASTIC_FLOW, 62 PLOT_PRESSURE, 63 PLOT_PRESSURE_YELD, 64 PLOT_SHEAR, 65 PLOT_K_JANOSI, 66 PLOT_IS_TOUCHED, 67 PLOT_ISLAND_ID, 68 PLOT_MASSREMAINDER 69 }; 70 71 /// Construct a default SCM deformable terrain. 72 /// The user is responsible for calling various Set methods before Initialize. 73 SCMDeformableTerrain(ChSystem* system, ///< [in] pointer to the containing multibody system 74 bool visualization_mesh = true ///< [in] enable/disable visualization asset 75 ); 76 ~SCMDeformableTerrain()77 ~SCMDeformableTerrain() {} 78 79 /// Set the plane reference. 80 /// By default, the reference plane is horizontal with Z up (ISO vehicle reference frame). 81 /// To set as Y up, call SetPlane(ChCoordys(VNULL, Q_from_AngX(-CH_C_PI_2))); 82 void SetPlane(const ChCoordsys<>& plane); 83 84 /// Get the current reference plane. 85 /// The SCM terrain patch is in the (x,y) plane with normal along the Z axis. 86 const ChCoordsys<>& GetPlane() const; 87 88 /// Set the properties of the SCM soil model. 89 /// These parameters are described in: "Parameter Identification of a Planetary Rover Wheel-Soil Contact Model via a 90 /// Bayesian Approach", A.Gallina, R. Krenn et al. Note that the original SCM model does not include the K and R 91 /// coefficients. A very large value of K and R=0 reproduce the original SCM. 92 void SetSoilParameters( 93 double Bekker_Kphi, ///< Kphi, frictional modulus in Bekker model 94 double Bekker_Kc, ///< Kc, cohesive modulus in Bekker model 95 double Bekker_n, ///< n, exponent of sinkage in Bekker model (usually 0.6...1.8) 96 double Mohr_cohesion, ///< Cohesion for shear failure [Pa] 97 double Mohr_friction, ///< Friction angle for shear failure [degree] 98 double Janosi_shear, ///< Shear parameter in Janosi-Hanamoto formula [m] 99 double elastic_K, ///< elastic stiffness K per unit area, [Pa/m] (must be larger than Kphi) 100 double damping_R ///< vertical damping R per unit area [Pa.s/m] (proportional to vertical speed) 101 ); 102 103 /// Enable/disable the creation of soil inflation at the side of the ruts (bulldozing effects). 104 void EnableBulldozing(bool mb); 105 106 /// Set parameters controlling the creation of side ruts (bulldozing effects). 107 void SetBulldozingParameters( 108 double erosion_angle, ///< angle of erosion of the displaced material [degrees] 109 double flow_factor = 1.0, ///< growth of lateral volume relative to pressed volume 110 int erosion_iterations = 3, ///< number of erosion refinements per timestep 111 int erosion_propagations = 10 ///< number of concentric vertex selections subject to erosion 112 ); 113 114 /// Set the vertical level up to which collision is tested (relative to the reference level at the sample point). 115 /// Since the contact is unilateral, this could be zero. However, when computing bulldozing flow, one might also 116 /// need to know if in the surrounding there is some potential future contact: so it might be better to use a 117 /// positive value (but not higher than the max. expected height of the bulldozed rubble, to avoid slowdown of 118 /// collision tests). Default: 0.1 m. 119 void SetTestHeight(double offset); 120 121 /// Return the current test height level. 122 double GetTestHeight() const; 123 124 /// Set the color plot type for the soil mesh. 125 /// When a scalar plot is used, also define the range in the pseudo-color colormap. 126 void SetPlotType(DataPlotType plot_type, double min_val, double max_val); 127 128 /// Set visualization color. 129 void SetColor(const ChColor& color); 130 131 /// Set texture properties. 132 void SetTexture(const std::string tex_file, ///< [in] texture filename 133 float tex_scale_x = 1, ///< [in] texture scale in X 134 float tex_scale_y = 1 ///< [in] texture scale in Y 135 ); 136 137 /// Add a new moving patch. 138 /// Multiple calls to this function can be made, each of them adding a new active patch area. 139 /// If no patches are defined, ray-casting is performed for every single node of the underlying SCM grid. 140 /// If at least one patch is defined, ray-casting is performed only for mesh nodes within the AABB of the 141 /// body OOBB projection onto the SCM plane. 142 void AddMovingPatch(std::shared_ptr<ChBody> body, ///< [in] monitored body 143 const ChVector<>& OOBB_center, ///< [in] OOBB center, relative to body 144 const ChVector<>& OOBB_dims ///< [in] OOBB dimensions 145 ); 146 147 /// Class to be used as a callback interface for location-dependent soil parameters. 148 /// A derived class must implement Set() and set *all* soil parameters (no defaults are provided). 149 class CH_VEHICLE_API SoilParametersCallback { 150 public: ~SoilParametersCallback()151 virtual ~SoilParametersCallback() {} 152 153 /// Set the soil properties at a given (x,y) location (below the given point). 154 /// Attention: the location is assumed to be provided in the SCM reference frame! 155 virtual void Set( 156 const ChVector<>& loc, ///< query location 157 double& Bekker_Kphi, ///< frictional modulus in Bekker model 158 double& Bekker_Kc, ///< cohesive modulus in Bekker model 159 double& Bekker_n, ///< exponent of sinkage in Bekker model (usually 0.6...1.8) 160 double& Mohr_cohesion, ///< cohesion for shear failure [Pa] 161 double& Mohr_friction, ///< friction angle for shear failure [degree] 162 double& Janosi_shear, ///< shear parameter in Janosi-Hanamoto formula [m] 163 double& elastic_K, ///< elastic stiffness K per unit area, [Pa/m] (must be larger than Kphi) 164 double& damping_R ///< vertical damping R per unit area [Pa.s/m] (proportional to vertical speed) 165 ) = 0; 166 }; 167 168 /// Specify the callback object to set the soil parameters at given (x,y) locations. 169 /// To use constant soil parameters throughout the entire patch, use SetSoilParameters. 170 void RegisterSoilParametersCallback(std::shared_ptr<SoilParametersCallback> cb); 171 172 /// Get the initial (undeformed) terrain height below the specified location. 173 double GetInitHeight(const ChVector<>& loc) const; 174 175 /// Get the initial (undeformed) terrain normal at the point below the specified location. 176 ChVector<> GetInitNormal(const ChVector<>& loc) const; 177 178 /// Get the terrain height below the specified location. 179 virtual double GetHeight(const ChVector<>& loc) const override; 180 181 /// Get the terrain normal at the point below the specified location. 182 virtual ChVector<> GetNormal(const ChVector<>& loc) const override; 183 184 /// Get the terrain coefficient of friction at the point below the specified location. 185 /// This coefficient of friction value may be used by certain tire models to modify 186 /// the tire characteristics, but it will have no effect on the interaction of the terrain 187 /// with other objects (including tire models that do not explicitly use it). 188 /// For SCMDeformableTerrain, this function defers to the user-provided functor object 189 /// of type ChTerrain::FrictionFunctor, if one was specified. 190 /// Otherwise, it returns the constant value of 0.8. 191 virtual float GetCoefficientFriction(const ChVector<>& loc) const override; 192 193 /// Get the visualization triangular mesh. 194 std::shared_ptr<ChTriangleMeshShape> GetMesh() const; 195 196 /// Set the visualization mesh as wireframe or as solid (default: wireframe). 197 /// Note: in wireframe mode, normals for the visualization mesh are not calculated. 198 void SetMeshWireframe(bool val); 199 200 /// Save the visualization mesh as a Wavefront OBJ file. 201 void WriteMesh(const std::string& filename) const; 202 203 /// Initialize the terrain system (flat). 204 /// This version creates a flat array of points. 205 void Initialize(double sizeX, ///< [in] terrain dimension in the X direction 206 double sizeY, ///< [in] terrain dimension in the Y direction 207 double delta ///< [in] grid spacing (may be slightly decreased) 208 ); 209 210 /// Initialize the terrain system (height map). 211 /// The initial undeformed mesh is provided via the specified image file as a height map. 212 /// By default, a mesh vertex is created for each pixel in the image. If divX and divY are non-zero, 213 /// the image will be sampled at the specified resolution with linear interpolation as needed. 214 void Initialize(const std::string& heightmap_file, ///< [in] filename for the height map (image file) 215 double sizeX, ///< [in] terrain dimension in the X direction 216 double sizeY, ///< [in] terrain dimension in the Y direction 217 double hMin, ///< [in] minimum height (black level) 218 double hMax, ///< [in] maximum height (white level) 219 double delta ///< [in] grid spacing (may be slightly decreased) 220 ); 221 222 /// Node height level at a given grid location. 223 typedef std::pair<ChVector2<int>, double> NodeLevel; 224 225 /// Get the heights of all modified grid nodes. 226 /// If 'all_nodes = true', return modified nodes from the start of simulation. Otherwise, return only the nodes 227 /// modified over the last step. 228 std::vector<NodeLevel> GetModifiedNodes(bool all_nodes = false) const; 229 230 /// Modify the level of grid nodes from the given list. 231 void SetModifiedNodes(const std::vector<NodeLevel>& nodes); 232 233 /// Return the current cumulative contact force on the specified body (due to interaction with the SCM terrain). 234 TerrainForce GetContactForce(std::shared_ptr<ChBody> body) const; 235 236 /// Return the number of rays cast at last step. 237 int GetNumRayCasts() const; 238 /// Return the number of ray hits at last step. 239 int GetNumRayHits() const; 240 /// Return the number of contact patches at last step. 241 int GetNumContactPatches() const; 242 /// Return the number of nodes in the erosion domain at last step (bulldosing effects). 243 int GetNumErosionNodes() const; 244 245 /// Return time for updating moving patches at last step (ms). 246 double GetTimerMovingPatches() const; 247 /// Return time for geometric ray intersection tests at last step (ms). 248 double GetTimerRayTesting() const; 249 /// Return time for ray casting at last step (ms). Includes time for ray intersectin testing. 250 double GetTimerRayCasting() const; 251 /// Return time for computing contact patches at last step (ms). 252 double GetTimerContactPatches() const; 253 /// Return time for computing contact forces at last step (ms). 254 double GetTimerContactForces() const; 255 /// Return time for computing bulldozing effects at last step (ms). 256 double GetTimerBulldozing() const; 257 /// Return time for visualization assets update at last step (ms). 258 double GetTimerVisUpdate() const; 259 260 /// Print timing and counter information for last step. 261 void PrintStepStatistics(std::ostream& os) const; 262 263 private: 264 std::shared_ptr<SCMDeformableSoil> m_ground; ///< underlying load container for contact force generation 265 }; 266 267 /// Parameters for soil-contactable interaction. 268 class CH_VEHICLE_API SCMContactableData { 269 public: 270 SCMContactableData(double area_ratio, ///< area fraction with overriden parameters (in [0,1]) 271 double Mohr_cohesion, ///< cohesion for shear failure [Pa] 272 double Mohr_friction, ///< friction angle for shear failure [degree] 273 double Janosi_shear ///< shear parameter in Janosi-Hanamoto formula [m] 274 ); 275 276 private: 277 double area_ratio; ///< fraction of contactable surface where soil-soil parameters are overriden 278 double Mohr_cohesion; ///< cohesion for shear failure [Pa] 279 double Mohr_mu; ///< coefficient of friction for shear failure [degree] 280 double Janosi_shear; ///< shear parameter in Janosi-Hanamoto formula [m] 281 282 friend class SCMDeformableSoil; 283 }; 284 285 /// Underlying implementation of the Soil Contact Model. 286 class CH_VEHICLE_API SCMDeformableSoil : public ChLoadContainer { 287 public: 288 SCMDeformableSoil(ChSystem* system, bool visualization_mesh); ~SCMDeformableSoil()289 ~SCMDeformableSoil() {} 290 291 /// Initialize the terrain system (flat). 292 /// This version creates a flat array of points. 293 void Initialize(double hsizeX, ///< [in] terrain dimension in the X direction 294 double hsizeY, ///< [in] terrain dimension in the Y direction 295 double delta ///< [in] grid spacing (may be slightly decreased) 296 ); 297 298 /// Initialize the terrain system (height map). 299 /// The initial undeformed mesh is provided via the specified image file as a height map 300 /// By default, a mesh vertex is created for each pixel in the image. If divX and divY are non-zero, 301 /// the image will be sampled at the specified resolution with linear interpolation as needed. 302 void Initialize(const std::string& heightmap_file, ///< [in] filename for the height map (image file) 303 double sizeX, ///< [in] terrain dimension in the X direction 304 double sizeY, ///< [in] terrain dimension in the Y direction 305 double hMin, ///< [in] minimum height (black level) 306 double hMax, ///< [in] maximum height (white level) 307 double delta ///< [in] grid spacing (may be slightly decreased) 308 ); 309 310 private: 311 // SCM patch type 312 enum class PatchType { 313 FLAT, // flat patch 314 HEIGHT_MAP // triangular mesh (generated from a gray-scale image height-map) 315 }; 316 317 // Moving patch parameters 318 struct MovingPatchInfo { 319 std::shared_ptr<ChBody> m_body; // tracked body 320 ChVector<> m_center; // OOBB center, relative to body 321 ChVector<> m_hdims; // OOBB half-dimensions 322 std::vector<ChVector2<int>> m_range; // current grid nodes covered by the patch 323 ChVector<> m_ooN; // current inverse of SCM normal in body frame 324 }; 325 326 // Information at contacted node 327 struct NodeRecord { 328 double level_initial; // initial node level (relative to SCM frame) 329 double level; // current node level (relative to SCM frame) 330 double hit_level; // ray hit level (relative to SCM frame) 331 ChVector<> normal; // normal of undeformed terrain (in SCM frame) 332 double sinkage; // along local normal direction 333 double sinkage_plastic; // along local normal direction 334 double sinkage_elastic; // along local normal direction 335 double sigma; // along local normal direction 336 double sigma_yield; // along local normal direction 337 double kshear; // along local tangent direction 338 double tau; // along local tangent direction 339 bool erosion; // for bulldozing 340 double massremainder; // for bulldozing 341 double step_plastic_flow; // for bulldozing 342 NodeRecordNodeRecord343 NodeRecord() : NodeRecord(0, 0, ChVector<>(0,0,1)) {} ~NodeRecordNodeRecord344 ~NodeRecord() {} 345 NodeRecordNodeRecord346 NodeRecord(double init_level, double level, const ChVector<>& n) 347 : level_initial(init_level), 348 level(level), 349 hit_level(1e9), 350 normal(n), 351 sinkage(init_level - level), 352 sinkage_plastic(0), 353 sinkage_elastic(0), 354 sigma(0), 355 sigma_yield(0), 356 kshear(0), 357 tau(0), 358 erosion(false), 359 massremainder(0), 360 step_plastic_flow(0) {} 361 }; 362 363 // Hash function for a pair of integer grid coordinates 364 struct CoordHash { 365 public: 366 // 31 is just a decently-sized prime number to reduce bucket collisions operatorCoordHash367 std::size_t operator()(const ChVector2<int>& p) const { return p.x() * 31 + p.y(); } 368 }; 369 370 // Get the initial undeformed terrain height (relative to the SCM plane) at the specified grid node. 371 double GetInitHeight(const ChVector2<int>& loc) const; 372 373 // Get the initial undeformed terrain normal (relative to the SCM plane) at the specified grid node. 374 ChVector<> GetInitNormal(const ChVector2<int>& loc) const; 375 376 // Get the terrain height (relative to the SCM plane) at the specified grid node. 377 double GetHeight(const ChVector2<int>& loc) const; 378 379 // Get the terrain normal (relative to the SCM plane) at the specified grid vertex. 380 ChVector<> GetNormal(const ChVector2<>& loc) const; 381 382 // Get the initial terrain height (expressed in World frame) below the specified location. 383 double GetInitHeight(const ChVector<>& loc) const; 384 385 // Get the initial terrain normal (expressed in World frame) at the point below the specified location. 386 ChVector<> GetInitNormal(const ChVector<>& loc) const; 387 388 // Get the terrain height (expressed in World frame) below the specified location. 389 double GetHeight(const ChVector<>& loc) const; 390 391 // Get the terrain normal (expressed in World frame) at the point below the specified location. 392 ChVector<> GetNormal(const ChVector<>& loc) const; 393 394 // Get index of trimesh vertex corresponding to the specified grid node. 395 int GetMeshVertexIndex(const ChVector2<int>& loc); 396 397 // Get indices of trimesh faces incident to the specified grid vertex. 398 std::vector<int> GetMeshFaceIndices(const ChVector2<int>& loc); 399 400 // Check if the provided grid location is within the visualization mesh bounds 401 bool CheckMeshBounds(const ChVector2<int>& loc) const; 402 403 // Complete setup before first simulation step. 404 virtual void SetupInitial() override; 405 406 // Update the forces and the geometry, at the beginning of each timestep. Setup()407 virtual void Setup() override { 408 ComputeInternalForces(); 409 ChLoadContainer::Update(ChTime, true); 410 } 411 412 virtual void Update(double mytime, bool update_assets = true) override { 413 // Note!!! we cannot call ComputeInternalForces here, because Update() could 414 // be called multiple times per timestep and not necessarily in time-increasing order; 415 // this is a problem because in this force model the force is dissipative and keeps a 'history'. 416 // Instead, we invoke ComputeInternalForces only at the beginning of the timestep in Setup(). 417 418 ChTime = mytime; 419 } 420 421 // Synchronize information for a moving patch 422 void UpdateMovingPatch(MovingPatchInfo& p, const ChVector<>& Z); 423 424 // Synchronize information for fixed patch 425 void UpdateFixedPatch(MovingPatchInfo& p); 426 427 // Ray-OBB intersection test 428 bool RayOBBtest(const MovingPatchInfo& p, const ChVector<>& from, const ChVector<>& Z); 429 430 // Reset the list of forces and fill it with forces from the soil contact model. 431 // This is called automatically during timestepping (only at the beginning of each step). 432 void ComputeInternalForces(); 433 434 // Override the ChLoadContainer method for computing the generalized force F term: IntLoadResidual_F(const unsigned int off,ChVectorDynamic<> & R,const double c)435 virtual void IntLoadResidual_F(const unsigned int off, // offset in R residual 436 ChVectorDynamic<>& R, // result: the R residual, R += c*F 437 const double c // a scaling factor 438 ) override { 439 ChLoadContainer::IntLoadResidual_F(off, R, c); 440 } 441 442 // Add specified amount of material (possibly clamped) to node. 443 void AddMaterialToNode(double amount, NodeRecord& nr); 444 445 // Remove specified amount of material (possibly clamped) from node. 446 void RemoveMaterialFromNode(double amount, NodeRecord& nr); 447 448 // Update vertex position and color in visualization mesh 449 void UpdateMeshVertexCoordinates(const ChVector2<int> ij, int iv, const NodeRecord& nr); 450 451 // Update vertex normal in visualization mesh 452 void UpdateMeshVertexNormal(const ChVector2<int> ij, int iv); 453 454 /// Get the heights of all modified grid nodes. 455 /// If 'all_nodes = true', return modified nodes from the start of simulation. Otherwise, return only the nodes 456 /// modified over the last step. 457 std::vector<SCMDeformableTerrain::NodeLevel> GetModifiedNodes(bool all_nodes = false) const; 458 459 // Modify the level of grid nodes from the given list. 460 void SetModifiedNodes(const std::vector<SCMDeformableTerrain::NodeLevel>& nodes); 461 462 PatchType m_type; // type of SCM patch 463 ChCoordsys<> m_plane; // SCM frame (deformation occurs along the z axis of this frame) 464 ChVector<> m_Z; // SCM plane vertical direction (in absolute frame) 465 double m_delta; // grid spacing 466 double m_area; // area of a grid cell 467 int m_nx; // range for grid indices in X direction: [-m_nx, +m_nx] 468 int m_ny; // range for grid indices in Y direction: [-m_ny, +m_ny] 469 470 ChMatrixDynamic<> m_heights; // (base) grid heights (when initializing from height-field map) 471 472 std::unordered_map<ChVector2<int>, NodeRecord, CoordHash> m_grid_map; // modified grid nodes (persistent) 473 std::vector<ChVector2<int>> m_modified_nodes; // modified grid nodes (current) 474 475 std::vector<MovingPatchInfo> m_patches; // set of active moving patches 476 bool m_moving_patch; // user-specified moving patches? 477 478 double m_test_offset_down; // offset for ray start 479 double m_test_offset_up; // offset for ray end 480 481 std::shared_ptr<ChTriangleMeshShape> m_trimesh_shape; // mesh visualization asset 482 std::shared_ptr<ChColorAsset> m_color; // mesh edge default color 483 484 // SCM parameters 485 double m_Bekker_Kphi; ///< frictional modulus in Bekker model 486 double m_Bekker_Kc; ///< cohesive modulus in Bekker model 487 double m_Bekker_n; ///< exponent of sinkage in Bekker model (usually 0.6...1.8) 488 double m_Mohr_cohesion; ///< cohesion for shear failure [Pa] 489 double m_Mohr_mu; ///< coefficient of friction for shear failure [degree] 490 double m_Janosi_shear; ///< shear parameter in Janosi-Hanamoto formula [m] 491 double m_elastic_K; ///< elastic stiffness K per unit area, [Pa/m] (must be larger than Kphi) 492 double m_damping_R; ///< vertical damping R per unit area [Pa.s/m] (proportional to vertical speed) 493 494 // Callback object for position-dependent soil properties 495 std::shared_ptr<SCMDeformableTerrain::SoilParametersCallback> m_soil_fun; 496 497 // Contact forces on contactable objects interacting with the SCM terrain 498 std::unordered_map<ChContactable*, TerrainForce> m_contact_forces; 499 500 // Bulldozing effects 501 bool m_bulldozing; 502 double m_flow_factor; 503 double m_erosion_slope; 504 int m_erosion_iterations; 505 int m_erosion_propagations; 506 507 // Mesh coloring mode 508 SCMDeformableTerrain::DataPlotType m_plot_type; 509 double m_plot_v_min; 510 double m_plot_v_max; 511 512 // Indices of visualization mesh vertices modified externally 513 std::vector<int> m_external_modified_vertices; 514 515 // Timers and counters 516 ChTimer<double> m_timer_moving_patches; 517 ChTimer<double> m_timer_ray_testing; 518 ChTimer<double> m_timer_ray_casting; 519 ChTimer<double> m_timer_contact_patches; 520 ChTimer<double> m_timer_contact_forces; 521 ChTimer<double> m_timer_bulldozing; 522 ChTimer<double> m_timer_bulldozing_boundary; 523 ChTimer<double> m_timer_bulldozing_domain; 524 ChTimer<double> m_timer_bulldozing_erosion; 525 ChTimer<double> m_timer_visualization; 526 int m_num_ray_casts; 527 int m_num_ray_hits; 528 int m_num_contact_patches; 529 int m_num_erosion_nodes; 530 531 friend class SCMDeformableTerrain; 532 }; 533 534 /// @} vehicle_terrain 535 536 } // end namespace vehicle 537 } // end namespace chrono 538 539 #endif 540