From 0cb2c812274d7501a5df4552f3931313280f5253 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 15 May 2019 17:13:29 +0200 Subject: [PATCH] Rough draft of a client application for the C++ IfcGeomServer binary --- .../ifcopenshell/geom/client.py | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/ifcopenshell-python/ifcopenshell/geom/client.py diff --git a/src/ifcopenshell-python/ifcopenshell/geom/client.py b/src/ifcopenshell-python/ifcopenshell/geom/client.py new file mode 100644 index 0000000000..d4eca22783 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/geom/client.py @@ -0,0 +1,103 @@ +############################################################################### +# # +# 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 . # +# # +############################################################################### + +""" +Rough draft of a client application for the C++ IfcGeomServer binary +""" + +import os +import numpy +import subprocess + +from collections import namedtuple + +class message_headers(object): + HELLO = 0xff00 + IFC_MODEL = HELLO + 1 + GET = IFC_MODEL + 1 + ENTITY = GET + 1 + MORE = ENTITY + 1 + NEXT = MORE + 1 + BYE = NEXT + 1 + GET_LOG = BYE + 1 + LOG = GET_LOG + 1 + DEFLECTION = LOG + 1 + SETTING = DEFLECTION + 1 + +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) + assert header_assertion is None or header_assertion == header + contents = b"" + if size > 0: + contents = proc.stdout.read(size) + return message(header, contents) + + def write(header, contents=None): + if contents is None: contents = [] + proc.stdin.write(numpy.int32(header).tobytes()) + integers_as_int32 = list(map(lambda s: numpy.int32(s) if isinstance(s, int) else s, contents)) + to_bytes = list(map(lambda s: s.tobytes() if hasattr(s, 'tobytes') else s, integers_as_int32)) + total_length = numpy.int32(sum(map(len, to_bytes))) + proc.stdin.write(total_length.tobytes()) + for b in to_bytes: + proc.stdin.write(b) + proc.stdin.flush() + + read_message(message_headers.HELLO) + + # @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.IFC_MODEL, [numpy.int32(len(s)), s, b"\x00" * ((4 - (len(s) % 4)) % 4)]) + + 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) + write(message_headers.NEXT) + + write(message_headers.BYE) + read_message(message_headers.BYE) + proc.wait() + assert proc.returncode == 0 + +if __name__ == "__main__": + import sys + import platform + 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)