mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 10:51:13 +00:00
Merge branch 'master' into v0.6.0
# Conflicts: # src/ifcconvert/IfcConvert.cpp # src/ifcgeom/IfcGeomRenderStyles.cpp # src/ifcgeom/IfcGeomWires.cpp # src/ifcparse/IfcLogger.cpp # src/ifcparse/IfcLogger.h # src/ifcparse/IfcParse.cpp # src/ifcparse/IfcUtil.cpp # src/serializers/ColladaSerializer.cpp # src/serializers/schema_dependent/XmlSerializer.cpp
This commit is contained in:
@@ -27,42 +27,46 @@
|
|||||||
|
|
||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "IfcBlender",
|
"name": "IfcBlender",
|
||||||
"description": "Import files in the "\
|
"description": "Import files in the "
|
||||||
"Industry Foundation Classes (.ifc) file format",
|
"Industry Foundation Classes (.ifc) file format",
|
||||||
"author": "Thomas Krijnen, IfcOpenShell",
|
"author": "Thomas Krijnen, IfcOpenShell",
|
||||||
"blender": (2, 73, 0),
|
"blender": (2, 80, 0),
|
||||||
"location": "File > Import",
|
"location": "File > Import",
|
||||||
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"\
|
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"
|
||||||
"_list/tickets?source=navbar",
|
"_list/tickets?source=navbar",
|
||||||
"category": "Import-Export"}
|
"category": "Import-Export"}
|
||||||
|
|
||||||
if "bpy" in locals():
|
if "bpy" in locals():
|
||||||
import imp
|
import importlib
|
||||||
if "ifcopenshell" in locals():
|
if "ifcopenshell" in locals():
|
||||||
imp.reload(ifcopenshell)
|
importlib.reload(ifcopenshell)
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import mathutils
|
import mathutils
|
||||||
from bpy.props import StringProperty, IntProperty, BoolProperty
|
from bpy.props import StringProperty, IntProperty, BoolProperty
|
||||||
from bpy_extras.io_utils import ImportHelper
|
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
|
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")
|
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")
|
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")
|
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")
|
description="The STEP Datatype keyword")
|
||||||
|
|
||||||
|
|
||||||
def import_ifc(filename, use_names, process_relations, blender_booleans):
|
def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||||
from . import ifcopenshell
|
from . import ifcopenshell
|
||||||
from .ifcopenshell import geom as ifcopenshell_geom
|
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 = ifcopenshell_geom.settings()
|
||||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
||||||
iterator = ifcopenshell_geom.iterator(settings, filename)
|
iterator = ifcopenshell_geom.iterator(settings, filename)
|
||||||
@@ -76,6 +80,11 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
openings = []
|
openings = []
|
||||||
old_progress = -1
|
old_progress = -1
|
||||||
print("Creating geometry...")
|
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:
|
while True:
|
||||||
ob = iterator.get()
|
ob = iterator.get()
|
||||||
|
|
||||||
@@ -86,54 +95,75 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
m = ob.transformation.matrix.data
|
m = ob.transformation.matrix.data
|
||||||
t = ob.type[0:21]
|
t = ob.type[0:21]
|
||||||
nm = ob.name if len(ob.name) and use_names else ob.guid
|
nm = ob.name if len(ob.name) and use_names else ob.guid
|
||||||
|
# MESH CREATION
|
||||||
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)]
|
|
||||||
|
|
||||||
# Depending on version, geometry.id will be either int or str
|
# Depending on version, geometry.id will be either int or str
|
||||||
me = bpy.data.meshes.new('mesh-%r' % ob.geometry.id)
|
mesh_name = 'mesh-%r' % ob.geometry.id
|
||||||
me.from_pydata(verts, [], faces)
|
if mesh_name in bpy.data.meshes:
|
||||||
me.validate()
|
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)]
|
||||||
|
|
||||||
def add_material(mname, props):
|
me = bpy.data.meshes.new(mesh_name)
|
||||||
if mname in bpy.data.materials:
|
me.from_pydata(verts, [], faces)
|
||||||
mat = bpy.data.materials[mname]
|
me.validate()
|
||||||
mat.use_fake_user = True
|
# MATERIAL CREATION
|
||||||
else:
|
def add_material(mname, props):
|
||||||
mat = bpy.data.materials.new(mname)
|
if mname in bpy.data.materials:
|
||||||
for k,v in props.items():
|
mat = bpy.data.materials[mname]
|
||||||
setattr(mat, k, v)
|
mat.use_fake_user = True
|
||||||
me.materials.append(mat)
|
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
|
needs_default = -1 in matids
|
||||||
if needs_default: add_material(t, {})
|
if needs_default:
|
||||||
|
add_material(t, {})
|
||||||
|
|
||||||
for mat in mats:
|
for mat in mats:
|
||||||
props = {}
|
props = {}
|
||||||
if mat.has_diffuse: props['diffuse_color'] = mat.diffuse
|
if mat.has_diffuse:
|
||||||
if mat.has_specular: props['specular_color'] = mat.specular
|
props['diffuse_color'] = mat.diffuse
|
||||||
if mat.has_transparency and mat.transparency > 0:
|
if mat.has_specular:
|
||||||
props['alpha'] = 1.0 - mat.transparency
|
props['specular_color'] = mat.specular
|
||||||
props['use_transparency'] = True
|
if mat.has_transparency and mat.transparency > 0:
|
||||||
if mat.has_specularity: props['specular_hardness'] = mat.specularity
|
props['transparency'] = mat.transparency
|
||||||
add_material(mat.name, props)
|
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)
|
bob = bpy.data.objects.new(nm, me)
|
||||||
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
|
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
|
||||||
[m[3], m[4], m[5], 0],
|
[m[3], m[4], m[5], 0],
|
||||||
[m[6], m[7], m[8], 0],
|
[m[6], m[7], m[8], 0],
|
||||||
[m[9], m[10], m[11], 1]))
|
[m[9], m[10], m[11], 1]))
|
||||||
if transpose_matrices: mat.transpose()
|
if transpose_matrices:
|
||||||
|
mat.transpose()
|
||||||
|
|
||||||
if process_relations:
|
if process_relations:
|
||||||
id_to_matrix[ob.id] = mat
|
id_to_matrix[ob.id] = mat
|
||||||
else:
|
else:
|
||||||
bob.matrix_world = mat
|
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.object.mode_set(mode='EDIT')
|
||||||
bpy.ops.mesh.normals_make_consistent()
|
bpy.ops.mesh.normals_make_consistent()
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
@@ -143,10 +173,11 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
|
|
||||||
if ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement':
|
if ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement':
|
||||||
if not (ob.type == 'IfcOpeningElement' and blender_booleans):
|
if not (ob.type == 'IfcOpeningElement' and blender_booleans):
|
||||||
bob.hide = bob.hide_render = True
|
bob.hide_viewport = bob.hide_render = True
|
||||||
bob.draw_type = 'WIRE'
|
bob.display_type = 'WIRE'
|
||||||
|
|
||||||
if ob.id not in id_to_object: id_to_object[ob.id] = []
|
if ob.id not in id_to_object:
|
||||||
|
id_to_object[ob.id] = []
|
||||||
id_to_object[ob.id].append(bob)
|
id_to_object[ob.id].append(bob)
|
||||||
|
|
||||||
if ob.parent_id > 0:
|
if ob.parent_id > 0:
|
||||||
@@ -155,11 +186,6 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
if blender_booleans and ob.type == 'IfcOpeningElement':
|
if blender_booleans and ob.type == 'IfcOpeningElement':
|
||||||
openings.append(ob.id)
|
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
|
progress = iterator.progress() // 2
|
||||||
if progress > old_progress:
|
if progress > old_progress:
|
||||||
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
||||||
@@ -194,10 +220,11 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
[m[3], m[4], m[5], 0],
|
[m[3], m[4], m[5], 0],
|
||||||
[m[6], m[7], m[8], 0],
|
[m[6], m[7], m[8], 0],
|
||||||
[m[9], m[10], m[11], 1]))
|
[m[9], m[10], m[11], 1]))
|
||||||
if transpose_matrices: mat.transpose()
|
if transpose_matrices:
|
||||||
|
mat.transpose()
|
||||||
id_to_matrix[parent_ob.id] = mat
|
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_id = parent_ob.id
|
||||||
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
|
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
|
||||||
@@ -220,7 +247,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
parent_matrix = id_to_matrix.get(parent_id, None)
|
parent_matrix = id_to_matrix.get(parent_id, None)
|
||||||
for ob in id_to_object[id]:
|
for ob in id_to_object[id]:
|
||||||
if parent_matrix:
|
if parent_matrix:
|
||||||
ob.matrix_local = parent_matrix.inverted() * matrix
|
ob.matrix_local = parent_matrix.inverted() @ matrix
|
||||||
else:
|
else:
|
||||||
ob.matrix_world = matrix
|
ob.matrix_world = matrix
|
||||||
|
|
||||||
@@ -236,7 +263,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
mod.operation = "DIFFERENCE"
|
mod.operation = "DIFFERENCE"
|
||||||
mod.object = opening_ob
|
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())
|
txt.from_string(iterator.getLog())
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -247,42 +274,51 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
|
|||||||
bl_label = "Import .ifc file"
|
bl_label = "Import .ifc file"
|
||||||
|
|
||||||
filename_ext = ".ifc"
|
filename_ext = ".ifc"
|
||||||
filter_glob = StringProperty(default="*.ifc", options={'HIDDEN'})
|
filter_glob: StringProperty(default="*.ifc", options={'HIDDEN'})
|
||||||
|
|
||||||
use_names = BoolProperty(name="Use entity names",
|
use_names: BoolProperty(name="Use entity names",
|
||||||
description="Use entity names rather than GlobalIds for objects",
|
description="Use entity names rather than "
|
||||||
default=True)
|
"GlobalIds for objects",
|
||||||
process_relations = BoolProperty(name="Process relations",
|
default=True)
|
||||||
description="Convert containment and aggregation" \
|
process_relations: BoolProperty(name="Process relations",
|
||||||
" relations to parenting" \
|
description="Convert containment and "
|
||||||
" (warning: may be slow on large files)",
|
"aggregation relations to parenting"
|
||||||
default=False)
|
" (warning: may be slow on large files)",
|
||||||
blender_booleans = BoolProperty(name="Use Blender booleans",
|
default=False)
|
||||||
description="Use Blender boolean modifiers for opening" \
|
blender_booleans: BoolProperty(name="Use Blender booleans",
|
||||||
" elements",
|
description="Use Blender boolean modifiers "
|
||||||
default=False)
|
"for opening elements",
|
||||||
|
default=False)
|
||||||
|
|
||||||
def execute(self, context):
|
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'},
|
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'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
def menu_func_import(self, context):
|
def menu_func_import(self, context):
|
||||||
self.layout.operator(ImportIFC.bl_idname,
|
self.layout.operator(ImportIFC.bl_idname,
|
||||||
text="Industry Foundation Classes (.ifc)")
|
text="Industry Foundation Classes (.ifc)")
|
||||||
|
|
||||||
|
|
||||||
|
classes = (
|
||||||
|
ImportIFC,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
bpy.utils.register_module(__name__)
|
for cls in classes:
|
||||||
bpy.types.INFO_MT_file_import.append(menu_func_import)
|
bpy.utils.register_class(cls)
|
||||||
|
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
bpy.utils.unregister_module(__name__)
|
for cls in reversed(classes):
|
||||||
bpy.types.INFO_MT_file_import.remove(menu_func_import)
|
bpy.utils.unregister_class(cls)
|
||||||
|
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
+227
-165
@@ -37,6 +37,8 @@
|
|||||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||||
|
|
||||||
|
#include "../ifcparse/utils.h"
|
||||||
|
|
||||||
#include <Standard_Version.hxx>
|
#include <Standard_Version.hxx>
|
||||||
|
|
||||||
#if OCC_VERSION_HEX < 0x60900
|
#if OCC_VERSION_HEX < 0x60900
|
||||||
@@ -55,6 +57,23 @@
|
|||||||
#include <vld.h>
|
#include <vld.h>
|
||||||
#endif
|
#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 DEFAULT_EXTENSION = "obj";
|
||||||
const std::string TEMP_FILE_EXTENSION = ".tmp";
|
const std::string TEMP_FILE_EXTENSION = ".tmp";
|
||||||
|
|
||||||
@@ -62,12 +81,12 @@ namespace po = boost::program_options;
|
|||||||
|
|
||||||
void print_version()
|
void print_version()
|
||||||
{
|
{
|
||||||
std::cout << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n";
|
cout_ << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_usage(bool suggest_help = true)
|
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"
|
<< "\n"
|
||||||
<< "Converts (the geometry in) an IFC file into one of the following formats:\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"
|
<< " .obj WaveFront OBJ (a .mtl file is also created)\n"
|
||||||
@@ -80,46 +99,43 @@ void print_usage(bool suggest_help = true)
|
|||||||
<< " .svg SVG Scalable Vector Graphics (2D floor plan)\n"
|
<< " .svg SVG Scalable Vector Graphics (2D floor plan)\n"
|
||||||
<< " .ifc IFC-SPF Industry Foundation Classes\n"
|
<< " .ifc IFC-SPF Industry Foundation Classes\n"
|
||||||
<< "\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) {
|
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
|
/// @todo Add help for single option
|
||||||
void print_options(const po::options_description& options)
|
void print_options(const po::options_description& options)
|
||||||
{
|
{
|
||||||
std::cout << "\n" << options;
|
#if defined(_MSC_VER) && defined(_UNICODE)
|
||||||
std::cout << std::endl;
|
// 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) {
|
template <typename T>
|
||||||
std::string::size_type dot = fn.find_last_of('.');
|
T change_extension(const T& fn, const T& ext) {
|
||||||
if (dot != std::string::npos) {
|
typename T::size_type dot = fn.find_last_of('.');
|
||||||
return fn.substr(0,dot+1) + ext;
|
if (dot != T::npos) {
|
||||||
|
return fn.substr(0, dot) + ext;
|
||||||
} else {
|
} else {
|
||||||
return fn + "." + ext;
|
return fn + ext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file_exists(const std::string& filename)
|
bool file_exists(const std::string& filename) {
|
||||||
{
|
std::ifstream file(IfcUtil::path::from_utf8(filename).c_str());
|
||||||
/// @todo Windows Unicode support
|
|
||||||
std::ifstream file(filename.c_str());
|
|
||||||
return file.good();
|
return file.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rename_file(const std::string& old_filename, const std::string& new_filename)
|
static std::basic_stringstream<path_t::value_type> log_stream;
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
void write_log(bool);
|
void write_log(bool);
|
||||||
void fix_quantities(IfcParse::IfcFile&, bool, bool, bool);
|
void fix_quantities(IfcParse::IfcFile&, bool, bool, bool);
|
||||||
std::string format_duration(time_t start, time_t end);
|
std::string format_duration(time_t start, time_t end);
|
||||||
@@ -153,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);
|
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;
|
std::string log_format;
|
||||||
|
|
||||||
po::options_description generic_options("Command line options");
|
po::options_description generic_options("Command line options");
|
||||||
generic_options.add_options()
|
generic_options.add_options()
|
||||||
("help,h", "display usage information")
|
("help,h", "display usage information")
|
||||||
@@ -172,8 +207,8 @@ int main(int argc, char** argv)
|
|||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
("mmap", "use memory-mapped file for input")
|
("mmap", "use memory-mapped file for input")
|
||||||
#endif
|
#endif
|
||||||
("input-file", po::value<std::string>(), "input IFC file")
|
("input-file", new po::typed_value<path_t, char_t>(0), "input IFC file")
|
||||||
("output-file", po::value<std::string>(), "output geometry file");
|
("output-file", new po::typed_value<path_t, char_t>(0), "output geometry file");
|
||||||
|
|
||||||
|
|
||||||
double deflection_tolerance;
|
double deflection_tolerance;
|
||||||
@@ -250,7 +285,7 @@ int main(int argc, char** argv)
|
|||||||
("exclude+", po::value<exclusion_traverse_filter>(&exclude_traverse_filter)->multitoken(),
|
("exclude+", po::value<exclusion_traverse_filter>(&exclude_traverse_filter)->multitoken(),
|
||||||
"Same as --exclude but applies filtering also to the decomposition and/or containment "
|
"Same as --exclude but applies filtering also to the decomposition and/or containment "
|
||||||
"of the filtered entity. See --include+ for more details.")
|
"of the filtered entity. See --include+ for more details.")
|
||||||
("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 "
|
"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."
|
"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. "
|
"Multiple filters of same type with different values can be inserted on their own lines. "
|
||||||
@@ -264,7 +299,7 @@ int main(int argc, char** argv)
|
|||||||
("generate-uvs",
|
("generate-uvs",
|
||||||
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
|
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
|
||||||
"Not guaranteed to work properly if used with --weld-vertices.")
|
"Not guaranteed to work properly if used with --weld-vertices.")
|
||||||
("default-material-file", po::value<std::string>(&default_material_filename),
|
("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"
|
"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.")
|
"if an object does not have any specified material in the IFC file.")
|
||||||
("validate", "Checks whether geometrical output conforms to the included explicit quantities.");
|
("validate", "Checks whether geometrical output conforms to the included explicit quantities.");
|
||||||
@@ -327,21 +362,21 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
po::variables_map vmap;
|
po::variables_map vmap;
|
||||||
try {
|
try {
|
||||||
po::store(po::command_line_parser(argc, argv).
|
po::store(command_line_parser(argc, argv).
|
||||||
options(cmdline_options).positional(positional_options).run(), vmap);
|
options(cmdline_options).positional(positional_options).run(), vmap);
|
||||||
} catch (const po::unknown_option& e) {
|
} 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();
|
print_usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} catch (const po::error_with_option_name& e) {
|
} 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;
|
return EXIT_FAILURE;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << "[Error] " << e.what() << "\n\n";
|
cerr_ << "[Error] " << e.what() << "\n\n";
|
||||||
print_usage();
|
print_usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cerr << "[Error] Unknown error parsing command line options\n\n";
|
cerr_ << "[Error] Unknown error parsing command line options\n\n";
|
||||||
print_usage();
|
print_usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -376,11 +411,11 @@ int main(int argc, char** argv)
|
|||||||
const bool generate_uvs = vmap.count("generate-uvs") != 0;
|
const bool generate_uvs = vmap.count("generate-uvs") != 0;
|
||||||
const bool validate = vmap.count("validate") != 0;
|
const bool validate = vmap.count("validate") != 0;
|
||||||
|
|
||||||
if (!quiet || vmap.count("version")) {
|
if (!quiet || vmap.count("version")) {
|
||||||
print_version();
|
print_version();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vmap.count("version")) {
|
if (vmap.count("version")) {
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
} else if (vmap.count("help")) {
|
} else if (vmap.count("help")) {
|
||||||
print_usage(false);
|
print_usage(false);
|
||||||
@@ -392,69 +427,6 @@ int main(int argc, char** argv)
|
|||||||
return EXIT_FAILURE;
|
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) {
|
if (vmap.count("log-format") == 1) {
|
||||||
boost::to_lower(log_format);
|
boost::to_lower(log_format);
|
||||||
if (log_format == "plain") {
|
if (log_format == "plain") {
|
||||||
@@ -468,23 +440,115 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = 0;
|
IfcParse::IfcFile* ifc_file = 0;
|
||||||
|
|
||||||
|
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");
|
||||||
|
IFC = IfcUtil::path::from_utf8(".ifc");
|
||||||
|
|
||||||
// @todo clean up serializer selection
|
// @todo clean up serializer selection
|
||||||
// @todo detect program options that conflict with the chosen serializer
|
// @todo detect program options that conflict with the chosen serializer
|
||||||
if (output_extension == ".xml") {
|
if (output_extension == XML) {
|
||||||
int exit_code = EXIT_FAILURE;
|
int exit_code = EXIT_FAILURE;
|
||||||
try {
|
try {
|
||||||
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)) {
|
||||||
time_t start, end;
|
time_t start, end;
|
||||||
time(&start);
|
time(&start);
|
||||||
XmlSerializer s(ifc_file, output_temp_filename);
|
XmlSerializer s(ifc_file, IfcUtil::path::to_utf8(output_temp_filename));
|
||||||
Logger::Status("Writing XML output...");
|
Logger::Status("Writing XML output...");
|
||||||
s.finalize();
|
s.finalize();
|
||||||
time(&end);
|
time(&end);
|
||||||
Logger::Status("Done! Conversion took " + format_duration(start, end));
|
Logger::Status("Done! Conversion took " + format_duration(start, end));
|
||||||
|
|
||||||
rename_file(output_temp_filename, output_filename);
|
IfcUtil::path::rename_file(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(output_filename));
|
||||||
exit_code = EXIT_SUCCESS;
|
exit_code = EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@@ -492,10 +556,12 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
write_log(!quiet);
|
write_log(!quiet);
|
||||||
return exit_code;
|
return exit_code;
|
||||||
} else if (output_extension == ".ifc") {
|
} else if (output_extension == IFC) {
|
||||||
int exit_code = EXIT_FAILURE;
|
int exit_code = EXIT_FAILURE;
|
||||||
try {
|
try {
|
||||||
if (init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
|
if (init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
|
||||||
|
time_t start, end;
|
||||||
|
time(&start);
|
||||||
std::ofstream fs(output_filename.c_str());
|
std::ofstream fs(output_filename.c_str());
|
||||||
if (fs.is_open()) {
|
if (fs.is_open()) {
|
||||||
if (vmap.count("calculate-quantities")) {
|
if (vmap.count("calculate-quantities")) {
|
||||||
@@ -506,6 +572,8 @@ int main(int argc, char** argv)
|
|||||||
} else {
|
} else {
|
||||||
Logger::Error("Unable to open output file for writing");
|
Logger::Error("Unable to open output file for writing");
|
||||||
}
|
}
|
||||||
|
time(&end);
|
||||||
|
Logger::Status("Done! Writing IFC took " + format_duration(start, end));
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
Logger::Error(e);
|
Logger::Error(e);
|
||||||
@@ -514,27 +582,6 @@ int main(int argc, char** argv)
|
|||||||
return exit_code;
|
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.
|
/// @todo Clean up this filter code further.
|
||||||
std::vector<geom_filter> used_filters;
|
std::vector<geom_filter> used_filters;
|
||||||
if (include_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_filter); }
|
if (include_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_filter); }
|
||||||
@@ -542,9 +589,9 @@ int main(int argc, char** argv)
|
|||||||
if (exclude_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_filter); }
|
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); }
|
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()) {
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,6 +599,20 @@ int main(int argc, char** argv)
|
|||||||
if (!layer_filter.values.empty()) { layer_filter.update_description(); Logger::Notice(layer_filter.description); }
|
if (!layer_filter.values.empty()) { layer_filter.update_description(); Logger::Notice(layer_filter.description); }
|
||||||
if (!attribute_filter.attribute_name.empty()) { attribute_filter.update_description(); Logger::Notice(layer_filter.description); }
|
if (!attribute_filter.attribute_name.empty()) { attribute_filter.update_description(); Logger::Notice(layer_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;
|
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.
|
/// @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);
|
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
|
||||||
@@ -581,29 +642,29 @@ int main(int argc, char** argv)
|
|||||||
settings.precision = precision;
|
settings.precision = precision;
|
||||||
|
|
||||||
boost::shared_ptr<GeometrySerializer> serializer; /**< @todo use std::unique_ptr when possible */
|
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.
|
// 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) {
|
if (!use_world_coords) {
|
||||||
Logger::Notice("Using world coords when writing WaveFront OBJ files");
|
Logger::Notice("Using world coords when writing WaveFront OBJ files");
|
||||||
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
|
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
|
#ifdef WITH_OPENCOLLADA
|
||||||
} else if (output_extension == ".dae") {
|
} else if (output_extension == DAE) {
|
||||||
serializer = boost::make_shared<ColladaSerializer>(output_temp_filename, settings);
|
serializer = boost::make_shared<ColladaSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
|
||||||
#endif
|
#endif
|
||||||
} else if (output_extension == ".stp") {
|
} else if (output_extension == STP) {
|
||||||
serializer = boost::make_shared<StepSerializer>(output_temp_filename, settings);
|
serializer = boost::make_shared<StepSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
|
||||||
} else if (output_extension == ".igs") {
|
} else if (output_extension == IGS) {
|
||||||
#if OCC_VERSION_HEX < 0x60900
|
#if OCC_VERSION_HEX < 0x60900
|
||||||
// According to https://tracker.dev.opencascade.org/view.php?id=25689 something has been fixed in 6.9.0
|
// According to https://tracker.dev.opencascade.org/view.php?id=25689 something has been fixed in 6.9.0
|
||||||
IGESControl_Controller::Init(); // work around Open Cascade bug
|
IGESControl_Controller::Init(); // work around Open Cascade bug
|
||||||
#endif
|
#endif
|
||||||
serializer = boost::make_shared<IgesSerializer>(output_temp_filename, settings);
|
serializer = boost::make_shared<IgesSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
|
||||||
} else if (output_extension == ".svg") {
|
} else if (output_extension == SVG) {
|
||||||
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
|
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) {
|
if (vmap.count("section-height") != 0) {
|
||||||
Logger::Notice("Overriding section height");
|
Logger::Notice("Overriding section height");
|
||||||
static_cast<SvgSerializer*>(serializer.get())->setSectionHeight(section_height);
|
static_cast<SvgSerializer*>(serializer.get())->setSectionHeight(section_height);
|
||||||
@@ -612,18 +673,18 @@ int main(int argc, char** argv)
|
|||||||
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
|
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "[Error] Unknown output filename extension '" + output_extension + "'\n";
|
cerr_ << "[Error] Unknown output filename extension '" << output_extension << "'\n";
|
||||||
write_log(!quiet);
|
write_log(!quiet);
|
||||||
print_usage();
|
print_usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_element_hierarchy && output_extension != ".dae") {
|
if (use_element_hierarchy && output_extension != DAE) {
|
||||||
std::cerr << "[Error] --use-element-hierarchy can be used only with .dae output.\n";
|
cerr_ << "[Error] --use-element-hierarchy can be used only with .dae output.\n";
|
||||||
/// @todo Lots of duplicate error-and-exit code.
|
/// @todo Lots of duplicate error-and-exit code.
|
||||||
write_log(!quiet);
|
write_log(!quiet);
|
||||||
print_usage();
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,7 +704,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!serializer->ready()) {
|
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);
|
write_log(!quiet);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -651,9 +712,9 @@ int main(int argc, char** argv)
|
|||||||
time_t start,end;
|
time_t start,end;
|
||||||
time(&start);
|
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);
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,7 +723,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
|
/// @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.
|
/// and for a case we found no entities that satisfy our filtering criteria.
|
||||||
Logger::Notice("No geometrical elements found or none succesfully converted");
|
Logger::Notice("No geometrical elements found or none succesfully converted");
|
||||||
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);
|
write_log(!quiet);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -697,8 +758,8 @@ int main(int argc, char** argv)
|
|||||||
offset[2] = -center.Z();
|
offset[2] = -center.Z();
|
||||||
} else {
|
} else {
|
||||||
if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) {
|
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";
|
cerr_ << "[Error] Invalid use of --model-offset\n";
|
||||||
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
|
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
|
||||||
print_options(serializer_options);
|
print_options(serializer_options);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -776,10 +837,10 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
// Renaming might fail (e.g. maybe the existing file was open in a viewer application)
|
// 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.
|
// 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) {
|
if (!successful) {
|
||||||
Logger::Error("Unable to write output file '" + output_filename + "', see '" +
|
cerr_ << "Unable to write output file '" << output_filename << "', see '" <<
|
||||||
output_temp_filename + "' for the conversion result.");
|
output_temp_filename << "' for the conversion result.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validate && Logger::MaxSeverity() >= Logger::LOG_ERROR) {
|
if (validate && Logger::MaxSeverity() >= Logger::LOG_ERROR) {
|
||||||
@@ -819,12 +880,12 @@ std::string format_duration(time_t start, time_t end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void write_log(bool header) {
|
void write_log(bool header) {
|
||||||
std::string log = log_stream.str();
|
path_t log = log_stream.str();
|
||||||
if (!log.empty()) {
|
if (!log.empty()) {
|
||||||
if (header) {
|
if (header) {
|
||||||
std::cout << "\nLog:\n";
|
cout_ << "\nLog:\n";
|
||||||
}
|
}
|
||||||
std::cout << log << std::endl;
|
cout_ << log << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,7 +916,7 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file,
|
|||||||
}
|
}
|
||||||
time(&end);
|
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)); }
|
else { Logger::Status("Parsing input file took " + format_duration(start, end)); }
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -868,7 +929,7 @@ bool append_filter(const std::string& type, const std::vector<std::string>& valu
|
|||||||
parse_filter(temp, values);
|
parse_filter(temp, values);
|
||||||
// Merge values only if type and arg match.
|
// 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)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
filter.type = temp.type;
|
filter.type = temp.type;
|
||||||
@@ -884,9 +945,10 @@ size_t read_filters_from_file(
|
|||||||
exclusion_filter& exclude_filter,
|
exclusion_filter& exclude_filter,
|
||||||
exclusion_traverse_filter& exclude_traverse_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()) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,11 +983,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_filter)) { ++num_filters; } }
|
||||||
else if (type == "exclude+") { if (append_filter("exclude+", values, exclude_traverse_filter)) { ++num_filters; } }
|
else if (type == "exclude+") { if (append_filter("exclude+", values, exclude_traverse_filter)) { ++num_filters; } }
|
||||||
else {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
} catch(...) {
|
} 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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -924,7 +924,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
|
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
|
||||||
gp_Trsf directrix, position;
|
gp_Trsf directrix;
|
||||||
TopoDS_Shape face;
|
TopoDS_Shape face;
|
||||||
TopoDS_Wire wire, section;
|
TopoDS_Wire wire, section;
|
||||||
|
|
||||||
@@ -1003,7 +1003,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
|
|||||||
if (has_position) {
|
if (has_position) {
|
||||||
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
|
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
|
||||||
// and therefore has a unit scale factor
|
// and therefore has a unit scale factor
|
||||||
shape.Move(position);
|
shape.Move(trsf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1152,9 +1152,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_
|
|||||||
|
|
||||||
// IfcElementarySurface.Position has unit scale factor
|
// IfcElementarySurface.Position has unit scale factor
|
||||||
#if OCC_VERSION_HEX < 0x60502
|
#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
|
#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
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -875,44 +875,52 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIndexedPolyCurve* l, TopoDS_Wi
|
|||||||
|
|
||||||
BRepBuilderAPI_MakeWire w;
|
BRepBuilderAPI_MakeWire w;
|
||||||
|
|
||||||
IfcEntityList::ptr segments = l->Segments();
|
if(l->hasSegments()) {
|
||||||
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
|
IfcEntityList::ptr segments = l->Segments();
|
||||||
IfcUtil::IfcBaseClass* segment = *it;
|
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
|
||||||
if (segment->declaration().is(IfcSchema::IfcLineIndex::Class())) {
|
IfcUtil::IfcBaseClass* segment = *it;
|
||||||
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
|
if (segment->declaration().is(IfcSchema::IfcLineIndex::Class())) {
|
||||||
std::vector<int> indices = *line;
|
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
|
||||||
gp_Pnt previous;
|
std::vector<int> indices = *line;
|
||||||
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
|
gp_Pnt previous;
|
||||||
if (*jt < 1 || *jt > max_index) {
|
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
|
||||||
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(*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];
|
} else if (segment->declaration().is(IfcSchema::IfcArcIndex::Class())) {
|
||||||
if (jt != indices.begin()) {
|
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
|
||||||
w.Add(BRepBuilderAPI_MakeEdge(previous, current));
|
std::vector<int> indices = *arc;
|
||||||
|
if (indices.size() != 3) {
|
||||||
|
throw IfcParse::IfcException("Invalid IfcArcIndex encountered");
|
||||||
}
|
}
|
||||||
previous = current;
|
for (int i = 0; i < 3; ++i) {
|
||||||
}
|
const int& idx = indices[i];
|
||||||
} else if (segment->declaration().is(IfcSchema::IfcArcIndex::Class())) {
|
if (idx < 1 || idx > max_index) {
|
||||||
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
|
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(idx));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
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 " + segment->declaration().name());
|
||||||
}
|
}
|
||||||
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 " + segment->declaration().name());
|
|
||||||
}
|
}
|
||||||
}
|
} 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();
|
result = w.Wire();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ void IfcGeom::set_default_style_file(const std::string& json_file) {
|
|||||||
if (!default_materials_initialized) InitDefaultMaterials();
|
if (!default_materials_initialized) InitDefaultMaterials();
|
||||||
default_materials.clear();
|
default_materials.clear();
|
||||||
|
|
||||||
|
// @todo this will probably need to be updated for UTF-8 paths on Windows
|
||||||
pt::ptree root;
|
pt::ptree root;
|
||||||
pt::read_json(json_file, root);
|
pt::read_json(json_file, root);
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,6 @@ namespace IfcUtil {
|
|||||||
IFC_PARSE_API const char* ArgumentTypeToString(ArgumentType argument_type);
|
IFC_PARSE_API const char* ArgumentTypeToString(ArgumentType argument_type);
|
||||||
|
|
||||||
IFC_PARSE_API bool valid_binary_string(const std::string& s);
|
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 {
|
class IFC_PARSE_API Argument {
|
||||||
|
|||||||
+94
-29
@@ -32,58 +32,113 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using boost::property_tree::ptree;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static const char* severity_strings[] = {"Notice", "Warning", "Error"};
|
|
||||||
|
|
||||||
void plain_text_message(std::ostream& os, const boost::optional<IfcUtil::IfcBaseClass*>& current_product, Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
|
template <typename T>
|
||||||
os << "[" << severity_strings[type] << "] ";
|
struct severity_strings {
|
||||||
|
static const std::array<std::basic_string<T>, 3> value;
|
||||||
|
};
|
||||||
|
|
||||||
|
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<IfcUtil::IfcBaseClass*>& current_product, Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
|
||||||
|
os << "[" << severity_strings<typename T::char_type>::value[type] << "] ";
|
||||||
if (current_product) {
|
if (current_product) {
|
||||||
std::string global_id = *(**current_product).data().getArgument((**current_product).declaration().as_entity()->attribute_index("GlobalId"));
|
std::string global_id = *(**current_product).get("GlobalId"));
|
||||||
os << "{" << global_id << "} ";
|
os << "{" << global_id.c_str() << "} ";
|
||||||
}
|
}
|
||||||
os << message << std::endl;
|
os << message.c_str() << std::endl;
|
||||||
if (instance) {
|
if (instance) {
|
||||||
std::string instance_string = instance->data().toString();
|
std::string instance_string = entity->data().toString();
|
||||||
if (instance_string.size() > 259) {
|
if (instance_string.size() > 259) {
|
||||||
instance_string = instance_string.substr(0, 256) + "...";
|
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<IfcUtil::IfcBaseClass*>& current_product, Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
|
template <typename T>
|
||||||
ptree pt;
|
std::basic_string<T> string_as(const std::string& s) {
|
||||||
pt.put("level", severity_strings[type]);
|
std::basic_string<T> v;
|
||||||
|
v.assign(s.begin(), s.end());
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void json_message(T& os, const boost::optional<IfcUtil::IfcBaseClass*>& current_product, Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
|
||||||
|
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) {
|
if (current_product) {
|
||||||
pt.put("product", (**current_product).data().toString());
|
pt.put(product_string, string_as<typename T::char_type>((**current_product).data().toString()));
|
||||||
}
|
}
|
||||||
pt.put("message", message);
|
pt.put(message_string, string_as<typename T::char_type>(message));
|
||||||
if (instance) {
|
if (instance) {
|
||||||
pt.put("instance", instance->data().toString());
|
pt.put(instance_string, string_as<typename T::char_type>(instance->data().toString()));
|
||||||
}
|
}
|
||||||
boost::property_tree::write_json(os, pt, false);
|
boost::property_tree::write_json(os, pt, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logger::SetProduct(boost::optional<IfcUtil::IfcBaseClass*> 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;
|
log1 = l1;
|
||||||
log2 = l2;
|
log2 = l2;
|
||||||
if ( ! log2 ) {
|
if (!log2) {
|
||||||
log2 = &log_stream;
|
log2 = &log_stream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::Message(Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
|
void Logger::SetOutput(std::wostream* l1, std::wostream* l2) {
|
||||||
if (type > max_severity) {
|
log1 = log2 = 0;
|
||||||
max_severity = type;
|
wlog1 = l1;
|
||||||
|
wlog2 = l2;
|
||||||
|
if (!wlog2) {
|
||||||
|
log2 = &log_stream;
|
||||||
}
|
}
|
||||||
if (log2 && type >= verbosity) {
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Logger::log(T& log2, Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
|
||||||
|
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 (instance) {
|
||||||
|
log2 << instance->data().toString().c_str() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Message(Logger::Severity type, const std::string& message, const IfcUtil::IfcBaseClass* instance) {
|
||||||
|
if ((log2 || wlog2) && type >= verbosity) {
|
||||||
if (format == FMT_PLAIN) {
|
if (format == FMT_PLAIN) {
|
||||||
plain_text_message(*log2, current_product, type, message, instance);
|
if (log2) {
|
||||||
|
plain_text_message(*log2, current_product, type, message, instance);
|
||||||
|
} else if (wlog2) {
|
||||||
|
plain_text_message(*wlog2, current_product, type, message, instance);
|
||||||
|
}
|
||||||
} else if (format == FMT_JSON) {
|
} else if (format == FMT_JSON) {
|
||||||
json_message(*log2, current_product, type, message, instance);
|
if (log2) {
|
||||||
|
json_message(*log2, current_product, type, message, instance);
|
||||||
|
} else if (wlog2) {
|
||||||
|
json_message(*wlog2, current_product, type, message, instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,18 +147,26 @@ void Logger::Message(Logger::Severity type, const std::exception& exception, con
|
|||||||
Message(type, std::string(exception.what()), instance);
|
Message(type, std::string(exception.what()), instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void Logger::Status(const std::string& message, bool new_line) {
|
||||||
if (log1) {
|
if (log1) {
|
||||||
(*log1) << message;
|
status(*log1, message, new_line);
|
||||||
if ( new_line ) (*log1) << std::endl;
|
} else if (wlog1) {
|
||||||
else (*log1) << std::flush;
|
status(*wlog1, message, new_line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::ProgressBar(int progress) {
|
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() {
|
std::string Logger::GetLog() {
|
||||||
@@ -120,6 +183,8 @@ Logger::Format Logger::OutputFormat() { return format; }
|
|||||||
|
|
||||||
std::ostream* Logger::log1 = 0;
|
std::ostream* Logger::log1 = 0;
|
||||||
std::ostream* Logger::log2 = 0;
|
std::ostream* Logger::log2 = 0;
|
||||||
|
std::wostream* Logger::wlog1 = 0;
|
||||||
|
std::wostream* Logger::wlog2 = 0;
|
||||||
std::stringstream Logger::log_stream;
|
std::stringstream Logger::log_stream;
|
||||||
Logger::Severity Logger::verbosity = Logger::LOG_NOTICE;
|
Logger::Severity Logger::verbosity = Logger::LOG_NOTICE;
|
||||||
Logger::Severity Logger::max_severity = Logger::LOG_NOTICE;
|
Logger::Severity Logger::max_severity = Logger::LOG_NOTICE;
|
||||||
|
|||||||
@@ -38,18 +38,30 @@ public:
|
|||||||
typedef enum { LOG_NOTICE, LOG_WARNING, LOG_ERROR } Severity;
|
typedef enum { LOG_NOTICE, LOG_WARNING, LOG_ERROR } Severity;
|
||||||
typedef enum { FMT_PLAIN, FMT_JSON } Format;
|
typedef enum { FMT_PLAIN, FMT_JSON } Format;
|
||||||
private:
|
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* log1;
|
||||||
static std::ostream* log2;
|
static std::ostream* log2;
|
||||||
|
|
||||||
|
static std::wostream* wlog1;
|
||||||
|
static std::wostream* wlog2;
|
||||||
|
|
||||||
static std::stringstream log_stream;
|
static std::stringstream log_stream;
|
||||||
|
|
||||||
static Severity verbosity;
|
static Severity verbosity;
|
||||||
static Format format;
|
static Format format;
|
||||||
static boost::optional<IfcUtil::IfcBaseClass*> current_product;
|
static boost::optional<IfcUtil::IfcBaseClass*> current_product;
|
||||||
static Severity max_severity;
|
static Severity max_severity;
|
||||||
public:
|
static boost::optional<IfcSchema::IfcProduct*> current_product;
|
||||||
|
|
||||||
static void SetProduct(boost::optional<IfcUtil::IfcBaseClass*> product) {
|
template <typename T>
|
||||||
current_product = product;
|
static void log(T& log2, Logger::Severity type, const std::string& message, IfcUtil::IfcBaseClass* instance);
|
||||||
}
|
public:
|
||||||
|
static void SetProduct(boost::optional<IfcUtil::IfcBaseClass*> 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
|
/// Determines to what stream respectively progress and errors are logged
|
||||||
static void SetOutput(std::ostream* l1, std::ostream* l2);
|
static void SetOutput(std::ostream* l1, std::ostream* l2);
|
||||||
|
|||||||
@@ -25,10 +25,6 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <boost/circular_buffer.hpp>
|
#include <boost/circular_buffer.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#include <Windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/math/special_functions/fpclassify.hpp>
|
#include <boost/math/special_functions/fpclassify.hpp>
|
||||||
|
|
||||||
@@ -40,6 +36,7 @@
|
|||||||
#include "../ifcparse/IfcFile.h"
|
#include "../ifcparse/IfcFile.h"
|
||||||
#include "../ifcparse/IfcSIPrefix.h"
|
#include "../ifcparse/IfcSIPrefix.h"
|
||||||
#include "../ifcparse/IfcSchema.h"
|
#include "../ifcparse/IfcSchema.h"
|
||||||
|
#include "../ifcparse/utils.h"
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
@@ -117,9 +114,8 @@ IfcSpfStream::IfcSpfStream(const std::string& fn)
|
|||||||
, eof(false)
|
, eof(false)
|
||||||
{
|
{
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
int fn_buffer_size = MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, 0, 0);
|
std::wstring fn_ws = IfcUtil::path::from_utf8(fn);
|
||||||
wchar_t* fn_wide = new wchar_t[fn_buffer_size];
|
const wchar_t* fn_wide = fn_ws.c_str();
|
||||||
MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, fn_wide, fn_buffer_size);
|
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
if (mmap) {
|
if (mmap) {
|
||||||
@@ -131,7 +127,6 @@ IfcSpfStream::IfcSpfStream(const std::string& fn)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
delete[] fn_wide;
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifdef USE_MMAP
|
#ifdef USE_MMAP
|
||||||
|
|||||||
@@ -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/IfcBaseClass.h"
|
||||||
#include "../ifcparse/Argument.h"
|
#include "../ifcparse/Argument.h"
|
||||||
|
#include "../ifcparse/utils.h"
|
||||||
#include "../ifcparse/IfcException.h"
|
#include "../ifcparse/IfcException.h"
|
||||||
#include "../ifcparse/IfcEntityList.h"
|
#include "../ifcparse/IfcEntityList.h"
|
||||||
|
|
||||||
@@ -241,3 +276,51 @@ IfcUtil::ArgumentType IfcUtil::from_parameter_type(const IfcParse::parameter_typ
|
|||||||
|
|
||||||
return IfcUtil::Argument_UNKNOWN;
|
return IfcUtil::Argument_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -34,6 +34,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "../ifcparse/utils.h"
|
||||||
|
|
||||||
static std::string& collada_id(std::string& s)
|
static std::string& collada_id(std::string& s)
|
||||||
{
|
{
|
||||||
IfcUtil::sanitate_material_name(s);
|
IfcUtil::sanitate_material_name(s);
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ private:
|
|||||||
ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer,
|
ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer,
|
||||||
bool double_precision)
|
bool double_precision)
|
||||||
: filename(fn)
|
: filename(fn)
|
||||||
, stream(filename, double_precision)
|
, stream(COLLADASW::NativeString(filename.c_str(), COLLADASW::NativeString::ENCODING_UTF8), double_precision)
|
||||||
, scene(scene_name, stream, _serializer)
|
, scene(scene_name, stream, _serializer)
|
||||||
, materials(stream, _serializer)
|
, materials(stream, _serializer)
|
||||||
, geometries(stream, _serializer)
|
, geometries(stream, _serializer)
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
* *
|
* *
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include "OpenCascadeBasedSerializer.h"
|
||||||
|
|
||||||
|
#include "../ifcparse/utils.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -24,13 +28,11 @@
|
|||||||
#include <Standard_Version.hxx>
|
#include <Standard_Version.hxx>
|
||||||
#include <BRepBuilderAPI_Transform.hxx>
|
#include <BRepBuilderAPI_Transform.hxx>
|
||||||
|
|
||||||
#include "OpenCascadeBasedSerializer.h"
|
|
||||||
|
|
||||||
bool OpenCascadeBasedSerializer::ready() {
|
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();
|
bool succeeded = test_file.is_open();
|
||||||
test_file.close();
|
test_file.close();
|
||||||
remove(out_filename.c_str());
|
IfcUtil::path::delete_file(out_filename);
|
||||||
return succeeded;
|
return succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#include "../serializers/GeometrySerializer.h"
|
#include "../serializers/GeometrySerializer.h"
|
||||||
#include "../serializers/util.h"
|
#include "../serializers/util.h"
|
||||||
|
|
||||||
|
#include "../ifcparse/utils.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@@ -46,7 +48,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
SvgSerializer(const std::string& out_filename, const SerializerSettings& settings)
|
SvgSerializer(const std::string& out_filename, const SerializerSettings& settings)
|
||||||
: GeometrySerializer(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())
|
, xmin(+std::numeric_limits<double>::infinity())
|
||||||
, ymin(+std::numeric_limits<double>::infinity())
|
, ymin(+std::numeric_limits<double>::infinity())
|
||||||
, xmax(-std::numeric_limits<double>::infinity())
|
, xmax(-std::numeric_limits<double>::infinity())
|
||||||
|
|||||||
@@ -22,9 +22,22 @@
|
|||||||
|
|
||||||
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
|
||||||
|
|
||||||
|
#include "../ifcparse/utils.h"
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iomanip>
|
#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() {
|
bool WaveFrontOBJSerializer::ready() {
|
||||||
return obj_stream.is_open() && mtl_stream.is_open();
|
return obj_stream.is_open() && mtl_stream.is_open();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,17 +35,7 @@ private:
|
|||||||
unsigned int vcount_total;
|
unsigned int vcount_total;
|
||||||
std::set<std::string> materials;
|
std::set<std::string> materials;
|
||||||
public:
|
public:
|
||||||
WaveFrontOBJSerializer(const std::string& obj_filename, const std::string& mtl_filename, const SerializerSettings& settings)
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~WaveFrontOBJSerializer() {}
|
virtual ~WaveFrontOBJSerializer() {}
|
||||||
bool ready();
|
bool ready();
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
* *
|
* *
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
#include <boost/property_tree/xml_parser.hpp>
|
#include <boost/property_tree/xml_parser.hpp>
|
||||||
#include <boost/version.hpp>
|
#include <boost/version.hpp>
|
||||||
@@ -30,6 +28,7 @@
|
|||||||
|
|
||||||
#include "../../ifcparse/IfcSIPrefix.h"
|
#include "../../ifcparse/IfcSIPrefix.h"
|
||||||
#include "../../ifcgeom/IfcGeom.h"
|
#include "../../ifcgeom/IfcGeom.h"
|
||||||
|
#include "../../ifcparse/utils.h"
|
||||||
|
|
||||||
using boost::property_tree::ptree;
|
using boost::property_tree::ptree;
|
||||||
|
|
||||||
@@ -549,5 +548,7 @@ void MAKE_TYPE_NAME(XmlSerializer)::finalize() {
|
|||||||
#else
|
#else
|
||||||
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
|
boost::property_tree::xml_writer_settings<char> settings('\t', 1);
|
||||||
#endif
|
#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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user