mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
See #1227. Recalculate normals and limited dissolve when layerset slicing and generating underside clipping geom.
This commit is contained in:
@@ -20,7 +20,6 @@ from __future__ import annotations
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import bpy
|
import bpy
|
||||||
import math
|
|
||||||
import bmesh
|
import bmesh
|
||||||
import logging
|
import logging
|
||||||
import ifcopenshell.geom
|
import ifcopenshell.geom
|
||||||
@@ -36,6 +35,7 @@ import bonsai.bim.import_ifc
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
from ifcopenshell.util.shape_builder import np_to_4d
|
from ifcopenshell.util.shape_builder import np_to_4d
|
||||||
|
from math import atan, radians
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union, Any, Optional
|
from typing import Union, Any, Optional
|
||||||
@@ -857,9 +857,9 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
camera.BIMCameraProperties.height = height
|
camera.BIMCameraProperties.height = height
|
||||||
|
|
||||||
if width > height:
|
if width > height:
|
||||||
fov = 2 * math.atan(width / (2 * abs_min_z))
|
fov = 2 * atan(width / (2 * abs_min_z))
|
||||||
else:
|
else:
|
||||||
fov = 2 * math.atan(height / (2 * abs_min_z))
|
fov = 2 * atan(height / (2 * abs_min_z))
|
||||||
|
|
||||||
camera.angle = fov
|
camera.angle = fov
|
||||||
|
|
||||||
@@ -1060,13 +1060,15 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
for i, material in enumerate(mesh.materials):
|
for i, material in enumerate(mesh.materials):
|
||||||
if style := tool.Ifc.get_entity(material):
|
if style := tool.Ifc.get_entity(material):
|
||||||
styles[style] = i
|
styles[style] = i
|
||||||
for layer in layer_set.MaterialLayers[:-1]:
|
last_i = len(layer_set.MaterialLayers) - 1
|
||||||
|
for i, layer in enumerate(layer_set.MaterialLayers):
|
||||||
prev_co = co.copy()
|
prev_co = co.copy()
|
||||||
co += no * layer.LayerThickness * cls.unit_scale
|
co += no * layer.LayerThickness * cls.unit_scale
|
||||||
bisect_geom = bmesh.ops.bisect_plane(
|
if i != last_i:
|
||||||
bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], dist=0.0001, plane_co=co, plane_no=no
|
bisect_geom = bmesh.ops.bisect_plane(
|
||||||
)
|
bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], dist=0.0001, plane_co=co, plane_no=no
|
||||||
bmesh.ops.duplicate(bm, geom=bisect_geom["geom_cut"])
|
)
|
||||||
|
bmesh.ops.duplicate(bm, geom=bisect_geom["geom_cut"])
|
||||||
if style := ifcopenshell.util.representation.get_material_style(layer.Material, body):
|
if style := ifcopenshell.util.representation.get_material_style(layer.Material, body):
|
||||||
if (material_index := styles.get(style, None)) is None:
|
if (material_index := styles.get(style, None)) is None:
|
||||||
material_index = len(mesh.materials)
|
material_index = len(mesh.materials)
|
||||||
@@ -1078,19 +1080,8 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
face.material_index = material_index
|
face.material_index = material_index
|
||||||
has_layer_styles = True
|
has_layer_styles = True
|
||||||
|
|
||||||
# Last layer
|
bmesh.ops.dissolve_limit(bm, angle_limit=radians(1), verts=bm.verts, edges=bm.edges, delimit={"MATERIAL"})
|
||||||
layer = layer_set.MaterialLayers[-1]
|
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
|
||||||
if style := ifcopenshell.util.representation.get_material_style(layer.Material, body):
|
|
||||||
if (material_index := styles.get(style, None)) is None:
|
|
||||||
material_index = len(mesh.materials)
|
|
||||||
mesh.materials.append(tool.Ifc.get_object(style))
|
|
||||||
for face in bisect_geom["geom"]:
|
|
||||||
if isinstance(face, bmesh.types.BMFace):
|
|
||||||
center = face.calc_center_median()
|
|
||||||
# if center.y > co.y:
|
|
||||||
if (center - co).dot(no) >= 0:
|
|
||||||
face.material_index = material_index
|
|
||||||
has_layer_styles = True
|
|
||||||
|
|
||||||
bm.to_mesh(mesh)
|
bm.to_mesh(mesh)
|
||||||
bm.free()
|
bm.free()
|
||||||
|
|||||||
@@ -38,15 +38,12 @@ import ifcopenshell.util.unit
|
|||||||
import bonsai.core.geometry
|
import bonsai.core.geometry
|
||||||
import bonsai.core.tool
|
import bonsai.core.tool
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
import bonsai.core.geometry as geometry
|
from math import atan, cos, degrees, pi, radians
|
||||||
from math import atan, cos, degrees, pi, inf
|
|
||||||
from mathutils import Matrix, Vector
|
from mathutils import Matrix, Vector
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from bonsai.bim import import_ifc
|
from bonsai.bim import import_ifc
|
||||||
|
|
||||||
# TODO: This line is somehow keeping the world from falling apart with a circular import error.
|
|
||||||
from bonsai.bim.module.geometry.helper import Helper
|
|
||||||
from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData
|
from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData
|
||||||
from bonsai.bim.module.model.opening import FilledOpeningGenerator
|
from bonsai.bim.module.model.opening import FilledOpeningGenerator
|
||||||
from ifcopenshell.util.shape_builder import ShapeBuilder
|
from ifcopenshell.util.shape_builder import ShapeBuilder
|
||||||
@@ -2108,6 +2105,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
|
|
||||||
bm = bmesh.new()
|
bm = bmesh.new()
|
||||||
bm.from_mesh(obj.data)
|
bm.from_mesh(obj.data)
|
||||||
|
bmesh.ops.dissolve_limit(bm, angle_limit=radians(1), verts=bm.verts, edges=bm.edges)
|
||||||
bm.faces.ensure_lookup_table()
|
bm.faces.ensure_lookup_table()
|
||||||
|
|
||||||
clipping_bm = bmesh.new()
|
clipping_bm = bmesh.new()
|
||||||
@@ -2117,7 +2115,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
face.normal_update()
|
face.normal_update()
|
||||||
normal = face.normal.to_4d()
|
normal = face.normal.to_4d()
|
||||||
normal.w = 0
|
normal.w = 0
|
||||||
if (obj.matrix_world @ normal).z >= 0:
|
if (obj.matrix_world @ normal).z >= -0.5:
|
||||||
continue
|
continue
|
||||||
new_verts = []
|
new_verts = []
|
||||||
for vert in face.verts:
|
for vert in face.verts:
|
||||||
@@ -2130,6 +2128,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
if not len(clipping_bm.faces):
|
if not len(clipping_bm.faces):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
bmesh.ops.recalc_face_normals(clipping_bm, faces=clipping_bm.faces)
|
||||||
return clipping_bm # clipping_bm is in project units
|
return clipping_bm # clipping_bm is in project units
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user