Skip to content

Commit 96d82b0

Browse files
committed
use spatial index for most binary geom ops; #394 #76
1 parent 2134309 commit 96d82b0

1 file changed

Lines changed: 56 additions & 9 deletions

File tree

src/geos.cpp

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@
1414
#include "wkb.h"
1515

1616
typedef char (* log_fn)(GEOSContextHandle_t, const GEOSGeometry *, const GEOSGeometry *);
17-
typedef char (* log_prfn)(GEOSContextHandle_t, const GEOSPreparedGeometry *, const GEOSGeometry *);
17+
typedef char (* log_prfn)(GEOSContextHandle_t, const GEOSPreparedGeometry *,
18+
const GEOSGeometry *);
1819
typedef GEOSGeom (* geom_fn)(GEOSContextHandle_t, const GEOSGeom, const GEOSGeom);
1920

21+
void cb(void *item, void *userdata) { // callback function for tree selection
22+
std::vector<size_t> *ret = (std::vector<size_t> *) userdata;
23+
ret->push_back(*((size_t *) item));
24+
}
25+
2026
static void __errorHandler(const char *fmt, ...) { // #nocov start
2127

2228
char buf[BUFSIZ], *p;
@@ -193,9 +199,16 @@ Rcpp::List CPL_geos_binop(Rcpp::List sfc0, Rcpp::List sfc1, std::string op, doub
193199

194200
std::vector<GEOSGeom> gmv0 = geometries_from_sfc(hGEOSCtxt, sfc0, NULL);
195201
std::vector<GEOSGeom> gmv1 = geometries_from_sfc(hGEOSCtxt, sfc1, NULL);
202+
std::vector<size_t> items(gmv1.size());
196203

197204
Rcpp::List ret_list;
198205

206+
GEOSSTRtree *tree1 = GEOSSTRtree_create_r(hGEOSCtxt, 10);
207+
for (size_t i = 0; i < gmv1.size(); i++) {
208+
items[i] = i;
209+
GEOSSTRtree_insert_r(hGEOSCtxt, tree1, gmv1[i], &(items[i]));
210+
}
211+
199212
using namespace Rcpp; // so that later on the (i,_) works
200213
if (op == "relate") { // character return matrix:
201214
Rcpp::CharacterVector out(sfc0.length() * sfc1.length());
@@ -253,19 +266,39 @@ Rcpp::List CPL_geos_binop(Rcpp::List sfc0, Rcpp::List sfc1, std::string op, doub
253266
sparsemat[i] = get_which(rowi);
254267
R_CheckUserInterrupt();
255268
}
269+
} else if (op == "disjoint") {
270+
for (int i = 0; i < sfc0.length(); i++) { // row
271+
Rcpp::LogicalVector rowi(sfc1.length());
272+
for (int j = 0; j < sfc1.length(); j++)
273+
rowi(j) = chk_(GEOSDisjoint_r(hGEOSCtxt, gmv0[i], gmv1[j]));
274+
if (! sparse)
275+
densemat(i,_) = rowi; // #nocov
276+
else
277+
sparsemat[i] = get_which(rowi);
278+
R_CheckUserInterrupt();
279+
}
256280
} else {
257281
if (prepared) {
258282
log_prfn logical_fn = which_prep_geom_fn(op);
259283
for (int i = 0; i < sfc0.length(); i++) { // row
260-
Rcpp::LogicalVector rowi(sfc1.length());
261284
const GEOSPreparedGeometry *pr = GEOSPrepare_r(hGEOSCtxt, gmv0[i]);
262-
for (int j = 0; j < sfc1.length(); j++)
263-
rowi(j) = chk_(logical_fn(hGEOSCtxt, pr, gmv1[j]));
264-
GEOSPreparedGeom_destroy_r(hGEOSCtxt, pr);
265-
if (! sparse)
285+
if (sparse) {
286+
// pre-select sfc1's using tree:
287+
std::vector<size_t> tree_sel, sel;
288+
GEOSSTRtree_query_r(hGEOSCtxt, tree1, gmv0[i], cb, &tree_sel);
289+
for (int j = 0; j < tree_sel.size(); j++)
290+
if (chk_(logical_fn(hGEOSCtxt, pr, gmv1[tree_sel[j]])))
291+
sel.push_back(tree_sel[j] + 1); // 1-based
292+
std::sort(sel.begin(), sel.end());
293+
sparsemat[i] = Rcpp::IntegerVector(sel.begin(), sel.end());
294+
} else {
295+
Rcpp::LogicalVector rowi(sfc1.length());
296+
for (int j = 0; j < sfc1.length(); j++)
297+
rowi(j) = chk_(logical_fn(hGEOSCtxt, pr, gmv1[j]));
298+
GEOSPreparedGeom_destroy_r(hGEOSCtxt, pr);
266299
densemat(i,_) = rowi;
267-
else
268-
sparsemat[i] = get_which(rowi);
300+
}
301+
269302
R_CheckUserInterrupt();
270303
}
271304
} else {
@@ -500,6 +533,7 @@ Rcpp::List CPL_geos_op2(std::string op, Rcpp::List sfcx, Rcpp::List sfcy) {
500533
std::vector<GEOSGeom> y = geometries_from_sfc(hGEOSCtxt, sfcy, &dim);
501534
std::vector<GEOSGeom> out;
502535
std::vector<double> index_x, index_y;
536+
std::vector<size_t> items(x.size());
503537

504538
geom_fn geom_function;
505539

@@ -514,8 +548,20 @@ Rcpp::List CPL_geos_op2(std::string op, Rcpp::List sfcx, Rcpp::List sfcy) {
514548
else
515549
throw std::invalid_argument("invalid operation"); // #nocov
516550

551+
GEOSSTRtree *tree = GEOSSTRtree_create_r(hGEOSCtxt, 10);
552+
for (size_t i = 0; i < x.size(); i++) {
553+
items[i] = i;
554+
GEOSSTRtree_insert_r(hGEOSCtxt, tree, x[i], &(items[i]));
555+
}
556+
517557
for (size_t i = 0; i < y.size(); i++) {
518-
for (size_t j = 0; j < x.size(); j++) {
558+
// select x's using tree:
559+
std::vector<size_t> sel;
560+
sel.reserve(x.size());
561+
GEOSSTRtree_query_r(hGEOSCtxt, tree, y[i], cb, &sel);
562+
std::sort(sel.begin(), sel.end());
563+
for (size_t item = 0; item < sel.size(); item++) {
564+
size_t j = sel[item];
519565
GEOSGeom geom = geom_function(hGEOSCtxt, x[j], y[i]);
520566
if (geom == NULL)
521567
throw std::range_error("GEOS exception"); // #nocov
@@ -528,6 +574,7 @@ Rcpp::List CPL_geos_op2(std::string op, Rcpp::List sfcx, Rcpp::List sfcy) {
528574
}
529575
R_CheckUserInterrupt();
530576
}
577+
GEOSSTRtree_destroy_r(hGEOSCtxt, tree);
531578

532579
// clean up x and y:
533580
for (size_t i = 0; i < x.size(); i++)

0 commit comments

Comments
 (0)