Skip to content

folded

FoldedLevel

Bases: AbsoluteObjectState, ClothStateMixin

State representing the object's folded level. Value is a FoldedLevelData object.

Source code in omnigibson/object_states/folded.py
class FoldedLevel(AbsoluteObjectState, ClothStateMixin):
    """
    State representing the object's folded level.
    Value is a FoldedLevelData object.
    """
    def _initialize(self):
        super()._initialize()
        # Assume the initial state is unfolded
        self.area_unfolded, self.diagonal_unfolded = self.calculate_projection_area_and_diagonal_maximum()

    def _get_value(self):
        smoothness = self.calculate_smoothness()
        area, diagonal = self.calculate_projection_area_and_diagonal([0, 1])
        return FoldedLevelData(smoothness, area / self.area_unfolded, diagonal / self.diagonal_unfolded)

    def calculate_smoothness(self):
        """
        Calculate the percantage of surface normals that are sufficiently close to the z-axis.
        """
        cloth = self.obj.root_link
        normals = cloth.compute_face_normals(face_ids=cloth.keyface_idx)

        # projection onto the z-axis
        proj = np.abs(np.dot(normals, np.array([0.0, 0.0, 1.0])))
        percentage = np.mean(proj > np.cos(m.NORMAL_Z_ANGLE_DIFF))
        return percentage

    def calculate_projection_area_and_diagonal_maximum(self):
        """
        Calculate the maximum projection area and the diagonal length along different axes

        Returns:
            area_max (float): area of the convex hull of the projected points
            diagonal_max (float): diagonal of the convex hull of the projected points
        """
        # use the largest projection area as the unfolded area
        area_max = 0.0
        diagonal_max = 0.0
        dims_list = [[0, 1], [0, 2], [1, 2]]  # x-y plane, x-z plane, y-z plane

        for dims in dims_list:
            area, diagonal = self.calculate_projection_area_and_diagonal(dims)
            if area > area_max:
                area_max = area
                diagonal_max = diagonal

        return area_max, diagonal_max

    def calculate_projection_area_and_diagonal(self, dims):
        """
        Calculate the projection area and the diagonal length when projecting to the plane defined by the input dims
        E.g. if dims is [0, 1], the points will be projected onto the x-y plane.

        Args:
            dims (2-array): Global axes to project area onto. Options are {0, 1, 2}.
                E.g. if dims is [0, 1], project onto the x-y plane.

        Returns:
            area (float): area of the convex hull of the projected points
            diagonal (float): diagonal of the convex hull of the projected points
        """
        cloth = self.obj.root_link
        points = cloth.keypoint_particle_positions[:, dims]
        try:
            hull = ConvexHull(points)

        # The points may be 2D-degenerate, so catch the error and return 0 if so
        except QhullError:
            # This is a degenerate hull, so return 0 area and diagonal
            return 0.0, 0.0

        # When input points are 2-dimensional, this is the area of the convex hull.
        # Ref: https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.ConvexHull.html
        area = hull.volume
        diagonal = distance_matrix(points[hull.vertices], points[hull.vertices]).max()

        if m.DEBUG_CLOTH_PROJ_VIS:
            import matplotlib.pyplot as plt
            ax = plt.gca()
            ax.set_aspect('equal')

            plt.plot(points[:, dims[0]], points[:, dims[1]], 'o')
            for simplex in hull.simplices:
                plt.plot(points[simplex, dims[0]], points[simplex, dims[1]], 'k-')
            plt.plot(points[hull.vertices, dims[0]], points[hull.vertices, dims[1]], 'r--', lw=2)
            plt.plot(points[hull.vertices[0], dims[0]], points[hull.vertices[0], dims[1]], 'ro')
            plt.show()

        return area, diagonal

calculate_projection_area_and_diagonal(dims)

Calculate the projection area and the diagonal length when projecting to the plane defined by the input dims E.g. if dims is [0, 1], the points will be projected onto the x-y plane.

Parameters:

Name Type Description Default
dims 2 - array

Global axes to project area onto. Options are {0, 1, 2}. E.g. if dims is [0, 1], project onto the x-y plane.

required

Returns:

Name Type Description
area float

area of the convex hull of the projected points

diagonal float

diagonal of the convex hull of the projected points

Source code in omnigibson/object_states/folded.py
def calculate_projection_area_and_diagonal(self, dims):
    """
    Calculate the projection area and the diagonal length when projecting to the plane defined by the input dims
    E.g. if dims is [0, 1], the points will be projected onto the x-y plane.

    Args:
        dims (2-array): Global axes to project area onto. Options are {0, 1, 2}.
            E.g. if dims is [0, 1], project onto the x-y plane.

    Returns:
        area (float): area of the convex hull of the projected points
        diagonal (float): diagonal of the convex hull of the projected points
    """
    cloth = self.obj.root_link
    points = cloth.keypoint_particle_positions[:, dims]
    try:
        hull = ConvexHull(points)

    # The points may be 2D-degenerate, so catch the error and return 0 if so
    except QhullError:
        # This is a degenerate hull, so return 0 area and diagonal
        return 0.0, 0.0

    # When input points are 2-dimensional, this is the area of the convex hull.
    # Ref: https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.ConvexHull.html
    area = hull.volume
    diagonal = distance_matrix(points[hull.vertices], points[hull.vertices]).max()

    if m.DEBUG_CLOTH_PROJ_VIS:
        import matplotlib.pyplot as plt
        ax = plt.gca()
        ax.set_aspect('equal')

        plt.plot(points[:, dims[0]], points[:, dims[1]], 'o')
        for simplex in hull.simplices:
            plt.plot(points[simplex, dims[0]], points[simplex, dims[1]], 'k-')
        plt.plot(points[hull.vertices, dims[0]], points[hull.vertices, dims[1]], 'r--', lw=2)
        plt.plot(points[hull.vertices[0], dims[0]], points[hull.vertices[0], dims[1]], 'ro')
        plt.show()

    return area, diagonal

calculate_projection_area_and_diagonal_maximum()

Calculate the maximum projection area and the diagonal length along different axes

Returns:

Name Type Description
area_max float

area of the convex hull of the projected points

diagonal_max float

diagonal of the convex hull of the projected points

Source code in omnigibson/object_states/folded.py
def calculate_projection_area_and_diagonal_maximum(self):
    """
    Calculate the maximum projection area and the diagonal length along different axes

    Returns:
        area_max (float): area of the convex hull of the projected points
        diagonal_max (float): diagonal of the convex hull of the projected points
    """
    # use the largest projection area as the unfolded area
    area_max = 0.0
    diagonal_max = 0.0
    dims_list = [[0, 1], [0, 2], [1, 2]]  # x-y plane, x-z plane, y-z plane

    for dims in dims_list:
        area, diagonal = self.calculate_projection_area_and_diagonal(dims)
        if area > area_max:
            area_max = area
            diagonal_max = diagonal

    return area_max, diagonal_max

calculate_smoothness()

Calculate the percantage of surface normals that are sufficiently close to the z-axis.

Source code in omnigibson/object_states/folded.py
def calculate_smoothness(self):
    """
    Calculate the percantage of surface normals that are sufficiently close to the z-axis.
    """
    cloth = self.obj.root_link
    normals = cloth.compute_face_normals(face_ids=cloth.keyface_idx)

    # projection onto the z-axis
    proj = np.abs(np.dot(normals, np.array([0.0, 0.0, 1.0])))
    percentage = np.mean(proj > np.cos(m.NORMAL_Z_ANGLE_DIFF))
    return percentage