-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevice.py
More file actions
177 lines (148 loc) · 4.65 KB
/
Copy pathdevice.py
File metadata and controls
177 lines (148 loc) · 4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# bpy-only syntax
# pyright: reportAttributeAccessIssue=false
# pyright: reportInvalidTypeForm=false
import bpy
from .ui import redraw_ui
from mathutils import Quaternion
def update_object(self, context):
if self.object_backup:
self.apply_transform(self["transform_backup"], True)
self.object_backup = self.object
self["transform_backup"] = self.get_transform()
def apply_rotation(obj, mode, rot):
match mode:
case 'QUATERNION':
obj.rotation_quaternion = rot
case 'AXIS_ANGLE':
obj.rotation_axis_angle = rot.to_axis_angle()
case _:
obj.rotation_euler = rot.to_euler(mode)
class BmcDevice(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(
name="Device Name",
description="Name of the device"
)
ip: bpy.props.StringProperty(
name="Device IP Address",
description="IP address of the device"
)
port: bpy.props.IntProperty(
name="Device Port",
description="Remote port the device is communicating from"
)
object: bpy.props.PointerProperty(
type=bpy.types.Object,
name="Controlled Object",
description="Object controlled by this device",
update=update_object
)
object_backup: bpy.props.PointerProperty(
type=bpy.types.Object
)
loc_mode: bpy.props.EnumProperty(
name="Location Mode",
description="How to apply device location to object",
items=[
("add", "Add", "Add device location to object location"),
("replace", "Replace", "Set object location to device location"),
("disabled", "Off", "Do not apply device location to object")
],
default="add"
)
rot_mode: bpy.props.EnumProperty(
name="Rotation Mode",
description="How to apply device rotation to object",
items=[
("add", "Add", "Add device rotation to object rotation"),
("replace", "Replace", "Set object rotation to device rotation"),
("disabled", "Off", "Do not apply device rotation to object")
],
default="add"
)
loc_scale: bpy.props.FloatProperty(
name="Location Scale",
description="Scale factor for device location (1.0 is 1:1 with real world)",
min=0.0,
soft_min=0.1,
soft_max=100.0,
default=1.0
)
def get_transform(self):
if self.object is None:
return {}
mode = self.object.rotation_mode
self.object.rotation_mode = 'QUATERNION'
transform = {
"loc": list(self.object.location),
"rot": list(self.object.rotation_quaternion),
"scale": list(self.object.scale)
}
self.object.rotation_mode = mode
return transform
def apply_transform(self, transform: dict, apply_to_backup: bool = False):
obj = None
if apply_to_backup:
obj = self.object_backup
else:
obj = self.object
if obj is None:
return
loc = transform.get("loc", None)
rot = transform.get("rot", None)
scale = transform.get("scale", None)
do_keyframes = False
if bpy.context.scene is not None:
do_keyframes = bpy.context.scene.tool_settings.use_keyframe_insert_auto
if loc is not None:
if apply_to_backup:
obj.location = loc
else:
if self.loc_mode == 'add':
obj.location = [a + b for a, b in zip([a * self.loc_scale for a in loc], self["transform_backup"]["loc"])]
elif self.loc_mode == 'replace':
obj.location = [a * self.loc_scale for a in loc]
elif self.loc_mode == 'disabled':
obj.location = self["transform_backup"]["loc"]
if do_keyframes and not self.loc_mode == 'disabled':
obj.keyframe_insert(data_path="location")
if rot is not None:
rot = Quaternion(rot)
mode = obj.rotation_mode
if apply_to_backup:
apply_rotation(obj, mode, rot)
else:
if self.rot_mode == 'add':
apply_rotation(obj, mode, rot @ Quaternion(self["transform_backup"]["rot"]))
elif self.rot_mode == 'replace':
apply_rotation(obj, mode, rot)
elif self.rot_mode == 'disabled':
apply_rotation(obj, mode, Quaternion(self["transform_backup"]["rot"]))
if do_keyframes and not self.loc_mode == 'disabled':
path = "rotation_quaternion"
match mode:
case 'AXIS_ANGLE':
path = "rotation_axis_angle"
case _:
path = "rotation_euler"
obj.keyframe_insert(data_path=path)
# if scale is not None:
# obj.scale = scale
def add_bmc_device(name, ip, port):
assert bpy.context.window_manager is not None
device = bpy.context.window_manager.bmc_devices.add()
device.name = name
device.ip = ip
device.port = port
if bpy.context.view_layer is not None:
if bpy.context.view_layer.objects.active is not None:
device.object = bpy.context.view_layer.objects.active
redraw_ui()
return device
def remove_bmc_device(ip):
assert bpy.context.window_manager is not None
wm = bpy.context.window_manager
for i, device in enumerate(wm.bmc_devices):
if device.ip == ip:
wm.bmc_devices.remove(i)
redraw_ui()
return