Exemple #1
0
    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"}
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
    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)
Exemple #8
0
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)
Exemple #10
0
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
Exemple #11
0
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
Exemple #12
0
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
Exemple #13
0
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()