Compare commits

...

16 Commits

Author SHA1 Message Date
Stefano Beccaletto 62386c663a Added default constructor to IfcHierarchyHelper 2021-01-22 11:00:14 +01:00
Thomas Krijnen a10e852a35 Fixes for placement cloning that affected layersets 2019-09-22 14:01:35 +02:00
Thomas Krijnen 7f5d733ed8 Propagate static runtime settings to voxel tk 2019-09-22 12:57:36 +02:00
Thomas Krijnen cdfbde8f18 Subtract interior voxel volumes 2019-09-01 08:56:56 +02:00
Thomas Krijnen 0d7f6af681 Mesh compound prior to voxelization 2019-08-28 16:15:28 +02:00
Thomas Krijnen d76c599477 geom server client getattr; yield from process() 2019-08-28 14:56:09 +02:00
Thomas Krijnen c09de2c568 Test geom server voxels 2019-08-24 13:44:42 +02:00
Thomas Krijnen 3f7290cdc6 Lower voxel resolution, use padding 2019-08-23 14:59:31 +02:00
Thomas Krijnen 7bd4699f65 Update geom server client to parse entity bodies 2019-08-23 14:54:16 +02:00
Thomas Krijnen e137036bbb Update .travis.yml 2019-08-09 13:59:24 +02:00
Thomas Krijnen b1a0e2a62b Update .travis.yml 2019-08-09 11:59:04 +02:00
Thomas Krijnen a97577d272 Update .travis.yml 2019-08-09 11:53:20 +02:00
Thomas Krijnen 53bcb333da Update .travis.yml 2019-08-09 11:34:55 +02:00
Thomas Krijnen 49fb919fbc thread_local define for clang 2019-08-09 10:06:55 +02:00
Thomas Krijnen 5dbbd917d1 gcc and clang on travis 2019-08-08 12:13:06 +02:00
Thomas Krijnen 10d11031e5 Remove redundant occt library links to executables and python wrapper 2019-08-04 12:49:22 +02:00
10 changed files with 146 additions and 37 deletions
+5 -3
View File
@@ -1,7 +1,9 @@
language: cpp
compiler: gcc
compiler:
- gcc
- clang
os: linux
dist: xenial
dist: bionic
sudo: required
before_install:
@@ -36,7 +38,7 @@ script:
-DPYTHON_INCLUDE_DIR=/usr/include/python2.7 \
-DPYTHON_EXECUTABLE=/usr/bin/python2.7 \
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.a;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so.55;/usr/lib/x86_64-linux-gnu/libicudata.so.55" \
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.a;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so;/usr/lib/x86_64-linux-gnu/libicudata.so" \
-DGLTF_SUPPORT=On \
-DJSON_INCLUDE_DIR=/usr/include/json \
..
+2 -2
View File
@@ -709,7 +709,7 @@ set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES})
set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS "${CONVERT_PRECISION}")
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
# Only set RPATHs when building shared libraries (i.e. IfcParse and
@@ -733,7 +733,7 @@ file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp)
file(GLOB H_FILES ../src/ifcgeomserver/*.h)
set(SOURCE_FILES ${CPP_FILES} ${H_FILES})
ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${VOXEL_LIBRARIES})
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${Boost_LIBRARIES} ${VOXEL_LIBRARIES})
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
@@ -2115,8 +2115,8 @@ bool IfcGeom::Kernel::apply_folded_layerset(const ConversionResults& items, cons
for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) {
TopoDS_Shape a,b;
if (split_solid_by_shell(*(OpenCascadeShape*)it->Shape(), shells.First(), a, b)) {
result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement() ? it->Placement()->clone() : nullptr, new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement() ? it->Placement()->clone() : nullptr, new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style()));
} else {
continue;
}
@@ -2135,7 +2135,7 @@ bool IfcGeom::Kernel::apply_folded_layerset(const ConversionResults& items, cons
std::vector<TopoDS_Shape> slices;
if (split(*this, *(OpenCascadeShape*)it->Shape(), shells, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) {
for (size_t i = 0; i < slices.size(); ++i) {
result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(slices[i]), styles[i] ? styles[i] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement() ? it->Placement()->clone() : nullptr, new OpenCascadeShape(slices[i]), styles[i] ? styles[i] : &it->Style()));
}
} else {
return false;
@@ -2158,8 +2158,8 @@ bool IfcGeom::Kernel::apply_layerset(const ConversionResults& items, const std::
for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) {
TopoDS_Shape a,b;
if (split_solid_by_surface(*(OpenCascadeShape*)it->Shape(), surfaces[1], a, b)) {
result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement() ? it->Placement()->clone() : nullptr, new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement() ? it->Placement()->clone() : nullptr, new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style()));
} else {
continue;
}
@@ -2219,7 +2219,7 @@ bool IfcGeom::Kernel::apply_layerset(const ConversionResults& items, const std::
std::vector<TopoDS_Shape> slices;
if (split(*this, *(OpenCascadeShape*)it->Shape(), operands, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) {
for (size_t i = 0; i < slices.size(); ++i) {
result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(slices[i]), styles[i] ? styles[i] : &it->Style()));
result.push_back(ConversionResult(it->ItemId(), it->Placement() ? it->Placement()->clone() : nullptr, new OpenCascadeShape(slices[i]), styles[i] ? styles[i] : &it->Style()));
}
} else {
return false;
@@ -60,9 +60,9 @@ namespace IfcGeom {
const SurfaceStyle* style;
public:
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const SurfaceStyle* style)
: id(id), placement(placement->clone()), shape(shape->clone()), style(style) {}
: id(id), placement(placement ? placement->clone() : nullptr), shape(shape->clone()), style(style) {}
ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape)
: id(id), placement(placement->clone()), shape(shape->clone()), style(0) {}
: id(id), placement(placement ? placement->clone() : nullptr), shape(shape->clone()), style(0) {}
ConversionResult(int id, const ConversionResultShape* shape, const SurfaceStyle* style)
: id(id), placement(0), shape(shape->clone()), style(style) {}
ConversionResult(int id, const ConversionResultShape* shape)
+36 -5
View File
@@ -439,6 +439,7 @@ public:
static const std::string TOTAL_SURFACE_AREA = "TOTAL_SURFACE_AREA";
static const std::string TOTAL_SHAPE_VOLUME = "TOTAL_SHAPE_VOLUME";
static const std::string TOTAL_SHAPE_VOLUME_VOXELS = "TOTAL_SHAPE_VOLUME_VOXELS";
static const std::string SURFACE_AREA_ALONG_X = "SURFACE_AREA_ALONG_X";
static const std::string SURFACE_AREA_ALONG_Y = "SURFACE_AREA_ALONG_Y";
static const std::string SURFACE_AREA_ALONG_Z = "SURFACE_AREA_ALONG_Z";
@@ -463,6 +464,16 @@ public:
}
};
#ifdef USE_VOXELS
namespace {
void write_voxels(const std::string& fn, abstract_voxel_storage* voxels) {
voxel_writer w;
w.SetVoxels(voxels);
w.Write(fn);
}
}
#endif
class QuantityWriter_v1 : public EntityExtension {
private:
const IfcGeom::NativeElement<double, double>* elem_;
@@ -535,20 +546,40 @@ public:
bounds[1].get(i) = bbox_xyz[i + 3];
}
progress_writer silent;
auto surface = storage_for(bounds, 256U);
// At least one padding voxel need to be in place as the traversal happens outside
// of the surface voxel bounds and is subsequently inverted to find the interior
// voxels.
auto surface = storage_for(bounds, 256U, 4U, 16U);
processor proc(surface, silent);
// @todo is scanline entirely reliable due to rounding from float to int?
// This is also observed in voxec dump_surfaces().
// proc.use_scanline() = false;
BRepMesh_IncrementalMesh(compound, 0.001);
std::vector<std::pair<int, TopoDS_Compound > > geometries = { {1, compound} };
proc.process(geometries.begin(), geometries.end(), SURFACE(), output(MERGED()));
surface = (regular_voxel_storage*) proc.voxels();
double vsize = surface->voxel_size();
auto surface_count = surface->count();
traversal_voxel_filler_inverse filler;
auto volume = filler(surface);
auto volume_count = volume->count();
double total_volume = 0.;
if (surface->count() != 0) {
auto volume = filler(surface);
auto volume_count = volume->count();
auto inner_surface = (regular_voxel_storage*) volume->boolean_intersection(surface);
if (inner_surface->count() != 0) {
// Or, use a boolean intersection of surface and volume and subtract any subsequent
// interior void volumes.
auto inner_volume = filler(inner_surface);
volume_count -= inner_volume->count();
delete inner_volume;
}
delete inner_surface;
delete volume;
total_volume = (volume_count + surface_count / 2) * (vsize * vsize * vsize);
}
delete surface;
delete volume;
double total_volume = (volume_count + surface_count / 2) * (vsize * vsize * vsize);
put_json(TOTAL_SHAPE_VOLUME, total_volume);
put_json(TOTAL_SHAPE_VOLUME_VOXELS, total_volume);
}
#endif
@@ -40,27 +40,95 @@ class message_headers(object):
DEFLECTION = LOG + 1
SETTING = DEFLECTION + 1
CALCULATE_QUANTITIES = numpy.int32((1 << 4))
APPLY_LAYERSETS = numpy.int32((1 << 13))
def cast(data, dtype, n=None):
arr = numpy.frombuffer(data, dtype=dtype)
if n is None: return arr[0]
else: return arr
def read(stream, dtype, n=None):
data = stream.read(dtype().nbytes * (n or 1))
x = cast(data, dtype, n)
# print(x)
return x
def readString(s):
l = read(s, numpy.int32)
S = s.read(int(l)).decode('ascii')
while (l % 4 != 0):
s.read(1);
l += 1
# print(S)
return S
def readDoubleArray(s):
l = read(s, numpy.int32) // 8
return read(s, numpy.float64, int(l))
def readByteBuffer(s):
l = read(s, numpy.int32)
return s.read(int(l))
class entity_contents(object):
def __init__(self, data):
import json
from io import BytesIO
s = BytesIO(data)
self.structure = [
("id" , read(s, numpy.int32)),
("guid" , readString(s)),
("name" , readString(s)),
("type" , readString(s)),
("parentId" , read(s, numpy.int32)),
("matrix" , readDoubleArray(s)),
("repId" , read(s, numpy.int32)),
("positions" , readByteBuffer(s)),
("normals" , readByteBuffer(s)),
("indices" , readByteBuffer(s)),
("colors" , readByteBuffer(s)),
("materialIndices" , readByteBuffer(s)),
("extendedData" , json.loads(s.read().strip(b'\x00').decode('ascii').strip(' ')))
]
def __getattr__(self, k):
return [kv for kv in self.structure if kv[0] == k][0][1]
def __repr__(self):
def format(x):
a, b = x
if isinstance(b, bytes):
b = "<bytes>"
elif isinstance(b, dict):
padding = " " * (len(a) + 2)
b = ("\n".join("%s%%s: %%s" % padding % format(x) for x in b.items())).strip()
return a, b
return "ENTITY: \n" + "\n".join("%s: %s" % format(x) for x in self.structure)
content_factory = {
message_headers.ENTITY: entity_contents
}
identity = lambda x: x
def parse_contents(header, contents):
return (content_factory.get(header, identity))(contents)
message = namedtuple("message", ("header", "contents"))
def process(geomserver_exe, ifc_filename):
proc = subprocess.Popen([geomserver_exe], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
def cast(data, dtype, n=None):
arr = numpy.frombuffer(data, dtype=dtype)
if n is None: return arr[0]
else: return arr
def read(dtype, n=None):
data = proc.stdout.read(dtype().nbytes * (n or 1))
return cast(data, dtype, n)
def read_message(header_assertion=None):
header, size = read(numpy.int32, 2)
header, size = read(proc.stdout, numpy.int32, 2)
assert header_assertion is None or header_assertion == header
contents = b""
if size > 0:
contents = proc.stdout.read(size)
contents = parse_contents(header, contents)
return message(header, contents)
def write(header, contents=None):
@@ -79,14 +147,16 @@ def process(geomserver_exe, ifc_filename):
# @todo: no need to read the entire file in memory
s = open(ifc_filename, "rb").read()
write(message_headers.SETTING, [numpy.int32((1 << 4)), numpy.int32(1)])
write(message_headers.SETTING, [CALCULATE_QUANTITIES, numpy.int32(1)])
write(message_headers.SETTING, [APPLY_LAYERSETS, numpy.int32(1)])
write(message_headers.IFC_MODEL, [numpy.int32(len(s)), s, b"\x00" * ((4 - (len(s) % 4)) % 4)])
while True:
while True:
has_more = cast(read_message(message_headers.MORE).contents, numpy.int32) == 1
if not has_more: break
write(message_headers.GET)
print(read_message(message_headers.ENTITY).contents)
geom_data = read_message(message_headers.ENTITY).contents
yield geom_data
write(message_headers.NEXT)
write(message_headers.BYE)
@@ -100,4 +170,5 @@ if __name__ == "__main__":
exe_extension = ".exe" if platform.system() == 'Windows' else ""
exe = os.environ.get("IFCGEOMSERVER") or ("IfcGeomServer" + exe_extension)
for fn in sys.argv[1:]:
process(exe, fn)
for geom_data in process(exe, fn):
print(geom_data)
+1
View File
@@ -100,6 +100,7 @@ namespace {
template <typename Schema>
class IFC_PARSE_API IfcHierarchyHelper : public IfcParse::IfcFile {
public:
IfcHierarchyHelper(const IfcParse::schema_definition* schema) :IfcFile(schema) {}
template <class T>
T* addTriplet(double x, double y, double z) {
std::vector<double> a; a.push_back(x); a.push_back(y); a.push_back(z);
+3 -2
View File
@@ -49,8 +49,9 @@
#include "../ifcparse/IfcSpfStream.h"
/* gcc doesn't know _Thread_local from C11 yet */
#ifdef __GNUC__
#if defined(__clang__)
# define my_thread_local thread_local
#elif defined(__GNUC__)
# define my_thread_local __thread
#elif __STDC_VERSION__ >= 201112L
# define my_thread_local _Thread_local
+2 -2
View File
@@ -56,9 +56,9 @@ SET_SOURCE_FILES_PROPERTIES(IfcPython.i PROPERTIES CPLUSPLUS ON)
SWIG_ADD_MODULE(ifcopenshell_wrapper python IfcPython.i)
if("$ENV{LDFLAGS}" MATCHES ".undefined.suppress")
# On osx there is some state in the python dylib. With `-Wl,undefined,suppress` we can ignore the missing symbols at compile time.
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES})
else()
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${PYTHON_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
SWIG_LINK_LIBRARIES(ifcopenshell_wrapper ${IFCOPENSHELL_LIBRARIES} ${PYTHON_LIBRARIES})
endif()
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
SET_INSTALL_RPATHS(${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} "${IFCDIRS};${OCC_LIBRARY_DIR}")
+3
View File
@@ -391,11 +391,14 @@ set DEPENDENCY_DIR=%DEPS_DIR%\voxel
call :GitCloneAndCheckoutRevision https://github.com/opensourceBIM/voxelization_toolkit.git "%DEPENDENCY_DIR%"
IF NOT %ERRORLEVEL%==0 GOTO :Error
cd "%DEPENDENCY_DIR%"
if NOT "%USE_STATIC_RUNTIME%"=="FALSE" set STATIC_RUNTIME_1=-DUSE_STATIC_MSVC_RUNTIME=1
if "%USE_STATIC_RUNTIME%"=="FALSE" set STATIC_RUNTIME_1=-DUSE_STATIC_MSVC_RUNTIME=0
call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\voxel" ^
-DIFC_SUPPORT=Off ^
-DOCC_INCLUDE_DIR="%OCC_INCLUDE_DIR%" ^
-DOCC_LIBRARY_DIR="%OCC_LIBRARY_DIR%" ^
-DBOOST_ROOT="%DEPS_DIR%\boost_%BOOST_VER%" ^
%STATIC_RUNTIME_1% ^
-DBOOST_LIBRARYDIR="%DEPS_DIR%\boost_%BOOST_VER%\stage\vs%VS_VER%-%VS_PLATFORM%\lib"
IF NOT %ERRORLEVEL%==0 GOTO :Error
call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\voxel.sln" %BUILD_CFG%