PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ lwgeom_subdivide_recursive()

static void lwgeom_subdivide_recursive ( const LWGEOM geom,
uint8_t  dimension,
uint32_t  maxvertices,
uint32_t  depth,
LWCOLLECTION col 
)
static

Definition at line 2261 of file lwgeom.c.

2266{
2267 const uint32_t maxdepth = 50;
2268
2269 if (!geom)
2270 return;
2271
2272 const GBOX *box_in = lwgeom_get_bbox(geom);
2273 if (!box_in)
2274 return;
2275
2276 GBOX clip;
2277 gbox_duplicate(box_in, &clip);
2278 double width = clip.xmax - clip.xmin;
2279 double height = clip.ymax - clip.ymin;
2280
2281 if ( geom->type == POLYHEDRALSURFACETYPE || geom->type == TINTYPE )
2282 lwerror("%s: unsupported geometry type '%s'", __func__, lwtype_name(geom->type));
2283
2284 if ( width == 0.0 && height == 0.0 )
2285 {
2286 if ( geom->type == POINTTYPE && dimension == 0)
2288 return;
2289 }
2290
2291 if (width == 0.0)
2292 {
2293 clip.xmax += FP_TOLERANCE;
2294 clip.xmin -= FP_TOLERANCE;
2295 width = 2 * FP_TOLERANCE;
2296 }
2297 if (height == 0.0)
2298 {
2299 clip.ymax += FP_TOLERANCE;
2300 clip.ymin -= FP_TOLERANCE;
2301 height = 2 * FP_TOLERANCE;
2302 }
2303
2304 /* Always just recurse into collections */
2305 if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE )
2306 {
2307 LWCOLLECTION *incol = (LWCOLLECTION*)geom;
2308 /* Don't increment depth yet, since we aren't actually
2309 * subdividing geometries yet */
2310 for (uint32_t i = 0; i < incol->ngeoms; i++ )
2311 lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col);
2312 return;
2313 }
2314
2315 if (lwgeom_dimension(geom) < dimension)
2316 {
2317 /* We've hit a lower dimension object produced by clipping at
2318 * a shallower recursion level. Ignore it. */
2319 return;
2320 }
2321
2322 /* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */
2323 /* Just add what's left */
2324 if ( depth > maxdepth )
2325 {
2327 return;
2328 }
2329
2330 uint32_t nvertices = lwgeom_count_vertices(geom);
2331
2332 /* Skip empties entirely */
2333 if (nvertices == 0)
2334 return;
2335
2336 /* If it is under the vertex tolerance, just add it, we're done */
2337 if (nvertices <= maxvertices)
2338 {
2340 return;
2341 }
2342
2343 uint8_t split_ordinate = (width > height) ? 0 : 1;
2344 double center = (split_ordinate == 0) ? (clip.xmin + clip.xmax) / 2 : (clip.ymin + clip.ymax) / 2;
2345 double pivot = DBL_MAX;
2346 if (geom->type == POLYGONTYPE)
2347 {
2348 uint32_t ring_to_trim = 0;
2349 double ring_area = 0;
2350 double pivot_eps = DBL_MAX;
2351 double pt_eps = DBL_MAX;
2352 POINTARRAY *pa;
2353 LWPOLY *lwpoly = (LWPOLY *)geom;
2354
2355 /* if there are more points in holes than in outer ring */
2356 if (nvertices >= 2 * lwpoly->rings[0]->npoints)
2357 {
2358 /* trim holes starting from biggest */
2359 for (uint32_t i = 1; i < lwpoly->nrings; i++)
2360 {
2361 double current_ring_area = fabs(ptarray_signed_area(lwpoly->rings[i]));
2362 if (current_ring_area >= ring_area)
2363 {
2364 ring_area = current_ring_area;
2365 ring_to_trim = i;
2366 }
2367 }
2368 }
2369
2370 pa = lwpoly->rings[ring_to_trim];
2371
2372 /* find most central point in chosen ring */
2373 for (uint32_t i = 0; i < pa->npoints; i++)
2374 {
2375 double pt;
2376 if (split_ordinate == 0)
2377 pt = getPoint2d_cp(pa, i)->x;
2378 else
2379 pt = getPoint2d_cp(pa, i)->y;
2380 pt_eps = fabs(pt - center);
2381 if (pivot_eps > pt_eps)
2382 {
2383 pivot = pt;
2384 pivot_eps = pt_eps;
2385 }
2386 }
2387 }
2388 GBOX subbox1, subbox2;
2389 gbox_duplicate(&clip, &subbox1);
2390 gbox_duplicate(&clip, &subbox2);
2391
2392 if (pivot == DBL_MAX)
2393 pivot = center;
2394
2395 if (split_ordinate == 0)
2396 {
2397 if (FP_NEQUALS(subbox1.xmax, pivot) && FP_NEQUALS(subbox1.xmin, pivot))
2398 subbox1.xmax = subbox2.xmin = pivot;
2399 else
2400 subbox1.xmax = subbox2.xmin = center;
2401 }
2402 else
2403 {
2404 if (FP_NEQUALS(subbox1.ymax, pivot) && FP_NEQUALS(subbox1.ymin, pivot))
2405 subbox1.ymax = subbox2.ymin = pivot;
2406 else
2407 subbox1.ymax = subbox2.ymin = center;
2408 }
2409
2410 ++depth;
2411
2412 {
2414 geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
2415 LWGEOM *clipped = lwgeom_intersection(geom, subbox);
2416 lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2417 lwgeom_free(subbox);
2418 if (clipped && !lwgeom_is_empty(clipped))
2419 {
2420 lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
2421 lwgeom_free(clipped);
2422 }
2423 }
2424 {
2426 geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
2427 LWGEOM *clipped = lwgeom_intersection(geom, subbox);
2428 lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2429 lwgeom_free(subbox);
2430 if (clipped && !lwgeom_is_empty(clipped))
2431 {
2432 lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
2433 lwgeom_free(clipped);
2434 }
2435 }
2436}
void gbox_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
Definition gbox.c:433
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
#define MULTIPOINTTYPE
Definition liblwgeom.h:119
LWPOLY * lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
Definition lwpoly.c:98
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
#define TINTYPE
Definition liblwgeom.h:130
#define POLYGONTYPE
Definition liblwgeom.h:118
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:128
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:107
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition ptarray.c:1003
#define FP_TOLERANCE
Floating point comparators.
#define FP_NEQUALS(A, B)
int lwgeom_is_collection(const LWGEOM *geom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition lwgeom.c:1079
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count points in an LWGEOM.
Definition lwgeom.c:1229
int lwgeom_dimension(const LWGEOM *geom)
For an LWGEOM, returns 0 for points, 1 for lines, 2 for polygons, 3 for volume, and the max dimension...
Definition lwgeom.c:1281
static void lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col)
Definition lwgeom.c:2261
void lwgeom_free(LWGEOM *lwgeom)
Definition lwgeom.c:1138
int lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
Definition lwgeom.c:1715
const GBOX * lwgeom_get_bbox(const LWGEOM *lwg)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition lwgeom.c:725
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep-clone an LWGEOM object.
Definition lwgeom.c:511
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition lwutil.c:190
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition lwinline.h:193
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:91
static double pivot(double *left, double *right)
double ymax
Definition liblwgeom.h:343
double xmax
Definition liblwgeom.h:341
double ymin
Definition liblwgeom.h:342
double xmin
Definition liblwgeom.h:340
uint32_t ngeoms
Definition liblwgeom.h:566
LWGEOM ** geoms
Definition liblwgeom.h:561
uint8_t type
Definition liblwgeom.h:448
int32_t srid
Definition liblwgeom.h:446
POINTARRAY ** rings
Definition liblwgeom.h:505
uint32_t nrings
Definition liblwgeom.h:510
double y
Definition liblwgeom.h:376
double x
Definition liblwgeom.h:376
uint32_t npoints
Definition liblwgeom.h:413

References FP_NEQUALS, FP_TOLERANCE, gbox_duplicate(), LWCOLLECTION::geoms, getPoint2d_cp(), LW_TRUE, lwcollection_add_lwgeom(), lwerror(), lwgeom_clone_deep(), lwgeom_count_vertices(), lwgeom_dimension(), lwgeom_free(), lwgeom_get_bbox(), lwgeom_intersection(), lwgeom_is_collection(), lwgeom_is_empty(), lwgeom_simplify_in_place(), lwgeom_subdivide_recursive(), lwpoly_construct_envelope(), lwtype_name(), MULTIPOINTTYPE, LWCOLLECTION::ngeoms, POINTARRAY::npoints, LWPOLY::nrings, pivot(), POINTTYPE, POLYGONTYPE, POLYHEDRALSURFACETYPE, ptarray_signed_area(), LWPOLY::rings, LWGEOM::srid, TINTYPE, LWGEOM::type, POINT2D::x, GBOX::xmax, GBOX::xmin, POINT2D::y, GBOX::ymax, and GBOX::ymin.

Referenced by lwgeom_subdivide(), and lwgeom_subdivide_recursive().

Here is the call graph for this function:
Here is the caller graph for this function: