mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 09:08:40 +00:00
moved raycasting functions to Raycasting module
This commit is contained in:
committed by
Bruno Perdigão
parent
cef8251458
commit
bf96c63f7d
@@ -312,41 +312,6 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
self.input_panel = {"X": "", "Y": "", "D": "", "A": ""}
|
self.input_panel = {"X": "", "Y": "", "D": "", "A": ""}
|
||||||
self.snap_angle = None
|
self.snap_angle = None
|
||||||
|
|
||||||
def get_visible_objects(self, context):
|
|
||||||
depsgraph = context.evaluated_depsgraph_get()
|
|
||||||
all_objs = []
|
|
||||||
for dup in depsgraph.object_instances:
|
|
||||||
if dup.is_instance: # Real dupli instance
|
|
||||||
obj = dup.instance_object
|
|
||||||
all_objs.append(obj)
|
|
||||||
else: # Usual object
|
|
||||||
obj = dup.object
|
|
||||||
all_objs.append(obj)
|
|
||||||
return all_objs
|
|
||||||
|
|
||||||
def get_objects_2d_bounding_boxes(self, context, obj):
|
|
||||||
obj_matrix = obj.matrix_world.copy()
|
|
||||||
bbox = [obj_matrix @ Vector(v) for v in obj.bound_box]
|
|
||||||
|
|
||||||
transposed_bbox = []
|
|
||||||
bbox_2d = []
|
|
||||||
|
|
||||||
for v in bbox:
|
|
||||||
coord_2d = view3d_utils.location_3d_to_region_2d(context.region, context.space_data.region_3d, v)
|
|
||||||
if coord_2d is not None:
|
|
||||||
transposed_bbox.append(coord_2d)
|
|
||||||
|
|
||||||
region = context.region
|
|
||||||
borders = (region.width, region.height)
|
|
||||||
for i, axis in enumerate(zip(*transposed_bbox)):
|
|
||||||
if all(ax < 0 or ax > borders[i] for ax in axis): # Filter only objects in viewport
|
|
||||||
return (obj, None)
|
|
||||||
min_point = min(axis)
|
|
||||||
max_point = max(axis)
|
|
||||||
bbox_2d.extend([min_point, max_point])
|
|
||||||
|
|
||||||
return (obj, bbox_2d)
|
|
||||||
|
|
||||||
def snaping_movement(self, context, event):
|
def snaping_movement(self, context, event):
|
||||||
region = context.region
|
region = context.region
|
||||||
rv3d = context.region_data
|
rv3d = context.region_data
|
||||||
@@ -369,53 +334,6 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
plane_origin = Vector((0, 0, 0))
|
plane_origin = Vector((0, 0, 0))
|
||||||
plane_normal = Vector((0, 0, 1))
|
plane_normal = Vector((0, 0, 1))
|
||||||
|
|
||||||
def get_viewport_ray_data():
|
|
||||||
view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, self.mouse_pos)
|
|
||||||
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, self.mouse_pos)
|
|
||||||
ray_target = ray_origin + view_vector
|
|
||||||
ray_direction = ray_target - ray_origin
|
|
||||||
|
|
||||||
return ray_origin, ray_target, ray_direction
|
|
||||||
|
|
||||||
def get_object_ray_data(obj_matrix):
|
|
||||||
ray_origin, ray_target, _ = get_viewport_ray_data()
|
|
||||||
matrix_inv = obj_matrix.inverted()
|
|
||||||
ray_origin_obj = matrix_inv @ ray_origin
|
|
||||||
ray_target_obj = matrix_inv @ ray_target
|
|
||||||
ray_direction_obj = ray_target_obj - ray_origin_obj
|
|
||||||
|
|
||||||
return ray_origin_obj, ray_target_obj, ray_direction_obj
|
|
||||||
|
|
||||||
def in_view_2d_bounding_box(bbox):
|
|
||||||
x, y = self.mouse_pos
|
|
||||||
xmin, xmax, ymin, ymax = bbox
|
|
||||||
|
|
||||||
if xmin < x < xmax and ymin < y < ymax:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def obj_ray_cast(obj):
|
|
||||||
ray_origin_obj, _, ray_direction_obj = get_object_ray_data(obj.matrix_world.copy())
|
|
||||||
success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
|
|
||||||
if success:
|
|
||||||
return location, normal, face_index
|
|
||||||
else:
|
|
||||||
return None, None, None
|
|
||||||
|
|
||||||
def ray_cast_to_plane(plane_origin, plane_normal):
|
|
||||||
intersection = Vector((0, 0, 0))
|
|
||||||
try:
|
|
||||||
loc = view3d_utils.region_2d_to_location_3d(region, rv3d, self.mouse_pos, ray_direction)
|
|
||||||
intersection = mathutils.geometry.intersect_line_plane(ray_target, loc, plane_origin, plane_normal)
|
|
||||||
except:
|
|
||||||
intersection = Vector((0, 0, 0))
|
|
||||||
|
|
||||||
if intersection == None:
|
|
||||||
intersection = Vector((0, 0, 0))
|
|
||||||
|
|
||||||
return intersection
|
|
||||||
|
|
||||||
def cast_rays_and_get_best_object():
|
def cast_rays_and_get_best_object():
|
||||||
best_length_squared = 1.0
|
best_length_squared = 1.0
|
||||||
best_obj = None
|
best_obj = None
|
||||||
@@ -426,17 +344,17 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
|
|
||||||
for obj, bbox_2d in self.objs_2d_bbox:
|
for obj, bbox_2d in self.objs_2d_bbox:
|
||||||
if obj.type == "MESH" and bbox_2d:
|
if obj.type == "MESH" and bbox_2d:
|
||||||
if in_view_2d_bounding_box(bbox_2d):
|
if tool.Raycasting.in_view_2d_bounding_box(self.mouse_pos, bbox_2d):
|
||||||
objs_to_raycast.append(obj)
|
objs_to_raycast.append(obj)
|
||||||
|
|
||||||
for obj in objs_to_raycast:
|
for obj in objs_to_raycast:
|
||||||
hit, normal, face_index = obj_ray_cast(obj)
|
hit, normal, face_index = tool.Raycasting.obj_ray_cast(context, event, obj)
|
||||||
if hit is None:
|
if hit is None:
|
||||||
# Tried original mouse position. Now it will try the offsets.
|
# Tried original mouse position. Now it will try the offsets.
|
||||||
original_mouse_pos = self.mouse_pos
|
original_mouse_pos = self.mouse_pos
|
||||||
for value in mouse_offset:
|
for value in mouse_offset:
|
||||||
self.mouse_pos = tuple(x + y for x, y in zip(original_mouse_pos, value))
|
self.mouse_pos = tuple(x + y for x, y in zip(original_mouse_pos, value))
|
||||||
hit, normal, face_index = obj_ray_cast(obj)
|
hit, normal, face_index = tool.Raycasting.obj_ray_cast(context, event, obj)
|
||||||
if hit:
|
if hit:
|
||||||
break
|
break
|
||||||
self.mouse_pos = original_mouse_pos
|
self.mouse_pos = original_mouse_pos
|
||||||
@@ -456,9 +374,9 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
snap_threshold = 0.3
|
snap_threshold = 0.3
|
||||||
ray_origin, ray_target, ray_direction = get_viewport_ray_data()
|
ray_origin, ray_target, ray_direction = tool.Raycasting.get_viewport_ray_data(context, event)
|
||||||
obj, hit, face_index = cast_rays_and_get_best_object()
|
obj, hit, face_index = cast_rays_and_get_best_object()
|
||||||
intersection = ray_cast_to_plane(plane_origin, plane_normal)
|
intersection = tool.Raycasting.ray_cast_to_plane(context, event, plane_origin, plane_normal)
|
||||||
|
|
||||||
# Locks snap into an angle axis
|
# Locks snap into an angle axis
|
||||||
if event.shift:
|
if event.shift:
|
||||||
@@ -475,10 +393,12 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
if snap_point:
|
if snap_point:
|
||||||
# Creates a mixed snap point between the locked axis and
|
# Creates a mixed snap point between the locked axis and
|
||||||
# the object snap
|
# the object snap
|
||||||
# TODO Use ALT key to give the user the option to choose between the two results.
|
# TODO Use ALT key to give the user the option to choose between the two results.
|
||||||
# TODO Create decorator for this
|
# TODO Create decorator for this
|
||||||
try:
|
try:
|
||||||
snap_point_vector = Vector((snap_point[0].x, snap_point[0].y, snap_point[0].z)) # TODO use Z from default container
|
snap_point_vector = Vector(
|
||||||
|
(snap_point[0].x, snap_point[0].y, snap_point[0].z)
|
||||||
|
) # TODO use Z from default container
|
||||||
snap_point_axis_1 = (
|
snap_point_axis_1 = (
|
||||||
Vector((snap_point[0].x + 1000, snap_point[0].y, 0)),
|
Vector((snap_point[0].x + 1000, snap_point[0].y, 0)),
|
||||||
Vector((snap_point[0].x - 1000, snap_point[0].y, 0)),
|
Vector((snap_point[0].x - 1000, snap_point[0].y, 0)),
|
||||||
@@ -489,11 +409,11 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
snap_angle_axis = (axis_start, axis_end)
|
snap_angle_axis = (axis_start, axis_end)
|
||||||
result_1 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_1)
|
result_1 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_1)
|
||||||
result_1 = Vector((result_1[0].x, result_1[0].y, 0)) # TODO use Z from default container
|
result_1 = Vector((result_1[0].x, result_1[0].y, 0)) # TODO use Z from default container
|
||||||
distance_1 = (result_1 - snap_point_vector).length
|
distance_1 = (result_1 - snap_point_vector).length
|
||||||
|
|
||||||
result_2 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_2)
|
result_2 = tool.Cad.intersect_edges(snap_angle_axis, snap_point_axis_2)
|
||||||
result_2 = Vector((result_2[0].x, result_2[0].y, 0)) # TODO use Z from default container
|
result_2 = Vector((result_2[0].x, result_2[0].y, 0)) # TODO use Z from default container
|
||||||
distance_2 = (result_2 - snap_point_vector).length
|
distance_2 = (result_2 - snap_point_vector).length
|
||||||
|
|
||||||
if distance_1 < distance_2:
|
if distance_1 < distance_2:
|
||||||
@@ -581,7 +501,6 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
||||||
tool.Blender.update_viewport()
|
tool.Blender.update_viewport()
|
||||||
|
|
||||||
|
|
||||||
# TODO This is creating a hack in generate function from DumbWallGenerator
|
# TODO This is creating a hack in generate function from DumbWallGenerator
|
||||||
# Come up with a better solution
|
# Come up with a better solution
|
||||||
def create_walls_from_polyline(self, context):
|
def create_walls_from_polyline(self, context):
|
||||||
@@ -614,7 +533,7 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
if self.mousemove_count == 2:
|
if self.mousemove_count == 2:
|
||||||
self.objs_2d_bbox = []
|
self.objs_2d_bbox = []
|
||||||
for obj in self.visible_objs:
|
for obj in self.visible_objs:
|
||||||
self.objs_2d_bbox.append(self.get_objects_2d_bounding_boxes(context, obj))
|
self.objs_2d_bbox.append(tool.Raycasting.get_objects_2d_bounding_boxes(context, obj))
|
||||||
|
|
||||||
if self.mousemove_count > 3:
|
if self.mousemove_count > 3:
|
||||||
self.snaping_movement(context, event)
|
self.snaping_movement(context, event)
|
||||||
@@ -732,13 +651,10 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
if context.space_data.type == "VIEW_3D":
|
if context.space_data.type == "VIEW_3D":
|
||||||
WallPolylineDecorator.install(context)
|
WallPolylineDecorator.install(context)
|
||||||
# self.is_input_on = False
|
|
||||||
# self.input_type = "OFF"
|
|
||||||
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
WallPolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
||||||
# self.objs_2d_bbox = []
|
self.visible_objs = tool.Raycasting.get_visible_objects(context)
|
||||||
self.visible_objs = self.get_visible_objects(context)
|
|
||||||
for obj in self.visible_objs:
|
for obj in self.visible_objs:
|
||||||
self.objs_2d_bbox.append(self.get_objects_2d_bounding_boxes(context, obj))
|
self.objs_2d_bbox.append(tool.Raycasting.get_objects_2d_bounding_boxes(context, obj))
|
||||||
self.snaping_movement(context, event)
|
self.snaping_movement(context, event)
|
||||||
WallPolylineDecorator.set_mouse_position(event)
|
WallPolylineDecorator.set_mouse_position(event)
|
||||||
self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, self.is_input_on)
|
self.input_panel = WallPolylineDecorator.calculate_distance_and_angle(context, self.is_input_on)
|
||||||
|
|||||||
@@ -659,6 +659,9 @@ class Qto:
|
|||||||
def get_rounded_value(cls, new_quantity): pass
|
def get_rounded_value(cls, new_quantity): pass
|
||||||
def set_qto_result(cls, result): pass
|
def set_qto_result(cls, result): pass
|
||||||
|
|
||||||
|
@interface
|
||||||
|
class Raycasting:
|
||||||
|
pass
|
||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Resource:
|
class Resource:
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ from blenderbim.tool.project import Project
|
|||||||
from blenderbim.tool.profile import Profile
|
from blenderbim.tool.profile import Profile
|
||||||
from blenderbim.tool.pset import Pset
|
from blenderbim.tool.pset import Pset
|
||||||
from blenderbim.tool.qto import Qto
|
from blenderbim.tool.qto import Qto
|
||||||
|
from blenderbim.tool.raycasting import Raycasting
|
||||||
from blenderbim.tool.resource import Resource
|
from blenderbim.tool.resource import Resource
|
||||||
from blenderbim.tool.root import Root
|
from blenderbim.tool.root import Root
|
||||||
from blenderbim.tool.sequence import Sequence
|
from blenderbim.tool.sequence import Sequence
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2022 Cyril Waechter <cyril@biminsight.ch>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
from bpy_extras import view3d_utils
|
||||||
|
import blenderbim.core.tool
|
||||||
|
|
||||||
|
# from blenderbim.bim.module.model.decorator import WallPolylineDecorator
|
||||||
|
import math
|
||||||
|
import mathutils
|
||||||
|
from mathutils import Matrix, Vector
|
||||||
|
|
||||||
|
|
||||||
|
class Raycasting(blenderbim.core.tool.Raycasting):
|
||||||
|
@classmethod
|
||||||
|
def get_visible_objects(cls, context):
|
||||||
|
depsgraph = context.evaluated_depsgraph_get()
|
||||||
|
all_objs = []
|
||||||
|
for dup in depsgraph.object_instances:
|
||||||
|
if dup.is_instance: # Real dupli instance
|
||||||
|
obj = dup.instance_object
|
||||||
|
all_objs.append(obj)
|
||||||
|
else: # Usual object
|
||||||
|
obj = dup.object
|
||||||
|
all_objs.append(obj)
|
||||||
|
return all_objs
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_objects_2d_bounding_boxes(cls, context, obj):
|
||||||
|
obj_matrix = obj.matrix_world.copy()
|
||||||
|
bbox = [obj_matrix @ Vector(v) for v in obj.bound_box]
|
||||||
|
|
||||||
|
transposed_bbox = []
|
||||||
|
bbox_2d = []
|
||||||
|
|
||||||
|
for v in bbox:
|
||||||
|
coord_2d = view3d_utils.location_3d_to_region_2d(context.region, context.space_data.region_3d, v)
|
||||||
|
if coord_2d is not None:
|
||||||
|
transposed_bbox.append(coord_2d)
|
||||||
|
|
||||||
|
region = context.region
|
||||||
|
borders = (region.width, region.height)
|
||||||
|
for i, axis in enumerate(zip(*transposed_bbox)):
|
||||||
|
if all(ax < 0 or ax > borders[i] for ax in axis): # Filter only objects in viewport
|
||||||
|
return (obj, None)
|
||||||
|
min_point = min(axis)
|
||||||
|
max_point = max(axis)
|
||||||
|
bbox_2d.extend([min_point, max_point])
|
||||||
|
|
||||||
|
return (obj, bbox_2d)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def in_view_2d_bounding_box(cls, mouse_pos, bbox):
|
||||||
|
x, y = mouse_pos
|
||||||
|
xmin, xmax, ymin, ymax = bbox
|
||||||
|
|
||||||
|
if xmin < x < xmax and ymin < y < ymax:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_viewport_ray_data(cls, context, event):
|
||||||
|
region = context.region
|
||||||
|
rv3d = context.region_data
|
||||||
|
mouse_pos = event.mouse_region_x, event.mouse_region_y
|
||||||
|
|
||||||
|
view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, mouse_pos)
|
||||||
|
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, mouse_pos)
|
||||||
|
ray_target = ray_origin + view_vector
|
||||||
|
ray_direction = ray_target - ray_origin
|
||||||
|
|
||||||
|
return ray_origin, ray_target, ray_direction
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_object_ray_data(cls, context, event, obj_matrix):
|
||||||
|
ray_origin, ray_target, _ = cls.get_viewport_ray_data(context, event)
|
||||||
|
matrix_inv = obj_matrix.inverted()
|
||||||
|
ray_origin_obj = matrix_inv @ ray_origin
|
||||||
|
ray_target_obj = matrix_inv @ ray_target
|
||||||
|
ray_direction_obj = ray_target_obj - ray_origin_obj
|
||||||
|
|
||||||
|
return ray_origin_obj, ray_target_obj, ray_direction_obj
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def obj_ray_cast(cls, context, event, obj):
|
||||||
|
ray_origin_obj, _, ray_direction_obj = cls.get_object_ray_data(context, event, obj.matrix_world.copy())
|
||||||
|
success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
|
||||||
|
if success:
|
||||||
|
return location, normal, face_index
|
||||||
|
else:
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ray_cast_to_plane(cls, context, event, plane_origin, plane_normal):
|
||||||
|
region = context.region
|
||||||
|
rv3d = context.region_data
|
||||||
|
mouse_pos = event.mouse_region_x, event.mouse_region_y
|
||||||
|
ray_origin, ray_target, ray_direction = cls.get_viewport_ray_data(context, event)
|
||||||
|
|
||||||
|
intersection = Vector((0, 0, 0))
|
||||||
|
try:
|
||||||
|
loc = view3d_utils.region_2d_to_location_3d(region, rv3d, mouse_pos, ray_direction)
|
||||||
|
intersection = mathutils.geometry.intersect_line_plane(ray_target, loc, plane_origin, plane_normal)
|
||||||
|
except:
|
||||||
|
intersection = Vector((0, 0, 0))
|
||||||
|
|
||||||
|
if intersection == None:
|
||||||
|
intersection = Vector((0, 0, 0))
|
||||||
|
|
||||||
|
return intersection
|
||||||
Reference in New Issue
Block a user