mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Fixed door / window preview and made preview of other objects not rotate with wall
This commit is contained in:
committed by
Ryan Schultz
parent
59dd25e1c2
commit
51016de211
@@ -18,15 +18,550 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from math import cos, pi, radians, tan
|
||||
from typing import Literal, Union
|
||||
|
||||
import bmesh
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.unit
|
||||
from mathutils import Vector
|
||||
from mathutils import Matrix, Quaternion, Vector
|
||||
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim.module.model.decorator import PolylineDecorator
|
||||
from bonsai.bim.module.geometry.decorator import ItemDecorator
|
||||
from typing import Optional, Union, Literal, Any
|
||||
from lark import Lark, Transformer
|
||||
|
||||
|
||||
def create_bmesh_from_vertices(vertices, is_closed=False):
|
||||
bm = bmesh.new()
|
||||
|
||||
new_verts = [bm.verts.new(v) for v in vertices]
|
||||
if is_closed:
|
||||
new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)]
|
||||
new_edges.append(
|
||||
bm.edges.new((new_verts[-1], new_verts[0]))
|
||||
) # Add an edge between the last an first point to make it closed.
|
||||
else:
|
||||
new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)]
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
return bm
|
||||
|
||||
|
||||
def get_wall_preview_data(context, relating_type):
|
||||
# Get properties from object type
|
||||
model_props = tool.Model.get_model_props()
|
||||
direction_sense = model_props.direction_sense
|
||||
direction = 1
|
||||
if direction_sense == "NEGATIVE":
|
||||
direction = -1
|
||||
|
||||
layers = tool.Model.get_material_layer_parameters(relating_type)
|
||||
if not layers["thickness"]:
|
||||
return
|
||||
thickness = layers["thickness"]
|
||||
thickness *= direction
|
||||
|
||||
offset_type = model_props.offset_type_vertical
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
offset = model_props.offset * unit_scale
|
||||
|
||||
height = float(model_props.extrusion_depth)
|
||||
rl = float(model_props.rl1)
|
||||
x_angle = float(model_props.x_angle)
|
||||
if x_angle > radians(90) or x_angle < radians(-90):
|
||||
height *= -1
|
||||
angle_distance = height * tan(x_angle)
|
||||
thickness *= 1 / cos(x_angle)
|
||||
|
||||
data = {}
|
||||
data["verts"] = []
|
||||
|
||||
# Verts
|
||||
polyline_vertices = []
|
||||
polyline_props = tool.Model.get_polyline_props()
|
||||
polyline_data = polyline_props.insertion_polyline
|
||||
polyline_points = polyline_data[0].polyline_points if polyline_data else []
|
||||
if len(polyline_points) < 2:
|
||||
data = []
|
||||
return
|
||||
for point in polyline_points:
|
||||
polyline_vertices.append(Vector((point.x, point.y, point.z)))
|
||||
|
||||
is_closed = False
|
||||
if (
|
||||
polyline_vertices[0].x == polyline_vertices[-1].x
|
||||
and polyline_vertices[0].y == polyline_vertices[-1].y
|
||||
and polyline_vertices[0].z == polyline_vertices[-1].z
|
||||
):
|
||||
is_closed = True
|
||||
polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed.
|
||||
|
||||
bm_base = create_bmesh_from_vertices(polyline_vertices, is_closed)
|
||||
base_vertices = tool.Cad.offset_edges(bm_base, offset)
|
||||
offset_base_verts = tool.Cad.offset_edges(bm_base, thickness + offset)
|
||||
top_vertices = tool.Cad.offset_edges(bm_base, angle_distance + offset)
|
||||
offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distance + thickness + offset)
|
||||
if is_closed:
|
||||
base_vertices.append(base_vertices[0])
|
||||
offset_base_verts.append(offset_base_verts[0])
|
||||
top_vertices.append(top_vertices[0])
|
||||
offset_top_verts.append(offset_top_verts[0])
|
||||
|
||||
if offset_base_verts is not None:
|
||||
for v in base_vertices:
|
||||
data["verts"].append((v.co.x, v.co.y, v.co.z + rl))
|
||||
|
||||
for v in offset_base_verts[::-1]:
|
||||
data["verts"].append((v.co.x, v.co.y, v.co.z + rl))
|
||||
|
||||
for v in top_vertices:
|
||||
data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height))
|
||||
|
||||
for v in offset_top_verts[::-1]:
|
||||
data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height))
|
||||
|
||||
bm_base.free()
|
||||
|
||||
# Edges and Tris
|
||||
points = []
|
||||
side_edges_1 = []
|
||||
side_edges_2 = []
|
||||
base_edges = []
|
||||
|
||||
for i in range(len(data["verts"])):
|
||||
points.append(Vector(data["verts"][i]))
|
||||
|
||||
n = len(points) // 2
|
||||
bottom_side_1 = [[i, (i + 1) % (n)] for i in range((n - 1) // 2)]
|
||||
bottom_side_2 = [[i, (i + 1) % (n)] for i in range(n // 2, n - 1)]
|
||||
bottom_connections = [[i, n - i - 1] for i in range(n // 2)]
|
||||
bottom_loop = bottom_connections + bottom_side_1 + bottom_side_2
|
||||
side_edges_1.extend(bottom_side_1)
|
||||
side_edges_2.extend(bottom_side_2)
|
||||
base_edges.extend(bottom_loop)
|
||||
|
||||
upper_side_1 = [[i + n for i in edges] for edges in bottom_side_1]
|
||||
upper_side_2 = [[i + n for i in edges] for edges in bottom_side_2]
|
||||
upper_loop = [[i + n for i in edges] for edges in bottom_loop]
|
||||
side_edges_1.extend(upper_side_1)
|
||||
side_edges_2.extend(upper_side_2)
|
||||
base_edges.extend(upper_loop)
|
||||
|
||||
loops = [side_edges_1, side_edges_2, base_edges]
|
||||
|
||||
data["edges"] = []
|
||||
data["tris"] = []
|
||||
for i, group in enumerate(loops):
|
||||
bm = bmesh.new()
|
||||
|
||||
new_verts = [bm.verts.new(v) for v in points]
|
||||
new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in group]
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
|
||||
if i == 2:
|
||||
new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges)
|
||||
new_faces = bmesh.ops.bridge_loops(bm, edges=bm.edges, use_pairs=True, use_cyclic=True)
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
edges = [[v.index for v in e.verts] for e in bm.edges]
|
||||
tris = [[l.vert.index for l in loop] for loop in bm.calc_loop_triangles()]
|
||||
data["edges"].extend(edges)
|
||||
data["tris"].extend(tris)
|
||||
|
||||
data["edges"] = list(set(tuple(e) for e in data["edges"]))
|
||||
data["tris"] = list(set(tuple(t) for t in data["tris"]))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_slab_preview_data(context, relating_type):
|
||||
model_props = tool.Model.get_model_props()
|
||||
x_angle = 0 if tool.Cad.is_x(model_props.x_angle, 0, tolerance=0.001) else model_props.x_angle
|
||||
direction_sense = model_props.direction_sense
|
||||
direction = 1
|
||||
if direction_sense == "NEGATIVE":
|
||||
direction = -1
|
||||
|
||||
layers = tool.Model.get_material_layer_parameters(relating_type)
|
||||
if not layers["thickness"]:
|
||||
return
|
||||
thickness = layers["thickness"] * abs(1 / cos(x_angle))
|
||||
thickness *= direction
|
||||
|
||||
offset_type = model_props.offset_type_horizontal
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
offset = model_props.offset * abs(1 / cos(x_angle)) * unit_scale
|
||||
|
||||
data = {}
|
||||
data["verts"] = []
|
||||
# Verts
|
||||
polyline_vertices = []
|
||||
polyline_props = tool.Model.get_polyline_props()
|
||||
polyline_data = polyline_props.insertion_polyline
|
||||
polyline_points = polyline_data[0].polyline_points if polyline_data else []
|
||||
if len(polyline_points) < 3:
|
||||
data = []
|
||||
return
|
||||
for point in polyline_points:
|
||||
polyline_vertices.append(Vector((point.x, point.y, point.z)))
|
||||
if x_angle:
|
||||
# Get vertices relative to the first polyline point as origin
|
||||
local_vertices = [v - Vector(polyline_vertices[0]) for v in polyline_vertices]
|
||||
# Make the transformation relative to the x_angle
|
||||
transformed_vertices = [Vector((v.x, v.y * (1 / cos(x_angle)), v.z)) for v in local_vertices]
|
||||
# Convert back to world origin
|
||||
polyline_vertices = [v + Vector(polyline_vertices[0]) for v in transformed_vertices]
|
||||
if offset != 0:
|
||||
polyline_vertices = [v + Vector((0, 0, offset)) for v in polyline_vertices]
|
||||
is_closed = True
|
||||
if (
|
||||
polyline_vertices[0].x == polyline_vertices[-1].x
|
||||
and polyline_vertices[0].y == polyline_vertices[-1].y
|
||||
and polyline_vertices[0].z == polyline_vertices[-1].z
|
||||
):
|
||||
polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed.
|
||||
bm = create_bmesh_from_vertices(polyline_vertices, is_closed)
|
||||
bm.verts.ensure_lookup_table()
|
||||
if x_angle:
|
||||
rot_mat = Matrix.Rotation(x_angle, 3, "X")
|
||||
if abs(x_angle) > (pi / 2):
|
||||
rot_mat = rot_mat @ Matrix.Scale(-1, 3, (0, 1, 0))
|
||||
bmesh.ops.rotate(bm, cent=Vector(bm.verts[0].co), verts=bm.verts, matrix=rot_mat)
|
||||
new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges)
|
||||
new_faces = bmesh.ops.extrude_face_region(bm, geom=bm.edges[:] + bm.faces[:])
|
||||
new_verts = [e for e in new_faces["geom"] if isinstance(e, bmesh.types.BMVert)]
|
||||
new_faces = bmesh.ops.translate(bm, verts=new_verts, vec=(0.0, 0.0, thickness))
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
verts = [tuple(v.co) for v in bm.verts]
|
||||
edges = [[v.index for v in e.verts] for e in bm.edges]
|
||||
tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()]
|
||||
data["verts"] = verts
|
||||
data["edges"] = edges
|
||||
data["tris"] = tris
|
||||
return data
|
||||
|
||||
|
||||
def get_vertical_profile_preview_data(
|
||||
context: bpy.types.Context, relating_type: ifcopenshell.entity_instance
|
||||
) -> dict[str, Any]:
|
||||
material = ifcopenshell.util.element.get_material(relating_type)
|
||||
try:
|
||||
profile = material.MaterialProfiles[0].Profile
|
||||
except:
|
||||
return {}
|
||||
|
||||
model_props = tool.Model.get_model_props()
|
||||
extrusion_depth = model_props.extrusion_depth
|
||||
cardinal_point = model_props.cardinal_point
|
||||
rot_mat = Quaternion()
|
||||
if relating_type.is_a("IfcBeamType"):
|
||||
y_rot = Quaternion((0.0, 1.0, 0.0), radians(90))
|
||||
z_rot = Quaternion((0.0, 0.0, 1.0), radians(90))
|
||||
rot_mat = y_rot @ z_rot
|
||||
# Get profile data
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, profile)
|
||||
|
||||
verts = shape.verts
|
||||
if not verts:
|
||||
raise RuntimeError(f"Profile shape has no vertices, it probably is invalid: '{profile}'.")
|
||||
|
||||
edges = shape.edges
|
||||
|
||||
grouped_verts = [[verts[i], verts[i + 1], 0] for i in range(0, len(verts), 3)]
|
||||
grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)]
|
||||
|
||||
# Create offsets based on cardinal point
|
||||
min_x = min(v[0] for v in grouped_verts)
|
||||
max_x = max(v[0] for v in grouped_verts)
|
||||
min_y = min(v[1] for v in grouped_verts)
|
||||
max_y = max(v[1] for v in grouped_verts)
|
||||
|
||||
x_offset = (max_x - min_x) / 2
|
||||
y_offset = (max_y - min_y) / 2
|
||||
|
||||
match cardinal_point:
|
||||
case "1":
|
||||
grouped_verts = [(v[0] - x_offset, v[1] + y_offset, v[2]) for v in grouped_verts]
|
||||
case "2":
|
||||
grouped_verts = [(v[0], v[1] + y_offset, v[2]) for v in grouped_verts]
|
||||
case "3":
|
||||
grouped_verts = [(v[0] + x_offset, v[1] + y_offset, v[2]) for v in grouped_verts]
|
||||
case "4":
|
||||
grouped_verts = [(v[0] - x_offset, v[1], v[2]) for v in grouped_verts]
|
||||
case "5":
|
||||
grouped_verts = [(v[0], v[1], v[2]) for v in grouped_verts]
|
||||
case "6":
|
||||
grouped_verts = [(v[0] + x_offset, v[1], v[2]) for v in grouped_verts]
|
||||
case "7":
|
||||
grouped_verts = [(v[0] - x_offset, v[1] - y_offset, v[2]) for v in grouped_verts]
|
||||
case "8":
|
||||
grouped_verts = [(v[0], v[1] - y_offset, v[2]) for v in grouped_verts]
|
||||
case "9":
|
||||
grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts]
|
||||
|
||||
# Create extrusion bmesh
|
||||
bm = bmesh.new()
|
||||
|
||||
grouped_verts.append(grouped_verts[0]) # Close profile
|
||||
new_verts = [bm.verts.new(v) for v in grouped_verts]
|
||||
new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(grouped_verts) - 1)]
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
|
||||
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001)
|
||||
|
||||
new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges)
|
||||
|
||||
new_faces = bmesh.ops.extrude_face_region(bm, geom=bm.faces, use_dissolve_ortho_edges=True)
|
||||
new_verts = [e for e in new_faces["geom"] if isinstance(e, bmesh.types.BMVert)]
|
||||
new_faces = bmesh.ops.translate(bm, verts=new_verts, vec=(0.0, 0.0, extrusion_depth))
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()]
|
||||
|
||||
# Calculate rotation, mouse position, angle and cardinal point
|
||||
polyline_props = tool.Model.get_polyline_props()
|
||||
snap_prop = polyline_props.snap_mouse_point[0]
|
||||
mouse_point = Vector((snap_prop.x, snap_prop.y, snap_prop.z))
|
||||
data = {}
|
||||
|
||||
verts = [tuple(v.co) for v in bm.verts]
|
||||
verts = [tuple(rot_mat @ Vector(v)) for v in verts]
|
||||
verts = [tuple(Vector(v) + mouse_point) for v in verts]
|
||||
min_z = min(v.co.z for v in bm.verts)
|
||||
max_z = max(v.co.z for v in bm.verts)
|
||||
# Add axis verts
|
||||
verts.append(tuple(mouse_point))
|
||||
verts.append(tuple(mouse_point + Vector((0, 0, max_z))))
|
||||
# Add only profile edges
|
||||
edges = []
|
||||
for edge in bm.edges:
|
||||
if (edge.verts[0].co.z == min_z and edge.verts[1].co.z == min_z) or (
|
||||
edge.verts[0].co.z == max_z and edge.verts[1].co.z == max_z
|
||||
):
|
||||
edges.append(edge)
|
||||
# Add axis edge
|
||||
edges = [(edge.verts[0].index, edge.verts[1].index) for edge in edges]
|
||||
edges.append((len(verts) - 1, len(verts) - 2))
|
||||
data["verts"] = verts
|
||||
data["edges"] = edges
|
||||
data["tris"] = tris
|
||||
|
||||
bm.free()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_horizontal_profile_preview_data(
|
||||
context: bpy.types.Context, relating_type: ifcopenshell.entity_instance
|
||||
) -> dict[str, Any]:
|
||||
material = ifcopenshell.util.element.get_material(relating_type)
|
||||
try:
|
||||
profile_curve = material.MaterialProfiles[0].Profile
|
||||
except:
|
||||
return {}
|
||||
|
||||
model_props = tool.Model.get_model_props()
|
||||
cardinal_point = model_props.cardinal_point
|
||||
|
||||
polyline_verts = []
|
||||
polyline_props = tool.Model.get_polyline_props()
|
||||
polyline_data = polyline_props.insertion_polyline
|
||||
polyline_points = polyline_data[0].polyline_points if polyline_data else []
|
||||
if len(polyline_points) < 2:
|
||||
return {}
|
||||
for point in polyline_points:
|
||||
polyline_verts.append(Vector((point.x, point.y, point.z)))
|
||||
polyline_edges = [(i, i + 1) for i in range(len(polyline_verts) - 1)]
|
||||
|
||||
# Get profile shape
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, profile_curve)
|
||||
|
||||
verts = shape.verts
|
||||
if not verts:
|
||||
raise RuntimeError(f"Profile shape has no vertices, it probably is invalid: '{profile_curve}'.")
|
||||
|
||||
edges = shape.edges
|
||||
|
||||
grouped_verts = [[verts[i], verts[i + 1], 0] for i in range(0, len(verts), 3)]
|
||||
grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)]
|
||||
|
||||
# Create offsets based on cardinal point
|
||||
min_x = min(v[0] for v in grouped_verts)
|
||||
max_x = max(v[0] for v in grouped_verts)
|
||||
min_y = min(v[1] for v in grouped_verts)
|
||||
max_y = max(v[1] for v in grouped_verts)
|
||||
|
||||
x_offset = (max_x - min_x) / 2
|
||||
y_offset = (max_y - min_y) / 2
|
||||
|
||||
match cardinal_point:
|
||||
case "1":
|
||||
grouped_verts = [(v[0] - x_offset, v[1] + y_offset, v[2]) for v in grouped_verts]
|
||||
case "2":
|
||||
grouped_verts = [(v[0], v[1] + y_offset, v[2]) for v in grouped_verts]
|
||||
case "3":
|
||||
grouped_verts = [(v[0] + x_offset, v[1] + y_offset, v[2]) for v in grouped_verts]
|
||||
case "4":
|
||||
grouped_verts = [(v[0] - x_offset, v[1], v[2]) for v in grouped_verts]
|
||||
case "5":
|
||||
grouped_verts = [(v[0], v[1], v[2]) for v in grouped_verts]
|
||||
case "6":
|
||||
grouped_verts = [(v[0] + x_offset, v[1], v[2]) for v in grouped_verts]
|
||||
case "7":
|
||||
grouped_verts = [(v[0] - x_offset, v[1] - y_offset, v[2]) for v in grouped_verts]
|
||||
case "8":
|
||||
grouped_verts = [(v[0], v[1] - y_offset, v[2]) for v in grouped_verts]
|
||||
case "9":
|
||||
grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts]
|
||||
|
||||
data: dict[str, Any] = {}
|
||||
data["verts"] = []
|
||||
data["edges"] = []
|
||||
data["tris"] = []
|
||||
|
||||
grouped_verts = [(v) for v in grouped_verts]
|
||||
|
||||
all_bm = bmesh.new()
|
||||
for i in range(len(polyline_verts) - 1):
|
||||
mesh = bpy.data.meshes.new("TempMesh")
|
||||
# Create the initial mesh from the profile verts
|
||||
bm = create_bmesh_from_vertices(grouped_verts, is_closed=True)
|
||||
bm.verts.ensure_lookup_table()
|
||||
# Creates the clipping plane formed by two segments.
|
||||
# The first one is for the profile start, based on the current and previous segment of the polyline.
|
||||
# The second is for the profile end, based on the current and the next segment.
|
||||
if i == 0:
|
||||
d = (polyline_verts[i + 1] - polyline_verts[i]).normalized()
|
||||
clip_start = d
|
||||
else:
|
||||
d1 = (polyline_verts[i] - polyline_verts[i - 1]).normalized()
|
||||
d2 = (polyline_verts[i] - polyline_verts[i + 1]).normalized()
|
||||
clip_start = (d1 - d2).normalized()
|
||||
|
||||
if i == len(polyline_verts) - 2:
|
||||
d = (polyline_verts[i + 1] - polyline_verts[i]).normalized()
|
||||
clip_end = d
|
||||
else:
|
||||
d1 = (polyline_verts[i + 1] - polyline_verts[i]).normalized()
|
||||
d2 = (polyline_verts[i + 1] - polyline_verts[i + 2]).normalized()
|
||||
clip_end = (d1 - d2).normalized()
|
||||
|
||||
# Rotates the profile face to the right direction
|
||||
direction = polyline_verts[i + 1] - polyline_verts[i]
|
||||
position = polyline_verts[i]
|
||||
rotation_matrix = direction.to_track_quat("Z", "Y").to_matrix().to_4x4()
|
||||
bmesh.ops.transform(bm, verts=bm.verts, matrix=rotation_matrix)
|
||||
bmesh.ops.translate(bm, verts=bm.verts, vec=position)
|
||||
bmesh.ops.translate(bm, verts=bm.verts, vec=-direction)
|
||||
|
||||
# Extrude and move the new face
|
||||
last_face = bmesh.ops.extrude_face_region(bm, geom=bm.edges[:] + bm.faces[:])
|
||||
new_verts = [e for e in last_face["geom"] if isinstance(e, bmesh.types.BMVert)]
|
||||
bmesh.ops.translate(bm, verts=new_verts, vec=direction * 3)
|
||||
# Apply the cutting planes
|
||||
cut = bmesh.ops.bisect_plane(
|
||||
bm,
|
||||
geom=bm.verts[:] + bm.edges[:] + bm.faces[:],
|
||||
plane_co=polyline_verts[i],
|
||||
plane_no=clip_start,
|
||||
clear_inner=True,
|
||||
)
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
cut = bmesh.ops.bisect_plane(
|
||||
bm,
|
||||
geom=bm.verts[:] + bm.edges[:] + bm.faces[:],
|
||||
plane_co=polyline_verts[i + 1],
|
||||
plane_no=clip_end,
|
||||
clear_outer=True,
|
||||
)
|
||||
|
||||
bm.to_mesh(mesh)
|
||||
bm.free()
|
||||
mesh.update()
|
||||
all_bm.from_mesh(mesh)
|
||||
bpy.data.meshes.remove(bpy.data.meshes["TempMesh"])
|
||||
|
||||
# It's necessary to add the mesh to an object to get the expected result.
|
||||
mesh = bpy.data.meshes.new("TempMesh2")
|
||||
all_bm.to_mesh(mesh)
|
||||
all_bm.free()
|
||||
obj = bpy.data.objects.new("TempObj", mesh)
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(obj.data)
|
||||
bpy.data.meshes.remove(bpy.data.meshes["TempMesh2"])
|
||||
|
||||
verts = [tuple(v.co) for v in bm.verts]
|
||||
edges = [[v.index for v in e.verts] for e in bm.edges]
|
||||
tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()]
|
||||
data["verts"] = verts
|
||||
data["edges"] = edges
|
||||
data["tris"] = tris
|
||||
bm.free()
|
||||
return data
|
||||
|
||||
|
||||
def get_generic_product_preview_data(context, relating_type):
|
||||
model_props = tool.Model.get_model_props()
|
||||
if relating_type.is_a("IfcDoorType"):
|
||||
rl = float(model_props.rl1)
|
||||
elif relating_type.is_a("IfcWindowType"):
|
||||
rl = float(model_props.rl2)
|
||||
else:
|
||||
rl = 0
|
||||
polyline_props = tool.Model.get_polyline_props()
|
||||
snap_prop = polyline_props.snap_mouse_point[0]
|
||||
default_container_elevation = tool.Root.get_default_container_elevation()
|
||||
mouse_point = Vector((snap_prop.x, snap_prop.y, default_container_elevation))
|
||||
snap_obj = bpy.data.objects.get(snap_prop.snap_object)
|
||||
snap_element = tool.Ifc.get_entity(snap_obj)
|
||||
rot_mat = Quaternion()
|
||||
invert_x = False
|
||||
if relating_type.is_a() in [ "IfcDoorType", "IfcWindowType" ] and snap_element and snap_element.is_a("IfcWall"):
|
||||
layers = tool.Model.get_material_layer_parameters(snap_element)
|
||||
axes = tool.Model.get_wall_axis(snap_obj, layers=layers)
|
||||
axis_base = axes["base"]
|
||||
axis_side = axes["side"]
|
||||
point_on_base_axis = tool.Cad.point_on_edge(mouse_point, axis_base)
|
||||
point_on_side_axis = tool.Cad.point_on_edge(mouse_point, axis_side)
|
||||
if (point_on_base_axis - mouse_point).length_squared <= (point_on_side_axis - mouse_point).length_squared:
|
||||
# mouse is snapped to the base axis, the preview looks exactly like the placed door / window
|
||||
rot_mat = snap_obj.matrix_world.to_quaternion()
|
||||
else:
|
||||
# mouse is snapped to the side axis, the preview is inverted, rotate it now and correct x position later
|
||||
rot_mat = snap_obj.matrix_world.to_quaternion() @ Quaternion(Vector((0, 0, 1)), radians(180))
|
||||
invert_x = True
|
||||
|
||||
mouse_point.z = snap_obj.matrix_world.translation.z
|
||||
|
||||
obj_type = tool.Ifc.get_object(relating_type)
|
||||
if obj_type.data:
|
||||
data = ItemDecorator.get_obj_data(obj_type)
|
||||
data["verts"] = [tuple(obj_type.matrix_world.inverted() @ Vector(v)) for v in data["verts"]]
|
||||
offset_x = 0
|
||||
if invert_x:
|
||||
# correct the x position so that the inverted object occupies the same x extents
|
||||
min_x = min([p[0] for p in data["verts"]])
|
||||
max_x = max([p[0] for p in data["verts"]])
|
||||
offset_x = max_x + min_x
|
||||
data["verts"] = [tuple(rot_mat @ (Vector((v[0], v[1], (v[2] + rl)))) + mouse_point - Vector((offset_x, 0, 0))) for v in data["verts"]]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class PolylineOperator:
|
||||
|
||||
Reference in New Issue
Block a user