[gnome-maps/wip/mlundblad/replace-bbox-and-ensure-visible: 1/4] WIP: Add bounding box module




commit 48f60868aff2a95a76d32565750cb4f81cc2ce18
Author: Marcus Lundblad <ml update uu se>
Date:   Sat Feb 20 16:17:01 2021 +0100

    WIP: Add bounding box module

 src/boundingBox.js                   | 127 +++++++++++++++++++++++++++++
 src/org.gnome.Maps.src.gresource.xml |   1 +
 tests/boundingBoxTest.js             | 153 +++++++++++++++++++++++++++++++++++
 tests/meson.build                    |   4 +-
 4 files changed, 283 insertions(+), 2 deletions(-)
---
diff --git a/src/boundingBox.js b/src/boundingBox.js
new file mode 100644
index 00000000..009bf707
--- /dev/null
+++ b/src/boundingBox.js
@@ -0,0 +1,127 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * Copyright (c) 2021, Marcus Lundblad
+ *
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Marcus Lundblad <ml update uu se>
+ */
+
+const Constants = imports.constants;
+
+var BoundingBox = class {
+    constructor(params) {
+        /* default to a bounding box the "opposite" of covering the whole
+         * visible world, this way extending with a coordinate will ensure
+         * it is enlarged to fit that point
+         */
+        this._left = params?.left ?? Constants.MAX_LONGITUDE;
+        this._bottom = params?.bottom ?? Constants.MAX_LATITUDE;
+        this._right = params?.right ?? Constants.MIN_LONGITUDE;
+        this._top = params?.top ?? Constants.MIN_LATITUDE;
+    }
+
+    get top() {
+        return this._top;
+    }
+
+    set top(top) {
+        this._top = top;
+    }
+
+    get left() {
+        return this._left;
+    }
+
+    set left(left) {
+        this._left = left;
+    }
+
+    get bottom() {
+        return this._bottom;
+    }
+
+    set bottom(bottom) {
+        this._bottom = bottom;
+    }
+
+    get right() {
+        return this._right;
+    }
+
+    set right(right) {
+        this._right = right;
+    }
+
+    copy() {
+        let copy = new BoundingBox();
+
+        copy.top = this.top;
+        copy.left = this.left;
+        copy.bottom = this.bottom;
+        copy.right = this.right;
+
+        return copy;
+    }
+
+    getCenter() {
+        return [(this.right + this.left) / 2, (this.top + this.bottom) / 2];
+    }
+
+    compose(other) {
+        if (other.left < this.left)
+            this.left = other.left;
+
+        if (other.right > this.right)
+            this.right = other.right;
+
+        if (other.top > this.top)
+            this.top = other.top;
+
+        if (other.bottom < this.bottom)
+            this.bottom = other.bottom;
+    }
+
+    extend(latitude, longitude) {
+        if (longitude < this.left)
+            this.left = longitude;
+
+        if (latitude < this.bottom)
+            this.bottom = latitude;
+
+        if (longitude > this.right)
+            this.right = longitude;
+
+        if (latitude > this.top)
+            this.top = latitude;
+    }
+
+    isValid() {
+        return this.left < this.right && this.bottom < this.top &&
+               this.left >= Constants.MIN_LONGITUDE &&
+               this.left <= Constants.MAX_LONGITUDE &&
+               this.right >= Constants.MIN_LONGITUDE &&
+               this.right <= Constants.MAX_LONGITUDE &&
+               this.bottom >= Constants.MIN_LATITUDE &&
+               this.bottom <= Constants.MAX_LATITUDE &&
+               this.top >= Constants.MIN_LATITUDE &&
+               this.top <= Constants.MAX_LATITUDE;
+    }
+
+    covers(latitude, longitude) {
+        return (latitude >= this.bottom && latitude <= this.top) &&
+               (longitude >= this.left && longitude <= this.right);
+    }
+}
diff --git a/src/org.gnome.Maps.src.gresource.xml b/src/org.gnome.Maps.src.gresource.xml
index 70fa7df9..cec373ea 100644
--- a/src/org.gnome.Maps.src.gresource.xml
+++ b/src/org.gnome.Maps.src.gresource.xml
@@ -4,6 +4,7 @@
     <file>accountListBox.js</file>
     <file>address.js</file>
     <file>application.js</file>
+    <file>boundingBox.js</file>
     <file>checkIn.js</file>
     <file>checkInDialog.js</file>
     <file>color.js</file>
diff --git a/tests/boundingBoxTest.js b/tests/boundingBoxTest.js
new file mode 100644
index 00000000..d8a605e1
--- /dev/null
+++ b/tests/boundingBoxTest.js
@@ -0,0 +1,153 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * Copyright (c) 2020 Marcus Lundblad
+ *
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Marcus Lundblad <ml update uu se>
+ */
+
+const JsUnit = imports.jsUnit;
+
+const BoundingBox = imports.boundingBox;
+const Constants = imports.constants;
+
+function main() {
+    constructTest();
+    copyTest();
+    setTest();
+    getCenterTest();
+    composeTest();
+    extendTest();
+    isValidTest();
+    coversTest();
+}
+
+function constructTest() {
+    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
+                                             bottom: 59.0, right: 16.0 });
+
+    JsUnit.assertEquals(60.0, bbox.top);
+    JsUnit.assertEquals(15.0, bbox.left);
+    JsUnit.assertEquals(59.0, bbox.bottom);
+    JsUnit.assertEquals(16.0, bbox.right);
+
+    // test default values
+    bbox = new BoundingBox.BoundingBox();
+
+    JsUnit.assertEquals(Constants.MIN_LATITUDE, bbox.top);
+    JsUnit.assertEquals(Constants.MAX_LONGITUDE, bbox.left);
+    JsUnit.assertEquals(Constants.MAX_LATITUDE, bbox.bottom);
+    JsUnit.assertEquals(Constants.MIN_LONGITUDE, bbox.right);
+}
+
+function copyTest() {
+    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
+                                             bottom: 59.0, right: 16.0 });
+    let copy = bbox.copy();
+
+    // update original box
+    bbox.top = 65.0;
+    bbox.left = 16.0;
+    bbox.bottom = 55.0;
+    bbox.right = 17.0;
+
+    // copy should be uneffected
+    JsUnit.assertEquals(60.0, copy.top);
+    JsUnit.assertEquals(15.0, copy.left);
+    JsUnit.assertEquals(59.0, copy.bottom);
+    JsUnit.assertEquals(16.0, copy.right);
+}
+
+function setTest() {
+    let bbox = new BoundingBox.BoundingBox();
+
+    bbox.top = 0;
+    bbox.left = 0;
+    bbox.bottom = -10;
+    bbox.right = 10;
+
+    JsUnit.assertEquals(0.0, bbox.top);
+    JsUnit.assertEquals(0.0, bbox.left);
+    JsUnit.assertEquals(-10.0, bbox.bottom);
+    JsUnit.assertEquals(10.0, bbox.right);
+}
+
+function getCenterTest() {
+    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
+                                             bottom: 59.0, right: 16.0 });
+    let center = bbox.getCenter();
+
+    JsUnit.assertTrue(center instanceof Array);
+    JsUnit.assertEquals(2, center.length);
+    JsUnit.assertEquals(15.5, center[0]);
+    JsUnit.assertEquals(59.5, center[1]);
+}
+
+function composeTest() {
+    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
+                                             bottom: 59.0, right: 16.0 });
+    let other = new BoundingBox.BoundingBox({ top: 60.0, left: 14.0,
+                                              bottom: 59.0, right: 15.0 });
+
+    bbox.compose(other);
+
+    JsUnit.assertEquals(60.0, bbox.top);
+    JsUnit.assertEquals(14.0, bbox.left);
+    JsUnit.assertEquals(59.0, bbox.bottom);
+    JsUnit.assertEquals(16.0, bbox.right);
+}
+
+function extendTest() {
+    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
+                                             bottom: 59.0, right: 16.0 });
+
+    bbox.extend(58.0, 14.0);
+
+    JsUnit.assertEquals(60.0, bbox.top);
+    JsUnit.assertEquals(14.0, bbox.left);
+    JsUnit.assertEquals(58.0, bbox.bottom);
+    JsUnit.assertEquals(16.0, bbox.right);
+}
+
+function isValidTest() {
+    let valid = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
+                                              bottom: 59.0, right: 16.0 });
+
+    JsUnit.assertTrue(valid.isValid());
+
+    let unset = new BoundingBox.BoundingBox();
+
+    JsUnit.assertFalse(unset.isValid());
+
+    let overflowNorth = new BoundingBox.BoundingBox({ top: 100.0, left: 15.0,
+                                                      bottom: 0.0, right: 16.0 });
+
+    JsUnit.assertFalse(overflowNorth.isValid());
+
+    let flipped = new BoundingBox.BoundingBox({ top: 59.0, left: 16.0,
+                                                bottom: 60.0, right: 15.0 });
+
+    JsUnit.assertFalse(flipped.isValid());
+}
+
+function coversTest() {
+    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
+                                             bottom: 59.0, right: 16.0 });
+
+    JsUnit.assertTrue(bbox.covers(59.5, 15.5));
+    JsUnit.assertFalse(bbox.covers(0.0, 0.0));
+    JsUnit.assertFalse(bbox.covers(59.0, -180.0));
+}
diff --git a/tests/meson.build b/tests/meson.build
index d5942bde..2ba07ab0 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,5 +1,5 @@
-tests = ['addressTest', 'colorTest', 'osmNamesTest', 'timeTest',
-         'translationsTest', 'utilsTest', 'urlsTest']
+tests = ['addressTest', 'boundingBoxTest', 'colorTest', 'osmNamesTest',
+         'timeTest', 'translationsTest', 'utilsTest', 'urlsTest']
 
 foreach test : tests
   script_conf = configuration_data()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]