This commit is contained in:
Sander Boer
2019-04-26 11:22:36 +02:00
35 changed files with 1592 additions and 681 deletions
+1
View File
@@ -1,3 +1,4 @@
[submodule "test/input"]
path = test/input
url = https://github.com/IfcOpenShell/files
ignore = dirty
+3 -1
View File
@@ -413,9 +413,11 @@ IF(MSVC)
ENDIF()
ENDFOREACH()
ElSE()
add_definitions(-Wall -Wextra -Wno-maybe-uninitialized)
add_definitions(-Wall -Wextra)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_definitions(-Wno-tautological-constant-out-of-range-compare)
else()
add_definitions(-Wno-maybe-uninitialized)
endif()
# -fPIC is not relevant on Windows and creates pointless warnings
if (UNIX)
+1 -1
View File
@@ -61,7 +61,7 @@ PROJECT_NAME="IfcOpenShell"
OCE_VERSION="0.18"
# OCCT_VERSION="7.1.0"
# OCCT_HASH="89aebde"
PYTHON_VERSIONS=["2.7.12", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2"]
PYTHON_VERSIONS=["2.7.16", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2"]
# OCCT_VERSION="7.2.0"
# OCCT_HASH="88af392"
OCCT_VERSION="7.3.0"
+130 -94
View File
@@ -27,42 +27,46 @@
bl_info = {
"name": "IfcBlender",
"description": "Import files in the "\
"description": "Import files in the "
"Industry Foundation Classes (.ifc) file format",
"author": "Thomas Krijnen, IfcOpenShell",
"blender": (2, 73, 0),
"blender": (2, 80, 0),
"location": "File > Import",
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"
"_list/tickets?source=navbar",
"category": "Import-Export"}
if "bpy" in locals():
import imp
import importlib
if "ifcopenshell" in locals():
imp.reload(ifcopenshell)
importlib.reload(ifcopenshell)
import bpy
import mathutils
from bpy.props import StringProperty, IntProperty, BoolProperty
from bpy_extras.io_utils import ImportHelper
major,minor = bpy.app.version[0:2]
major, minor = bpy.app.version[0:2]
transpose_matrices = minor >= 62
bpy.types.Object.ifc_id = IntProperty(name="IFC Entity ID",
bpy.types.Object.ifc_id = IntProperty(
name="IFC Entity ID",
description="The STEP entity instance name")
bpy.types.Object.ifc_guid = StringProperty(name="IFC Entity GUID",
bpy.types.Object.ifc_guid = StringProperty(
name="IFC Entity GUID",
description="The IFC Globally Unique Identifier")
bpy.types.Object.ifc_name = StringProperty(name="IFC Entity Name",
bpy.types.Object.ifc_name = StringProperty(
name="IFC Entity Name",
description="The optional name attribute")
bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type",
bpy.types.Object.ifc_type = StringProperty(
name="IFC Entity Type",
description="The STEP Datatype keyword")
def import_ifc(filename, use_names, process_relations, blender_booleans):
from . import ifcopenshell
from .ifcopenshell import geom as ifcopenshell_geom
print("Reading %s..."%bpy.path.basename(filename))
print(f"Reading {bpy.path.basename(filename)}...")
settings = ifcopenshell_geom.settings()
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
iterator = ifcopenshell_geom.iterator(settings, filename)
@@ -76,9 +80,14 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
openings = []
old_progress = -1
print("Creating geometry...")
collection = bpy.data.collections.new(f"{bpy.path.basename(filename)}")
bpy.context.scene.collection.children.link(collection)
if process_relations:
rel_collection = bpy.data.collections.new("Relations")
collection.children.link(rel_collection)
while True:
ob = iterator.get()
f = ob.geometry.faces
v = ob.geometry.verts
mats = ob.geometry.materials
@@ -86,54 +95,75 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
m = ob.transformation.matrix.data
t = ob.type[0:21]
nm = ob.name if len(ob.name) and use_names else ob.guid
verts = [[v[i], v[i + 1], v[i + 2]] \
for i in range(0, len(v), 3)]
faces = [[f[i], f[i + 1], f[i + 2]] \
for i in range(0, len(f), 3)]
# MESH CREATION
# Depending on version, geometry.id will be either int or str
me = bpy.data.meshes.new('mesh-%r' % ob.geometry.id)
me.from_pydata(verts, [], faces)
me.validate()
def add_material(mname, props):
if mname in bpy.data.materials:
mat = bpy.data.materials[mname]
mat.use_fake_user = True
else:
mat = bpy.data.materials.new(mname)
for k,v in props.items():
setattr(mat, k, v)
me.materials.append(mat)
needs_default = -1 in matids
if needs_default: add_material(t, {})
for mat in mats:
props = {}
if mat.has_diffuse: props['diffuse_color'] = mat.diffuse
if mat.has_specular: props['specular_color'] = mat.specular
if mat.has_transparency and mat.transparency > 0:
props['alpha'] = 1.0 - mat.transparency
props['use_transparency'] = True
if mat.has_specularity: props['specular_hardness'] = mat.specularity
add_material(mat.name, props)
mesh_name = 'mesh-%r' % ob.geometry.id
if mesh_name in bpy.data.meshes:
me = bpy.data.meshes[mesh_name]
else:
verts = [[v[i], v[i + 1], v[i + 2]]
for i in range(0, len(v), 3)]
faces = [[f[i], f[i + 1], f[i + 2]]
for i in range(0, len(f), 3)]
me = bpy.data.meshes.new(mesh_name)
me.from_pydata(verts, [], faces)
me.validate()
# MATERIAL CREATION
def add_material(mname, props):
if mname in bpy.data.materials:
mat = bpy.data.materials[mname]
mat.use_fake_user = True
else:
mat = bpy.data.materials.new(mname)
for k, v in props.items():
if k == 'transparency':
mat.blend_method = 'HASHED'
mat.use_screen_refraction = True
mat.refraction_depth = 0.1
mat.use_nodes = True
mat.node_tree.nodes["Principled BSDF"].inputs[15].default_value = v
else:
setattr(mat, k, v)
me.materials.append(mat)
needs_default = -1 in matids
if needs_default:
add_material(t, {})
for mat in mats:
props = {}
if mat.has_diffuse:
props['diffuse_color'] = mat.diffuse
if mat.has_specular:
props['specular_color'] = mat.specular
if mat.has_transparency and mat.transparency > 0:
props['transparency'] = mat.transparency
if mat.has_specularity:
props['specular_intensity'] = mat.specularity
add_material(mat.name, props)
faces = me.polygons if hasattr(me, 'polygons') else me.faces
if len(faces) == len(matids):
for face, matid in zip(faces, matids):
face.material_index = matid + (1 if needs_default else 0)
# OBJECT CREATION
bob = bpy.data.objects.new(nm, me)
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
if transpose_matrices: mat.transpose()
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
if transpose_matrices:
mat.transpose()
if process_relations:
id_to_matrix[ob.id] = mat
else:
bob.matrix_world = mat
bpy.context.scene.objects.link(bob)
collection.objects.link(bob)
bpy.context.scene.objects.active = bob
bpy.context.view_layer.objects.active = bob
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.normals_make_consistent()
bpy.ops.object.mode_set(mode='OBJECT')
@@ -143,23 +173,19 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
if ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement':
if not (ob.type == 'IfcOpeningElement' and blender_booleans):
bob.hide = bob.hide_render = True
bob.draw_type = 'WIRE'
if ob.id not in id_to_object: id_to_object[ob.id] = []
bob.hide_viewport = bob.hide_render = True
bob.display_type = 'WIRE'
if ob.id not in id_to_object:
id_to_object[ob.id] = []
id_to_object[ob.id].append(bob)
if ob.parent_id > 0:
id_to_parent[ob.id] = ob.parent_id
if blender_booleans and ob.type == 'IfcOpeningElement':
openings.append(ob.id)
faces = me.polygons if hasattr(me, 'polygons') else me.faces
if len(faces) == len(matids):
for face, matid in zip(faces, matids):
face.material_index = matid + (1 if needs_default else 0)
progress = iterator.progress() // 2
if progress > old_progress:
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
@@ -170,13 +196,13 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
print("\rDone creating geometry" + " " * 30)
id_to_parent_temp = dict(id_to_parent)
if process_relations:
print("Processing relations...")
while len(id_to_parent_temp) and process_relations:
id, parent_id = id_to_parent_temp.popitem()
if parent_id in id_to_object:
bob = id_to_object[parent_id][0]
else:
@@ -188,16 +214,17 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
nm = parent_ob.name if len(parent_ob.name) and use_names \
else parent_ob.guid
bob = bpy.data.objects.new(nm, None)
mat = mathutils.Matrix((
[m[0], m[1], m[2], 0],
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
if transpose_matrices: mat.transpose()
if transpose_matrices:
mat.transpose()
id_to_matrix[parent_ob.id] = mat
bpy.context.scene.objects.link(bob)
rel_collection.objects.link(bob)
bob.ifc_id = parent_ob.id
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
@@ -220,13 +247,13 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
parent_matrix = id_to_matrix.get(parent_id, None)
for ob in id_to_object[id]:
if parent_matrix:
ob.matrix_local = parent_matrix.inverted() * matrix
ob.matrix_local = parent_matrix.inverted() @ matrix
else:
ob.matrix_world = matrix
if process_relations:
print("Done processing relations")
for opening_id in openings:
parent_id = id_to_parent[opening_id]
if parent_id in id_to_object:
@@ -235,8 +262,8 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
mod = parent_ob.modifiers.new("opening", "BOOLEAN")
mod.operation = "DIFFERENCE"
mod.object = opening_ob
txt = bpy.data.texts.new("%s.log"%bpy.path.basename(filename))
txt = bpy.data.texts.new(f"{bpy.path.basename(filename)}.log")
txt.from_string(iterator.getLog())
return True
@@ -247,42 +274,51 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
bl_label = "Import .ifc file"
filename_ext = ".ifc"
filter_glob = StringProperty(default="*.ifc", options={'HIDDEN'})
filter_glob: StringProperty(default="*.ifc", options={'HIDDEN'})
use_names = BoolProperty(name="Use entity names",
description="Use entity names rather than GlobalIds for objects",
default=True)
process_relations = BoolProperty(name="Process relations",
description="Convert containment and aggregation" \
" relations to parenting" \
" (warning: may be slow on large files)",
default=False)
blender_booleans = BoolProperty(name="Use Blender booleans",
description="Use Blender boolean modifiers for opening" \
" elements",
default=False)
use_names: BoolProperty(name="Use entity names",
description="Use entity names rather than "
"GlobalIds for objects",
default=True)
process_relations: BoolProperty(name="Process relations",
description="Convert containment and "
"aggregation relations to parenting"
" (warning: may be slow on large files)",
default=False)
blender_booleans: BoolProperty(name="Use Blender booleans",
description="Use Blender boolean modifiers "
"for opening elements",
default=False)
def execute(self, context):
if not import_ifc(self.filepath, self.use_names, self.process_relations, self.blender_booleans):
if not import_ifc(self.filepath, self.use_names,
self.process_relations, self.blender_booleans):
self.report({'ERROR'},
'Unable to parse .ifc file or no geometrical entities found'
)
'Unable to parse .ifc file or no geometrical entities found'
)
return {'FINISHED'}
def menu_func_import(self, context):
self.layout.operator(ImportIFC.bl_idname,
text="Industry Foundation Classes (.ifc)")
text="Industry Foundation Classes (.ifc)")
classes = (
ImportIFC,
)
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_import.append(menu_func_import)
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_import.remove(menu_func_import)
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
if __name__ == "__main__":
+2
View File
@@ -32,6 +32,8 @@
#include <string>
#include <cmath>
#include "../ifcparse/utils.h"
using namespace IfcSchema;
static std::string& collada_id(std::string& s)
+1 -1
View File
@@ -198,7 +198,7 @@ private:
ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer,
bool double_precision)
: filename(fn)
, stream(filename, double_precision)
, stream(COLLADASW::NativeString(filename.c_str(), COLLADASW::NativeString::ENCODING_UTF8), double_precision)
, scene(scene_name, stream, _serializer)
, materials(stream, _serializer)
, geometries(stream, _serializer)
+258 -194
View File
@@ -36,6 +36,8 @@
#include "../ifcgeom/IfcGeomIterator.h"
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "../ifcparse/utils.h"
#include <IGESControl_Controller.hxx>
#include <Standard_Version.hxx>
@@ -51,6 +53,23 @@
#include <vld.h>
#endif
#ifdef _MSC_VER
#include <io.h>
#include <fcntl.h>
// C++11 header:
#include <random>
#endif
#if defined(_MSC_VER) && defined(_UNICODE)
typedef std::wstring path_t;
static std::wostream& cout_ = std::wcout;
static std::wostream& cerr_ = std::wcerr;
#else
typedef std::string path_t;
static std::ostream& cout_ = std::cout;
static std::ostream& cerr_ = std::cerr;
#endif
const std::string DEFAULT_EXTENSION = "obj";
const std::string TEMP_FILE_EXTENSION = ".tmp";
@@ -58,12 +77,12 @@ namespace po = boost::program_options;
void print_version()
{
std::cout << "IfcOpenShell " << IfcSchema::Identifier << " IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n";
cout_ << "IfcOpenShell " << IfcSchema::Identifier << " IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n";
}
void print_usage(bool suggest_help = true)
{
std::cout << "Usage: IfcConvert [options] <input.ifc> [<output>]\n"
cout_ << "Usage: IfcConvert [options] <input.ifc> [<output>]\n"
<< "\n"
<< "Converts the geometry in an IFC file into one of the following formats:\n"
<< " .obj WaveFront OBJ (a .mtl file is also created)\n"
@@ -75,47 +94,45 @@ void print_usage(bool suggest_help = true)
<< " .xml XML Property definitions and decomposition tree\n"
<< " .svg SVG Scalable Vector Graphics (2D floor plan)\n"
<< "\n"
<< "If no output filename given, <input>." + DEFAULT_EXTENSION + " will be used as the output file.\n";
<< "If no output filename given, <input>." << IfcUtil::path::from_utf8(DEFAULT_EXTENSION) << " will be used as the output file.\n";
if (suggest_help) {
std::cout << "\nRun 'IfcConvert --help' for more information.";
cout_ << "\nRun 'IfcConvert --help' for more information.";
}
std::cout << std::endl;
cout_ << std::endl;
}
/// @todo Add help for single option
void print_options(const po::options_description& options)
{
std::cout << "\n" << options;
std::cout << std::endl;
#if defined(_MSC_VER) && defined(_UNICODE)
// See issue https://svn.boost.org/trac10/ticket/10952
std::ostringstream temp;
temp << options;
cout_ << "\n" << temp.str().c_str();
#else
cout_ << "\n" << options;
#endif
cout_ << std::endl;
}
std::string change_extension(const std::string& fn, const std::string& ext) {
std::string::size_type dot = fn.find_last_of('.');
if (dot != std::string::npos) {
return fn.substr(0,dot+1) + ext;
template <typename T>
T change_extension(const T& fn, const T& ext) {
typename T::size_type dot = fn.find_last_of('.');
if (dot != T::npos) {
return fn.substr(0, dot) + ext;
} else {
return fn + "." + ext;
return fn + ext;
}
}
bool file_exists(const std::string& filename)
{
/// @todo Windows Unicode support
std::ifstream file(filename.c_str());
bool file_exists(const std::string& filename) {
std::ifstream file(IfcUtil::path::from_utf8(filename).c_str());
return file.good();
}
bool rename_file(const std::string& old_filename, const std::string& new_filename)
{
// Whether or not rename() replaces an existing file is implementation-specific,
// so remove() possible existing file always.
/// @todo Windows Unicode support
std::remove(new_filename.c_str());
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
}
static std::stringstream log_stream;
static std::basic_stringstream<path_t::value_type> log_stream;
void write_log(bool);
std::string format_duration(time_t start, time_t end);
/// @todo make the filters non-global
IfcGeom::entity_filter entity_filter; // Entity filter is used always by default.
@@ -152,9 +169,28 @@ std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>&, co
bool init_input_file(const std::string& filename, IfcParse::IfcFile& ifc_file, bool no_progress, bool mmap);
int main(int argc, char** argv)
{
#if defined(_MSC_VER) && defined(_UNICODE)
int wmain(int argc, wchar_t** argv) {
typedef po::wcommand_line_parser command_line_parser;
typedef wchar_t char_t;
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stderr), _O_U16TEXT);
#else
int main(int argc, char** argv) {
typedef po::command_line_parser command_line_parser;
typedef char char_t;
#endif
double deflection_tolerance;
inclusion_filter include_filter;
inclusion_traverse_filter include_traverse_filter;
exclusion_filter exclude_filter;
exclusion_traverse_filter exclude_traverse_filter;
path_t filter_filename;
path_t default_material_filename;
std::string log_format;
po::options_description generic_options("Command line options");
generic_options.add_options()
("help,h", "display usage information")
@@ -171,17 +207,8 @@ int main(int argc, char** argv)
#ifdef USE_MMAP
("mmap", "use memory-mapped file for input")
#endif
("input-file", po::value<std::string>(), "input IFC file")
("output-file", po::value<std::string>(), "output geometry file");
double deflection_tolerance;
inclusion_filter include_filter;
inclusion_traverse_filter include_traverse_filter;
exclusion_filter exclude_filter;
exclusion_traverse_filter exclude_traverse_filter;
std::string filter_filename;
std::string default_material_filename;
("input-file", new po::typed_value<path_t, char_t>(0), "input IFC file")
("output-file", new po::typed_value<path_t, char_t>(0), "output geometry file");
po::options_description geom_options("Geometry options");
geom_options.add_options()
@@ -258,12 +285,12 @@ int main(int argc, char** argv)
("generate-uvs",
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
"Not guaranteed to work properly if used with --weld-vertices.")
("filter-file", po::value<std::string>(&filter_filename),
("filter-file", new po::typed_value<path_t, char_t>(&filter_filename),
"Specifies a filter file that describes the used filtering criteria. Supported formats "
"are '--include=arg GlobalId ...' and 'include arg GlobalId ...'. Spaces and tabs can be used as delimiters."
"Multiple filters of same type with different values can be inserted on their own lines. "
"See --include, --include+, --exclude, and --exclude+ for more details.")
("default-material-file", po::value<std::string>(&default_material_filename),
("default-material-file", new po::typed_value<path_t, char_t>(&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.");
@@ -326,21 +353,21 @@ int main(int argc, char** argv)
po::variables_map vmap;
try {
po::store(po::command_line_parser(argc, argv).
po::store(command_line_parser(argc, argv).
options(cmdline_options).positional(positional_options).run(), vmap);
} catch (const po::unknown_option& e) {
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'\n\n";
cerr_ << "[Error] Unknown option '" << e.get_option_name().c_str() << "'\n\n";
print_usage();
return EXIT_FAILURE;
} catch (const po::error_with_option_name& e) {
std::cerr << "[Error] Invalid usage of '" << e.get_option_name() << "': " << e.what() << "\n\n";
cerr_ << "[Error] Invalid usage of '" << e.get_option_name().c_str() << "': " << e.what() << "\n\n";
return EXIT_FAILURE;
} catch (const std::exception& e) {
std::cerr << "[Error] " << e.what() << "\n\n";
cerr_ << "[Error] " << e.what() << "\n\n";
print_usage();
return EXIT_FAILURE;
} catch (...) {
std::cerr << "[Error] Unknown error parsing command line options\n\n";
cerr_ << "[Error] Unknown error parsing command line options\n\n";
print_usage();
return EXIT_FAILURE;
}
@@ -375,11 +402,11 @@ int main(int argc, char** argv)
const bool building_local_placement = vmap.count("building-local-placement") != 0;
const bool generate_uvs = vmap.count("generate-uvs") != 0;
if (!quiet || vmap.count("version")) {
if (!quiet || vmap.count("version")) {
print_version();
}
if (vmap.count("version")) {
if (vmap.count("version")) {
return EXIT_SUCCESS;
} else if (vmap.count("help")) {
print_usage(false);
@@ -390,70 +417,7 @@ int main(int argc, char** argv)
print_usage();
return EXIT_FAILURE;
}
#ifdef HAVE_ICU
if (!unicode_mode.empty()) {
if (unicode_mode == "utf8") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::UTF8;
} else if (unicode_mode == "escape") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::JSON;
} else {
std::cerr << "[Error] Invalid value for --unicode" << std::endl;
print_options(serializer_options);
return 1;
}
}
#endif
boost::optional<double> bounding_width;
boost::optional<double> bounding_height;
if (vmap.count("bounds") == 1) {
int w, h;
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2 && w > 0 && h > 0) {
bounding_width = w;
bounding_height = h;
} else {
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
print_options(serializer_options);
return EXIT_FAILURE;
}
}
const std::string input_filename = vmap["input-file"].as<std::string>();
if (!file_exists(input_filename)) {
std::cerr << "[Error] Input file '" << input_filename << "' does not exist" << std::endl;
return EXIT_FAILURE;
}
// If no output filename is specified a Wavefront OBJ file will be output
// to maintain backwards compatibility with the obsolete IfcObj executable.
const std::string output_filename = vmap.count("output-file") == 1
? vmap["output-file"].as<std::string>()
: change_extension(input_filename, DEFAULT_EXTENSION);
if (output_filename.size() < 5) {
std::cerr << "[Error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
print_usage();
return EXIT_FAILURE;
}
if (file_exists(output_filename) && !vmap.count("yes")) {
std::string answer;
std::cout << "A file '" << output_filename << "' already exists. Overwrite the existing file?" << std::endl;
std::cin >> answer;
if (!boost::iequals(answer, "yes") && !boost::iequals(answer, "y")) {
return EXIT_SUCCESS;
}
}
std::string output_temp_filename = output_filename + TEMP_FILE_EXTENSION;
std::string output_extension = output_filename.substr(output_filename.size()-4);
boost::to_lower(output_extension);
Logger::SetOutput(&std::cout, &log_stream);
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
if (vmap.count("log-format") == 1) {
boost::to_lower(log_format);
if (log_format == "plain") {
@@ -466,19 +430,114 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
}
if (!filter_filename.empty()) {
size_t num_filters = read_filters_from_file(IfcUtil::path::to_utf8(filter_filename), include_filter, include_traverse_filter, exclude_filter, exclude_traverse_filter);
if (num_filters) {
Logger::Notice(boost::lexical_cast<std::string>(num_filters) + " filters read from specifified file.");
} else {
std::cerr << "[Error] No filters read from specifified file.\n";
return EXIT_FAILURE;
}
}
#ifdef HAVE_ICU
if (!unicode_mode.empty()) {
if (unicode_mode == "utf8") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::UTF8;
} else if (unicode_mode == "escape") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::JSON;
} else {
cerr_ << "[Error] Invalid value for --unicode" << std::endl;
print_options(serializer_options);
return 1;
}
}
#endif
if (!default_material_filename.empty()) {
try {
IfcGeom::set_default_style_file(IfcUtil::path::to_utf8(default_material_filename));
} catch (const std::exception& e) {
std::cerr << "[Error] Could not read default material file:" << std::endl;
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
}
boost::optional<double> bounding_width;
boost::optional<double> bounding_height;
if (vmap.count("bounds") == 1) {
int w, h;
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2 && w > 0 && h > 0) {
bounding_width = w;
bounding_height = h;
} else {
cerr_ << "[Error] Invalid use of --bounds" << std::endl;
print_options(serializer_options);
return EXIT_FAILURE;
}
}
const path_t input_filename = vmap["input-file"].as<path_t>();
if (!file_exists(IfcUtil::path::to_utf8(input_filename))) {
cerr_ << "[Error] Input file '" << input_filename << "' does not exist" << std::endl;
return EXIT_FAILURE;
}
// If no output filename is specified a Wavefront OBJ file will be output
// to maintain backwards compatibility with the obsolete IfcObj executable.
const path_t output_filename = vmap.count("output-file") == 1
? vmap["output-file"].as<path_t>()
: change_extension(input_filename, IfcUtil::path::from_utf8(DEFAULT_EXTENSION));
if (output_filename.size() < 5) {
cerr_ << "[Error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
print_usage();
return EXIT_FAILURE;
}
if (file_exists(IfcUtil::path::to_utf8(output_filename)) && !vmap.count("yes")) {
std::string answer;
cout_ << "A file '" << output_filename << "' already exists. Overwrite the existing file?" << std::endl;
std::cin >> answer;
if (!boost::iequals(answer, "yes") && !boost::iequals(answer, "y")) {
return EXIT_SUCCESS;
}
}
Logger::SetOutput(&cout_, &log_stream);
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
path_t output_temp_filename = output_filename + IfcUtil::path::from_utf8(TEMP_FILE_EXTENSION);
path_t output_extension = output_filename.substr(output_filename.size()-4);
boost::to_lower(output_extension);
IfcParse::IfcFile ifc_file;
if (output_extension == ".xml") {
const path_t OBJ = IfcUtil::path::from_utf8(".obj"),
MTL = IfcUtil::path::from_utf8(".mtl"),
DAE = IfcUtil::path::from_utf8(".dae"),
STP = IfcUtil::path::from_utf8(".stp"),
IGS = IfcUtil::path::from_utf8(".igs"),
SVG = IfcUtil::path::from_utf8(".svg"),
XML = IfcUtil::path::from_utf8(".xml");
if (output_extension == XML) {
int exit_code = EXIT_FAILURE;
try {
if (init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
XmlSerializer s(output_temp_filename);
if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) {
time_t start, end;
time(&start);
XmlSerializer s(IfcUtil::path::to_utf8(output_temp_filename));
s.setFile(&ifc_file);
Logger::Status("Writing XML output...");
s.finalize();
Logger::Status("Done!");
rename_file(output_temp_filename, output_filename);
time(&end);
Logger::Status("Done! Conversion took " + format_duration(start, end));
IfcUtil::path::rename_file(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(output_filename));
exit_code = EXIT_SUCCESS;
}
} catch (const std::exception& e) {
@@ -488,26 +547,6 @@ int main(int argc, char** argv)
return exit_code;
}
if (!filter_filename.empty()) {
size_t num_filters = read_filters_from_file(filter_filename, include_filter, include_traverse_filter, exclude_filter, exclude_traverse_filter);
if (num_filters) {
Logger::Notice(boost::lexical_cast<std::string>(num_filters) + " filters read from '" + filter_filename + "'.");
} else {
std::cerr << "[Error] No filters read from '" + filter_filename + "'.\n";
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); }
@@ -515,9 +554,9 @@ int main(int argc, char** argv)
if (exclude_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_filter); }
if (exclude_traverse_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_traverse_filter); }
std::vector<IfcGeom::filter_t> filter_funcs = setup_filters(used_filters, output_extension);
std::vector<IfcGeom::filter_t> filter_funcs = setup_filters(used_filters, IfcUtil::path::to_utf8(output_extension));
if (filter_funcs.empty()) {
std::cerr << "[Error] Failed to set up geometry filters\n";
cerr_ << "[Error] Failed to set up geometry filters\n";
return EXIT_FAILURE;
}
@@ -528,6 +567,20 @@ int main(int argc, char** argv)
if (!desc_filter.values.empty()) { desc_filter.update_description(); Logger::Notice(desc_filter.description); }
if (!tag_filter.values.empty()) { tag_filter.update_description(); Logger::Notice(tag_filter.description); }
#ifdef _MSC_VER
if (output_extension == DAE || output_extension == STP || output_extension == IGS) {
// These serializers do not support opening unicode paths on Windows. Therefore
// a random temp file is generated using only ASCII characters instead.
std::random_device rng;
std::uniform_int_distribution<int> index_dist(L'A', L'Z');
output_temp_filename = L".ifcopenshell.";
for (int i = 0; i < 8; ++i) {
output_temp_filename.push_back(static_cast<wchar_t>(index_dist(rng)));
}
output_temp_filename += L".tmp";
}
#endif
SerializerSettings settings;
/// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn.
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
@@ -558,26 +611,26 @@ int main(int argc, char** argv)
settings.precision = precision;
boost::shared_ptr<GeometrySerializer> serializer; /**< @todo use std::unique_ptr when possible */
if (output_extension == ".obj") {
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");
const path_t mtl_filename = change_extension(output_filename, MTL);
if (!use_world_coords) {
Logger::Notice("Using world coords when writing WaveFront OBJ files");
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
}
serializer = boost::make_shared<WaveFrontOBJSerializer>(output_temp_filename, mtl_filename, settings);
serializer = boost::make_shared<WaveFrontOBJSerializer>(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(mtl_filename), settings);
#ifdef WITH_OPENCOLLADA
} else if (output_extension == ".dae") {
serializer = boost::make_shared<ColladaSerializer>(output_temp_filename, settings);
} else if (output_extension == DAE) {
serializer = boost::make_shared<ColladaSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
#endif
} else if (output_extension == ".stp") {
serializer = boost::make_shared<StepSerializer>(output_temp_filename, settings);
} else if (output_extension == ".igs") {
} else if (output_extension == STP) {
serializer = boost::make_shared<StepSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
} else if (output_extension == IGS) {
IGESControl_Controller::Init(); // work around Open Cascade bug
serializer = boost::make_shared<IgesSerializer>(output_temp_filename, settings);
} else if (output_extension == ".svg") {
serializer = boost::make_shared<IgesSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
} else if (output_extension == SVG) {
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
serializer = boost::make_shared<SvgSerializer>(output_temp_filename, settings);
serializer = boost::make_shared<SvgSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
if (vmap.count("section-height") != 0) {
Logger::Notice("Overriding section height");
static_cast<SvgSerializer*>(serializer.get())->setSectionHeight(section_height);
@@ -586,18 +639,18 @@ int main(int argc, char** argv)
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
}
} else {
std::cerr << "[Error] Unknown output filename extension '" + output_extension + "'\n";
cerr_ << "[Error] Unknown output filename extension '" << output_extension << "'\n";
write_log(!quiet);
print_usage();
return EXIT_FAILURE;
}
if (use_element_hierarchy && output_extension != ".dae") {
std::cerr << "[Error] --use-element-hierarchy can be used only with .dae output.\n";
if (use_element_hierarchy && output_extension != DAE) {
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();
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
return EXIT_FAILURE;
}
@@ -617,7 +670,7 @@ int main(int argc, char** argv)
}
if (!serializer->ready()) {
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
write_log(!quiet);
return EXIT_FAILURE;
}
@@ -625,9 +678,9 @@ int main(int argc, char** argv)
time_t start,end;
time(&start);
if (!init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
if (!init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) {
write_log(!quiet);
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename)); /**< @todo Windows Unicode support */
return EXIT_FAILURE;
}
@@ -636,7 +689,7 @@ 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");
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
write_log(!quiet);
return EXIT_FAILURE;
}
@@ -671,8 +724,8 @@ int main(int argc, char** argv)
offset[2] = -center.Z();
} 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";
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
cerr_ << "[Error] Invalid use of --model-offset\n";
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
print_options(serializer_options);
return EXIT_FAILURE;
}
@@ -750,53 +803,61 @@ int main(int argc, char** argv)
// 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.
bool successful = rename_file(output_temp_filename, output_filename);
bool successful = IfcUtil::path::rename_file(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(output_filename));
if (!successful) {
Logger::Error("Unable to write output file '" + output_filename + "', see '" +
output_temp_filename + "' for the conversion result.");
cerr_ << "Unable to write output file '" << output_filename << "', see '" <<
output_temp_filename << "' for the conversion result.";
}
write_log(!quiet);
time(&end);
if (!quiet) {
int seconds = (int)difftime(end, start);
std::stringstream msg;
int minutes = seconds / 60;
seconds = seconds % 60;
msg << "\nConversion took";
if (minutes > 0) {
msg << " " << minutes << " minute";
if (minutes > 1) {
msg << "s";
}
}
msg << " " << seconds << " second";
if (seconds > 1) {
msg << "s";
}
Logger::Status(msg.str());
}
if (!quiet) {
Logger::Status("\nConversion took " + format_duration(start, end));
}
return successful ? EXIT_SUCCESS : EXIT_FAILURE;
}
std::string format_duration(time_t start, time_t end)
{
int seconds = (int)difftime(end, start);
std::stringstream ss;
int minutes = seconds / 60;
seconds = seconds % 60;
if (minutes > 0) {
ss << minutes << " minute";
if (minutes == 0 || minutes > 1) {
ss << "s";
}
ss << " ";
}
ss << seconds << " second";
if (seconds == 0 || seconds > 1) {
ss << "s";
}
return ss.str();
}
void write_log(bool header) {
std::string log = log_stream.str();
path_t log = log_stream.str();
if (!log.empty()) {
if (header) {
std::cout << "\nLog:\n";
}
std::cout << log << std::endl;
if (header) {
cout_ << "\nLog:\n";
}
cout_ << log << std::endl;
}
}
bool init_input_file(const std::string &filename, IfcParse::IfcFile &ifc_file, bool no_progress, bool mmap)
{
time_t start, end;
// Prevent IfcFile::Init() prints by setting output to null temporarily
if (no_progress) { Logger::SetOutput(NULL, &log_stream); }
time(&start);
#ifdef USE_MMAP
if (!ifc_file.Init(filename, mmap)) {
#else
@@ -806,8 +867,10 @@ bool init_input_file(const std::string &filename, IfcParse::IfcFile &ifc_file, b
Logger::Error("Unable to parse input file '" + filename + "'");
return false;
}
time(&end);
if (no_progress) { Logger::SetOutput(&std::cout, &log_stream); }
if (no_progress) { Logger::SetOutput(&cout_, &log_stream); }
else { Logger::Status("Parsing input file took " + format_duration(start, end)); }
return true;
}
@@ -818,7 +881,7 @@ bool append_filter(const std::string& type, const std::vector<std::string>& valu
parse_filter(temp, values);
// Merge values only if type and arg match.
if ((filter.type != geom_filter::UNUSED && filter.type != temp.type) || (!filter.arg.empty() && filter.arg != temp.arg)) {
std::cerr << "[Error] Multiple '" << type << "' filters specified with different criteria\n";
cerr_ << "[Error] Multiple '" << type.c_str() << "' filters specified with different criteria\n";
return false;
}
filter.type = temp.type;
@@ -834,9 +897,10 @@ size_t read_filters_from_file(
exclusion_filter& exclude_filter,
exclusion_traverse_filter& exclude_traverse_filter)
{
std::ifstream filter_file(filename.c_str());
std::ifstream filter_file(IfcUtil::path::from_utf8(filename).c_str());
if (!filter_file.is_open()) {
std::cerr << "[Error] Unable to open filter file '" + filename + "' or the file does not exist.\n";
cerr_ << "[Error] Unable to open filter file '" << IfcUtil::path::from_utf8(filename) << "' or the file does not exist.\n";
return 0;
}
@@ -871,11 +935,11 @@ size_t read_filters_from_file(
else if (type == "exclude") { if (append_filter("exclude", values, exclude_filter)) { ++num_filters; } }
else if (type == "exclude+") { if (append_filter("exclude+", values, exclude_traverse_filter)) { ++num_filters; } }
else {
std::cerr << "[Error] Invalid filtering type at line " + boost::lexical_cast<std::string>(line_number) + "\n";
cerr_ << "[Error] Invalid filtering type at line " << boost::lexical_cast<path_t>(line_number) << "\n";
return 0;
}
} catch(...) {
std::cerr << "[Error] Unable to parse filter at line " + boost::lexical_cast<std::string>(line_number) + ".\n";
cerr_ << "[Error] Unable to parse filter at line " << boost::lexical_cast<path_t>(line_number) << ".\n";
return 0;
}
}
@@ -950,7 +1014,7 @@ std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>& fil
try {
entity_filter.populate(f.values);
} catch (const IfcParse::IfcException& e) {
std::cerr << "[Error] " << e.what() << std::endl;
cerr_ << "[Error] " << e.what() << std::endl;
return std::vector<IfcGeom::filter_t>();
}
} else if (f.type == geom_filter::LAYER_NAME) {
@@ -990,7 +1054,7 @@ std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>& fil
}
entity_filter.populate(entities);
} catch (const IfcParse::IfcException& e) {
std::cerr << "[Error] " << e.what() << std::endl;
cerr_ << "[Error] " << e.what() << std::endl;
return std::vector<IfcGeom::filter_t>();
}
}
@@ -17,19 +17,21 @@
* *
********************************************************************************/
#include "OpenCascadeBasedSerializer.h"
#include "../ifcparse/utils.h"
#include <string>
#include <fstream>
#include <cstdio>
#include <Standard_Version.hxx>
#include "OpenCascadeBasedSerializer.h"
bool OpenCascadeBasedSerializer::ready() {
std::ofstream test_file(out_filename.c_str(), std::ios_base::binary);
std::ofstream test_file(IfcUtil::path::from_utf8(out_filename).c_str(), std::ios_base::binary);
bool succeeded = test_file.is_open();
test_file.close();
remove(out_filename.c_str());
IfcUtil::path::delete_file(out_filename);
return succeeded;
}
+3 -1
View File
@@ -25,6 +25,8 @@
#include "../ifcconvert/GeometrySerializer.h"
#include "../ifcconvert/util.h"
#include "../ifcparse/utils.h"
#include <sstream>
#include <string>
#include <limits>
@@ -46,7 +48,7 @@ protected:
public:
SvgSerializer(const std::string& out_filename, const SerializerSettings& settings)
: GeometrySerializer(settings)
, svg_file(out_filename.c_str())
, svg_file(IfcUtil::path::from_utf8(out_filename).c_str())
, xmin(+std::numeric_limits<double>::infinity())
, ymin(+std::numeric_limits<double>::infinity())
, xmax(-std::numeric_limits<double>::infinity())
+13
View File
@@ -22,9 +22,22 @@
#include "../ifcgeom/IfcGeomRenderStyles.h"
#include "../ifcparse/utils.h"
#include <boost/lexical_cast.hpp>
#include <iomanip>
WaveFrontOBJSerializer::WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings)
: GeometrySerializer(settings)
, mtl_filename(mtl_filename)
, obj_stream(IfcUtil::path::from_utf8(obj_filename).c_str())
, mtl_stream(IfcUtil::path::from_utf8(mtl_filename).c_str())
, vcount_total(1)
{
obj_stream << std::setprecision(settings.precision);
mtl_stream << std::setprecision(settings.precision);
}
bool WaveFrontOBJSerializer::ready() {
return obj_stream.is_open() && mtl_stream.is_open();
}
+1 -11
View File
@@ -35,17 +35,7 @@ private:
unsigned int vcount_total;
std::set<std::string> materials;
public:
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings)
: GeometrySerializer(settings)
, mtl_filename(mtl_filename)
, obj_stream(obj_filename.c_str())
, mtl_stream(mtl_filename.c_str())
, vcount_total(1)
{
obj_stream << std::setprecision(settings.precision);
mtl_stream << std::setprecision(settings.precision);
}
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings);
virtual ~WaveFrontOBJSerializer() {}
bool ready();
void writeHeader();
+7 -5
View File
@@ -17,8 +17,6 @@
* *
********************************************************************************/
#include <map>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/version.hpp>
@@ -26,10 +24,12 @@
#include "XmlSerializer.h"
#include <algorithm>
#include "../ifcparse/IfcSIPrefix.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcparse/utils.h"
#include <map>
#include <algorithm>
using boost::property_tree::ptree;
using namespace IfcSchema;
@@ -528,5 +528,7 @@ void XmlSerializer::finalize() {
#else
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
#endif
boost::property_tree::write_xml(xml_filename, root, std::locale(), settings);
std::ofstream f(IfcUtil::path::from_utf8(xml_filename).c_str());
boost::property_tree::write_xml(f, root, settings);
}
+3 -2
View File
@@ -195,7 +195,8 @@ public:
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes);
void assert_closed_wire(TopoDS_Wire& wire);
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<const SurfaceStyle*>&, std::vector<double>&);
bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, IfcRepresentationShapeItems&);
@@ -267,7 +268,7 @@ public:
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
static IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*);
static IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*, bool include_openings=true);
static std::map<std::string, IfcSchema::IfcPresentationLayerAssignment*> get_layers(IfcSchema::IfcProduct* prod);
+36 -9
View File
@@ -67,6 +67,7 @@
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <TopExp.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
@@ -218,11 +219,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
process_wire:
if (face_surface.IsNull()) {
if (count(wire, TopAbs_EDGE) > 128) {
gp_Pln pln;
if (count(wire, TopAbs_EDGE) > 128 && approximate_plane_through_wire(wire, pln)) {
// tfk: optimization find the underlying surface ourselves since it's going
// to be planar in IFC if no explicit surface is given. Should we always do this?
gp_Pln pln;
approximate_plane_through_wire(wire, pln);
mf = new BRepBuilderAPI_MakeFace(pln, wire, true);
} else {
mf = new BRepBuilderAPI_MakeFace(wire);
@@ -245,7 +245,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
// In case of (non-planar) face surface, p-curves need to be computed.
// For planar faces, Open Cascade generates p-curves on the fly.
if (!face_surface.IsNull()) {
if (!face_surface.IsNull() && face_surface->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
TopExp_Explorer exp(outer_face_bound, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(exp.Current());
@@ -321,6 +321,17 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
} else {
mf->Add(wire);
// Same as above:
// In case of (non-planar) face surface, p-curves need to be computed.
if (BRep_Tool::Surface(mf->Face())->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
TopExp_Explorer exp(wire, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(exp.Current());
ShapeFix_Edge fix_edge;
fix_edge.FixAddPCurve(edge, mf->Face(), false, getValue(GV_PRECISION));
}
}
}
processed ++;
}
@@ -386,28 +397,44 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) {
TopoDS_Wire wire;
if ( ! convert_wire(l->OuterCurve(),wire) ) return false;
if (!convert_wire(l->OuterCurve(), wire)) {
return false;
}
assert_closed_wire(wire);
TopoDS_Face f;
bool success = convert_wire_to_face(wire, f);
if (success) face = f;
if (success) {
face = f;
}
return success;
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) {
TopoDS_Wire profile;
if ( ! convert_wire(l->OuterCurve(),profile) ) return false;
if (!convert_wire(l->OuterCurve(), profile)) {
return false;
}
assert_closed_wire(profile);
BRepBuilderAPI_MakeFace mf(profile);
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) {
for(IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++it) {
TopoDS_Wire hole;
if ( convert_wire(*it,hole) ) {
if (convert_wire(*it, hole)) {
assert_closed_wire(hole);
mf.Add(hole);
}
}
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
face = sfs.Shape();
return true;
}
+11 -12
View File
@@ -42,13 +42,15 @@ namespace IfcGeom
struct filter
{
filter() : include(false), traverse(false) {}
filter(bool incl, bool trav) : include(incl), traverse(trav) {}
filter() : include(false), traverse(false), traverse_openings(false) {}
filter(bool incl, bool trav, bool trav_openings = false) : include(incl), traverse(trav), traverse_openings(trav_openings) {}
/// Should the product be included (true) or excluded (false).
bool include;
/// If traversal requested, traverse to the parents to see if they satisfy the criteria. E.g. we might be looking for
/// children of a storey named "Level 20", or children of entities that have no representation, e.g. IfcCurtainWall.
bool traverse;
/// Include opening relationships as part of traversal.
bool traverse_openings;
/// Optional description for the filtering criteria of this filter.
std::string description;
@@ -61,10 +63,10 @@ namespace IfcGeom
return is_match == include;
}
static bool traverse_match(IfcSchema::IfcProduct* prod, const filter_t& pred)
bool traverse_match(IfcSchema::IfcProduct* prod, const filter_t& pred) const
{
IfcSchema::IfcProduct* parent, *current = prod;
while ((parent = dynamic_cast<IfcSchema::IfcProduct*>(IfcGeom::Kernel::get_decomposing_entity(current))) != 0) {
while ((parent = dynamic_cast<IfcSchema::IfcProduct*>(IfcGeom::Kernel::get_decomposing_entity(current, traverse_openings))) != 0) {
if (pred(parent)) {
return true;
}
@@ -171,8 +173,7 @@ namespace IfcGeom
bool operator()(IfcSchema::IfcProduct* prod) const
{
// @note bind1st() and mem_fun() deprecated in C++11, use bind() and mem_fn() when migrating to C++11.
return filter::match(prod, std::bind1st(std::mem_fun(&string_arg_filter::match), this));
return filter::match(prod, std::bind(&string_arg_filter::match, this, std::placeholders::_1));
}
void update_description()
@@ -219,7 +220,7 @@ namespace IfcGeom
bool operator()(IfcSchema::IfcProduct* prod) const
{
return filter::match(prod, std::bind1st(std::mem_fun(&layer_filter::match), this));
return filter::match(prod, std::bind(&layer_filter::match, this, std::placeholders::_1));
}
struct wildcards_match
@@ -249,11 +250,9 @@ namespace IfcGeom
struct entity_filter : public filter
{
entity_filter() {}
entity_filter(bool include, bool traverse/*, const std::set<std::string>& types*/)
entity_filter(bool include, bool traverse)
: filter(include, traverse)
{
//populate(types);
}
{}
std::set<IfcSchema::Type::Enum> values;
@@ -285,7 +284,7 @@ namespace IfcGeom
bool operator()(IfcSchema::IfcProduct* prod) const
{
return filter::match(prod, std::bind1st(std::mem_fun(&entity_filter::match), this));
return filter::match(prod, std::bind(&entity_filter::match, this, std::placeholders::_1));
}
void update_description()
+332 -154
View File
@@ -27,6 +27,8 @@
#include <cassert>
#include <algorithm>
#include <Standard_Version.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Dir.hxx>
@@ -90,6 +92,9 @@
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_BooleanOperation.hxx>
#if OCC_VERSION_HEX >= 0x70200
#include <BRepAlgoAPI_Splitter.hxx>
#endif
#include <BRepAlgo_NormalProjection.hxx>
@@ -141,8 +146,6 @@
#include <Extrema_ExtPC.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <Standard_Version.hxx>
#include "../ifcparse/IfcSIPrefix.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
@@ -193,22 +196,33 @@ namespace {
return min_edge_len;
}
double min_vertex_edge_distance(const TopoDS_Shape& a, double t) {
TopExp_Explorer exp(a, TopAbs_VERTEX);
double min_vertex_edge_distance(const TopoDS_Shape& a, double min_search, double max_search) {
double M = std::numeric_limits<double>::infinity();
for (; exp.More(); exp.Next()) {
if (exp.Current().Orientation() != TopAbs_FORWARD) {
continue;
}
TopTools_IndexedMapOfShape vertices, edges;
const TopoDS_Vertex& v = TopoDS::Vertex(exp.Current());
TopExp::MapShapes(a, TopAbs_VERTEX, vertices);
TopExp::MapShapes(a, TopAbs_EDGE, edges);
IfcGeom::impl::tree<int> tree;
// Add edges to tree
for (int i = 1; i <= edges.Extent(); ++i) {
tree.add(i, edges(i));
}
for (int j = 1; j <= vertices.Extent(); ++j) {
const TopoDS_Vertex& v = TopoDS::Vertex(vertices(j));
gp_Pnt p = BRep_Tool::Pnt(v);
TopExp_Explorer exp2(a, TopAbs_EDGE);
for (; exp2.More(); exp2.Next()) {
const TopoDS_Edge& e = TopoDS::Edge(exp2.Current());
Bnd_Box b;
b.Add(p);
b.Enlarge(max_search);
std::vector<int> edge_idxs = tree.select_box(b, false);
std::vector<int>::const_iterator it = edge_idxs.begin();
for (; it != edge_idxs.end(); ++it) {
const TopoDS_Edge& e = TopoDS::Edge(edges(*it));
TopoDS_Vertex v1, v2;
TopExp::Vertices(e, v1, v2);
@@ -224,7 +238,7 @@ namespace {
for (int i = 1; i <= ext.NbExt(); ++i) {
const double m = sqrt(ext.SquareDistance(i));
if (m < M && m > t) {
if (m < M && m > min_search) {
M = m;
}
}
@@ -235,7 +249,7 @@ namespace {
}
bool is_manifold(const TopoDS_Shape& a) {
if (a.ShapeType() == TopAbs_COMPOUND) {
if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) {
TopoDS_Iterator it(a);
for (; it.More(); it.Next()) {
if (!is_manifold(it.Value())) {
@@ -862,6 +876,27 @@ bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& w, TopoDS_Face& fa
return true;
}
void IfcGeom::Kernel::assert_closed_wire(TopoDS_Wire& wire) {
if (wire.Closed() == 0) {
TopoDS_Vertex v0, v1;
TopExp::Vertices(wire, v0, v1);
gp_Pnt p1 = BRep_Tool::Pnt(v0);
gp_Pnt p2 = BRep_Tool::Pnt(v1);
if (p1.Distance(p2) > getValue(GV_PRECISION)) {
BRepBuilderAPI_MakeWire mw;
mw.Add(wire);
mw.Add(BRepBuilderAPI_MakeEdge(v0, v1).Edge());
wire = mw.Wire();
}
Logger::Warning("Wire not closed:");
}
}
bool IfcGeom::Kernel::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) {
try {
wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve));
@@ -1380,7 +1415,9 @@ const IfcSchema::IfcMaterial* IfcGeom::Kernel::get_single_material_association(c
if (associated_materials->size() == 1) {
IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial();
single_material = associated_material->as<IfcSchema::IfcMaterial>();
// TODO: Should this check for APPLY_LAYERSETS setting?
// NB: Single-layer layersets are also considered, regardless of --enable-layerset-slicing, this
// in accordance with other viewers.
if (!single_material && associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
IfcSchema::IfcMaterialLayerSet* layerset = associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()->ForLayerSet();
if (layerset->MaterialLayers()->size() == 1) {
@@ -1429,13 +1466,23 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
}
}
if (product->as<IfcSchema::IfcWall>() && fold_layers(product->as<IfcSchema::IfcWall>(), shapes, layers, thickness, folded_layers)) {
if (apply_folded_layerset(shapes, folded_layers, styles, shapes2)) {
std::swap(shapes, shapes2);
if (styles.size() > 1) {
// If there's only a single layer there is no need to manipulate geometries.
bool success = true;
if (product->as<IfcSchema::IfcWall>() && fold_layers(product->as<IfcSchema::IfcWall>(), shapes, layers, thickness, folded_layers)) {
if (apply_folded_layerset(shapes, folded_layers, styles, shapes2)) {
std::swap(shapes, shapes2);
success = true;
}
} else {
if (apply_layerset(shapes, layers, styles, shapes2)) {
std::swap(shapes, shapes2);
success = true;
}
}
} else {
if (apply_layerset(shapes, layers, styles, shapes2)) {
std::swap(shapes, shapes2);
if (!success) {
Logger::Error("Failed processing layerset");
}
}
}
@@ -1454,9 +1501,17 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
material_style_applied = true;
}
}
}
else {
Logger::Warning("Object '" + product->GlobalId() + "' has no material!");
} else {
bool some_items_without_style = false;
for (IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++it) {
if (!it->hasStyle()) {
some_items_without_style = true;
break;
}
}
if (some_items_without_style) {
Logger::Warning("No material and surface styles for:", product->entity);
}
}
if (material_style_applied) {
@@ -1684,33 +1739,33 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_processed_representati
);
}
IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchema::IfcProduct* product) {
IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchema::IfcProduct* product, bool include_openings) {
IfcSchema::IfcObjectDefinition* parent = 0;
// In case of an opening element, parent to the RelatingBuildingElement
if ( product->is(IfcSchema::Type::IfcOpeningElement ) ) {
if (include_openings && product->is(IfcSchema::Type::IfcOpeningElement)) {
IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product;
IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements();
if ( voids->size() ) {
if (voids->size()) {
IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin();
parent = ifc_void->RelatingBuildingElement();
}
} else if ( product->is(IfcSchema::Type::IfcElement ) ) {
} else if (product->is(IfcSchema::Type::IfcElement)) {
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids();
// In case of a RelatedBuildingElement parent to the opening element
if ( fills->size() ) {
for ( IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++ it ) {
if (fills->size() && include_openings) {
for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++ it) {
IfcSchema::IfcRelFillsElement* fill = *it;
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement();
if ( product == ifc_objectdef ) continue;
if (product == ifc_objectdef) continue;
parent = ifc_objectdef;
}
}
// Else simply parent to the containing structure
if (!parent) {
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure();
if ( parents->size() ) {
if (parents->size()) {
IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin();
parent = container->RelatingStructure();
}
@@ -1752,20 +1807,6 @@ std::map<std::string, IfcSchema::IfcPresentationLayerAssignment*> IfcGeom::Kerne
layers[(*jt)->Name()] = *jt;
}
}
IfcRepresentationItem::list::ptr items = r->as<IfcRepresentationItem>();
for (IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) {
IfcPresentationLayerAssignment::list::ptr a = (*it)->
// LayerAssignments renamed from plural to singular, LayerAssignment, so work around that
#ifdef USE_IFC4
LayerAssignment();
#else
LayerAssignments();
#endif
for (IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
layers[(*jt)->Name()] = *jt;
}
}
}
return layers;
}
@@ -1906,8 +1947,11 @@ bool IfcGeom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std
if (true) { /**< @todo Why always true? */
if (axis_curve->DynamicType() == STANDARD_TYPE(Geom_Line)) {
Handle_Geom_Line axis_line = Handle_Geom_Line::DownCast(axis_curve);
// @todo note that this creates an offset into the wrong order, the cross product arguments should be
// reversed. This causes some inversions later on, e.g. if(positive) { reverse(); }
reference_surface = new Geom_Plane(axis_line->Lin().Location(), axis_line->Lin().Direction() ^ gp::DZ());
} else if (axis_curve->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
// @todo note that in this branch this inversion does not seem to take place.
Handle_Geom_Circle axis_line = Handle_Geom_Circle::DownCast(axis_curve);
reference_surface = new Geom_CylindricalSurface(axis_line->Position(), axis_line->Radius());
} else {
@@ -2416,20 +2460,137 @@ bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const IfcRepre
return folds_made;
}
namespace {
#if OCC_VERSION_HEX >= 0x70200
bool split(IfcGeom::Kernel&, const TopoDS_Shape& input, const TopTools_ListOfShape& operands, double eps, std::vector<TopoDS_Shape>& slices) {
if (operands.Extent() < 2) {
// Needs to have at least two cutting surfaces for the ordering based on surface containment to work.
return false;
}
BRepAlgoAPI_Splitter split;
TopTools_ListOfShape input_list;
input_list.Append(input);
split.SetArguments(input_list);
split.SetTools(operands);
split.SetNonDestructive(true);
split.SetFuzzyValue(eps);
split.Build();
if (!split.IsDone()) {
return false;
} else {
std::map<Geom_Surface*, int> surfaces;
// NB 1, since first surface has been excluded
int i = 1;
for (TopTools_ListIteratorOfListOfShape it(operands); it.More(); it.Next(), ++i) {
TopExp_Explorer exp(it.Value(), TopAbs_FACE);
for (; exp.More(); exp.Next()) {
surfaces.insert(std::make_pair(BRep_Tool::Surface(TopoDS::Face(exp.Current())).get(), i));
}
}
// Count subshapes
size_t n = 0;
TopoDS_Iterator sit(split.Shape());
for (; sit.More(); sit.Next()) {
++n;
}
// Initialize storage
slices.resize(n);
sit.Initialize(split.Shape());
for (; sit.More(); sit.Next()) {
// Iterate over the faces of solid to find correspondence to original
// splitting surfaces. For the outmost slices, there will be a single
// corresponding surface, because the outmost surfaces that align with
// the body geometry have not been added as operands. For intermediate
// slices, two surface indices should be find that should be next to
// each other in the array of input surfaces.
TopExp_Explorer exp(sit.Value(), TopAbs_FACE);
int min = std::numeric_limits<int>::max();
int max = std::numeric_limits<int>::min();
for (; exp.More(); exp.Next()) {
auto ssrf = BRep_Tool::Surface(TopoDS::Face(exp.Current()));
auto it = surfaces.find(ssrf.get());
if (it != surfaces.end()) {
if (it->second < min) {
min = it->second;
}
if (it->second > max) {
max = it->second;
}
}
}
int idx = std::numeric_limits<int>::max();
if (min != std::numeric_limits<int>::max()) {
if (min == 1 && max == 1) {
idx = 0;
} else if (min + 1 == max || min == max) {
idx = min;
}
}
if (idx < (int) slices.size()) {
if (slices[idx].IsNull()) {
slices[idx] = sit.Value();
continue;
}
}
Logger::Error("Unable to map layer geometry to material index");
return false;
}
}
return true;
}
#else
bool split(IfcGeom::Kernel& k, const TopoDS_Shape& input, const TopTools_ListOfShape& operands, double, std::vector<TopoDS_Shape>& slices) {
TopTools_ListIteratorOfListOfShape it(operands);
TopoDS_Shape i = input;
for (; it.More(); it.Next()) {
const TopoDS_Shape& s = it.Value();
TopoDS_Shape a, b;
Handle(Geom_Surface) surf;
if (s.ShapeType() == TopAbs_FACE) {
surf = BRep_Tool::Surface(TopoDS::Face(s));
}
if ((s.ShapeType() == TopAbs_FACE && k.split_solid_by_surface(i, surf, a, b)) ||
(s.ShapeType() == TopAbs_SHELL && k.split_solid_by_shell(i, s, a, b)))
{
slices.push_back(b);
i = a;
} else {
return false;
}
}
slices.push_back(i);
return true;
}
#endif
}
bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& items, const std::vector< std::vector<Handle_Geom_Surface> >& surfaces, const std::vector<const SurfaceStyle*>& styles, IfcRepresentationShapeItems& result) {
Bnd_Box bb;
TopoDS_Shape input;
flatten_shape_list(items, input, false);
BRepBndLib::Add(input, bb);
std::vector<double> bb_coords(6);
bb.Get(bb_coords[0], bb_coords[1], bb_coords[2], bb_coords[3], bb_coords[4], bb_coords[5]);
typedef std::vector< std::vector<Handle_Geom_Surface> > folded_surfaces_t;
typedef std::vector< std::pair< TopoDS_Face, std::pair<gp_Pnt, gp_Pnt> > > faces_with_mass_t;
std::vector<TopoDS_Shell> shells;
TopTools_ListOfShape shells;
// result = items;
for (folded_surfaces_t::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) {
if (it->empty()) {
continue;
@@ -2439,7 +2600,7 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i
if (!project(surface, input, u1, v1, u2, v2)) {
continue;
}
shells.push_back(BRepBuilderAPI_MakeShell(surface, u1, v1, u2, v2).Shell());
shells.Append(BRepBuilderAPI_MakeShell(surface, u1, v1, u2, v2).Shell());
} else {
faces_with_mass_t solids;
for (folded_surfaces_t::value_type::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
@@ -2486,19 +2647,19 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i
}
builder.Perform();
shells.push_back(TopoDS::Shell(builder.SewedShape()));
shells.Append(TopoDS::Shell(builder.SewedShape()));
}
}
if (shells.empty()) {
if (shells.Extent() == 0) {
return false;
} else if (shells.size() == 1) {
} else if (shells.Extent() == 1) {
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
TopoDS_Shape a,b;
if (split_solid_by_shell(it->Shape(), shells[0], a, b)) {
if (split_solid_by_shell(it->Shape(), shells.First(), a, b)) {
result.push_back(IfcRepresentationShapeItem(it->Placement(), b, styles[0] ? styles[0] : &it->Style()));
result.push_back(IfcRepresentationShapeItem(it->Placement(), a, styles[1] ? styles[1] : &it->Style()));
} else {
@@ -2510,39 +2671,19 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i
} else {
typedef std::vector< std::vector<TopoDS_Shape> > temp_t;
temp_t temp;
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
const TopoDS_Shape& s = it->Shape();
TopoDS_Solid sld;
ensure_fit_for_subtraction(s, sld);
std::vector<TopoDS_Shape> temp2;
temp2.push_back(sld);
temp.push_back(temp2);
}
for (unsigned i = 0; i < shells.size(); ++i) {
for(temp_t::iterator it = temp.begin(); it != temp.end(); ++it) {
TopoDS_Shape a,b;
TopoDS_Shape& ab = (*it)[(*it).size() - 1];
if (split_solid_by_shell(ab, shells[i], a, b)) {
ab = b;
it->push_back(a);
} else {
continue;
std::vector<TopoDS_Shape> slices;
if (split(*this, it->Shape(), shells, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) {
for (size_t i = 0; i < slices.size(); ++i) {
result.push_back(IfcRepresentationShapeItem(it->Placement(), slices[i], styles[i] ? styles[i] : &it->Style()));
}
}
}
IfcRepresentationShapeItems::const_iterator it1 = items.begin();
temp_t::const_iterator it2 = temp.begin();
for(; it1 != items.end(); ++it1, ++it2) {
std::vector<const SurfaceStyle*>::const_iterator it4 = styles.begin();
for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) {
result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style()));
} else {
return false;
}
}
@@ -2602,40 +2743,31 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c
mass.ChangeCoord() += n1.XYZ();
*/
typedef std::vector< std::vector<TopoDS_Shape> > temp_t;
temp_t temp;
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
// No transformation on purpose in order not interfere with layerset alignment
const TopoDS_Shape& s = it->Shape();
TopoDS_Solid sld;
ensure_fit_for_subtraction(s, sld);
std::vector<TopoDS_Shape> temp2;
temp2.push_back(sld);
temp.push_back(temp2);
}
for (unsigned i = 1; i < surfaces.size() - 1; ++i) {
for(temp_t::iterator it = temp.begin(); it != temp.end(); ++it) {
TopoDS_Shape a,b;
TopoDS_Shape& ab = (*it)[(*it).size() - 1];
if (split_solid_by_surface(ab, surfaces[i], a, b)) {
ab = b;
it->push_back(a);
} else {
continue;
TopTools_ListOfShape operands;
for (unsigned i = 1; i < surfaces.size() - 1; ++i) {
double u1, v1, u2, v2;
if (!project(surfaces[i], sld, u1, v1, u2, v2)) {
return false;
}
}
}
IfcRepresentationShapeItems::const_iterator it1 = items.begin();
temp_t::const_iterator it2 = temp.begin();
for(; it1 != items.end(); ++it1, ++it2) {
std::vector<const SurfaceStyle*>::const_iterator it4 = styles.begin();
for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) {
result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style()));
TopoDS_Face face = BRepBuilderAPI_MakeFace(surfaces[i], u1, u2, v1, v2, 1.e-7).Face();
operands.Append(face);
}
std::vector<TopoDS_Shape> slices;
if (split(*this, it->Shape(), operands, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) {
for (size_t i = 0; i < slices.size(); ++i) {
result.push_back(IfcRepresentationShapeItem(it->Placement(), slices[i], styles[i] ? styles[i] : &it->Style()));
}
} else {
return false;
}
}
@@ -2748,7 +2880,19 @@ bool IfcGeom::Kernel::split_solid_by_shell(const TopoDS_Shape& input, const Topo
}
bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape& shp, double& u1, double& v1, double& u2, double& v2, double widen) {
ShapeAnalysis_Surface sas(srf);
// @todo std::unique_ptr for C++11
ShapeAnalysis_Surface* sas = 0;
Handle(Geom_Plane) pln;
if (srf->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
// Optimize projection for specific cases
pln = Handle(Geom_Plane)::DownCast(srf);
} else if (srf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface) && Handle(Geom_OffsetSurface)::DownCast(srf)->BasisSurface()->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
// For an offset planar surface the projected UV coords are the same as the basis surface
pln = Handle(Geom_Plane)::DownCast(Handle(Geom_OffsetSurface)::DownCast(srf)->BasisSurface());
} else {
sas = new ShapeAnalysis_Surface(srf);
}
u1 = v1 = +std::numeric_limits<double>::infinity();
u2 = v2 = -std::numeric_limits<double>::infinity();
@@ -2759,7 +2903,14 @@ bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape
gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()));
median.ChangeCoord() += p.XYZ();
const gp_Pnt2d uv = sas.ValueOfUV(p, 1e-3);
gp_Pnt2d uv;
if (sas) {
uv = sas->ValueOfUV(p, 1e-3);
} else {
gp_Vec d = p.XYZ() - pln->Position().Location().XYZ();
uv.SetX(d.Dot(pln->Position().XDirection()));
uv.SetY(d.Dot(pln->Position().YDirection()));
}
if (uv.X() < u1) u1 = uv.X();
if (uv.Y() < v1) v1 = uv.Y();
@@ -2767,36 +2918,44 @@ bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape
if (uv.Y() > v2) v2 = uv.Y();
}
if (vertex_count == 0) {
return false;
if (vertex_count > 0) {
// Add a little bit of resolution so that the median is shifted towards the mass
// of the curve. This helps to find the parameter ordering for conic surfaces.
for (TopExp_Explorer exp(shp, TopAbs_EDGE); exp.More(); exp.Next(), ++vertex_count) {
const TopoDS_Edge& e = TopoDS::Edge(exp.Current());
double a, b;
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
gp_Pnt p;
crv->D0((a + b) / 2., p);
median.ChangeCoord() += p.XYZ();
}
median.ChangeCoord().Divide(vertex_count);
gp_Pnt2d uv;
if (sas) {
uv = sas->ValueOfUV(median, 1e-3);
} else {
gp_Vec d = median.XYZ() - pln->Position().Location().XYZ();
uv.SetX(d.Dot(pln->Position().XDirection()));
uv.SetY(d.Dot(pln->Position().YDirection()));
}
if (uv.X() < u1 || uv.X() > u2) {
std::swap(u1, u2);
}
u1 -= widen;
u2 += widen;
v1 -= widen;
v2 += widen;
}
// Add a little bit of resolution so that the median is shifted towards the mass
// of the curve. This helps to find the parameter ordering for conic surfaces.
for (TopExp_Explorer exp(shp, TopAbs_EDGE); exp.More(); exp.Next(), ++vertex_count) {
const TopoDS_Edge& e = TopoDS::Edge(exp.Current());
double a, b;
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
gp_Pnt p;
crv->D0((a + b) / 2., p);
median.ChangeCoord() += p.XYZ();
}
median.ChangeCoord().Divide(vertex_count);
const gp_Pnt2d uv = sas.ValueOfUV(median, 1e-3);
if (uv.X() < u1 || uv.X() > u2) {
std::swap(u1, u2);
}
u1 -= widen;
u2 += widen;
v1 -= widen;
v2 += widen;
return true;
delete sas;
return vertex_count > 0;
}
const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) {
@@ -3071,13 +3230,13 @@ namespace {
operator int() { return i; }
};
std::string format_pnt(const gp_Pnt& p) {
inline std::string format_pnt(const gp_Pnt& p) {
std::stringstream ss;
ss << std::fixed << std::setprecision(4) << p.X() << " " << p.Y() << " " << p.Z();
return ss.str();
}
std::string format_edge(const TopoDS_Edge& e) {
inline std::string format_edge(const TopoDS_Edge& e) {
std::stringstream ss;
TopoDS_Vertex v1, v2;
TopExp::Vertices(e, v1, v2);
@@ -3210,7 +3369,7 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
TopoDS_Edge e = wd->Edge(k + 1);
TopoDS_Vertex v1, v2;
TopExp::Vertices(e, v1, v2);
TopExp::Vertices(e, v1, v2, true);
const TopoDS_Vertex* v = first == forward ? &v2 : &v1;
// gp_Pnt p2 = points3d.Value(1);
@@ -3479,20 +3638,23 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li
fuzziness = getValue(GV_PRECISION);
}
double min_len = (std::min)(min_edge_length(a), min_vertex_edge_distance(a, getValue(GV_PRECISION)));
// Find a sensible value for the fuzziness, based on precision
// and limited by edge lengths and vertex-edge distances.
const double len_a = min_edge_length(a);
double min_length_orig = (std::min)(len_a, min_vertex_edge_distance(a, getValue(GV_PRECISION), len_a));
TopTools_ListIteratorOfListOfShape it(b);
for (; it.More(); it.Next()) {
double d = min_edge_length(it.Value());
if (d < min_len) {
min_len = d;
if (d < min_length_orig) {
min_length_orig = d;
}
d = min_vertex_edge_distance(it.Value(), getValue(GV_PRECISION));
if (d < min_len) {
min_len = d;
d = min_vertex_edge_distance(it.Value(), getValue(GV_PRECISION), d);
if (d < min_length_orig) {
min_length_orig = d;
}
}
const double fuzz = (std::min)(min_len / 10., fuzziness);
const double fuzz = (std::min)(min_length_orig / 10., fuzziness);
TopTools_ListOfShape s1s;
s1s.Append(copy_operand(a));
@@ -3528,19 +3690,35 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li
// when there are edges or vertex-edge distances close to the used fuzziness, the
// output is not trusted and the operation is attempted with a higher fuzziness.
double min_len_check = (std::min)(min_edge_length(r), min_vertex_edge_distance(r, getValue(GV_PRECISION)));
success = min_len_check > fuzziness * 10.;
double min_lengh_result = (std::min)(min_edge_length(r), min_vertex_edge_distance(r, getValue(GV_PRECISION), fuzziness * 10.));
success = min_lengh_result <= min_length_orig || min_lengh_result > fuzziness * 10.;
if (success) {
result = r;
} else {
std::stringstream str;
str << "Boolean operation result failing interference check, with fuzziness " << fuzziness << " min length " << min_lengh_result << " originally " << min_length_orig;
Logger::Notice(str.str());
}
} else {
Logger::Notice("Boolean operation yields non-manifold result");
}
} else {
Logger::Notice("Boolean operation yields invalid result");
}
} else {
std::stringstream str;
#if OCC_VERSION_HEX >= 0x70000
builder->DumpErrors(str);
#else
str << "Error code :" << builder->ErrorStatus();
#endif
Logger::Notice(str.str());
}
delete builder;
if (!success) {
const double new_fuzziness = fuzziness * 10.;
if (new_fuzziness + 1e-15 <= getValue(GV_PRECISION) * 1000. && new_fuzziness < min_len) {
if (new_fuzziness + 1e-15 <= getValue(GV_PRECISION) * 1000. && new_fuzziness < min_length_orig) {
return boolean_operation(a, b, op, result, new_fuzziness);
}
}
+32 -9
View File
@@ -158,15 +158,38 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) {
IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
IfcGeom::Kernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
IN_CACHE(IfcAxis2Placement3D, l, gp_Trsf, trsf)
gp_Pnt o;
gp_Dir axis(0, 0, 1);
gp_Dir refDirection;
IfcGeom::Kernel::convert(l->Location(), o);
const bool hasAxis = l->hasAxis();
const bool hasRef = l->hasRefDirection();
if (hasAxis != hasRef) {
Logger::Warning("Axis and RefDirection should be specified together", l->entity);
}
if (hasAxis) {
IfcGeom::Kernel::convert(l->Axis(), axis);
}
if (hasRef) {
IfcGeom::Kernel::convert(l->RefDirection(), refDirection);
} else {
if (!axis.IsParallel(gp::DX(), 1.e-5)) {
refDirection = gp::DX();
} else {
refDirection = gp::DZ();
}
gp_Vec Xvec = axis.Dot(refDirection) * axis;
gp_Vec Xaxis = refDirection.XYZ() - Xvec.XYZ();
refDirection = Xaxis;
}
gp_Ax3 ax3(o, axis, refDirection);
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
trsf.SetTransformation(ax3, gp::XOY());
+1
View File
@@ -200,6 +200,7 @@ void IfcGeom::set_default_style_file(const std::string& json_file) {
if (!default_materials_initialized) InitDefaultMaterials();
default_materials.clear();
// @todo this will probably need to be updated for UTF-8 paths on Windows
pt::ptree root;
pt::read_json(json_file, root);
+48 -6
View File
@@ -885,7 +885,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l,
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
gp_Trsf directrix, position;
gp_Trsf directrix;
TopoDS_Shape face;
TopoDS_Wire wire, section;
@@ -964,12 +964,47 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(position);
shape.Move(trsf);
}
return true;
}
namespace {
bool wire_is_c1_continuous(const TopoDS_Wire& w, double tol) {
// NB Note that c0 continuity is NOT checked!
TopTools_IndexedDataMapOfShapeListOfShape map;
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map);
for (int i = 1; i <= map.Extent(); ++i) {
const auto& li = map.FindFromIndex(i);
if (li.Extent() == 2) {
const TopoDS_Vertex& v = TopoDS::Vertex(map.FindKey(i));
const TopoDS_Edge& e0 = TopoDS::Edge(li.First());
const TopoDS_Edge& e1 = TopoDS::Edge(li.Last());
double u0 = BRep_Tool::Parameter(v, e0);
double u1 = BRep_Tool::Parameter(v, e1);
double _, __;
Handle(Geom_Curve) c0 = BRep_Tool::Curve(e0, _, __);
Handle(Geom_Curve) c1 = BRep_Tool::Curve(e1, _, __);
gp_Pnt p;
gp_Vec v0, v1;
c0->D1(u0, p, v0);
c1->D1(u1, p, v1);
if (1. - std::abs(v0.Normalized().Dot(v1.Normalized())) > tol) {
return false;
}
}
}
return true;
}
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) {
TopoDS_Wire wire, section1, section2;
@@ -1019,6 +1054,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
}
}
const bool is_continuous = wire_is_c1_continuous(wire, 1.e-3);
// NB: Note that StartParam and EndParam param are ignored and the assumption is
// made that the parametric range over which to be swept matches the IfcCurve in
// its entirety.
@@ -1027,7 +1064,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
// of directrices encountered, which do not necessarily conform to a surface.
{ BRepOffsetAPI_MakePipeShell builder(wire);
builder.Add(section1);
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
if (!is_continuous) {
// Only perform round corners on wires that are not c1 continuous
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
}
builder.Build();
builder.MakeSolid();
shape = builder.Shape(); }
@@ -1035,7 +1075,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap
if (hasInnerRadius) {
BRepOffsetAPI_MakePipeShell builder(wire);
builder.Add(section2);
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
if (!is_continuous) {
builder.SetTransitionMode(BRepBuilderAPI_RoundCorner);
}
builder.Build();
builder.MakeSolid();
TopoDS_Shape inner = builder.Shape();
@@ -1071,9 +1113,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_
// IfcElementarySurface.Position has unit scale factor
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf);
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT))).Face().Moved(trsf);
#else
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT)), getValue(GV_PRECISION)).Face().Moved(trsf);
#endif
return true;
}
+56 -37
View File
@@ -715,7 +715,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& res
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
BRepBuilderAPI_MakeEdge me(crv, p1, p2);
if (!me.IsDone()) {
return false;
}
mw.Add(me.Edge());
result = mw;
return true;
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
@@ -745,7 +749,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& res
ecrv->D0(u1, a);
b = p2;
} else {
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
BRepBuilderAPI_MakeEdge me(ecrv, u1, u2);
if (!me.IsDone()) {
return false;
}
mw.Add(me.Edge());
first = false;
continue;
}
@@ -776,7 +784,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& resu
mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
}
}
result = mw;
if (!mw.IsDone()) {
return false;
}
result = mw.Wire();
return true;
}
@@ -862,45 +873,53 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIndexedPolyCurve* l, TopoDS_Wi
BRepBuilderAPI_MakeWire w;
IfcEntityList::ptr segments = l->Segments();
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
IfcUtil::IfcBaseClass* segment = *it;
if (segment->is(IfcSchema::Type::IfcLineIndex)) {
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
std::vector<int> indices = *line;
gp_Pnt previous;
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
if (*jt < 1 || *jt > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
if(l->hasSegments()) {
IfcEntityList::ptr segments = l->Segments();
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
IfcUtil::IfcBaseClass* segment = *it;
if (segment->is(IfcSchema::Type::IfcLineIndex)) {
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
std::vector<int> indices = *line;
gp_Pnt previous;
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
if (*jt < 1 || *jt > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
}
const gp_Pnt& current = points[*jt - 1];
if (jt != indices.begin()) {
w.Add(BRepBuilderAPI_MakeEdge(previous, current));
}
previous = current;
}
const gp_Pnt& current = points[*jt - 1];
if (jt != indices.begin()) {
w.Add(BRepBuilderAPI_MakeEdge(previous, current));
} else if (segment->is(IfcSchema::Type::IfcArcIndex)) {
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
std::vector<int> indices = *arc;
if (indices.size() != 3) {
throw IfcParse::IfcException("Invalid IfcArcIndex encountered");
}
previous = current;
}
} else if (segment->is(IfcSchema::Type::IfcArcIndex)) {
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
std::vector<int> indices = *arc;
if (indices.size() != 3) {
throw IfcParse::IfcException("Invalid IfcArcIndex encountered");
}
for (int i = 0; i < 3; ++i) {
const int& idx = indices[i];
if (idx < 1 || idx > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(idx));
for (int i = 0; i < 3; ++i) {
const int& idx = indices[i];
if (idx < 1 || idx > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(idx));
}
}
const gp_Pnt& a = points[indices[0] - 1];
const gp_Pnt& b = points[indices[1] - 1];
const gp_Pnt& c = points[indices[2] - 1];
Handle(Geom_Circle) circ = GC_MakeCircle(a, b, c).Value();
w.Add(BRepBuilderAPI_MakeEdge(circ, a, c));
} else {
throw IfcParse::IfcException("Unexpected IfcIndexedPolyCurve segment of type " + IfcSchema::Type::ToString(segment->type()));
}
const gp_Pnt& a = points[indices[0] - 1];
const gp_Pnt& b = points[indices[1] - 1];
const gp_Pnt& c = points[indices[2] - 1];
Handle(Geom_Circle) circ = GC_MakeCircle(a, b, c).Value();
w.Add(BRepBuilderAPI_MakeEdge(circ, a, c));
} else {
throw IfcParse::IfcException("Unexpected IfcIndexedPolyCurve segment of type " + IfcSchema::Type::ToString(segment->type()));
}
}
} else if (points.begin() < points.end()) {
std::vector<gp_Pnt>::const_iterator previous = points.begin();
for (std::vector<gp_Pnt>::const_iterator current = previous+1; current < points.end(); ++current){
w.Add(BRepBuilderAPI_MakeEdge(*previous, *current));
previous = current;
}
}
result = w.Wire();
return true;
}
+1 -1
View File
@@ -46,7 +46,7 @@ namespace IfcGeom {
const gp_GTrsf& Placement() const { return placement; }
bool hasStyle() const { return style != 0; }
const SurfaceStyle& Style() const { return *style; }
void setStyle(const SurfaceStyle* style) { this->style = style; }
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
};
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
}
-4
View File
@@ -52,10 +52,6 @@ namespace IfcUtil {
IFC_PARSE_API const char* ArgumentTypeToString(ArgumentType argument_type);
IFC_PARSE_API bool valid_binary_string(const std::string& s);
/// Replaces spaces and potentially other problem causing characters with underscores.
IFC_PARSE_API void sanitate_material_name(std::string &str);
IFC_PARSE_API void escape_xml(std::string &str);
IFC_PARSE_API void unescape_xml(std::string &str);
}
class IFC_PARSE_API Argument {
+34 -7
View File
@@ -271,8 +271,6 @@ void InitDescriptorMap() {
current->add("wrappedValue",false,IfcUtil::Argument_DOUBLE);
current = entity_descriptor_map[Type::IfcSpecularRoughness] = new IfcEntityDescriptor(Type::IfcSpecularRoughness,0);
current->add("wrappedValue",false,IfcUtil::Argument_DOUBLE);
current = entity_descriptor_map[Type::IfcStrippedOptional] = new IfcEntityDescriptor(Type::IfcStrippedOptional,0);
current->add("wrappedValue",false,IfcUtil::Argument_BOOL);
current = entity_descriptor_map[Type::IfcTemperatureGradientMeasure] = new IfcEntityDescriptor(Type::IfcTemperatureGradientMeasure,0);
current->add("wrappedValue",false,IfcUtil::Argument_DOUBLE);
current = entity_descriptor_map[Type::IfcTemperatureRateOfChangeMeasure] = new IfcEntityDescriptor(Type::IfcTemperatureRateOfChangeMeasure,0);
@@ -1484,6 +1482,10 @@ void InitDescriptorMap() {
current->add("FilletRadius",true,IfcUtil::Argument_DOUBLE,Type::IfcNonNegativeLengthMeasure);
current->add("FlangeEdgeRadius",true,IfcUtil::Argument_DOUBLE,Type::IfcNonNegativeLengthMeasure);
current->add("FlangeSlope",true,IfcUtil::Argument_DOUBLE,Type::IfcPlaneAngleMeasure);
current = entity_descriptor_map[Type::IfcIndexedPolygonalFace] = new IfcEntityDescriptor(Type::IfcIndexedPolygonalFace,entity_descriptor_map.find(Type::IfcTessellatedItem)->second);
current->add("CoordIndex",false,IfcUtil::Argument_AGGREGATE_OF_INT,Type::IfcPositiveInteger);
current = entity_descriptor_map[Type::IfcIndexedPolygonalFaceWithVoids] = new IfcEntityDescriptor(Type::IfcIndexedPolygonalFaceWithVoids,entity_descriptor_map.find(Type::IfcIndexedPolygonalFace)->second);
current->add("InnerCoordIndices",false,IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT,Type::IfcPositiveInteger);
current = entity_descriptor_map[Type::IfcLShapeProfileDef] = new IfcEntityDescriptor(Type::IfcLShapeProfileDef,entity_descriptor_map.find(Type::IfcParameterizedProfileDef)->second);
current->add("Depth",false,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current->add("Width",true,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
@@ -1766,6 +1768,8 @@ void InitDescriptorMap() {
current->add("LongName",true,IfcUtil::Argument_STRING,Type::IfcLabel);
current = entity_descriptor_map[Type::IfcSphere] = new IfcEntityDescriptor(Type::IfcSphere,entity_descriptor_map.find(Type::IfcCsgPrimitive3D)->second);
current->add("Radius",false,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current = entity_descriptor_map[Type::IfcSphericalSurface] = new IfcEntityDescriptor(Type::IfcSphericalSurface,entity_descriptor_map.find(Type::IfcElementarySurface)->second);
current->add("Radius",false,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current = entity_descriptor_map[Type::IfcStructuralActivity] = new IfcEntityDescriptor(Type::IfcStructuralActivity,entity_descriptor_map.find(Type::IfcProduct)->second);
current->add("AppliedLoad",false,IfcUtil::Argument_ENTITY_INSTANCE,Type::IfcStructuralLoad);
current->add("GlobalOrLocal",false,IfcUtil::Argument_ENUMERATION,Type::IfcGlobalOrLocalEnum);
@@ -1784,6 +1788,10 @@ void InitDescriptorMap() {
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcStructuralSurfaceActivityTypeEnum);
current = entity_descriptor_map[Type::IfcSubContractResourceType] = new IfcEntityDescriptor(Type::IfcSubContractResourceType,entity_descriptor_map.find(Type::IfcConstructionResourceType)->second);
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcSubContractResourceTypeEnum);
current = entity_descriptor_map[Type::IfcSurfaceCurve] = new IfcEntityDescriptor(Type::IfcSurfaceCurve,entity_descriptor_map.find(Type::IfcCurve)->second);
current->add("Curve3D",false,IfcUtil::Argument_ENTITY_INSTANCE,Type::IfcCurve);
current->add("AssociatedGeometry",false,IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE,Type::IfcPcurve);
current->add("MasterRepresentation",false,IfcUtil::Argument_ENUMERATION,Type::IfcPreferredSurfaceCurveRepresentation);
current = entity_descriptor_map[Type::IfcSurfaceCurveSweptAreaSolid] = new IfcEntityDescriptor(Type::IfcSurfaceCurveSweptAreaSolid,entity_descriptor_map.find(Type::IfcSweptAreaSolid)->second);
current->add("Directrix",false,IfcUtil::Argument_ENTITY_INSTANCE,Type::IfcCurve);
current->add("StartParam",true,IfcUtil::Argument_DOUBLE,Type::IfcParameterValue);
@@ -1808,13 +1816,16 @@ void InitDescriptorMap() {
current->add("WorkMethod",true,IfcUtil::Argument_STRING,Type::IfcLabel);
current = entity_descriptor_map[Type::IfcTessellatedFaceSet] = new IfcEntityDescriptor(Type::IfcTessellatedFaceSet,entity_descriptor_map.find(Type::IfcTessellatedItem)->second);
current->add("Coordinates",false,IfcUtil::Argument_ENTITY_INSTANCE,Type::IfcCartesianPointList3D);
current->add("Normals",true,IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE,Type::IfcParameterValue);
current->add("Closed",true,IfcUtil::Argument_BOOL,Type::IfcBoolean);
current = entity_descriptor_map[Type::IfcToroidalSurface] = new IfcEntityDescriptor(Type::IfcToroidalSurface,entity_descriptor_map.find(Type::IfcElementarySurface)->second);
current->add("MajorRadius",false,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current->add("MinorRadius",false,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current = entity_descriptor_map[Type::IfcTransportElementType] = new IfcEntityDescriptor(Type::IfcTransportElementType,entity_descriptor_map.find(Type::IfcElementType)->second);
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcTransportElementTypeEnum);
current = entity_descriptor_map[Type::IfcTriangulatedFaceSet] = new IfcEntityDescriptor(Type::IfcTriangulatedFaceSet,entity_descriptor_map.find(Type::IfcTessellatedFaceSet)->second);
current->add("Normals",true,IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE,Type::IfcParameterValue);
current->add("Closed",true,IfcUtil::Argument_BOOL,Type::IfcBoolean);
current->add("CoordIndex",false,IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT,Type::IfcPositiveInteger);
current->add("NormalIndex",true,IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT,Type::IfcPositiveInteger);
current->add("PnIndex",true,IfcUtil::Argument_AGGREGATE_OF_INT,Type::IfcPositiveInteger);
current = entity_descriptor_map[Type::IfcWindowLiningProperties] = new IfcEntityDescriptor(Type::IfcWindowLiningProperties,entity_descriptor_map.find(Type::IfcPreDefinedPropertySet)->second);
current->add("LiningDepth",true,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current->add("LiningThickness",true,IfcUtil::Argument_DOUBLE,Type::IfcNonNegativeLengthMeasure);
@@ -2037,6 +2048,8 @@ void InitDescriptorMap() {
current->add("SelfIntersect",true,IfcUtil::Argument_BOOL,Type::IfcBoolean);
current = entity_descriptor_map[Type::IfcInterceptorType] = new IfcEntityDescriptor(Type::IfcInterceptorType,entity_descriptor_map.find(Type::IfcFlowTreatmentDeviceType)->second);
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcInterceptorTypeEnum);
current = entity_descriptor_map[Type::IfcIntersectionCurve] = new IfcEntityDescriptor(Type::IfcIntersectionCurve,entity_descriptor_map.find(Type::IfcSurfaceCurve)->second);
current = entity_descriptor_map[Type::IfcInventory] = new IfcEntityDescriptor(Type::IfcInventory,entity_descriptor_map.find(Type::IfcGroup)->second);
current->add("PredefinedType",true,IfcUtil::Argument_ENUMERATION,Type::IfcInventoryTypeEnum);
current->add("Jurisdiction",true,IfcUtil::Argument_ENTITY_INSTANCE,Type::IfcActorSelect);
@@ -2095,6 +2108,10 @@ void InitDescriptorMap() {
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcPipeSegmentTypeEnum);
current = entity_descriptor_map[Type::IfcPlateType] = new IfcEntityDescriptor(Type::IfcPlateType,entity_descriptor_map.find(Type::IfcBuildingElementType)->second);
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcPlateTypeEnum);
current = entity_descriptor_map[Type::IfcPolygonalFaceSet] = new IfcEntityDescriptor(Type::IfcPolygonalFaceSet,entity_descriptor_map.find(Type::IfcTessellatedFaceSet)->second);
current->add("Closed",true,IfcUtil::Argument_BOOL,Type::IfcBoolean);
current->add("Faces",false,IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE,Type::IfcIndexedPolygonalFace);
current->add("PnIndex",true,IfcUtil::Argument_AGGREGATE_OF_INT,Type::IfcPositiveInteger);
current = entity_descriptor_map[Type::IfcPolyline] = new IfcEntityDescriptor(Type::IfcPolyline,entity_descriptor_map.find(Type::IfcBoundedCurve)->second);
current->add("Points",false,IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE,Type::IfcCartesianPoint);
current = entity_descriptor_map[Type::IfcPort] = new IfcEntityDescriptor(Type::IfcPort,entity_descriptor_map.find(Type::IfcProduct)->second);
@@ -2152,6 +2169,8 @@ void InitDescriptorMap() {
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcRoofTypeEnum);
current = entity_descriptor_map[Type::IfcSanitaryTerminalType] = new IfcEntityDescriptor(Type::IfcSanitaryTerminalType,entity_descriptor_map.find(Type::IfcFlowTerminalType)->second);
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcSanitaryTerminalTypeEnum);
current = entity_descriptor_map[Type::IfcSeamCurve] = new IfcEntityDescriptor(Type::IfcSeamCurve,entity_descriptor_map.find(Type::IfcSurfaceCurve)->second);
current = entity_descriptor_map[Type::IfcShadingDeviceType] = new IfcEntityDescriptor(Type::IfcShadingDeviceType,entity_descriptor_map.find(Type::IfcBuildingElementType)->second);
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcShadingDeviceTypeEnum);
current = entity_descriptor_map[Type::IfcSite] = new IfcEntityDescriptor(Type::IfcSite,entity_descriptor_map.find(Type::IfcSpatialStructureElement)->second);
@@ -2246,7 +2265,7 @@ void InitDescriptorMap() {
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcTendonTypeEnum);
current->add("NominalDiameter",true,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current->add("CrossSectionArea",true,IfcUtil::Argument_DOUBLE,Type::IfcAreaMeasure);
current->add("SheethDiameter",true,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current->add("SheathDiameter",true,IfcUtil::Argument_DOUBLE,Type::IfcPositiveLengthMeasure);
current = entity_descriptor_map[Type::IfcTransformerType] = new IfcEntityDescriptor(Type::IfcTransformerType,entity_descriptor_map.find(Type::IfcEnergyConversionDeviceType)->second);
current->add("PredefinedType",false,IfcUtil::Argument_ENUMERATION,Type::IfcTransformerTypeEnum);
current = entity_descriptor_map[Type::IfcTransportElement] = new IfcEntityDescriptor(Type::IfcTransportElement,entity_descriptor_map.find(Type::IfcElement)->second);
@@ -2904,6 +2923,7 @@ void InitDescriptorMap() {
values.push_back("ELEMENT");
values.push_back("PARTIAL");
values.push_back("PROVISIONFORVOID");
values.push_back("PROVISIONFORSPACE");
values.push_back("USERDEFINED");
values.push_back("NOTDEFINED");
enumeration_descriptor_map[Type::IfcBuildingElementProxyTypeEnum] = new IfcEnumerationDescriptor(Type::IfcBuildingElementProxyTypeEnum, values);
@@ -3548,7 +3568,7 @@ void InitDescriptorMap() {
values.push_back("EXTERNAL_WATER");
values.push_back("EXTERNAL_FIRE");
values.push_back("USERDEFINED");
values.push_back("NOTDEFIEND");
values.push_back("NOTDEFINED");
enumeration_descriptor_map[Type::IfcExternalSpatialElementTypeEnum] = new IfcEnumerationDescriptor(Type::IfcExternalSpatialElementTypeEnum, values);
values.clear(); values.reserve(128);
values.push_back("CENTRIFUGALFORWARDCURVED");
@@ -3968,6 +3988,11 @@ void InitDescriptorMap() {
values.push_back("NOTDEFINED");
enumeration_descriptor_map[Type::IfcPlateTypeEnum] = new IfcEnumerationDescriptor(Type::IfcPlateTypeEnum, values);
values.clear(); values.reserve(128);
values.push_back("CURVE3D");
values.push_back("PCURVE_S1");
values.push_back("PCURVE_S2");
enumeration_descriptor_map[Type::IfcPreferredSurfaceCurveRepresentation] = new IfcEnumerationDescriptor(Type::IfcPreferredSurfaceCurveRepresentation, values);
values.clear(); values.reserve(128);
values.push_back("ADVICE_CAUTION");
values.push_back("ADVICE_NOTE");
values.push_back("ADVICE_WARNING");
@@ -4227,6 +4252,7 @@ void InitDescriptorMap() {
values.push_back("TAPERED");
enumeration_descriptor_map[Type::IfcSectionTypeEnum] = new IfcEnumerationDescriptor(Type::IfcSectionTypeEnum, values);
values.clear(); values.reserve(128);
values.push_back("COSENSOR");
values.push_back("CO2SENSOR");
values.push_back("CONDUCTANCESENSOR");
values.push_back("CONTACTSENSOR");
@@ -4804,6 +4830,7 @@ void InitInverseMap() {
inverse_map[Type::IfcGridAxis].insert(std::make_pair("PartOfU", std::make_pair(Type::IfcGrid, 7)));
inverse_map[Type::IfcGridAxis].insert(std::make_pair("HasIntersections", std::make_pair(Type::IfcVirtualGridIntersection, 0)));
inverse_map[Type::IfcGroup].insert(std::make_pair("IsGroupedBy", std::make_pair(Type::IfcRelAssignsToGroup, 6)));
inverse_map[Type::IfcIndexedPolygonalFace].insert(std::make_pair("ToFaceSet", std::make_pair(Type::IfcPolygonalFaceSet, 2)));
inverse_map[Type::IfcLibraryInformation].insert(std::make_pair("LibraryInfoForObjects", std::make_pair(Type::IfcRelAssociatesLibrary, 5)));
inverse_map[Type::IfcLibraryInformation].insert(std::make_pair("HasLibraryReferences", std::make_pair(Type::IfcLibraryReference, 5)));
inverse_map[Type::IfcLibraryReference].insert(std::make_pair("LibraryRefForObjects", std::make_pair(Type::IfcRelAssociatesLibrary, 5)));
+138 -37
View File
File diff suppressed because one or more lines are too long
+184 -43
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -40,6 +40,7 @@ public:
it end();
IfcUtil::IfcBaseClass* operator[] (int i);
unsigned int size() const;
void reserve(unsigned capacity);
bool contains(IfcUtil::IfcBaseClass*) const;
template <class U>
typename U::list::ptr as() {
+9 -1
View File
@@ -39,6 +39,7 @@ public:
typedef boost::unordered_map<unsigned int, IfcUtil::IfcBaseClass*> entity_by_id_t;
typedef std::map<std::string, IfcSchema::IfcRoot*> entity_by_guid_t;
typedef std::map<unsigned int, std::vector<unsigned int> > entities_by_ref_t;
typedef std::map<unsigned int, IfcEntityList::ptr> ref_map_t;
typedef entity_by_id_t::const_iterator const_iterator;
class type_iterator : private entities_by_type_t::const_iterator {
@@ -62,7 +63,9 @@ public:
}
bool operator!=(const type_iterator& other) const {
return entities_by_type_t::const_iterator::operator!=(other);
const entities_by_type_t::const_iterator& self_ = *this;
const entities_by_type_t::const_iterator& other_ = other;
return self_ != other_;
}
};
@@ -75,6 +78,7 @@ private:
entities_by_type_t bytype;
entities_by_type_t bytype_excl;
entities_by_ref_t byref;
ref_map_t by_ref_cached_;
entity_by_guid_t byguid;
entity_entity_map_t entity_file_map;
@@ -144,6 +148,10 @@ public:
/// in the first function argument.
IfcEntityList::ptr traverse(IfcUtil::IfcBaseClass* instance, int max_level=-1);
/// Marks entity as modified so that potential cache for it is invalidated.
/// @todo Currently the whole cache is invalidated. Implement more fine-grained invalidation.
void mark_entity_as_modified(int id);
#ifdef USE_MMAP
bool Init(const std::string& fn, bool mmap=false);
#else
+90 -26
View File
@@ -30,35 +30,59 @@
#include <iostream>
#include <algorithm>
using boost::property_tree::ptree;
namespace {
static const char* severity_strings[] = {"Notice", "Warning", "Error"};
template <typename T>
struct severity_strings {
static const std::array<std::basic_string<T>, 3> value;
};
void plain_text_message(std::ostream& os, const boost::optional<IfcSchema::IfcProduct*>& current_product, Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity) {
os << "[" << severity_strings[type] << "] ";
template <>
const std::array<std::basic_string<char>, 3> severity_strings<char>::value = { "Notice", "Warning", "Error" };
template <>
const std::array<std::basic_string<wchar_t>, 3> severity_strings<wchar_t>::value = { L"Notice", L"Warning", L"Error" };
template <typename T>
void plain_text_message(T& os, const boost::optional<IfcSchema::IfcProduct*>& current_product, Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity) {
os << "[" << severity_strings<typename T::char_type>::value[type] << "] ";
if (current_product) {
os << "{" << (*current_product)->GlobalId() << "} ";
os << "{" << (*current_product)->GlobalId().c_str() << "} ";
}
os << message << std::endl;
os << message.c_str() << std::endl;
if (entity) {
std::string instance_string = entity->toString();
if (instance_string.size() > 259) {
instance_string = instance_string.substr(0, 256) + "...";
}
os << instance_string << std::endl;
os << instance_string.c_str() << std::endl;
}
}
void json_message(std::ostream& os, const boost::optional<IfcSchema::IfcProduct*>& current_product, Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity) {
ptree pt;
pt.put("level", severity_strings[type]);
template <typename T>
std::basic_string<T> string_as(const std::string& s) {
std::basic_string<T> v;
v.assign(s.begin(), s.end());
return v;
}
template <typename T>
void json_message(T& os, const boost::optional<IfcSchema::IfcProduct*>& current_product, Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity) {
boost::property_tree::basic_ptree<std::basic_string<typename T::char_type>, std::basic_string<typename T::char_type> > pt;
// @todo this is crazy
static const typename T::char_type level_string[] = { 'l', 'e', 'v', 'e', 'l', 0 };
static const typename T::char_type product_string[] = { 'p', 'r', 'o', 'd', 'u', 'c', 't', 0 };
static const typename T::char_type message_string[] = { 'm', 'e', 's', 's', 'a', 'g', 'e', 0 };
static const typename T::char_type instance_string[] = { 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 0 };
pt.put(level_string, severity_strings<typename T::char_type>::value[type]);
if (current_product) {
pt.put("product", (**current_product).entity->toString());
pt.put(product_string, string_as<typename T::char_type>((**current_product).entity->toString()));
}
pt.put("message", message);
pt.put(message_string, string_as<typename T::char_type>(message));
if (entity) {
pt.put("instance", entity);
pt.put(instance_string, string_as<typename T::char_type>(entity->toString()));
}
boost::property_tree::write_json(os, pt, false);
}
@@ -68,20 +92,50 @@ void Logger::SetProduct(boost::optional<IfcSchema::IfcProduct*> product) {
current_product = product;
}
void Logger::SetOutput(std::ostream* l1, std::ostream* l2) {
void Logger::SetOutput(std::ostream* l1, std::ostream* l2) {
wlog1 = wlog2 = 0;
log1 = l1;
log2 = l2;
if ( ! log2 ) {
if (!log2) {
log2 = &log_stream;
}
}
void Logger::SetOutput(std::wostream* l1, std::wostream* l2) {
log1 = log2 = 0;
wlog1 = l1;
wlog2 = l2;
if (!wlog2) {
log2 = &log_stream;
}
}
template <typename T>
void Logger::log(T& log2, Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity) {
log2 << "[" << severity_strings<typename T::char_type>::value[type] << "] ";
if (current_product) {
log2 << "{" << (*current_product)->GlobalId().c_str() << "} ";
}
log2 << message.c_str() << std::endl;
if (entity) {
log2 << entity->toString().c_str() << std::endl;
}
}
void Logger::Message(Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity) {
if (log2 && type >= verbosity) {
if ((log2 || wlog2) && type >= verbosity) {
if (format == FMT_PLAIN) {
plain_text_message(*log2, current_product, type, message, entity);
if (log2) {
plain_text_message(*log2, current_product, type, message, entity);
} else if (wlog2) {
plain_text_message(*wlog2, current_product, type, message, entity);
}
} else if (format == FMT_JSON) {
json_message(*log2, current_product, type, message, entity);
if (log2) {
json_message(*log2, current_product, type, message, entity);
} else if (wlog2) {
json_message(*wlog2, current_product, type, message, entity);
}
}
}
}
@@ -90,18 +144,26 @@ void Logger::Message(Logger::Severity type, const std::exception& exception, Ifc
Message(type, exception.what(), entity);
}
template <typename T>
void status(T& log1, const std::string& message, bool new_line) {
log1 << message.c_str();
if (new_line) {
log1 << std::endl;
} else {
log1 << std::flush;
}
}
void Logger::Status(const std::string& message, bool new_line) {
if (log1) {
(*log1) << message;
if ( new_line ) (*log1) << std::endl;
else (*log1) << std::flush;
status(*log1, message, new_line);
} else if (wlog1) {
status(*wlog1, message, new_line);
}
}
void Logger::ProgressBar(int progress) {
if (log1) {
Status("\r[" + std::string(progress,'#') + std::string(50 - progress,' ') + "]", false);
}
Status("\r[" + std::string(progress,'#') + std::string(50 - progress,' ') + "]", false);
}
std::string Logger::GetLog() {
@@ -116,7 +178,9 @@ Logger::Format Logger::OutputFormat() { return format; }
std::ostream* Logger::log1 = 0;
std::ostream* Logger::log2 = 0;
std::wostream* Logger::wlog1 = 0;
std::wostream* Logger::wlog2 = 0;
std::stringstream Logger::log_stream;
Logger::Severity Logger::verbosity = Logger::LOG_NOTICE;
Logger::Format Logger::format = Logger::FMT_PLAIN;
boost::optional<IfcSchema::IfcProduct*> Logger::current_product;
boost::optional<IfcSchema::IfcProduct*> Logger::current_product;
+15
View File
@@ -42,14 +42,29 @@ public:
typedef enum { LOG_NOTICE, LOG_WARNING, LOG_ERROR } Severity;
typedef enum { FMT_PLAIN, FMT_JSON } Format;
private:
// To both stream variants need to exist at runtime or should this be a
// template argument of Logger or controlled using preprocessor directives?
static std::ostream* log1;
static std::ostream* log2;
static std::wostream* wlog1;
static std::wostream* wlog2;
static std::stringstream log_stream;
static Severity verbosity;
static Format format;
static boost::optional<IfcSchema::IfcProduct*> current_product;
template <typename T>
static void log(T& log2, Logger::Severity type, const std::string& message, IfcEntityInstanceData* entity);
public:
static void SetProduct(boost::optional<IfcSchema::IfcProduct*> product);
/// Determines to what stream respectively progress and errors are logged
static void SetOutput(std::wostream* l1, std::wostream* l2);
/// Determines to what stream respectively progress and errors are logged
static void SetOutput(std::ostream* l1, std::ostream* l2);
+28 -18
View File
@@ -25,10 +25,6 @@
#include <ctime>
#include <boost/circular_buffer.hpp>
#ifdef _MSC_VER
#include <Windows.h>
#endif
#include <boost/algorithm/string.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
@@ -39,6 +35,7 @@
#include "../ifcparse/IfcSpfStream.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcparse/IfcSIPrefix.h"
#include "../ifcparse/utils.h"
#ifdef USE_IFC4
#include "../ifcparse/Ifc4-latebound.h"
@@ -122,9 +119,8 @@ IfcSpfStream::IfcSpfStream(const std::string& fn)
, eof(false)
{
#ifdef _MSC_VER
int fn_buffer_size = MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, 0, 0);
wchar_t* fn_wide = new wchar_t[fn_buffer_size];
MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, fn_wide, fn_buffer_size);
std::wstring fn_ws = IfcUtil::path::from_utf8(fn);
const wchar_t* fn_wide = fn_ws.c_str();
#ifdef USE_MMAP
if (mmap) {
@@ -136,7 +132,6 @@ IfcSpfStream::IfcSpfStream(const std::string& fn)
}
#endif
delete[] fn_wide;
#else
#ifdef USE_MMAP
@@ -1213,7 +1208,9 @@ void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::Ar
if (this->file) {
register_inverse_visitor visitor(*this->file, *this);
apply_individual_instance_visitor(copy).apply(visitor);
}
this->file->mark_entity_as_modified(id_);
}
if (i < attributes_.size()) {
attributes_[i] = copy;
@@ -1429,6 +1426,11 @@ IfcEntityList::ptr IfcFile::traverse(IfcUtil::IfcBaseClass* instance, int max_le
return IfcParse::traverse(instance, max_level);
}
void IfcFile::mark_entity_as_modified(int /*id*/)
{
by_ref_cached_.clear();
}
void IfcFile::addEntities(IfcEntityList::ptr es) {
for( IfcEntityList::it i = es->begin(); i != es->end(); ++ i ) {
addEntity(*i);
@@ -1793,17 +1795,25 @@ IfcEntityList::ptr IfcFile::entitiesByType(const std::string& t) {
IfcEntityList::ptr IfcFile::entitiesByReference(int t) {
entities_by_ref_t::const_iterator it = byref.find(t);
IfcEntityList::ptr return_value;
IfcEntityList::ptr ret;
if (it != byref.end()) {
const std::vector<unsigned>& ids = it->second;
for (std::vector<unsigned>::const_iterator jt = ids.begin(); jt != ids.end(); ++jt) {
if (!return_value) {
return_value.reset(new IfcEntityList);
}
return_value->push(entityById(*jt));
}
ref_map_t::const_iterator cached_it = by_ref_cached_.find(t);
if (cached_it != by_ref_cached_.end()) {
ret = cached_it->second;
}
else {
if (it->second.size()) {
ret.reset(new IfcEntityList);
ret->reserve((unsigned)it->second.size());
const std::vector<unsigned>& ids = it->second;
for (std::vector<unsigned>::const_iterator jt = ids.begin(); jt != ids.end(); ++jt) {
ret->push(entityById(*jt));
}
}
by_ref_cached_[t] = ret;
}
}
return return_value;
return ret;
}
IfcUtil::IfcBaseClass* IfcFile::entityById(int id) {
+85
View File
@@ -17,8 +17,43 @@
* *
********************************************************************************/
#ifdef _MSC_VER
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef NOMSG
#define NOMSG NOMSG
#endif
#ifndef NODRAWTEXT
#define NODRAWTEXT NODRAWTEXT
#endif
#ifndef NOGDI
#define NOGDI NOGDI
#endif
#ifndef NOSERVICE
#define NOSERVICE NOSERVICE
#endif
#ifndef NOKERNEL
#define NOKERNEL NOKERNEL
#endif
#ifndef NOUSER
#define NOUSER NOUSER
#endif
#ifndef NOMCX
#define NOMCX NOMCX
#endif
#ifndef NOIME
#define NOIME NOIME
#endif
#include <Windows.h>
#endif
#include "../ifcparse/IfcBaseClass.h"
#include "../ifcparse/Argument.h"
#include "../ifcparse/utils.h"
#include "../ifcparse/IfcException.h"
#include "../ifcparse/IfcEntityList.h"
@@ -48,6 +83,7 @@ void IfcEntityList::push(const IfcEntityList::ptr& l) {
}
}
unsigned int IfcEntityList::size() const { return (unsigned int) ls.size(); }
void IfcEntityList::reserve(unsigned capacity) { ls.reserve((size_t)capacity); }
IfcEntityList::it IfcEntityList::begin() { return ls.begin(); }
IfcEntityList::it IfcEntityList::end() { return ls.end(); }
IfcUtil::IfcBaseClass* IfcEntityList::operator[] (int i) {
@@ -197,3 +233,52 @@ Argument* IfcUtil::IfcBaseEntity::getArgumentByName(const std::string& name) con
unsigned int i = IfcSchema::Type::GetAttributeIndex(type(), name);
return getArgument(i);
}
#ifdef _MSC_VER
std::string IfcUtil::path::to_utf8(const std::wstring& str) {
int buffer_size = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, 0, 0, 0, 0);
char* buffer = new char[buffer_size];
WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, buffer, buffer_size, 0, 0);
std::string str_utf8(buffer);
delete[] buffer;
return str_utf8;
}
std::wstring IfcUtil::path::from_utf8(const std::string& str) {
int buffer_size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, 0, 0);
wchar_t* buffer = new wchar_t[buffer_size];
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, buffer, buffer_size);
std::wstring str_wide(buffer);
delete[] buffer;
return str_wide;
}
IFC_PARSE_API bool IfcUtil::path::rename_file(const std::string& old_filename, const std::string& new_filename) {
std::wstring old_filename_w = from_utf8(old_filename);
std::wstring new_filename_w = from_utf8(new_filename);
delete_file(new_filename);
const bool success = !!MoveFileW(old_filename_w.c_str(), new_filename_w.c_str());
return success;
}
IFC_PARSE_API bool IfcUtil::path::delete_file(const std::string& filename) {
std::wstring filename_w = from_utf8(filename);
const bool success = !!DeleteFileW(filename_w.c_str());
return success;
}
#else
IFC_PARSE_API bool IfcUtil::path::rename_file(const std::string& old_filename, const std::string& new_filename) {
// Whether or not rename() replaces an existing file is implementation-specific,
// so remove() possible existing file always.
delete_file(new_filename);
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
}
IFC_PARSE_API bool IfcUtil::path::delete_file(const std::string& filename) {
return std::remove(filename.c_str());
}
#endif
+59
View File
@@ -0,0 +1,59 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../ifcparse/ifc_parse_api.h"
#include <string>
#ifndef IFCPARSE_UTILS_H
#define IFCPARSE_UTILS_H
namespace IfcUtil {
/// Replaces spaces and potentially other problem causing characters with underscores.
IFC_PARSE_API void sanitate_material_name(std::string &str);
IFC_PARSE_API void escape_xml(std::string &str);
IFC_PARSE_API void unescape_xml(std::string &str);
namespace path {
IFC_PARSE_API bool delete_file(const std::string& filename);
IFC_PARSE_API bool rename_file(const std::string& old_filename, const std::string& new_filename);
#ifdef _MSC_VER
/// Uses windows.h string conversion functions
IFC_PARSE_API std::string to_utf8(const std::wstring& str);
/// Uses windows.h string conversion functions
IFC_PARSE_API std::wstring from_utf8(const std::string& str);
#else
/// Identity operation
IFC_PARSE_API inline std::string to_utf8(const std::string& str) { return str; }
/// Identity operation
IFC_PARSE_API inline std::string from_utf8(const std::string& str) { return str; }
#endif
}
}
#endif
+1 -1
View File
@@ -290,7 +290,7 @@ if not %ERRORLEVEL%==0 goto :Error
findstr IfcOpenShell "%DEPENDENCY_DIR%\CMakeLists.txt">NUL
if not %ERRORLEVEL%==0 (
pushd "%DEPENDENCY_DIR%"
git apply ""%~dp0patches\%OCCT_VER%.patch"
git apply --ignore-whitespace ""%~dp0patches\%OCCT_VER%.patch"
popd
)
findstr IfcOpenShell "%DEPENDENCY_DIR%\CMakeLists.txt">NUL