@@ -62,6 +62,7 @@ typedef char (* log_fn)(GEOSContextHandle_t, const GEOSGeometry *, const GEOSGeo
6262typedef char (* log_prfn)(GEOSContextHandle_t, const GEOSPreparedGeometry *,
6363 const GEOSGeometry *);
6464typedef GEOSGeom (* geom_fn)(GEOSContextHandle_t, const GEOSGeom, const GEOSGeom);
65+ typedef GEOSGeom (* geom_fnp)(GEOSContextHandle_t, const GEOSGeom, const GEOSGeom, double grid_size);
6566
6667static int notice = 0 ; // global var to silently catch notice of illegal geoms, e.g. non-closed rings
6768
@@ -170,6 +171,17 @@ static std::vector<GEOSGeometry*> to_raw(std::vector<GeomPtr> & g) {
170171 return raw;
171172}
172173
174+ double geos_grid_size (Rcpp::List x) {
175+ double precision = x.attr (" precision" );
176+ if (precision != 0.0 )
177+ precision = 1 . / precision;
178+ return precision;
179+ }
180+
181+ double geos_grid_size_xy (Rcpp::List x, Rcpp::List y) {
182+ return std::max (geos_grid_size (x), geos_grid_size (y));
183+ }
184+
173185std::vector<GeomPtr> geometries_from_sfc (GEOSContextHandle_t hGEOSCtxt, Rcpp::List sfc, int *dim = NULL , bool stop_on_NULL = true ) {
174186
175187 Rcpp::List sfc_cls = get_dim_sfc (sfc);
@@ -185,10 +197,8 @@ std::vector<GeomPtr> geometries_from_sfc(GEOSContextHandle_t hGEOSCtxt, Rcpp::Li
185197 Rcpp::stop (" GEOS does not support XYM or XYZM geometries; use st_zm() to drop M\n " ); // #nocov
186198
187199#ifdef HAVE_390
188- double precision = sfc.attr (" precision" );
189- bool set_precision = precision != 0.0 ;
190- if (set_precision)
191- precision = 1 /precision;
200+ double grid_size = geos_grid_size (sfc);
201+ bool set_precision = grid_size != 0.0 ;
192202 sfc.attr (" precision" ) = 0.0 ; // so that CPL_write_wkb doesn't do the rounding;
193203#endif
194204 Rcpp::List wkblst = CPL_write_wkb (sfc, true );
@@ -205,7 +215,7 @@ std::vector<GeomPtr> geometries_from_sfc(GEOSContextHandle_t hGEOSCtxt, Rcpp::Li
205215 }
206216#ifdef HAVE_390
207217 else if (set_precision)
208- g[i] = geos_ptr (GEOSGeom_setPrecision_r (hGEOSCtxt, g[i].get (), precision , GEOS_PREC_VALID_OUTPUT), hGEOSCtxt);
218+ g[i] = geos_ptr (GEOSGeom_setPrecision_r (hGEOSCtxt, g[i].get (), grid_size , GEOS_PREC_VALID_OUTPUT), hGEOSCtxt);
209219#endif
210220 }
211221 GEOSWKBReader_destroy_r (hGEOSCtxt, wkb_reader);
@@ -933,6 +943,7 @@ Rcpp::List CPL_geos_op2(std::string op, Rcpp::List sfcx, Rcpp::List sfcy) {
933943 std::vector<GeomPtr> out;
934944 std::vector<double > index_x, index_y;
935945 std::vector<size_t > items (x.size ());
946+ double grid_size = geos_grid_size_xy (sfcx, sfcy);
936947
937948 if (op == " intersection" ) {
938949
@@ -955,7 +966,11 @@ Rcpp::List CPL_geos_op2(std::string op, Rcpp::List sfcx, Rcpp::List sfcy) {
955966 std::sort (sel.begin (), sel.end ());
956967 for (size_t item = 0 ; item < sel.size (); item++) {
957968 size_t j = sel[item];
969+ #ifndef HAVE_390
958970 GeomPtr geom = geos_ptr (GEOSIntersection_r (hGEOSCtxt, x[j].get (), y[i].get ()), hGEOSCtxt);
971+ #else
972+ GeomPtr geom = geos_ptr (GEOSIntersectionPrec_r (hGEOSCtxt, x[j].get (), y[i].get (), grid_size), hGEOSCtxt);
973+ #endif
959974 if (geom == nullptr )
960975 Rcpp::stop (" GEOS exception" ); // #nocov
961976 if (! chk_ (GEOSisEmpty_r (hGEOSCtxt, geom.get ()))) {
@@ -968,19 +983,33 @@ Rcpp::List CPL_geos_op2(std::string op, Rcpp::List sfcx, Rcpp::List sfcy) {
968983 }
969984
970985 } else {
986+ #ifndef HAVE_390
971987 geom_fn geom_function;
972988 if (op == " union" )
973989 geom_function = (geom_fn) GEOSUnion_r;
974990 else if (op == " difference" )
975991 geom_function = (geom_fn) GEOSDifference_r;
976992 else if (op == " sym_difference" )
977993 geom_function = (geom_fn) GEOSSymDifference_r;
994+ #else
995+ geom_fnp geom_function;
996+ if (op == " union" )
997+ geom_function = (geom_fn) GEOSUnionPrec_r;
998+ else if (op == " difference" )
999+ geom_function = (geom_fn) GEOSDifferencePrec_r;
1000+ else if (op == " sym_difference" )
1001+ geom_function = (geom_fn) GEOSSymDifferencePrec_r;
1002+ #endif
9781003 else
9791004 Rcpp::stop (" invalid operation" ); // #nocov
9801005
9811006 for (size_t i = 0 ; i < y.size (); i++) {
9821007 for (size_t j = 0 ; j < x.size (); j++) {
1008+ #ifndef HAVE_390
9831009 GeomPtr geom = geos_ptr (geom_function (hGEOSCtxt, x[j].get (), y[i].get ()), hGEOSCtxt);
1010+ #else
1011+ GeomPtr geom = geos_ptr (geom_function (hGEOSCtxt, x[j].get (), y[i].get (), grid_size), hGEOSCtxt);
1012+ #endif
9841013 if (geom == nullptr )
9851014 Rcpp::stop (" GEOS exception" ); // #nocov
9861015 if (! chk_ (GEOSisEmpty_r (hGEOSCtxt, geom.get ()))) {
@@ -1156,6 +1185,7 @@ Rcpp::List CPL_nary_difference(Rcpp::List sfc) {
11561185 GEOSContextHandle_t hGEOSCtxt = CPL_geos_init ();
11571186 std::vector<GeomPtr> x = geometries_from_sfc (hGEOSCtxt, sfc, &dim);
11581187 std::vector<GeomPtr> out;
1188+ double grid_size = geos_grid_size (sfc);
11591189 // initialize trees to find overlapping areas quickly
11601190 for (size_t i = 0 ; i < x.size (); i++) {
11611191 // if i'th geometry in x is empty then skip it
@@ -1185,7 +1215,11 @@ Rcpp::List CPL_nary_difference(Rcpp::List sfc) {
11851215 // test if the items intersect with geom
11861216 if (chk_ (GEOSIntersects_r (hGEOSCtxt, geom.get (), out[tree_sel[j]].get ()))) {
11871217 // if they do then erase overlapping parts from geom
1218+ #ifndef HAVE_390
11881219 geom = geos_ptr (GEOSDifference_r (hGEOSCtxt, geom.get (), out[tree_sel[j]].get ()), hGEOSCtxt);
1220+ #else
1221+ geom = geos_ptr (GEOSDifferencePrec_r (hGEOSCtxt, geom.get (), out[tree_sel[j]].get (), grid_size), hGEOSCtxt);
1222+ #endif
11891223 if (geom == nullptr )
11901224 Rcpp::stop (" GEOS exception" ); // #nocov
11911225 // ensure that geom is valid
@@ -1221,6 +1255,7 @@ Rcpp::List CPL_nary_intersection(Rcpp::List sfc) {
12211255 std::vector<GeomPtr> x = geometries_from_sfc (hGEOSCtxt, sfc, &dim);
12221256 std::vector<GeomPtr> out;
12231257 int errors = 0 ;
1258+ double grid_size = geos_grid_size (sfc);
12241259#ifdef HAVE350
12251260 notice = 0 ;
12261261 GEOSContext_setNoticeMessageHandler_r (hGEOSCtxt,
@@ -1249,7 +1284,11 @@ Rcpp::List CPL_nary_intersection(Rcpp::List sfc) {
12491284 // iterate over items in query and erase overlapping areas in geom
12501285 for (size_t j = 0 ; j < tree_sel.size (); j++) {
12511286 size_t k = tree_sel[j];
1287+ #ifndef HAVE_390
12521288 GeomPtr inters = geos_ptr (GEOSIntersection_r (hGEOSCtxt, out[k].get (), geom.get ()), hGEOSCtxt);
1289+ #else
1290+ GeomPtr inters = geos_ptr (GEOSIntersectionPrec_r (hGEOSCtxt, out[k].get (), geom.get (), grid_size), hGEOSCtxt);
1291+ #endif
12531292 if (geom.get () != nullptr ) {
12541293 if (inters == nullptr )
12551294 errors++;
@@ -1259,7 +1298,11 @@ Rcpp::List CPL_nary_intersection(Rcpp::List sfc) {
12591298 if (geom == nullptr )
12601299 Rcpp::stop (" GEOS exception" ); // #nocov
12611300 // cut out inters from out[k]:
1301+ #ifndef HAVE_390
12621302 GeomPtr g = geos_ptr (GEOSDifference_r (hGEOSCtxt, out[k].get (), inters.get ()), hGEOSCtxt);
1303+ #else
1304+ GeomPtr g = geos_ptr (GEOSDifferencePrec_r (hGEOSCtxt, out[k].get (), inters.get (), grid_size), hGEOSCtxt);
1305+ #endif
12631306 if (g == nullptr )
12641307 Rcpp::warning (" GEOS difference returns NULL" ); // #nocov
12651308 else {
0 commit comments