diff --git a/samples/04-object-properties/main.cc b/samples/04-object-properties/main.cc
index 3b56a04bd9f9068d4aae61e5aa5c4ecac319fe95..810c10782ee5f817ae401d320adf9bcedf7ddcd5 100644
--- a/samples/04-object-properties/main.cc
+++ b/samples/04-object-properties/main.cc
@@ -22,34 +22,60 @@ void test_obj(Obj const& obj)
             size = 100.f + length(obj);
 
         auto uniformPts = std::vector<tg::pos3>();
-        for (tg::u64 i = 0; i < size; ++i)
+        for (auto i = 0; i < size; ++i)
             uniformPts.emplace_back(uniform(rng, obj));
 
-        auto v = gv::view();
-
-        // uniform
-        gv::view(uniformPts, tg::to_string(obj));
-
-        // any_point
-        gv::view(gv::points(tg::pos3(any_point(obj))).point_size_px(12.f), tg::color4::red);
-
-        // centroid
-        auto const centroid = centroid_of(obj);
-        if (any_point(obj) == centroid)
-            gv::view(gv::points(tg::pos3(centroid)).point_size_px(13.f), tg::color4::yellow);
-        else
-            gv::view(gv::points(tg::pos3(centroid)).point_size_px(12.f), tg::color4::green);
-
-        // aabb_of
         auto const aabb = aabb_of(obj);
+        tg::aabb3 aabb3;
         if constexpr (domainD == 3)
-            gv::view(gv::lines(aabb));
+            aabb3 = aabb;
         else
-            gv::view(gv::lines(tg::aabb3(tg::pos3(aabb.min), tg::pos3(aabb.max))));
-
-        // normal_of
-        if constexpr (domainD == 3 && ((objectD == 2 && !tg::object_traits<Obj>::is_boundary) || (objectD == 1 && tg::object_traits<Obj>::is_boundary)))
-            gv::view(tg::segment3(centroid, centroid + normal_of(obj)), tg::color4::green);
+            aabb3 = tg::aabb3(tg::pos3(aabb.min), tg::pos3(aabb.max));
+
+        auto g = gv::grid();
+        {
+            auto v = gv::view();
+
+            // uniform
+            gv::view(uniformPts, tg::to_string(obj));
+
+            // any_point
+            gv::view(gv::points(tg::pos3(any_point(obj))).point_size_px(12.f), tg::color4::red);
+
+            // centroid
+            auto const centroid = centroid_of(obj);
+            if (any_point(obj) == centroid)
+                gv::view(gv::points(tg::pos3(centroid)).point_size_px(13.f), tg::color4::yellow);
+            else
+                gv::view(gv::points(tg::pos3(centroid)).point_size_px(12.f), tg::color4::green);
+
+            // aabb_of
+            gv::view(gv::lines(aabb3));
+
+            // normal_of
+            if constexpr (domainD == 3 && ((objectD == 2 && !tg::object_traits<Obj>::is_boundary) || (objectD == 1 && tg::object_traits<Obj>::is_boundary)))
+                gv::view(tg::segment3(centroid, centroid + normal_of(obj)), tg::color4::green);
+        }
+        {
+            auto const aabbBigger = tg::aabb(aabb.min - 0.25f, aabb.max + 0.25f);
+            auto pointsInside = std::vector<tg::pos3>();
+            auto pointsOutside = std::vector<tg::pos3>();
+            auto const numPts = tg::pow(20.f, domainD);
+            auto const tolerance = objectD < domainD ? 0.1f : 0.f;
+            for (auto i = 0; i < numPts; ++i)
+            {
+                auto const p = uniform(rng, aabbBigger);
+                if (contains(obj, p, tolerance))
+                    pointsInside.emplace_back(p);
+                else
+                    pointsOutside.emplace_back(p);
+            }
+
+            // contains
+            auto v = gv::view();
+            view(pointsInside, gv::maybe_empty, tg::color4::green);
+            gv::view(gv::points(pointsOutside).point_size_px(5.f));
+        }
     }
 }