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:
Thomas Krijnen
2018-10-30 14:32:28 +01:00
8 changed files with 149 additions and 51 deletions
+4
View File
@@ -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
View File
@@ -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
+32 -19
View File
@@ -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.
+12 -1
View File
@@ -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());
+26 -19
View File
@@ -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
+66 -1
View File
@@ -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;
+5 -9
View File
@@ -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());