mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Implement element-hierarchy setting in USD
This commit is contained in:
@@ -872,8 +872,8 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (geometry_settings.get<ifcopenshell::geometry::settings::UseElementHierarchy>().get() && output_extension != DAE) {
|
||||
cerr_ << "[Error] --use-element-hierarchy can be used only with .dae output.\n";
|
||||
if (geometry_settings.get<ifcopenshell::geometry::settings::UseElementHierarchy>().get() && output_extension != DAE && output_extension != USD) {
|
||||
cerr_ << "[Error] --use-element-hierarchy can be used only with .dae or .usd output.\n";
|
||||
/// @todo Lots of duplicate error-and-exit code.
|
||||
write_log(!quiet);
|
||||
print_usage();
|
||||
|
||||
@@ -96,8 +96,8 @@ namespace IfcGeom {
|
||||
const std::string& unique_id() const { return _unique_id; }
|
||||
const Transformation& transformation() const { return _transformation; }
|
||||
const IfcUtil::IfcBaseEntity* product() const { return product_; }
|
||||
const std::vector<const IfcGeom::Element*> parents() const { return _parents; }
|
||||
void SetParents(std::vector<const IfcGeom::Element*> newparents) { _parents = newparents; }
|
||||
const std::vector<const IfcGeom::Element*>& parents() const { return _parents; }
|
||||
void SetParents(std::vector<const IfcGeom::Element*>& newparents) { _parents = newparents; }
|
||||
|
||||
Element(const ifcopenshell::geometry::Settings& settings, int id, int parent_id, const std::string& name, const std::string& type,
|
||||
const std::string& guid, const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4::ptr& trsf, const IfcUtil::IfcBaseEntity* product)
|
||||
|
||||
+13
-7
@@ -712,20 +712,26 @@ namespace IfcGeom {
|
||||
IfcUtil::IfcBaseEntity* ifc_product = 0;
|
||||
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* ifc_entity = ifc_file->instance_by_id(id)->as<IfcUtil::IfcBaseEntity>();
|
||||
instance_type = ifc_entity->declaration().name();
|
||||
ifc_product = ifc_file->instance_by_id(id)->as<IfcUtil::IfcBaseEntity>();
|
||||
instance_type = ifc_product->declaration().name();
|
||||
|
||||
if (ifc_entity->declaration().is("IfcRoot")) {
|
||||
product_guid = (std::string) *ifc_entity->get("GlobalId");
|
||||
product_name = ifc_entity->get_value<std::string>("Name", "");
|
||||
if (ifc_product->declaration().is("IfcRoot")) {
|
||||
product_guid = (std::string) *ifc_product->get("GlobalId");
|
||||
product_name = ifc_product->get_value<std::string>("Name", "");
|
||||
}
|
||||
|
||||
auto parent_object = converter_->mapping()->get_decomposing_entity(ifc_entity);
|
||||
auto parent_object = converter_->mapping()->get_decomposing_entity(ifc_product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->data().id();
|
||||
}
|
||||
|
||||
m4 = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(converter_->mapping()->map(ifc_product))->matrix;
|
||||
// fails in case of IfcProject
|
||||
auto mapped = converter_->mapping()->map(ifc_product);
|
||||
auto casted = mapped ? ifcopenshell::geometry::taxonomy::dcast<ifcopenshell::geometry::taxonomy::geom_item>(mapped) : nullptr;
|
||||
|
||||
if (casted) {
|
||||
m4 = casted->matrix;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
@@ -53,8 +53,6 @@ USDSerializer::USDSerializer(const std::string& out_filename, const ifcopenshell
|
||||
|
||||
pxr::UsdGeomSetStageMetersPerUnit(stage_, 1.0f);
|
||||
|
||||
auto world = pxr::UsdGeomXform::Define(stage_, pxr::SdfPath("/World"));
|
||||
stage_->SetDefaultPrim(world.GetPrim());
|
||||
pxr::UsdGeomScope::Define(stage_, pxr::SdfPath("/Looks"));
|
||||
auto light = pxr::UsdLuxDistantLight::Define(stage_, pxr::SdfPath("/defaultLight"));
|
||||
light.CreateIntensityAttr().Set(1000.0f);
|
||||
@@ -119,26 +117,85 @@ void USDSerializer::writeHeader() {
|
||||
stage_->GetRootLayer()->SetComment("File generated by IfcOpenShell " + std::string(IFCOPENSHELL_VERSION));
|
||||
}
|
||||
|
||||
void USDSerializer::write(const IfcGeom::TriangulationElement* o) {
|
||||
pxr::UsdGeomMesh usd_mesh;
|
||||
const IfcGeom::Representation::Triangulation& mesh = o->geometry();
|
||||
const auto verts = mesh.verts();
|
||||
const auto faces = mesh.faces();
|
||||
const auto material_ids = mesh.material_ids();
|
||||
namespace {
|
||||
std::string nameObject(const IfcGeom::Element* o) {
|
||||
std::string name = o->name();
|
||||
const std::string type = o->type();
|
||||
const std::string id = std::to_string(o->id());
|
||||
if (name.empty()) {
|
||||
name = type + "_UnNamed_" + id;
|
||||
} else {
|
||||
name = type + "_" + usd_utils::toPath(name) + "_" + id;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T USDSerializer::writeNode(const IfcGeom::Element* o, const IfcGeom::Element* p) {
|
||||
written_.insert(o->id());
|
||||
|
||||
auto m = o->transformation().data()->ccomponents();
|
||||
|
||||
// store absolute matrix for calculating relative child matrices later on.
|
||||
placements_[o->id()] = o->transformation().data();
|
||||
|
||||
bool is_root = false;
|
||||
std::string prefix = "/";
|
||||
if (geometry_settings_.get<ifcopenshell::geometry::settings::UseElementHierarchy>().get() && p == nullptr && o->parents().empty()) {
|
||||
// Emitting hierarchy
|
||||
// p == nullptr means we're in the first pass serializing geometric elements
|
||||
// in that case empty parents vector means it's the root
|
||||
is_root = true;
|
||||
} else if (p != nullptr) {
|
||||
// Providing explicit parent pointer, lookup previously serialized m4 and path
|
||||
prefix = paths_[p->id()] + "/";
|
||||
m = placements_[p->id()]->ccomponents().inverse() * m;
|
||||
} else {
|
||||
std::vector<std::string> names;
|
||||
std::transform(o->parents().begin(), o->parents().end(), std::back_inserter(names), nameObject);
|
||||
std::ostringstream oss;
|
||||
std::copy(names.begin(), names.end(), std::ostream_iterator<std::string>(oss, "/"));
|
||||
prefix += oss.str();
|
||||
|
||||
// std::ostringstream pss;
|
||||
// pss << "MATT" << std::endl << std::endl;
|
||||
// pss << m << std::endl << std::endl << o->parents().back()->transformation().data()->ccomponents() << std::endl << std::endl;
|
||||
m = o->parents().back()->transformation().data()->ccomponents().inverse() * m;
|
||||
// pss << m << std::endl << std::endl;
|
||||
// auto psss = pss.str();
|
||||
// std::wcout << psss.c_str() << std::endl;
|
||||
}
|
||||
auto el_path = prefix + nameObject(o);
|
||||
paths_[o->id()] = el_path;
|
||||
|
||||
T t = T::Define(stage_, pxr::SdfPath(el_path));
|
||||
if (is_root) {
|
||||
stage_->SetDefaultPrim(t.GetPrim());
|
||||
}
|
||||
|
||||
t.AddTransformOp().Set(pxr::GfMatrix4d(
|
||||
m.data()[0], m.data()[1], m.data()[2], m.data()[3],
|
||||
m.data()[4], m.data()[5], m.data()[6], m.data()[7],
|
||||
m.data()[8], m.data()[9], m.data()[10], m.data()[11],
|
||||
m.data()[12], m.data()[13], m.data()[14], m.data()[15]
|
||||
));
|
||||
return t;
|
||||
}
|
||||
|
||||
if (material_ids.empty() || verts.empty() || faces.empty())
|
||||
return;
|
||||
void USDSerializer::write(const IfcGeom::TriangulationElement* o) {
|
||||
IfcGeom::Element const * previous = nullptr;
|
||||
for (auto it = o->parents().begin(); it != o->parents().end(); ++it) {
|
||||
parents_.push_back({ *it, previous });
|
||||
previous = *it;
|
||||
}
|
||||
pxr::UsdGeomMesh usd_mesh = writeNode<pxr::UsdGeomMesh>(o);
|
||||
const IfcGeom::Representation::Triangulation& mesh = o->geometry();
|
||||
const auto verts = mesh.verts();
|
||||
const auto faces = mesh.faces();
|
||||
const auto material_ids = mesh.material_ids();
|
||||
|
||||
|
||||
std::string name = o->name();
|
||||
const std::string type = o->type();
|
||||
const std::string id = std::to_string(o->id());
|
||||
if(name.empty()) {
|
||||
name = type + "_UnNamed_" + id;
|
||||
} else {
|
||||
name = type + "_" + usd_utils::toPath(name) + "_" + id;
|
||||
}
|
||||
usd_mesh = pxr::UsdGeomMesh::Define(stage_, pxr::SdfPath("/World/" + name));
|
||||
pxr::VtVec3fArray points;
|
||||
for(std::size_t i = 0; i < verts.size(); i+=3) {
|
||||
points.push_back(pxr::GfVec3f(static_cast<float>(verts[i]),
|
||||
@@ -149,13 +206,6 @@ void USDSerializer::write(const IfcGeom::TriangulationElement* o) {
|
||||
usd_mesh.CreateFaceVertexIndicesAttr().Set(usd_utils::toVtArray(faces));
|
||||
usd_mesh.CreateFaceVertexCountsAttr().Set(pxr::VtArray<int>((int) faces.size() / 3, 3));
|
||||
|
||||
usd_mesh.AddTransformOp().Set(pxr::GfMatrix4d(
|
||||
m.data()[0], m.data()[1], m.data()[2], m.data()[3],
|
||||
m.data()[4], m.data()[5], m.data()[6], m.data()[7],
|
||||
m.data()[8], m.data()[9], m.data()[10], m.data()[11],
|
||||
m.data()[12], m.data()[13], m.data()[14], m.data()[15]
|
||||
));
|
||||
|
||||
pxr::VtVec3fArray normals;
|
||||
for (std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end();)
|
||||
normals.push_back(pxr::GfVec3f(static_cast<float>(*(it++)), static_cast<float>(*(it++)), static_cast<float>(*(it++))));
|
||||
@@ -178,7 +228,20 @@ void USDSerializer::write(const IfcGeom::TriangulationElement* o) {
|
||||
}
|
||||
|
||||
void USDSerializer::finalize() {
|
||||
// we write the parents at the end, because some parents might actually be
|
||||
// geometrical entities such as the IfcSite.
|
||||
std::set<int> written;
|
||||
for (auto& [p, q] : parents_) {
|
||||
if (written.find(p->id()) == written.end() && written_.find(p->id()) == written_.end()) {
|
||||
written.insert(p->id());
|
||||
writeNode<pxr::UsdGeomXform>(p, q);
|
||||
}
|
||||
}
|
||||
|
||||
stage_->Save();
|
||||
}
|
||||
|
||||
template pxr::UsdGeomMesh USDSerializer::writeNode<pxr::UsdGeomMesh>(const IfcGeom::Element*, const IfcGeom::Element*);
|
||||
template pxr::UsdGeomXform USDSerializer::writeNode<pxr::UsdGeomXform>(const IfcGeom::Element*, const IfcGeom::Element*);
|
||||
|
||||
#endif // WITH_USD
|
||||
@@ -71,6 +71,13 @@ private:
|
||||
std::map<std::string, std::string> meshes_;
|
||||
|
||||
std::vector<pxr::UsdShadeMaterial> createMaterials(const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>&);
|
||||
template <typename T>
|
||||
T writeNode(const IfcGeom::Element*, const IfcGeom::Element* = nullptr);
|
||||
std::vector<std::pair<IfcGeom::Element const*, IfcGeom::Element const*>> parents_;
|
||||
|
||||
std::set<int> written_;
|
||||
std::map<int, std::string> paths_;
|
||||
std::map<int, ifcopenshell::geometry::taxonomy::matrix4::ptr> placements_;
|
||||
public:
|
||||
USDSerializer(const std::string&, const ifcopenshell::geometry::Settings&, const ifcopenshell::geometry::SerializerSettings&);
|
||||
virtual ~USDSerializer();
|
||||
|
||||
Reference in New Issue
Block a user