Example #1
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'}
Example #2
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 = json.loads(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, json.dumps(posedict))
    else:
        log("No model root provided to store the pose for", "ERROR")
Example #3
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        root = sUtils.getRoot(context.selected_objects[0])
        objectlist = sUtils.getChildren(root, selected_only=True, include_hidden=False)
        sUtils.selectObjects(objectlist)
        poses = models.getPoses(root['model/name'])
        i = 1
        for pose in poses:
            sUtils.selectObjects([root] + objectlist, clear=True, active=0)
            models.loadPose(root['model/name'], pose)
            parameter = self.decimate_ratio
            if self.decimate_type == 'UNSUBDIV':
                parameter = self.decimate_iteration
            elif self.decimate_type == 'DISSOLVE':
                parameter = self.decimate_angle_limit
            exporter.bakeModel(
                objectlist,
                root['model/name'],
                pose,
                decimate_type=self.decimate_type,
                decimate_parameter=parameter,
            )
            display.setProgress(i / len(poses))
            i += 1
        sUtils.selectObjects([root] + objectlist, clear=True, active=0)
        bpy.ops.scene.reload_models_and_poses_operator()
        return {'FINISHED'}
Example #4
0
 def execute(self, context):
     root = sUtils.getRoot(context.selected_objects[0])
     objectlist = sUtils.getChildren(root,
                                     selected_only=True,
                                     include_hidden=False)
     sUtils.selectObjects(objectlist)
     poses = models.getPoses(root['modelname'])
     i = 1
     for pose in poses:
         sUtils.selectObjects([root] + objectlist, clear=True, active=0)
         models.loadPose(root['modelname'], pose)
         parameter = self.decimate_ratio
         if self.decimate_type == 'UNSUBDIV':
             parameter = self.decimate_iteration
         elif self.decimate_type == 'DISSOLVE':
             parameter = self.decimate_angle_limit
         exporter.bakeModel(objectlist,
                            root['modelname'],
                            pose,
                            decimate_type=self.decimate_type,
                            decimate_parameter=parameter)
         display.setProgress(i / len(poses))
         i += 1
     sUtils.selectObjects([root] + objectlist, clear=True, active=0)
     bpy.ops.scene.reload_models_and_poses_operator()
     return {'FINISHED'}
Example #5
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        root = sUtils.getRoot(context.selected_objects[0])

        modelsPosesColl = bUtils.getPhobosPreferences().models_poses
        activeModelPoseIndex = bpy.context.scene.active_ModelPose
        selected_robot = modelsPosesColl[bpy.data.images[activeModelPoseIndex].name]

        objectlist = sUtils.getChildren(root, selected_only=True, include_hidden=False)
        sUtils.selectObjects([root] + objectlist, clear=True, active=0)
        models.loadPose(selected_robot.robot_name, selected_robot.label)
        parameter = self.decimate_ratio
        if self.decimate_type == 'UNSUBDIV':
            parameter = self.decimate_iteration
        elif self.decimate_type == 'DISSOLVE':
            parameter = self.decimate_angle_limit
        exporter.bakeModel(
            objectlist,
            root['model/name'],
            selected_robot.label,
            decimate_type=self.decimate_type,
            decimate_parameter=parameter,
        )
        sUtils.selectObjects([root] + objectlist, clear=True, active=0)
        bpy.ops.scene.reload_models_and_poses_operator()
        return {'FINISHED'}
Example #6
0
def storePose(modelname, posename):
    """
    Stores the current pose of all of a robot's selected joints.
    Existing poses of the same name will be overwritten.

    :param modelname: The robot the pose belongs to.
    :type modelname: str.
    :param posename: The name the pose will be stored under.
    :type posename: str.
    :return: Nothing.
    """
    rootlink = None
    for root in sUtils.getRoots():
        if root['modelname'] == modelname:
            rootlink = root
    if rootlink:
        filename = modelname + '::poses'
        posedict = yaml.load(bUtils.readTextFile(filename))
        if not posedict:
            posedict = {posename: {'name': posename, 'joints': {}}}
        else:
            posedict[posename] = {'name': posename, 'joints': {}}
        bpy.ops.object.mode_set(mode='POSE')
        links = sUtils.getChildren(rootlink, ('link',), True, False)
        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
        bUtils.updateTextFile(filename, yaml.dump(posedict, default_flow_style=False))
    else:
        log("No model root could be found to store the pose for", "ERROR", "storePose")
Example #7
0
 def execute(self, context):
     startLog(self)
     objlist = context.selected_objects
     if self.complete:
         roots = list(
             set([sUtils.getRoot(obj) for obj in context.selected_objects]))
         if None in roots:
             roots.remove(None)
         objlist = [
             elem
             for sublist in [sUtils.getChildren(root) for root in roots]
             for elem in sublist
         ]
     objnames = [o.name for o in bpy.data.objects]
     for obj in objlist:
         if "::" in obj.name:
             if nUtils.namesAreExplicit({obj.name.split("::")[-1]},
                                        objnames):
                 nUtils.removeNamespace(obj)
             else:
                 log(
                     "Cannot remove namespace from " + obj.name +
                     ". Name wouldn't be explicit", "ERROR")
         else:
             nUtils.addNamespace(obj)
     endLog()
     return {'FINISHED'}
Example #8
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'}
def storePose(robot_name, pose_name):
    """
    Store the current pose of all of a robot's selected links.
    Existing poses of the same name will be overwritten.

    :param robot_name: The robot the pose belongs to.
    :type robot_name: str.
    :param pose_name: The name the pose will be stored under.
    :type pose_name: str.
    :return: Nothing.
    """
    file_name = 'robot_poses_' + robot_name
    load_file = blenderUtils.readTextFile(file_name)
    if load_file == '':
        poses = {}
    else:
        poses = yaml.load(load_file)
    new_pose = {}
    prev_mode = bpy.context.mode
    bpy.ops.object.mode_set(mode='POSE')
    for root in selectionUtils.getRoots():
        if root['modelname'] == robot_name:
            links = selectionUtils.getChildren(root)
            for link in links:
                if link.select and link.phobostype == 'link':
                    link.pose.bones['Bone'].rotation_mode = 'XYZ'
                    new_pose[namingUtils.getObjectName(link, 'joint')] = link.pose.bones['Bone'].rotation_euler.y
    bpy.ops.object.mode_set(mode=prev_mode)
    poses[pose_name] = new_pose
    blenderUtils.updateTextFile(file_name, yaml.dump(poses))
Example #10
0
def storePose(robot_name, pose_name):
    """
    Store the current pose of all of a robot's selected links.
    Existing poses of the same name will be overwritten.

    :param robot_name: The robot the pose belongs to.
    :type robot_name: str.
    :param pose_name: The name the pose will be stored under.
    :type pose_name: str.
    :return: Nothing.
    """
    file_name = 'robot_poses_' + robot_name
    load_file = blenderUtils.readTextFile(file_name)
    if load_file == '':
        poses = {}
    else:
        poses = yaml.load(load_file)
    new_pose = {}
    prev_mode = bpy.context.mode
    bpy.ops.object.mode_set(mode='POSE')
    for root in selectionUtils.getRoots():
        if root['modelname'] == robot_name:
            links = selectionUtils.getChildren(root)
            for link in links:
                if link.select and link.phobostype == 'link':
                    link.pose.bones['Bone'].rotation_mode = 'XYZ'
                    new_pose[namingUtils.getObjectName(
                        link,
                        'joint')] = link.pose.bones['Bone'].rotation_euler.y
    bpy.ops.object.mode_set(mode=prev_mode)
    poses[pose_name] = new_pose
    blenderUtils.updateTextFile(file_name, yaml.dump(poses))
Example #11
0
    def execute(self, context):
        root = sUtils.getRoot(context.selected_objects[0])

        modelsPosesColl = bpy.context.user_preferences.addons[
            'phobos'].preferences.models_poses
        activeModelPoseIndex = bpy.context.scene.active_ModelPose
        selected_robot = modelsPosesColl[
            bpy.data.images[activeModelPoseIndex].name]

        objectlist = sUtils.getChildren(root,
                                        selected_only=True,
                                        include_hidden=False)
        sUtils.selectObjects([root] + objectlist, clear=True, active=0)
        models.loadPose(selected_robot.robot_name, selected_robot.label)
        parameter = self.decimate_ratio
        if self.decimate_type == 'UNSUBDIV':
            parameter = self.decimate_iteration
        elif self.decimate_type == 'DISSOLVE':
            parameter = self.decimate_angle_limit
        exporter.bakeModel(objectlist,
                           root['modelname'],
                           selected_robot.label,
                           decimate_type=self.decimate_type,
                           decimate_parameter=parameter)
        sUtils.selectObjects([root] + objectlist, clear=True, active=0)
        bpy.ops.scene.reload_models_and_poses_operator()
        return {'FINISHED'}
Example #12
0
def storePose(modelname, posename):
    """
    Stores the current pose of all of a robot's selected joints.
    Existing poses of the same name will be overwritten.

    :param modelname: The robot the pose belongs to.
    :type modelname: str.
    :param posename: The name the pose will be stored under.
    :type posename: str.
    :return: Nothing.
    """
    rootlink = None
    for root in sUtils.getRoots():
        if root['modelname'] == modelname:
            rootlink = root
    if rootlink:
        filename = modelname + '::poses'
        posedict = yaml.load(bUtils.readTextFile(filename))
        if not posedict:
            posedict = {posename: {'name': posename, 'joints': {}}}
        else:
            posedict[posename] = {'name': posename, 'joints': {}}
        bpy.ops.object.mode_set(mode='POSE')
        links = sUtils.getChildren(rootlink, ('link', ), True, False)
        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
        bUtils.updateTextFile(filename,
                              yaml.dump(posedict, default_flow_style=False))
    else:
        log("No model root could be found to store the pose for", "ERROR")
Example #13
0
 def execute(self, context):
     selection = []
     if self.modelname:
         print("phobos: Selecting model", self.modelname)
         roots = selectionUtils.getRoots()
         for root in roots:
             if root["modelname"] == self.modelname:
                 selection = selectionUtils.getChildren(root)
     else:
         print("phobos: No model name provided, deriving from selection...")
         roots = set()
         for obj in bpy.context.selected_objects:
             print("Selecting", selectionUtils.getRoot(obj).name)
             roots.add(selectionUtils.getRoot(obj))
         for root in list(roots):
             selection.extend(selectionUtils.getChildren(root))
     selectionUtils.selectObjects(list(selection), True)
     return {'FINISHED'}
Example #14
0
 def execute(self, context):
     selection = []
     if self.modelname:
         print("phobos: Selecting model", self.modelname)
         roots = sUtils.getRoots()
         for root in roots:
             if root["modelname"] == self.modelname:
                 selection = sUtils.getChildren(root)
     else:
         print("phobos: No model name provided, deriving from selection...")
         roots = set()
         for obj in bpy.context.selected_objects:
             print("Selecting", sUtils.getRoot(obj).name)
             roots.add(sUtils.getRoot(obj))
         for root in list(roots):
             selection.extend(sUtils.getChildren(root))
     sUtils.selectObjects(list(selection), True)
     return {'FINISHED'}
Example #15
0
 def execute(self, context):
     startLog(self)
     objlist = context.selected_objects
     if self.complete:
         roots = list(set([selectionUtils.getRoot(obj) for obj in context.selected_objects]))
         if None in roots:
             roots.remove(None)
         objlist = [elem for sublist in [selectionUtils.getChildren(root) for root in roots] for elem in sublist]
     objnames = [o.name for o in bpy.data.objects]
     for obj in objlist:
         if "::" in obj.name:
             if namingUtils.namesAreExplicit({obj.name.split("::")[-1]}, objnames):
                 namingUtils.removeNamespace(obj)
             else:
                 log("Cannot remove namespace from " + obj.name + ". Name wouldn't be explicit", "ERROR")
         else:
             namingUtils.addNamespace(obj)
     endLog()
     return {'FINISHED'}
Example #16
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 root['modelname'] == 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'}
Example #17
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")
Example #18
0
def exportSMURFsScene(selected_only=True, subfolders=True): #TODO: Refactoring needed!!!
    """Exports all robots in a scene in *.smurfs format.
    :param selected_only: Decides if only models with selected root links are exported.
    :param subfolders: If True, the export is structured with subfolders for each model.
    """
    objects = {}
    models = {}  # models to be exported by name
    instances = [] #the instances to export
    for root in selectionUtils.getRoots():
        if (not (selected_only and not root.select)):
            if "modelname" in root:
                objects[root['modelname']] = selectionUtils.getChildren(root)
                if not root['modelname'] in models:
                    models[root['modelname']] = [root]
                else:
                    models[root['modelname']].append(root)
            elif "reference" in root:
                instances.append(root["reference"])
                if not root['reference'] in models:
                    models[root['reference']] = [root]
                else:
                    models[root['reference']].append(root)
    entities = []
    for modelname in models:
        entitylist = models[modelname]
        unnamed_entities = 0
        for entity in entitylist:
            if 'entityname' in entity:
                entityname = entity['entityname']
            else:
                entityname = modelname+'_'+str(unnamed_entities)
                unnamed_entities += 1
            entitypose = robotdictionary.deriveObjectPose(entity)
            uri = os.path.join(modelname, modelname+'.smurf') if subfolders else modelname+'.smurf'
            scenedict = {'name': entityname,
                         'type': 'smurf',
                         'file': uri,
                         'anchor': entity['anchor'] if 'anchor' in entity else 'none',
                         'position': entitypose['translation'],
                         'rotation': entitypose['rotation_quaternion'],
                         'pose': 'default'}  # TODO: implement multiple poses
            entities.append(scenedict)

    if bpy.data.worlds[0].relativePath:
        outpath = securepath(os.path.expanduser(os.path.join(bpy.path.abspath("//"), bpy.data.worlds[0].path)))
    else:
        outpath = securepath(os.path.expanduser(bpy.data.worlds[0].path))

    with open(os.path.join(outpath, bpy.data.worlds['World'].sceneName + '.smurfs'),
              'w') as outputfile:
        outputfile.write("# SMURF scene: '" + bpy.data.worlds['World'].sceneName
                         + "'; created " + datetime.now().strftime("%Y%m%d_%H:%M") + "\n")
        outputfile.write("# created with Phobos " + defs.version
                         + " - https://github.com/rock-simulation/phobos\n\n")
        outputfile.write(yaml.dump({'entities': entities}))

    for modelname in objects:
        smurf_outpath = securepath(os.path.join(outpath, modelname) if subfolders else outpath)
        selectionUtils.selectObjects(objects[modelname], True)
        export(smurf_outpath)

    for instance in set(instances).difference(set(objects)):
        libpath = os.path.join(os.path.dirname(__file__), "lib")
        if os.path.isdir(os.path.join(outpath, instance)):
            shutil.rmtree(os.path.join(outpath, instance))
        shutil.copytree(os.path.join(libpath, instance), os.path.join(outpath, instance))
Example #19
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
Example #20
0
def deriveModelDictionary(root, name='', objectlist=[]):
    """Returns a dictionary representation of a Phobos model.
    
    If name is not specified, it overrides the modelname in the root. If the modelname is not
    defined at all, 'unnamed' will be used instead.

    Args:
      root(bpy_types.Object): root object of the model
      name(str, optional): name for the derived model (Default value = '')
      objectlist(list: bpy_types.Object): objects to derive the model from
      objectlist: (Default value = [])

    Returns:

    """
    if root.phobostype not in ['link', 'submodel']:
        log(root.name + " is no valid 'link' or 'submodel' object.", "ERROR")
        return None

    # define model name
    if name:
        modelname = name
    elif 'model/name' in root:
        modelname = root['model/name']
    else:
        modelname = 'unnamed'

    # define model version
    if 'model/version' in root:
        modelversion = root['model/version']
    else:
        modelversion = 'undefined'

    modeldescription = bUtils.readTextFile('README.md')

    model = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'meshes': {},
        'lights': {},
        'groups': {},
        'chains': {},
        'date': datetime.now().strftime("%Y%m%d_%H:%M"),
        'name': modelname,
        'version': modelversion,
        'description': modeldescription,
    }

    log(
        "Creating dictionary for model '" + modelname + "' with root '" + root.name + "'.",
        'INFO',
        prefix="\n",
    )

    # create tuples of objects belonging to model
    if not objectlist:
        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))) + " total.", "INFO")
    for link in linklist:
        # parse link information (including inertia)
        model['links'][nUtils.getObjectName(link, 'link')] = deriveLink(
            link, logging=True, objectlist=objectlist
        )

        # parse joint and motor information
        if sUtils.getEffectiveParent(link):
            # joint may be None if link is a root
            # to prevent confusion links are always defining also joints
            jointdict = deriveJoint(link, logging=True, adjust=True)
            log("  Setting joint type '{}' for link.".format(jointdict['type']), 'DEBUG')
            # first check if we have motor information in the joint properties
            # if so they can be extended/overwritten by motor objects later on
            if '$motor' in jointdict:
                motordict = jointdict['$motor']
                # at least we need a type property
                if 'type' in motordict:
                    # if no name is given derive it from the joint
                    if not 'name' in motordict:
                        motordict["name"] = jointdict['name']
                    model['motors'][motordict['name']] = motordict
                    # link the joint by name:
                    motordict['joint'] = jointdict['name']
                del jointdict['$motor']

            model['joints'][jointdict['name']] = jointdict

            for mot in [child for child in link.children if child.phobostype == 'motor']:
                motordict = motormodel.deriveMotor(mot, jointdict)
                # motor may be None if no motor is attached
                if motordict:
                    log("  Added motor {} to link.".format(motordict['name']), 'DEBUG')
                    if motordict['name'] in model["motors"]:
                        model['motors'][motordict['name']].update(motordict)
                    else:
                        model['motors'][motordict['name']] = motordict

    # parse sensors and controllers
    sencons = [obj for obj in objectlist if obj.phobostype in ['sensor', 'controller']]
    log("Parsing sensors and controllers... {} total.".format(len(sencons)), 'INFO')
    for obj in sencons:
        props = deriveDictEntry(obj, names=True, objectlist=objectlist)
        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
            if mat:
                if mat.name not in model['materials']:
                    model['materials'][mat.name] = deriveMaterial(mat)
                    linkname = nUtils.getObjectName(
                        sUtils.getEffectiveParent(obj, ignore_selection=bool(objectlist))
                    )
                    model['links'][linkname]['visual'][nUtils.getObjectName(obj)][
                        'material'
                    ] = mat.name

    # 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
                #todo2.9: 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')
    #todo2.9: 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")

    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

    model['submechanisms'] = getSubmechanisms(root)

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

    # shorten numbers in dictionary to n decimalPlaces and return it
    log("Rounding numbers to {} digits.".format(ioUtils.getExpSettings().decimalPlaces), 'INFO')
    model = roundFloatsInDict(model, ioUtils.getExpSettings().decimalPlaces)
    log("Sorting objects.", 'DEBUG')
    model = sortListsInDict(model)

    return model
Example #21
0
def deriveModelDictionaryFromAssemblies(modelname):
    model = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'meshes': {},
        'lights': {},
        'groups': {},
        'chains': {}
    }
    model['date'] = datetime.now().strftime("%Y%m%d_%H:%M")
    model['name'] = modelname
    assemblies = [a for a in bpy.data.objects if a.phobostype == 'assembly']
    for a in assemblies:
        print('-----------------------', a.name, a['assemblyname'], '\n')
        rootlink = [
            r for r in bpy.data.objects
            if sUtils.isRoot(r) and r['modelname'] == a['assemblyname']
        ][0]
        adict = buildModelDictionary(rootlink)
        for l in adict['links']:
            model['links'][namespaced(l, a.name)] = namespaceLink(
                adict['links'][l], a.name)
        for j in adict['joints']:
            model['joints'][namespaced(j, a.name)] = namespaceJoint(
                adict['joints'][j], a.name)
        for m in adict['motors']:
            model['motors'][namespaced(m, a.name)] = namespaceMotor(
                adict['motors'][m], a.name)
        for mat in adict['materials']:
            if mat not in model['materials']:
                model['materials'][mat] = adict['materials'][mat]
        for mesh in adict['meshes']:
            model['meshes'][namespaced(mesh, a.name)] = adict['meshes'][mesh]
        print('\n\n')
    for a in assemblies:
        rootlink = [
            r for r in bpy.data.objects
            if sUtils.isRoot(r) and r['modelname'] == a['assemblyname']
        ][0]
        if a.parent:
            #print('combining...:', a.name)
            #print([l for l in model['links']])
            parentassemblyname = a.parent.parent.parent['assemblyname']
            #print(parentassemblyname)
            parentinterfacename = a.parent.parent['interface/name']
            #print(parentinterfacename)
            parentassembly = [
                r for r in bpy.data.objects
                if sUtils.isRoot(r) and r['modelname'] == parentassemblyname
            ][0]
            #print(parentassembly)
            parentinterface = [
                i for i in sUtils.getChildren(parentassembly, ('interface', ))
                if i['interface/name'] == parentinterfacename
            ][0]
            #print(parentinterface)
            parentlinkname = parentinterface.parent.name
            #print(parentlinkname)

            # derive link pose for root link
            matrix = eUtils.getCombinedTransform(a, a.parent.parent.parent)
            pose = {
                'rawmatrix': matrix,
                'matrix': [list(vector) for vector in list(matrix)],
                'translation': list(matrix.to_translation()),
                'rotation_euler': list(matrix.to_euler()),
                'rotation_quaternion': list(matrix.to_quaternion())
            }
            model['links'][namespaced(rootlink.name, a.name)]['pose'] = pose

            # derive additional joint
            model['joints'][a.name] = deriveJoint(rootlink)
            #print(yaml.dump(model['joints'][a.name]))
            model['joints'][a.name]['name'] = namespaced(rootlink.name, a.name)
            model['joints'][a.name]['parent'] = namespaced(
                parentlinkname, a.parent.parent.parent.name)
            model['joints'][a.name]['child'] = namespaced(
                rootlink.name, a.name)
            #print(yaml.dump(model['joints'][a.name]))
        #print('######################')
        #for j in model['joints']:
        #    print(model['joints'][j]['name'], model['joints'][j]['child'], model['joints'][j]['child'])
        #print('######################')
    return model
Example #22
0
    def execute(self, context):
        """

        Args:
          context: 

        Returns:

        """
        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()

        # TODO: Move mesh export to individual formats? This is practically SMURF
        # export meshes in selected formats
        # for meshtype in meshes.mesh_types:
        #     mesh_path = ioUtils.getOutputMeshpath(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)
        #     except KeyError:
        #         log("No export function available for selected mesh function: " + meshtype,
        #             "ERROR", "ExportModelOperator")
        #         print(sys.exc_info()[0])

        # TODO: Move texture export to individual formats? This is practically SMURF
        # export textures
        # if ioUtils.textureExportEnabled():
        #     texture_path = ''
        #     for materialname in model['materials']:
        #         mat = model['materials'][materialname]
        #         for texturetype in ['diffuseTexture', 'normalTexture', 'displacementTexture']:
        #             if texturetype in mat:
        #                 texpath = os.path.join(os.path.expanduser(bpy.path.abspath('//')), mat[texturetype])
        #                 if os.path.isfile(texpath):
        #                     if texture_path == '':
        #                         texture_path = securepath(os.path.join(export_path, 'textures'))
        #                         log("Exporting textures to " + texture_path, "INFO", "ExportModelOperator")
        #                     try:
        #                         shutil.copy(texpath, os.path.join(texture_path, os.path.basename(mat[texturetype])))
        #                     except shutil.SameFileError:
        #                         log("{} already in place".format(texturetype), "INFO", "ExportModelOperator")
        # report success to user
        log("Export successful.", "INFO", end="\n\n")
        return {'FINISHED'}
Example #23
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
Example #24
0
def deriveModelDictionaryFromSubmodel(modelname):
    model = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'meshes': {},
        'lights': {},
        'groups': {},
        'chains': {}
    }

    # collect general model properties
    model['date'] = datetime.now().strftime("%Y%m%d_%H:%M")
    model['name'] = modelname

    # collect all submodels
    submodels = [a for a in bpy.data.objects if a.phobostype == 'submodel']

    # namespace links, joints, motors etc for each submodel
    for subm in submodels:
        print('-----------------------', subm.name, subm['submodelname'], '\n')
        rootlink = [
            r for r in bpy.data.objects
            if sUtils.isRoot(r) and r['modelname'] == subm['submodelname']
        ][0]
        adict = buildModelDictionary(rootlink)
        for l in adict['links']:
            model['links'][namespaced(l, subm.name)] = namespaceLink(
                adict['links'][l], subm.name)
        for j in adict['joints']:
            model['joints'][namespaced(j, subm.name)] = namespaceJoint(
                adict['joints'][j], subm.name)
        for m in adict['motors']:
            model['motors'][namespaced(m, subm.name)] = namespaceMotor(
                adict['motors'][m], subm.name)
        for mat in adict['materials']:
            if mat not in model['materials']:
                model['materials'][mat] = adict['materials'][mat]
        for mesh in adict['meshes']:
            model['meshes'][namespaced(mesh,
                                       subm.name)] = adict['meshes'][mesh]
        print('\n\n')

    for subm in submodels:
        rootlink = [
            r for r in bpy.data.objects
            if sUtils.isRoot(r) and r['modelname'] == subm['submodelname']
        ][0]
        if subm.parent:
            # get interfaces and parents
            parentsubmodelname = subm.parent.parent.parent['submodelname']
            parentinterfacename = subm.parent.parent['interface/name']
            parentsubmodel = [
                r for r in bpy.data.objects
                if sUtils.isRoot(r) and r['modelname'] == parentsubmodelname
            ][0]
            parentinterface = [
                i for i in sUtils.getChildren(parentsubmodel, ('interface', ))
                if i['interface/name'] == parentinterfacename
            ][0]
            parentlinkname = parentinterface.parent.name

            # derive link pose for root link
            matrix = eUtils.getCombinedTransform(subm,
                                                 subm.parent.parent.parent)
            pose = {
                'rawmatrix': matrix,
                'matrix': [list(vector) for vector in list(matrix)],
                'translation': list(matrix.to_translation()),
                'rotation_euler': list(matrix.to_euler()),
                'rotation_quaternion': list(matrix.to_quaternion())
            }
            model['links'][namespaced(rootlink.name, subm.name)]['pose'] = pose

            # derive additional joint
            model['joints'][a.name] = deriveJoint(rootlink)
            #print(yaml.dump(model['joints'][a.name]))
            model['joints'][a.name]['name'] = namespaced(rootlink.name, a.name)
            model['joints'][a.name]['parent'] = namespaced(
                parentlinkname, a.parent.parent.parent.name)
            model['joints'][a.name]['child'] = namespaced(
                rootlink.name, a.name)
            #print(yaml.dump(model['joints'][a.name]))
        #print('######################')
        #for j in model['joints']:
        #    print(model['joints'][j]['name'], model['joints'][j]['child'], model['joints'][j]['child'])
        #print('######################')
    return model
Example #25
0
def deriveModelDictionary(root, name='', objectlist=[]):
    """Returns a dictionary representation of a Phobos model.

    If name is not specified, it overrides the modelname in the root. If the modelname is not
    defined at all, 'unnamed' will be used instead.

    Args:
        root(bpy_types.Object): root object of the model
        name(str): name for the derived model
        objectlist(list: bpy_types.Object): objects to derive the model from
    """
    if root.phobostype not in ['link', 'submodel']:
        log(root.name + " is no valid 'link' or 'submodel' object.", "ERROR")
        return None

    # define model name
    if name:
        modelname = name
    elif 'modelname' in root:
        modelname = root['modelname']
    else:
        modelname = 'unnamed'

    model = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'meshes': {},
        'lights': {},
        'groups': {},
        'chains': {},
        'date': datetime.now().strftime("%Y%m%d_%H:%M"),
        'name': modelname
    }

    log(
        "Creating dictionary for model '" + modelname + "' with root '" +
        root.name + "'.", 'INFO')

    # create tuples of objects belonging to model
    if not objectlist:
        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))) +
        " total.", "INFO")
    for link in linklist:
        # parse link information (including inertia)
        model['links'][nUtils.getObjectName(link, 'link')] = deriveLink(link)

        if sUtils.getEffectiveParent(link):
            # joint may be None if link is a root
            jointdict = deriveJoint(link)
            model['joints'][jointdict['name']] = jointdict

            motordict = deriveMotor(link, jointdict)
            # motor may be None if no motor is attached
            if motordict:
                model['motors'][motordict['name']] = motordict

    # combine inertia for each link, taking into account inactive links
    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, ignore_selection=bool(objectlist))
            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

        # get inertia data
        mass, com, inertia = inertiamodel.fuse_inertia_data(inertials)
        if not any(mass, com, inertia):
            continue

        # add inertia to model
        inertia = inertiamodel.inertiaMatrixToList(inertia)
        model['links'][linkname]['inertial'] = {
            'mass': mass,
            'inertia': inertia,
            'pose': {
                'translation': list(com),
                '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:
        if obj.phobostype in ['visual', 'collision']:
            props = deriveDictEntry(obj)
            parentname = nUtils.getObjectName(
                sUtils.getEffectiveParent(obj,
                                          ignore_selection=bool(objectlist)))
            model['links'][parentname][obj.phobostype][nUtils.getObjectName(
                obj)] = props
        elif obj.phobostype == 'approxsphere':
            props = deriveDictEntry(obj)
            parentname = nUtils.getObjectName(
                sUtils.getEffectiveParent(obj,
                                          ignore_selection=bool(objectlist)))
            model['links'][parentname]['approxcollision'].append(props)

    # 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
            if mat:
                if mat.name not in model['materials']:
                    model['materials'][mat.name] = deriveMaterial(mat)
                    linkname = nUtils.getObjectName(
                        sUtils.getEffectiveParent(
                            obj, ignore_selection=bool(objectlist)))
                    model['links'][linkname]['visual'][nUtils.getObjectName(
                        obj)]['material'] = mat.name

    # 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")

    def getSubmechanisms(link):
        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

    model['submechanisms'] = getSubmechanisms(root)

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

    # shorten numbers in dictionary to n decimalPlaces and return it
    log("Rounding numbers...", "INFO")
    return roundFloatsInDict(model, ioUtils.getExpSettings().decimalPlaces)
Example #26
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)
Example #27
0
    def execute(self, context):
        """

        Args:
          context:

        Returns:

        """
        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()

        # TODO: Move mesh export to individual formats? This is practically SMURF
        # export meshes in selected formats
        # for meshtype in meshes.mesh_types:
        #     mesh_path = ioUtils.getOutputMeshpath(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)
        #     except KeyError:
        #         log("No export function available for selected mesh function: " + meshtype,
        #             "ERROR", "ExportModelOperator")
        #         print(sys.exc_info()[0])

        # TODO: Move texture export to individual formats? This is practically SMURF
        # export textures
        # if ioUtils.textureExportEnabled():
        #     texture_path = ''
        #     for materialname in model['materials']:
        #         mat = model['materials'][materialname]
        #         for texturetype in ['diffuseTexture', 'normalTexture', 'displacementTexture']:
        #             if texturetype in mat:
        #                 texpath = os.path.join(os.path.expanduser(bpy.path.abspath('//')), mat[texturetype])
        #                 if os.path.isfile(texpath):
        #                     if texture_path == '':
        #                         texture_path = securepath(os.path.join(export_path, 'textures'))
        #                         log("Exporting textures to " + texture_path, "INFO", "ExportModelOperator")
        #                     try:
        #                         shutil.copy(texpath, os.path.join(texture_path, os.path.basename(mat[texturetype])))
        #                     except shutil.SameFileError:
        #                         log("{} already in place".format(texturetype), "INFO", "ExportModelOperator")
        # report success to user
        log("Export successful.", "INFO", end="\n\n")
        return {'FINISHED'}
Example #28
0
def deriveModelDictionary(root, name='', objectlist=[]):
    """Derives a dictionary representation of a Phobos model.

    If name is not specified, it overrides the modelname in the root. If the modelname is not
    defined at all, 'unnamed' will be used instead.

    :param root: root object of the model
    :type root: bpy.types.Object
    :param name: name for the derived model
    :type name: str
    :param objectlist: objects to derive the model from
    :type objectlist: list of bpy.types.Object

    :return: representation of the model based on the root object
    :rtype: dict
    """
    if root.phobostype not in ['link', 'submodel']:
        log(root.name + " is no valid 'link' or 'submodel' object.", "ERROR")
        return None

    # define model name
    if name:
        modelname = name
    elif 'modelname' in root:
        modelname = root['modelname']
    else:
        modelname = 'unnamed'

    model = {
        'links': {},
        'joints': {},
        'sensors': {},
        'motors': {},
        'controllers': {},
        'materials': {},
        'meshes': {},
        'lights': {},
        'groups': {},
        'chains': {},
        'date': datetime.now().strftime("%Y%m%d_%H:%M"),
        'name': modelname
    }

    log(
        "Creating dictionary for model " + modelname + " with root " +
        root.name + ".", 'INFO')

    # create tuples of objects belonging to model
    if not objectlist:
        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))) +
        " total.", "INFO")
    for link in linklist:
        # parse link information (including inertia)
        model['links'][nUtils.getObjectName(link, 'link')] = derive_link(link)

        if sUtils.getEffectiveParent(link):
            # joint may be None if link is a root
            jointdict = deriveJoint(link)
            model['joints'][jointdict['name']] = jointdict

            motordict = deriveMotor(link, jointdict)
            # motor may be None if no motor is attached
            if motordict:
                model['motors'][motordict['name']] = motordict

    # TODO what was this supposed to do?
    # as it is only ever used by deriveSubmechanism we might want to move it...?

    # combine inertia if certain objects are left out, and overwrite it
    # inertials = (i for i in objectlist if i.phobostype == 'inertial' and 'inertia' in i)
    # editlinks = {}

    # for i in inertials:
    #     if i.parent not in linklist:
    #         realparent = sUtils.getEffectiveParent(i, ignore_selection=bool(objectlist))
    #         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

    #     # get inertia data
    #     mass, com, inertia = inertiamodel.fuse_inertia_data(inertials)
    #     if not any(mass, com, inertia):
    #         continue

    #     # add inertia to model
    #     inertia = inertiamodel.inertiaMatrixToList(inertia)
    #     model['links'][linkname]['inertial'] = {
    #         'mass': mass, 'inertia': inertia,
    #         'pose': {'translation': list(com),
    #                  '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:
        if obj.phobostype in ['visual', 'collision']:
            props = deriveDictEntry(obj)
            parentname = nUtils.getObjectName(
                sUtils.getEffectiveParent(obj,
                                          ignore_selection=bool(objectlist)))
            model['links'][parentname][obj.phobostype][nUtils.getObjectName(
                obj)] = props
        elif obj.phobostype == 'approxsphere':
            props = deriveDictEntry(obj)
            parentname = nUtils.getObjectName(
                sUtils.getEffectiveParent(obj,
                                          ignore_selection=bool(objectlist)))
            model['links'][parentname]['approxcollision'].append(props)

    # 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, ignore_selection=bool(objectlist)))
                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:
            indep = [
                nUtils.getObjectName(j, 'joint')
                for j in link['submechanism/independent']
            ]
            spann = [
                nUtils.getObjectName(j, 'joint')
                for j in link['submechanism/spanningtree']
            ]
            active = [
                nUtils.getObjectName(j, 'joint')
                for j in link['submechanism/active']
            ]
            submech = {
                'type': link['submechanism/type'],
                'contextual_name': link['submechanism/name'],
                'jointnames_independent': indep,
                'jointnames_spanningtree': spann,
                'jointnames_active': 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
    return roundFloatsInDict(model, ioUtils.getExpSettings().decimalPlaces)
Example #29
0
def deriveEntity(entity, outpath, savetosubfolder):
    """Derives the dictionary for a SMURF entity from the phobos model dictionary.

    :param entity: The smurf root object.
    :type entity: bpy.types.Object
    :param outpath: The path to export the smurf to.
    :type outpath: str
    :param savetosubfolder: If True the export path has a subfolder for this smurf entity.
    :type savetosubfolder: bool
    :return: dict - An entry for the scenes entitiesList

    """

    smurf = entity

    # determine outpath for the smurf export
    # differentiate between full model and baked reference
    if "entity/isReference" in smurf:
        bpy.ops.scene.reload_models_and_poses_operator()
        modelsPosesColl = bpy.context.user_preferences.addons[
            "phobos"].preferences.models_poses
        for robot_model in modelsPosesColl:
            if (smurf["modelname"]
                    == robot_model.robot_name) and (smurf["entity/pose"]
                                                    == robot_model.label):
                entitypose = models.deriveObjectPose(smurf)
                entry = models.initObjectProperties(smurf, 'entity',
                                                    ['link', 'joint', 'motor'])
                entry.pop("isReference")

                entry['file'] = os.path.join(
                    os.path.relpath(robot_model.path, outpath),
                    smurf["modelname"] + ".smurf")
                if 'parent' not in entry and 'joint/type' in smurf and smurf[
                        'joint/type'] == 'fixed':
                    entry['parent'] = 'world'
                entry["position"] = entitypose["translation"]
                entry["rotation"] = entitypose["rotation_quaternion"]
        '''
        with open(os.path.join(os.path.dirname(defs.__file__), "RobotLib.yml"), "r") as f:
            robots = yaml.load(f.read())
            sourcepath = robots[smurf["modelname"]]
            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:
        smurf_outpath = securepath(
            os.path.join(outpath, entity["modelname"]
                         ) if savetosubfolder else outpath)
        log("smurf_outpath: " + outpath, "DEBUG", "exportSMURFsScene")

        log(
            "Exporting " + smurf["entity/name"] + " as a smurf entity to " +
            smurf_outpath, "INFO", "deriveSMURFEntity", "\n\n")
        subfolder = smurf["modelname"] if savetosubfolder else ""
        sUtils.selectObjects(sUtils.getChildren(smurf),
                             clear=True)  # re-select for mesh export
        model, objectlist = models.buildModelDictionary(smurf)
        export(
            model, objectlist,
            smurf_outpath)  # FIXME: this is the export function from entities!
        entitypose = models.deriveObjectPose(smurf)
        entry = models.initObjectProperties(smurf, 'entity',
                                            ['link', 'joint', 'motor'])

        entry['file'] = (os.path.join(subfolder, smurf["modelname"] + ".smurf")
                         if os.path.isfile(smurf_outpath) else os.path.join(
                             subfolder, "smurf", smurf["modelname"] +
                             ".smurf"))
        if 'parent' not in entry and 'joint/type' in smurf and smurf[
                'joint/type'] == 'fixed':
            entry['parent'] = 'world'
        entry["position"] = entitypose["translation"]
        entry["rotation"] = entitypose["rotation_quaternion"]
    return entry