def execute(self, context): """ Args: context: Returns: """ if self.bakeObj == "None": return {"FINISHED"} with open(os.path.join(os.path.dirname(defs.__file__), "RobotLib.yml"), "r") as f: robot_lib = json.loads(f.read()) root = links.createLink(1.0, name=self.robName + "::" + self.bakeObj) root["model/name"] = self.bakeObj root["entity/name"] = self.robName root["isInstance"] = True bpy.ops.import_mesh.stl( filepath=os.path.join(robot_lib[self.bakeObj], "bake.stl")) bpy.ops.view3d.snap_selected_to_cursor(use_offset=False) obj = context.active_object obj.name = self.robName + "::visual" obj.phobostype = "visual" eUtils.parentObjectsTo(obj, root) return {"FINISHED"}
def deriveLinkfromObject(obj, scale=0.2, parent_link=True, parent_objects=False, nameformat=''): """Derives a link from an object using its name, transformation and parenting. Args: obj(bpy_types.Object): object to derive a link from scale(float, optional): scale factor for bone size (Default value = 0.2) parent_link(bool, optional): whether to automate the parenting of the new link or not. (Default value = True) parent_objects(bool, optional): whether to parent all the objects to the new link or not (Default value = False) nameformat(str, optional): re-formatting template for obj names (Default value = '') Returns: : newly created link """ log('Deriving link from ' + nUtils.getObjectName(obj), level="INFO") try: nameparts = [p for p in re.split('[^a-zA-Z]', nUtils.getObjectName(obj)) if p != ''] linkname = nameformat.format(*nameparts) except IndexError: log('Invalid name format (indices) for naming: ' + nUtils.getObjectName(obj), 'WARNING') linkname = 'link_' + nUtils.getObjectName(obj) link = createLink({'scale': scale, 'name': linkname, 'matrix': obj.matrix_world}) # parent link to object's parent if parent_link: if obj.parent: eUtils.parentObjectsTo(link, obj.parent) # parent children of object to link if parent_objects: children = [obj] + sUtils.getImmediateChildren(obj) eUtils.parentObjectsTo(children, link, clear=True) return link
def addLight(light_dict): """ Args: light_dict: Returns: """ # DOCU add some docstring if light_dict['type'] == 'spotlight': light_type = 'SPOT' elif light_dict['type'] == 'omnilight': light_type = 'POINT' position = light_dict['pose']['translation'] rotation = light_dict['pose']['rotation_euler'] bpy.ops.object.lamp_add(type=light_type, location=position, rotation=rotation) light = bpy.context.active_object if 'parent' in light_dict: eUtils.parentObjectsTo(light, bpy.data.objects[light_dict['parent']]) light_data = light.data light.name = light_dict['name'] colour_vals = ['r', 'g', 'b'] colour_data = light_dict['color']['diffuse'] light_data.color = [colour_data[v] for v in colour_vals] for v in colour_vals: if light_dict['color']['specular'][v] > 0: light_data.use_specular = True break if type == 'SPOT': light_data.spot_size = light_dict['angle'] # TODO delete me? # if light_dict['attenuation']['constant'] > 0: light_data.energy = light_dict['attenuation']['constant'] falloff = 'CONSTANT' if light_dict['attenuation']['linear'] > 0: light_data.linear_attenuation = light_dict['attenuation']['linear'] falloff = 'INVERSE_LINEAR' if light_dict['attenuation']['quadratic'] > 0: light_data.quadratic_attenuation = light_dict['attenuation']['quadratic'] if falloff == 'INVERSE_LINEAR': falloff = 'LINEAR_QUADRATIC_WEIGHTED' else: falloff = 'INVERSE_SQUARE' light_data.falloff_type = falloff light.phobostype = 'light' light['light/exponent'] = light_dict['exponent'] light.phobostype = 'light' light['light/directional'] = light_dict['directional'] return light
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(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 execute(self, context): """ Args: context: Returns: """ if self.bakeObj == "None": return {"FINISHED"} with open(os.path.join(os.path.dirname(defs.__file__), "RobotLib.yml"), "r") as f: robot_lib = yaml.load(f.read()) root = links.createLink(1.0, name=self.robName + "::" + self.bakeObj) root["model/name"] = self.bakeObj root["entity/name"] = self.robName root["isInstance"] = True bpy.ops.import_mesh.stl(filepath=os.path.join(robot_lib[self.bakeObj], "bake.stl")) bpy.ops.view3d.snap_selected_to_cursor(use_offset=False) obj = context.active_object obj.name = self.robName + "::visual" obj.phobostype = "visual" eUtils.parentObjectsTo(obj, root) return {"FINISHED"}
# save list of all parent joints for all visuals vparents = {} lparents = {} for v in visuals: vparents[v.name] = v.parent.name for l in links: try: lparents[l.name] = l.parent.name except AttributeError: pass # root link select(visuals, clear=True, active=0) bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM') select(links, clear=True, active=links.index(root)) bpy.context.scene.objects.active = root bpy.ops.object.join() bpy.ops.object.mode_set(mode='EDIT') for key, value in lparents.items(): root.data.edit_bones[key].parent = root.data.edit_bones[value] bpy.ops.object.mode_set(mode='OBJECT') for v in visuals: select([root], clear=True, active=0) bpy.ops.object.join() bpy.ops.object.mode_set(mode='EDIT') root.data.edit_bones.active = root.data.edit_bones[vparents[v.name]] bpy.ops.object.mode_set(mode='OBJECT') eUtils.parentObjectsTo(v, root, 1)
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
# save list of all parent joints for all visuals vparents = {} lparents = {} for v in visuals: vparents[v.name] = v.parent.name for l in links: try: lparents[l.name] = l.parent.name except AttributeError: pass # root link select(visuals, clear=True, active=0) bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM') select(links, clear=True, active=links.index(root)) bpy.context.scene.objects.active = root bpy.ops.object.join() bpy.ops.object.mode_set(mode='EDIT') for key, value in lparents.items(): root.data.edit_bones[key].parent = root.data.edit_bones[value] bpy.ops.object.mode_set(mode='OBJECT') for v in visuals: select([root], clear=True, active=0) bpy.ops.object.join() bpy.ops.object.mode_set(mode='EDIT') root.data.edit_bones.active = root.data.edit_bones[vparents[v.name]] bpy.ops.object.mode_set(mode='OBJECT') eUtils.parentObjectsTo(v, root, 1)
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 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 buildModelFromDictionary(model): """Creates the Blender representation of the imported model, using a model dictionary. Args: model(dict): model representation of the imported model Returns: """ log("Creating Blender model...", 'INFO', prefix='\n' + '-' * 25 + '\n') log(" Initializing materials... ({} total)".format(len(model['materials'])), 'INFO') for mat in model['materials']: matmodel.createMaterial(model['materials'][mat], logging=True, adjust=True) # ['name'], tuple(mat['color'][0:3]), (1, 1, 1), mat['color'][-1]) newobjects = [] log(" Creating links... ({} total)".format(len(model['links'])), 'INFO') for lnk in model['links']: link = model['links'][lnk] model['links'][lnk]['object'] = linkmodel.createLink(link) newobjects.append(model['links'][lnk]['object']) newobjects.extend(model['links'][lnk]['object'].children) log("Setting parent-child relationships", 'INFO', prefix='\n') bUtils.toggleLayer('link', True) for lnk in model['links']: parent = model['links'][lnk] log("Children for link " + parent['name'] + ":\n" + '\n'.join(parent['children']), 'DEBUG') for chi in parent['children']: child = model['links'][chi] child['object'].matrix_world = parent['object'].matrix_world eUtils.parentObjectsTo(child['object'], parent['object']) # set transformations log("Transforming links... ({} total)".format(len(model['links'])), 'INFO', prefix='\n') for lnk in model['links']: if 'parent' not in model['links'][lnk]: root = model['links'][lnk] break linkmodel.setLinkTransformations(model, root) log("Creating joints... ({} total)".format(len(model['joints'])), 'INFO', prefix='\n') for j in model['joints']: joint = model['joints'][j] jointmodel.createJoint(joint, links=model['links']) log("Assigning model name: {}".format(model['name']), 'INFO') rootlink = sUtils.getRoot(bpy.data.objects[root['object'].name]) if 'name' not in model: log("Model name not specified in URDF. Make sure to define it thereafter.", 'WARNING') else: rootlink['model/name'] = model['name'] rootlink.location = (0, 0, 0) # TODO make sure this works log("Creating sensors...", 'INFO') if 'sensors' in model and model['sensors']: for sen in model['sensors']: sensormodel.createSensor(model['sensors'][sen], model['sensors'][sen]['parent']) else: log(" No sensors in model.", 'INFO') # TODO make sure this works log("Creating motors...", 'INFO') if 'motors' in model and model['motors']: for motor in model['motors']: eUtils.setProperties( model['joints'][model['motors'][motor]['joint']], model['motors'][motor], category='motor', ) else: log(" No motors in model.", 'INFO') # TODO make sure this works log("Creating groups...", 'INFO') if 'groups' in model and model['groups']: for group in model['groups']: createGroup(model['groups'][group]) else: log(" No kinematic groups in model.", 'INFO') # TODO make sure this works log("Creating chains...", 'INFO') if 'chains' in model and model['chains']: for ch in model['chains']: createChain(model['chains'][ch]) else: log(" No kinematic chains in model.", 'INFO') # TODO make sure this works log("Creating lights...", 'INFO') if 'lights' in model and model['lights']: for light in model['lights']: lightmodel.createLight(model['lights'][light]) else: log(" No lights in model.", 'INFO') # display new objects after import sUtils.selectObjects(newobjects, clear=True, active=0) eUtils.sortObjectsToLayers(newobjects) for obj in newobjects: bUtils.setObjectLayersActive(obj, extendlayers=True) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.view3d.view_selected() # update the scene bUtils.update()