Example #1
0
def createLink(scale, position=None, orientation=None, name=''):
    """Creates an empty link (bone) at the current 3D cursor position.

    :param scale: This is the scale you want to apply to the new link.
    :type scale: Float array with 3 elements.
    :param position: This specifies the position of the newly created link. When not given its (0.0,0.0,0.0)
    :type position: Float array with 3 elements.
    :param orientation: This specifies the rotation of the newly created link. When not given its (0.0,0.0,0.0)
    :type orientation:Float array with 3 elements.
    :param name: This sets the name for the new link. When not given the link is nameless.
    :type name: str
    :return: bpy_types.Object

    """
    blenderUtils.toggleLayer(defs.layerTypes['link'], True)
    if position is None and orientation is None:
        bpy.ops.object.armature_add(layers=blenderUtils.defLayers([0]))
    elif position is None:
        bpy.ops.object.armature_add(rotation=orientation,
                                    layers=blenderUtils.defLayers([0]))
    elif orientation is None:
        bpy.ops.object.armature_add(location=position,
                                    layers=blenderUtils.defLayers([0]))
    else:
        bpy.ops.object.armature_add(location=position,
                                    rotation=orientation,
                                    layers=blenderUtils.defLayers([0]))
    link = bpy.context.active_object
    link.scale = [scale, scale, scale]
    bpy.ops.object.transform_apply(scale=True)
    if name:
        link.name = name
    link.phobostype = 'link'
    return link
Example #2
0
def createLink(scale, position=None, orientation=None, name=''):
    """Creates an empty link (bone) at the current 3D cursor position.

    :param scale: This is the scale you want to apply to the new link.
    :type scale: Float array with 3 elements.
    :param position: This specifies the position of the newly created link. When not given its (0.0,0.0,0.0)
    :type position: Float array with 3 elements.
    :param orientation: This specifies the rotation of the newly created link. When not given its (0.0,0.0,0.0)
    :type orientation:Float array with 3 elements.
    :param name: This sets the name for the new link. When not given the link is nameless.
    :type name: string.
    :return: blender object

    """
    blenderUtils.toggleLayer(defs.layerTypes['link'], True)
    if position is None and orientation is None:
        bpy.ops.object.armature_add(layers=blenderUtils.defLayers([0]))
    elif position is None:
        bpy.ops.object.armature_add(rotation=orientation, layers=blenderUtils.defLayers([0]))
    elif orientation is None:
        bpy.ops.object.armature_add(location=position, layers=blenderUtils.defLayers([0]))
    else:
        bpy.ops.object.armature_add(location=position, rotation=orientation, layers=blenderUtils.defLayers([0]))
    link = bpy.context.active_object
    link.scale = [scale, scale, scale]
    bpy.ops.object.transform_apply(scale=True)
    if name:
        link.name = name
    link.phobostype = 'link'
    return link
Example #3
0
def setLinkTransformations(model, parent):
    """Assigns the transformations recursively for a model parent link according to the model.
    
    This needs access to the **object** key of a link entry in the specified model.
    The transformations for each link object are extracted from the specified model and applied to
    the Blender object.

    Args:
      parent(dict): parent link you want to set the children for.
      model(dict): model dictionary containing the **object** key for each link

    Returns:

    """
    bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes['link'])
    for chi in parent['children']:
        child = model['links'][chi]

        # apply transform as saved in model
        location = mathutils.Matrix.Translation(child['pose']['translation'])
        rotation = (
            mathutils.Euler(tuple(child['pose']['rotation_euler']), 'XYZ').to_matrix().to_4x4()
        )

        log("Transforming link {0}.".format(child['name']), 'DEBUG')
        transform_matrix = location * rotation
        child['object'].matrix_local = transform_matrix

        # traverse the tree
        setLinkTransformations(model, child)
Example #4
0
def placeLinkSubelements(link):
    """Finds all subelements for a given link and sets the appropriate relations.
    In this case subelements are interials, visuals and collisions.

    :param link: The parent link you want to set the subelements for
    :type link: dict

    """
    elements = getGeometricElements(link) + ([link['inertial']] if 'inertial' in link else [])
    bpy.context.scene.layers = bUtils.defLayers([defs.layerTypes[t] for t in defs.layerTypes])
    parentlink = bpy.data.objects[link['name']]
    for element in elements:
        if 'pose' in element:
            location = mathutils.Matrix.Translation(element['pose']['translation'])
            rotation = mathutils.Euler(tuple(element['pose']['rotation_euler']), 'XYZ').to_matrix().to_4x4()
        else:
            location = mathutils.Matrix.Identity(4)
            rotation = mathutils.Matrix.Identity(4)
        try:
            obj = bpy.data.objects[element['name']]
        except KeyError:
            log('Missing link element for placement: ' + element['name'], 'ERROR', 'placeLinkSubelements')
            continue
        sUtils.selectObjects([obj, parentlink], True, 1)
        bpy.ops.object.parent_set(type='BONE_RELATIVE')
        obj.matrix_local = location * rotation
        try:
            obj.scale = mathutils.Vector(element['geometry']['scale'])
        except KeyError:
            pass
Example #5
0
def attachSensor(self, sensor):
    """This function attaches a given sensor to its parent link.

    :param sensor: The sensor you want to attach to its parent link.
    :type sensor: dict

    """
    bpy.context.scene.layers = bUtils.defLayers([defs.layerTypes[t] for t in defs.layerTypes])
    #try:
    if 'pose' in sensor:
        urdf_geom_loc = mathutils.Matrix.Translation(sensor['pose']['translation'])
        urdf_geom_rot = mathutils.Euler(tuple(sensor['pose']['rotation_euler']), 'XYZ').to_matrix().to_4x4()
    else:
        urdf_geom_loc = mathutils.Matrix.Identity(4)
        urdf_geom_rot = mathutils.Matrix.Identity(4)
    sensorobj = bpy.data.objects[sensor['name']]
    if 'link' in sensor:
        parentLink = sUtils.getObjectByNameAndType(sensor['link'], 'link')
        #parentLink = bpy.data.objects['link_' + sensor['link']]
        sUtils.selectObjects([sensorobj, parentLink], True, 1)
        bpy.ops.object.parent_set(type='BONE_RELATIVE')
    else:
        #TODO: what?
        pass
    sensorobj.matrix_local = urdf_geom_loc * urdf_geom_rot
Example #6
0
def createLink(link):
    """Creates the blender representation of a given link and its parent joint.

    Args:
      link(dict): The link you want to create a representation of.

    Returns:
      bpy_types.Object -- the newly created blender link object.

    """
    # create armature/bone
    bUtils.toggleLayer(defs.layerTypes['link'], True)
    bpy.ops.object.select_all(action='DESELECT')
    bpy.ops.object.armature_add(
        layers=bUtils.defLayers([defs.layerTypes['link']]))
    newlink = bpy.context.active_object
    # Move bone when adding at selected objects location
    if 'matrix' in link:
        newlink.matrix_world = link['matrix']
    newlink.phobostype = 'link'
    if link['name'] in bpy.data.objects.keys():
        log('Object with name of new link already exists: ' + link['name'],
            'WARNING')
    nUtils.safelyName(newlink, link['name'])

    # set the size of the link
    visuals, collisions = getGeometricElements(link)
    if visuals or collisions:
        scale = max((geometrymodel.getLargestDimension(e['geometry'])
                     for e in visuals + collisions))
    else:
        scale = 0.2

    # use scaling factor provided by user
    if 'scale' in link:
        scale *= link['scale']
    newlink.scale = (scale, scale, scale)
    bpy.ops.object.transform_apply(scale=True)

    # add custom properties
    for prop in link:
        if prop.startswith('$'):
            for tag in link[prop]:
                newlink['link/' + prop[1:] + '/' + tag] = link[prop][tag]

    # create inertial
    if 'inertial' in link:
        inertia.createInertial(link['name'], link['inertial'], newlink)

    # create geometric elements
    log(
        "Creating visual and collision objects for link '{0}': {1}".format(
            link['name'],
            ', '.join([elem['name'] for elem in visuals + collisions])),
        'DEBUG')
    for v in visuals:
        geometrymodel.createGeometry(v, 'visual', newlink)
    for c in collisions:
        geometrymodel.createGeometry(c, 'collision', newlink)
    return newlink
Example #7
0
def createLink(link):
    """Creates the blender representation of a given link and its parent joint.

    :param link: The link you want to create a representation of.
    :type link: dict
    :return: bpy_types.Object -- the newly created blender link object.
    """
    # create armature/bone
    bUtils.toggleLayer(defs.layerTypes['link'], True)
    bpy.ops.object.select_all(action='DESELECT')
    bpy.ops.object.armature_add(
        layers=bUtils.defLayers([defs.layerTypes['link']]))
    newlink = bpy.context.active_object
    # Move bone when adding at selected objects location
    if 'matrix' in link:
        newlink.matrix_world = link['matrix']
    newlink.phobostype = 'link'
    newlink.name = link['name']
    # FIXME: This is a hack and should be checked before creation!
    # this is a backup in case an object with the link's name already exists
    newlink["link/name"] = link['name']

    # FIXME geometric dimensions are not intiallized properly, thus scale always 0.2!
    # set the size of the link
    elements = getGeometricElements(link)
    scale = max((geometrymodel.getLargestDimension(element['geometry'])
                 for element in elements)) if elements else 0.2

    # use scaling factor provided by user
    #FIXME where would this *scale* come from?
    if 'scale' in link:
        scale *= link['scale']
    newlink.scale = (scale, scale, scale)
    bpy.ops.object.transform_apply(scale=True)

    # add custom properties
    for prop in link:
        if prop.startswith('$'):
            for tag in link[prop]:
                newlink['link/' + prop[1:] + '/' + tag] = link[prop][tag]

    # create inertial
    if 'inertial' in link:
        inertiamodel.createInertialFromDictionary(link['name'],
                                                  link['inertial'])

    # create visual elements
    if 'visual' in link:
        for v in link['visual']:
            visual = link['visual'][v]
            geometrymodel.createGeometry(visual, 'visual')

    # create collision elements
    if 'collision' in link:
        for c in link['collision']:
            collision = link['collision'][c]
            geometrymodel.createGeometry(collision, 'collision')

    return newlink
Example #8
0
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
Example #9
0
def placeChildLinks(model, parent):
    """Creates parent-child-relationship for a given parent and all existing children in Blender.

    :param parent: This is the parent link you want to set the children for.
    :type: dict
    """
    bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes['link'])
    children = []
    for l in model['links']:
        if 'parent' in model['links'][l] and model['links'][l][
                'parent'] == parent['name']:
            children.append(model['links'][l])
    for child in children:
        # 1: set parent relationship (this makes the parent inverse the inverse of the parents world transform)
        parentLink = bpy.data.objects[parent['name']]
        childLink = bpy.data.objects[child['name']]
        sUtils.selectObjects([childLink, parentLink], True, 1)
        bpy.ops.object.parent_set(type='BONE_RELATIVE')
        # 2: move to parents origin by setting the world matrix to the parents world matrix
        # removing this line does not seem to make a difference (TODO delete me?)
        childLink.matrix_world = parentLink.matrix_world

        # TODO delete me?
        # #bpy.context.scene.objects.active = childLink
        # if 'pivot' in child:
        #     pivot = child['pivot']
        #     cursor_location = bpy.context.scene.cursor_location
        #     bpy.context.scene.cursor_location = mathutils.Vector((-pivot[0]*0.3, -pivot[1]*0.3, -pivot[2]*0.3))
        #     bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
        #     bpy.context.scene.cursor_location = cursor_location

        # 3: apply local transform as saved in model (changes matrix_local)
        location = mathutils.Matrix.Translation(child['pose']['translation'])
        rotation = mathutils.Euler(tuple(child['pose']['rotation_euler']),
                                   'XYZ').to_matrix().to_4x4()
        transform_matrix = location * rotation
        childLink.matrix_local = transform_matrix
        # 4: be happy, as world and basis are now the same and local is the transform to be exported to urdf
        # 5: take care of the rest of the tree
        placeChildLinks(model, child)
Example #10
0
def placeLinkSubelements(link):
    """Places visual and collision objects for a given link.

    :param link: The parent link you want to set the subelements for
    :type link: dict
    """
    elements = getGeometricElements(link)
    bpy.context.scene.layers = bUtils.defLayers(
        [defs.layerTypes[t] for t in defs.layerTypes])
    parentlink = bpy.data.objects[link['name']]
    log(
        'Placing subelements for link: ' + link['name'] + ': ' +
        ', '.join([elem['name'] for elem in elements]), 'DEBUG')
    for element in elements:
        if 'pose' in element:
            log('Pose detected for element: ' + element['name'], 'DEBUG')
            location = mathutils.Matrix.Translation(
                element['pose']['translation'])
            rotation = mathutils.Euler(
                tuple(element['pose']['rotation_euler']),
                'XYZ').to_matrix().to_4x4()
        else:
            log('No pose in element: ' + element['name'], 'DEBUG')
            location = mathutils.Matrix.Identity(4)
            rotation = mathutils.Matrix.Identity(4)
        try:
            obj = bpy.data.objects[element['name']]
        except KeyError:
            log('Missing link element for placement: ' + element['name'],
                'ERROR')
            continue
        sUtils.selectObjects([obj, parentlink], True, 1)
        bpy.ops.object.parent_set(type='BONE_RELATIVE')
        obj.matrix_local = location * rotation
        try:
            obj.scale = mathutils.Vector(element['geometry']['scale'])
        except KeyError:
            log('No scale defined for element ' + element['name'], 'DEBUG')
Example #11
0
def placeChildLinks(model, parent):
    """Creates parent-child-relationship for a given parent and all existing children in Blender.

    Args:
      parent(dict): parent link you want to set the children for.
      model(dict):

    Returns:

    """
    bpy.context.scene.layers = bUtils.defLayers(defs.layerTypes['link'])
    for c in parent['children']:
        child = model['links'][c]
        # apply transform as saved in model
        location = mathutils.Matrix.Translation(child['pose']['translation'])
        rotation = mathutils.Euler(tuple(child['pose']['rotation_euler']),
                                   'XYZ').to_matrix().to_4x4()
        log('Placing link {0}'.format(child['name']), 'DEBUG')
        transform_matrix = location * rotation
        log("Joint transform: {0}".format(transform_matrix), 'DEBUG')
        child['object'].matrix_local = transform_matrix

        # traverse the tree
        placeChildLinks(model, child)
Example #12
0
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
Example #13
0
def defineSubmodel(submodelname, submodeltype, version='', objects=None):
    """Defines a new submodule group with the specified name and type.
    
    The group will be named like so:
        'submodeltype:submodelname/version'
    
    Objects with the phobostype 'interface' (if present) are handled separately
    and put into a respective submodel group (which features the 'interface'
    submodeltype).
    
    If the version is omitted, the respective part of the name is dropped, too.
    If no object list is provided the objects are derived from selection.
    The submodeltype is also added as dict entry to the group in Blender.
    
    The selected objects are moved to the respective layer for submodels or
    interfaces.

    Args:
      submodelname: descriptive name of the submodel
      submodeltype: type of the submodel (e.g. 'fmu', 'mechanics')
      version: a version string (e.g. '1.0', 'dangerous') (Default value = '')
      objects: the objects which belong to the submodel (None will derive
    objects from the selection) (Default value = None)

    Returns:
      : a tuple of the submodelgroup and interfacegroup/None

    """
    if not objects:
        objects = bpy.context.selected_objects

    # split interface from physical objects
    interfaces = [i for i in objects if i.phobostype == 'interface']
    physical_objects = [p for p in objects if p.phobostype != 'interface']

    # make the physical group
    sUtils.selectObjects(physical_objects, True, 0)
    submodelgroupname = submodeltype + ':' + submodelname
    if version != '':
        submodelgroupname += '/' + version
    if submodelgroupname in bpy.data.groups.keys():
        log('submodelgroupname ' + 'already exists', 'WARNING')
    bpy.ops.group.create(name=submodelgroupname)
    submodelgroup = bpy.data.groups[submodelgroupname]
    submodelgroup['submodeltype'] = submodeltype
    submodelgroup['version'] = version

    modeldefs = defs.definitions['submodeltypes'][submodeltype]

    # copy the definition parameters to the group properties
    for key in modeldefs['definitions']:
        submodelgroup[key] = modeldefs['definitions'][key]

    # move objects to submodel layer
    for obj in physical_objects:
        obj.layers = bUtils.defLayers(defs.layerTypes['submodel'])
    log('Created submodel group ' + submodelname + ' of type "' + submodeltype + '".', 'DEBUG')

    interfacegroup = None
    # make the interface group
    if interfaces:
        sUtils.selectObjects(interfaces, True, 0)
        interfacegroupname = 'interfaces:' + submodelname
        if version != '':
            interfacegroupname += '/' + version
        # TODO what about overwriting groups with same names?
        bpy.ops.group.create(name=interfacegroupname)
        interfacegroup = bpy.data.groups[interfacegroupname]
        interfacegroup['submodeltype'] = 'interfaces'

        # copy interface definitions from submodel definitions
        for key in modeldefs['interfaces']:
            interfacegroup[key] = modeldefs['interfaces'][key]

        # move objects to interface layer
        for obj in interfaces:
            obj.layers = bUtils.defLayers(defs.layerTypes['interface'])
        log('Created interface group for submodel ' + submodelname + '.', 'DEBUG')
    else:
        log('No interfaces for this submodel.', 'DEBUG')

    for i in interfaces:
        i.show_name = True
    return (submodelgroup, interfacegroup)
Example #14
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
Example #15
0
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
Example #16
0
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
Example #17
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
Example #18
0
def defineSubmodel(submodelname, submodeltype, version='', objects=None):
    """Defines a new submodule group with the specified name and type.
    
    The group will be named like so:
        'submodeltype:submodelname/version'
    
    Objects with the phobostype 'interface' (if present) are handled separately
    and put into a respective submodel group (which features the 'interface'
    submodeltype).
    
    If the version is omitted, the respective part of the name is dropped, too.
    If no object list is provided the objects are derived from selection.
    The submodeltype is also added as dict entry to the group in Blender.
    
    The selected objects are moved to the respective layer for submodels or
    interfaces.

    Args:
      submodelname: descriptive name of the submodel
      submodeltype: type of the submodel (e.g. 'fmu', 'mechanics')
      version: a version string (e.g. '1.0', 'dangerous') (Default value = '')
      objects: the objects which belong to the submodel (None will derive
    objects from the selection) (Default value = None)

    Returns:
      : a tuple of the submodelgroup and interfacegroup/None

    """
    if not objects:
        objects = bpy.context.selected_objects

    # split interface from physical objects
    interfaces = [i for i in objects if i.phobostype == 'interface']
    physical_objects = [p for p in objects if p.phobostype != 'interface']

    # make the physical group
    sUtils.selectObjects(physical_objects, True, 0)
    submodelgroupname = submodeltype + ':' + submodelname
    if version != '':
        submodelgroupname += '/' + version
    if submodelgroupname in bpy.data.groups.keys():
        log('submodelgroupname ' + 'already exists', 'WARNING')
    bpy.ops.group.create(name=submodelgroupname)
    submodelgroup = bpy.data.groups[submodelgroupname]
    submodelgroup['submodeltype'] = submodeltype
    submodelgroup['version'] = version

    modeldefs = defs.definitions['submodeltypes'][submodeltype]

    # copy the definition parameters to the group properties
    for key in modeldefs['definitions']:
        submodelgroup[key] = modeldefs['definitions'][key]

    # move objects to submodel layer
    for obj in physical_objects:
        obj.layers = bUtils.defLayers(defs.layerTypes['submodel'])
    log('Created submodel group ' + submodelname + ' of type "' + submodeltype + '".', 'DEBUG')

    interfacegroup = None
    # make the interface group
    if interfaces:
        sUtils.selectObjects(interfaces, True, 0)
        interfacegroupname = 'interfaces:' + submodelname
        if version != '':
            interfacegroupname += '/' + version
        # TODO what about overwriting groups with same names?
        bpy.ops.group.create(name=interfacegroupname)
        interfacegroup = bpy.data.groups[interfacegroupname]
        interfacegroup['submodeltype'] = 'interfaces'

        # copy interface definitions from submodel definitions
        for key in modeldefs['interfaces']:
            interfacegroup[key] = modeldefs['interfaces'][key]

        # move objects to interface layer
        for obj in interfaces:
            obj.layers = bUtils.defLayers(defs.layerTypes['interface'])
        log('Created interface group for submodel ' + submodelname + '.', 'DEBUG')
    else:
        log('No interfaces for this submodel.', 'DEBUG')

    for i in interfaces:
        i.show_name = True
    return (submodelgroup, interfacegroup)
Example #19
0
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
Example #20
0
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
Example #21
0
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
Example #22
0
def createLink(link):
    """Creates the blender representation of a given link and its parent joint.
    
    The link is added to the link layer.
    
    These entries in the dictionary are mandatory:
        *name*: name for the link
    
    The specified dictionary may contain these entries:
        *matrix*: world matrix for the new link transformation
        *scale*: scale for the new link (single float)
        *visual*: list of visual dictionaries
        *collision*: list of collision dictionaries
        *inertial*: inertial dictionary (an inertial object will be created on the fly)
    
    Furthermore any generic properties, prepended by a `$` will be added as custom properties to the
    link. E.g. $test/etc would be put to link/test/etc. However, these properties are extracted
    only in the first layer of hierarchy.

    Args:
      link(dict): The link you want to create a representation of.

    Returns:
      : bpy_types.Object -- the newly created blender link object.

    """
    log("Creating link object '{}'...".format(link['name']), 'DEBUG', prefix='\n')
    # create armature/bone
    bUtils.toggleLayer(defs.layerTypes['link'], True)
    bpy.ops.object.select_all(action='DESELECT')
    bpy.ops.object.armature_add(layers=bUtils.defLayers([defs.layerTypes['link']]))
    newlink = bpy.context.active_object

    # Move bone when adding at selected objects location
    if 'matrix' in link:
        newlink.matrix_world = link['matrix']

    # give it a proper name
    newlink.phobostype = 'link'
    if link['name'] in bpy.data.objects.keys():
        log('Object with name of new link already exists: ' + link['name'], 'WARNING')
    nUtils.safelyName(newlink, link['name'])

    # set the size of the link
    visuals, collisions = getGeometricElements(link)
    if visuals or collisions:
        scale = max(
            (geometrymodel.getLargestDimension(e['geometry']) for e in visuals + collisions)
        )
    else:
        scale = 0.2

    # use scaling factor provided by user
    if 'scale' in link:
        scale *= link['scale']
    newlink.scale = (scale, scale, scale)
    bpy.ops.object.transform_apply(scale=True)

    # add custom properties
    for prop in link:
        if prop.startswith('$'):
            for tag in link[prop]:
                newlink['link/' + prop[1:] + '/' + tag] = link[prop][tag]

    # create inertial
    if 'inertial' in link:
        inertia.createInertial(link['inertial'], newlink)

    # create geometric elements
    log(
        "Creating visual and collision objects for link '{0}':\n{1}".format(
            link['name'], '    \n'.join([elem['name'] for elem in visuals + collisions])
        ),
        'DEBUG',
    )
    for vis in visuals:
        geometrymodel.createGeometry(vis, 'visual', newlink)
    for col in collisions:
        geometrymodel.createGeometry(col, 'collision', newlink)
    return newlink