From 306d2a9bb0d5a9130ffe7297fb73352c43cbc506 Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Thu, 12 Jan 2012 20:25:22 +0100 Subject: [PATCH 1/7] filler code cleaned, deprecation removed --- misc/geocouch-filler-js/geocouch-filler.js | 80 +++++++++---------- .../{lib => node_modules}/barrier.js | 0 2 files changed, 39 insertions(+), 41 deletions(-) rename misc/geocouch-filler-js/{lib => node_modules}/barrier.js (100%) diff --git a/misc/geocouch-filler-js/geocouch-filler.js b/misc/geocouch-filler-js/geocouch-filler.js index eff0c40..f8809de 100644 --- a/misc/geocouch-filler-js/geocouch-filler.js +++ b/misc/geocouch-filler-js/geocouch-filler.js @@ -6,71 +6,69 @@ var http = require('http'); var url = require('url'); var path = require('path'); - -require.paths.unshift(path.join(__dirname, 'lib')); var Barrier = require('barrier').Barrier; var httpClientPoolSize = 16; -var host,port,db; +var host, port, db; -if(process.argv.length < 5){ - console.log("\n\tUsage: node geocouch-filler.js <[bbox]> \n\n") - process.exit(1); +if (process.argv.length < 5) { + console.log("\n\tUsage: node geocouch-filler.js <[bbox]> \n\n") + process.exit(1); }; var uri = url.parse(process.argv[2] || "http://localhost:5984/gc-utils"); -var bbox = JSON.parse(process.argv[3] || "[-180,-90,180,90]") ; +var bbox = JSON.parse(process.argv[3] || "[-180,-90,180,90]"); var documentCount = parseInt(process.argv[4]) || 10; -if(uri && bbox && bbox.length === 4 && documentCount){ - host = uri.hostname; - port = uri.port || 5984; - db = uri.pathname.split("/")[1] || "gc-utils"; +if (uri && bbox && bbox.length === 4 && documentCount) { + host = uri.hostname; + port = uri.port || 5984; + db = uri.pathname.split("/")[1] || "gc-utils"; } -var randomArbitrary = function(min, max) { +var randomArbitrary = function (min, max) { return Math.random() * (max - min) + min; -}; + }; //create client pool to speed var clients = []; for (var i = 0; i < httpClientPoolSize; i++) { - clients.push(http.createClient(port, host)); + clients.push(http.createClient(port, host)); } //barrier allows to exit when queries have been executed -var b = new Barrier(documentCount, function() { - console.log("Insertion completed"); - process.exit(0); +var b = new Barrier(documentCount, function () { + console.log("Insertion completed"); + process.exit(0); }); var ptr = 0; for (var i = 0; i < documentCount; i++) { - var client = clients[ptr++ % httpClientPoolSize]; + var client = clients[ptr++ % httpClientPoolSize]; - var entity = { - "geometry" : { - "type" : "Point", - "coordinates": [randomArbitrary(bbox[0],bbox[2]),randomArbitrary(bbox[1],bbox[3])] - } - }; + var entity = { + "geometry": { + "type": "Point", + "coordinates": [randomArbitrary(bbox[0], bbox[2]), randomArbitrary(bbox[1], bbox[3])] + } + }; - var request = client.request('POST', "/" + db, { - "Content-Type": "application/json", - "Connection": "keep-alive" - }); - request.write(JSON.stringify(entity)); - request.end(); - request.once('response', function (response) { - if(response.statusCode === 201){ - console.log("Document "+response.headers['location']+" created"); - b.submit(); - } - else{ - console.log("POST caused "+response.statusCode+"!"); - b.submit(); - } - }); -} + var request = client.request('POST', "/" + db, { + "Content-Type": "application/json", + "Connection": "keep-alive" + }); + request.write(JSON.stringify(entity)); + request.end(); + request.once('response', function (response) { + + if (response.statusCode === 201) { + console.log("Document " + response.headers['location'] + " created"); + b.submit(); + } else { + console.log("POST caused " + response.statusCode + "!"); + b.submit(); + } + }); +} \ No newline at end of file diff --git a/misc/geocouch-filler-js/lib/barrier.js b/misc/geocouch-filler-js/node_modules/barrier.js similarity index 100% rename from misc/geocouch-filler-js/lib/barrier.js rename to misc/geocouch-filler-js/node_modules/barrier.js From 9a727185a42cf5efe310a32641769712eabf3853 Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Thu, 12 Jan 2012 21:10:06 +0100 Subject: [PATCH 2/7] class cleaned --- .../node_modules/barrier.js | 84 ++++++++----------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/misc/geocouch-filler-js/node_modules/barrier.js b/misc/geocouch-filler-js/node_modules/barrier.js index 59275ea..705fce7 100644 --- a/misc/geocouch-filler-js/node_modules/barrier.js +++ b/misc/geocouch-filler-js/node_modules/barrier.js @@ -1,57 +1,41 @@ /** -* A simple barrier point coordination class for node.js -* -* See http://www.ioexception.de/2010/07/05/barrier-points-in-node-js/ for more details. -* -* @author Benjamin Erb | http://www.benjamin-erb.de -* -*/ + * A simple barrier point coordination class for node.js + * + * See http://www.ioexception.de/2010/07/05/barrier-points-in-node-js/ for more details. + * + * @class Creates a new barrier for the given amount of parties. + * @param parties + * @param barrierCallback + * @param abortCallback + * @author Benjamin Erb | http://www.benjamin-erb.de + */ +var Barrier = exports.Barrier = function (parties, barrierCallback, abortCallback) { + this.parties = parties; + this.barrierCallback = barrierCallback; + this.abortCallback = abortCallback; -/** -* @class -* -* Creates a new barrier for the given amount of parties. -* @param parties -* @param barrierCallback -* @param abortCallback -* @return -*/ -var Barrier = exports.Barrier = function(parties, barrierCallback, abortCallback) -{ -this.parties = parties; -this.barrierCallback = barrierCallback; -this.abortCallback = abortCallback; - -this.running = true; -this.count = 0; -}; + this.running = true; + this.count = 0; + }; /** -* Signals a completion of one of the parties. -* @return -*/ -Barrier.prototype.submit = function() -{ -if (++this.count === this.parties && this.running) -{ -this.barrierCallback(); -} + * Signals a completion of one of the parties. + */ +Barrier.prototype.submit = function () { + if (++this.count === this.parties && this.running) { + this.barrierCallback(); + } }; /** -* Signals an abort by one of the parties. If not callback is passed, the default abort callback will be executed. -* @param customAbortCallback Optional callback that should be executed due to the abort. -* @return -*/ -Barrier.prototype.abort = function(customAbortCallback) -{ -if (this.running && customAbortCallback) -{ -customAbortCallback(); -} -else if (this.running && this.abortCallback) -{ -this.abortCallback(); -} -this.running = false; -}; + * Signals an abort by one of the parties. If not callback is passed, the default abort callback will be executed. + * @param customAbortCallback Optional callback that should be executed due to the abort. + */ +Barrier.prototype.abort = function (customAbortCallback) { + if (this.running && customAbortCallback) { + customAbortCallback(); + } else if (this.running && this.abortCallback) { + this.abortCallback(); + } + this.running = false; +}; \ No newline at end of file From 4de75e076f3f5a1883b92c143f90931b2f24b42a Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Thu, 12 Jan 2012 21:44:14 +0100 Subject: [PATCH 3/7] cleaned up --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 91ea5f5..3de441b 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,13 @@ Once you have the couchapp utility working, git clone this repo and ### [Spatial Views](https://github.com/couchbase/geocouch) -#### points.js +#### basic.js A spatial view that additionally emits the original GeoJSON value (doc.geometry) Example: - $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/points?bbox=80,88,90,90' + $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/basic?bbox=80,88,90,90' { "update_seq":203, "rows":[ @@ -56,13 +56,13 @@ Example: ] } -#### pointsFull.js +#### full.js -A spatial view that emits both GeoJSON and the full document (as value). +A spatial view that emits both GeoJSON and the full document (as value). Example: - $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/pointsFull?bbox=80,88,90,90' + $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/full?bbox=80,88,90,90' { "update_seq":203, "rows":[ @@ -89,13 +89,13 @@ Example: ] } -#### pointsOnly.js +#### minimal.js A spatial view that only emits GeoJSON and no additional value. Example: - $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/pointsOnly?bbox=80,88,90,90' + $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/minimal?bbox=80,88,90,90' { "update_seq":203, "rows":[ @@ -178,7 +178,7 @@ This list function generates a simple KML feed Example: - $ curl http://localhost:5984/yourdb/_design/geo/_spatiallist/kml/points?bbox=0,0,45,45 + $ curl http://localhost:5984/yourdb/_design/geo/_spatial/_list/kml/basic?bbox=0,0,45,45 @@ -198,7 +198,7 @@ This function outputs a GeoJSON FeatureCollection (compatible with OpenLayers). Example: - $curl -X GET 'http://localhost:5984/yourdb/_design/geo/_spatiallist/geojson/points?bbox=80,88,90,90' + $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/_list/geojson/basic?bbox=80,88,90,90' { "type":"FeatureCollection", "features":[ @@ -227,7 +227,7 @@ This will take the centroid of the bbox parameter and a supplied radius paramete Example: - $ curl -X GET http://localhost:5984/yourdb/_design/geo/_spatiallist/radius/points?bbox=-122.67,45.52,-122.67,45.52&radius=50 + $ curl 'http://localhost:5984/yourdb/_design/geo/_spatiallist/radius/points?bbox=-122.67,45.52,-122.67,45.52&radius=50' { "type":"FeatureCollection", "features":[ From 2fe71837d719fc823546e97b6a71f2f9be61962b Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Sun, 15 Jan 2012 10:33:03 +0100 Subject: [PATCH 4/7] list URL fixed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3de441b..e245c03 100644 --- a/README.md +++ b/README.md @@ -227,7 +227,7 @@ This will take the centroid of the bbox parameter and a supplied radius paramete Example: - $ curl 'http://localhost:5984/yourdb/_design/geo/_spatiallist/radius/points?bbox=-122.67,45.52,-122.67,45.52&radius=50' + $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/_list/radius/points?bbox=-122.67,45.52,-122.67,45.52&radius=50' { "type":"FeatureCollection", "features":[ From 08badcbcd4cc52e3a0cfeedc4e42cc39e4948c6a Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Sun, 15 Jan 2012 11:33:36 +0100 Subject: [PATCH 5/7] rewrite URL fixed --- couchapp/rewrites.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchapp/rewrites.json b/couchapp/rewrites.json index bd21df1..16e96b1 100644 --- a/couchapp/rewrites.json +++ b/couchapp/rewrites.json @@ -20,7 +20,7 @@ "from": "" }, { - "to": "/_spatiallist/geojson/full", + "to": "/_spatial/_list/geojson/full", "from": "/data" }, { From 3f0618859199e98a89aa5ab1177683a5efddaa93 Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Sun, 15 Jan 2012 11:39:40 +0100 Subject: [PATCH 6/7] view name fixed URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e245c03..2acc019 100644 --- a/README.md +++ b/README.md @@ -227,7 +227,7 @@ This will take the centroid of the bbox parameter and a supplied radius paramete Example: - $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/_list/radius/points?bbox=-122.67,45.52,-122.67,45.52&radius=50' + $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/_list/radius/basic?bbox=-122.67,45.52,-122.67,45.52&radius=50' { "type":"FeatureCollection", "features":[ From 513213bec1f329f47dc5a2206813316c368c5d67 Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Sun, 15 Jan 2012 12:39:36 +0100 Subject: [PATCH 7/7] efficient radius filtering for geometries --- README.md | 2 -- couchapp/_attachments/script/geojson-utils.js | 24 +++++++++++++++++++ couchapp/lists/radius.js | 3 +-- couchapp/vendor/geojson-utils.js | 24 +++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2acc019..f462eca 100644 --- a/README.md +++ b/README.md @@ -223,8 +223,6 @@ Example: This will take the centroid of the bbox parameter and a supplied radius parameter in meters and filter the rectangularly shaped bounding box result set by circular radius. -**WARNING** This only works with on points, not lines or polygons yet - Example: $ curl 'http://localhost:5984/yourdb/_design/geo/_spatial/_list/radius/basic?bbox=-122.67,45.52,-122.67,45.52&radius=50' diff --git a/couchapp/_attachments/script/geojson-utils.js b/couchapp/_attachments/script/geojson-utils.js index 5f1e671..3fbf393 100755 --- a/couchapp/_attachments/script/geojson-utils.js +++ b/couchapp/_attachments/script/geojson-utils.js @@ -139,6 +139,30 @@ return { 'type': 'Point', 'coordinates': [y/f, x/f] }; }, + // checks if geometry lies entirely within a circle + // works with Point, LineString, Polygon + gju.geometryWithinRadius = function (geometry, center, radius) { + if (geometry.type == 'Point') { + return gju.pointDistance(geometry, center) <= radius; + } else if (geometry.type == 'LineString' || geometry.type == 'Polygon') { + var point = {}; + var coordinates; + if (geometry.type == 'Polygon') { + // it's enough to check the exterior ring of the Polygon + coordinates = geometry.coordinates[0]; + } else { + coordinates = geometry.coordinates; + } + for (var i in coordinates) { + point.coordinates = coordinates[i]; + if (gju.pointDistance(point, center) > radius) { + return false; + } + } + } + return true; + } + gju.simplify = function (source, kink) { /* source[] array of geojson points */ /* kink in metres, kinks above this depth kept */ diff --git a/couchapp/lists/radius.js b/couchapp/lists/radius.js index 032c01e..dc4bbc6 100755 --- a/couchapp/lists/radius.js +++ b/couchapp/lists/radius.js @@ -16,7 +16,6 @@ function(head, req) { "coordinates": [[[bbox[0], bbox[1]], [bbox[2], bbox[3]]]] }), callback = req.query.callback, - circle = gju.drawCircle(radius, center), startedOutput = false; if (req.headers.Accept.indexOf('application/json') != -1) @@ -27,7 +26,7 @@ function(head, req) { if ('callback' in req.query) send(req.query['callback'] + "("); send('{"type": "FeatureCollection", "features":['); while (row = getRow()) { - if (gju.pointInPolygon(row.value.geometry, circle)) { + if (gju.geometryWithinRadius(row.value.geometry, center, radius)) { if (startedOutput) send(",\n"); out = '{"type": "Feature", "geometry": ' + JSON.stringify(row.value.geometry); delete row.value.geometry; diff --git a/couchapp/vendor/geojson-utils.js b/couchapp/vendor/geojson-utils.js index 5f1e671..3fbf393 100644 --- a/couchapp/vendor/geojson-utils.js +++ b/couchapp/vendor/geojson-utils.js @@ -139,6 +139,30 @@ return { 'type': 'Point', 'coordinates': [y/f, x/f] }; }, + // checks if geometry lies entirely within a circle + // works with Point, LineString, Polygon + gju.geometryWithinRadius = function (geometry, center, radius) { + if (geometry.type == 'Point') { + return gju.pointDistance(geometry, center) <= radius; + } else if (geometry.type == 'LineString' || geometry.type == 'Polygon') { + var point = {}; + var coordinates; + if (geometry.type == 'Polygon') { + // it's enough to check the exterior ring of the Polygon + coordinates = geometry.coordinates[0]; + } else { + coordinates = geometry.coordinates; + } + for (var i in coordinates) { + point.coordinates = coordinates[i]; + if (gju.pointDistance(point, center) > radius) { + return false; + } + } + } + return true; + } + gju.simplify = function (source, kink) { /* source[] array of geojson points */ /* kink in metres, kinks above this depth kept */