1 '''Helper functions for the Robowflex Visualization library.
16 '''Resolves `package://` URLs to their canonical form. The path does not need
17 to exist, but the package does. Can be used to write new files in packages.
19 Returns "" on failure.
28 path = path[len(PREFIX):]
33 package_name = path[:path.find(
"/")]
34 path = path[path.find(
"/"):]
36 package_path1 = subprocess.check_output(
37 [
"rospack",
"find", package_name]).decode().strip()
40 path = os.path.expanduser(path)
42 new_path = os.path.realpath(package_path1 + path)
47 '''Resolves `package://` URLs and relative file paths to their canonical form.
48 Returns "" on failure.
51 if not os.path.exists(full_path):
52 logging.warn(
"File {} does not exist".
format(full_path))
58 '''Selects and returns all children, recursively.'''
61 for child
in item.children:
68 '''Applies smooth shading to the provided object.
70 if bpy.context.mode !=
'OBJECT':
71 bpy.ops.object.mode_set(mode =
'OBJECT')
77 if item.type ==
'MESH':
78 bpy.ops.object.shade_smooth()
84 '''Applies the edge-split modifier to the provided object.
86 if bpy.context.mode !=
'OBJECT':
87 bpy.ops.object.mode_set(mode =
'OBJECT')
93 bpy.ops.object.modifier_add(type =
'EDGE_SPLIT')
94 bpy.context.object.modifiers[
"EdgeSplit"].split_angle = angle
102 '''Retrieves an object by name from a collection.
104 collection = bpy.data.collections.get(coll_name)
105 for item
in collection.objects:
106 if item.name == item_name:
113 '''Moves selected objects to collection.
115 collection = bpy.data.collections.get(name)
116 selected = bpy.context.selected_objects
117 for select
in selected:
120 collection.objects.link(select)
121 old.objects.unlink(select)
125 '''Find the current collection of an object.
127 collections = item.users_collection
128 if len(collections) > 0:
129 return collections[0]
130 return bpy.context.scene.collection
136 collection = bpy.data.collections.get(name)
141 '''Removes a collection and all its contents.
143 collection = bpy.data.collections.get(name)
147 obs = [o
for o
in collection.objects
if o.users == 1]
149 bpy.data.objects.remove(obs.pop())
151 bpy.data.collections.remove(collection)
155 '''Creates a new collection, deleting collections with the same name.
160 collection = bpy.data.collections.new(name)
161 bpy.context.scene.collection.children.link(collection)
166 bpy.ops.object.select_all(action =
'DESELECT')
180 if bpy.context.mode !=
'OBJECT':
181 bpy.ops.object.mode_set(mode =
'OBJECT')
185 child.select_set(
True)
190 bpy.ops.object.constraint_add(type =
'CHILD_OF')
191 constraint = bpy.context.object.constraints[
"Child Of"]
193 constraint.name =
"{}_to_{}".
format(parent.name, child.name)
194 constraint.target = parent
195 constraint.influence = 0.
204 if bpy.context.mode !=
'OBJECT':
205 bpy.ops.object.mode_set(mode =
'OBJECT')
209 child.select_set(
True)
212 name =
"{}_to_{}".
format(parent.name, child.name)
213 constraint = bpy.context.object.constraints[name]
223 bpy.context.scene.frame_set(frame)
227 constraint.influence = 1
228 constraint.keyframe_insert(data_path =
"influence", frame = frame)
233 child.select_set(
True)
235 context_py = bpy.context.copy()
236 context_py[
"constraint"] = constraint
238 bpy.ops.constraint.childof_set_inverse(context_py,
239 constraint = constraint.name,
245 constraint.influence = 0
246 constraint.keyframe_insert(data_path =
"influence", frame = frame - 1)
250 bpy.context.scene.frame_set(frame - 1)
256 constraint.influence = 1
257 constraint.keyframe_insert(data_path =
"influence", frame = frame - 1)
260 constraint.influence = 0
261 constraint.keyframe_insert(data_path =
"influence", frame = frame)
265 bpy.context.view_layer.objects.active = item
269 '''Adds a material to an object.
271 if item.data.materials:
273 item.data.materials[0] = material
277 item.data.materials.append(material)
281 if 'color' in element:
283 mat = bpy.data.materials.new(name = str(random.randint(1, 100000)))
284 if len(element[
'color']) > 3:
285 mat.diffuse_color = element[
'color']
287 mat.diffuse_color = element[
'color'] + (1., )
293 '''Takes a pose dict and extracts the orientation quaternion. ROS quaternions or XYZW, but Blender's are WXYZ, so
297 if 'x' in pose[
'orientation']:
298 q = pose[
'orientation']
299 return mathutils.Quaternion([q[
'w'], q[
'x'], q[
'y'], q[
'z']])
301 if isinstance(pose[
'orientation'][0], str):
303 return mathutils.Quaternion((1.0, 0.0, 0.0, 0.0))
305 return mathutils.Quaternion(pose[
'orientation'][3:] +
306 pose[
'orientation'][:3])
310 '''Takes a pose dict and extracts the position vector.
312 if 'x' in pose[
'position']:
314 return mathutils.Vector([v[
'x'], v[
'y'], v[
'z']])
316 return mathutils.Vector(pose[
'position'])
320 '''Adds the second pose after the first. For something like link origins, the
321 joint pose should be passed first, then the link origin
332 obj.location = p1_vec + p2_vec
336 obj.rotation_mode =
'QUATERNION'
337 obj.rotation_quaternion = q2
341 '''Sets the pose of a blender object by passing in a pose dict.
345 obj.rotation_mode =
'QUATERNION'
350 '''Returns the yaml data structure of the data stored.
354 logging.warn(
'Cannot open {}'.
format(file_name))
356 with open(full_name)
as input_file:
357 return yaml.load(input_file.read(), Loader=yaml.SafeLoader)
361 if bpy.context.mode !=
'OBJECT':
362 bpy.ops.object.mode_set(mode =
'OBJECT')
366 item.select_set(
True)
367 if item.type ==
'MESH':
368 bpy.ops.object.mode_set(mode =
'EDIT')
369 bpy.ops.mesh.select_all(action =
'SELECT')
370 bpy.ops.mesh.remove_doubles(threshold = threshold)
371 bpy.ops.object.mode_set(mode =
'OBJECT')
377 if bpy.context.mode !=
'OBJECT':
378 bpy.ops.object.mode_set(mode =
'OBJECT')
382 item.select_set(
True)
383 if item.type ==
'MESH':
384 bpy.ops.object.mode_set(mode =
'EDIT')
385 bpy.ops.mesh.select_all(action =
'SELECT')
386 bpy.ops.mesh.select_mode(type =
'FACE')
387 bpy.ops.mesh.select_interior_faces()
388 bpy.ops.mesh.delete(type =
'FACE')
389 bpy.ops.object.mode_set(mode =
'OBJECT')
395 for mat
in obj.data.materials:
398 for node
in mat.node_tree.nodes:
399 if 'Alpha' in node.inputs:
400 node.inputs[
'Alpha'].default_value = 1.
411 rot = mathutils.Euler(rpy,
'XYZ').to_matrix()
413 pos = mathutils.Matrix.Translation(xyz)
std::string format(const std::string &fmt, Args &&... args)
Recursion base case, return string form of formatted arguments.
def remove_inner_faces(item)
def find_object_in_collection(coll_name, item_name)
def create_object_parent(parent, child)
def set_color(obj, element)
def make_collection(name)
def move_selected_to_collection(name)
def resolve_package(path)
def get_object_parent(parent, child)
def remove_doubles(item, threshold=0.0001)
def unparent_object(parent, child, frame)
def get_tf_origin_xml(xml)
def apply_smooth_shade(item)
def pose_add(obj, pose1, pose2)
def read_YAML_data(file_name)
def remove_collection(name, remove_objects=True)
def parent_object(parent, child, frame)
def add_material(item, material)
def apply_edge_split(item, angle=math.pi/8)
def select_all_children(item)
def find_collection(item)