def execute(self, context): obj = context.active_object # rename only if necessary if self.newname != '' and self.newname != nUtils.getObjectName(obj): log("Renaming " + obj.phobostype + " '" + nUtils.getObjectName(obj) + "' to '" + self.newname + "'.", 'INFO') nUtils.safelyName(obj, self.newname) elif self.newname == '': log("Removing custom name from " + obj.phobostype + " '" + obj.name + "'.", 'INFO') if obj.phobostype + '/name' in obj: del obj[obj.phobostype + '/name'] # only links have joint names if obj.phobostype == 'link': if self.jointname != '': # only change/add joint/name if it was changed if 'joint/name' not in obj or ( 'joint/name' in obj and self.jointname != obj['joint/name']): log("Renaming joint of " + obj.phobostype + " '" + nUtils.getObjectName(obj) + "' to '" + self.jointname + "'.", 'INFO') obj['joint/name'] = self.jointname # remove joint/name when empty elif self.jointname == '': if 'joint/name' in obj: log("Removing joint name from " + obj.phobostype + " '" + obj.name + "'.", 'INFO') del obj['joint/name'] return {'FINISHED'}
def createLink(link): """Creates the blender representation of a given link and its parent joint. Args: link(dict): The link you want to create a representation of. Returns: bpy_types.Object -- the newly created blender link object. """ # create armature/bone bUtils.toggleLayer(defs.layerTypes['link'], True) bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.armature_add( layers=bUtils.defLayers([defs.layerTypes['link']])) newlink = bpy.context.active_object # Move bone when adding at selected objects location if 'matrix' in link: newlink.matrix_world = link['matrix'] newlink.phobostype = 'link' if link['name'] in bpy.data.objects.keys(): log('Object with name of new link already exists: ' + link['name'], 'WARNING') nUtils.safelyName(newlink, link['name']) # set the size of the link visuals, collisions = getGeometricElements(link) if visuals or collisions: scale = max((geometrymodel.getLargestDimension(e['geometry']) for e in visuals + collisions)) else: scale = 0.2 # use scaling factor provided by user if 'scale' in link: scale *= link['scale'] newlink.scale = (scale, scale, scale) bpy.ops.object.transform_apply(scale=True) # add custom properties for prop in link: if prop.startswith('$'): for tag in link[prop]: newlink['link/' + prop[1:] + '/' + tag] = link[prop][tag] # create inertial if 'inertial' in link: inertia.createInertial(link['name'], link['inertial'], newlink) # create geometric elements log( "Creating visual and collision objects for link '{0}': {1}".format( link['name'], ', '.join([elem['name'] for elem in visuals + collisions])), 'DEBUG') for v in visuals: geometrymodel.createGeometry(v, 'visual', newlink) for c in collisions: geometrymodel.createGeometry(c, 'collision', newlink) return newlink
def execute(self, context): """ Args: context: Returns: """ obj = context.active_object # rename only if necessary if self.newname != '' and self.newname != nUtils.getObjectName(obj): log( "Renaming " + obj.phobostype + " '" + nUtils.getObjectName(obj) + "' to '" + self.newname + "'.", 'INFO', ) nUtils.safelyName(obj, self.newname) elif self.newname == '': log("Removing custom name from " + obj.phobostype + " '" + obj.name + "'.", 'INFO') if obj.phobostype + '/name' in obj: del obj[obj.phobostype + '/name'] # only links have joint names if obj.phobostype == 'link': if self.jointname != '': # only change/add joint/name if it was changed if 'joint/name' not in obj or ( 'joint/name' in obj and self.jointname != obj['joint/name'] ): log( "Renaming joint of " + obj.phobostype + " '" + nUtils.getObjectName(obj) + "' to '" + self.jointname + "'.", 'INFO', ) obj['joint/name'] = self.jointname # remove joint/name when empty elif self.jointname == '': if 'joint/name' in obj: log( "Removing joint name from " + obj.phobostype + " '" + obj.name + "'.", 'INFO', ) del obj['joint/name'] return {'FINISHED'}
def createInterface(ifdict, parent=None): """Create an interface object and optionally parent to existing object. ifdict is expected as: | **type**: str | **direction**: str | **model**: str | **name**: str | **parent**: bpy.types.Object (optional) | **scale**: float (optional) Args: ifdict(dict): interface data parent(bpy.types.Object, optional): designated parent object (Default value = None) Returns: bpy.data.Object: newly created interface object """ if not parent: try: parent = ifdict['parent'] assert isinstance(parent, bpy.types.Object) except (AttributeError, AssertionError, KeyError): parent = None location = parent.matrix_world.translation if parent else mathutils.Vector( ) rotation = parent.matrix_world.to_euler() if parent else mathutils.Euler() model = ifdict['model'] if 'model' in ifdict else 'default' templateobj = ioUtils.getResource( ('interface', model, ifdict['direction'])) scale = ifdict['scale'] if 'scale' in ifdict else 1.0 ifobj = bUtils.createPrimitive( ifdict['name'], 'box', (1.0, 1.0, 1.0), defs.layerTypes['interface'], plocation=location, protation=rotation, phobostype='interface', ) nUtils.safelyName(ifobj, ifdict['name'], 'interface') ifobj.data = templateobj.data ifobj.scale = (scale, ) * 3 ifobj['interface/type'] = ifdict['type'] ifobj['interface/direction'] = ifdict['direction'] if parent is not None: ifobj['interface/parent'] = parent.name parentObjectsTo(ifobj, parent) bpy.ops.object.make_single_user(object=True, obdata=True)
def createInterface(ifdict, parent=None): """Create an interface object and optionally parent to existing object. ifdict is expected as: | **type**: str | **direction**: str | **model**: str | **name**: str | **parent**: bpy.types.Object (optional) | **scale**: float (optional) Args: ifdict(dict): interface data parent(bpy.types.Object, optional): designated parent object (Default value = None) Returns: bpy.data.Object: newly created interface object """ if not parent: try: parent = ifdict['parent'] assert isinstance(parent, bpy.types.Object) except (AttributeError, AssertionError, KeyError): parent = None location = parent.matrix_world.translation if parent else mathutils.Vector() rotation = parent.matrix_world.to_euler() if parent else mathutils.Euler() model = ifdict['model'] if 'model' in ifdict else 'default' templateobj = ioUtils.getResource(('interface', model, ifdict['direction'])) scale = ifdict['scale'] if 'scale' in ifdict else 1.0 ifobj = bUtils.createPrimitive( ifdict['name'], 'box', (1.0, 1.0, 1.0), defs.layerTypes['interface'], plocation=location, protation=rotation, phobostype='interface', ) nUtils.safelyName(ifobj, ifdict['name'], 'interface') ifobj.data = templateobj.data ifobj.scale = (scale,) * 3 ifobj['interface/type'] = ifdict['type'] ifobj['interface/direction'] = ifdict['direction'] bpy.ops.object.make_single_user(object=True, obdata=True)
def createLink(link): """Creates the blender representation of a given link and its parent joint. The link is added to the link layer. These entries in the dictionary are mandatory: *name*: name for the link The specified dictionary may contain these entries: *matrix*: world matrix for the new link transformation *scale*: scale for the new link (single float) *visual*: list of visual dictionaries *collision*: list of collision dictionaries *inertial*: inertial dictionary (an inertial object will be created on the fly) Furthermore any generic properties, prepended by a `$` will be added as custom properties to the link. E.g. $test/etc would be put to link/test/etc. However, these properties are extracted only in the first layer of hierarchy. Args: link(dict): The link you want to create a representation of. Returns: : bpy_types.Object -- the newly created blender link object. """ log("Creating link object '{}'...".format(link['name']), 'DEBUG', prefix='\n') # create armature/bone bUtils.toggleLayer('link', True) bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.armature_add() newlink = bpy.context.active_object # Move bone when adding at selected objects location if 'matrix' in link: newlink.matrix_world = link['matrix'] # give it a proper name newlink.phobostype = 'link' if link['name'] in bpy.data.objects.keys(): log('Object with name of new link already exists: ' + link['name'], 'WARNING') nUtils.safelyName(newlink, link['name']) # set the size of the link visuals, collisions = getGeometricElements(link) if visuals or collisions: scale = max((geometrymodel.getLargestDimension(e['geometry']) for e in visuals + collisions)) else: scale = 0.2 # use scaling factor provided by user if 'scale' in link: scale *= link['scale'] newlink.scale = (scale, scale, scale) bpy.ops.object.transform_apply(location=False, rotation=False, scale=True, properties=False) # add custom properties for prop in link: if prop.startswith('$'): for tag in link[prop]: newlink['link/' + prop[1:] + '/' + tag] = link[prop][tag] # create inertial if 'inertial' in link: inertia.createInertial(link['inertial'], newlink) # create geometric elements log( "Creating visual and collision objects for link '{0}':\n{1}".format( link['name'], ' \n'.join([elem['name'] for elem in visuals + collisions])), 'DEBUG', ) for vis in visuals: geometrymodel.createGeometry(vis, 'visual', newlink) for col in collisions: geometrymodel.createGeometry(col, 'collision', newlink) bUtils.sortObjectToCollection(newlink, 'link') return newlink
def createGeometry(viscol, geomsrc, linkobj=None): """Creates Blender object for visual or collision objects. Returns reference to new object or None if creation failed. Args: viscol(dict): visual/collision dictionary element geomsrc(str): new object's phobostype linkobj(bpy.types.Object): link object Returns: bpy.types.Object or None """ if 'geometry' not in viscol or viscol['geometry'] is {}: return None bpy.ops.object.select_all(action='DESELECT') geom = viscol['geometry'] # create the Blender object if geom['type'] == 'mesh': bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes[geomsrc]) meshname = "".join(os.path.basename(geom["filename"]).split(".")[:-1]) if not os.path.isfile(geom['filename']): log(geom['filename'] + " is no file. Object " + viscol['name'] + " will have empty mesh!", "ERROR") #bpy.data.meshes.new(meshname) bpy.ops.object.add(type='MESH') newgeom = bpy.context.active_object nUtils.safelyName(newgeom, viscol['name'], phobostype=geomsrc) else: if meshname in bpy.data.meshes: log('Assigning copy of existing mesh ' + meshname + ' to ' + viscol['name'], 'INFO') bpy.ops.object.add(type='MESH') newgeom = bpy.context.object newgeom.data = bpy.data.meshes[meshname] else: log("Importing mesh for {0} element: '{1}".format(geomsrc, viscol['name']), 'INFO') filetype = geom['filename'].split('.')[-1].lower() newgeom = meshes.importMesh(geom['filename'], filetype) newgeom.data.name = meshname if not newgeom: log('Failed to import mesh file ' + geom['filename'], 'ERROR') return # scale imported object if 'scale' in geom: newgeom.scale = geom['scale'] else: if geom['type'] == 'box': dimensions = geom['size'] elif geom['type'] == 'cylinder': dimensions = (geom['radius'], geom['length']) elif geom['type'] == 'sphere': dimensions = geom['radius'] else: log("Unknown geometry type of " + geomsrc + viscol['name'] + '. Placing empty coordinate system.', "ERROR") bpy.ops.object.empty_add(type='PLAIN_AXES', radius=0.2) obj = bpy.context.object obj.phobostype = geomsrc nUtils.safelyName(bpy.context.active_object, viscol['name'], phobostype=geomsrc) return None log('Creating primtive for {0}: {1}'.format(geomsrc, viscol['name']), 'INFO') newgeom = bUtils.createPrimitive(viscol['name'], geom['type'], dimensions, phobostype=geomsrc) newgeom.select = True bpy.ops.object.transform_apply(scale=True) # from here it's the same for both meshes and primitives newgeom['geometry/type'] = geom['type'] if geomsrc == 'visual': try: assignMaterial(newgeom, viscol['material']) except KeyError: log('No material for visual ' + viscol['name'], 'DEBUG') for prop in viscol: if prop.startswith('$'): for tag in viscol[prop]: newgeom[prop[1:]+'/'+tag] = viscol[prop][tag] nUtils.safelyName(newgeom, viscol['name']) newgeom[geomsrc+"/name"] = viscol['name'] newgeom.phobostype = geomsrc # place geometric object relative to its parent link if linkobj: if 'pose' in viscol: log('Setting transformation of element: ' + viscol['name'], 'DEBUG') location = mathutils.Matrix.Translation(viscol['pose']['translation']) rotation = mathutils.Euler(tuple(viscol['pose']['rotation_euler']), 'XYZ').to_matrix().to_4x4() else: log('No pose in element: ' + viscol['name'], 'DEBUG') location = mathutils.Matrix.Identity(4) rotation = mathutils.Matrix.Identity(4) sUtils.selectObjects([newgeom, linkobj], True, 1) bpy.ops.object.parent_set(type='BONE_RELATIVE') newgeom.matrix_local = location * rotation if 'scale' in viscol['geometry']: newgeom.scale = mathutils.Vector(viscol['geometry']['scale']) return newgeom
def createGeometry(viscol, geomsrc, linkobj=None): """Creates Blender object for visual or collision objects. If the creation fails, nothing is returned. These entries in the dictionary are mandatory: | **geometry**: | **type**: type of geometry (mesh, box, cylinder, sphere) Depending on the geometry type other values are required: `size`, `radius`, `length` These entries are optional: | **geometry**: | **scale**: scale for the new geometry | **material**: material name to assign to the visual | **pose**: specifies the placement of the new object relative to the optional linkobj | **translation**: position vector for the new object | **rotation_euler**: rotation for the new object Furthermore any generic properties, prepended by a ``$`` will be added as custom properties to the visual/collision object. E.g. ``$test/etc`` would be put to visual/test/etc for a visual object. However, these properties are extracted only in the first layer of hierarchy. Args: viscol(dict): visual/collision model dictionary representation geomsrc(str): phobostype of the new object linkobj(bpy.types.Object, optional): link object to attach the visual/collision object to (Default value = None) Returns: bpy.types.Object or None: the new geometry object or nothing """ if 'geometry' not in viscol or viscol['geometry'] is {}: log("Could not create {}. Geometry information not defined!".format(geomsrc), 'ERROR') return None bpy.ops.object.select_all(action='DESELECT') geom = viscol['geometry'] # create the Blender object if geom['type'] == 'mesh': bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes[geomsrc]) meshname = "".join(os.path.basename(geom["filename"]).split(".")[:-1]) if not os.path.isfile(geom['filename']): log( "This path " + geom['filename'] + " is no file. Object " + viscol['name'] + " will have empty mesh!", 'ERROR', ) bpy.ops.object.add(type='MESH') newgeom = bpy.context.active_object nUtils.safelyName(newgeom, viscol['name'], phobostype=geomsrc) else: if meshname in bpy.data.meshes: log('Assigning copy of existing mesh ' + meshname + ' to ' + viscol['name'], 'INFO') bpy.ops.object.add(type='MESH') newgeom = bpy.context.object newgeom.data = bpy.data.meshes[meshname] else: log("Importing mesh for {0} element: '{1}".format(geomsrc, viscol['name']), 'INFO') filetype = geom['filename'].split('.')[-1].lower() newgeom = meshes.importMesh(geom['filename'], filetype) # bpy.data.meshes[newgeom].name = meshname if not newgeom: log('Failed to import mesh file ' + geom['filename'], 'ERROR') return else: if geom['type'] == 'box': dimensions = geom['size'] elif geom['type'] == 'cylinder': dimensions = (geom['radius'], geom['length']) elif geom['type'] == 'sphere': dimensions = geom['radius'] # TODO add support for heightmap, image, plane and polyline geometries (see sdf!) else: log( "Unknown geometry type of " + geomsrc + viscol['name'] + '. Placing empty coordinate system.', "ERROR", ) bpy.ops.object.empty_add(type='PLAIN_AXES', radius=0.2) obj = bpy.context.object obj.phobostype = geomsrc nUtils.safelyName(bpy.context.active_object, viscol['name'], phobostype=geomsrc) return None log("Creating primtive for {0}: {1}".format(geomsrc, viscol['name']), 'INFO') newgeom = bUtils.createPrimitive( viscol['name'], geom['type'], dimensions, phobostype=geomsrc ) newgeom.select = True bpy.ops.object.transform_apply(scale=True) # from here it's the same for both meshes and primitives newgeom['geometry/type'] = geom['type'] if geomsrc == 'visual': if 'material' in viscol: assignMaterial(newgeom, viscol['material']) else: log('No material for visual {}.'.format(viscol['name']), 'WARNING') # write generic custom properties for prop in viscol: if prop.startswith('$'): for tag in viscol[prop]: newgeom[prop[1:] + '/' + tag] = viscol[prop][tag] nUtils.safelyName(newgeom, viscol['name']) newgeom[geomsrc + '/name'] = viscol['name'] newgeom.phobostype = geomsrc # place geometric object relative to its parent link if linkobj: if 'pose' in viscol: log("Setting transformation of element: " + viscol['name'], 'DEBUG') location = mathutils.Matrix.Translation(viscol['pose']['translation']) rotation = ( mathutils.Euler(tuple(viscol['pose']['rotation_euler']), 'XYZ').to_matrix().to_4x4() ) else: log("No pose in element: " + viscol['name'], 'DEBUG') location = mathutils.Matrix.Identity(4) rotation = mathutils.Matrix.Identity(4) eUtils.parentObjectsTo(newgeom, linkobj) newgeom.matrix_local = location * rotation # scale imported object if 'scale' in geom: newgeom.scale = geom['scale'] # make object smooth eUtils.smoothen_surface(newgeom) return newgeom
def createLink(link): """Creates the blender representation of a given link and its parent joint. The link is added to the link layer. These entries in the dictionary are mandatory: *name*: name for the link The specified dictionary may contain these entries: *matrix*: world matrix for the new link transformation *scale*: scale for the new link (single float) *visual*: list of visual dictionaries *collision*: list of collision dictionaries *inertial*: inertial dictionary (an inertial object will be created on the fly) Furthermore any generic properties, prepended by a `$` will be added as custom properties to the link. E.g. $test/etc would be put to link/test/etc. However, these properties are extracted only in the first layer of hierarchy. Args: link(dict): The link you want to create a representation of. Returns: : bpy_types.Object -- the newly created blender link object. """ log("Creating link object '{}'...".format(link['name']), 'DEBUG', prefix='\n') # create armature/bone bUtils.toggleLayer(defs.layerTypes['link'], True) bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.armature_add(layers=bUtils.defLayers([defs.layerTypes['link']])) newlink = bpy.context.active_object # Move bone when adding at selected objects location if 'matrix' in link: newlink.matrix_world = link['matrix'] # give it a proper name newlink.phobostype = 'link' if link['name'] in bpy.data.objects.keys(): log('Object with name of new link already exists: ' + link['name'], 'WARNING') nUtils.safelyName(newlink, link['name']) # set the size of the link visuals, collisions = getGeometricElements(link) if visuals or collisions: scale = max( (geometrymodel.getLargestDimension(e['geometry']) for e in visuals + collisions) ) else: scale = 0.2 # use scaling factor provided by user if 'scale' in link: scale *= link['scale'] newlink.scale = (scale, scale, scale) bpy.ops.object.transform_apply(scale=True) # add custom properties for prop in link: if prop.startswith('$'): for tag in link[prop]: newlink['link/' + prop[1:] + '/' + tag] = link[prop][tag] # create inertial if 'inertial' in link: inertia.createInertial(link['inertial'], newlink) # create geometric elements log( "Creating visual and collision objects for link '{0}':\n{1}".format( link['name'], ' \n'.join([elem['name'] for elem in visuals + collisions]) ), 'DEBUG', ) for vis in visuals: geometrymodel.createGeometry(vis, 'visual', newlink) for col in collisions: geometrymodel.createGeometry(col, 'collision', newlink) return newlink