PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ lwgeom_subdivide_recursive()

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

Definition at line 2438 of file lwgeom.c.

2444 {
2445  const uint32_t maxdepth = 50;
2446 
2447  if (!geom)
2448  return;
2449 
2450  const GBOX *box_in = lwgeom_get_bbox(geom);
2451  if (!box_in)
2452  return;
2453 
2454  LW_ON_INTERRUPT(return);
2455 
2456  GBOX clip;
2457  gbox_duplicate(box_in, &clip);
2458  double width = clip.xmax - clip.xmin;
2459  double height = clip.ymax - clip.ymin;
2460 
2461  if ( geom->type == POLYHEDRALSURFACETYPE || geom->type == TINTYPE )
2462  lwerror("%s: unsupported geometry type '%s'", __func__, lwtype_name(geom->type));
2463 
2464  if ( width == 0.0 && height == 0.0 )
2465  {
2466  if ( geom->type == POINTTYPE && dimension == 0)
2468  return;
2469  }
2470 
2471  if (width == 0.0)
2472  {
2473  clip.xmax += FP_TOLERANCE;
2474  clip.xmin -= FP_TOLERANCE;
2475  width = 2 * FP_TOLERANCE;
2476  }
2477  if (height == 0.0)
2478  {
2479  clip.ymax += FP_TOLERANCE;
2480  clip.ymin -= FP_TOLERANCE;
2481  height = 2 * FP_TOLERANCE;
2482  }
2483 
2484  /* Always just recurse into collections */
2485  if ( lwgeom_is_collection(geom) && geom->type != MULTIPOINTTYPE )
2486  {
2487  LWCOLLECTION *incol = (LWCOLLECTION*)geom;
2488  /* Don't increment depth yet, since we aren't actually
2489  * subdividing geometries yet */
2490  for (uint32_t i = 0; i < incol->ngeoms; i++ )
2491  lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col, gridSize);
2492  return;
2493  }
2494 
2495  if (lwgeom_dimension(geom) < dimension)
2496  {
2497  /* We've hit a lower dimension object produced by clipping at
2498  * a shallower recursion level. Ignore it. */
2499  return;
2500  }
2501 
2502  /* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */
2503  /* Just add what's left */
2504  if ( depth > maxdepth )
2505  {
2507  return;
2508  }
2509 
2510  uint32_t nvertices = lwgeom_count_vertices(geom);
2511 
2512  /* Skip empties entirely */
2513  if (nvertices == 0)
2514  return;
2515 
2516  /* If it is under the vertex tolerance, just add it, we're done */
2517  if (nvertices <= maxvertices)
2518  {
2520  return;
2521  }
2522 
2523  uint8_t split_ordinate = (width > height) ? 0 : 1;
2524  double center = (split_ordinate == 0) ? (clip.xmin + clip.xmax) / 2 : (clip.ymin + clip.ymax) / 2;
2525  double pivot = DBL_MAX;
2526  if (geom->type == POLYGONTYPE)
2527  {
2528  uint32_t ring_to_trim = 0;
2529  double ring_area = 0;
2530  double pivot_eps = DBL_MAX;
2531  double pt_eps = DBL_MAX;
2532  POINTARRAY *pa;
2533  LWPOLY *lwpoly = (LWPOLY *)geom;
2534 
2535  /* if there are more points in holes than in outer ring */
2536  if (nvertices >= 2 * lwpoly->rings[0]->npoints)
2537  {
2538  /* trim holes starting from biggest */
2539  for (uint32_t i = 1; i < lwpoly->nrings; i++)
2540  {
2541  double current_ring_area = fabs(ptarray_signed_area(lwpoly->rings[i]));
2542  if (current_ring_area >= ring_area)
2543  {
2544  ring_area = current_ring_area;
2545  ring_to_trim = i;
2546  }
2547  }
2548  }
2549 
2550  pa = lwpoly->rings[ring_to_trim];
2551 
2552  /* find most central point in chosen ring */
2553  for (uint32_t i = 0; i < pa->npoints; i++)
2554  {
2555  double pt;
2556  if (split_ordinate == 0)
2557  pt = getPoint2d_cp(pa, i)->x;
2558  else
2559  pt = getPoint2d_cp(pa, i)->y;
2560  pt_eps = fabs(pt - center);
2561  if (pivot_eps > pt_eps)
2562  {
2563  pivot = pt;
2564  pivot_eps = pt_eps;
2565  }
2566  }
2567  }
2568  GBOX subbox1, subbox2;
2569  gbox_duplicate(&clip, &subbox1);
2570  gbox_duplicate(&clip, &subbox2);
2571 
2572  if (pivot == DBL_MAX)
2573  pivot = center;
2574 
2575  if (split_ordinate == 0)
2576  {
2577  if (FP_NEQUALS(subbox1.xmax, pivot) && FP_NEQUALS(subbox1.xmin, pivot))
2578  subbox1.xmax = subbox2.xmin = pivot;
2579  else
2580  subbox1.xmax = subbox2.xmin = center;
2581  }
2582  else
2583  {
2584  if (FP_NEQUALS(subbox1.ymax, pivot) && FP_NEQUALS(subbox1.ymin, pivot))
2585  subbox1.ymax = subbox2.ymin = pivot;
2586  else
2587  subbox1.ymax = subbox2.ymin = center;
2588  }
2589 
2590  ++depth;
2591 
2592  {
2594  geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
2595  LWGEOM *clipped = lwgeom_intersection_prec(geom, subbox, gridSize);
2596  lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2597  lwgeom_free(subbox);
2598  if (clipped && !lwgeom_is_empty(clipped))
2599  {
2600  lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col, gridSize);
2601  lwgeom_free(clipped);
2602  }
2603  }
2604  {
2606  geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
2607  LWGEOM *clipped = lwgeom_intersection_prec(geom, subbox, gridSize);
2608  lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
2609  lwgeom_free(subbox);
2610  if (clipped && !lwgeom_is_empty(clipped))
2611  {
2612  lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col, gridSize);
2613  lwgeom_free(clipped);
2614  }
2615  }
2616 }
void gbox_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
Definition: gbox.c:445
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
#define TINTYPE
Definition: liblwgeom.h:116
LWPOLY * lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
Definition: lwpoly.c:98
#define POLYGONTYPE
Definition: liblwgeom.h:104
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
LWGEOM * lwgeom_intersection_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:189
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:1143
#define LW_ON_INTERRUPT(x)
#define FP_TOLERANCE
Floating point comparators.
#define FP_NEQUALS(A, B)
int lwgeom_is_collection(const LWGEOM *geom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
Definition: lwgeom.c:1125
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep-clone an LWGEOM object.
Definition: lwgeom.c:557
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count points in an LWGEOM.
Definition: lwgeom.c:1337
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:1389
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:771
void lwgeom_free(LWGEOM *lwgeom)
Definition: lwgeom.c:1246
static void lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col, double gridSize)
Definition: lwgeom.c:2438
int lwgeom_simplify_in_place(LWGEOM *geom, double epsilon, int preserve_collapsed)
Definition: lwgeom.c:1851
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
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:97
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:199
static double pivot(double *left, double *right)
Definition: rt_statistics.c:40
double ymax
Definition: liblwgeom.h:357
double xmax
Definition: liblwgeom.h:355
double ymin
Definition: liblwgeom.h:356
double xmin
Definition: liblwgeom.h:354
uint32_t ngeoms
Definition: liblwgeom.h:580
LWGEOM ** geoms
Definition: liblwgeom.h:575
uint8_t type
Definition: liblwgeom.h:462
int32_t srid
Definition: liblwgeom.h:460
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint32_t nrings
Definition: liblwgeom.h:524
double y
Definition: liblwgeom.h:390
double x
Definition: liblwgeom.h:390
uint32_t npoints
Definition: liblwgeom.h:427

References FP_NEQUALS, FP_TOLERANCE, gbox_duplicate(), LWCOLLECTION::geoms, getPoint2d_cp(), LW_ON_INTERRUPT, LW_TRUE, lwcollection_add_lwgeom(), lwerror(), lwgeom_clone_deep(), lwgeom_count_vertices(), lwgeom_dimension(), lwgeom_free(), lwgeom_get_bbox(), lwgeom_intersection_prec(), lwgeom_is_collection(), lwgeom_is_empty(), lwgeom_simplify_in_place(), 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_prec().

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