def execute(self, context): startLog(self) global sensors global motors location = bpy.context.scene.cursor_location objects = [] controllers = [] for obj in bpy.context.selected_objects: if obj.phobostype == "controller": controllers.append(obj) else: objects.append(obj) if len(controllers) <= 0: blenderUtils.createPrimitive(self.controller_name, "sphere", self.controller_scale, defs.layerTypes["sensor"], "phobos_controller", location) bpy.context.scene.objects.active.phobostype = "controller" bpy.context.scene.objects.active.name = self.controller_name controllers.append(bpy.context.scene.objects.active) #empty index list so enable robotupdate of controller for ctrl in controllers: ctrl['controller/sensors'] = sorted(sensors, key=str.lower) ctrl['controller/motors'] = sorted(motors, key=str.lower) ctrl['controller/rate'] = self.controller_rate print("Added joints/motors to (new) controller(s).") #for prop in defs.controllerProperties[self.controller_type]: # for ctrl in controllers: # ctrl[prop] = defs.controllerProperties[prop] endLog() return {'FINISHED'}
def execute(self, context): location = bpy.context.scene.cursor_location objects = [] controllers = [] for obj in bpy.context.selected_objects: if obj.phobostype == "controller": controllers.append(obj) else: objects.append(obj) if len(controllers) <= 0: bUtils.createPrimitive("controller", "sphere", self.controller_scale, defs.layerTypes["sensor"], "controller", location) bpy.context.scene.objects.active.phobostype = "controller" bpy.context.scene.objects.active.name = "controller" controllers.append(bpy.context.scene.objects.active) #empty index list so enable robotupdate of controller for ctrl in controllers: for key in ctrl.keys(): if key.find("index") >= 0: del ctrl[key] log("Deleting " + str(key) + " in " + ctrl.name, "INFO") i = 1 for obj in objects: if obj.phobostype == "link": ctrl["index" + (str(i) if i >= 10 else "0" + str(i))] = nUtils.getObjectName(obj) i += 1 log("Added joints to (new) controller(s).", "INFO") #for prop in defs.controllerProperties[self.controller_type]: # for ctrl in controllers: # ctrl[prop] = defs.controllerProperties[prop] return {'FINISHED'}
def execute(self, context): startLog(self) location = bpy.context.scene.cursor_location objects = [] controllers = [] for obj in bpy.context.selected_objects: if obj.phobostype == "controller": controllers.append(obj) else: objects.append(obj) if len(controllers) <= 0: blenderUtils.createPrimitive("controller", "sphere", self.controller_scale, defs.layerTypes["sensor"], "controller", location) bpy.context.scene.objects.active.phobostype = "controller" bpy.context.scene.objects.active.name = "controller" controllers.append(bpy.context.scene.objects.active) #empty index list so enable robotupdate of controller for ctrl in controllers: for key in ctrl.keys(): if key.find("index") >= 0: del ctrl[key] log("Deleting " + str(key) + " in " + ctrl.name, "INFO") i = 1 for obj in objects: if obj.phobostype == "link": ctrl["index"+(str(i) if i >= 10 else "0"+str(i))] = namingUtils.getObjectName(obj) i += 1 log("Added joints to (new) controller(s).", "INFO") #for prop in defs.controllerProperties[self.controller_type]: # for ctrl in controllers: # ctrl[prop] = defs.controllerProperties[prop] endLog() return {'FINISHED'}
def createSensor(sensor, reference, origin=mathutils.Matrix()): blenderUtils.toggleLayer(defs.layerTypes['sensor'], value=True) # create sensor object if 'Camera' in sensor['type']: bpy.context.scene.layers[defs.layerTypes['sensor']] = True bpy.ops.object.add(type='CAMERA', location=origin.to_translation(), rotation=origin.to_euler(), layers=blenderUtils.defLayers([defs.layerTypes['sensor']])) newsensor = bpy.context.active_object if reference is not None: selectionUtils.selectObjects([newsensor, bpy.data.objects[reference]], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') elif sensor['type'] in ['RaySensor', 'RotatingRaySensor', 'ScanningSonar', 'MultiLevelLaserRangeFinder']: # TODO: create a proper ray sensor scanning layer disc here newsensor = blenderUtils.createPrimitive(sensor['name'], 'disc', (0.5, 36), defs.layerTypes['sensor'], 'phobos_laserscanner', origin.to_translation(), protation=origin.to_euler()) if reference is not None and reference != []: if type(reference) == str: key = reference else: key = reference[0] selectionUtils.selectObjects([newsensor, bpy.data.objects[key]], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') else: # contact, force and torque sensors (or unknown sensors) newsensor = blenderUtils.createPrimitive(sensor['name'], 'sphere', 0.05, defs.layerTypes['sensor'], 'phobos_sensor', origin.to_translation(), protation=origin.to_euler()) if 'Node' in sensor['type']: newsensor['sensor/nodes'] = sorted(reference) elif 'Joint' in sensor['type'] or 'Motor' in sensor['type']: newsensor['sensor/joints'] = sorted(reference) if reference is not None and reference != []: selectionUtils.selectObjects([newsensor, selectionUtils.getRoot(bpy.data.objects[0])], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') # set sensor properties newsensor.phobostype = 'sensor' newsensor.name = sensor['name'] newsensor['sensor/type'] = sensor['type'] for prop in sensor['props']: newsensor['sensor/'+prop] = sensor['props'][prop] # add custom properties #for prop in sensor: # if prop.startswith('$'): # for tag in sensor[prop]: # newsensor[prop[1:]+'/'+tag] = sensor[prop][tag] # throw warning if type is not known if sensor['type'] not in defs.sensortypes: print("### Warning: sensor", sensor['name'], "is of unknown/custom type.") selectionUtils.selectObjects([newsensor], clear=False, active=0) return newsensor
def createInertial(obj): """Creates an empty inertial object with the same world transform as the corresponding object and parents it to the correct link. :param obj: The object you want to copy the world transform from. :type obj: bpy_types.Object :return: bpy_types.Object -- the newly created inertia. """ if obj.phobostype == 'link': parent = obj size = (0.04, 0.04, 0.04) else: parent = obj.parent size = (0.02, 0.02, 0.02) rotation = obj.matrix_world.to_euler() center = obj.matrix_world.to_translation() inertial = blenderUtils.createPrimitive( 'inertial_' + namingUtils.getObjectName(obj, phobostype="link"), 'box', size, defs.layerTypes["inertial"], 'phobos_inertial', center, rotation) bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) inertial.phobostype = 'inertial' bpy.ops.object.select_all(action="DESELECT") #utility.selectObjects([inertial], True, 0) selectionUtils.selectObjects([parent, inertial], True, 0) #bpy.context.scene.objects.active = parent.pose.bones[0] bpy.ops.object.parent_set(type='BONE_RELATIVE') return inertial
def exportMesh(obj, path, meshtype): # DOCU add some docstring objname = nUtils.getObjectName(obj) tmpobjname = obj.name # OPT: surely no one will ever name an object like so, better solution? obj.name = 'tmp_export_666' tmpobject = bUtils.createPrimitive(objname, 'box', (1.0, 1.0, 1.0)) # copy the mesh here tmpobject.data = obj.data outpath = os.path.join(path, obj.data.name + "." + meshtype) if meshtype == 'obj': axis_forward = ioUtils.getExpSettings().obj_axis_forward axis_up = ioUtils.getExpSettings().obj_axis_up bpy.ops.export_scene.obj(filepath=outpath, use_selection=True, use_normals=True, use_materials=False, use_mesh_modifiers=True, axis_forward=axis_forward, axis_up=axis_up) elif meshtype == 'stl': bpy.ops.export_mesh.stl(filepath=outpath, use_selection=True, use_mesh_modifiers=True) elif meshtype == 'dae': bpy.ops.wm.collada_export(filepath=outpath, selected=True) bpy.ops.object.select_all(action='DESELECT') tmpobject.select = True bpy.ops.object.delete() obj.name = tmpobjname
def createInertial(obj): """Creates an empty inertial object with the same world transform as the corresponding object and parents it to the correct link. :param obj: The object you want to copy the world transform from. :type obj: blender object. :return: blender object -- the newly created inertia. """ if obj.phobostype == 'link': parent = obj size = (0.04, 0.04, 0.04) else: parent = obj.parent size = (0.02, 0.02, 0.02) rotation = obj.matrix_world.to_euler() center = obj.matrix_world.to_translation() inertial = blenderUtils.createPrimitive('inertial_' + obj.name, 'box', size, defs.layerTypes["inertial"], 'phobos_inertial', center, rotation) bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) inertial.phobostype = 'inertial' bpy.ops.object.select_all(action="DESELECT") #utility.selectObjects([inertial], True, 0) selectionUtils.selectObjects([parent, inertial], True, 0) #bpy.context.scene.objects.active = parent.pose.bones[0] bpy.ops.object.parent_set(type='BONE_RELATIVE') return inertial
def exportMesh(obj, path, meshtype): objname = nUtils.getObjectName(obj) tmpobjname = obj.name obj.name = 'tmp_export_666' # surely no one will ever name an object like so tmpobject = bUtils.createPrimitive(objname, 'box', (1.0, 1.0, 1.0)) tmpobject.data = obj.data # copy the mesh here outpath = os.path.join(path, obj.data.name + "." + meshtype) if meshtype == 'obj': bpy.ops.export_scene.obj(filepath=outpath, use_selection=True, use_normals=True, use_materials=False, use_mesh_modifiers=True) elif meshtype == 'stl': if bpy.app.version[0] * 100 + bpy.app.version[1] >= 277: bpy.ops.export_mesh.stl(filepath=outpath, use_selection=True, use_mesh_modifiers=True) else: bpy.ops.export_mesh.stl(filepath=outpath, use_mesh_modifiers=True) elif meshtype == 'dae': bpy.ops.wm.collada_export(filepath=outpath, selected=True) bpy.ops.object.select_all(action='DESELECT') tmpobject.select = True bpy.ops.object.delete() obj.name = tmpobjname
def createInertialFromDictionary(name, inertial): """Creates the Blender representation of a given intertial provided a dictionary. :param name: The intertials name. :param type: str :param inertial: The intertial you want to create in blender form. :type intertial: dict :return: bpy_types.Object -- the newly created blender inertial object. """ # FIXME: this needs work to get rid of duplicate code bpy.ops.object.select_all(action='DESELECT') inert = bUtils.createPrimitive('inertial_' + name, 'box', [0.06, 0.06, 0.06], player='inertial') inert.select = True bpy.ops.object.transform_apply(scale=True) for prop in inertial: if prop not in ['pose'] and inertial[prop] is not None: if not prop.startswith('$'): inert[prop] = inertial[prop] else: for tag in inertial[prop]: inert[prop[1:] + '/' + tag] = inertial[prop][tag] inert.phobostype = 'inertial' assignMaterial(inert, 'phobos_inertial') return inert
def createInertial(obj): """Creates an empty inertial object with the same world transform as the corresponding object and parents it to the correct link. :param obj: The object you want to copy the world transform from. :type obj: bpy_types.Object :return: bpy_types.Object -- the newly created inertia. """ if obj.phobostype == 'link': parent = obj size = (0.06, 0.06, 0.06) else: parent = obj.parent size = (0.015, 0.015, 0.015) rotation = obj.matrix_world.to_euler() center = obj.matrix_world.to_translation() inertial = bUtils.createPrimitive( 'inertial_' + nUtils.getObjectName(obj, phobostype="link"), 'box', size, defs.layerTypes["inertial"], 'phobos_inertial', center, rotation) bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) inertial.phobostype = 'inertial' bpy.ops.object.select_all(action="DESELECT") sUtils.selectObjects((inertial, parent), clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') return inertial
def addAnnotationObject(obj, annotation, name=None, size=0.1, namespace=None): """Add a new annotation object with the specified annotations to the object. The annotation object will receive 'annotation_object' as its default name, unless a name is provided. Naming is done using :func:`phobos.utils.naming.safelyName`. The annotation object will be scaled according to the **size** parameter. If ``namespace`` is provided, the annotations will be saved with this string prepended. This is done using :func:`addAnnotation`. Args: obj(bpy.types.Object): object to add annotation object to annotation(dict): annotations that will be added name(str, optional): name for the new annotation object (Default value = None) size(int/float, optional): size of the new annotation object (Default value = 0.1) namespace(str, optional): namespace that will be prepended to the annotations (Default value = None) Returns: : bpy.types.Object - the new annotation object """ loc = obj.matrix_world.to_translation() if not name: name = obj.name + '_annotation_object' annot_obj = bUtils.createPrimitive( name, 'box', [1, 1, 1], defs.layerTypes['annotation'], plocation=loc, phobostype='annotation', ) annot_obj.scale = (size, ) * 3 resource = ioUtils.getResource(['annotation', namespace.split('/')[-1]]) if resource: annot_obj.data = resource.data else: annot_obj.data = ioUtils.getResource(['annotation', 'default']).data # make sure all layers are enabled for parenting originallayers = {} for name, coll in bpy.context.window.view_layer.layer_collection.children.items( ): originallayers[name] = coll.exclude coll.exclude = False # parent annotation object parentObjectsTo(annot_obj, obj) # Restore original layers for key, value in originallayers.items(): bpy.context.window.view_layer.layer_collection.children[ key].exclude = value addAnnotation(annot_obj, annotation, namespace=namespace) return annot_obj
def createInertial(inertialdict, obj, size=0.03, errors=None, adjust=False, logging=False): """Creates the Blender representation of a given inertial provided a dictionary. Args: inertialdict(dict): intertial data obj: size: (Default value = 0.03) errors: (Default value = None) adjust: (Default value = False) logging: (Default value = False) Returns: : bpy_types.Object -- newly created blender inertial object """ if errors and not adjust: log('Can not create inertial object.', 'ERROR') try: origin = mathutils.Vector(inertialdict['pose']['translation']) except KeyError: origin = mathutils.Vector() # create new inertial object name = nUtils.getUniqueName('inertial_' + nUtils.getObjectName(obj), bpy.data.objects) inertialobject = bUtils.createPrimitive( name, 'box', (size, ) * 3, defs.layerTypes["inertial"], pmaterial='phobos_inertial', phobostype='inertial', ) sUtils.selectObjects((inertialobject, ), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) # set position according to the parent link inertialobject.matrix_world = obj.matrix_world parent = obj if parent.phobostype != 'link': parent = sUtils.getEffectiveParent(obj, ignore_selection=True) eUtils.parentObjectsTo(inertialobject, parent) # position and parent the inertial object relative to the link # inertialobject.matrix_local = mathutils.Matrix.Translation(origin) sUtils.selectObjects((inertialobject, ), clear=True, active=0) # bpy.ops.object.transform_apply(scale=True) # add properties to the object for prop in ('mass', 'inertia'): inertialobject['inertial/' + prop] = inertialdict[prop] return inertialobject
def createInertial(parentname, inertialdict, parentobj=None, effectiveParent=None): """Creates the Blender representation of a given inertial provided a dictionary. :param parentname: inertial object's parent's name :type parentname: str :param inertialdict: intertial data :type inertialdict: dict :param parentobj: link or visual/collision with which the inertial obj is associated :type parentobj: bpy.types.Object :param helper: whether or not the object is a helper inertial :type helper: bool :return: the newly created blender inertial object. :rtype: bpy_types.Object """ size = 0.03 try: origin = mathutils.Vector(inertialdict['pose']['translation']) except KeyError: origin = mathutils.Vector() # Check the inertia data for consistency if checkInertiaData(inertialdict): material = 'phobos_inertial' elif not checkInertiaData(inertialdict): log( 'Inconsistent inertia data found for object {}!'.format( parentname), "WARNING") material = 'phobos_error' inertialobject = bUtils.createPrimitive('inertial_' + parentname, 'box', (size, ) * 3, defs.layerTypes["inertial"], pmaterial=material, phobostype='inertial') sUtils.selectObjects((inertialobject, ), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) if parentobj: inertialobject.matrix_world = parentobj.matrix_world parent = parentobj if parentobj.phobostype == 'link' else parentobj.parent sUtils.selectObjects((inertialobject, parent), clear=True, active=1) # Create the inertial object relative to the link / joint bpy.ops.object.parent_set(type='BONE_RELATIVE') inertialobject.matrix_local = mathutils.Matrix.Translation(origin) sUtils.selectObjects((inertialobject, ), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) # force matrix_world update # set properties for prop in ('mass', 'inertia'): inertialobject[prop] = inertialdict[prop] return inertialobject
def addAnnotationObject(obj, annotation, name=None, size=0.1, namespace=None): """Add a new annotation object with the specified annotations to the object. The annotation object will receive 'annotation_object' as its default name, unless a name is provided. Naming is done using :func:`phobos.utils.naming.safelyName`. The annotation object will be scaled according to the **size** parameter. If ``namespace`` is provided, the annotations will be saved with this string prepended. This is done using :func:`addAnnotation`. Args: obj(bpy.types.Object): object to add annotation object to annotation(dict): annotations that will be added name(str, optional): name for the new annotation object (Default value = None) size(int/float, optional): size of the new annotation object (Default value = 0.1) namespace(str, optional): namespace that will be prepended to the annotations (Default value = None) Returns: : bpy.types.Object - the new annotation object """ loc = obj.matrix_world.to_translation() if not name: name = obj.name + '_annotation_object' annot_obj = bUtils.createPrimitive( name, 'box', [1, 1, 1], defs.layerTypes['annotation'], plocation=loc, phobostype='annotation', ) annot_obj.scale = (size,) * 3 resource = ioUtils.getResource(['annotation', namespace.split('/')[-1]]) if resource: annot_obj.data = resource.data else: annot_obj.data = ioUtils.getResource(['annotation', 'default']).data # make sure all layers are enabled for parenting originallayers = list(bpy.context.scene.layers) bpy.context.scene.layers = [True for i in range(20)] # parent annotation object parentObjectsTo(annot_obj, obj) bpy.context.scene.layers = originallayers addAnnotation(annot_obj, annotation, namespace=namespace) return annot_obj
def createInertial(inertialdict, obj, size=0.03, errors=None, adjust=False, logging=False): """Creates the Blender representation of a given inertial provided a dictionary. Args: inertialdict(dict): intertial data obj: size: (Default value = 0.03) errors: (Default value = None) adjust: (Default value = False) logging: (Default value = False) Returns: : bpy_types.Object -- newly created blender inertial object """ if errors and not adjust: log('Can not create inertial object.', 'ERROR') try: origin = mathutils.Vector(inertialdict['pose']['translation']) except KeyError: origin = mathutils.Vector() # create new inertial object name = nUtils.getUniqueName('inertial_' + nUtils.getObjectName(obj), bpy.data.objects) inertialobject = bUtils.createPrimitive( name, 'box', (size,) * 3, defs.layerTypes["inertial"], pmaterial='phobos_inertial', phobostype='inertial', ) sUtils.selectObjects((inertialobject,), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) # set position according to the parent link inertialobject.matrix_world = obj.matrix_world parent = obj if parent.phobostype != 'link': parent = sUtils.getEffectiveParent(obj, ignore_selection=True) eUtils.parentObjectsTo(inertialobject, parent) # position and parent the inertial object relative to the link # inertialobject.matrix_local = mathutils.Matrix.Translation(origin) sUtils.selectObjects((inertialobject,), clear=True, active=0) # bpy.ops.object.transform_apply(scale=True) # add properties to the object for prop in ('mass', 'inertia'): inertialobject['inertial/' + prop] = inertialdict[prop] return inertialobject
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 exportMesh(obj, path, meshtype): """ Args: obj: path: meshtype: Returns: """ import phobos.utils.io as ioUtils # DOCU add some docstring objname = nUtils.getObjectName(obj) tmpobjname = obj.name # OPT: surely no one will ever name an object like so, better solution? obj.name = 'tmp_export_666' tmpobject = bUtils.createPrimitive(objname, 'box', (1.0, 1.0, 1.0)) # copy the mesh here tmpobject.data = obj.data outpath = os.path.join(path, obj.data.name + "." + meshtype) if meshtype == 'obj': axis_forward = bpy.context.scene.phobosexportsettings.obj_axis_forward axis_up = bpy.context.scene.phobosexportsettings.obj_axis_up bpy.ops.export_scene.obj( filepath=outpath, use_selection=True, use_normals=True, use_materials=False, use_mesh_modifiers=True, axis_forward=axis_forward, axis_up=axis_up, ) elif meshtype == 'stl': bpy.ops.export_mesh.stl(filepath=outpath, use_selection=True, use_mesh_modifiers=True) elif meshtype == 'dae': bpy.ops.wm.collada_export(filepath=outpath, selected=True) bpy.ops.object.select_all(action='DESELECT') tmpobject.select = True bpy.ops.object.delete() obj.name = tmpobjname
def exportObj(path, obj): """This function exports a specific object to a chosen path as an .obj :param path: The path you want the object export to. *without the filename!* :type path: String :param obj: The blender object you want to export. :type obj: bpy.types.Object :return: Nothing. """ objname = namingUtils.getObjectName(obj) oldBlenderObjName = obj.name obj.name = 'tmp_export_666' # surely no one will ever name an object like so tmpobject = blenderUtils.createPrimitive(objname, 'box', (2.0, 2.0, 2.0)) tmpobject.data = obj.data # copy the mesh here outpath = determineMeshOutpath(obj, objname, 'obj', path) bpy.ops.export_scene.obj(filepath=outpath, use_selection=True, use_normals=True, use_materials=False) bpy.ops.object.select_all(action='DESELECT') tmpobject.select = True bpy.ops.object.delete() obj.name = oldBlenderObjName
def createInertial(parentname, inertialdict, parentobj=None, helper=False): """Creates the Blender representation of a given inertial provided a dictionary. :param parentname: inertial object's parent's name :type parentname: str :param inertialdict: intertial data :type inertialdict: dict :param parentobj: link or visual/collision with which the inertial obj is associated :type parentobj: bpy_types.Object :param helper: whether or not the object is a helper inertial :type helper: bool :return: bpy_types.Object -- the newly created blender inertial object. """ size = 0.015 if helper else 0.06 try: origin = mathutils.Vector(inertialdict['pose']['translation']) except KeyError: origin = mathutils.Vector() inertialobject = bUtils.createPrimitive('inertial_' + parentname, 'box', (size, ) * 3, defs.layerTypes["inertial"], 'phobos_inertial') sUtils.selectObjects((inertialobject, ), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) inertialobject.phobostype = 'inertial' if parentobj: inertialobject.matrix_world = parentobj.matrix_world parent = parentobj if parentobj.phobostype == 'link' else parentobj.parent sUtils.selectObjects((inertialobject, parent), clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') inertialobject.matrix_local = mathutils.Matrix.Translation(origin) sUtils.selectObjects((inertialobject, ), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) # force matrix_world update # set properties for prop in ('mass', 'inertia'): if helper: inertialobject[prop] = inertialdict[prop] else: inertialobject['inertial/' + prop] = inertialdict[prop] return inertialobject
def createInertial(inertialdict, obj=None): """Creates the Blender representation of a given inertial provided a dictionary. Args: inertialdict(dict): intertial data obj(bpy.types.Object): link or visual/collision reference object Returns: bpy_types.Object: newly created blender inertial object """ size = 0.03 try: origin = mathutils.Vector(inertialdict['pose']['translation']) except KeyError: origin = mathutils.Vector() if not isInertiaDataValid(inertialdict): return None name = nUtils.getUniqueName('inertial_' + nUtils.getObjectName(obj), bpy.data.objects) inertialobject = bUtils.createPrimitive(name, 'box', (size,) * 3, defs.layerTypes["inertial"], pmaterial='phobos_inertial', phobostype='inertial') sUtils.selectObjects((inertialobject,), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) if obj: inertialobject.matrix_world = obj.matrix_world parent = obj if obj.phobostype == 'link' else obj.parent sUtils.selectObjects((inertialobject, parent), clear=True, active=1) # Create the inertial object relative to the link / joint bpy.ops.object.parent_set(type='BONE_RELATIVE') inertialobject.matrix_local = mathutils.Matrix.Translation(origin) sUtils.selectObjects((inertialobject,), clear=True, active=0) bpy.ops.object.transform_apply(scale=True) # force matrix_world update # set properties for prop in ('mass', 'inertia'): inertialobject['inertia/' + prop] = inertialdict[prop] return inertialobject
def exportStl(path, obj): """This function exports a specific object to a chosen path as a .stl :param path: The path you want the object exported to. *without filename!* :type path: String :param obj: The blender object you want to export. :type obj: bpy.types.Object :return: Nothing. """ objname = namingUtils.getObjectName(obj) oldBlenderObjectName = obj.name print("OBJNAME: " + objname) obj.name = 'tmp_export_666' # surely no one will ever name an object like so tmpobject = blenderUtils.createPrimitive(objname, 'box', (1.0, 1.0, 1.0)) tmpobject.data = obj.data # copy the mesh here outpath = determineMeshOutpath(obj, objname, 'stl', path) bpy.ops.export_mesh.stl(filepath=outpath) bpy.ops.object.select_all(action='DESELECT') tmpobject.select = True bpy.ops.object.delete() obj.name = oldBlenderObjectName
def createGeometry(viscol, geomsrc): """Creates geometrical Blender object for visual or collision objects. :param viscol: The visual/collision dictionary element you want to create the geometry for. :type viscol: dict :param geomsrc: The new viscols phobostype. :type geomsrc: str """ if 'geometry' not in viscol or viscol['geometry'] is {}: return None bpy.ops.object.select_all(action='DESELECT') geom = viscol['geometry'] geomtype = geom['type'] # create the Blender object if geomtype == '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) 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 link element ' + 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: sUtils.selectObjects((newgeom,), clear=True) newgeom.scale = geom['scale'] else: if geomtype == 'box': dimensions = geom['size'] elif geomtype == 'cylinder': dimensions = (geom['radius'], geom['length']) elif geomtype == 'sphere': dimensions = geom['radius'] else: log("Could not determine geometry type of " + geomsrc + viscol['name'] + '. Placing empty coordinate system.', "ERROR") bpy.ops.object.empty_add(type='PLAIN_AXES', radius=0.2) bpy.context.active_object.name = viscol['name'] return None log('Creating primtive for obj ' + viscol['name'], 'INFO') newgeom = bUtils.createPrimitive(viscol['name'], geomtype, dimensions, player=geomsrc) newgeom.select = True bpy.ops.object.transform_apply(scale=True) # from here it's the same for both meshes and primitives newgeom.phobostype = geomsrc newgeom['geometry/type'] = geomtype if geomsrc == 'visual': try: if 'name' in viscol['material']: assignMaterial(newgeom, viscol['material']['name']) else: assignMaterial(newgeom, viscol['material']) except KeyError: log('No material for obj ' + viscol['name'], 'DEBUG') # FIXME: place empty coordinate system and return...what? Error handling of file import! for prop in viscol: if prop.startswith('$'): for tag in viscol[prop]: newgeom[prop[1:]+'/'+tag] = viscol[prop][tag] newgeom.name = viscol['name'] newgeom[geomsrc+"/name"] = viscol['name'] return newgeom
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): """Creates geometrical Blender object for visual or collision objects. :param viscol: The visual/collision dictionary element you want to create the geometry for. :type viscol: dict :param geomsrc: The new viscols phobostype. :type geomsrc: str """ if 'geometry' not in viscol or viscol['geometry'] is {}: return None newgeom = None bpy.ops.object.select_all(action='DESELECT') geom = viscol['geometry'] geomtype = geom['type'] # create the Blender object if geomtype == 'mesh': # if hasattr(self, 'zipped') and self.zipped: # if not os.path.isdir(os.path.join(self.tmp_path, tmp_dir_name)): # os.mkdir(os.path.join(self.tmp_path, tmp_dir_name)) # archive = zipfile.ZipFile(self.filepath) # archive.extract(geom['filename'], path=os.path.join(self.tmp_path, tmp_dir_name)) # geom_path = os.path.join(os.path.abspath(os.path.join(self.tmp_path, tmp_dir_name)), geom['filename']) # else: if 'sourcefilepath' in geom: geom_path = os.path.normpath( os.path.join(os.path.dirname(geom['sourcefilepath']), geom['filename'])) log('sourcefilepath: ' + geom_path, 'DEBUG', 'createGeometry') else: geom_path = geom['filename'] # Remove 'urdf/package://{package_name}' to workaround the lack # of rospack here. This supposes that the urdf file is in the # urdf folder and that the meshes are in the meshes folder at # the same level as the urdf folder. if 'package://' in geom_path: geom_path = re.sub(r'(.*)urdf/package://([^/]+)/(.*)', '\\1\\3', geom_path) bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes[geomsrc]) meshname = "".join(os.path.basename(geom["filename"]).split(".")[:-1]) if not os.path.isfile(geom_path): log( geom_path + " is no file. Object " + viscol['name'] + " will have empty mesh!", "ERROR", "createGeometry") bpy.data.meshes.new(meshname) if meshname in bpy.data.meshes: log( 'Assigning copy of existing mesh ' + meshname + ' to ' + viscol['name'], 'INFO', 'createGeometry') bpy.ops.object.add(type='MESH') newgeom = bpy.context.object newgeom.data = bpy.data.meshes[meshname] else: log('Importing mesh for link element ' + viscol['name'], 'INFO', 'createGeometry') filetype = geom['filename'].split('.')[-1].lower() newgeom = meshes.importMesh(geom_path, filetype) newgeom.data.name = meshname if not newgeom: log('Failed to import mesh file ' + geom['filename'], 'ERROR', 'createGeometry') return # scale imported object if 'scale' in geom: sUtils.selectObjects((newgeom, ), clear=True) newgeom.scale = geom['scale'] else: if geomtype == 'box': dimensions = geom['size'] elif geomtype == 'cylinder': dimensions = (geom['radius'], geom['length']) elif geomtype == 'sphere': dimensions = geom['radius'] else: log( "Could not determine geometry type of " + geomsrc + viscol['name'] + '. Placing empty coordinate system.', "ERROR") bpy.ops.object.empty_add(type='PLAIN_AXES', radius=0.2) bpy.context.active_object.name = viscol['name'] return None log('Creating primitve for obj ' + viscol['name'], 'INFO', 'createGeometry') newgeom = bUtils.createPrimitive(viscol['name'], geomtype, dimensions, player=geomsrc) newgeom.select = True bpy.ops.object.transform_apply(scale=True) # from here it's the same for both meshes and primitives newgeom.phobostype = geomsrc newgeom['geometry/type'] = geomtype if geomsrc == 'visual': try: if 'name' in viscol['material']: assignMaterial(newgeom, viscol['material']['name']) else: assignMaterial(newgeom, viscol['material']) except KeyError: log('No material for obj', viscol['name'], 'DEBUG', 'createGeometry') #FIXME: place empty coordinate system and return...what? Error handling of file import! for prop in viscol: if prop.startswith('$'): for tag in viscol[prop]: newgeom[prop[1:] + '/' + tag] = viscol[prop][tag] newgeom.name = viscol['name'] newgeom[geomsrc + "/name"] = viscol['name'] return newgeom
def createSensor(sensor, reference, origin=mathutils.Matrix()): """This function creates a new sensor specified by its parameters. :param sensor: The phobos representation of the new sensor. :type sensor: dict :param reference: This is an object to add a parent relationship to. :type reference: bpy_types.Object :param origin: The new sensors origin. :type origin: mathutils.Matrix :return: The newly created sensor object """ blenderUtils.toggleLayer(defs.layerTypes['sensor'], value=True) # create sensor object if 'Camera' in sensor['type']: bpy.ops.object.add(type='CAMERA', location=origin.to_translation(), rotation=origin.to_euler(), layers=blenderUtils.defLayers([defs.layerTypes['sensor']])) newsensor = bpy.context.active_object if reference is not None: selectionUtils.selectObjects([newsensor, reference], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') elif sensor['type'] in ['RaySensor', 'RotatingRaySensor', 'ScanningSonar', 'MultiLevelLaserRangeFinder']: # TODO: create a proper ray sensor scanning layer disc here newsensor = blenderUtils.createPrimitive(sensor['name'], 'disc', (0.5, 36), defs.layerTypes['sensor'], 'phobos_laserscanner', origin.to_translation(), protation=origin.to_euler()) if reference is not None: selectionUtils.selectObjects([newsensor, reference], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') else: # contact, force and torque sensors (or unknown sensors) newsensor = blenderUtils.createPrimitive(sensor['name'], 'sphere', 0.05, defs.layerTypes['sensor'], 'phobos_sensor', origin.to_translation(), protation=origin.to_euler()) if sensor['type'] == 'Joint6DOF': pass #newsensor['sensor/nodes'] = nameUtils.getObjectName(reference) elif 'Node' in sensor['type']: newsensor['sensor/nodes'] = sorted([nameUtils.getObjectName(ref) for ref in reference]) elif 'Joint' in sensor['type'] or 'Motor' in sensor['type']: newsensor['sensor/joints'] = sorted([nameUtils.getObjectName(ref) for ref in reference]) if reference is not None: selectionUtils.selectObjects([newsensor, reference], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') # set sensor properties newsensor.phobostype = 'sensor' newsensor.name = sensor['name'] newsensor['sensor/type'] = sensor['type'] #for prop in ['link', 'joint', 'links', 'joints', 'motors']: # if prop in sensor: # newsensor['sensor/'+prop] = sensor[prop] # add custom properties #for prop in sensor: # if prop.startswith('$'): # for tag in sensor[prop]: # newsensor[prop[1:]+'/'+tag] = sensor[prop][tag] # throw warning if type is not known if sensor['type'] not in defs.sensortypes: print("### Warning: sensor", sensor['name'], "is of unknown/custom type.") selectionUtils.selectObjects([newsensor], clear=False, active=0) return newsensor
def createSensor(sensor, reference, origin=mathutils.Matrix()): """This function creates a new sensor specified by its parameters. The sensor dictionary has to contain these keys: *name*: name of the new sensor *type*: type specifier of the sensor *shape*: a shape specifier for the sensor *props*: custom properties to be written to the sensor object Args: sensor(dict): phobos representation of the new sensor reference(bpy_types.Object): object to add a parent relationship to origin(mathutils.Matrix, optional): new sensors origin (Default value = mathutils.Matrix()) Returns: : The newly created sensor object """ layers = defs.layerTypes['sensor'] bUtils.toggleLayer(layers, value=True) # create sensor object if sensor['shape'].startswith('resource'): newsensor = bUtils.createPrimitive( sensor['name'], 'box', [1, 1, 1], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=sensor['material'], phobostype='sensor', ) # use resource name provided as: "resource:whatever_name" resource_obj = ioUtils.getResource(['sensor'] + sensor['shape'].split('://')[1].split('_')) if resource_obj: log("Assigned resource mesh and materials to new sensor object.", 'DEBUG') newsensor.data = resource_obj.data newsensor.scale = (sensor['size'],) * 3 else: log("Could not use resource mesh for sensor. Default cube used instead.", 'WARNING') else: newsensor = bUtils.createPrimitive( sensor['name'], sensor['shape'], sensor['size'], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=sensor['material'], phobostype='sensor', ) # assign the parent if available if reference is not None: eUtils.parentObjectsTo(newsensor, reference) # TODO we need to deal with other types of parameters for sensors # TODO cameraRotLock() use or dispose? # contact, force and torque sensors (or unknown sensors) # else: # newsensor = bUtils.createPrimitive( # sensor['name'], 'ico', 0.05, layers, 'phobos_sensor', # origin.to_translation(), protation=origin.to_euler()) # if sensor['name'] == 'Joint6DOF': # # TODO delete me? handle this # #newsensor['sensor/nodes'] = nUtils.getObjectName(reference) # pass # elif 'Node' in sensor['type']: # newsensor['sensor/nodes'] = sorted([nUtils.getObjectName(ref) for ref in reference]) # elif 'Joint' in sensor['type'] or 'Motor' in sensor['type']: # newsensor['sensor/joints'] = sorted([nUtils.getObjectName(ref) for ref in reference]) # elif sensor['type'] in ['Joint6DOF']: # for obj in context.selected_objects: # if obj.phobostype == 'link': # sensor['name'] = "sensor_joint6dof_" + nUtils.getObjectName(obj, phobostype="joint") # sensors.createSensor(sensor, obj, obj.matrix_world) # elif 'Node' in sensor['type']: # sensors.createSensor(sensor, [obj for obj in context.selected_objects if obj.phobostype == 'collision'], # mathutils.Matrix.Translation(context.scene.cursor_location)) # elif 'Motor' in sensor['type'] or 'Joint' in sensor['type']: # sensors.createSensor(sensor, [obj for obj in context.selected_objects if obj.phobostype == 'link'], # mathutils.Matrix.Translation(context.scene.cursor_location)) # set sensor properties newsensor.phobostype = 'sensor' newsensor.name = sensor['name'] newsensor['sensor/name'] = sensor['name'] newsensor['sensor/type'] = sensor['type'] # write the custom properties to the sensor eUtils.addAnnotation(newsensor, sensor['props'], namespace='sensor') # throw warning if type is not known # TODO we need to link this error to the sensor type specifications if sensor['type'] not in [key.lower() for key in defs.def_settings['sensors']]: log( "Sensor " + sensor['name'] + " is of unknown/custom type: " + sensor['type'] + ".", 'WARNING', ) # select the new sensor sUtils.selectObjects([newsensor], clear=True, active=0) return newsensor
def execute(self, context): """Executes this blender operator and creates collision objects for the selected bodies. :param context: The blender context this function should work with. :return: set -- the blender specific return set. """ startLog(self) visuals = [] for obj in bpy.context.selected_objects: if obj.phobostype == "visual": visuals.append(obj) obj.select = False if not visuals: # bpy.ops.error.message('INVOKE_DEFAULT', type="CreateCollisions Error", message="Not enough bodies selected.") log("Not enough bodies selected.", "ERROR") return {'CANCELLED'} for vis in visuals: nameparts = vis.name.split('_') if nameparts[0] == 'visual': nameparts[0] = 'collision' collname = '_'.join(nameparts) materialname = vis.data.materials[0].name if len(vis.data.materials) > 0 else "None" bBox = vis.bound_box center = generalUtils.calcBoundingBoxCenter(bBox) rotation = mathutils.Matrix.Identity(4) size = list(vis.dimensions) if self.property_colltype in ['cylinder', 'capsule']: axes = ('X', 'Y', 'Z') long_side = axes[size.index(max(size))] # xyequal = (size[0] - size[1]) length = max(size) radii = [s for s in size if s != length] radius = max(radii) / 2 if radii != [] else length / 2 size = (radius, length) if long_side == 'X': rotation = mathutils.Matrix.Rotation(math.pi / 2, 4, 'Y') elif long_side == 'Y': rotation = mathutils.Matrix.Rotation(math.pi / 2, 4, 'X') # FIXME: apply rotation for moved cylinder object? elif self.property_colltype == 'sphere': size = max(size) / 2 rotation_euler = (vis.matrix_world * rotation).to_euler() center = vis.matrix_world.to_translation() + vis.matrix_world.to_quaternion() * center if self.property_colltype != 'capsule': ob = blenderUtils.createPrimitive(collname, self.property_colltype, size, defs.layerTypes['collision'], materialname, center, rotation_euler) elif self.property_colltype == 'capsule': length = max(length - 2 * radius, 0.001) # prevent length from turning negative size = (radius, length) zshift = length / 2 ob = blenderUtils.createPrimitive(collname, 'cylinder', size, defs.layerTypes['collision'], materialname, center, rotation_euler) sph1 = blenderUtils.createPrimitive('tmpsph1', 'sphere', radius, defs.layerTypes['collision'], materialname, center + rotation * mathutils.Vector((0, 0, zshift)), rotation_euler) sph2 = blenderUtils.createPrimitive('tmpsph2', 'sphere', radius, defs.layerTypes['collision'], materialname, center - rotation * mathutils.Vector((0, 0, zshift)), rotation_euler) selectionUtils.selectObjects([ob, sph1, sph2], True, 0) bpy.ops.object.join() ob['length'] = length ob['radius'] = radius elif self.property_colltype == 'mesh': pass # TODO: copy mesh!! ob.phobostype = 'collision' ob['geometry/type'] = self.property_colltype if vis.parent: ob.select = True bpy.ops.object.transform_apply(scale=True) vis.parent.select = True bpy.context.scene.objects.active = vis.parent bpy.ops.object.parent_set(type='BONE_RELATIVE') # ob.parent_type = vis.parent_type # ob.parent_bone = vis.parent_bone endLog() return {'FINISHED'}
def createMotor(motor, parentobj, origin=mathutils.Matrix(), addcontrollers=False): """This function creates a new motor specified by its parameters. If *addcontrollers* is set, a controller object will be created from the controller definition which is specified in the motor dictionary (key *controller*). Args: motor(dict): phobos representation of the new motor. parentobj(bpy_types.Object): object to parent new motor to origin(mathutils.Matrix, optional): new motors origin (Default value = mathutils.Matrix()) addcontrollers(bool, optional): whether to add the defined controller as object (Default value = False) Returns: bpy.types.Object: new motor object or a list of the new motor_object and the new controller object """ bUtils.toggleLayer('motor', value=True) primitive_name = '' # create name if not given by motor dict if not 'name' in motor or len(motor['name']) == 0: motor['name'] = parentobj.name primitive_name = "motor_" + motor['name'] else: primitive_name = motor['name'] primitive_name = '' # create name if not given by motor dict if not 'name' in motor or len(motor['name']) == 0: motor['name'] = parentobj.name primitive_name = "motor_" + motor['name'] else: primitive_name = motor['name'] # create motor object if motor['shape'].startswith('resource'): newmotor = bUtils.createPrimitive( primitive_name, 'box', [1, 1, 1], [], plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=motor['material'], phobostype='motor', ) # use resource name provided as: "resource:whatever_name" resource_obj = ioUtils.getResource( ['motor'] + motor['shape'].split('://')[1].split('_')) if resource_obj: log("Assigned resource mesh and materials to new motor object.", 'DEBUG') newmotor.data = resource_obj.data newmotor.scale = (motor['size'], ) * 3 else: log( "Could not use resource mesh for motor. Default cube used instead.", 'WARNING') else: newmotor = bUtils.createPrimitive( primitive_name, motor['shape'], motor['size'], [], plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=motor['material'], phobostype='motor', ) # assign the parent if available if parentobj is not None: sUtils.selectObjects([newmotor, parentobj], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') # set motor properties newmotor.phobostype = 'motor' # should not be nessaccary: newmotor.name = motor['name'] defname = motor['defname'] # write the custom properties to the motor eUtils.addAnnotation(newmotor, motor['props'], namespace='motor', ignore=['defname']) # fix motor name since it can differe from object name newmotor['motor/name'] = motor['name'] if 'controller' in defs.definitions['motors'][defname] and addcontrollers: import phobos.model.controllers as controllermodel motorcontroller = defs.definitions['motors'][defname]['controller'] controllerdefs = ioUtils.getDictFromYamlDefs( 'controller', motorcontroller, newmotor.name + '_controller') newcontroller = controllermodel.createController( controllerdefs, newmotor, origin=newmotor.matrix_world, annotations='all') else: newcontroller = None # select the new motor sUtils.selectObjects( [newmotor] if not newcontroller else [newmotor, newcontroller], clear=True, active=0) return newmotor if not newcontroller else [newmotor, newcontroller]
def createController(controller, reference, origin=mathutils.Matrix(), annotations=None): """This function creates a new controller specified by its parameters. If an annotation category or the keyword 'all' is specified, the respective annotations for the controller will be added as objects. Args: controller(dict): phobos representation of the new controller reference(bpy_types.Object): object to add a parent relationship to origin(mathutils.Matrix, optional): new controllers origin (Default value = mathutils.Matrix()) annotations(list(str, optional): list of annotation keys or 'all' to add to as annotation objects (Default value = None) Returns: : bpy.types.Object -- new created controller object """ layers = defs.layerTypes['controller'] bUtils.toggleLayer(layers, value=True) # create controller object if controller['shape'].startswith('resource'): newcontroller = bUtils.createPrimitive( controller['name'], 'box', [1, 1, 1], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=controller['material'], phobostype='controller', ) # use resource name provided as: "resource:whatever_name" resource_obj = ioUtils.getResource( ['controller'] + controller['shape'].split('://')[1].split('_') ) if resource_obj: log("Assigned resource mesh and materials to new controller object.", 'DEBUG') newcontroller.data = resource_obj.data newcontroller.scale = (controller['size'],) * 3 else: log("Could not use resource mesh for controller. Default cube used instead.", 'WARNING') else: newcontroller = bUtils.createPrimitive( controller['name'], controller['shape'], controller['size'], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=controller['material'], phobostype='controller', ) newcontroller.name = controller['name'] newcontroller['controller/type'] = controller['type'] # write the custom properties to the controller eUtils.addAnnotation(newcontroller, controller['props'], namespace='controller') if controller['annotations'] and annotations: if annotations == 'all': keys = controller['annotations'].keys() elif isinstance(annotations, list): keys = [key for key in annotations if key in controller['annotations']] else: keys = [] for key in keys: eUtils.addAnnotationObject( newcontroller, controller['annotations'][key], namespace='controller/' + key ) # assign the parent if available if reference is not None: sUtils.selectObjects([newcontroller, reference], clear=True, active=1) if reference.phobostype == 'link': bpy.ops.object.parent_set(type='BONE_RELATIVE') else: bpy.ops.object.parent_set(type='OBJECT') return newcontroller
def createSensor(sensor, reference, origin=mathutils.Matrix()): """This function creates a new sensor specified by its parameters. The sensor dictionary has to contain these keys: *name*: name of the new sensor *type*: type specifier of the sensor *shape*: a shape specifier for the sensor *props*: custom properties to be written to the sensor object Args: sensor(dict): phobos representation of the new sensor reference(bpy_types.Object): object to add a parent relationship to origin(mathutils.Matrix, optional): new sensors origin (Default value = mathutils.Matrix()) Returns: : The newly created sensor object """ layers = defs.layerTypes['sensor'] bUtils.toggleLayer(layers, value=True) # create sensor object if sensor['shape'].startswith('resource'): newsensor = bUtils.createPrimitive( sensor['name'], 'box', [1, 1, 1], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=sensor['material'], phobostype='sensor', ) # use resource name provided as: "resource:whatever_name" resource_obj = ioUtils.getResource( ['sensor'] + sensor['shape'].split('://')[1].split('_')) if resource_obj: log("Assigned resource mesh and materials to new sensor object.", 'DEBUG') newsensor.data = resource_obj.data newsensor.scale = (sensor['size'], ) * 3 else: log( "Could not use resource mesh for sensor. Default cube used instead.", 'WARNING') else: newsensor = bUtils.createPrimitive( sensor['name'], sensor['shape'], sensor['size'], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=sensor['material'], phobostype='sensor', ) # assign the parent if available if reference is not None: eUtils.parentObjectsTo(newsensor, reference) # TODO we need to deal with other types of parameters for sensors # TODO cameraRotLock() use or dispose? # contact, force and torque sensors (or unknown sensors) # else: # newsensor = bUtils.createPrimitive( # sensor['name'], 'ico', 0.05, layers, 'phobos_sensor', # origin.to_translation(), protation=origin.to_euler()) # if sensor['name'] == 'Joint6DOF': # # TODO delete me? handle this # #newsensor['sensor/nodes'] = nUtils.getObjectName(reference) # pass # elif 'Node' in sensor['type']: # newsensor['sensor/nodes'] = sorted([nUtils.getObjectName(ref) for ref in reference]) # elif 'Joint' in sensor['type'] or 'Motor' in sensor['type']: # newsensor['sensor/joints'] = sorted([nUtils.getObjectName(ref) for ref in reference]) # elif sensor['type'] in ['Joint6DOF']: # for obj in context.selected_objects: # if obj.phobostype == 'link': # sensor['name'] = "sensor_joint6dof_" + nUtils.getObjectName(obj, phobostype="joint") # sensors.createSensor(sensor, obj, obj.matrix_world) # elif 'Node' in sensor['type']: # sensors.createSensor(sensor, [obj for obj in context.selected_objects if obj.phobostype == 'collision'], # mathutils.Matrix.Translation(context.scene.cursor_location)) # elif 'Motor' in sensor['type'] or 'Joint' in sensor['type']: # sensors.createSensor(sensor, [obj for obj in context.selected_objects if obj.phobostype == 'link'], # mathutils.Matrix.Translation(context.scene.cursor_location)) # set sensor properties newsensor.phobostype = 'sensor' newsensor.name = sensor['name'] newsensor['sensor/name'] = sensor['name'] newsensor['sensor/type'] = sensor['type'] # write the custom properties to the sensor eUtils.addAnnotation(newsensor, sensor['props'], namespace='sensor') # throw warning if type is not known # TODO we need to link this error to the sensor type specifications if sensor['type'] not in [ key.lower() for key in defs.def_settings['sensors'] ]: log( "Sensor " + sensor['name'] + " is of unknown/custom type: " + sensor['type'] + ".", 'WARNING', ) # select the new sensor sUtils.selectObjects([newsensor], clear=True, active=0) return newsensor
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 createController(controller, reference, origin=mathutils.Matrix(), annotations=None): """This function creates a new controller specified by its parameters. If an annotation category or the keyword 'all' is specified, the respective annotations for the controller will be added as objects. Args: controller(dict): phobos representation of the new controller reference(bpy_types.Object): object to add a parent relationship to origin(mathutils.Matrix, optional): new controllers origin (Default value = mathutils.Matrix()) annotations(list(str, optional): list of annotation keys or 'all' to add to as annotation objects (Default value = None) Returns: : bpy.types.Object -- new created controller object """ bUtils.toggleLayer('controller', value=True) # create controller object if controller['shape'].startswith('resource'): newcontroller = bUtils.createPrimitive( controller['name'], 'box', [1, 1, 1], [], plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=controller['material'], phobostype='controller', ) # use resource name provided as: "resource:whatever_name" resource_obj = ioUtils.getResource( ['controller'] + controller['shape'].split('://')[1].split('_')) if resource_obj: log( "Assigned resource mesh and materials to new controller object.", 'DEBUG') newcontroller.data = resource_obj.data newcontroller.scale = (controller['size'], ) * 3 else: log( "Could not use resource mesh for controller. Default cube used instead.", 'WARNING') else: newcontroller = bUtils.createPrimitive( controller['name'], controller['shape'], controller['size'], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=controller['material'], phobostype='controller', ) newcontroller.name = controller['name'] newcontroller['controller/type'] = controller['type'] # write the custom properties to the controller eUtils.addAnnotation(newcontroller, controller['props'], namespace='controller') if controller['annotations'] and annotations: if annotations == 'all': keys = controller['annotations'].keys() elif isinstance(annotations, list): keys = [ key for key in annotations if key in controller['annotations'] ] else: keys = [] for key in keys: eUtils.addAnnotationObject(newcontroller, controller['annotations'][key], namespace='controller/' + key) # assign the parent if available if reference is not None: sUtils.selectObjects([newcontroller, reference], clear=True, active=1) if reference.phobostype == 'link': bpy.ops.object.parent_set(type='BONE_RELATIVE') else: bpy.ops.object.parent_set(type='OBJECT') return newcontroller
def createSensor(sensor, reference, origin=mathutils.Matrix()): """This function creates a new sensor specified by its parameters. :param sensor: The phobos representation of the new sensor. :type sensor: dict :param reference: This is an object to add a parent relationship to. :type reference: bpy_types.Object :param origin: The new sensors origin. :type origin: mathutils.Matrix :return: The newly created sensor object """ blenderUtils.toggleLayer(defs.layerTypes['sensor'], value=True) # create sensor object if 'Camera' in sensor['type']: bpy.context.scene.layers[defs.layerTypes['sensor']] = True bpy.ops.object.add(type='CAMERA', location=origin.to_translation(), rotation=origin.to_euler(), layers=blenderUtils.defLayers([defs.layerTypes['sensor']])) newsensor = bpy.context.active_object if reference is not None: selectionUtils.selectObjects([newsensor, bpy.data.objects[reference]], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') elif sensor['type'] in ['RaySensor', 'RotatingRaySensor', 'ScanningSonar', 'MultiLevelLaserRangeFinder']: # TODO: create a proper ray sensor scanning layer disc here newsensor = blenderUtils.createPrimitive(sensor['name'], 'disc', (0.5, 36), defs.layerTypes['sensor'], 'phobos_laserscanner', origin.to_translation(), protation=origin.to_euler()) if reference is not None and reference != []: if type(reference) == str: key = reference else: key = reference[0] selectionUtils.selectObjects([newsensor, bpy.data.objects[key]], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') else: # contact, force and torque sensors (or unknown sensors) newsensor = blenderUtils.createPrimitive(sensor['name'], 'sphere', 0.05, defs.layerTypes['sensor'], 'phobos_sensor', origin.to_translation(), protation=origin.to_euler()) if 'Node' in sensor['type']: newsensor['sensor/nodes'] = sorted(reference) elif 'Joint' in sensor['type'] or 'Motor' in sensor['type']: newsensor['sensor/joints'] = sorted(reference) # set sensor properties newsensor.phobostype = 'sensor' newsensor.name = sensor['name'] newsensor['sensor/type'] = sensor['type'] #for prop in ['link', 'joint', 'links', 'joints', 'motors']: # if prop in sensor: # newsensor['sensor/'+prop] = sensor[prop] # add custom properties #for prop in sensor: # if prop.startswith('$'): # for tag in sensor[prop]: # newsensor[prop[1:]+'/'+tag] = sensor[prop][tag] # throw warning if type is not known if sensor['type'] not in defs.sensortypes: print("### Warning: sensor", sensor['name'], "is of unknown/custom type.") selectionUtils.selectObjects([newsensor], clear=False, active=0) return newsensor
def createSensor(sensor, reference, origin=mathutils.Matrix()): """This function creates a new sensor specified by its parameters. Args: sensor(dict): The phobos representation of the new sensor. reference(bpy_types.Object): This is an object to add a parent relationship to. origin(mathutils.Matrix, optional): The new sensors origin. (Default value = mathutils.Matrix() Returns: The newly created sensor object """ bUtils.toggleLayer(defs.layerTypes['sensor'], value=True) # create sensor object if 'Camera' in sensor['type']: bpy.ops.object.add(type='CAMERA', location=origin.to_translation(), rotation=origin.to_euler(), layers=bUtils.defLayers([defs.layerTypes['sensor'] ])) newsensor = bpy.context.active_object if reference is not None: sUtils.selectObjects([newsensor, reference], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') elif sensor['type'] in [ 'RaySensor', 'RotatingRaySensor', 'ScanningSonar', 'MultiLevelLaserRangeFinder' ]: # TODO: create a proper ray sensor scanning layer disc here newsensor = bUtils.createPrimitive(sensor['name'], 'disc', (0.5, 36), defs.layerTypes['sensor'], 'phobos_laserscanner', origin.to_translation(), protation=origin.to_euler()) if reference is not None: sUtils.selectObjects([newsensor, reference], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') # contact, force and torque sensors (or unknown sensors) else: newsensor = bUtils.createPrimitive(sensor['name'], 'sphere', 0.05, defs.layerTypes['sensor'], 'phobos_sensor', origin.to_translation(), protation=origin.to_euler()) if sensor['type'] == 'Joint6DOF': # TODO delete me? handle this #newsensor['sensor/nodes'] = nUtils.getObjectName(reference) pass elif 'Node' in sensor['type']: newsensor['sensor/nodes'] = sorted( [nUtils.getObjectName(ref) for ref in reference]) elif 'Joint' in sensor['type'] or 'Motor' in sensor['type']: newsensor['sensor/joints'] = sorted( [nUtils.getObjectName(ref) for ref in reference]) if reference is not None: sUtils.selectObjects([newsensor, reference], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') # set sensor properties newsensor.phobostype = 'sensor' newsensor.name = sensor['name'] newsensor['sensor/type'] = sensor['type'] # TODO delete me? #for prop in ['link', 'joint', 'links', 'joints', 'motors']: # if prop in sensor: # newsensor['sensor/'+prop] = sensor[prop] # add custom properties #for prop in sensor: # if prop.startswith('$'): # for tag in sensor[prop]: # newsensor[prop[1:]+'/'+tag] = sensor[prop][tag] # throw warning if type is not known if sensor['type'] not in defs.sensortypes: print("### Warning: sensor", sensor['name'], "is of unknown/custom type.") sUtils.selectObjects([newsensor], clear=False, active=0) return newsensor
def execute(self, context): visuals = [] collisions = [] # find all selected visual objects for obj in context.selected_objects: if obj.phobostype == "visual": visuals.append(obj) obj.select = False if not visuals: log("No visual objects selected.", "ERROR", self) return {'CANCELLED'} # create collision objects for each visual for vis in visuals: # build object names nameparts = vis.name.split('_') if nameparts[0] == 'visual': nameparts[0] = 'collision' collname = '_'.join(nameparts) materialname = vis.data.materials[0].name if len( vis.data.materials) > 0 else "None" # get bounding box bBox = vis.bound_box center = gUtils.calcBoundingBoxCenter(bBox) rotation = mathutils.Matrix.Identity(4) size = list(vis.dimensions) # calculate size for cylinder, capsule or sphere if self.property_colltype in ['cylinder', 'capsule']: axes = ('X', 'Y', 'Z') long_side = axes[size.index(max(size))] length = max(size) radii = [s for s in size if s != length] radius = max(radii) / 2 if radii != [] else length / 2 size = (radius, length) # rotate cylinder/capsule to match longest side if long_side == 'X': rotation = mathutils.Matrix.Rotation(math.pi / 2, 4, 'Y') elif long_side == 'Y': rotation = mathutils.Matrix.Rotation(math.pi / 2, 4, 'X') # FIXME: apply rotation for moved cylinder object? elif self.property_colltype == 'sphere': size = max(size) / 2 # calculate rotation and center coordinates rotation_euler = (vis.matrix_world * rotation).to_euler() center = vis.matrix_world.to_translation( ) + vis.matrix_world.to_quaternion() * center # create Mesh if self.property_colltype != 'capsule' and self.property_colltype != 'mesh': ob = bUtils.createPrimitive(collname, self.property_colltype, size, defs.layerTypes['collision'], materialname, center, rotation_euler) elif self.property_colltype == 'capsule': # TODO reimplement capsules # prevent length from turning negative length = max(length - 2 * radius, 0.001) size = (radius, length) zshift = length / 2 tmpsph1_location = center + rotation_euler.to_matrix().to_4x4( ) * mathutils.Vector((0, 0, zshift)) tmpsph2_location = center - rotation_euler.to_matrix().to_4x4( ) * mathutils.Vector((0, 0, zshift)) # create cylinder and spheres and join them ob = bUtils.createPrimitive(collname, 'cylinder', size, defs.layerTypes['collision'], materialname, center, rotation_euler) sph1 = bUtils.createPrimitive('tmpsph1', 'sphere', radius, defs.layerTypes['collision'], materialname, tmpsph1_location, rotation_euler) sph2 = bUtils.createPrimitive('tmpsph2', 'sphere', radius, defs.layerTypes['collision'], materialname, tmpsph2_location, rotation_euler) sUtils.selectObjects([ob, sph1, sph2], True, 0) bpy.ops.object.join() # assign capsule properties ob['geometry/length'] = length ob['geometry/radius'] = radius ob['sph1_location'] = tmpsph1_location ob['sph2_location'] = tmpsph2_location elif self.property_colltype == 'mesh': # FIXME: simply turn this into object.duplicate? bpy.ops.object.duplicate_move( OBJECT_OT_duplicate={ "linked": False, "mode": 'TRANSLATION' }, TRANSFORM_OT_translate={"value": (0, 0, 0)}) # TODO: copy mesh!! # set properties of new collision object ob.phobostype = 'collision' ob['geometry/type'] = self.property_colltype collisions.append(ob) # make collision object relative if visual object has a parent if vis.parent: ob.select = True bpy.ops.object.transform_apply(scale=True) vis.parent.select = True context.scene.objects.active = vis.parent bpy.ops.object.parent_set(type='BONE_RELATIVE') # TODO delete these lines? # ob.parent_type = vis.parent_type # ob.parent_bone = vis.parent_bone # select created collision objects sUtils.selectObjects(collisions) return {'FINISHED'}
def createMotor(motor, parentobj, origin=mathutils.Matrix(), addcontrollers=False): """This function creates a new motor specified by its parameters. If *addcontrollers* is set, a controller object will be created from the controller definition which is specified in the motor dictionary (key *controller*). Args: motor(dict): phobos representation of the new motor. parentobj(bpy_types.Object): object to parent new motor to origin(mathutils.Matrix, optional): new motors origin (Default value = mathutils.Matrix()) addcontrollers(bool, optional): whether to add the defined controller as object (Default value = False) Returns: bpy.types.Object: new motor object or a list of the new motor_object and the new controller object """ layers = defs.layerTypes['motor'] bUtils.toggleLayer(layers, value=True) # create motor object if motor['shape'].startswith('resource'): newmotor = bUtils.createPrimitive( motor['name'], 'box', [1, 1, 1], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=motor['material'], phobostype='motor', ) # use resource name provided as: "resource:whatever_name" resource_obj = ioUtils.getResource(['motor'] + motor['shape'].split('://')[1].split('_')) if resource_obj: log("Assigned resource mesh and materials to new motor object.", 'DEBUG') newmotor.data = resource_obj.data newmotor.scale = (motor['size'],) * 3 else: log("Could not use resource mesh for motor. Default cube used instead.", 'WARNING') else: newmotor = bUtils.createPrimitive( motor['name'], motor['shape'], motor['size'], layers, plocation=origin.to_translation(), protation=origin.to_euler(), pmaterial=motor['material'], phobostype='motor', ) # assign the parent if available if parentobj is not None: sUtils.selectObjects([newmotor, parentobj], clear=True, active=1) bpy.ops.object.parent_set(type='BONE_RELATIVE') # set motor properties newmotor.phobostype = 'motor' newmotor.name = motor['name'] defname = motor['defname'] # write the custom properties to the motor eUtils.addAnnotation(newmotor, motor['props'], namespace='motor', ignore=['defname']) if 'controller' in defs.definitions['motors'][defname] and addcontrollers: import phobos.model.controllers as controllermodel motorcontroller = defs.definitions['motors'][defname]['controller'] controllerdefs = ioUtils.getDictFromYamlDefs( 'controller', motorcontroller, newmotor.name + '_controller' ) newcontroller = controllermodel.createController( controllerdefs, newmotor, origin=newmotor.matrix_world, annotations='all' ) else: newcontroller = None # select the new motor sUtils.selectObjects( [newmotor] if not newcontroller else [newmotor, newcontroller], clear=True, active=0 ) return newmotor if not newcontroller else [newmotor, newcontroller]