Integrate ifccityjson in BlenderBIM (#1859)

* ifccityjson-BB integration: include CJIO in makefile

* Add ifccityjson to BlenderBIM

* Make ifccityjson work like a package

* Use pip while installing CJIO dependency for ifccityjson

* revert removal of brick module

* Changes from pull request review

* Use ifccityjson as CLI and as package for BlenderBIM
This commit is contained in:
Laurens Oostwegel
2021-11-08 22:51:30 +01:00
committed by GitHub
parent de7c54b771
commit ff6db5f24d
11 changed files with 185 additions and 19 deletions
+10
View File
@@ -134,6 +134,8 @@ endif
# Provides IFC5D functionality # Provides IFC5D functionality
cp -r dist/working/IfcOpenShell-0.7.0/src/ifc5d/ifc5d dist/blenderbim/libs/site/packages/ cp -r dist/working/IfcOpenShell-0.7.0/src/ifc5d/ifc5d dist/blenderbim/libs/site/packages/
rm -rf dist/working rm -rf dist/working
# Provides IFCCityJSON functionality
cp -r dist/working/IfcOpenShell-0.7.0/src/ifccityjson dist/blenderbim/libs/site/packages/
# Provides Mustache templating in construction documentation # Provides Mustache templating in construction documentation
mkdir dist/working mkdir dist/working
@@ -259,6 +261,14 @@ endif
mkdir dist/working mkdir dist/working
cd dist/working && wget $(HPPFCL_URL) cd dist/working && wget $(HPPFCL_URL)
cd dist/working && tar -xf hpp-fcl* cd dist/working && tar -xf hpp-fcl*
# Required by IFCCityJSON
mkdir dist/working
cd dist/working && python -m venv env
cd dist/working && . env/bin/activate && pip install cjio
cp -r dist/working/env/Lib/site-packages dist/blenderbim/libs/site/packages/
rm -rf dist/working
ifeq ($(PLATFORM), linux) ifeq ($(PLATFORM), linux)
cp -r dist/working/lib/$(PYLIBDIR)/site-packages/hppfcl dist/blenderbim/libs/site/packages/ cp -r dist/working/lib/$(PYLIBDIR)/site-packages/hppfcl dist/blenderbim/libs/site/packages/
cp -r dist/working/lib/*.so* dist/blenderbim/libs/ cp -r dist/working/lib/*.so* dist/blenderbim/libs/
@@ -63,6 +63,7 @@ modules = {
"bimtester": None, "bimtester": None,
"diff": None, "diff": None,
"patch": None, "patch": None,
"gis": None,
"covetool": None, "covetool": None,
"augin": None, "augin": None,
"debug": None, "debug": None,
@@ -0,0 +1,17 @@
import bpy
from . import prop
from . import operator
from . import ui
classes = (
prop.BIMCityJsonProperties,
operator.BIM_OT_cityjson2ifc,
operator.BIM_OT_find_cityjson_lod,
ui.BIM_PT_cityjson_converter,
)
def register():
bpy.types.Scene.ifccityjson_properties = bpy.props.PointerProperty(type=prop.BIMCityJsonProperties)
def unregister():
del bpy.types.Scene.ifccityjson_properties
@@ -0,0 +1,47 @@
import bpy
from bpy.types import Operator
from cjio import cityjson
from ifccityjson.cityjson2ifc.cityjson2ifc import Cityjson2ifc
class BIM_OT_cityjson2ifc(Operator):
bl_idname = "bim.convert_cityjson2ifc"
bl_label = "Convert CityJSON to IFC"
bl_context = "scene"
def execute(self, context):
props = context.scene.ifccityjson_properties
city_model = cityjson.load(props.input, transform=False)
data = {
"file_destination": props.output,
"lod": props.lod,
"split": props.split_lod,
}
if props.name is not "":
data["name_attribute"] = props.name
converter = Cityjson2ifc()
converter.configuration(**data)
converter.convert(city_model)
if props.load_after_convert:
bpy.ops.bim.load_project(filepath=props.output)
return {'FINISHED'}
class BIM_OT_find_cityjson_lod(Operator):
bl_idname = "bim.find_cityjson_lod"
bl_label = "Find LODs in CityJSON file"
bl_context = "scene"
def execute(self, context):
props = context.scene.ifccityjson_properties
city_model = cityjson.load(props.input)
lods = set()
for obj_id, obj in city_model.get_cityobjects().items():
for geometry in obj.geometry:
lod = str(geometry.lod)
if lod not in lods:
lods.add(lod)
props.lods.add()
props.lods[-1].name = lod
props.is_lod_found = True
return {'FINISHED'}
@@ -0,0 +1,16 @@
from bpy.types import PropertyGroup
from bpy.props import StringProperty, BoolProperty, EnumProperty, CollectionProperty
from blenderbim.bim.prop import StrProperty
class BIMCityJsonProperties(PropertyGroup):
def get_lods(self, context):
return [(item.name, "LOD" + item.name, "Level of Detail " + item.name) for item in self.lods]
input: StringProperty(name="cj_input", default="", subtype='FILE_PATH')
output: StringProperty(name="ifc_output", default="", subtype='FILE_PATH')
name: StringProperty(name="identifier", default="")
split_lod: BoolProperty(name="split_lod", default=True)
lods: CollectionProperty(name="lods", type=StrProperty)
lod: EnumProperty(name="lod", description="", items=get_lods, options={'ANIMATABLE'}, default=None)
is_lod_found: BoolProperty(name="is_lod_found", default=False)
load_after_convert: BoolProperty(name="load_after_convert", default=True)
@@ -0,0 +1,32 @@
from bpy.types import Panel
class BIM_PT_cityjson_converter(Panel):
bl_label = "IFC CityJSON converter"
bl_idname = "BIM_PT_ifccityjson"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
props = scene.ifccityjson_properties
row = layout.row(align=True)
row.prop(props, "input")
row = layout.row(align=True)
row.operator("bim.find_cityjson_lod")
row = layout.row(align=True)
row.prop(props, "output")
row = layout.row(align=True)
row.prop(props, "name")
row = layout.row(align=True)
row.prop(props, "split_lod")
row.prop(props, "load_after_convert")
row = layout.row(align=True)
row.prop(props, "lod")
if not props.is_lod_found:
row.enabled = False
row = layout.row(align=True)
row.operator("bim.convert_cityjson2ifc")
+23
View File
@@ -0,0 +1,23 @@
# ifccityjson - Python CityJSON to IFC converter
# Copyright (C) 2021 Laurens J.N. Oostwegel <l.oostwegel@gmail.com>
#
# This file is part of ifccityjson.
#
# ifccityjson is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ifccityjson 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
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ifccityjson. If not, see <http://www.gnu.org/licenses/>.
from .cityjson2ifc import *
# Export version number
__version__ = "0.0.1"
+20
View File
@@ -0,0 +1,20 @@
# ifccityjson - Python CityJSON to IFC converter
# Copyright (C) 2021 Laurens J.N. Oostwegel <l.oostwegel@gmail.com>
#
# This file is part of ifccityjson.
#
# ifccityjson is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ifccityjson 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
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ifccityjson. If not, see <http://www.gnu.org/licenses/>.
from .cityjson2ifc import *
@@ -15,14 +15,13 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with ifccityjson. If not, see <http://www.gnu.org/licenses/>. # along with ifccityjson. If not, see <http://www.gnu.org/licenses/>.
import os
import copy
import os
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
from geometry import GeometryIO
from datetime import datetime from datetime import datetime
from .geometry import GeometryIO
JSON_TO_IFC = { JSON_TO_IFC = {
"Building": ["IfcBuilding"], "Building": ["IfcBuilding"],
@@ -145,8 +144,8 @@ class Cityjson2ifc:
def create_representation_sub_contexts(self): def create_representation_sub_contexts(self):
self.IFC_representation_sub_contexts = {} self.IFC_representation_sub_contexts = {}
for lod in self.city_model.j["metadata"]["presentLoDs"]: # for lod in self.city_model.j["metadata"]["presentLoDs"]:
self.IFC_representation_sub_contexts[str(lod)] = self.create_representation_sub_context(lod) # self.IFC_representation_sub_contexts[str(lod)] = self.create_representation_sub_context(lod)
def create_representation_sub_context(self, lod): def create_representation_sub_context(self, lod):
# TODO in ifcopenshell.api.context.add_context add support for UserDefinedTargetView # TODO in ifcopenshell.api.context.add_context add support for UserDefinedTargetView
@@ -29,7 +29,7 @@ class GeometryIO:
def build_vertices(self, IFC_model, vertices): def build_vertices(self, IFC_model, vertices):
for vertex in vertices: for vertex in vertices:
self.build_vertex(self, IFC_model, vertex) self.build_vertex(IFC_model, vertex)
def build_vertex(self, IFC_model, vertex): def build_vertex(self, IFC_model, vertex):
if self.scale: if self.scale:
@@ -158,12 +158,11 @@ class GeometryIO:
if len(face) == 1: if len(face) == 1:
return IFC_model.create_entity("IfcFace", Bounds=[outerbound]) return IFC_model.create_entity("IfcFace", Bounds=[outerbound])
return IFC_model.create_entity("IfcFace", [outerbound]) innerbounds = []
# interior face BUGS for interior_face in face[1:]:
# innerbounds = [] vertices = []
# for interior_face in face[1:]: for vertex in interior_face:
# for vertex in interior_face: vertices.append(self.get_vertex(IFC_model, vertex))
# vertices.append(self.get_vertex(IFC_model, vertex)) polyloop = IFC_model.create_entity("IfcPolyLoop", Polygon=vertices)
# polyloop = IFC_model.create_entity("IfcPolyLoop", Polygon=vertices) innerbounds.append(IFC_model.create_entity("IfcFaceBound", Bound=polyloop, Orientation=False))
# innerbounds.append(IFC_model.create_entity("IfcFaceBound", Bound=polyloop, Orientation=False)) return IFC_model.create_entity("IfcFace", Bounds=[outerbound] + innerbounds)
# return IFC_model.create_entity("IfcFace", Bounds=[outerbound] + innerbounds)
+6 -4
View File
@@ -1,4 +1,3 @@
# ifccityjson - Python CityJSON to IFC converter # ifccityjson - Python CityJSON to IFC converter
# Copyright (C) 2021 Laurens J.N. Oostwegel <l.oostwegel@gmail.com> # Copyright (C) 2021 Laurens J.N. Oostwegel <l.oostwegel@gmail.com>
# #
@@ -16,12 +15,12 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with ifccityjson. If not, see <http://www.gnu.org/licenses/>. # along with ifccityjson. If not, see <http://www.gnu.org/licenses/>.
import argparse import argparse
from cjio import cityjson from cjio import cityjson
from cityjson2ifc import Cityjson2ifc from cityjson2ifc.cityjson2ifc import Cityjson2ifc
# Press the green button in the gutter to run the script. def cmdline():
if __name__ == '__main__':
# Example: # Example:
# python ifccityjson.py -i example/3DBAG_example.json -o example/output.ifc -n identificatie # python ifccityjson.py -i example/3DBAG_example.json -o example/output.ifc -n identificatie
# python ifccityjson.py -i example/geometries.json -o example/geometry_output.ifc # python ifccityjson.py -i example/geometries.json -o example/geometry_output.ifc
@@ -50,3 +49,6 @@ if __name__ == '__main__':
converter = Cityjson2ifc() converter = Cityjson2ifc()
converter.configuration(**data) converter.configuration(**data)
converter.convert(city_model) converter.convert(city_model)
if __name__ == '__main__':
cmdline()