Skip to content



Bases: KinematicsMixin, RelativeObjectState, BooleanStateMixin

Source code in omnigibson/object_states/
class Overlaid(KinematicsMixin, RelativeObjectState, BooleanStateMixin):

    def get_dependencies(cls):
        deps = super().get_dependencies()
        return deps

    def _set_value(self, other, new_value):
        if not new_value:
            raise NotImplementedError("Overlaid does not support set_value(False)")
        state = og.sim.dump_state(serialized=False)

        if sample_cloth_on_rigid(self.obj, other, randomize_xy=False) and self.get_value(other):
            return True
            og.sim.load_state(state, serialized=False)

        return False

    def _get_value(self, other):
        Check whether the (cloth) object is overlaid on the other (rigid) object.
        First, the cloth object needs to be touching the rigid object.
        Then, the convex hull of the particles of the cloth object needs to cover a decent percentage of the
        base aligned bounding box of the other rigid object.
        if not (self.obj.prim_type == PrimType.CLOTH and other.prim_type == PrimType.RIGID):
            raise ValueError("Overlaid state requires obj1 is cloth and obj2 is rigid.")

        if not self.obj.states[Touching].get_value(other):
            return False

        # Compute the convex hull of the particles of the cloth object.
        points = self.obj.root_link.keypoint_particle_positions[:, :2]
        cloth_hull = ConvexHull(points)

        # Compute the base aligned bounding box of the rigid object.
        bbox_center, bbox_orn, bbox_extent, _ = other.get_base_aligned_bbox(xy_aligned=True)
        vertices_local = np.array(list(itertools.product((1, -1), repeat=3))) * (bbox_extent / 2)
        vertices = trimesh.transformations.transform_points(vertices_local, T.pose2mat((bbox_center, bbox_orn)))
        rigid_hull = ConvexHull(vertices[:, :2])

        # The goal is to find the intersection of the convex hull and the bounding box.
        # We can do so with HalfspaceIntersection, which takes as input a list of equations that define the half spaces,
        # and an interior point. We assume the center of the bounding box is an interior point.
        interior_pt = vertices.mean(axis=0)[:2]
        half_spaces = np.vstack((cloth_hull.equations, rigid_hull.equations))
            half_space_intersection = HalfspaceIntersection(half_spaces, interior_pt)
        except QhullError:
            # The bbox center of the rigid body does not lie in the intersection, return False.
            return False

        # Compute the ratio between the intersection area and the bounding box area in the x-y plane.
        # When input points are 2-dimensional, this is the area of the convex hull.
        # Ref:
        intersection_area = ConvexHull(half_space_intersection.intersections).volume
        rigid_xy_area = bbox_extent[0] * bbox_extent[1]

        return (intersection_area / rigid_xy_area) > m.OVERLAP_AREA_PERCENTAGE