예제 #1
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.

    :param selected_only: If True only selected entities get exported.
    :type selected_only: bool
    :param subfolder: If True the models are exported into separate subfolders
    :type subfolder: bool

    """
    # TODO path consistency (Windows)
    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 + " - https://github.com/rock-simulation/phobos\n\n"
        securepath(path)
        log("Exporting scene to " + path + '.smurfs', "INFO")
        outputfile.write(sceneinfo)
        epsilon = 10**(-bpy.data.worlds[0].phobosexportsettings.decimalPlaces
                       )  # TODO: implement this separately
        entitiesdict = epsilonToZero(
            {'entities': entities}, epsilon,
            bpy.data.worlds[0].phobosexportsettings.decimalPlaces)
        outputfile.write(yaml.dump(entitiesdict))
예제 #2
0
파일: smurfs.py 프로젝트: jacknlliu/phobos
def exportSMURFsScene(entities, path, selected_only=True, subfolder=True):
    """Exports an arranged scene into SMURFS. It will export only entities
    with a valid entity/name, and entity/type property.

    :param selected_only: If True only selected entities get exported.
    :type selected_only: bool
    :param subfolder: If True the models are exported into separate subfolders
    :type subfolder: bool

    """

    outputlist = []

    # identify all entities in the scene
    entities = [
        e for e in [obj for obj in bpy.context.scene.objects if isEntity(obj)]
        if ((selected_only and e.select) or not selected_only)
    ]
    if len(entities) == 0:
        log("There are no entities to export!", "WARNING",
            __name__ + ".exportSMURFsScene")
        return
    log("Exporting scene to " + path, "INFO", "exportSMURFsScene")
    for entity in entities:
        log("Exporting " + str(entity["entity/name"]) + " to SMURFS", "INFO")
        if entity["entity/type"] in entity_types:
            if hasattr(entity_types[entity["entity/type"]], 'deriveEntity'):
                entry = entity_types[entity["entity/type"]].deriveEntity(
                    entity, path, subfolder)  # known entity export
            else:
                log("Required method "
                    "deriveEntity"
                    " not implemented", "ERROR")
        else:  # generic entity export
            entry = deriveGenericEntity(entity)
        outputlist.append(entry)

    with open(
            os.path.join(path, bpy.data.worlds['World'].sceneName + '.smurfs'),
            'w') as outputfile:
        sceneinfo = "# SMURF scene " + bpy.data.worlds[
            'World'].sceneName + "; created " + datetime.now().strftime(
                "%Y%m%d_%H:%M") + "\n"
        sceneinfo += "# created with Phobos " + version + " - https://github.com/rock-simulation/phobos\n\n"
        outputfile.write(sceneinfo)
        epsilon = 10**(-bpy.data.worlds[0].phobosexportsettings.decimalPlaces
                       )  # TODO: implement this separately
        entitiesdict = epsilonToZero(
            {'entities': outputlist}, epsilon,
            bpy.data.worlds[0].phobosexportsettings.decimalPlaces)
        outputfile.write(yaml.dump(entitiesdict))
예제 #3
0
def buildModelDictionary(root):
    """Builds a python dictionary representation of a Phobos model.

    :param root: bpy.types.objects
    :return: dict
    """
    # TODO remove this comment
    # os.system('clear')

    model = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'meshes': {},
        'lights': {},
        'groups': {},
        'chains': {}
    }
    # timestamp of model
    model["date"] = datetime.now().strftime("%Y%m%d_%H:%M")
    if root.phobostype not in ['link', 'submodel']:
        log("Found no 'link' or 'submodel' object as root of the robot model.",
            "ERROR")
        raise Exception(root.name + " is  no valid root link.")
    else:
        if 'modelname' in root:
            model['name'] = root["modelname"]
        else:
            log("No name for the model defines, setting to 'unnamed_model'",
                "WARNING")
            model['name'] = 'unnamed_model'

    log(
        "Creating dictionary for robot " + model['name'] + " from object " +
        root.name, "INFO")

    # create tuples of objects belonging to model
    objectlist = sUtils.getChildren(
        root,
        selected_only=ioUtils.getExpSettings().selectedOnly,
        include_hidden=False)
    linklist = [link for link in objectlist if link.phobostype == 'link']

    # digest all the links to derive link and joint information
    log("Parsing links, joints and motors..." + (str(len(linklist))), "INFO")
    for link in linklist:
        # parse link and extract joint and motor information
        linkdict, jointdict, motordict = deriveKinematics(link)
        model['links'][linkdict['name']] = linkdict
        # joint will be None if link is a root
        if jointdict:
            model['joints'][jointdict['name']] = jointdict
        # motor will be None if no motor is attached or link is a root
        if motordict:
            model['motors'][motordict['name']] = motordict
        # add inertial information to link
        # if this link-inertial object is no present, we ignore the inertia!
        try:
            inertial = bpy.context.scene.objects['inertial_' +
                                                 linkdict['name']]
            props = deriveDictEntry(inertial)
            if props is not None:
                model['links'][linkdict['name']]['inertial'] = props
        except KeyError:
            log("No inertia for link " + linkdict['name'], "WARNING")

    # combine inertia if certain objects are left out, and overwrite it
    inertials = (i for i in objectlist
                 if i.phobostype == 'inertial' and "inertial/inertia" in i)
    editlinks = {}
    for i in inertials:
        if i.parent not in linklist:
            realparent = sUtils.getEffectiveParent(i)
            if realparent:
                parentname = nUtils.getObjectName(realparent)
                if parentname in editlinks:
                    editlinks[parentname].append(i)
                else:
                    editlinks[parentname] = [i]
    for linkname in editlinks:
        inertials = editlinks[linkname]
        try:
            inertials.append(bpy.context.scene.objects['inertial_' + linkname])
        except KeyError:
            pass
        mv, cv, iv = inertiamodel.fuseInertiaData(inertials)
        iv = inertiamodel.inertiaMatrixToList(iv)
        if mv is not None and cv is not None and iv is not None:
            model['links'][linkname]['inertial'] = {
                'mass': mv,
                'inertia': iv,
                'pose': {
                    'translation': list(cv),
                    'rotation_euler': [0, 0, 0]
                }
            }

    # complete link information by parsing visuals and collision objects
    log("Parsing visual and collision (approximation) objects...", "INFO")
    for obj in objectlist:
        # try:
        if obj.phobostype in ['visual', 'collision']:
            props = deriveDictEntry(obj)
            parentname = nUtils.getObjectName(sUtils.getEffectiveParent(obj))
            model['links'][parentname][obj.phobostype][nUtils.getObjectName(
                obj)] = props
        elif obj.phobostype == 'approxsphere':
            props = deriveDictEntry(obj)
            parentname = nUtils.getObjectName(sUtils.getEffectiveParent(obj))
            model['links'][parentname]['approxcollision'].append(props)

        # TODO delete me?
        # except KeyError:
        #    try:
        #        log(parentname + " not found", "ERROR")
        #    except TypeError:
        #        log("No parent found for " + obj.name, "ERROR")

    # combine collision information for links
    for linkname in model['links']:
        link = model['links'][linkname]
        bitmask = 0
        for collname in link['collision']:
            try:
                # bitwise OR to add all collision layers
                bitmask = bitmask | link['collision'][collname]['bitmask']
            except KeyError:
                pass
        link['collision_bitmask'] = bitmask

    # parse sensors and controllers
    log("Parsing sensors and controllers...", "INFO")
    for obj in objectlist:
        if obj.phobostype in ['sensor', 'controller']:
            props = deriveDictEntry(obj)
            model[obj.phobostype + 's'][nUtils.getObjectName(obj)] = props

    # parse materials
    log("Parsing materials...", "INFO")
    model['materials'] = collectMaterials(objectlist)
    for obj in objectlist:
        if obj.phobostype == 'visual':
            mat = obj.active_material
            try:
                if mat.name not in model['materials']:
                    # this should actually never happen
                    model['materials'][mat.name] = deriveMaterial(mat)
                linkname = nUtils.getObjectName(sUtils.getEffectiveParent(obj))
                model['links'][linkname]['visual'][nUtils.getObjectName(
                    obj)]['material'] = mat.name
            except AttributeError:
                log("Could not parse material for object " + obj.name, "ERROR")

    # identify unique meshes
    log("Parsing meshes...", "INFO")
    for obj in objectlist:
        try:
            if ((obj.phobostype == 'visual' or obj.phobostype == 'collision')
                    and (obj['geometry/type'] == 'mesh')
                    and (obj.data.name not in model['meshes'])):
                model['meshes'][obj.data.name] = obj
                for lod in obj.lod_levels:
                    if lod.object.data.name not in model['meshes']:
                        model['meshes'][lod.object.data.name] = lod.object
        except KeyError:
            log("Undefined geometry type in object " + obj.name, "ERROR")

    # gather information on groups of objects
    log("Parsing groups...", "INFO")
    # TODO: get rid of the "data" part and check for relation to robot
    for group in bpy.data.groups:
        # skip empty groups
        if not group.objects:
            continue

        # handle submodel groups separately from other groups
        if 'submodeltype' in group.keys():
            continue
            # TODO create code to derive Submodels
            # model['submodels'] = deriveSubmodel(group)
        elif nUtils.getObjectName(group, 'group') != "RigidBodyWorld":
            model['groups'][nUtils.getObjectName(
                group, 'group')] = deriveGroupEntry(group)

    # gather information on chains of objects
    log("Parsing chains...", "INFO")
    chains = []
    for obj in objectlist:
        if obj.phobostype == 'link' and 'endChain' in obj:
            chains.extend(deriveChainEntry(obj))
    for chain in chains:
        model['chains'][chain['name']] = chain

    # gather information on lights
    log("Parsing lights...", "INFO")
    for obj in objectlist:
        if obj.phobostype == 'light':
            model['lights'][nUtils.getObjectName(obj)] = deriveLight(obj)

    # gather submechanism information from links
    log("Parsing submechanisms...", "INFO")
    submechanisms = []
    for link in linklist:
        if 'submechanism/name' in link.keys():
            #for key in [key for key in link.keys() if key.startswith('submechanism/')]:
            #    submechanisms.append({key.replace('submechanism/', ''): value
            #                        for key, value in link.items()})
            submech = {
                'name':
                link['submechanism/category'],
                'type':
                link['submechanism/type'],
                'contextual_name':
                link['submechanism/name'],
                'jointnames_independent':
                [j.name for j in link['submechanism/independent']],
                'jointnames_spanningtree':
                [j.name for j in link['submechanism/spanningtree']],
                'jointnames_active':
                [j.name for j in link['submechanism/active']]
            }
            submechanisms.append(submech)
    model['submechanisms'] = submechanisms

    # add additional data to model
    model.update(deriveTextData(model['name']))

    # shorten numbers in dictionary to n decimalPlaces and return it
    log("Rounding numbers...", "INFO")
    # TODO: implement this separately
    epsilon = 10**(-ioUtils.getExpSettings().decimalPlaces)
    return epsilonToZero(model, epsilon,
                         ioUtils.getExpSettings().decimalPlaces)
예제 #4
0
def buildModelDictionary(root):
    """Builds a python dictionary representation of a SMURF model for export and inspection.

    :param root: bpy.types.objects
    :return: dict
    """
    #os.system('clear')

    robot = {'links': {},
             'joints': {},
             'sensors': {},
             'motors': {},
             'controllers': {},
             'materials': {},
             'lights': {},
             'groups': {},
             'chains': {}
             }
    # timestamp of model
    robot["date"] = datetime.now().strftime("%Y%m%d_%H:%M")
    if root.phobostype != 'link':
        log("Found no 'link' object as root of the robot model.", "ERROR", "buildModelDictionary")
        raise Exception(root.name + " is  no valid root link.")
    else:
        if 'modelname' in root:
            robot['modelname'] = root["modelname"]
        else:
            log("No name for the model defines, setting to 'unnamed_model'", "WARNING", "buildModelDictionary")
            robot['modelname'] = 'unnamed_model'

    log("Creating dictionary for robot " + robot['modelname'] + " from object "
        + root.name, "INFO", "buildModelDictionary")

    # create tuples of objects belonging to model
    objectlist = sUtils.getChildren(root, selected_only=True, include_hidden=False)
    linklist = [link for link in objectlist if link.phobostype == 'link']

    # digest all the links to derive link and joint information
    log("Parsing links, joints and motors...", "INFO", "buildModelDictionary")
    for link in linklist:
        # parse link and extract joint and motor information
        linkdict, jointdict, motordict = deriveKinematics(link)
        robot['links'][linkdict['name']] = linkdict
        if jointdict:  # joint will be None if link is a root
            robot['joints'][jointdict['name']] = jointdict
        if motordict:  # motor will be None if no motor is attached or link is a root
            robot['motors'][motordict['name']] = motordict
        # add inertial information to link
        try:  # if this link-inertial object is no present, we ignore the inertia!
            inertial = bpy.context.scene.objects['inertial_' + linkdict['name']]
            props = deriveDictEntry(inertial)
            if props is not None:
                robot['links'][linkdict['name']]['inertial'] = props
        except KeyError:
            log("No inertia for link " + linkdict['name'], "WARNING", "buildModelDictionary")

    # we need to combine inertia if certain objects are left out, and overwrite it
    inertials = (i for i in objectlist if i.phobostype == 'inertial' and "inertial/inertia" in i)
    editlinks = {}
    for i in inertials:
        if i.parent not in linklist:
            realparent = sUtils.getEffectiveParent(i)
            if realparent:
                parentname = nUtils.getObjectName(realparent)
                if parentname in editlinks:
                    editlinks[parentname].append(i)
                else:
                    editlinks[parentname] = [i]
    for linkname in editlinks:
        inertials = editlinks[linkname]
        try:
            inertials.append(bpy.context.scene.objects['inertial_' + linkname])
        except KeyError:
            pass
        mv, cv, iv = inertia.fuseInertiaData(inertials)
        iv = inertia.inertiaMatrixToList(iv)
        if mv is not None and cv is not None and iv is not None:
            robot['links'][linkname]['inertial'] = {'mass': mv,
                                                            'inertia': iv,
                                                            'pose': {'translation': list(cv),
                                                                     'rotation_euler': [0, 0, 0]
                                                                     }
                                                            }

    # complete link information by parsing visuals and collision objects
    log("Parsing visual and collision (approximation) objects...", "INFO", "buildModelDictionary")
    for obj in objectlist:
        try:
            if obj.phobostype in ['visual', 'collision']:
                props = deriveDictEntry(obj)
                parentname = nUtils.getObjectName(sUtils.getEffectiveParent(obj))
                robot['links'][parentname][obj.phobostype][nUtils.getObjectName(obj)] = props
            elif obj.phobostype == 'approxsphere':
                props = deriveDictEntry(obj)
                parentname = nUtils.getObjectName(sUtils.getEffectiveParent(obj))
                robot['links'][parentname]['approxcollision'].append(props)
        except KeyError:
            try:
                log(parentname + " not found", "ERROR")
            except TypeError:
                log("No parent found for " + obj.name, "ERROR")

    # combine collision information for links
    for linkname in robot['links']:
        link = robot['links'][linkname]
        bitmask = 0
        for collname in link['collision']:
            try:
                bitmask = bitmask | link['collision'][collname]['bitmask']
            except KeyError:
                pass
        link['collision_bitmask'] = bitmask

    # parse sensors and controllers
    log("Parsing sensors and controllers...", "INFO", "buildModelDictionary")
    for obj in objectlist:
        if obj.phobostype in ['sensor', 'controller']:
            props = deriveDictEntry(obj)
            robot[obj.phobostype+'s'][nUtils.getObjectName(obj)] = props

    # parse materials
    log("Parsing materials...", "INFO", "buildModelDictionary")
    robot['materials'] = collectMaterials(objectlist)
    for obj in objectlist:
        if obj.phobostype == 'visual' and len(obj.data.materials) > 0:
            mat = obj.data.materials[0]
            matname = nUtils.getObjectName(mat, 'material')
            if matname not in robot['materials']:
                robot['materials'][matname] = deriveMaterial(mat)  # this should actually never happen
            linkname = nUtils.getObjectName(sUtils.getEffectiveParent(obj))
            robot['links'][linkname]['visual'][nUtils.getObjectName(obj)]['material'] = matname

    # gather information on groups of objects
    log("Parsing groups...", "INFO", "buildModelDictionary")
    for group in bpy.data.groups:  # TODO: get rid of the "data" part and check for relation to robot
        if len(group.objects) > 0 and nUtils.getObjectName(group, 'group') != "RigidBodyWorld":
            robot['groups'][nUtils.getObjectName(group, 'group')] = deriveGroupEntry(group)

    # gather information on chains of objects
    log("Parsing chains...", "INFO", "buildModelDictionary")
    chains = []
    for obj in objectlist:
        if obj.phobostype == 'link' and 'endChain' in obj:
            chains.extend(deriveChainEntry(obj))
    for chain in chains:
        robot['chains'][chain['name']] = chain

    # gather information on lights
    log("Parsing lights...", "INFO", "buildModelDictionary")
    for obj in objectlist:
        if obj.phobostype == 'light':
            robot['lights'][nUtils.getObjectName(obj)] = deriveLight(obj)

    # add additional data to model
    robot.update(deriveTextData(robot['modelname']))

    # shorten numbers in dictionary to n decimalPlaces and return it
    log("Rounding numbers...", "INFO", "buildModelDictionary")
    epsilon = 10**(-bpy.data.worlds[0].decimalPlaces)  # TODO: implement this separately
    return epsilonToZero(robot, epsilon, bpy.data.worlds[0].decimalPlaces), objectlist
예제 #5
0
def buildModelDictionary(root):
    """Builds a python dictionary representation of a SMURF model for export and inspection.

    :param root: bpy.types.objects
    :return: dict
    """
    #os.system('clear')

    robot = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'lights': {},
        'groups': {},
        'chains': {}
    }
    # timestamp of model
    robot["date"] = datetime.now().strftime("%Y%m%d_%H:%M")
    if root.phobostype != 'link':
        log("Found no 'link' object as root of the robot model.", "ERROR",
            "buildModelDictionary")
        raise Exception(root.name + " is  no valid root link.")
    else:
        if 'modelname' in root:
            robot['modelname'] = root["modelname"]
        else:
            log("No name for the model defines, setting to 'unnamed_model'",
                "WARNING", "buildModelDictionary")
            robot['modelname'] = 'unnamed_model'

    log(
        "Creating dictionary for robot " + robot['modelname'] +
        " from object " + root.name, "INFO", "buildModelDictionary")

    # create tuples of objects belonging to model
    objectlist = sUtils.getChildren(root,
                                    selected_only=True,
                                    include_hidden=False)
    linklist = [link for link in objectlist if link.phobostype == 'link']

    # digest all the links to derive link and joint information
    log("Parsing links, joints and motors...", "INFO", "buildModelDictionary")
    for link in linklist:
        # parse link and extract joint and motor information
        linkdict, jointdict, motordict = deriveKinematics(link)
        robot['links'][linkdict['name']] = linkdict
        if jointdict:  # joint will be None if link is a root
            robot['joints'][jointdict['name']] = jointdict
        if motordict:  # motor will be None if no motor is attached or link is a root
            robot['motors'][motordict['name']] = motordict
        # add inertial information to link
        try:  # if this link-inertial object is no present, we ignore the inertia!
            inertial = bpy.context.scene.objects['inertial_' +
                                                 linkdict['name']]
            props = deriveDictEntry(inertial)
            if props is not None:
                robot['links'][linkdict['name']]['inertial'] = props
        except KeyError:
            log("No inertia for link " + linkdict['name'], "WARNING",
                "buildModelDictionary")

    # we need to combine inertia if certain objects are left out, and overwrite it
    inertials = (i for i in objectlist
                 if i.phobostype == 'inertial' and "inertial/inertia" in i)
    editlinks = {}
    for i in inertials:
        if i.parent not in linklist:
            realparent = sUtils.getEffectiveParent(i)
            if realparent:
                parentname = nUtils.getObjectName(realparent)
                if parentname in editlinks:
                    editlinks[parentname].append(i)
                else:
                    editlinks[parentname] = [i]
    for linkname in editlinks:
        inertials = editlinks[linkname]
        try:
            inertials.append(bpy.context.scene.objects['inertial_' + linkname])
        except KeyError:
            pass
        mv, cv, iv = inertia.fuseInertiaData(inertials)
        iv = inertia.inertiaMatrixToList(iv)
        if mv is not None and cv is not None and iv is not None:
            robot['links'][linkname]['inertial'] = {
                'mass': mv,
                'inertia': iv,
                'pose': {
                    'translation': list(cv),
                    'rotation_euler': [0, 0, 0]
                }
            }

    # complete link information by parsing visuals and collision objects
    log("Parsing visual and collision (approximation) objects...", "INFO",
        "buildModelDictionary")
    for obj in objectlist:
        try:
            if obj.phobostype in ['visual', 'collision']:
                props = deriveDictEntry(obj)
                parentname = nUtils.getObjectName(
                    sUtils.getEffectiveParent(obj))
                robot['links'][parentname][obj.phobostype][
                    nUtils.getObjectName(obj)] = props
            elif obj.phobostype == 'approxsphere':
                props = deriveDictEntry(obj)
                parentname = nUtils.getObjectName(
                    sUtils.getEffectiveParent(obj))
                robot['links'][parentname]['approxcollision'].append(props)
        except KeyError:
            try:
                log(parentname + " not found", "ERROR")
            except TypeError:
                log("No parent found for " + obj.name, "ERROR")

    # combine collision information for links
    for linkname in robot['links']:
        link = robot['links'][linkname]
        bitmask = 0
        for collname in link['collision']:
            try:
                bitmask = bitmask | link['collision'][collname]['bitmask']
            except KeyError:
                pass
        link['collision_bitmask'] = bitmask

    # parse sensors and controllers
    log("Parsing sensors and controllers...", "INFO", "buildModelDictionary")
    for obj in objectlist:
        if obj.phobostype in ['sensor', 'controller']:
            props = deriveDictEntry(obj)
            robot[obj.phobostype + 's'][nUtils.getObjectName(obj)] = props

    # parse materials
    log("Parsing materials...", "INFO", "buildModelDictionary")
    robot['materials'] = collectMaterials(objectlist)
    for obj in objectlist:
        if obj.phobostype == 'visual' and len(obj.data.materials) > 0:
            mat = obj.data.materials[0]
            matname = nUtils.getObjectName(mat, 'material')
            if matname not in robot['materials']:
                robot['materials'][matname] = deriveMaterial(
                    mat)  # this should actually never happen
            linkname = nUtils.getObjectName(sUtils.getEffectiveParent(obj))
            robot['links'][linkname]['visual'][nUtils.getObjectName(
                obj)]['material'] = matname

    # gather information on groups of objects
    log("Parsing groups...", "INFO", "buildModelDictionary")
    for group in bpy.data.groups:  # TODO: get rid of the "data" part and check for relation to robot
        if len(group.objects) > 0 and nUtils.getObjectName(
                group, 'group') != "RigidBodyWorld":
            robot['groups'][nUtils.getObjectName(
                group, 'group')] = deriveGroupEntry(group)

    # gather information on chains of objects
    log("Parsing chains...", "INFO", "buildModelDictionary")
    chains = []
    for obj in objectlist:
        if obj.phobostype == 'link' and 'endChain' in obj:
            chains.extend(deriveChainEntry(obj))
    for chain in chains:
        robot['chains'][chain['name']] = chain

    # gather information on lights
    log("Parsing lights...", "INFO", "buildModelDictionary")
    for obj in objectlist:
        if obj.phobostype == 'light':
            robot['lights'][nUtils.getObjectName(obj)] = deriveLight(obj)

    # add additional data to model
    robot.update(deriveTextData(robot['modelname']))

    # shorten numbers in dictionary to n decimalPlaces and return it
    log("Rounding numbers...", "INFO", "buildModelDictionary")
    epsilon = 10**(-bpy.data.worlds[0].decimalPlaces
                   )  # TODO: implement this separately
    return epsilonToZero(robot, epsilon,
                         bpy.data.worlds[0].decimalPlaces), objectlist
예제 #6
0
def buildRobotDictionary():
    """Builds a python dictionary representation of a Blender robot model for export and inspection."""
    objectlist = bpy.context.selected_objects
    #notifications, faulty_objects = robotupdate.updateModel(bpy.context.selected_objects)
    #print(notifications)
    robot = {'links': {},
            'joints': {},
            'sensors': {},
            'motors': {},
            'controllers': {},
            'materials': {},
            'groups': {},
            'chains': {},
            'lights': {}
            }
    #save timestamped version of model
    robot["date"] = datetime.now().strftime("%Y%m%d_%H:%M")
    root = selectionUtils.getRoot(bpy.context.selected_objects[0])
    if root.phobostype != 'link':
        raise Exception("Found no 'link' object as root of the robot model.")
    else:
        if 'modelname' in root:
            robot['modelname'] = root["modelname"]
        else:
            robot['modelname'] = 'unnamed_robot'

    # digest all the links to derive link and joint information
    print('\nParsing links, joints and motors...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'link':
            link, joint, motor = deriveKinematics(obj)
            robot['links'][namingUtils.getObjectName(obj, phobostype="link")] = link  # it's important that this is really the object's name
            if joint:  # joint can be None if link is a root
                robot['joints'][joint['name']] = joint
            if motor:
                robot['motors'][joint['name']] = motor
            obj.select = False

    # add inertial information to link
    print('\n\nParsing inertials...')
    for l in robot['links']:
        #link = bpy.data.objects[l] NEW NAMING!
        link = selectionUtils.getObjectByName(l)[0] if selectionUtils.getObjectByName(l) is not None else "ERROR!"
        inertials = selectionUtils.getImmediateChildren(link, ['inertial'])
        if len(inertials) == 1:
            props, parent = deriveDictEntry(inertials[0])
            if not (props is None or parent is None):  # this may be the case if there is inertia information missing
                robot['links'][namingUtils.getObjectName(parent)]['inertial'] = props
            inertials[0].select = False
        elif len(inertials) > 1:
            for i in inertials:
                if namingUtils.getObjectName(i, phobostype="inertial") == 'inertial_' + l:
                    props, parent = deriveDictEntry(i)
                    robot['links'][namingUtils.getObjectName(parent, phobostype="link")]['inertial'] = props
            # FIXME: this has to be re-implemented
            #if linkinertial == None:
            #    mass, com, inertia = inertia.fuseInertiaData(inertials)
            #    parent = inertials[0].parent
            #    matrix_local = mathutils.Matrix.Translation(mathutils.Vector(com))
            #    pose = {}
            #    pose['matrix'] = [list(vector) for vector in list(matrix_local)]
            #    pose['translation'] = list(matrix_local.to_translation())
            #    pose['rotation_euler'] = list(matrix_local.to_euler())
            #    pose['rotation_quaternion'] = list(matrix_local.to_quaternion())
            #    props = {'mass': mass, 'pose': pose, 'inertia': inertia}
            #    robot['links'][parent.name]['inertial'] = props
            for i in inertials:
                i.select = False

    # complete link information by parsing visuals and collision objects
    print('\n\nParsing visual and collision (approximation) objects...')
    for obj in bpy.context.selected_objects:
        print("Parsing object " + namingUtils.getObjectName(obj))
        if obj.phobostype in ['visual', 'collision']:
            props, parent = deriveDictEntry(obj)
            robot['links'][namingUtils.getObjectName(parent, phobostype="link")][obj.phobostype][namingUtils.getObjectName(obj, phobostype=obj.phobostype)] = props
            obj.select = False
        elif obj.phobostype == 'approxsphere':
            props, parent = deriveDictEntry(obj)
            robot['links'][namingUtils.getObjectName(parent)]['approxcollision'].append(props)
            obj.select = False

    # combine collision information for links
    for linkname in robot['links']:
        link = robot['links'][linkname]
        bitmask = 0
        for collname in link['collision']:
            try:
                bitmask = bitmask | link['collision'][collname]['bitmask']
            except KeyError:
                pass
        link['collision_bitmask'] = bitmask

    # parse sensors and controllers
    print('\n\nParsing sensors and controllers...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype in ['sensor', 'controller']:
            robot[obj.phobostype+'s'][namingUtils.getObjectName(obj)] = deriveDictEntry(obj)
            obj.select = False

    # parse materials
    print('\n\nParsing materials...')
    robot['materials'] = collectMaterials(objectlist)
    for obj in objectlist:
        if obj.phobostype == 'visual' and len(obj.data.materials) > 0:
            mat = obj.data.materials[0]
            if not namingUtils.getObjectName(mat) in robot['materials']:
                robot['materials'][namingUtils.getObjectName(mat)] = deriveMaterial(mat) #this should actually never happen
            robot['links'][namingUtils.getObjectName(obj.parent)]['visual'][namingUtils.getObjectName(obj, phobostype="visual")]['material'] = namingUtils.getObjectName(mat)

    # gather information on groups of objects
    print('\n\nParsing groups...')
    for group in bpy.data.groups:  # TODO: get rid of the "data" part
        if len(group.objects) > 0 and namingUtils.getObjectName(group) != "RigidBodyWorld":
            robot['groups'][namingUtils.getObjectName(group)] = deriveGroupEntry(group)

    # gather information on chains of objects
    print('\n\nParsing chains...')
    chains = []
    for obj in bpy.data.objects:
        if obj.phobostype == 'link' and 'endChain' in obj:
            chains.extend(deriveChainEntry(obj))
    for chain in chains:
        robot['chains'][chain['name']] = chain

    # gather information on global lights
    print('\n\nParsing lights...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'light':
            robot['lights'][namingUtils.getObjectName(obj)] = deriveLight(obj)

    robot['poses'] = deriveStoredPoses()

    #shorten numbers in dictionary to n decimalPlaces and return it
    print('\n\nRounding numbers...')
    epsilon = 10**(-bpy.data.worlds[0].decimalPlaces)  # TODO: implement this separately
    return generalUtils.epsilonToZero(robot, epsilon, bpy.data.worlds[0].decimalPlaces)
예제 #7
0
def buildRobotDictionary():
    """Builds a python dictionary representation of a Blender robot model for export and inspection.

    """
    objectlist = bpy.context.selected_objects
    #notifications, faulty_objects = robotupdate.updateModel(bpy.context.selected_objects)
    #print(notifications)
    robot = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'groups': {},
        'chains': {},
        'lights': {}
    }
    #save timestamped version of model
    robot["date"] = datetime.now().strftime("%Y%m%d_%H:%M")
    root = selectionUtils.getRoot(bpy.context.selected_objects[0])
    if root.phobostype != 'link':
        raise Exception("Found no 'link' object as root of the robot model.")
    else:
        if 'modelname' in root:
            robot['modelname'] = root["modelname"]
        else:
            robot['modelname'] = 'unnamed_robot'

    # digest all the links to derive link and joint information
    print('\nParsing links, joints and motors...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'link':
            link, joint, motor = deriveKinematics(obj)
            robot['links'][namingUtils.getObjectName(
                obj, phobostype="link"
            )] = link  # it's important that this is really the object's name
            if joint:  # joint can be None if link is a root
                robot['joints'][joint['name']] = joint
            if motor:
                robot['motors'][joint['name']] = motor
            obj.select = False

    # add inertial information to link
    print('\n\nParsing inertials...')
    for l in robot['links']:
        #link = bpy.data.objects[l] NEW NAMING!
        link = selectionUtils.getObjectByName(
            l)[0] if selectionUtils.getObjectByName(
                l) is not None else "ERROR!"
        inertials = selectionUtils.getImmediateChildren(link, ['inertial'])
        if len(inertials) == 1:
            props, parent = deriveDictEntry(inertials[0])
            if not (
                    props is None or parent is None
            ):  # this may be the case if there is inertia information missing
                robot['links'][namingUtils.getObjectName(
                    parent)]['inertial'] = props
            inertials[0].select = False
        elif len(inertials) > 1:
            for i in inertials:
                if i.name == 'inertial_' + l:
                    props, parent = deriveDictEntry(i)
                    robot['links'][namingUtils.getObjectName(
                        parent, phobostype="link")]['inertial'] = props
            # FIXME: this has to be re-implemented
            #if linkinertial == None:
            #    mass, com, inertia = inertia.fuseInertiaData(inertials)
            #    parent = inertials[0].parent
            #    matrix_local = mathutils.Matrix.Translation(mathutils.Vector(com))
            #    pose = {}
            #    pose['matrix'] = [list(vector) for vector in list(matrix_local)]
            #    pose['translation'] = list(matrix_local.to_translation())
            #    pose['rotation_euler'] = list(matrix_local.to_euler())
            #    pose['rotation_quaternion'] = list(matrix_local.to_quaternion())
            #    props = {'mass': mass, 'pose': pose, 'inertia': inertia}
            #    robot['links'][parent.name]['inertial'] = props
            for i in inertials:
                i.select = False

    # complete link information by parsing visuals and collision objects
    print('\n\nParsing visual and collision (approximation) objects...')
    capsules_list = []
    for obj in bpy.context.selected_objects:
        print("Parsing object " + namingUtils.getObjectName(obj))
        if obj.phobostype in ['visual', 'collision']:
            props, parent = deriveDictEntry(obj)
            if all([
                    key in props for key in ['cylinder', 'sphere1', 'sphere2']
            ]):  # this is the case with simulated capsules
                capsules_list.append({
                    'link':
                    parent.name,
                    'name':
                    props['cylinder']['name'][:-len('_cylinder')],
                    'radius':
                    props['cylinder']['geometry']['radius'],
                    'length':
                    props['cylinder']['geometry']['length'] +
                    2 * props['cylinder']['geometry']['radius'],
                    #'bitmask': props['cylinder']['bitmask']
                })
                for key in props:
                    robot['links'][namingUtils.getObjectName(
                        parent,
                        phobostype="link")][obj.phobostype][key] = props[key]
            else:
                robot['links'][namingUtils.getObjectName(
                    parent, phobostype="link")][obj.phobostype][
                        namingUtils.getObjectName(
                            obj, phobostype=obj.phobostype)] = props
            obj.select = False
        elif obj.phobostype == 'approxsphere':
            props, parent = deriveDictEntry(obj)
            robot['links'][namingUtils.getObjectName(
                parent)]['approxcollision'].append(props)
            obj.select = False

    robot['capsules'] = capsules_list

    # combine collision information for links
    for linkname in robot['links']:
        link = robot['links'][linkname]
        bitmask = 0
        for collname in link['collision']:
            try:
                bitmask = bitmask | link['collision'][collname]['bitmask']
            except KeyError:
                pass
        link['collision_bitmask'] = bitmask

    # parse sensors and controllers
    print('\n\nParsing sensors and controllers...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype in ['sensor', 'controller']:
            robot[obj.phobostype +
                  's'][namingUtils.getObjectName(obj)] = deriveDictEntry(obj)
            obj.select = False

    # parse materials
    print('\n\nParsing materials...')
    robot['materials'] = collectMaterials(objectlist)
    for obj in objectlist:
        if obj.phobostype == 'visual' and len(obj.data.materials) > 0:
            mat = obj.data.materials[0]
            if not namingUtils.getObjectName(mat) in robot['materials']:
                robot['materials'][namingUtils.getObjectName(
                    mat)] = deriveMaterial(
                        mat)  #this should actually never happen
            robot['links'][namingUtils.getObjectName(
                obj.parent)]['visual'][namingUtils.getObjectName(
                    obj, phobostype="visual"
                )]['material'] = namingUtils.getObjectName(mat)

    # gather information on groups of objects
    print('\n\nParsing groups...')
    for group in bpy.data.groups:  # TODO: get rid of the "data" part
        if len(group.objects) > 0 and namingUtils.getObjectName(
                group) != "RigidBodyWorld":
            robot['groups'][namingUtils.getObjectName(
                group)] = deriveGroupEntry(group)

    # gather information on chains of objects
    print('\n\nParsing chains...')
    chains = []
    for obj in bpy.data.objects:
        if obj.phobostype == 'link' and 'endChain' in obj:
            chains.extend(deriveChainEntry(obj))
    for chain in chains:
        robot['chains'][chain['name']] = chain

    # gather information on global lights
    print('\n\nParsing lights...')
    for obj in bpy.context.selected_objects:
        if obj.phobostype == 'light':
            robot['lights'][namingUtils.getObjectName(obj)] = deriveLight(obj)

    robot['poses'] = deriveStoredPoses()

    #shorten numbers in dictionary to n decimalPlaces and return it
    print('\n\nRounding numbers...')
    epsilon = 10**(-bpy.data.worlds[0].decimalPlaces
                   )  # TODO: implement this separately
    return generalUtils.epsilonToZero(robot, epsilon,
                                      bpy.data.worlds[0].decimalPlaces)