Licensing and black for BIMTester and IfcBlender. See #1082.

This commit is contained in:
Dion Moult
2022-01-19 11:07:43 +11:00
parent 07264dafb1
commit 5b281260f8
44 changed files with 966 additions and 322 deletions
+7
View File
@@ -0,0 +1,7 @@
.PHONY: license
license:
copyright-header --license LGPL3 --copyright-holder "Thomas Krijnen <thomas@aecgeeks.com>" --copyright-year "2019" --copyright-software "IfcBlender" --copyright-software-description "Blender IFC Importer" -a ./ -o ./
.PHONY: qa
qa:
black .
+77 -100
View File
@@ -1,21 +1,20 @@
###############################################################################
# #
# 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/>. #
# #
###############################################################################
# IfcBlender - Blender IFC Importer
# Copyright (C) 2019 Thomas Krijnen <thomas@aecgeeks.com>
#
# This file is part of IfcBlender.
#
# IfcBlender 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.
#
# IfcBlender 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 IfcBlender. If not, see <http://www.gnu.org/licenses/>.
# <pep8 compliant>
@@ -27,17 +26,17 @@
bl_info = {
"name": "IfcBlender",
"description": "Import files in the "
"Industry Foundation Classes (.ifc) file format",
"description": "Import files in the " "Industry Foundation Classes (.ifc) file format",
"author": "Thomas Krijnen, IfcOpenShell",
"blender": (2, 80, 0),
"location": "File > Import",
"tracker_url": "https://sourceforge.net/p/ifcopenshell/"
"_list/tickets?source=navbar",
"category": "Import-Export"}
"tracker_url": "https://sourceforge.net/p/ifcopenshell/" "_list/tickets?source=navbar",
"category": "Import-Export",
}
if "bpy" in locals():
import importlib
if "ifcopenshell" in locals():
importlib.reload(ifcopenshell)
@@ -56,18 +55,11 @@ import os
major, minor = bpy.app.version[0:2]
transpose_matrices = minor >= 62
bpy.types.Object.ifc_id = IntProperty(
name="IFC Entity ID",
description="The STEP entity instance name")
bpy.types.Object.ifc_guid = StringProperty(
name="IFC Entity GUID",
description="The IFC Globally Unique Identifier")
bpy.types.Object.ifc_name = StringProperty(
name="IFC Entity Name",
description="The optional name attribute")
bpy.types.Object.ifc_type = StringProperty(
name="IFC Entity Type",
description="The STEP Datatype keyword")
bpy.types.Object.ifc_id = IntProperty(name="IFC Entity ID", description="The STEP entity instance name")
bpy.types.Object.ifc_guid = StringProperty(name="IFC Entity GUID", description="The IFC Globally Unique Identifier")
bpy.types.Object.ifc_name = StringProperty(name="IFC Entity Name", description="The optional name attribute")
bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type", description="The STEP Datatype keyword")
def _get_parent(instance):
"""This is based on ifcopenshell.app.geom"""
@@ -88,10 +80,10 @@ def _get_parent(instance):
return decompositions[0].RelatingObject
def import_ifc(filename, use_names, process_relations, blender_booleans):
from . import ifcopenshell
from .ifcopenshell import geom as ifcopenshell_geom
print(f"Reading {bpy.path.basename(filename)}...")
settings = ifcopenshell_geom.settings()
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
@@ -111,9 +103,8 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
root_collection = bpy.data.collections.new(f"{bpy.path.basename(filename)}")
bpy.context.scene.collection.children.link(root_collection)
collections = {
0: root_collection
}
collections = {0: root_collection}
def get_collection(cid):
if cid == 0:
return root_collection
@@ -131,10 +122,10 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
ifc_parent_object = _get_parent(ifc_object)
parent_id = ifc_parent_object.id() if ifc_parent_object is not None else 0
parent_collection = get_collection(parent_id)
name = ifc_object.Name or f'{ifc_object.is_a()}[{cid}]'
name = ifc_object.Name or f"{ifc_object.is_a()}[{cid}]"
else:
parent_collection = get_collection(0)
name = f'unresolved_{cid}'
name = f"unresolved_{cid}"
collection = bpy.data.collections.new(name)
parent_collection.children.link(collection)
@@ -142,7 +133,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
return collection
if process_relations:
if process_relations:
rel_collection = bpy.data.collections.new("Relations")
collection.children.link(rel_collection)
@@ -160,14 +151,12 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
nm = ob.name if len(ob.name) and use_names else ob.guid
# MESH CREATION
# Depending on version, geometry.id will be either int or str
mesh_name = f'mesh-{ob.geometry.id}'
mesh_name = f"mesh-{ob.geometry.id}"
me = project_meshes.get(mesh_name)
if me is None:
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)]
verts = [[v[i], v[i + 1], v[i + 2]] for i in range(0, len(v), 3)]
faces = [[f[i], f[i + 1], f[i + 2]] for i in range(0, len(f), 3)]
me = bpy.data.meshes.new(mesh_name)
project_meshes[mesh_name] = me
@@ -182,8 +171,8 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
else:
mat = bpy.data.materials.new(mname)
for k, v in props.items():
if k == 'transparency':
mat.blend_method = 'HASHED'
if k == "transparency":
mat.blend_method = "HASHED"
mat.use_screen_refraction = True
mat.refraction_depth = 0.1
mat.use_nodes = True
@@ -199,10 +188,10 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
for mat in mats:
props = {}
if mat.has_diffuse:
alpha = 1.
alpha = 1.0
if mat.has_transparency and mat.transparency > 0:
alpha = 1. - mat.transparency
props['diffuse_color'] = mat.diffuse + (alpha,)
alpha = 1.0 - mat.transparency
props["diffuse_color"] = mat.diffuse + (alpha,)
# @todo
# if mat.has_specular:
# props['specular_color'] = mat.specular
@@ -210,17 +199,16 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
# props['specular_intensity'] = mat.specularity
add_material(mat.name, props)
faces = me.polygons if hasattr(me, 'polygons') else me.faces
faces = me.polygons if hasattr(me, "polygons") else me.faces
if len(faces) == len(matids):
for face, matid in zip(faces, matids):
face.material_index = matid + (1 if needs_default else 0)
# OBJECT CREATION
bob = bpy.data.objects.new(nm, me)
mat = mathutils.Matrix(([m[0], m[1], m[2], 0],
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
mat = mathutils.Matrix(
([m[0], m[1], m[2], 0], [m[3], m[4], m[5], 0], [m[6], m[7], m[8], 0], [m[9], m[10], m[11], 1])
)
if transpose_matrices:
mat.transpose()
@@ -232,24 +220,23 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
get_collection(ob.parent_id).objects.link(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.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode="OBJECT")
bob.ifc_id, bob.ifc_guid, bob.ifc_name, bob.ifc_type = \
ob.id, ob.guid, ob.name, ob.type
bob.ifc_id, bob.ifc_guid, bob.ifc_name, bob.ifc_type = ob.id, ob.guid, ob.name, ob.type
if ob.type == 'IfcSpace' or ob.type == 'IfcOpeningElement':
if not (ob.type == 'IfcOpeningElement' and blender_booleans):
if ob.type == "IfcSpace" or ob.type == "IfcOpeningElement":
if not (ob.type == "IfcOpeningElement" and blender_booleans):
bob.hide_viewport = bob.hide_render = True
bob.display_type = 'WIRE'
bob.display_type = "WIRE"
id_to_object[ob.id].append(bob)
if ob.parent_id > 0:
id_to_parent[ob.id] = ob.parent_id
if blender_booleans and ob.type == 'IfcOpeningElement':
if blender_booleans and ob.type == "IfcOpeningElement":
openings.append(ob.id)
progress = iterator.progress() // 2
@@ -276,15 +263,12 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
bob = None
else:
m = parent_ob.transformation.matrix.data
nm = parent_ob.name if len(parent_ob.name) and use_names \
else parent_ob.guid
nm = parent_ob.name if len(parent_ob.name) and use_names else parent_ob.guid
bob = bpy.data.objects.new(nm, None)
mat = mathutils.Matrix((
[m[0], m[1], m[2], 0],
[m[3], m[4], m[5], 0],
[m[6], m[7], m[8], 0],
[m[9], m[10], m[11], 1]))
mat = mathutils.Matrix(
([m[0], m[1], m[2], 0], [m[3], m[4], m[5], 0], [m[6], m[7], m[8], 0], [m[9], m[10], m[11], 1])
)
if transpose_matrices:
mat.transpose()
id_to_matrix[parent_ob.id] = mat
@@ -292,8 +276,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
rel_collection.objects.link(bob)
bob.ifc_id = parent_ob.id
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
parent_ob.name, parent_ob.type, parent_ob.guid
bob.ifc_name, bob.ifc_type, bob.ifc_guid = parent_ob.name, parent_ob.type, parent_ob.guid
if parent_ob.parent_id > 0:
id_to_parent[parent_id] = parent_ob.parent_id
@@ -327,7 +310,7 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
mod.operation = "DIFFERENCE"
mod.object = opening_ob
if hasattr(iterator, 'getLog'):
if hasattr(iterator, "getLog"):
# @todo
txt = bpy.data.texts.new(f"{bpy.path.basename(filename)}.log")
txt.from_string(iterator.getLog())
@@ -340,39 +323,33 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
bl_label = "Import .ifc file"
filename_ext = ".ifc"
filter_glob: StringProperty(default="*.ifc", options={'HIDDEN'})
filter_glob: StringProperty(default="*.ifc", options={"HIDDEN"})
use_names: BoolProperty(name="Use entity names",
description="Use entity names rather than "
"GlobalIds for objects",
default=True)
process_relations: BoolProperty(name="Process relations",
description="Convert containment and "
"aggregation relations to parenting"
" (warning: may be slow on large files)",
default=False)
blender_booleans: BoolProperty(name="Use Blender booleans",
description="Use Blender boolean modifiers "
"for opening elements",
default=False)
use_names: BoolProperty(
name="Use entity names", description="Use entity names rather than " "GlobalIds for objects", default=True
)
process_relations: BoolProperty(
name="Process relations",
description="Convert containment and "
"aggregation relations to parenting"
" (warning: may be slow on large files)",
default=False,
)
blender_booleans: BoolProperty(
name="Use Blender booleans", description="Use Blender boolean modifiers " "for opening elements", default=False
)
def execute(self, context):
if not import_ifc(self.filepath, self.use_names,
self.process_relations, self.blender_booleans):
self.report({'ERROR'},
'Unable to parse .ifc file or no geometrical entities found'
)
return {'FINISHED'}
if not import_ifc(self.filepath, self.use_names, self.process_relations, self.blender_booleans):
self.report({"ERROR"}, "Unable to parse .ifc file or no geometrical entities found")
return {"FINISHED"}
def menu_func_import(self, context):
self.layout.operator(ImportIFC.bl_idname,
text="Industry Foundation Classes (.ifc)")
self.layout.operator(ImportIFC.bl_idname, text="Industry Foundation Classes (.ifc)")
classes = (
ImportIFC,
)
classes = (ImportIFC,)
def register():