text: // =============================================================================
  // PROJECT CHRONO - http://projectchrono.org
  //
  // Copyright (c) 2014 projectchrono.org
  // All rights reserved.
  //
  // Use of this source code is governed by a BSD-style license that can be found
  // in the LICENSE file at the top level of the distribution and at
  // http://projectchrono.org/license-chrono.txt.
  //
  // =============================================================================
  // Authors: Rainer Gericke, Radu Serban
  // =============================================================================
  //
  // Leaf-spring solid axle suspension constructed with data from file.
  //
  // =============================================================================
  
  #include <cstdio>
  
  #include "chrono_vehicle/utils/ChUtilsJSON.h"
  #include "chrono_vehicle/wheeled_vehicle/suspension/LeafspringAxle.h"
  
  #include "chrono_thirdparty/rapidjson/filereadstream.h"
  
  using namespace rapidjson;
  
  namespace chrono {
  namespace vehicle {
  
  // -----------------------------------------------------------------------------
  // Construct a solid axle suspension using data from the specified JSON
  // file.
  // -----------------------------------------------------------------------------
  LeafspringAxle::LeafspringAxle(const std::string& filename)
      : ChLeafspringAxle(""), m_springForceCB(NULL), m_shockForceCB(NULL) {
      FILE* fp = fopen(filename.c_str(), "r");
  
      char readBuffer[65536];
      FileReadStream is(fp, readBuffer, sizeof(readBuffer));
  
      fclose(fp);
  
      Document d;
      d.ParseStream<ParseFlag::kParseCommentsFlag>(is);
  
      Create(d);
  
      GetLog() << "Loaded JSON: " << filename.c_str() << "\n";
  }
  
  LeafspringAxle::LeafspringAxle(const rapidjson::Document& d)
      : ChLeafspringAxle(""), m_springForceCB(NULL), m_shockForceCB(NULL) {
      Create(d);
  }
  
  // -----------------------------------------------------------------------------
  // -----------------------------------------------------------------------------
  LeafspringAxle::~LeafspringAxle() {
      delete m_springForceCB;
      delete m_shockForceCB;
  }
  
  // -----------------------------------------------------------------------------
  // Worker function for creating a LeafspringAxle suspension using data in the
  // specified RapidJSON document.
  // -----------------------------------------------------------------------------
  void LeafspringAxle::Create(const rapidjson::Document& d) {
      // Invoke base class method.
      ChPart::Create(d);
  
      // Read Spindle data
      assert(d.HasMember("Spindle"));
      assert(d["Spindle"].IsObject());
  
      m_spindleMass = d["Spindle"]["Mass"].GetDouble();
      m_points[SPINDLE] = LoadVectorJSON(d["Spindle"]["COM"]);
      m_spindleInertia = LoadVectorJSON(d["Spindle"]["Inertia"]);
      m_spindleRadius = d["Spindle"]["Radius"].GetDouble();
      m_spindleWidth = d["Spindle"]["Width"].GetDouble();
  
      // Read Axle Tube data
      assert(d.HasMember("Axle Tube"));
      assert(d["Axle Tube"].IsObject());
  
      m_axleTubeMass = d["Axle Tube"]["Mass"].GetDouble();
      m_axleTubeCOM = LoadVectorJSON(d["Axle Tube"]["COM"]);
      m_axleTubeInertia = LoadVectorJSON(d["Axle Tube"]["Inertia"]);
      m_axleTubeRadius = d["Axle Tube"]["Radius"].GetDouble();
  
      // Read spring data and create force callback
      assert(d.HasMember("Spring"));
      assert(d["Spring"].IsObject());
  
      m_points[SPRING_C] = LoadVectorJSON(d["Spring"]["Location Chassis"]);
      m_points[SPRING_A] = LoadVectorJSON(d["Spring"]["Location Axle"]);
      m_springRestLength = d["Spring"]["Free Length"].GetDouble();
      m_springMinLength = d["Spring"]["Minimal Length"].GetDouble();
      m_springMaxLength = d["Spring"]["Maximal Length"].GetDouble();
  
      if (d["Spring"].HasMember("Spring Coefficient")) {
          m_springForceCB = new LinearSpringBistopForce(d["Spring"]["Spring Coefficient"].GetDouble(), m_springMinLength,
                                                        m_springMaxLength);
      } else if (d["Spring"].HasMember("Curve Data")) {
          int num_points = d["Spring"]["Curve Data"].Size();
          MapSpringForce* springForceCB = new MapSpringForce();
          for (int i = 0; i < num_points; i++) {
              springForceCB->add_point(d["Spring"]["Curve Data"][i][0u].GetDouble(),
                                       d["Spring"]["Curve Data"][i][1u].GetDouble());
          }
          m_springForceCB = springForceCB;
      }
  
      // Read shock data and create force callback
      assert(d.HasMember("Shock"));
      assert(d["Shock"].IsObject());
  
      m_points[SHOCK_C] = LoadVectorJSON(d["Shock"]["Location Chassis"]);
      m_points[SHOCK_A] = LoadVectorJSON(d["Shock"]["Location Axle"]);
  
      if (d["Shock"].HasMember("Damping Coefficient")) {
          if (d["Shock"].HasMember("Degressivity Compression") && d["Shock"].HasMember("Degressivity Expansion")) {
              m_shockForceCB = new DegressiveDamperForce(d["Shock"]["Damping Coefficient"].GetDouble(),
                                                         d["Shock"]["Degressivity Compression"].GetDouble(),
                                                         d["Shock"]["Degressivity Expansion"].GetDouble());
          } else {
              m_shockForceCB = new LinearDamperForce(d["Shock"]["Damping Coefficient"].GetDouble());
          }
      } else if (d["Shock"].HasMember("Curve Data")) {
          int num_points = d["Shock"]["Curve Data"].Size();
          MapDamperForce* shockForceCB = new MapDamperForce();
          for (int i = 0; i < num_points; i++) {
              shockForceCB->add_point(d["Shock"]["Curve Data"][i][0u].GetDouble(),
                                      d["Shock"]["Curve Data"][i][1u].GetDouble());
          }
          m_shockForceCB = shockForceCB;
      }
  
      // Read axle inertia
      assert(d.HasMember("Axle"));
      assert(d["Axle"].IsObject());
  
      m_axleInertia = d["Axle"]["Inertia"].GetDouble();
  }
  
  }  // end namespace vehicle
  }  // end namespace chrono
  