Beispiel #1
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        log("Jumping to object " + self.objectname + ".", 'DEBUG')

        # switch the scene if the object is anywhere else
        scene = None
        if self.objectname not in context.scene:
            for sce in bpy.data.scenes:
                if self.objectname in sce.objects:
                    scene = sce
                    break
            else:
                log("Could not find scene of object {}. Aborted.".format(self.objectname), 'ERROR')
                return {'CANCELLED'}
            bUtils.switchToScene(scene.name)

        # toggle layer to make object visible
        bUtils.setObjectLayersActive(scene.objects[self.objectname], extendlayers=True)

        sUtils.selectObjects([scene.objects[self.objectname]], clear=True, active=0)
        return {'FINISHED'}
Beispiel #2
0
def roundFloatsInDict(data, decimals):
    """Recursively rounds all floats in the dictionary to the specified decimal digits.
    
    If a float value is smaller than 10e-decimals it is set to zero.

    Args:
      data(dict): data dictionary
      decimals(int): number of decimals floats should be rounded to

    Returns:
      : dict -- dictionary with rounded floats

    """
    epsilon = 10 ** -decimals
    if is_float(data):
        if isinstance(data, str):
            log("Skipping rounding of " + data + " due to its type 'str'", "WARNING")
            return data
        return 0 if abs(data) < epsilon else round(data, decimals)
    elif isinstance(data, list):
        return [roundFloatsInDict(a, decimals) for a in data]
    elif isinstance(data, dict):
        return {key: roundFloatsInDict(value, decimals) for key, value in data.items()}
    else:
        return data
Beispiel #3
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        selection = []
        if self.modelname:
            log("phobos: Selecting model" + self.modelname, "INFO")
            roots = sUtils.getRoots()
            for root in roots:
                if nUtils.getModelName(root) == self.modelname:
                    selection = sUtils.getChildren(root)
        else:
            log("No model name provided, deriving from selection...", "INFO")
            roots = set()
            for obj in bpy.context.selected_objects:
                roots.add(sUtils.getRoot(obj))
            for root in list(roots):
                selection.extend(sUtils.getChildren(root))
        sUtils.selectObjects(list(selection), True)
        return {'FINISHED'}
Beispiel #4
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        roots = set()

        # add root object of each selected object
        for obj in context.selected_objects:
            roots.add(sUtils.getRoot(obj))

        # select all found root objects
        if roots:
            # toggle layer to make objects visible
            for root in roots:
                bUtils.setObjectLayersActive(root, extendlayers=True)

            # select objects
            sUtils.selectObjects(list(roots), True)
            context.scene.objects.active = list(roots)[0]
        else:
            log("Couldn't find any root object.", 'ERROR')
        return {'FINISHED'}
Beispiel #5
0
def deriveEntity(light, outpath):
    """This function handles a light entity in a scene to export it

    Args:
      entity(bpy.types.Object): The lights root object.
      outpath(str): The path to export to. Not used for light entity
      savetosubfolder(bool): If True data will be exported into subfolders. Not used for light entity
      light: 

    Returns:
      : dict - An entry for the scenes entitiesList

    """
    log("Exporting " + light["entity/name"] + " as a light entity", "INFO")
    entitypose = models.deriveObjectPose(light)
    lightobj = sUtils.getImmediateChildren(light)[0]
    color = lightobj.data.color
    entity = {
        "name": light["entity/name"],
        "type": "light",
        "light_type": "spotlight" if lightobj.data.type == "SPOT" else "omnilight",
        "anchor": light["anchor"] if "anchor" in light else "none",
        "color": {
            "diffuse": [color.r, color.g, color.b],
            "use_specular": lightobj.data.use_specular,  # only specular information currently available
        },
        "position": entitypose["translation"],
        "rotation": entitypose["rotation_quaternion"],
    }
    if entity["light_type"] == "spotlight":
        entity["angle"] = lightobj.data.spot_size
    return entity
Beispiel #6
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        libPath = os.path.join(os.path.dirname(defs.__file__), "RobotLib.yml")
        path, file = os.path.split(self.filepath)
        if file.endswith(".bake"):
            with open(self.filepath, "r") as f:
                info = yaml.load(f.read())
            if not os.path.isfile(libPath):
                open(libPath, "a").close()
            with open(libPath, "r+") as f:
                robot_lib = yaml.load(f.read())
                robot_lib = robot_lib if robot_lib is not None else {}
                robot_lib[info["name"]] = path
                f.seek(0)
                f.write(yaml.dump(robot_lib))
                f.truncate()
        else:
            log("This is no robot bake!", "ERROR")
        return {"FINISHED"}
Beispiel #7
0
def getRoots(scene=None):
    """Returns a list of all of the current/specified scene's root objects.

    Args:
      scene(bpy.types.Scene, optional): the scene of which to find the root objects (Default value = None)

    Returns:
      : list(bpy.types.Object) -- root objects of the scene

    """
    if not scene:
        scene = bpy.context.scene

    roots = [obj for obj in scene.objects if isRoot(obj, scene=scene)]
    if roots is None:
        log("No root objects found in scene {}.".format(scene), 'WARNING')
    else:
        rootnames = ', '.join((root.name for root in roots))
        log(
            "Found {} root object{} in scene {}: {}".format(
                len(roots), 's' if len(roots) > 1 else '', scene, rootnames
            ),
            'DEBUG',
        )
    return roots
Beispiel #8
0
def calculateSum(objects, numeric_prop):
    """Returns sum of *numeric_prop* in *objects*.

    Args:
      objects(list(bpy.types.Object): objects to sum up the property for
      numeric_prop(str): name of the custom property to sum

    Returns:
      : float/int -- sum of the values in the property of the objects

    """
    numsum = 0
    for obj in objects:
        try:
            numsum += obj[numeric_prop]
        except KeyError:
            log(
                "{0} object {1} does not contain '{2}'".format(
                    obj.phobostype, obj.name, numeric_prop
                ),
                "WARNING",
            )
        except TypeError:
            import phobos.utils.naming as nUtils

            log(
                "Could not add this type to the sum: "
                + str(type(obj[numeric_prop]))
                + " @"
                + nUtils.getObjectName(obj),
                'WARNING',
            )
    return numsum
Beispiel #9
0
def smoothen_surface(obj):
    """Applies various steps to make the specified object look clean and smooth.

    Args:
      obj(bpy.types.Object): object to make look clean

    Returns:

    """
    bpy.context.scene.objects.active = obj

    # recalculate surface normals
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.mesh.normals_make_consistent()
    bpy.ops.mesh.mark_sharp(clear=True)
    bpy.ops.object.mode_set(mode='OBJECT')

    # add smooth shading
    bpy.ops.object.shade_smooth()

    # use edge split modifier to improve the look of CAD-models
    for mod in obj.modifiers:
        if mod.type == 'EDGE_SPLIT':
            log("Edge split modifier already added to object {}.".format(obj.name), 'DEBUG')
            break
    else:
        bpy.ops.object.modifier_add(type='EDGE_SPLIT')
Beispiel #10
0
def importBlenderModel(filepath, namespace='', prefix=False):
    """Imports an existing Blender model into the current .blend scene

    Args:
      filepath(str): Path of the .blend file
      namespace: (Default value = '')
      prefix: (Default value = False)

    Returns:

    """
    if os.path.exists(filepath) and os.path.isfile(filepath) and filepath.endswith('.blend'):
        log("Importing Blender model" + filepath, "INFO")
        objects = []
        with bpy.data.libraries.load(filepath) as (data_from, data_to):
            for objname in data_from.objects:
                objects.append({'name': objname})
        bpy.ops.wm.append(directory=filepath + "/Object/", files=objects)
        imported_objects = bpy.context.selected_objects
        resources = [obj for obj in imported_objects if obj.name.startswith('resource::')]
        new_objects = [obj for obj in imported_objects if not obj.name.startswith('resource::')]
        if resources:
            if 'resources' not in bpy.data.scenes.keys():
                bpy.data.scenes.new('resources')
            sUtils.selectObjects(resources)
            bpy.ops.object.make_links_scene(scene='resources')
            bpy.ops.object.delete(use_global=False)
            sUtils.selectObjects(new_objects)
        bpy.ops.view3d.view_selected(use_all_regions=False)
        # allow the use of both prefixes and namespaces, thus truly merging
        # models or keeping them separate for export
        if namespace != '':
            if prefix:
                for obj in bpy.context.selected_objects:
                    # set prefix instead of namespace
                    obj.name = namespace + '__' + obj.name
                    # make sure no internal name-properties remain
                    for key in obj.keys():
                        try:
                            if obj[key].endswidth("/name"):
                                del obj[key]
                        except AttributeError:  # prevent exceptions from non-string properties
                            pass
            else:
                for obj in bpy.context.selected_objects:
                    nUtils.addNamespace(obj, namespace)
        submechanism_roots = [
            obj
            for obj in bpy.data.objects
            if obj.phobostype == 'link' and 'submechanism/spanningtree' in obj
        ]
        for root in submechanism_roots:
            partlist = [root] + root['submechanism/spanningtree']
            if 'submechanism/freeloader' in root:
                partlist += root['submechanism/freeloader']
            sUtils.selectObjects(partlist, active=0)
            bpy.ops.group.create(name='submechanism:' + root['submechanism/name'])
        return True
    else:
        return False
Beispiel #11
0
def getProperties(obj, category=None):
    """Returns a dictionary of custom property information of the object.
    
    If a category is provided, only the custom properties of the specified category are returned.
    Otherwise, the phobostype of the object will be used as category.
    
    The dictionary contains the custom property keys with the category removed (e.g. 'name' for
    'link/name').

    Args:
      obj(bpy.types.Object): object to get properties of
      category(str, optional): property category to look for (Default value = None)

    Returns:
      : dict -- custom property information of the phobostype/category for the object

    """
    if not category:
        category = obj.phobostype
    try:
        diction = {
            key.replace(category + '/', ''): value
            for key, value in obj.items()
            if key.startswith(category + '/')
        }
    except KeyError:
        log("Failed filtering properties for category " + category, "ERROR")
    return diction
Beispiel #12
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        if self.complete:
            roots = set([sUtils.getRoot(obj) for obj in context.selected_objects]) - {None}
            objects = set()
            for root in roots:
                objects = objects | set(sUtils.getChildren(root))
            objlist = list(objects)
        else:
            objlist = [bpy.context.active_object]
        for obj in objlist:
            try:
                entityname = sUtils.getRoot(obj)['entity/name']
            except (KeyError, TypeError):
                entityname = ''
                log(nUtils.getObjectName(obj) + " is not part of a well-defined entity.", "WARNING")
            namespace = self.namespace if self.namespace else entityname
            nUtils.toggleNamespace(obj, namespace)
        return {'FINISHED'}
Beispiel #13
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)
Beispiel #14
0
def deriveController(obj):
    """

    Args:
      obj: 

    Returns:

    """
    import phobos.model.models as models

    props = models.initObjectProperties(obj, phobostype='controller')

    # return None if no controller is found (there will always be at least a name in the props)
    if len(props) < 2:
        return None

    if not obj.parent or obj.parent.phobostype not in defs.controllabletypes:
        log(
            (
                "Can not derive controller from {}. "
                + "Insufficient requirements from parent object!"
            ).format(obj.name),
            'ERROR',
        )
        return None

    props['target'] = nUtils.getObjectName(obj.parent)
    log(
        "  Derived controller '{}' for target '{}'.".format(props['name'], props['target']), 'DEBUG'
    )

    return props
Beispiel #15
0
def assignMaterial(obj, materialname):
    """Assigns a material by name to an object.
    
    This avoids creating multiple copies and also omits duplicate material slots in the specified
    object.

    Args:
      obj(bpy.types.Object): The object to assign the material to.
      materialname(str): name of the material

    Returns:

    """
    if materialname not in bpy.data.materials:
        if materialname in defs.definitions['materials']:
            createPhobosMaterials()
        else:
            log("Material '" + materialname + "' is not defined.", "ERROR")
            return None

    # add material slot never twice
    if materialname not in obj.data.materials:
        obj.data.materials.append(bpy.data.materials[materialname])

    if obj.data.materials[materialname].use_transparency:
        obj.show_transparent = True
Beispiel #16
0
def exportSMURFScene(entities, path):
    """Exports an arranged scene into SMURFS. It will export only entities
    with a valid entity/name, and entity/type property.

    Args:
      selected_only(bool): If True only selected entities get exported.
      subfolder(bool): If True the models are exported into separate subfolders
      entities: 
      path: 

    Returns:

    """
    log("Exporting scene to " + path + '.smurfs', "INFO")
    with open(path + '.smurfs', 'w') as outputfile:
        sceneinfo = (
            "# SMURF scene created at "
            + path
            + " "
            + datetime.now().strftime("%Y%m%d_%H:%M")
            + "\n"
        )
        log(sceneinfo, "INFO")
        sceneinfo += "# created with Phobos " + version + " - " + repository + "\n\n"
        ioUtils.securepath(path)
        outputfile.write(sceneinfo)
        entitiesdict = roundFloatsInDict(
            {'entities': entities}, ioUtils.getExpSettings().decimalPlaces
        )
        outputfile.write(yaml.dump(entitiesdict))
Beispiel #17
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
Beispiel #18
0
def exportSubmechanisms(model, path):
    """This function exports the submechanisms contained in a robot model.

    Args:
      model(dict): The robot model to export
      path(str): The filepath to export the submechanisms data to

    Returns:

    """
    log("Phobos Submechanisms export: Creating submechanisms data at " + path, "INFO")
    for submechanism in model['submechanisms']:
        root = sUtils.getObjectByProperty('submechanism/name', submechanism['contextual_name'])
        linkobjs = [root] + root['submechanism/spanningtree']
        if 'submechanism/freeloader' in root:
            linkobjs += root['submechanism/freeloader']

        objects = [
            o
            for link in linkobjs
            for o in link.children
            if o.phobostype in ['visual', 'collision', 'inertial']
        ] + linkobjs
        model = deriveModelDictionary(root, root['submechanism/name'], objects)
        jointname = nUtils.getObjectName(root, 'joint')
        if jointname in model['joints']:
            del model['joints'][jointname]
            log('Removed joint which is not part of submodel: ' + jointname, 'DEBUG')
        exportModel(model, path, ['urdf'])
Beispiel #19
0
def createPreview(objects, export_path, modelname, render_resolution=256, opengl=False):
    """Creates a thumbnail of the given objects.

    Args:
      objects(list of bpy.types.Object): list of objects for the thumbnail
      export_path(str): folder to export image to
      modelname(str): name of model (used as file name)
      render_resolution(int, optional): side length of resulting image in pixels (Default value = 256)
      opengl(bool, optional): whether to use opengl rendering or not (Default value = False)

    Returns:

    """
    log("Creating thumbnail of model: " + modelname, "INFO")

    # render presets
    bpy.context.scene.render.image_settings.file_format = 'PNG'
    bpy.context.scene.render.resolution_x = render_resolution
    bpy.context.scene.render.resolution_y = render_resolution
    bpy.context.scene.render.resolution_percentage = 100

    # hide everything that is not supposed to show
    for ob in bpy.data.objects:
        if not (ob in objects):
            ob.hide_render = True
            ob.hide = True

    # render the preview
    if opengl:  # use the viewport representation to create preview
        bpy.ops.view3d.view_selected()
        bpy.ops.render.opengl(view_context=True)
    else:  # use real rendering
        # create camera
        bpy.ops.object.camera_add(view_align=True)
        cam = bpy.context.scene.objects.active
        bpy.data.cameras[cam.data.name].type = 'ORTHO'
        bpy.data.scenes[0].camera = cam  # set camera as active camera

        sUtils.selectObjects(objects, True, 0)
        bpy.ops.view3d.camera_to_view_selected()
        # create light
        bpy.ops.object.lamp_add(type='SUN', radius=1)
        light = bpy.context.scene.objects.active
        light.matrix_world = cam.matrix_world
        # set background
        oldcolor = bpy.data.worlds[0].horizon_color.copy()
        bpy.data.worlds[0].horizon_color = mathutils.Color((1.0, 1.0, 1.0))
        bpy.ops.render.render()
        bpy.data.worlds[0].horizon_color = oldcolor
        sUtils.selectObjects([cam, light], True, 0)
        bpy.ops.object.delete()

    # safe render and reset the scene
    log("Saving model preview to: " + os.path.join(export_path, modelname + '.png'), "INFO")
    bpy.data.images['Render Result'].save_render(os.path.join(export_path, modelname + '.png'))

    # make all objects visible again
    for ob in bpy.data.objects:
        ob.hide_render = False
        ob.hide = False
Beispiel #20
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        wm = context.window_manager
        # FIXME: the following is a hack to fix the problem mentioned at the top
        if not model_data:
            compileModelList()
        filepath = os.path.join(
            model_data[wm.category][wm.modelpreview]['path'], 'blender', wm.modelpreview + '.blend'
        )
        if ioUtils.importBlenderModel(filepath, self.namespace, self.use_prefix):
            return {'FINISHED'}
        else:
            log(
                "Model " + wm.modelpreview + " could not be loaded from library:"
                "No valid .blend file.",
                "ERROR",
            )
            return {'CANCELLED'}
Beispiel #21
0
    def draw(self, context):
        """

        Args:
          context: 

        Returns:

        """
        layout = self.layout
        if self.asObject:
            layout.prop(
                self, 'asObject', text='add annotations as object(s)', icon='FORCE_LENNARDJONES'
            )
        else:
            layout.prop(self, 'asObject', text='add annotations to object', icon='REC')
        layout.separator()

        layout.prop(self, 'annotationtype')

        if self.annotationcategories == 'None':
            layout.label('No categories available.')
        else:
            layout.prop(self, 'annotationcategories')

        # hide devicetype property when empty
        if self.devicetype == 'None':
            layout.label('No devices defined.')
            return

        layout.prop(self, 'devicetype')
        data = defs.definitions[self.annotationtype][self.devicetype]

        hidden_props = ['general']
        # identify the property type for all the stuff in the definition
        self.annotation_data.clear()
        unsupported = DynamicProperty.assignDict(
            self.annotation_data.add, data, ignore=hidden_props
        )

        # expose the parameters as the right Property
        if self.annotation_data:
            box = layout.box()
            for i in range(len(self.annotation_data)):
                name = self.annotation_data[i].name[2:].replace('_', ' ')

                # use the dynamic props name in the GUI, but without the type id
                self.annotation_data[i].draw(box, name)

            # add unsupported stuff as labels
            for item in unsupported:
                box.label(item, icon='ERROR')

        if unsupported:
            log(
                "These properties are not supported for generic editing: " + str(list(unsupported)),
                'DEBUG',
            )
Beispiel #22
0
def deriveEntity(root, outpath):
    """Derives the dictionary for a SMURF entity from the phobos model dictionary.
    
    # TODO savetosubfolder is not a parameter

    Args:
      root(bpy.types.Object): The smurf root object.
      outpath(str): The path to export the smurf to.
      savetosubfolder(bool): If True the export path has a subfolder for this smurf entity.

    Returns:
      : dict - An entry for the scenes entitiesList

    """
    entitypose = models.deriveObjectPose(root)
    entity = models.initObjectProperties(root, 'entity', ['link', 'joint', 'motor'])
    if 'parent' not in entity and 'joint/type' in root and root['joint/type'] == 'fixed':
        entity['parent'] = 'world'
    entity["position"] = entitypose["translation"]
    entity["rotation"] = entitypose["rotation_quaternion"]

    # check model data if entity is a reference
    # FIXME: this part is broken but not used at the moment anyways
    if "isReference" in entity:
        entity.pop("isReference")
        bpy.ops.scene.reload_models_and_poses_operator()
        modelsPosesColl = bUtils.getPhobosPreferences().models_poses
        for robot_model in modelsPosesColl:
            if (root["model/name"] == robot_model.robot_name) and (
                root["entity/pose"] == robot_model.label
            ):
                pass
        entity['file'] = os.path.join(
            os.path.relpath(robot_model.path, outpath), root["name"] + ".smurf"
        )
        """
        with open(os.path.join(os.path.dirname(defs.__file__), "RobotLib.yml"), "r") as f:
            robots = yaml.load(f.read())
            sourcepath = robots[smurf["model/name"]]
            for filename in os.listdir(sourcepath):
                fullpath = os.path.join(sourcepath, filename)
                if os.path.isfile(fullpath):
                    shutil.copy2(fullpath, os.path.join(smurf_outpath, filename))
                else:
                    # remove old folders to prevent errors in copytree
                    shutil.rmtree(os.path.join(smurf_outpath, filename), True)
                    shutil.copytree(fullpath, os.path.join(smurf_outpath, filename))
        """
    else:
        modelpath = os.path.join(outpath, root['model/name'], 'smurf')
        # TODO why the spacing between the paths?
        log("Scene paths: " + outpath + ' ' + modelpath, "DEBUG")
        entity['file'] = os.path.join(
            os.path.relpath(modelpath, os.path.dirname(outpath)), root['model/name'] + ".smurf"
        )
    return entity
Beispiel #23
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
Beispiel #24
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        # identify all entities' roots in the scene
        rootobjects = ioUtils.getEntityRoots()
        if not rootobjects:
            log("There are no entities to export!", "WARNING")

        # derive entities and export if necessary
        models = set()
        for root in entities:
            log("Adding entity '" + str(root["entity/name"]) + "' to scene.", "INFO")
            if root["entity/type"] in entity_types:
                # TODO delete me?
                # try:
                if (
                    self.exportModels
                    and 'export' in entity_types[root['entity/type']]
                    and root['model/name'] not in models
                ):
                    modelpath = os.path.join(
                        ioUtils.getExportPath(), self.sceneName, root['model/name']
                    )
                    exportModel(models.deriveModelDictionary(root), modelpath)
                    models.add(root['model/name'])
                # known entity export
                entity = entity_types[root["entity/type"]]['derive'](
                    root, os.path.join(ioUtils.getExportPath(), self.sceneName)
                )
                # TODO delete me?
                # except KeyError:
                #    log("Required method ""deriveEntity"" not implemented for type " + entity["entity/type"], "ERROR")
                #    continue
            # generic entity export
            else:
                entity = deriveGenericEntity(root)
            exportlist.append(entity)
        for scenetype in scene_types:
            typename = "export_scene_" + scenetype
            # check if format exists and should be exported
            if getattr(bpy.context.scene, typename):
                scene_types[scenetype]['export'](
                    exportlist, os.path.join(ioUtils.getExportPath(), self.sceneName)
                )
        return {'FINISHED'}
Beispiel #25
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        log("Import robot bake", "INFO")
        modelsPosesColl = bUtils.getPhobosPreferences().models_poses
        activeModelPoseIndex = bpy.context.scene.active_ModelPose
        selected_robot = modelsPosesColl[bpy.data.images[activeModelPoseIndex].name]
        if selected_robot.type != "robot_name":
            if os.path.splitext(selected_robot.model_file)[-1] == ".obj":
                bpy.ops.import_scene.obj(
                    filepath=selected_robot.model_file,
                    axis_forward='-Z',
                    axis_up='Y',
                    filter_glob="*.obj;*.mtl",
                    use_edges=True,
                    use_smooth_groups=True,
                    use_split_objects=True,
                    use_split_groups=True,
                    use_groups_as_vgroups=False,
                    use_image_search=True,
                    split_mode='ON',
                    global_clamp_size=0,
                )
            elif os.path.splitext(selected_robot.model_file)[-1] == ".stl":
                bpy.ops.import_mesh.stl(
                    filepath=selected_robot.model_file,
                    axis_forward='Y',
                    axis_up='Z',
                    filter_glob="*.stl",
                    files=[],
                    directory="",
                    global_scale=1,
                    use_scene_unit=True,
                    use_facet_normal=False,
                )
            robot_obj = bpy.context.selected_objects[0]
            bpy.context.scene.objects.active = robot_obj
            robot_obj.name = self.obj_name
            robot_obj["model/name"] = selected_robot.robot_name
            robot_obj["entity/name"] = self.obj_name
            robot_obj["entity/type"] = "smurf"
            robot_obj["entity/pose"] = selected_robot.label
            robot_obj["entity/isReference"] = True
            robot_obj.phobostype = 'entity'
        return {'FINISHED'}
Beispiel #26
0
def cloneGit(name, url, destination):
    """Clones the git repository which is specified by its url into the folder
    with the specified name in the destination folder. If the url provides the
    https:// start, it might be necessary to enter gituser and password into
    commandline, so better use the git@git start.
    If the destination folder is a git already, it will not be cloned, but True
    will be returned.
    If the destination folder does not exist, it is created on the fly.

    Args:
      name: 
      url: 
      destination: 

    Returns:

    """
    # check for existing git first
    try:
        if isGit(os.path.join(destination, name)):
            if not os.path.exists(os.path.join(destination, name, '.git', 'config')):
                log('Git folder found, but the config seems corrupted. Cloning aborted.', 'ERROR')
                return False
            # compare the git url with the existing git folder
            with open(os.path.join(destination, name, '.git', 'config'), 'r') as gitconfigfile:
                if url in gitconfigfile.read():
                    log('Git already cloned.', 'INFO')
                    return True
                log('Git folder found, but with different url. Cloning aborted.', 'ERROR')
                return False
    except subprocess.CalledProcessError:
        pass

    # if there is no destination folder, create it
    if not os.path.exists(destination):
        os.makedirs(destination)

    # clone git if not existing already
    try:
        subprocess.check_output(
            ['git', 'clone', url, name], cwd=destination, universal_newlines=True
        )
        log("Cloned git into " + destination + ".", "INFO")
        return True
    except subprocess.CalledProcessError:
        log(
            "Problem cloning git repository. Destination is either not empty or remote is incorrect.",
            "ERROR",
        )
    return False
Beispiel #27
0
def getMechanismListForEnumProperty(self, context):
    """Returns a list of (str, str, str) elements which contains the mechanisms
    currently loaded. If there are none, returns ('-', '-', '-').

    Args:
      context: 

    Returns:

    """
    try:
        return sorted(mechanismpreviewcollection.enum_items)
    except AttributeError:
        log('No mechanism previews available. Check config folder.', 'ERROR')
Beispiel #28
0
def openScriptInEditor(scriptname):
    """This function opens a script/textfile in an open blender text window. Nothing happens if there is no
    available text window.

    Args:
      scriptname(str): The scripts name.

    Returns:

    """
    if scriptname in bpy.data.texts:
        for area in bpy.context.screen.areas:
            if area.type == 'TEXT_EDITOR':
                area.spaces.active.text = bpy.data.texts[scriptname]
    else:
        log("There is no script named " + scriptname + "!", "ERROR")
Beispiel #29
0
def datetimeFromIso(iso):
    """Accepts a date-time string in ISO format and returns a datetime object.

    Args:
      iso(str): ISO format string for a date and time

    Returns:
      : datetime.datetime -- datetime object from the specified string

    """
    try:
        dtime = datetime(*[int(a) for a in re.split(":|-|T| |\.", iso)])
        return dtime
    except ValueError as error:
        log("Could not convert ISO string: " + str(error), "ERROR")
        return datetime.now()
Beispiel #30
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        log("Importing " + self.filepath + ' as ' + self.entitytype, "INFO")
        model = entity_io.entity_types[self.entitytype]['import'](self.filepath)
        # bUtils.cleanScene()
        models.buildModelFromDictionary(model)
        for layer in ['link', 'inertial', 'visual', 'collision', 'sensor']:
            bUtils.toggleLayer(defs.layerTypes[layer], True)
        return {'FINISHED'}
Beispiel #31
0
def deriveChainEntry(obj):
    """Derives a phobos dict entry for a kinematic chain ending in the provided object.

    :param obj:
    :return:
    """
    returnchains = []
    if 'endChain' in obj:
        chainlist = obj['endChain']
    for chainName in chainlist:
        chainclosed = False
        parent = obj
        chain = {
            'name': chainName,
            'start': '',
            'end': nUtils.getObjectName(obj),
            'elements': []
        }
        while not chainclosed:
            # FIXME: use effectiveParent
            if parent.parent is None:
                log("Unclosed chain, aborting parsing chain " + chainName,
                    "ERROR")
                chain = None
                break
            chain['elements'].append(parent.name)
            # FIXME: use effectiveParent
            parent = parent.parent
            if 'startChain' in parent:
                startchain = parent['startChain']
                if chainName in startchain:
                    chain['start'] = nUtils.getObjectName(parent)
                    chain['elements'].append(nUtils.getObjectName(parent))
                    chainclosed = True
        if chain is not None:
            returnchains.append(chain)
    return returnchains
Beispiel #32
0
    def execute(self, context):
        # identify all entities' roots in the scene
        rootobjects = ioUtils.getEntityRoots()
        if not rootobjects:
            log("There are no entities to export!", "WARNING")

        # derive entities and export if necessary
        modellist = []
        for root in rootobjects:
            log("Adding entity '" + str(root["entity/name"]) + "' to scene.", "INFO")
            if root["entity/type"] in entity_types:
                # TODO delete me?
                # try:
                if (self.exportModels and
                        'export' in entity_types[root['entity/type']] and
                        root['modelname'] not in models):
                    modelpath = os.path.join(ioUtils.getExportPath(), self.sceneName, root['modelname'])
                    exportModel(models.deriveModelDictionary(root), modelpath)
                    models.add(root['modelname'])
                # known entity export
                entity = entity_types[root["entity/type"]]['derive'](root,
                                                                     os.path.join(ioUtils.getExportPath(), self.sceneName))
                # TODO delete me?
                # except KeyError:
                #    log("Required method ""deriveEntity"" not implemented for type " + entity["entity/type"], "ERROR")
                #    continue
            # generic entity export
            else:
                entity = deriveGenericEntity(root)
            exportlist.append(entity)
        for scenetype in scene_types:
            typename = "export_scene_" + scenetype
            # check if format exists and should be exported
            if getattr(bpy.context.scene, typename):
                scene_types[scenetype]['export'](exportlist, os.path.join(
                    ioUtils.getExportPath(), self.sceneName))
        return {'FINISHED'}
Beispiel #33
0
def deriveVisual(obj):
    """This function derives the visual information from an object.

    :param obj: The blender object to derive the visuals from.
    :type obj: bpy_types.Object
    :return: dict

    """
    try:
        visual = initObjectProperties(obj,
                                      phobostype='visual',
                                      ignoretypes='geometry')
        visual['geometry'] = deriveGeometry(obj)
        visual['pose'] = deriveObjectPose(obj)
        if obj.lod_levels:
            if 'lodmaxdistances' in obj:
                maxdlist = obj['lodmaxdistances']
            else:
                maxdlist = [
                    obj.lod_levels[i + 1].distance
                    for i in range(len(obj.lod_levels) - 1)
                ] + [100.0]
            lodlist = []
            for i in range(len(obj.lod_levels)):
                filename = obj.lod_levels[
                    i].object.data.name + ioUtils.getOutputMeshtype()
                lodlist.append({
                    'start': obj.lod_levels[i].distance,
                    'end': maxdlist[i],
                    'filename': os.path.join('meshes', filename)
                })
            visual['lod'] = lodlist
    except KeyError:
        log("Missing data in visual object " + obj.name, "ERROR",
            "deriveVisual")
        return None
    return visual
Beispiel #34
0
def deriveSensor(obj, names=False, objectlist=[], logging=False):
    """This function derives a sensor from a given blender object

    Args:
      obj(bpy_types.Object): The blender object to derive the sensor from.
      names(bool, optional): return the link object name instead of an object link. (Default value = False)
      objectlist(list(bpy.types.Object, optional): objectlist to which possible parents are restricted (Default value = [])
      logging(bool, optional): whether to write log messages or not (Default value = False)

    Returns:
      : dict -- phobos representation of the sensor

    """
    from phobos.model.models import initObjectProperties

    if logging:
        log(
            "Deriving sensor from object " +
            nUtils.getObjectName(obj, phobostype='sensor') + ".",
            'DEBUG',
        )
    try:
        props = initObjectProperties(obj,
                                     phobostype='sensor',
                                     ignoretypes=('pose'))
        if names:
            props['link'] = nUtils.getObjectName(sUtils.getEffectiveParent(
                obj, objectlist=objectlist),
                                                 phobostype='link')
        else:
            props['link'] = sUtils.getEffectiveParent(obj,
                                                      objectlist=objectlist)
    except KeyError:
        if logging:
            log("Missing data in sensor " + obj.name, "ERROR")
        return None
    return props
Beispiel #35
0
def deriveGeometry(obj):
    """This function derives the geometry from an object.

    Args:
      obj(bpy_types.Object): The blender object to derive the geometry from.

    Returns:
      dict

    """
    try:
        geometry = {'type': obj['geometry/type']}
        gt = obj['geometry/type']
        if gt == 'box':
            geometry['size'] = list(obj.dimensions)
        elif gt == 'cylinder' or gt == 'capsule':
            geometry['radius'] = obj.dimensions[0]/2
            geometry['length'] = obj.dimensions[2]
        elif gt == 'capsule':
            geometry['radius'] = obj.dimensions[0]/2
            geometry['length'] = obj.dimensions[2] - obj.dimensions[0]
        elif gt == 'sphere':
            geometry['radius'] = obj.dimensions[0]/2
        elif gt == 'mesh':
            geometry['filename'] = obj.data.name
            geometry['scale'] = list(obj.scale)
            # FIXME: is this needed to calculate an approximate inertia
            geometry['size'] = list(obj.dimensions)
        # any other geometry type, i.e. 'plane'
        else:
            geometry['size'] = list(obj.dimensions)
        return geometry
    except KeyError as err:
        log("Undefined geometry for object " + nUtils.getObjectName(obj) +
            " " + str(err), "ERROR")
        return None
Beispiel #36
0
def getRoots(scene=None):
    """Returns a list of all of the current/specified scene's root objects.

    Args:
      scene(bpy.types.Scene, optional): the scene of which to find the root objects (Default value = None)

    Returns:
      : list(bpy.types.Object) -- root objects of the scene

    """
    if not scene:
        scene = bpy.context.scene

    roots = [obj for obj in scene.objects if isRoot(obj, scene=scene)]
    if roots is None:
        log("No root objects found in scene {}.".format(scene), 'WARNING')
    else:
        rootnames = ', '.join((root.name for root in roots))
        log(
            "Found {} root object{} in scene {}: {}".format(
                len(roots), 's' if len(roots) > 1 else '', scene, rootnames),
            'DEBUG',
        )
    return roots
Beispiel #37
0
def updateDefs(defsFolderPath):
    """Updates the definitions with all yml files in the given folder

    Args:
      defsFolderPath(str): The path to the folder with the definitions yaml files.

    Returns:

    """
    dicts = __parseAllYAML(defsFolderPath)
    for diction in dicts:
        for category in diction:
            for key, value in diction[category].items():
                if category not in definitions:
                    definitions[category] = {}
                if key in definitions[category]:
                    log(
                        "Entry for " + category + '/' + key +
                        " will be overwritten while parsing definitions.",
                        "WARNING")
                definitions[category][key] = value
    # Extending model definition
    definitions['model']['sensors']['$forElem'][
        '$selection__type'] = definitions['sensors']
Beispiel #38
0
    def getSubmechanisms(link):
        """

        Args:
          link: 

        Returns:

        """
        if 'submechanism/name' in link.keys():
            submech = {
                'type': link['submechanism/type'],
                'contextual_name': link['submechanism/name'],
                'name': link['submechanism/subtype']
                if 'submechanism/subtype' in link
                else link['submechanism/type'],
                'jointnames_independent': [
                    nUtils.getObjectName(j, 'joint') for j in link['submechanism/independent']
                ],
                'jointnames_spanningtree': [
                    nUtils.getObjectName(j, 'joint') for j in link['submechanism/spanningtree']
                ],
                'jointnames_active': [
                    nUtils.getObjectName(j, 'joint') for j in link['submechanism/active']
                ],
                # TODO: this should work in almost all cases, still a bit of a hack:
                'file_path': '../submechanisms/urdf/' + link['submechanism/name'] + '.urdf',
            }
            log('    ' + submech['contextual_name'], 'DEBUG')
        else:
            submech = None
        mechanisms = [submech] if submech else []
        for c in link.children:
            if c.phobostype in ['link', 'interface'] and c in objectlist:
                mechanisms.extend(getSubmechanisms(c))
        return mechanisms
Beispiel #39
0
def deriveTextData(modelname):
    """Collect additional data stored for a specific model.

    Args:
      modelname: Name of the model for which data should be derived.

    Returns:
      : A dictionary containing additional data.

    """
    datadict = {}
    datatextfiles = [text for text in bpy.data.texts if text.name.startswith(modelname + '::')]
    for text in datatextfiles:
        try:
            dataname = text.name.split('::')[-1]
        except IndexError:
            log("Possibly invalidly named model data text file: " + modelname, "WARNING")
        try:
            data = json.loads(bUtils.readTextFile(text.name))
        except:
            log("Invalid formatting of data file: " + dataname, "ERROR")
        if data:
            datadict[dataname] = data
    return datadict
Beispiel #40
0
def retrieve_from_list(alist, prop, value):
    """Returns the first object in a list which has a field named
    *prop* with value *value*. If no such object is found, returns 'None'.

    Args:
      alist: 
      prop: 
      value: 

    Returns:

    """
    n = -1
    for i in range(len(alist)):
        try:
            if alist[i][prop] == value:
                n = i
                break
        except KeyError:
            log("The object at index " + str(i) + " has no property " + str(prop), "ERROR")
    if n >= 0:
        return alist[n][prop]
    else:
        return "None"
Beispiel #41
0
def storePose(root, posename):
    """Stores the current pose of all of a model's selected joints.
    
    Existing poses of the same name will be overwritten.

    Args:
      root(bpy_types.Object): root of the model the pose belongs to
      posename(str): name the pose will be stored under

    Returns:
      : Nothing.

    """
    if root:
        filename = nUtils.getModelName(root) + '::poses'
        posedict = yaml.load(bUtils.readTextFile(filename))
        if not posedict:
            posedict = {posename: {'name': posename, 'joints': {}}}
        else:
            posedict[posename] = {'name': posename, 'joints': {}}
        links = sUtils.getChildren(root, ('link', ), True, False)
        sUtils.selectObjects([root] + links, clear=True, active=0)
        bpy.ops.object.mode_set(mode='POSE')
        for link in (link for link in links if 'joint/type' in link
                     and link['joint/type'] not in ['fixed', 'floating']):
            link.pose.bones['Bone'].rotation_mode = 'XYZ'
            posedict[posename]['joints'][nUtils.getObjectName(
                link, 'joint')] = link.pose.bones['Bone'].rotation_euler.y
        bpy.ops.object.mode_set(mode='OBJECT')
        posedict = gUtils.roundFloatsInDict(
            posedict,
            ioUtils.getExpSettings().decimalPlaces)
        bUtils.updateTextFile(filename,
                              yaml.dump(posedict, default_flow_style=False))
    else:
        log("No model root provided to store the pose for", "ERROR")
Beispiel #42
0
def addNamespace(obj):
    """This function namespaces a given blender object.

    :param obj: The object to namespace.
    :type obj: bpy.types.Object

    """
    types = defs.subtypes
    name = obj.name
    root = selection.getRoot(obj)
    try:
        namespace = root["entity/name"]
        obj.name = namespace + "::" + name
        for ptype in types:
            typetag = ptype + "/type"
            nametag = ptype + "/name"
            if (typetag in obj or
                ("phobostype" in obj
                 and obj.phobostype == ptype)) and nametag not in obj:
                obj[nametag] = name
    except (TypeError, KeyError):
        log(
            getObjectName(obj) + " is not part of a well-defined entity.",
            "ERROR", "utils/naming/addNamespace")
Beispiel #43
0
def exportSubmechanisms(model, path):
    """This function exports the submechanisms contained in a robot model.

    Args:
      model(dict): The robot model to export
      path(str): The filepath to export the submechanisms data to

    Returns:

    """
    log("Phobos Submechanisms export: Creating submechanisms data at " + path,
        "INFO")
    for submechanism in model['submechanisms']:
        root = sUtils.getObjectsByProperty('submechanism/name',
                                           submechanism['contextual_name'])
        linkobjs = [
            root
        ] + root['submechanism/freeloader'] + root['submechanism/spanningtree']
        objects = [
            o for link in linkobjs for o in link.children
            if o.phobostype in ['visual', 'collision', 'inertial']
        ] + linkobjs
        model = deriveModelDictionary(root, root['submechanism/name'], objects)
        exportModel(model, path, ['urdf'])
Beispiel #44
0
def deriveCollision(obj):
    """This function derives the collision information from an object.

    Args:
      obj(bpy_types.Object): The blender object to derive the collision information from.

    Returns:
      dict

    """
    try:
        collision = initObjectProperties(obj,
                                         phobostype='collision',
                                         ignoretypes='geometry')
        collision['geometry'] = deriveGeometry(obj)
        collision['pose'] = deriveObjectPose(obj)
        # the bitmask is cut to length = 16 and reverted for int parsing
        try:
            collision['bitmask'] = int(
                ''.join([
                    '1' if group else '0'
                    for group in obj.rigid_body.collision_groups[:16]
                ])[::-1], 2)
            for group in obj.rigid_body.collision_groups[16:]:
                if group:
                    log((
                        'Object {0} is on a collision layer higher than ' +
                        '16. These layers are ignored when exporting.').format(
                            obj.name), "WARNING")
                    break
        except AttributeError:
            pass
    except KeyError:
        log("Missing data in collision object " + obj.name, "ERROR")
        return None
    return collision
Beispiel #45
0
def createJoint(joint, linkobj=None):
    """Adds joint data to 'link' object.

    Args:
        joint (dict): dictionary containing the joint definition
        linkobj (bpy.types.Object): the obj of phobostype 'link' that receives the joint

    Returns:

    """
    # add joint information
    if not linkobj:
        linkobj = sUtils.getObjectByName(joint['child'])
        if isinstance(linkobj, list):
            log(
                "Could not identify object to define joint '{0}'.".format(
                    joint['name']), 'ERROR')
            return
    if joint['name'] != linkobj.name:
        linkobj['joint/name'] = joint['name']
    # get hold of object
    bUtils.toggleLayer(list(linkobj.layers).index(True),
                       True)  # any layer containing the object
    sUtils.selectObjects([linkobj], clear=True, active=0)

    # set axis
    if 'axis' in joint:
        if mathutils.Vector(tuple(joint['axis'])).length == 0.:
            log('Axis of joint {0} is of zero length: '.format(joint['name']),
                'ERROR')
        else:
            bpy.ops.object.mode_set(mode='EDIT')
            editbone = linkobj.data.edit_bones[0]
            length = editbone.length
            axis = mathutils.Vector(tuple(joint['axis']))
            editbone.tail = editbone.head + axis.normalized() * length

    # add constraints
    for param in ['effort', 'velocity']:
        try:
            if 'limits' in joint:
                linkobj['joint/max' + param] = joint['limits'][param]
        except KeyError:
            log("Joint limits incomplete for joint {0}".format(joint['name']),
                'ERROR')
    try:
        lower = joint['limits']['lower']
        upper = joint['limits']['upper']
    except KeyError:
        lower = 0.0
        upper = 0.0
    setJointConstraints(linkobj, joint['type'], lower, upper)
    for prop in joint:
        if prop.startswith('$'):
            for tag in joint[prop]:
                linkobj['joint/' + prop[1:] + '/' + tag] = joint[prop][tag]
Beispiel #46
0
def deriveGenericEntity(entityobj, outpath=None):
    """This function handles an entity of unknown type by simply exporting its custom properties.

    Args:
      entityobj(bpy.types.Object): The object representing the entity.
      outpath(str, optional): If True data will be exported into subfolders. (Default value = None)

    Returns:
      : dict - An entry for the scenes entitiesList

    """
    log(
        "Exporting " + nUtils.getObjectName(entityobj, 'entity') +
        " as entity of type 'generic",
        "INFO",
    )
    entity = models.initObjectProperties(entityobj, 'entity', ['geometry'])
    return entity

    # write urdf
    urdf_path = "../urdf/" if structured else ''
    urdf_filename = model['name'] + ".urdf"
    exportModelToURDF(model, os.path.join(path, urdf_path, urdf_filename),
                      '../meshes/' if structured else '')
Beispiel #47
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)
Beispiel #48
0
    def execute(self, context):
        roots = ioUtils.getExportModels()
        if not roots:
            log("No properly defined models selected or present in scene.", 'ERROR')
            return {'CANCELLED'}
        elif not self.exportall:
            roots = [root for root in roots if nUtils.getModelName(root) == self.modelname]
            if len(roots) > 1:
                log("Ambiguous model definitions: " + self.modelname + " exists "
                    + str(len(roots)) + " times.", "ERROR")
                return {'CANCELLED'}

        for root in roots:
            # setup paths
            exportpath = ioUtils.getExportPath()
            if not securepath(exportpath):
                log("Could not secure path to export to.", "ERROR")
                continue
            log("Export path: " + exportpath, "DEBUG")
            ioUtils.exportModel(models.deriveModelDictionary(root), exportpath)

        # select all exported models after export is done
        if ioUtils.getExpSettings().selectedOnly:
            for root in roots:
                objectlist = sUtils.getChildren(
                    root, selected_only=True, include_hidden=False)
                sUtils.selectObjects(objectlist, clear=False)
        else:
            bpy.ops.object.select_all(action='DESELECT')
            for root in roots:
                sUtils.selectObjects(list([root]), False)
            bpy.ops.phobos.select_model()

        # report success to user
        log("Export successful.", "INFO")
        return {'FINISHED'}
Beispiel #49
0
def compileMechanismList():
    """TODO Missing documentation"""
    from bpy.types import WindowManager
    from bpy.props import EnumProperty

    # DOCU missing some docstring

    global mechanismpreviewcollection

    log("Compiling mechanism list from local library...", "INFO")

    imagefolderpath = os.path.join(bUtils.getPhobosConfigPath(), 'images',
                                   'mechanisms')
    if imagefolderpath == '' or not os.path.exists(imagefolderpath):
        log('Visual mechanism representations could not be found.')
        return

    # read in mechanism thumbnails
    mechanismpreviewcollection = bpy.utils.previews.new()
    enum_items = []
    defaultimagepath = os.path.join(imagefolderpath, 'undefined.png')
    defaultpreview = mechanismpreviewcollection.load('undefined',
                                                     defaultimagepath, 'IMAGE')

    i = 1
    for mechanism in defs.definitions['submechanisms']:
        size = len(defs.definitions['submechanisms'][mechanism]['joints']
                   ['spanningtree'])
        imagepath = os.path.join(imagefolderpath, mechanism + '.png')
        if not (os.path.exists(imagepath) and os.path.isfile(imagepath)):
            log("No preview found, using default.", 'DEBUG')
            enum_items.append((mechanism, mechanism + ' [{0}] '.format(size),
                               "", defaultpreview.icon_id, i))
        else:
            log("Adding mechanism preview: " + imagepath, 'DEBUG')
            preview = mechanismpreviewcollection.load(mechanism, imagepath,
                                                      'IMAGE')
            enum_items.append((mechanism, mechanism + '[ {0}]'.format(size),
                               "", preview.icon_id, i))
        i += 1
    mechanismpreviewcollection.enum_items = enum_items

    # reregister the enumproperty to ensure new items are displayed
    WindowManager.mechanismpreview = EnumProperty(
        items=getMechanismListForEnumProperty, name='Mechanism')
Beispiel #50
0
def fuse_inertia_data(inertials):
    """Computes combined mass, center of mass and inertia given a list of inertial objects.

    If no inertials are found (None, None, None) is returned.

    If successful, the tuple contains this information:
        *mass*: float
        *com*: mathutils.Vector(3)
        *inertia*: mathutils.Matrix(3)

    :param inertials: the alist of objects relevant for the inertia of a link
    :type inertials: list

    :return: tuple of mass, COM and inertia or None(3) if no inertials are found
    :rtype: tuple(3)
    """
    # collect objects which contain inertia
    objects = []
    for inertia_object in inertials:
        objdict = None
        try:
            pose = deriveObjectPose(inertia_object)
            objdict = {'name': inertia_object.name,
                       'mass': inertia_object['mass'],
                       # FIXME: this is not nice, as we invert what is one when deriving the pose
                       'com': mathutils.Vector(pose['translation']),
                       'rot': pose['rawmatrix'].to_3x3(),
                       'inertia': list(inertia_object['inertia'])}
        except KeyError as e:
            log('Inertial object ' + inertia_object.name + ' is missing data: ' + str(e), 'WARNING')
            continue
        if objdict:
            objects.append(objdict)

    # fuse inertias of objects
    if objects:
        log("   Fusing inertials: " + str([i.name for i in inertials]), 'DEBUG')
        mass, com, inertia = compound_inertia_analysis_3x3(objects)
        log("   Fused mass: " + str(mass), 'DEBUG')
        return mass, com, inertia

    log("No inertial found to fuse.", 'DEBUG')
    return None, None, None
Beispiel #51
0
def fuseInertiaData(inertials):
    """Returns mass, center of mass and inertia of a link as a whole, taking a list of inertials.

    *mass*: double
    *com*: mathutils:Vector(3)
    *inertia*: mathutils:Matrix(3)

    :param inertials: The alist of objects relevant for the inertia of a link.
    :type inertials: list
    :return: tuple(3) -- see description for content.

    """
    objects = []
    for o in inertials:
        objdict = None
        try:
            pose = deriveObjectPose(o)
            # FIXME the following is really a short cut that points to a bigger problem
            inertia = o['inertia'] if 'inertia' in o else o['inertial/inertia']
            mass = o['mass'] if 'mass' in o else o['inertial/mass']
            objdict = {
                'name': o.name,
                'mass': mass,
                'com': mathutils.Vector(
                    pose['translation']
                ),  # FIXME: this is not nice, as we invert what is one when deriving the pose
                'rot': pose['rawmatrix'].to_3x3(),
                'inertia': inertia
            }
        except KeyError as e:
            log('Inertial object ' + o.name + ' is missing data: ' + str(e),
                "WARNING", "fuseInertiaData")
        if objdict:
            objects.append(objdict)
    if len(objects) > 0:
        log("Fusing inertials: " + str([i.name for i in inertials]), "DEBUG",
            "fuseInertiaData")
        mass, com, inertia = compound_inertia_analysis_3x3(objects)
        log("Fused mass: " + str(mass), "DEBUG", "fuseInertiaData")
        return mass, com, inertia
    else:
        log("No inertial found to fuse.", "DEBUG", "fuseInertiaData")
        return None, None, None
Beispiel #52
0
def createNewBranch(branch, workingdir):
    if not branch or not workingdir:
        log("No branch specified.", "ERROR")
        return False
    try:
        subprocess.check_output(['git', 'checkout', '-b', branch],
                                cwd=workingdir,
                                universal_newlines=True)
        log("Created branch " + branch + ".", "INFO")
        return True
    except subprocess.CalledProcessError:
        log("Could not create branch " + branch + ".", "ERROR")
        return False
Beispiel #53
0
def checkoutCommit(commit, workingdir):
    # DOCU add some docstring
    if not commit or not workingdir:
        log("No commit specified.", "ERROR")
        return False
    try:
        subprocess.check_output(['git', 'checkout', commit],
                                cwd=workingdir,
                                universal_newlines=True)
        log("Checked out commit " + commit + ".", "INFO")
        return True
    except subprocess.CalledProcessError:
        log("Problem checking out " + commit, "ERROR")
        return False
Beispiel #54
0
def isInertiaDataValid(inertialdict):
    """Returns True if the inertial data to be physical consistent, else False.
    """
    # Check inertia vector for various properties
    inertia = numpy.array(inertiaListToMatrix(inertialdict['inertia']))
    if not all(element >= 0.0 for element in inertia.diagonal()):
        log("Negative semidefinite main diagonal in inertia data!", "WARNING")
        return False
    # Calculate the determinant if consistent
    if numpy.linalg.det(inertia) <= 0.0:
        log("Negative semidefinite determinant in inertia data!", "WARNING")
        return False
    # Calculate the eigenvalues if consistent
    if any(element < 0.0 for element in numpy.linalg.eigvals(inertia)):
        log("Negative semidefinite eigenvalues in inertia data!", "WARNING")
        return False
    return 'mass' in inertialdict and inertialdict['mass'] > 0
Beispiel #55
0
def checkoutBranch(branch, workingdir, create=False, pushorigin=False):
    if not branch or not workingdir:
        log("No branch specified.", "ERROR")
        return False
    try:
        subprocess.check_output(['git', 'fetch'],
                                cwd=workingdir,
                                universal_newlines=True)
        subprocess.check_output(['git', 'checkout', branch],
                                cwd=workingdir,
                                universal_newlines=True)
        log("Checkout branch " + branch + " successful.", "INFO")
        return True
    except subprocess.CalledProcessError:
        if create:
            return createNewBranch(branch, workingdir, pushorigin)
        log("Could not checkout branch " + branch + ".", "ERROR")
        return False
Beispiel #56
0
def commit(destination,
           message='Automated commit',
           ignore=[],
           force_push=True):
    """Commits the current status in the git folder at destination.
    This can ignore the first level subfolders and files specified in the
    optional parameter.

    Args:
      destination: 
      message: (Default value = 'Automated commit')
      ignore: (Default value = [])

    Returns:
      : TODO

    """
    # Add the subfolders and files to git
    # TODO test this functionality
    for direc in os.listdir(destination):
        if direc not in ignore:
            try:
                subprocess.check_output(['git', 'add', direc],
                                        cwd=destination,
                                        universal_newlines=True)
            except subprocess.CalledProcessError:
                log('Could not add to git: ' + direc, 'ERROR')
                return False

    # Commit the changes
    try:
        subprocess.check_output(
            ['git', 'commit', '-m', '"{0}"'.format(message)],
            cwd=destination,
            universal_newlines=True,
        )
        push(destination, force_push=force_push)
        log('Commit to ' + destination + ' successful.', 'DEBUG')
        return True
    except subprocess.CalledProcessError as error:
        log('Could not commit and push: ' + str(error), 'ERROR')
        return False
Beispiel #57
0
def checkInertia(inertia):
    """Checks if the inertia of an object leads to positive definite inertia matrix.

    :param inertia: inertia of the object.
    :type inertia: list, tuple or matrix

    :return: true if inertia matrix is positive definite, false if not
    :rtype: bool
    """
    assert isinstance(
        inertia, (list, tuple, mathutils.Matrix)), ("Wrong inertia type: " +
                                                    type(inertia) + ".")

    consistency = True

    # Convert to matrix if necessary
    if not isinstance(inertia, mathutils.Matrix):
        inertia = numpy.array(inertiaListToMatrix(inertia))

    # Check the main diagonal for strictly positive values
    consistency = all(element >= 0.0 for element in inertia.diagonal())

    if not consistency:
        log("Negative semidefinite main diagonal found!", "WARNING")
        return consistency

    # Calculate the determinant if consistent
    consistency = numpy.linalg.det(inertia) > 0.0

    if not consistency:
        log("Negative semidefinite determinant found!", "WARNING")
        return consistency

    # Calculate the eigenvalues if consistent
    consistency = all(element > 0.0
                      for element in numpy.linalg.eigvals(inertia))

    if not consistency:
        log("Negative semidefinite eigenvalues found!", "WARNING")
    return consistency
Beispiel #58
0
def loadPose(modelname, posename):
    """Load and apply a robot's stored pose.

    Args:
      modelname(str): the model's name
      posename(str): the name the pose is stored under

    Returns:

    """

    load_file = bUtils.readTextFile(modelname + '::poses')
    if load_file == '':
        log('No poses stored.', 'ERROR')
        return

    loadedposes = yaml.load(load_file)
    if posename not in loadedposes:
        log('No pose with name ' + posename + ' stored for model ' + modelname,
            'ERROR')
        return
    prev_mode = bpy.context.mode
    pose = loadedposes[posename]

    # apply rotations to all joints defined by the pose
    try:
        bpy.ops.object.mode_set(mode='POSE')
        for obj in sUtils.getObjectsByPhobostypes(['link']):
            if nUtils.getObjectName(obj, 'joint') in pose['joints']:
                obj.pose.bones['Bone'].rotation_mode = 'XYZ'
                obj.pose.bones['Bone'].rotation_euler.y = float(
                    pose['joints'][nUtils.getObjectName(obj, 'joint')])
    except KeyError as error:
        log("Could not apply the pose: " + str(error), 'ERROR')
    finally:
        # restore previous mode
        bpy.ops.object.mode_set(mode=prev_mode)
Beispiel #59
0
def exportSmurf(model, path):
    """This function exports a given model to a specific path as a smurf representation.

    Args:
      model(dict): The model you want to export.
      path: The path you want to save the smurf file *without file name!*

    Returns:

    """
    collisiondata = deriveRefinedCollisionData(model)
    lodsettings = gatherLevelOfDetailSettings(model)

    exportdata = {
        'state': False,  # model['state'] != {}, # TODO: handle state
        'materials': model['materials'] != {},
        'sensors': model['sensors'] != {},
        'motors': model['motors'] != {},
        'controllers': model['controllers'] != {},
        'collision': collisiondata != {},
        'visuals': lodsettings != {},
        'lights': model['lights'] != {},
        'submechanisms': model['submechanisms'] != [],
    }

    # create all filenames
    smurf_filename = model['name'] + ".smurf"
    filenames = {
        'state': model['name'] + "_state.yml",
        'materials': model['name'] + "_materials.yml",
        'sensors': model['name'] + "_sensors.yml",
        'motors': model['name'] + "_motors.yml",
        'controllers': model['name'] + "_controllers.yml",
        'collision': model['name'] + "_collision.yml",
        'visuals': model['name'] + "_visuals.yml",
        'lights': model['name'] + "_lights.yml",
        'submechanisms': model['name'] + "_submechanisms.yml",
    }
    fileorder = [
        'collision',
        'visuals',
        'materials',
        'motors',
        'sensors',
        'controllers',
        'state',
        'lights',
        'submechanisms',
    ]
    urdf_path = '../urdf/'
    urdf_filename = model['name'] + '.urdf'

    # gather annotations and data from text files
    annotationdict = models.gatherAnnotations(model)

    # $mars annotated properties overwrite custom properties of objects for smurf
    if 'mars' in annotationdict:
        for category in annotationdict['mars']:
            for list_obj in annotationdict['mars'][category]:
                model[category + 's'][list_obj['name']].update(list_obj)
        del annotationdict['mars']

    for category in annotationdict:
        # TODO use os.path?
        if category != 'sdf':
            filenames[category] = model['name'] + '_' + category + '.yml'
            fileorder.append(category)
            exportdata[category] = True

    customdatalist = []
    for text in bpy.data.texts:
        if text.name.startswith(model['name'] + '::'):
            dataname = text.name.split('::')[-1]
            customdatalist.append(dataname)
            # TODO use os.path?
            filenames[dataname] = model['name'] + '_' + dataname + '.yml'
            fileorder.append(dataname)
            exportdata[dataname] = True

    infostring = ' definition SMURF file for "' + model[
        'name'] + '", ' + model["date"] + "\n\n"

    # write model information
    log("Writing SMURF model to " + smurf_filename, "INFO")
    # CHECK are these filepaths failsafe in Windows?
    modeldata = {
        "date":
        model["date"],
        "files": [urdf_path + urdf_filename] +
        [filenames[f] for f in fileorder if exportdata[f]],
    }
    # append custom data
    with open(os.path.join(path, smurf_filename), 'w') as op:
        op.write('# main SMURF file of model "' + model['name'] + '"\n')
        op.write('# created with Phobos ' + defs.version + ' - ' +
                 defs.repository + '\n\n')
        op.write("SMURF version: " + defs.version + "\n")
        op.write("modelname: " + model['name'] + "\n")
        op.write(yaml.dump(modeldata, default_flow_style=False))

    # TODO delete me?
    # #write semantics (SRDF information in YML format)
    # if export['semantics']:
    #     with open(path + filenames['semantics'], 'w') as op:
    #         op.write('#semantics'+infostring)
    #         op.write("modelname: "+model['name']+'\n')
    #         semantics = {}
    #         if model['groups'] != {}:
    #             semantics['groups'] = model['groups']
    #         if model['chains'] != {}:
    #             semantics['chains'] = model['chains']
    #         op.write(yaml.dump(semantics, default_flow_style=False))

    # for smurf, we parse the controller parameters into the motors

    for motor in model['motors']:
        motordict = model['motors'][motor]
        controllerparams = {}
        if 'controller' in motordict and motordict['controller'] in model[
                'controllers']:
            controllerparams = {
                key: value
                for key, value in model['controllers'][
                    motordict['controller']].items()
                if (key not in ['name', 'target'])
            }
            motordict.update(controllerparams)
            del motordict['controller']
        else:
            log(
                "No controller assigned to motor {}!".format(
                    motordict['name']), 'WARNING')

        # PID controlled motors get their min and max values from the joint limits
        if motordict['type'] == 'PID':
            try:
                joint = model['joints'][motordict['joint']]
                if 'limits' in joint:
                    motordict['minValue'] = joint['limits']['lower']
                    motordict['maxValue'] = joint['limits']['upper']
            except KeyError:
                log(
                    "Missing data in motor {}! No limits given for type PID. Motor might be incomplete."
                    .format(motordict['name']),
                    "WARNING",
                )
        # direct controllers are called generic_dc in mars
        elif motordict['type'] == 'direct':
            motordict['type'] = 'generic_dc'
            try:
                motordict['minValue'] = -motordict["maxSpeed"]
                motordict['maxValue'] = motordict["maxSpeed"]
            except KeyError:
                log(
                    "Missing data in motor {}! No maxSpeed given for motor type direct. Motor might be incomplete."
                    .format(motordict['name']),
                    "WARNING",
                )

    # TODO: implement everything but joints
    # write state (state information of all joints, sensor & motor activity etc.)
    if exportdata['state']:
        states = []
        # gather all states
        for jointname in model['joints']:
            joint = model['joints'][jointname]
            # this should always be the case, but testing doesn't hurt
            if 'state' in joint:
                tmpstate = joint['state'].copy()
                tmpstate['name'] = jointname
                states.append(joint['state'])
        with open(os.path.join(path, filenames['state']), 'w') as op:
            op.write('#state' + infostring)
            op.write("modelname: " + model['name'] + '\n')
            # TODO am I still needed?
            op.write(yaml.dump(states))  # , default_flow_style=False))

    # write materials, sensors, motors & controllers
    for data in ['materials', 'motors', 'sensors', 'controllers', 'lights']:
        if exportdata[data]:
            log("Writing {} to smurf file.".format(data), 'DEBUG')
            with open(os.path.join(path, filenames[data]), 'w') as op:
                op.write('#' + data + infostring)
                op.write(
                    yaml.dump(
                        sort_for_yaml_dump({data: list(model[data].values())},
                                           data),
                        default_flow_style=False,
                    ))

    # write additional collision information
    if exportdata['collision']:
        with open(os.path.join(path, filenames['collision']), 'w') as op:
            op.write('#collision data' + infostring)
            # TODO delete me?
            # op.write(yaml.dump({'collision': list(bitmasks.values())}, default_flow_style=False))
            op.write(
                yaml.dump(
                    {
                        'collision': [
                            collisiondata[key]
                            for key in sorted(collisiondata.keys())
                        ]
                    },
                    default_flow_style=False,
                ))

    # write visual information (level of detail, ...)
    if exportdata['visuals']:
        with open(os.path.join(path, filenames['visuals']), 'w') as op:
            op.write('#visual data' + infostring)
            op.write(
                yaml.dump({'visuals': list(lodsettings.values())},
                          default_flow_style=False))

    # write additional information
    for category in annotationdict.keys():
        if category != 'sdf':
            if exportdata[category]:
                outstring = '#' + category + infostring
                for elementtype in annotationdict[category]:
                    outstring += elementtype + ':\n'
                    outstring += (
                        yaml.dump(annotationdict[category][elementtype],
                                  default_flow_style=False) + "\n")
                with open(os.path.join(path, filenames[category]), 'w') as op:
                    op.write(outstring)

    # write custom data from textfiles
    for data in customdatalist:
        if exportdata[data]:
            with open(os.path.join(path, filenames[data]), 'w') as op:
                op.write('#' + data + infostring)
                op.write(
                    yaml.dump({data: list(model[data].values())},
                              default_flow_style=False))

    # write submechanisms
    if model['submechanisms']:
        with open(os.path.join(path, filenames['submechanisms']), 'w') as op:
            op.write('#submechanisms' + infostring)
            op.write(yaml.dump({'submechanisms': model['submechanisms']
                                }))  # , default_flow_style=False))
Beispiel #60
0
def exportModel(root, export_path, entitytypes=None, model=None):
    # derive model
    model = models.buildModelDictionary(root)
    if not model:
        model = models.buildModelDictionary(root)

    # export model in selected formats
    if entitytypes is None:
        entitytypes = entities.entity_types
    for entitytype in entitytypes:
        typename = "export_entity_" + entitytype
        # check if format exists and should be exported
        if not getattr(bpy.data.worlds[0], typename, False):
            continue
        # format exists and is exported:
        if ioUtils.getExpSettings().structureExport:
            model_path = os.path.join(export_path, entitytype)
        else:
            model_path = export_path
        securepath(model_path)
        try:
            entities.entity_types[entitytype]['export'](model, model_path)
            log(
                "Export model: " + model['name'] + ' as ' + entitytype +
                " to " + model_path, "DEBUG")
        except KeyError:
            log(
                "No export function available for selected model type: " +
                entitytype, "ERROR")
            continue

    # TODO: Move mesh export to individual formats? This is practically SMURF
    # export meshes in selected formats
    i = 1
    mt = len([
        m for m in meshes.mesh_types
        if getattr(bpy.data.worlds[0], "export_mesh_" + m)
    ])
    mc = len(model['meshes'])
    n = mt * mc
    for meshtype in meshes.mesh_types:
        mesh_path = ioUtils.getOutputMeshpath(export_path, meshtype)
        try:
            typename = "export_mesh_" + meshtype
            if getattr(bpy.data.worlds[0], typename):
                securepath(mesh_path)
                for meshname in model['meshes']:
                    meshes.mesh_types[meshtype]['export'](
                        model['meshes'][meshname], mesh_path)
                    display.setProgress(
                        i / n,
                        'Exporting ' + meshname + '.' + meshtype + '...')
                    i += 1
        except KeyError:
            log(
                "No export function available for selected mesh function: " +
                meshtype, "ERROR")
            print(sys.exc_info()[0])
    display.setProgress(0)

    # TODO: Move texture export to individual formats? This is practically SMURF
    # TODO: Also, this does not properly take care of textures embedded in a .blend file
    # export textures
    if ioUtils.getExpSettings().exportTextures:
        for materialname in model['materials']:
            mat = model['materials'][materialname]
            for texturetype in [
                    'diffuseTexture', 'normalTexture', 'displacementTexture'
            ]:
                if texturetype in mat:
                    sourcepath = os.path.join(
                        os.path.expanduser(bpy.path.abspath('//')),
                        mat[texturetype])
                    if os.path.isfile(sourcepath):
                        texture_path = securepath(
                            os.path.join(export_path, 'textures'))
                        log("Exporting textures to " + texture_path, "INFO")
                        try:
                            shutil.copy(
                                sourcepath,
                                os.path.join(
                                    texture_path,
                                    os.path.basename(mat[texturetype])))
                        except shutil.SameFileError:
                            log("{} already in place".format(texturetype),
                                "INFO")