// // Copyright Contributors to the MaterialX Project // SPDX-License-Identifier: Apache-2.0 // #include #include MATERIALX_NAMESPACE_BEGIN const string GEOM_PATH_SEPARATOR = "/"; const string UNIVERSAL_GEOM_NAME = GEOM_PATH_SEPARATOR; const string UDIM_TOKEN = ""; const string UV_TILE_TOKEN = ""; const string UDIM_SET_PROPERTY = "udimset"; const string GeomElement::GEOM_ATTRIBUTE = "geom"; const string GeomElement::COLLECTION_ATTRIBUTE = "collection"; const string GeomPropDef::GEOM_PROP_ATTRIBUTE = "geomprop"; const string GeomPropDef::SPACE_ATTRIBUTE = "space"; const string GeomPropDef::INDEX_ATTRIBUTE = "index"; const string Collection::INCLUDE_GEOM_ATTRIBUTE = "includegeom"; const string Collection::EXCLUDE_GEOM_ATTRIBUTE = "excludegeom"; const string Collection::INCLUDE_COLLECTION_ATTRIBUTE = "includecollection"; bool geomStringsMatch(const string& geom1, const string& geom2, bool contains) { vector paths1; for (const string& name1 : splitString(geom1, ARRAY_VALID_SEPARATORS)) { paths1.emplace_back(name1); } for (const string& name2 : splitString(geom2, ARRAY_VALID_SEPARATORS)) { GeomPath path2(name2); for (const GeomPath& path1 : paths1) { if (path1.isMatching(path2, contains)) { return true; } } } return false; } // // GeomElement methods // void GeomElement::setCollection(ConstCollectionPtr collection) { if (collection) { setCollectionString(collection->getName()); } else { removeAttribute(COLLECTION_ATTRIBUTE); } } CollectionPtr GeomElement::getCollection() const { return resolveNameReference(getCollectionString()); } bool GeomElement::validate(string* message) const { bool res = true; if (hasCollectionString()) { validateRequire(getCollection() != nullptr, res, message, "Invalid collection string"); } return Element::validate(message) && res; } // // Collection methods // void Collection::setIncludeCollection(ConstCollectionPtr collection) { if (collection) { setIncludeCollectionString(collection->getName()); } else { removeAttribute(INCLUDE_COLLECTION_ATTRIBUTE); } } void Collection::setIncludeCollections(const vector& collections) { if (!collections.empty()) { StringVec stringVec; for (ConstCollectionPtr collection : collections) { stringVec.push_back(collection->getName()); } setTypedAttribute(INCLUDE_COLLECTION_ATTRIBUTE, stringVec); } else { removeAttribute(INCLUDE_COLLECTION_ATTRIBUTE); } } vector Collection::getIncludeCollections() const { vector vec; for (const string& str : getTypedAttribute(INCLUDE_COLLECTION_ATTRIBUTE)) { CollectionPtr collection = resolveNameReference(str); if (collection) { vec.push_back(collection); } } return vec; } bool Collection::hasIncludeCycle() const { try { matchesGeomString(UNIVERSAL_GEOM_NAME); } catch (ExceptionFoundCycle&) { return true; } return false; } bool Collection::matchesGeomString(const string& geom) const { if (geomStringsMatch(getActiveExcludeGeom(), geom, true)) { return false; } if (geomStringsMatch(getActiveIncludeGeom(), geom)) { return true; } std::set includedSet; vector includedVec = getIncludeCollections(); for (size_t i = 0; i < includedVec.size(); i++) { CollectionPtr collection = includedVec[i]; if (includedSet.count(collection)) { throw ExceptionFoundCycle("Encountered a cycle in collection: " + getName()); } includedSet.insert(collection); vector appendVec = collection->getIncludeCollections(); includedVec.insert(includedVec.end(), appendVec.begin(), appendVec.end()); } for (ConstCollectionPtr collection : includedSet) { if (collection->matchesGeomString(geom)) { return true; } } return false; } bool Collection::validate(string* message) const { bool res = true; validateRequire(!hasIncludeCycle(), res, message, "Cycle in collection include chain"); return Element::validate(message) && res; } MATERIALX_NAMESPACE_END