1416{
1417
1418 typedef struct CellCorner {
1421 } CellCorner;
1422
1423 CellCorner* cells;
1424 uint32_t num_cells = 0;
1425
1426 double area, bbox_area, bbox_width, bbox_height, area_ratio;
1429 uint32_t sample_npoints, sample_sqrt, sample_width, sample_height;
1430 double sample_cell_size;
1431 uint32_t i, j, n;
1432 uint32_t iterations = 0;
1433 uint32_t npoints_generated = 0;
1434 uint32_t npoints_tested = 0;
1435 GEOSGeometry* g;
1436 const GEOSPreparedGeometry* gprep;
1439 int done = 0;
1440
1442 {
1443 lwerror(
"%s: only polygons supported", __func__);
1444 return NULL;
1445 }
1446
1448
1449 if (!lwpoly->bbox)
1451 else
1452 bbox = *(lwpoly->bbox);
1453
1455 bbox_width = bbox.
xmax - bbox.
xmin;
1456 bbox_height = bbox.
ymax - bbox.
ymin;
1457 bbox_area = bbox_width * bbox_height;
1458
1459 if (area == 0.0 || bbox_area == 0.0)
1460 {
1461 lwerror(
"%s: zero area input polygon, TBD", __func__);
1462 return NULL;
1463 }
1464
1465
1466
1467
1468
1469
1470
1471 area_ratio =
FP_MIN(bbox_area / area, 10000.0);
1472 sample_npoints = npoints * area_ratio;
1473
1474
1475
1476
1477
1478 sample_sqrt = ceil(sqrt(sample_npoints));
1479
1480
1481 if (bbox_width > bbox_height)
1482 {
1483 sample_width = sample_sqrt;
1484 sample_height = ceil((double)sample_npoints / (double)sample_width);
1485 sample_cell_size = bbox_width / sample_width;
1486 }
1487 else
1488 {
1489 sample_height = sample_sqrt;
1490 sample_width = ceil((double)sample_npoints / (double)sample_height);
1491 sample_cell_size = bbox_height / sample_height;
1492 }
1493
1494
1497 if (!g)
1498 {
1500 return NULL;
1501 }
1502 gprep = GEOSPrepare(g);
1503
1504
1505
1506
1507
1508
1509
1510 cells =
lwalloc(
sizeof(CellCorner) * sample_height * sample_width);
1511
1512 for (i = 0; i < sample_width; i++)
1513 {
1514 for (j = 0; j < sample_height; j++)
1515 {
1516 int intersects = 0;
1517 double xmin = bbox.
xmin + i * sample_cell_size;
1518 double ymin = bbox.
ymin + j * sample_cell_size;
1520 intersects = GEOSPreparedIntersects(gprep, gcell);
1521 GEOSGeom_destroy(gcell);
1522 if (intersects == 2)
1523 {
1524 GEOSPreparedGeom_destroy(gprep);
1525 GEOSGeom_destroy(g);
1527 return NULL;
1528 }
1529 if (intersects == 1)
1530 {
1531 cells[num_cells].x = xmin;
1532 cells[num_cells].y = ymin;
1533 num_cells++;
1534 }
1535 }
1536 }
1537
1538
1539
1540
1541
1542
1543
1545
1546
1547 n = num_cells;
1548 if (n > 1)
1549 {
1550 for (i = n - 1; i > 0; i--)
1551 {
1552 CellCorner tmp;
1554 memcpy( &tmp, cells + j, sizeof(CellCorner));
1555 memcpy(cells + j, cells + i, sizeof(CellCorner));
1556 memcpy(cells + i, &tmp, sizeof(CellCorner));
1557 }
1558 }
1559
1560
1562
1563
1564 while (npoints_generated < npoints)
1565 {
1566 iterations++;
1567 for (i = 0; i < num_cells; i++)
1568 {
1570 double y = cells[i].y;
1571 double x = cells[i].x;
1574 if (x >= bbox.
xmax || y >= bbox.
ymax)
continue;
1575
1576#if POSTGIS_GEOS_VERSION >= 31200
1577 contains = GEOSPreparedIntersectsXY(gprep, x, y);
1578#else
1579 {
1580 GEOSGeometry *gpt;
1581 GEOSCoordSequence *gseq = GEOSCoordSeq_create(1, 2);;
1582 GEOSCoordSeq_setXY(gseq, 0, x, y);
1583 gpt = GEOSGeom_createPoint(gseq);
1584 contains = GEOSPreparedIntersects(gprep, gpt);
1585 GEOSGeom_destroy(gpt);
1586 }
1587#endif
1589 {
1590 GEOSPreparedGeom_destroy(gprep);
1591 GEOSGeom_destroy(g);
1593 return NULL;
1594 }
1596 {
1598 npoints_generated++;
1599 if (npoints_generated == npoints)
1600 {
1601 done = 1;
1602 break;
1603 }
1604 }
1605
1606
1607 npoints_tested++;
1608 if (npoints_tested % 10000 == 0)
1609 LW_ON_INTERRUPT(GEOSPreparedGeom_destroy(gprep); GEOSGeom_destroy(g);
return NULL);
1610
1611 if (done) break;
1612 }
1613 if (done || iterations > 100) break;
1614 }
1615
1616 GEOSPreparedGeom_destroy(gprep);
1617 GEOSGeom_destroy(g);
1619
1620 return mpt;
1621}
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
static GEOSGeometry * lwpoly_to_points_make_cell(double xmin, double ymin, double cell_size)
void lwgeom_geos_error(const char *fmt,...)
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
void * lwalloc(size_t size)
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
LWMPOINT * lwmpoint_construct_empty(int32_t srid, char hasz, char hasm)
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
#define LW_ON_INTERRUPT(x)
double lwpoly_area(const LWPOLY *poly)
Find the area of the outer ring - sum (area of inner rings).
Datum contains(PG_FUNCTION_ARGS)
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
void lwrandom_set_seed(int32_t seed)
double lwrandom_uniform(void)