diff --git a/src/yamlbuilder/TensegrityModel.cpp b/src/yamlbuilder/TensegrityModel.cpp index a9f4b7f9d..57641ab3a 100644 --- a/src/yamlbuilder/TensegrityModel.cpp +++ b/src/yamlbuilder/TensegrityModel.cpp @@ -72,10 +72,13 @@ void TensegrityModel::setup(tgWorld& world) { void TensegrityModel::addChildren(tgStructure& structure, const std::string& structurePath, tgBuildSpec& spec, const Yam& children) { if (!children) return; + std::string structureAttributeKeys[] = {"path", "rotation", "translation", "scale", "offset"}; + std::vector structureAttributeKeysVector(structureAttributeKeys, structureAttributeKeys + sizeof(structureAttributeKeys) / sizeof(std::string)); // add all the children first for (YAML::const_iterator child = children.begin(); child != children.end(); ++child) { Yam childAttributes = child->second; + yamlContainsOnly(childAttributes, structurePath, structureAttributeKeysVector); // multiple children can be defined using the syntax: child1/child2/child3... // (add a slash so that each child is a string with a its name and a slash at the end) std::string childCombos = child->first.as() + "/"; @@ -187,6 +190,12 @@ void TensegrityModel::addChildTranslation(tgStructure& childStructure, const Yam void TensegrityModel::buildStructure(tgStructure& structure, const std::string& structurePath, tgBuildSpec& spec) { Yam root = YAML::LoadFile(structurePath); + // Validate YAML + std::string rootKeys[] = {"nodes", "pair_groups", "builders", "substructures", "bond_groups"}; + std::vector rootKeysVector(rootKeys, rootKeys + sizeof(rootKeys) / sizeof(std::string)); + yamlContainsOnly(root, structurePath, rootKeysVector); + yamlNoDuplicates(root, structurePath); + addChildren(structure, structurePath, spec, root["substructures"]); addBuilders(spec, root["builders"]); addNodes(structure, root["nodes"]); @@ -471,8 +480,8 @@ tgStructure& TensegrityModel::getStructure(tgStructure& parentStructure, const s void TensegrityModel::addBuilders(tgBuildSpec& spec, const Yam& builders) { for (YAML::const_iterator builder = builders.begin(); builder != builders.end(); ++builder) { - std::string tagMatch = builder->first.as(); + if (!builder->second["class"]) throw std::invalid_argument("Builder class not supplied for tag: " + tagMatch); std::string builderClass = builder->second["class"].as(); Yam parameters = builder->second["parameters"]; @@ -602,6 +611,32 @@ void TensegrityModel::addKinematicActuatorBuilder(const std::string& builderClas // add more builders that use tgKinematicActuator::Config here } +void TensegrityModel::yamlNoDuplicates(const Yam& yam, const std::string structurePath) { + std::set keys; + for (YAML::const_iterator iter = yam.begin(); iter != yam.end(); ++iter) { + Yam child = iter->second; + if (child.Type() == YAML::NodeType::Map) { + yamlNoDuplicates(child, structurePath); + } + std::string keyName = iter->first.as(); + if (keys.find(keyName) == keys.end()) { + keys.insert(keyName); + } + else { + throw std::invalid_argument(structurePath.substr(structurePath.rfind("/") + 1) + " contains duplicate key: " + keyName); + } + } +} + +void TensegrityModel::yamlContainsOnly(const Yam& yam, const std::string structurePath, const std::vector keys) { + for (YAML::const_iterator key = yam.begin(); key != yam.end(); ++key) { + std::string keyName = key->first.as(); + if (std::find(keys.begin(), keys.end(), keyName) == keys.end()) { + throw std::invalid_argument(structurePath.substr(structurePath.rfind("/") + 1) + " contains invalid key: " + keyName); + } + } +} + void TensegrityModel::step(double timeStep) { if (timeStep <= 0.0) { throw std::invalid_argument("time step is not positive"); diff --git a/src/yamlbuilder/TensegrityModel.h b/src/yamlbuilder/TensegrityModel.h index b360ca683..c24dd7359 100644 --- a/src/yamlbuilder/TensegrityModel.h +++ b/src/yamlbuilder/TensegrityModel.h @@ -57,76 +57,76 @@ class TensegrityModel : public tgSubject, public tgModel /* * Default rod radius. */ - const double rodRadius = 0.5; + const static double rodRadius = 0.5; /* * Default rod density. */ - const double rodDensity = 1.0; + const static double rodDensity = 1.0; /* * Default rod friction. */ - const double rodFriction = 1.0; + const static double rodFriction = 1.0; /* * Default rod roll friction. */ - const double rodRollFriction = 0.0; + const static double rodRollFriction = 0.0; /* * Default rod restitution. */ - const double rodRestitution = 0.2; + const static double rodRestitution = 0.2; /* * Default string stiffness. */ - const double stringStiffness = 1000.0; + const static double stringStiffness = 1000.0; /* * Default string damping. */ - const double stringDamping = 10.0; + const static double stringDamping = 10.0; /* * Default string pretension. */ - const double stringPretension = 0.0; + const static double stringPretension = 0.0; /* * Default string radius. */ - const double stringRadius = 1.0; + const static double stringRadius = 1.0; /* * Default string motor friction. */ - const double stringMotorFriction = 0.0; + const static double stringMotorFriction = 0.0; /* * Default string motor intertia. */ - const double stringMotorInertia = 1.0; + const static double stringMotorInertia = 1.0; /* * Default string back drivable (boolean). */ - const double stringBackDrivable = 0; + const static double stringBackDrivable = 0; /* * Default string history (boolean). */ - const double stringHistory = 0; + const static double stringHistory = 0; /* * Default string max tension. */ - const double stringMaxTension = 1000.0; + const static double stringMaxTension = 1000.0; /* * Default string target velocity. */ - const double stringTargetVelocity = 100.0; + const static double stringTargetVelocity = 100.0; /* * Default string min actual length. */ - const double stringMinActualLength = 0.1; + const static double stringMinActualLength = 0.1; /* * Default string min rest length. */ - const double stringMinRestLength = 0.1; + const static double stringMinRestLength = 0.1; /* * Default string rotation. */ - const double stringRotation = 0; + const static double stringRotation = 0; /* * YAML-encoded structure path. @@ -322,6 +322,17 @@ class TensegrityModel : public tgSubject, public tgModel * Responsible for adding a builder that uses the tgKinematicActuator config */ void addKinematicActuatorBuilder(const std::string& builderClass, const std::string& tagMatch, const Yam& parameters, tgBuildSpec& spec); + + /* + * Ensures YAML node contains only keys from the supplied vector + */ + void yamlContainsOnly(const Yam& yam, const std::string structurePath, const std::vector keys); + + /* + * Ensures that YAML has all unique keys within each map + */ + void yamlNoDuplicates(const Yam& yam, const std::string structurePath); + }; #endif // TENSEGRITY_MODEL_H