//  [python]
def containsObject(self, obj):
        """Check if this region's volume contains an :obj:`~scenic.core.object_types.Object`."""
        # PASS 1
        # Check if bounding boxes intersect. If not, volumes cannot intersect and so
        # the object cannot be contained in this region.
        range_overlaps = [
            (self.mesh.bounds[0, dim] <= obj.occupiedSpace.mesh.bounds[1, dim])
            and (obj.occupiedSpace.mesh.bounds[0, dim] <= self.mesh.bounds[1, dim])
            for dim in range(3)
        ]
        bb_overlap = all(range_overlaps)

        if not bb_overlap:
            return False

        # PASS 2
        # If this region is convex, first check if we contain all corners of the object's bounding box.
        # If so, return True. Otherwise, check if all points are contained and return that value.
        if self.isConvex:
            pq = trimesh.proximity.ProximityQuery(self.mesh)
            bb_distances = pq.signed_distance(obj.boundingBox.mesh.vertices)

            if n.all(bb_distances > 0):
                return True

            vertex_distances = pq.signed_distance(obj.occupiedSpace.mesh.vertices)

            return n.all(vertex_distances > 0)

        # PASS 3
        # Take the object's position if contained in the mesh, or a random sample otherwise.
        # Then check if the point is not in the region, return False if so. Otherwise, compute
        # the circumradius of the object from that point and see if the closest point on the
        # mesh is farther than the circumradius. If it is, then the object must be contained and
        # return True.

        # Get a candidate point from the object mesh. If the position of the object is in the mesh use that.
        # Otherwise try to sample a point as a candidate, skipping this pass if the sample fails.
        if obj.containsPoint(obj.position):
            obj_candidate_point = obj.position
        elif (
            len(
                samples := trimesh.sample.volume_mesh(
                    obj.occupiedSpace.mesh, obj.occupiedSpace.num_samples
                )
            )
            > 0
        ):
            obj_candidate_point = Vector(*samples[0])
        else:
            obj_candidate_point = None

        if obj_candidate_point is not None:
            # If this region doesn't contain the candidate point, it can't contain the object.
            if not self.containsPoint(obj_candidate_point):
                return False

            # Compute the circumradius of the object from the candidate point.
            obj_circumradius = numpy.max(
                numpy.linalg.norm(
                    obj.occupiedSpace.mesh.vertices - obj_candidate_point, axis=1
                )
            )

            # Compute the minimum distance from the region to this point.
            pq = trimesh.proximity.ProximityQuery(self.mesh)
            region_distance = abs(pq.signed_distance([obj_candidate_point])[0])

            if region_distance > obj_circumradius:
                return True

        # PASS 4
        # Take the region's center_mass if contained in the mesh, or a random sample otherwise.
        # Then get the circumradius of the region from that point and the farthest point on
        # the object from this point. If the maximum distance is greater than the circumradius,
        # return False.

        # Get a candidate point from the rgion mesh. If the center of mass of the region is in the mesh use that.
        # Otherwise try to sample a point as a candidate, skipping this pass if the sample fails.
        if self.containsPoint(Vector(*self.mesh.bounding_box.center_mass)):
            reg_candidate_point = Vector(*self.mesh.bounding_box.center_mass)
        elif len(samples := trimesh.sample.volume_mesh(self.mesh, self.num_samples)) > 0:
            reg_candidate_point = Vector(*samples[0])
        else:
            reg_candidate_point = None

        if reg_candidate_point is not None:
            # Calculate circumradius of the region from the candidate_point
            reg_circumradius = numpy.max(
                numpy.linalg.norm(self.mesh.vertices - reg_candidate_point, axis=1)
            )

            # Calculate maximum distance to the object.
            obj_max_distance = numpy.max(
                numpy.linalg.norm(
                    obj.occupiedSpace.mesh.vertices - reg_candidate_point, axis=1
                )
            )

            if obj_max_distance > reg_circumradius:
                return False

        # PASS 5
        # If the difference between the object's region and this region is empty,
        # i.e. obj_region - self_region = EmptyRegion, that means the object is
        # entirely contained in this region.
        diff_region = obj.occupiedSpace.difference(self)

        return isinstance(diff_region, EmptyRegion)