summaryrefslogtreecommitdiff
path: root/libs/canvas/test/group.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/canvas/test/group.cc')
-rw-r--r--libs/canvas/test/group.cc296
1 files changed, 296 insertions, 0 deletions
diff --git a/libs/canvas/test/group.cc b/libs/canvas/test/group.cc
new file mode 100644
index 0000000000..914b940c5e
--- /dev/null
+++ b/libs/canvas/test/group.cc
@@ -0,0 +1,296 @@
+#include "canvas/group.h"
+#include "canvas/types.h"
+#include "canvas/rectangle.h"
+#include "canvas/canvas.h"
+#include "group.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (GroupTest);
+
+/* Do some basic checks on the group's computation of its bounding box */
+void
+GroupTest::bounding_box ()
+{
+ /* a group with 4 rectangles in it */
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+ Rectangle b (canvas.root(), Rect (0, 33, 32, 64));
+ b.set_outline_width (0);
+ Rectangle c (canvas.root(), Rect (33, 0, 64, 32));
+ c.set_outline_width (0);
+ Rectangle d (canvas.root(), Rect (33, 33, 64, 64));
+ d.set_outline_width (0);
+ boost::optional<Rect> bbox = canvas.root()->bounding_box ();
+
+ /* check the bounding box */
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 64);
+ CPPUNIT_ASSERT (bbox.get().y1 == 64);
+
+ /* check that adding an item resets the bbox */
+ Rectangle e (canvas.root(), Rect (64, 64, 128, 128));
+ bbox = canvas.root()->bounding_box ();
+
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 128.25);
+ CPPUNIT_ASSERT (bbox.get().y1 == 128.25);
+}
+
+/* Check that a group containing only items with no bounding box itself has no bounding box */
+void
+GroupTest::null_bounding_box ()
+{
+ ImageCanvas canvas;
+
+ Group empty (canvas.root());
+
+ boost::optional<Rect> bbox = empty.bounding_box ();
+ CPPUNIT_ASSERT (!bbox.is_initialized ());
+}
+
+/* Do some basic tests on layering */
+void
+GroupTest::layers ()
+{
+ /* Set up 4 rectangles; order from the bottom is
+ a - b - c - d
+ */
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ Rectangle b (canvas.root(), Rect (0, 0, 32, 32));
+ Rectangle c (canvas.root(), Rect (0, 0, 32, 32));
+ Rectangle d (canvas.root(), Rect (0, 0, 32, 32));
+
+ /* Put a on top and check */
+ a.raise_to_top ();
+
+ list<Item*>::const_iterator i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &d);
+ CPPUNIT_ASSERT (*i++ == &a);
+
+ /* Put a on the bottom and check */
+ a.lower_to_bottom ();
+
+ i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &a);
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &d);
+
+ /* Check raise by a number of levels */
+
+ a.raise (2);
+
+ i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &a);
+ CPPUNIT_ASSERT (*i++ == &d);
+
+ a.raise (4);
+
+ i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &d);
+ CPPUNIT_ASSERT (*i++ == &a);
+}
+
+/* Check that groups notice when their children change */
+void
+GroupTest::children_changing ()
+{
+ ImageCanvas canvas;
+
+ /* Put a rectangle in the root group */
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+
+ /* Check that initial bbox */
+ boost::optional<Rect> bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 32);
+ CPPUNIT_ASSERT (bbox.get().y1 == 32);
+
+ /* Change the rectangle's size and check the parent */
+ a.set (Rect (0, 0, 48, 48));
+ bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48);
+
+ /* Change the rectangle's line width and check the parent */
+ a.set_outline_width (1);
+ bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == -0.5);
+ CPPUNIT_ASSERT (bbox.get().y0 == -0.5);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48.5);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48.5);
+}
+
+/* Check that a group notices when its grandchildren change */
+void
+GroupTest::grandchildren_changing ()
+{
+ ImageCanvas canvas;
+
+ /* Put a child group B in the root group */
+ Group B (canvas.root());
+
+ /* Grandchild rectangle */
+ Rectangle a (&B, Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+
+ /* Check the initial bboxes */
+ boost::optional<Rect> bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 32);
+ CPPUNIT_ASSERT (bbox.get().y1 == 32);
+
+ bbox = B.bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 32);
+ CPPUNIT_ASSERT (bbox.get().y1 == 32);
+
+ /* Change the grandchild and check its parent and grandparent */
+ a.set (Rect (0, 0, 48, 48));
+
+ bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48);
+
+ bbox = B.bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48);
+}
+
+/* Basic tests on the code to find items at a particular point */
+void
+GroupTest::add_items_at_point ()
+{
+ ImageCanvas canvas;
+
+ Group gA (canvas.root());
+ gA.set_position (Duple (128, 64));
+
+ Group gB (&gA);
+ gB.set_position (Duple (64, 32));
+
+ /* two rectangles in the same place, rB on top of rA */
+ Rectangle rA (&gB);
+ rA.set_position (Duple (4, 2));
+ rA.set (Rect (0, 0, 8, 4));
+ Rectangle rB (&gB);
+ rB.set_position (Duple (4, 2));
+ rB.set (Rect (0, 0, 8, 4));
+
+ /* rC below those two */
+ Rectangle rC (&gB);
+ rC.set_position (Duple (12, 6));
+ rC.set (Rect (0, 0, 8, 4));
+
+ vector<Item const *> items;
+ canvas.root()->add_items_at_point (Duple (128 + 64 + 4 + 4, 64 + 32 + 2 + 2), items);
+ CPPUNIT_ASSERT (items.size() == 5);
+ vector<Item const *>::iterator i = items.begin ();
+ CPPUNIT_ASSERT (*i++ == canvas.root ());
+ CPPUNIT_ASSERT (*i++ == &gA);
+ CPPUNIT_ASSERT (*i++ == &gB);
+ CPPUNIT_ASSERT (*i++ == &rA);
+ CPPUNIT_ASSERT (*i++ == &rB);
+
+ items.clear ();
+ canvas.root()->add_items_at_point (Duple (128 + 64 + 12 + 4, 64 + 32 + 6 + 2), items);
+ CPPUNIT_ASSERT (items.size() == 4);
+ i = items.begin ();
+ CPPUNIT_ASSERT (*i++ == canvas.root ());
+ CPPUNIT_ASSERT (*i++ == &gA);
+ CPPUNIT_ASSERT (*i++ == &gB);
+ CPPUNIT_ASSERT (*i++ == &rC);
+}
+
+static double
+double_random ()
+{
+ return ((double) rand() / RAND_MAX);
+}
+
+/* Check the find items at point code more thoroughly */
+void
+GroupTest::torture_add_items_at_point ()
+{
+ int const n_rectangles = 10000;
+ int const n_tests = 1000;
+ double const rough_size = 1000;
+ srand (1);
+
+ ImageCanvas canvas;
+
+ list<Item*> rectangles;
+
+ for (int i = 0; i < n_rectangles; ++i) {
+ Rectangle* r = new Rectangle (canvas.root());
+ double const x = double_random () * rough_size / 2;
+ double const y = double_random () * rough_size / 2;
+ double const w = double_random () * rough_size / 2;
+ double const h = double_random () * rough_size / 2;
+ r->set (Rect (x, y, x + w, y + h));
+ rectangles.push_back (r);
+ }
+
+ for (int i = 0; i < n_tests; ++i) {
+ Duple test (double_random() * rough_size, double_random() * rough_size);
+
+ /* ask the group what's at this point */
+ vector<Item const *> items_A;
+ canvas.root()->add_items_at_point (test, items_A);
+
+ /* work it out ourselves */
+ vector<Item*> items_B;
+ if (canvas.root()->bounding_box() && canvas.root()->bounding_box().get().contains (test)) {
+ items_B.push_back (canvas.root());
+ }
+
+ for (list<Item*>::iterator j = rectangles.begin(); j != rectangles.end(); ++j) {
+ boost::optional<Rect> bbox = (*j)->bounding_box ();
+ assert (bbox);
+ if (bbox.get().contains (test)) {
+ items_B.push_back (*j);
+ }
+ }
+
+ CPPUNIT_ASSERT (items_A.size() == items_B.size());
+ vector<Item const *>::iterator j = items_A.begin ();
+ vector<Item*>::iterator k = items_B.begin ();
+ while (j != items_A.end ()) {
+ CPPUNIT_ASSERT (*j == *k);
+ ++j;
+ ++k;
+ }
+ }
+}
+