mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
Merge branch 'master' into v0.6.0
# Conflicts: # src/ifcconvert/IfcConvert.cpp # src/ifcgeom/IfcGeomRenderStyles.cpp # src/ifcparse/IfcParse.cpp
This commit is contained in:
@@ -425,6 +425,10 @@ IF(MSVC)
|
||||
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
|
||||
ADD_DEFINITIONS(-wd4458)
|
||||
ENDIF()
|
||||
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
|
||||
if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
add_definitions(-permissive-)
|
||||
endif()
|
||||
# Link against the static VC runtime
|
||||
# TODO Make this configurable
|
||||
IF("$ENV{CONDA_BUILD}" STREQUAL "")
|
||||
|
||||
+2
-1
@@ -273,7 +273,8 @@ CMAKE_VERSION_2=CMAKE_VERSION[:CMAKE_VERSION.rindex('.')]
|
||||
OCE_LOCATION="https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz" % (OCE_VERSION,)
|
||||
BOOST_LOCATION="http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s.tar.bz2" % (BOOST_VERSION, BOOST_VERSION_UNDERSCORE)
|
||||
OPENCOLLADA_LOCATION="https://github.com/KhronosGroup/OpenCOLLADA.git"
|
||||
OPENCOLLADA_COMMIT="f99d59e73e565a41715eaebc00c7664e1ee5e628"
|
||||
#OPENCOLLADA_COMMIT="f99d59e73e565a41715eaebc00c7664e1ee5e628"
|
||||
OPENCOLLADA_COMMIT="v1.6.63"
|
||||
|
||||
# Helper functions
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
@@ -43,6 +44,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@@ -177,6 +179,7 @@ int main(int argc, char** argv)
|
||||
exclusion_filter exclude_filter;
|
||||
exclusion_traverse_filter exclude_traverse_filter;
|
||||
std::string filter_filename;
|
||||
std::string default_material_filename;
|
||||
|
||||
po::options_description geom_options("Geometry options");
|
||||
geom_options.add_options()
|
||||
@@ -257,8 +260,10 @@ int main(int argc, char** argv)
|
||||
"Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.")
|
||||
("generate-uvs",
|
||||
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
|
||||
"Not guaranteed to work properly if used with --weld-vertices.");
|
||||
|
||||
"Not guaranteed to work properly if used with --weld-vertices.")
|
||||
("default-material-file", po::value<std::string>(&default_material_filename),
|
||||
"Specifies a material file that describes the material object types will have"
|
||||
"if an object does not have any specified material in the IFC file.");
|
||||
|
||||
std::string bounds, offset_str;
|
||||
#ifdef HAVE_ICU
|
||||
@@ -488,7 +493,18 @@ int main(int argc, char** argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!default_material_filename.empty()) {
|
||||
try {
|
||||
IfcGeom::set_default_style_file(default_material_filename);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[Error] Could not read default material file " << default_material_filename << ":" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @todo Clean up this filter code further.
|
||||
std::vector<geom_filter> used_filters;
|
||||
if (include_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_filter); }
|
||||
@@ -535,7 +551,7 @@ int main(int argc, char** argv)
|
||||
settings.set_deflection_tolerance(deflection_tolerance);
|
||||
settings.precision = precision;
|
||||
|
||||
GeometrySerializer* serializer;
|
||||
boost::shared_ptr<GeometrySerializer> serializer; /**< @todo use std::unique_ptr when possible */
|
||||
if (output_extension == ".obj") {
|
||||
// Do not use temp file for MTL as it's such a small file.
|
||||
const std::string mtl_filename = change_extension(output_filename, "mtl");
|
||||
@@ -543,28 +559,28 @@ int main(int argc, char** argv)
|
||||
Logger::Notice("Using world coords when writing WaveFront OBJ files");
|
||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
||||
}
|
||||
serializer = new WaveFrontOBJSerializer(output_temp_filename, mtl_filename, settings);
|
||||
serializer = boost::make_shared<WaveFrontOBJSerializer>(output_temp_filename, mtl_filename, settings);
|
||||
#ifdef WITH_OPENCOLLADA
|
||||
} else if (output_extension == ".dae") {
|
||||
serializer = new ColladaSerializer(output_temp_filename, settings);
|
||||
serializer = boost::make_shared<ColladaSerializer>(output_temp_filename, settings);
|
||||
#endif
|
||||
} else if (output_extension == ".stp") {
|
||||
serializer = new StepSerializer(output_temp_filename, settings);
|
||||
serializer = boost::make_shared<StepSerializer>(output_temp_filename, settings);
|
||||
} else if (output_extension == ".igs") {
|
||||
#if OCC_VERSION_HEX < 0x60900
|
||||
// According to https://tracker.dev.opencascade.org/view.php?id=25689 something has been fixed in 6.9.0
|
||||
IGESControl_Controller::Init(); // work around Open Cascade bug
|
||||
#endif
|
||||
serializer = new IgesSerializer(output_temp_filename, settings);
|
||||
serializer = boost::make_shared<IgesSerializer>(output_temp_filename, settings);
|
||||
} else if (output_extension == ".svg") {
|
||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
||||
serializer = new SvgSerializer(output_temp_filename, settings);
|
||||
serializer = boost::make_shared<SvgSerializer>(output_temp_filename, settings);
|
||||
if (vmap.count("section-height") != 0) {
|
||||
Logger::Notice("Overriding section height");
|
||||
static_cast<SvgSerializer*>(serializer)->setSectionHeight(section_height);
|
||||
static_cast<SvgSerializer*>(serializer.get())->setSectionHeight(section_height);
|
||||
}
|
||||
if (bounding_width.is_initialized() && bounding_height.is_initialized()) {
|
||||
static_cast<SvgSerializer*>(serializer)->setBoundingRectangle(bounding_width.get(), bounding_height.get());
|
||||
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
|
||||
}
|
||||
} else {
|
||||
std::cerr << "[Error] Unknown output filename extension '" + output_extension + "'\n";
|
||||
@@ -573,13 +589,11 @@ int main(int argc, char** argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// NOTE After this point, make sure to delete serializer upon application exit.
|
||||
|
||||
if (use_element_hierarchy && output_extension != ".dae") {
|
||||
std::cerr << "[Error] --use-element-hierarchy can be used only with .dae output.\n";
|
||||
/// @todo Lots of duplicate error-and-exit code.
|
||||
write_log(!quiet);
|
||||
print_usage();
|
||||
delete serializer;
|
||||
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@@ -600,7 +614,6 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
if (!serializer->ready()) {
|
||||
delete serializer;
|
||||
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
|
||||
write_log(!quiet);
|
||||
return EXIT_FAILURE;
|
||||
@@ -610,6 +623,8 @@ int main(int argc, char** argv)
|
||||
time(&start);
|
||||
|
||||
if (!init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
|
||||
write_log(!quiet);
|
||||
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -618,7 +633,6 @@ int main(int argc, char** argv)
|
||||
/// @todo It would be nice to know and print separate error prints for a case where we found no entities
|
||||
/// and for a case we found no entities that satisfy our filtering criteria.
|
||||
Logger::Error("No geometrical entities found");
|
||||
delete serializer;
|
||||
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
|
||||
write_log(!quiet);
|
||||
return EXIT_FAILURE;
|
||||
@@ -641,7 +655,6 @@ int main(int argc, char** argv)
|
||||
if (center_model) {
|
||||
if (site_local_placement || building_local_placement) {
|
||||
Logger::Error("Cannot use --center-model together with --{site,building}-local-placement");
|
||||
delete serializer;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -658,7 +671,6 @@ int main(int argc, char** argv)
|
||||
} else {
|
||||
if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) {
|
||||
std::cerr << "[Error] Invalid use of --model-offset\n";
|
||||
delete serializer;
|
||||
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
|
||||
print_options(serializer_options);
|
||||
return EXIT_FAILURE;
|
||||
@@ -732,7 +744,8 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
serializer->finalize();
|
||||
delete serializer;
|
||||
// Make sure the dtor is explicitly run here (e.g. output files are closed before renaming them).
|
||||
serializer.reset();
|
||||
|
||||
// Renaming might fail (e.g. maybe the existing file was open in a viewer application)
|
||||
// Do not remove the temp file as user can salvage the conversion result from it.
|
||||
|
||||
@@ -387,7 +387,18 @@ bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_l
|
||||
try {
|
||||
builder.Perform();
|
||||
shape = builder.SewedShape();
|
||||
valid_shell = BRepCheck_Analyzer(shape).IsValid() != 0 && count(shape, TopAbs_SHELL) > 0;
|
||||
|
||||
{
|
||||
BRepCheck_Analyzer ana(shape);
|
||||
if (!ana.IsValid()) {
|
||||
ShapeFix_Shape sfs(shape);
|
||||
sfs.Perform();
|
||||
shape = sfs.Shape();
|
||||
}
|
||||
}
|
||||
|
||||
BRepCheck_Analyzer ana(shape);
|
||||
valid_shell = ana.IsValid() != 0 && count(shape, TopAbs_SHELL) > 0;
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
|
||||
@@ -270,10 +270,15 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Message(Logger::LOG_ERROR, "No geometries found");
|
||||
return false;
|
||||
Logger::Message(Logger::LOG_ERROR, "No representations encountered in relevant contexts, using all");
|
||||
representations = ifc_file->instances_by_type<IfcSchema::IfcRepresentation>();
|
||||
}
|
||||
|
||||
if (representations->size() == 0) {
|
||||
Logger::Message(Logger::LOG_ERROR, "No representations encountered, aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
representation_iterator = representations->begin();
|
||||
ifcproducts.reset();
|
||||
|
||||
@@ -402,19 +407,30 @@ namespace IfcGeom {
|
||||
for (;;) {
|
||||
IfcSchema::IfcRepresentation* representation;
|
||||
|
||||
// Have we reached the end of our list of representations?
|
||||
if ( representation_iterator == representations->end() ) {
|
||||
representations.reset();
|
||||
return 0;
|
||||
return 0; // reached the end of our list of representations
|
||||
}
|
||||
representation = *representation_iterator;
|
||||
|
||||
// Has the list of IfcProducts for this representation been initialized?
|
||||
if (!ifcproducts) {
|
||||
// Init. the list of filtered IfcProducts for this representation
|
||||
ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list);
|
||||
IfcSchema::IfcProduct::list::ptr unfiltered_products = kernel.products_represented_by(representation);
|
||||
// Include only the desired products for processing.
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters_, filter_match(prod))) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
|
||||
geometry_reuse_ok_for_current_representation_ = reuse_ok_(unfiltered_products);
|
||||
if (ifcproducts->size() == 0) {
|
||||
_nextShape();
|
||||
continue;
|
||||
}
|
||||
|
||||
geometry_reuse_ok_for_current_representation_ = reuse_ok_(ifcproducts);
|
||||
|
||||
IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
|
||||
|
||||
@@ -432,13 +448,12 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this represenation has (or will be) processed as part its mapped representation
|
||||
bool representation_processed_as_mapped_item = false;
|
||||
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = kernel.representation_mapped_to(representation);
|
||||
IfcSchema::IfcRepresentation* representation_mapped_to = kernel.representation_mapped_to(representation);
|
||||
if (representation_mapped_to) {
|
||||
// Check if this representation has (or will be) processed as part its mapped representation
|
||||
representation_processed_as_mapped_item = ok_mapped_representations->contains(representation_mapped_to) ||
|
||||
reuse_ok_(kernel.products_represented_by(representation_mapped_to));
|
||||
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ ||
|
||||
ok_mapped_representations->contains(representation_mapped_to);
|
||||
}
|
||||
|
||||
if (representation_processed_as_mapped_item) {
|
||||
@@ -447,14 +462,6 @@ namespace IfcGeom {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter the products based on the set of entities and/or names being included or excluded for processing.
|
||||
for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) {
|
||||
IfcSchema::IfcProduct* prod = *jt;
|
||||
if (boost::all(filters_, filter_match(prod))) {
|
||||
ifcproducts->push(prod);
|
||||
}
|
||||
}
|
||||
|
||||
ifcproduct_iterator = ifcproducts->begin();
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,8 @@ namespace IfcGeom {
|
||||
boost::optional<double>& Specularity() { return specularity; }
|
||||
};
|
||||
|
||||
IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type);
|
||||
IFC_GEOM_API void set_default_style_file(const std::string& json_file);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
static std::map<std::string, IfcGeom::SurfaceStyle> default_materials;
|
||||
static IfcGeom::SurfaceStyle default_material;
|
||||
static bool default_materials_initialized = false;
|
||||
@@ -44,12 +49,72 @@ void InitDefaultMaterials() {
|
||||
default_materials_initialized = true;
|
||||
}
|
||||
|
||||
boost::optional<IfcGeom::SurfaceStyle::ColorComponent> read_colour_component(const boost::optional<pt::ptree&> list) {
|
||||
if (!list) {
|
||||
return boost::none;
|
||||
}
|
||||
double rgb[3];
|
||||
int i = 0;
|
||||
for (pt::ptree::value_type &colour : list.get()) {
|
||||
if (3 <= i) {
|
||||
throw std::runtime_error("rgb array over 3 elements large");
|
||||
}
|
||||
rgb[i] = colour.second.get_value<double>();
|
||||
i++;
|
||||
}
|
||||
if (i != 3) {
|
||||
throw std::runtime_error("rgb array less than 3 elements large (was " + std::to_string(i) + ")");
|
||||
}
|
||||
return IfcGeom::SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
void IfcGeom::set_default_style_file(const std::string& json_file) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
default_materials.clear();
|
||||
|
||||
pt::ptree root;
|
||||
pt::read_json(json_file, root);
|
||||
|
||||
for (pt::ptree::value_type &material_pair : root) {
|
||||
std::string name = material_pair.first;
|
||||
default_materials.insert(std::make_pair(name, IfcGeom::SurfaceStyle(name)));
|
||||
|
||||
pt::ptree material = material_pair.second;
|
||||
boost::optional<pt::ptree&> diffuse = material.get_child_optional("diffuse");
|
||||
default_materials[name].Diffuse() = read_colour_component(diffuse);
|
||||
|
||||
boost::optional<pt::ptree&> specular = material.get_child_optional("specular");
|
||||
default_materials[name].Specular() = read_colour_component(specular);
|
||||
|
||||
if (material.get_child_optional("specular-roughness")) {
|
||||
default_materials[name].Specularity().reset(1.0 / material.get<double>("specular-roughness"));
|
||||
}
|
||||
if (material.get_child_optional("transparency")) {
|
||||
default_materials[name].Transparency() = material.get<double>("transparency");
|
||||
}
|
||||
}
|
||||
|
||||
// Is "*" present? If yes, remove it and make it the default style.
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find("*");
|
||||
if (it != default_materials.end()) {
|
||||
IfcGeom::SurfaceStyle star = it->second;
|
||||
default_material.Diffuse() = star.Diffuse();
|
||||
default_material.Specular() = star.Specular();
|
||||
default_material.Specularity() = star.Specularity();
|
||||
default_material.Transparency() = star.Transparency();
|
||||
default_materials.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) {
|
||||
if (!default_materials_initialized) InitDefaultMaterials();
|
||||
std::map<std::string, IfcGeom::SurfaceStyle>::const_iterator it = default_materials.find(s);
|
||||
if (it == default_materials.end()) {
|
||||
default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s)));
|
||||
default_materials[s].Diffuse().reset(*default_material.Diffuse());
|
||||
default_materials[s].Diffuse() = default_material.Diffuse();
|
||||
default_materials[s].Specular() = default_material.Specular();
|
||||
default_materials[s].Specularity() = default_material.Specularity();
|
||||
default_materials[s].Transparency() = default_material.Transparency();
|
||||
it = default_materials.find(s);
|
||||
}
|
||||
const IfcGeom::SurfaceStyle& surface_style = it->second;
|
||||
|
||||
@@ -1320,8 +1320,6 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
||||
return;
|
||||
}
|
||||
|
||||
good_ = true;
|
||||
|
||||
tokens = new IfcSpfLexer(stream, this);
|
||||
_header.file(this);
|
||||
_header.tryRead();
|
||||
@@ -1339,18 +1337,16 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
||||
} catch (const IfcParse::IfcException& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
|
||||
if (schema_ == 0 && schemas.front().substr(0, 4) == "IFC2") {
|
||||
Logger::Message(Logger::LOG_ERROR, schemas.front() + " not supported, using IFC2X3 instead");
|
||||
schema_ = IfcParse::schema_by_name("IFC2X3");
|
||||
}
|
||||
}
|
||||
|
||||
if (schema_ == 0) {
|
||||
schema_ = IfcParse::schema_by_name("IFC4");
|
||||
Logger::Message(Logger::LOG_ERROR, "Unable to deduce schema version from header identifiers, defaulting to IFC4");
|
||||
Logger::Message(Logger::LOG_ERROR, "No support for file schema encountered ("
|
||||
+ boost::algorithm::join(schemas, ", ") + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
good_ = true;
|
||||
|
||||
ifcroot_type_ = schema_->declaration_by_name("IfcRoot");
|
||||
|
||||
boost::circular_buffer<Token> token_stream(3, Token());
|
||||
|
||||
Reference in New Issue
Block a user