mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 10:51:13 +00:00
drawing grid clipping
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import math
|
import math
|
||||||
|
from mathutils import geometry
|
||||||
|
from mathutils import Vector
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
|
||||||
@@ -285,3 +287,94 @@ def format_distance(value, isArea=False, hide_units=True):
|
|||||||
tx_dist = fmt % value
|
tx_dist = fmt % value
|
||||||
|
|
||||||
return tx_dist
|
return tx_dist
|
||||||
|
|
||||||
|
|
||||||
|
def parse_diagram_scale(camera):
|
||||||
|
"""Returns numeric value of scale"""
|
||||||
|
if camera.BIMCameraProperties.diagram_scale == "CUSTOM":
|
||||||
|
_, fraction = camera.BIMCameraProperties.custom_diagram_scale.split("|")
|
||||||
|
else:
|
||||||
|
_, fraction = camera.BIMCameraProperties.diagram_scale.split("|")
|
||||||
|
numerator, denominator = fraction.split("/")
|
||||||
|
return float(numerator) / float(denominator)
|
||||||
|
|
||||||
|
|
||||||
|
def ortho_view_frame(camera, margin=0.015):
|
||||||
|
"""Calculates 2d bounding box of camera view area.
|
||||||
|
|
||||||
|
Similar to `bpy.types.Camera.view_frame`
|
||||||
|
|
||||||
|
:arg camera: camera of drawing
|
||||||
|
:type camera: bpy.types.Camera + BIMCameraProperties
|
||||||
|
:arg margin: margins, in scene units
|
||||||
|
:type margin: float
|
||||||
|
:return: (xmin, xmax, ymin, ymax) in local camera coordinates
|
||||||
|
"""
|
||||||
|
aspect = camera.BIMCameraProperties.raster_y / camera.BIMCameraProperties.raster_x
|
||||||
|
size = camera.ortho_scale
|
||||||
|
hwidth = size * .5
|
||||||
|
hheight = size * .5 * aspect
|
||||||
|
scale = parse_diagram_scale(camera)
|
||||||
|
xmarg = margin * scale
|
||||||
|
ymarg = margin * scale * aspect
|
||||||
|
return (-hwidth + xmarg, hwidth - xmarg, -hheight + ymarg, hheight - ymarg)
|
||||||
|
|
||||||
|
|
||||||
|
def clip_segment(bounds, segm):
|
||||||
|
"""Clipping line segment to bounds
|
||||||
|
|
||||||
|
:arg bounds: (xmin, xmax, ymin, ymax)
|
||||||
|
:arg segm: 2 vertices of the segment
|
||||||
|
:return: 2 new vertices of segment or None if segment outside the bounding box
|
||||||
|
"""
|
||||||
|
# Liang–Barsky algorithm
|
||||||
|
|
||||||
|
def iszero(v):
|
||||||
|
return abs(v) < 1e-10
|
||||||
|
|
||||||
|
xmin, xmax, ymin, ymax = bounds
|
||||||
|
p1, p2 = segm
|
||||||
|
|
||||||
|
dlt = p2 - p1
|
||||||
|
q_l = p1.x - xmin
|
||||||
|
q_r = xmax - p1.x
|
||||||
|
q_t = p1.y - ymin
|
||||||
|
q_b = ymax - p1.y
|
||||||
|
|
||||||
|
pos = [1]
|
||||||
|
neg = [0]
|
||||||
|
|
||||||
|
if (iszero(dlt.x) and (q_l < 0 or q_r < 0)) or (iszero(dlt.y) and (q_t < 0 or q_b < 0)):
|
||||||
|
# parallel to a boundary and outside it
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not iszero(dlt.x):
|
||||||
|
t_l = q_l / -dlt.x
|
||||||
|
t_r = q_r / dlt.x
|
||||||
|
if t_l < 0:
|
||||||
|
neg.append(t_l)
|
||||||
|
pos.append(t_r)
|
||||||
|
else:
|
||||||
|
neg.append(t_r)
|
||||||
|
pos.append(t_l)
|
||||||
|
|
||||||
|
if not iszero(dlt.y):
|
||||||
|
t_t = q_t / -dlt.y
|
||||||
|
t_b = q_b / dlt.y
|
||||||
|
if t_t < 0:
|
||||||
|
neg.append(t_t)
|
||||||
|
pos.append(t_b)
|
||||||
|
else:
|
||||||
|
neg.append(t_b)
|
||||||
|
pos.append(t_t)
|
||||||
|
|
||||||
|
t1 = max(neg)
|
||||||
|
t2 = min(pos)
|
||||||
|
|
||||||
|
if t1 > t2:
|
||||||
|
return None
|
||||||
|
|
||||||
|
p1c = p1 + dlt * t1
|
||||||
|
p2c = p1 + dlt * t2
|
||||||
|
|
||||||
|
return p1c, p2c
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from . import helper
|
|||||||
from bpy_extras.io_utils import ImportHelper
|
from bpy_extras.io_utils import ImportHelper
|
||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
from mathutils import Vector, Matrix, Euler, geometry
|
from mathutils import Vector, Matrix, Euler, geometry
|
||||||
|
import bmesh
|
||||||
from math import radians, degrees, atan, tan, cos, sin
|
from math import radians, degrees, atan, tan, cos, sin
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from bpy.app.handlers import persistent
|
from bpy.app.handlers import persistent
|
||||||
@@ -4226,13 +4227,42 @@ class CopyGrid(bpy.types.Operator):
|
|||||||
collection.objects.unlink(obj)
|
collection.objects.unlink(obj)
|
||||||
|
|
||||||
source = [obj
|
source = [obj
|
||||||
for coll in bpy.data.collections
|
for coll in bpy.data.collections
|
||||||
if coll.name.startswith('IfcGrid')
|
if coll.name.startswith("IfcGrid")
|
||||||
for obj in coll.all_objects
|
for obj in coll.all_objects
|
||||||
if obj.type == 'MESH']
|
if obj.name.startswith("IfcGridAxis")]
|
||||||
for obj in source:
|
camera = [obj
|
||||||
dstobj = obj.copy()
|
for obj in collection.all_objects
|
||||||
dstobj.data = dstobj.data.copy()
|
if obj.type == 'CAMERA'][0]
|
||||||
collection.objects.link(dstobj)
|
|
||||||
|
clipping = camera.data.type == 'ORTHO'
|
||||||
|
bounds = helper.ortho_view_frame(camera.data) if clipping else None
|
||||||
|
|
||||||
|
for src in source:
|
||||||
|
bm = bmesh.new()
|
||||||
|
bm.from_mesh(src.data)
|
||||||
|
bm.verts.ensure_lookup_table()
|
||||||
|
|
||||||
|
if clipping:
|
||||||
|
proj = src.matrix_world @ camera.matrix_world.inverted()
|
||||||
|
unproj = src.matrix_world.inverted() @ camera.matrix_world
|
||||||
|
|
||||||
|
bm.transform(proj)
|
||||||
|
|
||||||
|
points_orig = [v.co for v in bm.verts[0:2]]
|
||||||
|
points_clip = helper.clip_segment(bounds, points_orig)
|
||||||
|
|
||||||
|
if points_clip is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
bm.verts[0].co = points_clip[0]
|
||||||
|
bm.verts[1].co = points_clip[1]
|
||||||
|
|
||||||
|
bm.transform(unproj)
|
||||||
|
|
||||||
|
dst = src.copy()
|
||||||
|
dst.data = bpy.data.meshes.new(dst.name)
|
||||||
|
bm.to_mesh(dst.data)
|
||||||
|
collection.objects.link(dst)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
Reference in New Issue
Block a user