diff --git a/spatial-lib/README.md b/spatial-lib/README.md index 5d9117450c..f44f3b114a 100644 --- a/spatial-lib/README.md +++ b/spatial-lib/README.md @@ -1,7 +1,39 @@ # cmr-spatial-lib -A spatial library for the CMR. +A spatial library for the CMR. A collection of functions for managing and calculating geometrys. + +## Library + +(more should be said here) + +## Command line Interface + +A command line interface is available for getting direct access to some of the functions inside the library. This is used to ensure that external processing tools can use the exact same algorithum as is being used in CMR. Currently only one function is exposed: + +**find-lr**: "Finds the 'largest' interior rectangle (LR) of the polygon. This is not the provably largest interior rectangle for a polygon. It uses a simpler algorithm that works well for simple 4 point rings and less well for more points. It should always find a LR for any ring of arbitrary polygon." + +Usage example: + + cd spatial-lib + lein compile uberjar + java -Dclojure.warn.reflection=false + -jar target/cmr-spatial-lib-0.1.0-SNAPSHOT-standalone.jar + lr-json "POLYGON ((-124.409202 32.531669, -114.119061 32.531669, -114.119061 41.99954, -124.409202 41.99954, -124.409202 32.531669))" + java -Dclojure.warn.reflection=false + -jar cmr-spatial-lib-0.1.0-SNAPSHOT-standalone.jar cmr.spatial.runner + lr-json "POLYGON((-124.409202 32.531669, -114.119061 32.531669, -114.119061 41.99954, -124.409202 41.99954, -124.409202 32.531669))" + +| Command | Input | Output | Description +| ------- | --------------- | ---------------------------------------------- | ----------- +| lr-json | POLYGON((...))) | {"west":x1 ,"east":x2 ,"south":y1 ,"north":y1} | JSON bounding box of the Largest *internal* Rectangle +| lr-wkt | POLYGON((...))) | POLYGON((x1 y1, x2 y2, x3 y3, x4 y4, x1 y1)) | Well Known Text of the Largest *internal* Rectangle ## License -Copyright © 2021 NASA +Copyright © 2021-2024 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/spatial-lib/project.clj b/spatial-lib/project.clj index 35aaaa1c2f..189e4f0ca7 100644 --- a/spatial-lib/project.clj +++ b/spatial-lib/project.clj @@ -9,6 +9,7 @@ [org.clojure/math.combinatorics "0.1.4"] [pjstadig/assertions "0.2.0"] [primitive-math "0.1.4"]] + :main cmr.spatial.runner :plugins [[lein-shell "0.5.0"]] :global-vars {*warn-on-reflection* true} ;; The ^replace is done to disable the tiered compilation for accurate benchmarks diff --git a/spatial-lib/resources/multipolygon.txt b/spatial-lib/resources/multipolygon.txt new file mode 100644 index 0000000000..beb6c87490 --- /dev/null +++ b/spatial-lib/resources/multipolygon.txt @@ -0,0 +1,116 @@ +# A multi polygon for testing the lr-bin/find-lr function +MULTIPOLYGON ((( + -114.724285 32.712836, -117.125121 32.531669, -117.14981 32.646308, -117.166371 32.669501, + -117.223975 32.684714, -117.226186 32.697207, -117.205814 32.713403, -117.168058 32.698805, + -117.115089 32.600262, -117.102311 32.620468, -117.133209 32.689846, -117.177343 32.715031, + -117.174638 32.726732, -117.237834 32.707223, -117.236562 32.669623, -117.255279 32.691392, + -117.257556 32.784245, -117.283597 32.837654, -117.259874 32.854067, -117.253641 32.885081, + -117.27477 32.993476, -117.322161 33.108501, -117.508844 33.335205, -117.735219 33.484768, + -117.824574 33.561672, -117.978505 33.635972, -118.117387 33.743607, -118.20721 33.763834, + -118.192863 33.731729, -118.221506 33.770901, -118.254552 33.765401, -118.27677 33.756616, + -118.272206 33.715277, -118.291307 33.703208, -118.412041 33.741678, -118.427569 33.773731, + -118.395715 33.805654, -118.391388 33.835941, -118.444651 33.949408, -118.514068 34.022162, + -118.544057 34.038886, -118.666589 34.038945, -118.748392 34.031889, -118.806969 33.999406, + -118.852604 34.033657, -118.936807 34.0432, -119.089698 34.100484, -119.128653 34.100547, + -119.208323 34.152322, -119.217087 34.145502, -119.281158 34.268704, -119.391482 34.318445, + -119.460229 34.37404, -119.563175 34.414795, -119.678061 34.414385, -119.707879 34.395441, + -119.787649 34.417211, -119.878636 34.406613, -120.009968 34.461012, -120.133412 34.472724, + -120.293207 34.468486, -120.454107 34.442812, -120.472681 34.450273, -120.509986 34.521375, + -120.636627 34.562893, -120.647834 34.585676, -120.603054 34.704782, -120.640248 34.758531, + -120.615573 34.858003, -120.672839 34.907521, -120.633697 35.035102, -120.644887 35.13939, + -120.70637 35.174221, -120.749669 35.177397, -120.765534 35.160242, -120.876682 35.22379, + -120.897654 35.249766, -120.895591 35.273514, -120.862244 35.361905, -120.85558 35.321519, + -120.831405 35.336088, -120.86675 35.370993, -120.887318 35.432929, -120.908184 35.448244, + -121.005362 35.460657, -121.169402 35.636919, -121.195031 35.632336, -121.288313 35.66483, + -121.337232 35.786529, -121.463201 35.886731, -121.506678 36.00326, -121.566739 36.020117, + -121.677921 36.162675, -121.824859 36.239203, -121.852203 36.279446, -121.899661 36.3044, + -121.904168 36.384537, -121.94227 36.511901, -121.95693 36.517618, -121.927533 36.523852, + -121.932528 36.555129, -121.981115 36.583717, -121.96722 36.585213, -121.937695 36.639249, + -121.887421 36.601994, -121.870004 36.607212, -121.827061 36.6562, -121.805359 36.737739, + -121.763743 36.722073, -121.770215 36.739083, -121.803205 36.750459, -121.789812 36.806199, + -121.804246 36.836018, -121.859934 36.927476, -121.905601 36.969126, -121.937243 36.978307, + -121.974235 36.955199, -122.02121 36.962668, -122.046794 36.948157, -122.134991 36.965726, + -122.222118 37.024295, -122.297658 37.111227, -122.33929 37.118582, -122.369353 37.17402, + -122.404457 37.194526, -122.418363 37.25231, -122.400338 37.359741, -122.444446 37.437519, + -122.44916 37.476655, -122.479268 37.502783, -122.499263 37.493066, -122.520472 37.531421, + -122.522424 37.593217, -122.503233 37.601463, -122.49474 37.665229, -122.515172 37.781126, + -122.48593 37.790811, -122.476449 37.810675, -122.408637 37.810392, -122.354544 37.730008, + -122.392455 37.71033, -122.374911 37.655163, -122.38373 37.63146, -122.354142 37.613507, + -122.374109 37.604187, -122.250966 37.568061, -122.239576 37.546887, -122.199298 37.534962, + -122.207346 37.517483, -122.134145 37.497789, -122.100168 37.455064, -122.058909 37.447414, + -122.03214 37.463364, -122.052235 37.471381, -122.062367 37.501695, -122.109039 37.517971, + -122.14631 37.578968, -122.162779 37.664434, -122.191863 37.700313, -122.251766 37.722777, + -122.26235 37.743003, -122.212452 37.743484, -122.217293 37.758486, -122.331509 37.782388, + -122.325009 37.803751, -122.340657 37.807116, -122.295502 37.831292, -122.313902 37.885829, + -122.32876 37.908058, -122.391088 37.907675, -122.429698 37.964262, -122.397725 37.956117, + -122.359566 37.987649, -122.366306 38.012336, -122.299041 38.011198, -122.27557 38.039101, + -122.22704 38.058417, -122.147939 38.023627, -122.00399 38.056136, -121.690044 38.009119, + -121.681443 38.017453, -121.720606 38.032117, -121.681508 38.048326, -121.671132 38.083889, + -121.606679 38.099351, -121.582054 38.092, -121.576519 38.074307, -121.620623 38.061825, + -121.632239 38.044229, -121.61276 38.021491, -121.584243 38.02871, -121.569305 38.065844, + -121.445383 38.003892, -121.486562 38.044745, -121.548642 38.064206, -121.571278 38.097139, + -121.604075 38.10578, -121.680282 38.092691, -121.69933 38.050849, -121.742063 38.029449, + -121.778709 38.036019, -121.77985 38.061375, -121.716668 38.092807, -121.682602 38.147193, + -121.746978 38.087714, -121.80308 38.062883, -121.846118 38.072511, -121.89817 38.053221, + -121.928822 38.058417, -121.908315 38.078843, -121.971269 38.074918, -122.014955 38.098511 + -121.985992 38.110704, -122.000296 38.137312, -122.055165 38.133734, -122.13029 38.042142, + -122.184302 38.064789, -122.260888 38.069433, -122.300677 38.108196, -122.39652 38.153231, + -122.434131 38.123345, -122.502317 38.113521, -122.482488 38.076881, -122.50605 38.017172, + -122.445336 37.985123, -122.492543 37.969794, -122.480346 37.94182, -122.503593 37.940495, + -122.50344 37.924812, -122.438801 37.882083, -122.459009 37.862485, -122.499029 37.89359, + -122.470391 37.831832, -122.528426 37.816372, -122.645199 37.898816, -122.727738 37.90304, + -122.821432 37.99767, -122.921112 38.034871, -122.932696 38.049519, -122.920142 38.065312, + -122.948476 38.060736, -122.936086 38.03077, -122.97907 38.014516, -122.98033 37.998039, + -122.962504 37.992048, -123.027453 37.994489, -122.949648 38.143991, -122.996297 38.24273, + -122.825673 38.072089, -122.832265 38.095893, -122.968815 38.237094, -123.00228 38.294859, + -123.029522 38.312692, -123.06244 38.295903, -123.070932 38.359954, -123.128729 38.44931, + -123.336979 38.567259, -123.433607 38.686795, -123.726242 38.918576, -123.742607 38.955624, + -123.725242 38.960372, -123.689076 39.027899, -123.721649 39.133019, -123.76785 39.194007, + -123.824924 39.347296, -123.816509 39.443998, -123.769444 39.563728, -123.786828 39.596777, + -123.790582 39.677374, -123.83002 39.726514, -123.854019 39.833514, -123.907721 39.865867, + -123.930696 39.908018, -124.033458 40.012126, -124.076052 40.027217, -124.087442 40.077515, + -124.115793 40.107123, -124.185317 40.129551, -124.36351 40.261481, -124.348283 40.318907, + -124.409202 40.443818, -124.357981 40.563056, -124.239738 40.758709, -124.230885 40.750081, + -124.259498 40.69841, -124.22576 40.686123, -124.213845 40.701402, -124.220455 40.737238, + -124.202899 40.745186, -124.182743 40.799903, -124.121865 40.807383, -124.087398 40.825156, + -124.082483 40.843502, -124.154968 40.861727, -124.199745 40.784853, -124.223288 40.757096, + -124.232841 40.766643, -124.176575 40.847754, -124.110413 41.015253, -124.111412 41.04166, + -124.146878 41.060165, -124.164053 41.13222, -124.124262 41.181809, -124.062155 41.435876, + -124.082021 41.52147, -124.068349 41.539252, -124.103098 41.566555, -124.102773 41.602607, + -124.139882 41.664293, -124.159459 41.736675, -124.201107 41.739305, -124.262895 41.776428, + -124.218837 41.850006, -124.202219 41.960395, -124.214521 41.99954, -120.000751 41.99954, + -120.000018 38.999223, -118.126215 37.691337, -116.65954 36.58892, -114.628217 35.003569, + -114.616962 34.879301, -114.568622 34.843046, -114.542352 34.767875, -114.494257 34.753593, + -114.421112 34.634281, -114.419745 34.595951, -114.367206 34.530131, -114.368964 34.471537, + -114.12514 34.327787, -114.119061 34.293217, -114.224262 34.198075, -114.382147 34.12371, + -114.428583 34.029081, -114.515936 33.963627, -114.518842 33.929814, -114.489764 33.89058, + -114.515985 33.86912, -114.488055 33.725126, -114.517304 33.684745, -114.532611 33.568559, + -114.57934 33.520121, -114.625848 33.437138, -114.726898 33.411479, -114.698138 33.368412, + -114.723505 33.321244, -114.683173 33.262773, -114.673016 33.204985, -114.696747 33.08936, + -114.666815 33.054154, -114.501727 33.019413, -114.469794 32.972612, -114.460736 32.854911, + -114.522186 32.807133, -114.535858 32.738237, -114.578192 32.730082, -114.682929 32.7481, + -114.724285 32.712836)), ((-118.358766 32.827828, -118.350942 32.818671, -118.384181 32.824391, + -118.429043 32.802873, -118.49915 32.850628, -118.607215 33.030856, -118.564367 33.023762, + -118.504424 32.941329, -118.358766 32.827828)), ((-119.488604 33.267188, -119.434337 33.224012, + -119.472942 33.215324, -119.544188 33.23132, -119.578926 33.276097, -119.532103 33.286278, + -119.488604 33.267188)), ((-118.515654 33.423005, -118.572851 33.437907, -118.603913 33.476589, + -118.535861 33.477278, -118.49877 33.442666, -118.476901 33.447445, -118.369206 33.408393, + -118.368289 33.389003, -118.308665 33.33642, -118.30434 33.30904, -118.326035 33.298633, + -118.374796 33.319512, -118.463586 33.323514, -118.489582 33.358499, -118.474872 33.382371, + -118.486346 33.415968, -118.515654 33.423005)), ((-120.044139 34.037273, -120.047004 34.003813, + -120.008337 33.979027, -119.980407 33.983467, -119.96883 33.941117, -119.999628 33.941479, + -120.109891 33.89314, -120.17561 33.922232, -120.248517 34.001127, -120.044139 34.037273 +)), +(( + -120.344582 34.046492, -120.318326 34.040055, -120.308301 34.0182, -120.449203 34.035866, + -120.369068 34.076225, -120.344582 34.046492)), ((-119.529426 34.025248, -119.559521 33.994309, + -119.657683 33.986062, -119.719512 33.959134, -119.817205 33.959338, -119.874109 33.980047, + -119.887069 34.008777, -119.877222 34.032483, -119.933019 34.060229, -119.917225 34.07882, + -119.806996 34.051947, -119.759263 34.055809, -119.68536 34.019871, -119.633183 34.013635, + -119.610079 34.039646, -119.564931 34.055325, -119.521494 34.034291, -119.529426 34.025248 +)), +(( + -118.234676 33.763153, -118.223919 33.756067, -118.243878 33.750844, -118.236346 33.728046, + -118.257629 33.716554, -118.24432 33.734291, -118.248994 33.749427, -118.268615 33.728931, + -118.267506 33.747029, -118.234676 33.763153 +))) diff --git a/spatial-lib/src/cmr/spatial/runner.clj b/spatial-lib/src/cmr/spatial/runner.clj new file mode 100644 index 0000000000..659c784d52 --- /dev/null +++ b/spatial-lib/src/cmr/spatial/runner.clj @@ -0,0 +1,71 @@ +(ns cmr.spatial.runner + "Create a command line interface to expose useful api calls for working with spatial data." + (:require + [cheshire.core :as json] + [cmr.spatial.lr-binary-search :as lr-bin] + [cmr.spatial.ring-relations :as ring-rel]) + (:gen-class)) + +(defn parse-polygon + "Take a raw string in the style of POLYGON((x1 y1, x2 y2, ...)) and return a vector of vectors of + doubles" + [polygon-str] + (vec (flatten (->> polygon-str + (re-seq #"-?\d+\.\d+") + (map #(Double/parseDouble %)) + (partition 2) + (mapv vec))))) + +(defn create-wkt-bbox + "Create a string in for a bbox in the WKT format." + ([obj] + (create-wkt-bbox (:west obj) (:east obj) (:south obj) (:north obj))) + ([west east south north] + (str "POLYGON((" + west " " south ", " + east " " south ", " + east " " north ", " + west " " north ", " + west " " south + "))"))) + +(defn polygon-string->box + "Take a raw string in the POLYGON(()) style and turn it into a bbox, a dictionary with east, + west, north, south edges." + [raw-string] + (let [polygon-str raw-string + polygon (parse-polygon polygon-str) + polygon-obj (ring-rel/ords->ring :cartesian polygon) + lr (lr-bin/find-lr polygon-obj)] + {:west (:west lr) :east (:east lr) :south (:south lr) :north (:north lr)})) + +;; A command line interface to run any utilitity in the spatial-lib package. Currently only +;; exposing the find-lr function. +(defn -main [& args] + (if (empty? args) + (println "Usage: action ") + (println + (case (first args) + "lr-wkt" (create-wkt-bbox (polygon-string->box (second args))) + "lr-json" (json/generate-string (polygon-string->box (second args))) + "Unknown action, try: lr-wkt or lr-json")))) + +(comment + + (def polygon-string + (str "POLYGON ((-124.409202 32.531669, -114.119061 32.531669, -114.119061 41.99954," + "-124.409202 41.99954, -124.409202 32.531669))")) + + ;; Run the command line interface with different parameters + (-main) + (-main "wrong") + (-main "lr-json" polygon-string) + (-main "lr-wkt" (slurp (io/resource "multipolygon.txt"))) + + ;; try out the parse function + (parse-polygon polygon-string) + + ;; call the find-lr directly and see what it returns + (lr-bin/find-lr (ring-rel/ords->ring :cartesian [0 0, 10 0, 10 10, 0 10, 0 0])) + + )