Merge pull request #21 from assimp/assimp-metadata

Assimp metadata implementation. This adds aiNode::mMetaData, the <assimp/metadata.h> header containing the aiMetaData structure. Also adds support for Ifc reading metadata to test out the new feature.
This commit is contained in:
Alexander Gessler
2013-03-29 12:08:29 -07:00
10 changed files with 8222 additions and 7620 deletions

View File

@@ -34,6 +34,7 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/quaternion.h
${HEADER_PATH}/quaternion.inl
${HEADER_PATH}/scene.h
${HEADER_PATH}/metadata.h
${HEADER_PATH}/texture.h
${HEADER_PATH}/types.h
${HEADER_PATH}/vector2.h

View File

@@ -251,7 +251,7 @@ void IFCImporter::InternReadFile( const std::string& pFile,
// tell the reader for which types we need to simulate STEPs reverse indices
static const char* const inverse_indices_to_track[] = {
"ifcrelcontainedinspatialstructure", "ifcrelaggregates", "ifcrelvoidselement", "ifcstyleditem"
"ifcrelcontainedinspatialstructure", "ifcrelaggregates", "ifcrelvoidselement", "ifcreldefinesbyproperties", "ifcpropertyset", "ifcstyleditem"
};
// feed the IFC schema into the reader and pre-parse all lines
@@ -513,7 +513,7 @@ struct RateRepresentationPredicate {
return -3;
}
// give strong preference to extruded geometry
// give strong preference to extruded geometry.
if (r == "SweptSolid") {
return -10;
}
@@ -584,6 +584,86 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
AssignAddedMeshes(meshes,nd,conv);
}
typedef std::map<std::string, std::string> Metadata;
// ------------------------------------------------------------------------------------------------
void ProcessMetadata(const ListOf< Lazy< IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties,
const std::string& prefix = "",
unsigned int nest = 0)
{
BOOST_FOREACH(const IfcProperty& property, set) {
const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
if (const IfcPropertySingleValue* const singleValue = property.ToPtr<IfcPropertySingleValue>()) {
if (singleValue->NominalValue) {
if (const EXPRESS::STRING* str = singleValue->NominalValue.Get()->ToPtr<EXPRESS::STRING>()) {
std::string value = static_cast<std::string>(*str);
properties[key]=value;
}
else if (const EXPRESS::REAL* val = singleValue->NominalValue.Get()->ToPtr<EXPRESS::REAL>()) {
float value = static_cast<float>(*val);
std::stringstream s;
s << value;
properties[key]=s.str();
}
else if (const EXPRESS::INTEGER* val = singleValue->NominalValue.Get()->ToPtr<EXPRESS::INTEGER>()) {
int64_t value = static_cast<int64_t>(*val);
std::stringstream s;
s << value;
properties[key]=s.str();
}
}
}
else if (const IfcPropertyListValue* const listValue = property.ToPtr<IfcPropertyListValue>()) {
std::stringstream ss;
ss << "[";
unsigned index=0;
BOOST_FOREACH(const IfcValue::Out& v, listValue->ListValues) {
if (!v) continue;
if (const EXPRESS::STRING* str = v->ToPtr<EXPRESS::STRING>()) {
std::string value = static_cast<std::string>(*str);
ss << "'" << value << "'";
}
else if (const EXPRESS::REAL* val = v->ToPtr<EXPRESS::REAL>()) {
float value = static_cast<float>(*val);
ss << value;
}
else if (const EXPRESS::INTEGER* val = v->ToPtr<EXPRESS::INTEGER>()) {
int64_t value = static_cast<int64_t>(*val);
ss << value;
}
if (index+1<listValue->ListValues.size()) {
ss << ",";
}
index++;
}
ss << "]";
properties[key]=ss.str();
}
else if (const IfcComplexProperty* const complexProp = property.ToPtr<IfcComplexProperty>()) {
if(nest > 2) { // mostly arbitrary limit to prevent stack overflow vulnerabilities
IFCImporter::LogError("maximum nesting level for IfcComplexProperty reached, skipping this property.");
}
else {
ProcessMetadata(complexProp->HasProperties, conv, properties, key, nest + 1);
}
}
else {
properties[key]="";
}
}
}
// ------------------------------------------------------------------------------------------------
void ProcessMetadata(uint64_t relDefinesByPropertiesID, ConversionData& conv, Metadata& properties)
{
if (const IfcRelDefinesByProperties* const pset = conv.db.GetObject(relDefinesByPropertiesID)->ToPtr<IfcRelDefinesByProperties>()) {
if (const IfcPropertySet* const set = conv.db.GetObject(pset->RelatingPropertyDefinition->GetID())->ToPtr<IfcPropertySet>()) {
ProcessMetadata(set->HasProperties, conv, properties);
}
}
}
// ------------------------------------------------------------------------------------------------
aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, ConversionData& conv, std::vector<TempOpening>* collect_openings = NULL)
{
@@ -609,6 +689,42 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
nd->mName.Set(el.GetClassName()+"_"+(el.Name?el.Name.Get():"Unnamed")+"_"+el.GlobalId);
nd->mParent = parent;
conv.already_processed.insert(el.GetID());
// check for node metadata
STEP::DB::RefMapRange children = refs.equal_range(el.GetID());
if (children.first!=refs.end()) {
Metadata properties;
if (children.first==children.second) {
// handles single property set
ProcessMetadata((*children.first).second, conv, properties);
}
else {
// handles multiple property sets (currently all property sets are merged,
// which may not be the best solution in the long run)
for (STEP::DB::RefMap::const_iterator it=children.first; it!=children.second; ++it) {
ProcessMetadata((*it).second, conv, properties);
}
}
if (!properties.empty()) {
aiMetadata* data = new aiMetadata();
data->mNumProperties = properties.size();
data->mKeys = new aiString*[data->mNumProperties]();
data->mValues = new aiString*[data->mNumProperties]();
unsigned int i = 0;
BOOST_FOREACH(const Metadata::value_type& kv, properties) {
data->mKeys[i] = new aiString(kv.first);
if (kv.second.length() > 0) {
data->mValues[i] = new aiString(kv.second);
}
++i;
}
nd->mMetaData = data;
}
}
if(el.ObjectPlacement) {
ResolveObjectPlacement(nd->mTransformation,el.ObjectPlacement.Get(),conv);
}
@@ -627,15 +743,24 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
STEP::DB::RefMapRange range = refs.equal_range(el.GetID());
for(STEP::DB::RefMapRange range2 = range; range2.first != range.second; ++range2.first) {
// skip over meshes that have already been processed before. This is strictly necessary
// because the reverse indices also include references contained in argument lists and
// therefore every element has a back-reference hold by its parent.
if (conv.already_processed.find((*range2.first).second) != conv.already_processed.end()) {
continue;
}
const STEP::LazyObject& obj = conv.db.MustGetObject((*range2.first).second);
// handle regularly-contained elements
if(const IfcRelContainedInSpatialStructure* const cont = obj->ToPtr<IfcRelContainedInSpatialStructure>()) {
if(cont->RelatingStructure->GetID() != el.GetID()) {
continue;
}
BOOST_FOREACH(const IfcProduct& pro, cont->RelatedElements) {
if(const IfcOpeningElement* const open = pro.ToPtr<IfcOpeningElement>()) {
// IfcOpeningElement is handled below. Sadly we can't use it here as is:
// The docs say that opening elements are USUALLY attached to building storeys
// but we want them for the building elements to which they belong to.
// The docs say that opening elements are USUALLY attached to building storey,
// but we want them for the building elements to which they belong.
continue;
}
@@ -686,7 +811,14 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
}
for(;range.first != range.second; ++range.first) {
// see note in loop above
if (conv.already_processed.find((*range.first).second) != conv.already_processed.end()) {
continue;
}
if(const IfcRelAggregates* const aggr = conv.db.GetObject((*range.first).second)->ToPtr<IfcRelAggregates>()) {
if(aggr->RelatingObject->GetID() != el.GetID()) {
continue;
}
// move aggregate elements to a separate node since they are semantically different than elements that are just 'contained'
std::auto_ptr<aiNode> nd_aggr(new aiNode());
@@ -732,6 +864,8 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
throw;
}
ai_assert(conv.already_processed.find(el.GetID()) != conv.already_processed.end());
conv.already_processed.erase(conv.already_processed.find(el.GetID()));
return nd.release();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -208,6 +208,8 @@ struct ConversionData
// for later processing by a parent, which is a wall.
std::vector<TempOpening>* apply_openings;
std::vector<TempOpening>* collect_openings;
std::set<uint64_t> already_processed;
};

View File

@@ -525,7 +525,7 @@ STEP::LazyObject::LazyObject(DB& db, uint64_t id,uint64_t /*line*/, const char*
--skip_depth;
}
if (skip_depth == 1 && *a=='#') {
if (skip_depth >= 1 && *a=='#') {
const char* tmp;
const int64_t num = static_cast<int64_t>( strtoul10_64(a+1,&tmp) );
db.MarkRef(num,id);