mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 10:06:47 +00:00
Merge branch 'master' of https://github.com/IfcOpenShell/IfcOpenShell
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
[submodule "test/input"]
|
||||
path = test/input
|
||||
url = https://github.com/IfcOpenShell/files
|
||||
ignore = dirty
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
#include "../ifcparse/utils.h"
|
||||
|
||||
using namespace IfcSchema;
|
||||
|
||||
static std::string& collada_id(std::string& s)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
File diff suppressed because one or more lines are too long
+184
-43
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
Submodule test/input updated: 2abd02c2a3...a75c92451c
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user