2056
#ifdef GEOS_ADVANCED /* GEOS advanced features */
2058
GAIAGEO_DECLARE gaiaGeomCollPtr
2059
gaiaOffsetCurve (gaiaGeomCollPtr geom, double radius, int points,
2063
// builds a geometry that is the OffsetCurve of GEOM
2064
// (which is expected to be of the LINESTRING type)
2067
gaiaGeomCollPtr geo;
2071
gaiaLinestringPtr ln;
2080
/* checking the input geometry for validity */
2081
pt = geom->FirstPoint;
2084
/* counting how many POINTs are there */
2088
ln = geom->FirstLinestring;
2091
/* counting how many LINESTRINGs are there */
2093
if (gaiaIsClosed (ln))
2097
pg = geom->FirstPolygon;
2100
/* counting how many POLYGON are there */
2104
if (pts > 0 || pgs > 0 || lns > 1 || closed > 0)
2107
/* all right: this one simply is a LINESTRING */
2108
geom->DeclaredType = GAIA_LINESTRING;
2110
g1 = gaiaToGeos (geom);
2111
g2 = GEOSSingleSidedBuffer (g1, radius, points, GEOSBUF_JOIN_ROUND, 5.0,
2113
GEOSGeom_destroy (g1);
2116
if (geom->DimensionModel == GAIA_XY_Z)
2117
geo = gaiaFromGeos_XYZ (g2);
2118
else if (geom->DimensionModel == GAIA_XY_M)
2119
geo = gaiaFromGeos_XYM (g2);
2120
else if (geom->DimensionModel == GAIA_XY_Z_M)
2121
geo = gaiaFromGeos_XYZM (g2);
2123
geo = gaiaFromGeos_XY (g2);
2124
GEOSGeom_destroy (g2);
2127
geo->Srid = geom->Srid;
2131
GAIAGEO_DECLARE gaiaGeomCollPtr
2132
gaiaSingleSidedBuffer (gaiaGeomCollPtr geom, double radius, int points,
2136
// builds a geometry that is the SingleSided BUFFER of GEOM
2137
// (which is expected to be of the LINESTRING type)
2140
gaiaGeomCollPtr geo;
2143
GEOSBufferParams *params = NULL;
2145
gaiaLinestringPtr ln;
2154
/* checking the input geometry for validity */
2155
pt = geom->FirstPoint;
2158
/* counting how many POINTs are there */
2162
ln = geom->FirstLinestring;
2165
/* counting how many LINESTRINGs are there */
2167
if (gaiaIsClosed (ln))
2171
pg = geom->FirstPolygon;
2174
/* counting how many POLYGON are there */
2178
if (pts > 0 || pgs > 0 || lns > 1 || closed > 0)
2181
/* all right: this one simply is a LINESTRING */
2182
geom->DeclaredType = GAIA_LINESTRING;
2184
g1 = gaiaToGeos (geom);
2185
/* setting up Buffer params */
2186
params = GEOSBufferParams_create ();
2187
GEOSBufferParams_setJoinStyle (params, GEOSBUF_JOIN_ROUND);
2188
GEOSBufferParams_setMitreLimit (params, 5.0);
2189
GEOSBufferParams_setQuadrantSegments (params, points);
2190
GEOSBufferParams_setSingleSided (params, 1);
2192
/* creating the SingleSided Buffer */
2193
if (left_right == 0)
2195
/* right-sided requires NEGATIVE radius */
2198
g2 = GEOSBufferWithParams (g1, params, radius);
2199
GEOSGeom_destroy (g1);
2200
GEOSBufferParams_destroy (params);
2203
if (geom->DimensionModel == GAIA_XY_Z)
2204
geo = gaiaFromGeos_XYZ (g2);
2205
else if (geom->DimensionModel == GAIA_XY_M)
2206
geo = gaiaFromGeos_XYM (g2);
2207
else if (geom->DimensionModel == GAIA_XY_Z_M)
2208
geo = gaiaFromGeos_XYZM (g2);
2210
geo = gaiaFromGeos_XY (g2);
2211
GEOSGeom_destroy (g2);
2214
geo->Srid = geom->Srid;
2219
gaiaHausdorffDistance (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
2223
/ computes the (discrete) Hausdorff distance intercurring
2224
/ between GEOM-1 and GEOM-2
2230
if (!geom1 || !geom2)
2232
g1 = gaiaToGeos (geom1);
2233
g2 = gaiaToGeos (geom2);
2234
ret = GEOSHausdorffDistance (g1, g2, &dist);
2235
GEOSGeom_destroy (g1);
2236
GEOSGeom_destroy (g2);
2242
static gaiaGeomCollPtr
2243
geom_as_lines (gaiaGeomCollPtr geom)
2245
/* transforms a Geometry into a LINESTRING/MULTILINESTRING (if possible) */
2246
gaiaGeomCollPtr result;
2247
gaiaLinestringPtr ln;
2248
gaiaLinestringPtr new_ln;
2260
if (geom->FirstPoint != NULL)
2262
/* invalid: GEOM contains at least one POINT */
2266
switch (geom->DimensionModel)
2269
result = gaiaAllocGeomCollXYZM ();
2272
result = gaiaAllocGeomCollXYZ ();
2275
result = gaiaAllocGeomCollXYM ();
2278
result = gaiaAllocGeomColl ();
2281
result->Srid = geom->Srid;
2282
ln = geom->FirstLinestring;
2285
/* copying any Linestring */
2286
new_ln = gaiaAddLinestringToGeomColl (result, ln->Points);
2287
for (iv = 0; iv < ln->Points; iv++)
2289
if (ln->DimensionModel == GAIA_XY_Z)
2291
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2292
gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
2294
else if (ln->DimensionModel == GAIA_XY_M)
2296
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2297
gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
2299
else if (ln->DimensionModel == GAIA_XY_Z_M)
2301
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
2302
gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
2306
gaiaGetPoint (ln->Coords, iv, &x, &y);
2307
gaiaSetPoint (new_ln->Coords, iv, x, y);
2312
pg = geom->FirstPolygon;
2315
/* copying any Polygon Ring (as Linestring) */
2317
new_ln = gaiaAddLinestringToGeomColl (result, rng->Points);
2318
for (iv = 0; iv < rng->Points; iv++)
2321
if (rng->DimensionModel == GAIA_XY_Z)
2323
gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2324
gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
2326
else if (rng->DimensionModel == GAIA_XY_M)
2328
gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2329
gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
2331
else if (rng->DimensionModel == GAIA_XY_Z_M)
2333
gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2334
gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
2338
gaiaGetPoint (rng->Coords, iv, &x, &y);
2339
gaiaSetPoint (new_ln->Coords, iv, x, y);
2342
for (ib = 0; ib < pg->NumInteriors; ib++)
2344
rng = pg->Interiors + ib;
2345
new_ln = gaiaAddLinestringToGeomColl (result, rng->Points);
2346
for (iv = 0; iv < rng->Points; iv++)
2348
/* any interior Ring */
2349
if (rng->DimensionModel == GAIA_XY_Z)
2351
gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2352
gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
2354
else if (rng->DimensionModel == GAIA_XY_M)
2356
gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2357
gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
2359
else if (rng->DimensionModel == GAIA_XY_Z_M)
2361
gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2362
gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
2366
gaiaGetPoint (rng->Coords, iv, &x, &y);
2367
gaiaSetPoint (new_ln->Coords, iv, x, y);
2377
add_shared_linestring (gaiaGeomCollPtr geom, gaiaDynamicLinePtr dyn)
2379
/* adding a LINESTRING from Dynamic Line */
2381
gaiaLinestringPtr ln;
2392
/* counting how many Points are there */
2398
ln = gaiaAddLinestringToGeomColl (geom, count);
2403
/* copying points into the LINESTRING */
2404
if (ln->DimensionModel == GAIA_XY_Z)
2406
gaiaSetPointXYZ (ln->Coords, iv, pt->X, pt->Y, pt->Z);
2408
else if (ln->DimensionModel == GAIA_XY_M)
2410
gaiaSetPointXYM (ln->Coords, iv, pt->X, pt->Y, pt->M);
2412
else if (ln->DimensionModel == GAIA_XY_Z_M)
2414
gaiaSetPointXYZM (ln->Coords, iv, pt->X, pt->Y, pt->Z, pt->M);
2418
gaiaSetPoint (ln->Coords, iv, pt->X, pt->Y);
2426
append_shared_path (gaiaDynamicLinePtr dyn, gaiaLinestringPtr ln, int order)
2428
/* appends a Shared Path item to Dynamic Line */
2436
/* reversed order */
2437
for (iv = ln->Points - 1; iv >= 0; iv--)
2439
if (ln->DimensionModel == GAIA_XY_Z)
2441
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2442
if (x == dyn->Last->X && y == dyn->Last->Y
2443
&& z == dyn->Last->Z)
2446
gaiaAppendPointZToDynamicLine (dyn, x, y, z);
2448
else if (ln->DimensionModel == GAIA_XY_M)
2450
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2451
if (x == dyn->Last->X && y == dyn->Last->Y
2452
&& m == dyn->Last->M)
2455
gaiaAppendPointMToDynamicLine (dyn, x, y, m);
2457
else if (ln->DimensionModel == GAIA_XY_Z_M)
2459
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
2460
if (x == dyn->Last->X && y == dyn->Last->Y
2461
&& z == dyn->Last->Z && m == dyn->Last->M)
2464
gaiaAppendPointZMToDynamicLine (dyn, x, y, z, m);
2468
gaiaGetPoint (ln->Coords, iv, &x, &y);
2469
if (x == dyn->Last->X && y == dyn->Last->Y)
2472
gaiaAppendPointToDynamicLine (dyn, x, y);
2478
/* conformant order */
2479
for (iv = 0; iv < ln->Points; iv++)
2481
if (ln->DimensionModel == GAIA_XY_Z)
2483
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2484
if (x == dyn->Last->X && y == dyn->Last->Y
2485
&& z == dyn->Last->Z)
2488
gaiaAppendPointZToDynamicLine (dyn, x, y, z);
2490
else if (ln->DimensionModel == GAIA_XY_M)
2492
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2493
if (x == dyn->Last->X && y == dyn->Last->Y
2494
&& m == dyn->Last->M)
2497
gaiaAppendPointMToDynamicLine (dyn, x, y, m);
2499
else if (ln->DimensionModel == GAIA_XY_Z_M)
2501
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
2502
if (x == dyn->Last->X && y == dyn->Last->Y
2503
&& z == dyn->Last->Z && m == dyn->Last->M)
2506
gaiaAppendPointZMToDynamicLine (dyn, x, y, z, m);
2510
gaiaGetPoint (ln->Coords, iv, &x, &y);
2511
if (x == dyn->Last->X && y == dyn->Last->Y)
2514
gaiaAppendPointToDynamicLine (dyn, x, y);
2521
prepend_shared_path (gaiaDynamicLinePtr dyn, gaiaLinestringPtr ln, int order)
2523
/* prepends a Shared Path item to Dynamic Line */
2531
/* reversed order */
2532
for (iv = 0; iv < ln->Points; iv++)
2534
if (ln->DimensionModel == GAIA_XY_Z)
2536
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2537
if (x == dyn->First->X && y == dyn->First->Y
2538
&& z == dyn->First->Z)
2541
gaiaPrependPointZToDynamicLine (dyn, x, y, z);
2543
else if (ln->DimensionModel == GAIA_XY_M)
2545
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2546
if (x == dyn->First->X && y == dyn->First->Y
2547
&& m == dyn->First->M)
2550
gaiaPrependPointMToDynamicLine (dyn, x, y, m);
2552
else if (ln->DimensionModel == GAIA_XY_Z_M)
2554
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
2555
if (x == dyn->First->X && y == dyn->First->Y
2556
&& z == dyn->First->Z && m == dyn->First->M)
2559
gaiaPrependPointZMToDynamicLine (dyn, x, y, z, m);
2563
gaiaGetPoint (ln->Coords, iv, &x, &y);
2564
if (x == dyn->First->X && y == dyn->First->Y)
2567
gaiaPrependPointToDynamicLine (dyn, x, y);
2573
/* conformant order */
2574
for (iv = ln->Points - 1; iv >= 0; iv--)
2576
if (ln->DimensionModel == GAIA_XY_Z)
2578
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2579
if (x == dyn->First->X && y == dyn->First->Y
2580
&& z == dyn->First->Z)
2583
gaiaPrependPointZToDynamicLine (dyn, x, y, z);
2585
else if (ln->DimensionModel == GAIA_XY_M)
2587
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2588
if (x == dyn->First->X && y == dyn->First->Y
2589
&& m == dyn->First->M)
2592
gaiaPrependPointMToDynamicLine (dyn, x, y, m);
2594
else if (ln->DimensionModel == GAIA_XY_Z_M)
2596
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
2597
if (x == dyn->First->X && y == dyn->First->Y
2598
&& z == dyn->First->Z && m == dyn->First->M)
2601
gaiaPrependPointZMToDynamicLine (dyn, x, y, z, m);
2605
gaiaGetPoint (ln->Coords, iv, &x, &y);
2606
if (x == dyn->First->X && y == dyn->First->Y)
2609
gaiaPrependPointToDynamicLine (dyn, x, y);
2615
static gaiaGeomCollPtr
2616
arrange_shared_paths (gaiaGeomCollPtr geom)
2618
/* final aggregation step for shared paths */
2619
gaiaLinestringPtr ln;
2620
gaiaLinestringPtr *ln_array;
2621
gaiaGeomCollPtr result;
2622
gaiaDynamicLinePtr dyn;
2637
ln = geom->FirstLinestring;
2640
/* counting how many Linestrings are there */
2647
ln_array = malloc (sizeof (gaiaLinestringPtr) * count);
2649
ln = geom->FirstLinestring;
2652
/* populating the Linestring references array */
2657
/* allocating a new Geometry [MULTILINESTRING] */
2658
switch (geom->DimensionModel)
2661
result = gaiaAllocGeomCollXYZM ();
2664
result = gaiaAllocGeomCollXYZ ();
2667
result = gaiaAllocGeomCollXYM ();
2670
result = gaiaAllocGeomColl ();
2673
result->Srid = geom->Srid;
2674
result->DeclaredType = GAIA_MULTILINESTRING;
2679
/* looping until we have processed any input item */
2681
for (i = 0; i < count; i++)
2683
if (ln_array[i] != NULL)
2685
/* starting a new LINESTRING */
2686
dyn = gaiaAllocDynamicLine ();
2689
for (iv = 0; iv < ln->Points; iv++)
2691
/* inserting the 'seed' path */
2692
if (ln->DimensionModel == GAIA_XY_Z)
2694
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2695
gaiaAppendPointZToDynamicLine (dyn, x, y, z);
2697
else if (ln->DimensionModel == GAIA_XY_M)
2699
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2700
gaiaAppendPointMToDynamicLine (dyn, x, y, m);
2702
else if (ln->DimensionModel == GAIA_XY_Z_M)
2704
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z,
2706
gaiaAppendPointZMToDynamicLine (dyn, x, y, z,
2711
gaiaGetPoint (ln->Coords, iv, &x, &y);
2712
gaiaAppendPointToDynamicLine (dyn, x, y);
2718
/* looping until we have checked any other item */
2720
for (i2 = 0; i2 < count; i2++)
2722
/* expanding the 'seed' path */
2723
if (ln_array[i2] == NULL)
2726
/* checking the first vertex */
2728
if (ln->DimensionModel == GAIA_XY_Z)
2730
gaiaGetPointXYZ (ln->Coords, iv, &x, &y,
2733
else if (ln->DimensionModel == GAIA_XY_M)
2735
gaiaGetPointXYM (ln->Coords, iv, &x, &y,
2738
else if (ln->DimensionModel == GAIA_XY_Z_M)
2740
gaiaGetPointXYZM (ln->Coords, iv, &x,
2745
gaiaGetPoint (ln->Coords, iv, &x, &y);
2747
if (x == dyn->Last->X && y == dyn->Last->Y)
2749
/* appending this item to the 'seed' (conformant order) */
2750
append_shared_path (dyn, ln, 0);
2751
ln_array[i2] = NULL;
2755
if (x == dyn->First->X && y == dyn->First->Y)
2757
/* prepending this item to the 'seed' (reversed order) */
2758
prepend_shared_path (dyn, ln, 1);
2759
ln_array[i2] = NULL;
2763
/* checking the last vertex */
2764
iv = ln->Points - 1;
2765
if (ln->DimensionModel == GAIA_XY_Z)
2767
gaiaGetPointXYZ (ln->Coords, iv, &x, &y,
2770
else if (ln->DimensionModel == GAIA_XY_M)
2772
gaiaGetPointXYM (ln->Coords, iv, &x, &y,
2775
else if (ln->DimensionModel == GAIA_XY_Z_M)
2777
gaiaGetPointXYZM (ln->Coords, iv, &x,
2782
gaiaGetPoint (ln->Coords, iv, &x, &y);
2784
if (x == dyn->Last->X && y == dyn->Last->Y)
2786
/* appending this item to the 'seed' (reversed order) */
2787
append_shared_path (dyn, ln, 1);
2788
ln_array[i2] = NULL;
2792
if (x == dyn->First->X && y == dyn->First->Y)
2794
/* prepending this item to the 'seed' (conformant order) */
2795
prepend_shared_path (dyn, ln, 0);
2796
ln_array[i2] = NULL;
2802
add_shared_linestring (result, dyn);
2803
gaiaFreeDynamicLine (dyn);
2813
GAIAGEO_DECLARE gaiaGeomCollPtr
2814
gaiaSharedPaths (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
2817
// builds a geometry containing Shared Paths commons to GEOM1 & GEOM2
2818
// (which are expected to be of the LINESTRING/MULTILINESTRING type)
2821
gaiaGeomCollPtr geo;
2822
gaiaGeomCollPtr result;
2823
gaiaGeomCollPtr line1;
2824
gaiaGeomCollPtr line2;
2832
/* transforming input geoms as Lines */
2833
line1 = geom_as_lines (geom1);
2834
line2 = geom_as_lines (geom2);
2835
if (line1 == NULL || line2 == NULL)
2838
gaiaFreeGeomColl (line1);
2840
gaiaFreeGeomColl (line2);
2844
g1 = gaiaToGeos (line1);
2845
g2 = gaiaToGeos (line2);
2846
gaiaFreeGeomColl (line1);
2847
gaiaFreeGeomColl (line2);
2848
g3 = GEOSSharedPaths (g1, g2);
2849
GEOSGeom_destroy (g1);
2850
GEOSGeom_destroy (g2);
2853
if (geom1->DimensionModel == GAIA_XY_Z)
2854
geo = gaiaFromGeos_XYZ (g3);
2855
else if (geom1->DimensionModel == GAIA_XY_M)
2856
geo = gaiaFromGeos_XYM (g3);
2857
else if (geom1->DimensionModel == GAIA_XY_Z_M)
2858
geo = gaiaFromGeos_XYZM (g3);
2860
geo = gaiaFromGeos_XY (g3);
2861
GEOSGeom_destroy (g3);
2864
geo->Srid = geom1->Srid;
2865
result = arrange_shared_paths (geo);
2866
gaiaFreeGeomColl (geo);
3724
GAIAGEO_DECLARE gaiaGeomCollPtr
3725
gaiaPolygonize (gaiaGeomCollPtr geom, int force_multi)
3727
/* attempts to rearrange a generic Geometry into a (multi)polygon */
3728
gaiaResetGeosMsg ();
3729
return gaiaPolygonizeCommon (NULL, NULL, geom, force_multi);
3732
GAIAGEO_DECLARE gaiaGeomCollPtr
3733
gaiaPolygonize_r (const void *p_cache, gaiaGeomCollPtr geom, int force_multi)
3735
/* attempts to rearrange a generic Geometry into a (multi)polygon */
3736
struct splite_internal_cache *cache =
3737
(struct splite_internal_cache *) p_cache;
3738
GEOSContextHandle_t handle = NULL;
3741
if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3742
|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3744
handle = cache->GEOS_handle;
3747
gaiaResetGeosMsg_r (cache);
3748
return gaiaPolygonizeCommon (cache, handle, geom, force_multi);
2870
3751
GAIAGEO_DECLARE int
2986
3964
if (evalGeosCache
2987
3965
(cache, geom1, blob1, size1, geom2, blob2, size2, &gPrep, &geom))
2989
g2 = gaiaToGeos (geom);
3967
g2 = gaiaToGeos_r (cache, geom);
2990
3968
if (geom == geom2)
2991
ret = GEOSPreparedCoveredBy (gPrep, g2);
3969
ret = GEOSPreparedCoveredBy_r (handle, gPrep, g2);
2993
ret = GEOSPreparedCovers (gPrep, g2);
2994
GEOSGeom_destroy (g2);
3971
ret = GEOSPreparedCovers_r (handle, gPrep, g2);
3972
GEOSGeom_destroy_r (handle, g2);
3000
g1 = gaiaToGeos (geom1);
3001
g2 = gaiaToGeos (geom2);
3002
ret = GEOSCoveredBy (g1, g2);
3003
GEOSGeom_destroy (g1);
3004
GEOSGeom_destroy (g2);
3978
g1 = gaiaToGeos_r (cache, geom1);
3979
g2 = gaiaToGeos_r (cache, geom2);
3980
ret = GEOSCoveredBy_r (handle, g1, g2);
3981
GEOSGeom_destroy_r (handle, g1);
3982
GEOSGeom_destroy_r (handle, g2);
3010
GAIAGEO_DECLARE gaiaGeomCollPtr
3011
gaiaLineInterpolatePoint (gaiaGeomCollPtr geom, double fraction)
3014
* attempts to intepolate a point on line at dist "fraction"
3016
* the fraction is expressed into the range from 0.0 to 1.0
3021
gaiaGeomCollPtr result;
3023
gaiaLinestringPtr ln;
3032
/* checking if a single Linestring has been passed */
3033
pt = geom->FirstPoint;
3039
ln = geom->FirstLinestring;
3045
pg = geom->FirstPolygon;
3051
if (pts == 0 && lns == 1 && pgs == 0)
3056
g = gaiaToGeos (geom);
3057
if (GEOSLength (g, &length))
3059
/* transforming fraction to length */
3064
projection = length * fraction;
3068
GEOSGeom_destroy (g);
3071
g_pt = GEOSInterpolate (g, projection);
3072
GEOSGeom_destroy (g);
3075
if (geom->DimensionModel == GAIA_XY_Z)
3076
result = gaiaFromGeos_XYZ (g_pt);
3077
else if (geom->DimensionModel == GAIA_XY_M)
3078
result = gaiaFromGeos_XYM (g_pt);
3079
else if (geom->DimensionModel == GAIA_XY_Z_M)
3080
result = gaiaFromGeos_XYZM (g_pt);
3082
result = gaiaFromGeos_XY (g_pt);
3083
GEOSGeom_destroy (g_pt);
3086
result->Srid = geom->Srid;
3090
GAIAGEO_DECLARE gaiaGeomCollPtr
3091
gaiaLineInterpolateEquidistantPoints (gaiaGeomCollPtr geom, double distance)
3094
* attempts to intepolate a set of points on line at regular distances
3099
gaiaGeomCollPtr result;
3100
gaiaGeomCollPtr xpt;
3102
gaiaLinestringPtr ln;
3107
double current_length = 0.0;
3110
if (distance <= 0.0)
3113
/* checking if a single Linestring has been passed */
3114
pt = geom->FirstPoint;
3120
ln = geom->FirstLinestring;
3126
pg = geom->FirstPolygon;
3132
if (pts == 0 && lns == 1 && pgs == 0)
3137
g = gaiaToGeos (geom);
3138
if (GEOSLength (g, &length))
3140
if (length <= distance)
3142
/* the line is too short to apply interpolation */
3143
GEOSGeom_destroy (g);
3149
GEOSGeom_destroy (g);
3153
/* creating the MultiPoint [always supporting M] */
3154
if (geom->DimensionModel == GAIA_XY_Z
3155
|| geom->DimensionModel == GAIA_XY_Z_M)
3156
result = gaiaAllocGeomCollXYZM ();
3158
result = gaiaAllocGeomCollXYM ();
3161
GEOSGeom_destroy (g);
3167
/* increasing the current distance */
3168
current_length += distance;
3169
if (current_length >= length)
3171
/* interpolating a point */
3172
g_pt = GEOSInterpolate (g, current_length);
3175
if (geom->DimensionModel == GAIA_XY_Z)
3177
xpt = gaiaFromGeos_XYZ (g_pt);
3180
pt = xpt->FirstPoint;
3183
gaiaAddPointToGeomCollXYZM (result, pt->X, pt->Y, pt->Z,
3186
else if (geom->DimensionModel == GAIA_XY_M)
3188
xpt = gaiaFromGeos_XYM (g_pt);
3191
pt = xpt->FirstPoint;
3194
gaiaAddPointToGeomCollXYM (result, pt->X, pt->Y,
3197
else if (geom->DimensionModel == GAIA_XY_Z_M)
3199
xpt = gaiaFromGeos_XYZM (g_pt);
3202
pt = xpt->FirstPoint;
3205
gaiaAddPointToGeomCollXYZM (result, pt->X, pt->Y, pt->Z,
3210
xpt = gaiaFromGeos_XY (g_pt);
3213
pt = xpt->FirstPoint;
3216
gaiaAddPointToGeomCollXYM (result, pt->X, pt->Y,
3219
GEOSGeom_destroy (g_pt);
3220
gaiaFreeGeomColl (xpt);
3222
GEOSGeom_destroy (g);
3223
result->Srid = geom->Srid;
3224
result->DeclaredType = GAIA_MULTIPOINT;
3229
GEOSGeom_destroy (g_pt);
3230
GEOSGeom_destroy (g);
3231
gaiaFreeGeomColl (result);
3235
GAIAGEO_DECLARE double
3236
gaiaLineLocatePoint (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
3239
* attempts to compute the location of the closest point on LineString
3240
* to the given Point, as a fraction of total 2d line length
3242
* the fraction is expressed into the range from 0.0 to 1.0
3254
gaiaLinestringPtr ln;
3258
if (!geom1 || !geom2)
3261
/* checking if a single Linestring has been passed */
3262
pt = geom1->FirstPoint;
3268
ln = geom1->FirstLinestring;
3274
pg = geom1->FirstPolygon;
3280
if (pts1 == 0 && lns1 >= 1 && pgs1 == 0)
3285
/* checking if a single Point has been passed */
3286
pt = geom2->FirstPoint;
3292
ln = geom2->FirstLinestring;
3298
pg = geom2->FirstPolygon;
3304
if (pts2 == 1 && lns2 == 0 && pgs2 == 0)
3309
g1 = gaiaToGeos (geom1);
3310
g2 = gaiaToGeos (geom2);
3311
projection = GEOSProject (g1, g2);
3312
if (GEOSLength (g1, &length))
3314
/* normalizing as a fraction between 0.0 and 1.0 */
3315
result = projection / length;
3319
GEOSGeom_destroy (g1);
3320
GEOSGeom_destroy (g2);
3324
GAIAGEO_DECLARE gaiaGeomCollPtr
3325
gaiaLineSubstring (gaiaGeomCollPtr geom, double start_fraction,
3326
double end_fraction)
3329
* attempts to build a new Linestring being a substring of the input one starting
3330
* and ending at the given fractions of total 2d length
3335
gaiaGeomCollPtr result;
3337
gaiaLinestringPtr ln;
3338
gaiaLinestringPtr out;
3341
GEOSGeometry *g_start;
3342
GEOSGeometry *g_end;
3343
GEOSCoordSequence *cs;
3344
const GEOSCoordSequence *in_cs;
3362
/* checking if a single Linestring has been passed */
3363
pt = geom->FirstPoint;
3369
ln = geom->FirstLinestring;
3375
pg = geom->FirstPolygon;
3381
if (pts == 0 && lns == 1 && pgs == 0)
3386
if (start_fraction < 0.0)
3387
start_fraction = 0.0;
3388
if (start_fraction > 1.0)
3389
start_fraction = 1.0;
3390
if (end_fraction < 0.0)
3392
if (end_fraction > 1.0)
3394
if (start_fraction >= end_fraction)
3396
g = gaiaToGeos (geom);
3397
if (GEOSLength (g, &length))
3399
start = length * start_fraction;
3400
end = length * end_fraction;
3404
GEOSGeom_destroy (g);
3407
g_start = GEOSInterpolate (g, start);
3408
g_end = GEOSInterpolate (g, end);
3409
GEOSGeom_destroy (g);
3410
if (!g_start || !g_end)
3413
/* identifying first and last valid vertex */
3414
ln = geom->FirstLinestring;
3415
for (iv = 0; iv < ln->Points; iv++)
3420
switch (ln->DimensionModel)
3423
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
3426
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
3429
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
3432
gaiaGetPoint (ln->Coords, iv, &x, &y);
3438
cs = GEOSCoordSeq_create (2, 2);
3439
GEOSCoordSeq_setX (cs, 0, x0);
3440
GEOSCoordSeq_setY (cs, 0, y0);
3441
GEOSCoordSeq_setX (cs, 1, x);
3442
GEOSCoordSeq_setY (cs, 1, y);
3443
segm = GEOSGeom_createLineString (cs);
3444
GEOSLength (segm, &length);
3446
GEOSGeom_destroy (segm);
3447
if (total > start && i_start < 0)
3455
if (i_start < 0 || i_end < 0)
3462
points = i_end - i_start + 3;
3464
/* creating the output geometry */
3465
switch (ln->DimensionModel)
3468
result = gaiaAllocGeomCollXYZ ();
3471
result = gaiaAllocGeomCollXYM ();
3474
result = gaiaAllocGeomCollXYZM ();
3477
result = gaiaAllocGeomColl ();
3480
result->Srid = geom->Srid;
3481
out = gaiaAddLinestringToGeomColl (result, points);
3485
in_cs = GEOSGeom_getCoordSeq (g_start);
3486
GEOSCoordSeq_getDimensions (in_cs, &dims);
3489
GEOSCoordSeq_getX (in_cs, 0, &x);
3490
GEOSCoordSeq_getY (in_cs, 0, &y);
3491
GEOSCoordSeq_getZ (in_cs, 0, &z);
3496
GEOSCoordSeq_getX (in_cs, 0, &x);
3497
GEOSCoordSeq_getY (in_cs, 0, &y);
3501
GEOSGeom_destroy (g_start);
3502
switch (out->DimensionModel)
3505
gaiaSetPointXYZ (out->Coords, points, x, y, z);
3508
gaiaSetPointXYM (out->Coords, points, x, y, 0.0);
3511
gaiaSetPointXYZM (out->Coords, points, x, y, z, 0.0);
3514
gaiaSetPoint (out->Coords, points, x, y);
3519
if (i_start < 0 || i_end < 0)
3523
for (iv = i_start; iv <= i_end; iv++)
3527
switch (ln->DimensionModel)
3530
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
3533
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
3536
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
3539
gaiaGetPoint (ln->Coords, iv, &x, &y);
3542
switch (out->DimensionModel)
3545
gaiaSetPointXYZ (out->Coords, points, x, y, z);
3548
gaiaSetPointXYM (out->Coords, points, x, y, 0.0);
3551
gaiaSetPointXYZM (out->Coords, points, x, y, z, 0.0);
3554
gaiaSetPoint (out->Coords, points, x, y);
3562
in_cs = GEOSGeom_getCoordSeq (g_end);
3563
GEOSCoordSeq_getDimensions (in_cs, &dims);
3566
GEOSCoordSeq_getX (in_cs, 0, &x);
3567
GEOSCoordSeq_getY (in_cs, 0, &y);
3568
GEOSCoordSeq_getZ (in_cs, 0, &z);
3573
GEOSCoordSeq_getX (in_cs, 0, &x);
3574
GEOSCoordSeq_getY (in_cs, 0, &y);
3578
GEOSGeom_destroy (g_end);
3579
switch (out->DimensionModel)
3582
gaiaSetPointXYZ (out->Coords, points, x, y, z);
3585
gaiaSetPointXYM (out->Coords, points, x, y, 0.0);
3588
gaiaSetPointXYZM (out->Coords, points, x, y, z, 0.0);
3591
gaiaSetPoint (out->Coords, points, x, y);
3597
static GEOSGeometry *
3598
buildGeosPoints (const gaiaGeomCollPtr gaia)
3600
/* converting a GAIA Geometry into a GEOS Geometry of POINTS */
3611
gaiaLinestringPtr ln;
3615
GEOSGeometry *geos_item;
3616
GEOSGeometry **geos_coll;
3617
GEOSCoordSequence *cs;
3620
pt = gaia->FirstPoint;
3623
/* counting how many POINTs are there */
3627
ln = gaia->FirstLinestring;
3630
/* counting how many POINTs are there */
3634
pg = gaia->FirstPolygon;
3637
/* counting how many POINTs are there */
3639
pts += rng->Points - 1; /* exterior ring */
3640
for (ib = 0; ib < pg->NumInteriors; ib++)
3643
rng = pg->Interiors + ib;
3644
pts += rng->Points - 1;
3650
switch (gaia->DimensionModel)
3661
geos_coll = malloc (sizeof (GEOSGeometry *) * (pts));
3662
pt = gaia->FirstPoint;
3665
cs = GEOSCoordSeq_create (1, dims);
3666
switch (pt->DimensionModel)
3670
GEOSCoordSeq_setX (cs, 0, pt->X);
3671
GEOSCoordSeq_setY (cs, 0, pt->Y);
3672
GEOSCoordSeq_setZ (cs, 0, pt->Z);
3675
GEOSCoordSeq_setX (cs, 0, pt->X);
3676
GEOSCoordSeq_setY (cs, 0, pt->Y);
3679
geos_item = GEOSGeom_createPoint (cs);
3680
*(geos_coll + nItem++) = geos_item;
3683
ln = gaia->FirstLinestring;
3686
for (iv = 0; iv < ln->Points; iv++)
3690
switch (ln->DimensionModel)
3693
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
3696
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
3699
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
3702
gaiaGetPoint (ln->Coords, iv, &x, &y);
3705
cs = GEOSCoordSeq_create (1, dims);
3708
GEOSCoordSeq_setX (cs, 0, x);
3709
GEOSCoordSeq_setY (cs, 0, y);
3710
GEOSCoordSeq_setZ (cs, 0, z);
3714
GEOSCoordSeq_setX (cs, 0, x);
3715
GEOSCoordSeq_setY (cs, 0, y);
3717
geos_item = GEOSGeom_createPoint (cs);
3718
*(geos_coll + nItem++) = geos_item;
3722
pg = gaia->FirstPolygon;
3726
for (iv = 1; iv < rng->Points; iv++)
3731
switch (rng->DimensionModel)
3734
gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3737
gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3740
gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3743
gaiaGetPoint (rng->Coords, iv, &x, &y);
3746
cs = GEOSCoordSeq_create (1, dims);
3749
GEOSCoordSeq_setX (cs, 0, x);
3750
GEOSCoordSeq_setY (cs, 0, y);
3751
GEOSCoordSeq_setZ (cs, 0, z);
3755
GEOSCoordSeq_setX (cs, 0, x);
3756
GEOSCoordSeq_setY (cs, 0, y);
3758
geos_item = GEOSGeom_createPoint (cs);
3759
*(geos_coll + nItem++) = geos_item;
3761
for (ib = 0; ib < pg->NumInteriors; ib++)
3764
rng = pg->Interiors + ib;
3765
for (iv = 1; iv < rng->Points; iv++)
3770
switch (rng->DimensionModel)
3773
gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3776
gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3779
gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3782
gaiaGetPoint (rng->Coords, iv, &x, &y);
3785
cs = GEOSCoordSeq_create (1, dims);
3788
GEOSCoordSeq_setX (cs, 0, x);
3789
GEOSCoordSeq_setY (cs, 0, y);
3790
GEOSCoordSeq_setZ (cs, 0, z);
3794
GEOSCoordSeq_setX (cs, 0, x);
3795
GEOSCoordSeq_setY (cs, 0, y);
3797
geos_item = GEOSGeom_createPoint (cs);
3798
*(geos_coll + nItem++) = geos_item;
3803
geos = GEOSGeom_createCollection (GEOS_MULTIPOINT, geos_coll, pts);
3805
GEOSSetSRID (geos, gaia->Srid);
3809
static GEOSGeometry *
3810
buildGeosSegments (const gaiaGeomCollPtr gaia)
3812
/* converting a GAIA Geometry into a GEOS Geometry of SEGMENTS */
3825
gaiaLinestringPtr ln;
3829
GEOSGeometry *geos_item;
3830
GEOSGeometry **geos_coll;
3831
GEOSCoordSequence *cs;
3834
ln = gaia->FirstLinestring;
3837
/* counting how many SEGMENTs are there */
3838
segms += ln->Points - 1;
3841
pg = gaia->FirstPolygon;
3844
/* counting how many SEGMENTs are there */
3846
segms += rng->Points - 1; /* exterior ring */
3847
for (ib = 0; ib < pg->NumInteriors; ib++)
3850
rng = pg->Interiors + ib;
3851
segms += rng->Points - 1;
3857
switch (gaia->DimensionModel)
3868
geos_coll = malloc (sizeof (GEOSGeometry *) * (segms));
3869
ln = gaia->FirstLinestring;
3872
for (iv = 0; iv < ln->Points; iv++)
3876
switch (ln->DimensionModel)
3879
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
3882
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
3885
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
3888
gaiaGetPoint (ln->Coords, iv, &x, &y);
3893
cs = GEOSCoordSeq_create (2, dims);
3896
GEOSCoordSeq_setX (cs, 0, x0);
3897
GEOSCoordSeq_setY (cs, 0, y0);
3898
GEOSCoordSeq_setZ (cs, 0, z0);
3899
GEOSCoordSeq_setX (cs, 1, x);
3900
GEOSCoordSeq_setY (cs, 1, y);
3901
GEOSCoordSeq_setZ (cs, 1, z);
3905
GEOSCoordSeq_setX (cs, 0, x0);
3906
GEOSCoordSeq_setY (cs, 0, y0);
3907
GEOSCoordSeq_setX (cs, 1, x);
3908
GEOSCoordSeq_setY (cs, 1, y);
3910
geos_item = GEOSGeom_createLineString (cs);
3911
*(geos_coll + nItem++) = geos_item;
3919
pg = gaia->FirstPolygon;
3923
for (iv = 0; iv < rng->Points; iv++)
3928
switch (rng->DimensionModel)
3931
gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3934
gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3937
gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3940
gaiaGetPoint (rng->Coords, iv, &x, &y);
3945
cs = GEOSCoordSeq_create (2, dims);
3948
GEOSCoordSeq_setX (cs, 0, x0);
3949
GEOSCoordSeq_setY (cs, 0, y0);
3950
GEOSCoordSeq_setZ (cs, 0, z0);
3951
GEOSCoordSeq_setX (cs, 1, x);
3952
GEOSCoordSeq_setY (cs, 1, y);
3953
GEOSCoordSeq_setZ (cs, 1, z);
3957
GEOSCoordSeq_setX (cs, 0, x0);
3958
GEOSCoordSeq_setY (cs, 0, y0);
3959
GEOSCoordSeq_setX (cs, 1, x);
3960
GEOSCoordSeq_setY (cs, 1, y);
3962
geos_item = GEOSGeom_createLineString (cs);
3963
*(geos_coll + nItem++) = geos_item;
3969
for (ib = 0; ib < pg->NumInteriors; ib++)
3972
rng = pg->Interiors + ib;
3973
for (iv = 0; iv < rng->Points; iv++)
3978
switch (rng->DimensionModel)
3981
gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3984
gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3987
gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3990
gaiaGetPoint (rng->Coords, iv, &x, &y);
3995
cs = GEOSCoordSeq_create (2, dims);
3998
GEOSCoordSeq_setX (cs, 0, x0);
3999
GEOSCoordSeq_setY (cs, 0, y0);
4000
GEOSCoordSeq_setZ (cs, 0, z0);
4001
GEOSCoordSeq_setX (cs, 1, x);
4002
GEOSCoordSeq_setY (cs, 1, y);
4003
GEOSCoordSeq_setZ (cs, 1, z);
4007
GEOSCoordSeq_setX (cs, 0, x0);
4008
GEOSCoordSeq_setY (cs, 0, y0);
4009
GEOSCoordSeq_setX (cs, 1, x);
4010
GEOSCoordSeq_setY (cs, 1, y);
4012
geos_item = GEOSGeom_createLineString (cs);
4013
*(geos_coll + nItem++) = geos_item;
4022
geos = GEOSGeom_createCollection (GEOS_MULTILINESTRING, geos_coll, segms);
4024
GEOSSetSRID (geos, gaia->Srid);
4028
GAIAGEO_DECLARE gaiaGeomCollPtr
4029
gaiaShortestLine (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
4031
/* attempts to compute the the shortest line between two geometries */
4032
GEOSGeometry *g1_points;
4033
GEOSGeometry *g1_segments;
4034
const GEOSGeometry *g1_item;
4035
GEOSGeometry *g2_points;
4036
GEOSGeometry *g2_segments;
4037
const GEOSGeometry *g2_item;
4038
const GEOSCoordSequence *cs;
4040
gaiaGeomCollPtr result;
4041
gaiaLinestringPtr ln;
4054
double min_dist = DBL_MAX;
4056
if (!geom1 || !geom2)
4059
g1_points = buildGeosPoints (geom1);
4060
g1_segments = buildGeosSegments (geom1);
4061
g2_points = buildGeosPoints (geom2);
4062
g2_segments = buildGeosSegments (geom2);
4064
if (g1_points && g2_points)
4066
/* computing distances between POINTs */
4067
nItems1 = GEOSGetNumGeometries (g1_points);
4068
nItems2 = GEOSGetNumGeometries (g2_points);
4069
for (it1 = 0; it1 < nItems1; it1++)
4071
g1_item = GEOSGetGeometryN (g1_points, it1);
4072
for (it2 = 0; it2 < nItems2; it2++)
4074
g2_item = GEOSGetGeometryN (g2_points, it2);
4075
if (GEOSDistance (g1_item, g2_item, &dist))
4077
if (dist < min_dist)
4079
/* saving min-dist points */
4081
cs = GEOSGeom_getCoordSeq (g1_item);
4082
GEOSCoordSeq_getDimensions (cs, &dims);
4085
GEOSCoordSeq_getX (cs, 0, &x_ini);
4086
GEOSCoordSeq_getY (cs, 0, &y_ini);
4087
GEOSCoordSeq_getZ (cs, 0, &z_ini);
4091
GEOSCoordSeq_getX (cs, 0, &x_ini);
4092
GEOSCoordSeq_getY (cs, 0, &y_ini);
4095
cs = GEOSGeom_getCoordSeq (g2_item);
4096
GEOSCoordSeq_getDimensions (cs, &dims);
4099
GEOSCoordSeq_getX (cs, 0, &x_fin);
4100
GEOSCoordSeq_getY (cs, 0, &y_fin);
4101
GEOSCoordSeq_getZ (cs, 0, &z_fin);
4105
GEOSCoordSeq_getX (cs, 0, &x_fin);
4106
GEOSCoordSeq_getY (cs, 0, &y_fin);
4115
if (g1_points && g2_segments)
4117
/* computing distances between POINTs (g1) and SEGMENTs (g2) */
4118
nItems1 = GEOSGetNumGeometries (g1_points);
4119
nItems2 = GEOSGetNumGeometries (g2_segments);
4120
for (it1 = 0; it1 < nItems1; it1++)
4122
g1_item = GEOSGetGeometryN (g1_points, it1);
4123
for (it2 = 0; it2 < nItems2; it2++)
4125
g2_item = GEOSGetGeometryN (g2_segments, it2);
4126
if (GEOSDistance (g1_item, g2_item, &dist))
4128
if (dist < min_dist)
4130
/* saving min-dist points */
4131
projection = GEOSProject (g2_item, g1_item);
4132
g_pt = GEOSInterpolate (g2_item, projection);
4136
cs = GEOSGeom_getCoordSeq (g1_item);
4137
GEOSCoordSeq_getDimensions (cs, &dims);
4140
GEOSCoordSeq_getX (cs, 0, &x_ini);
4141
GEOSCoordSeq_getY (cs, 0, &y_ini);
4142
GEOSCoordSeq_getZ (cs, 0, &z_ini);
4146
GEOSCoordSeq_getX (cs, 0, &x_ini);
4147
GEOSCoordSeq_getY (cs, 0, &y_ini);
4150
cs = GEOSGeom_getCoordSeq (g_pt);
4151
GEOSCoordSeq_getDimensions (cs, &dims);
4154
GEOSCoordSeq_getX (cs, 0, &x_fin);
4155
GEOSCoordSeq_getY (cs, 0, &y_fin);
4156
GEOSCoordSeq_getZ (cs, 0, &z_fin);
4160
GEOSCoordSeq_getX (cs, 0, &x_fin);
4161
GEOSCoordSeq_getY (cs, 0, &y_fin);
4164
GEOSGeom_destroy (g_pt);
4172
if (g1_segments && g2_points)
4174
/* computing distances between SEGMENTs (g1) and POINTs (g2) */
4175
nItems1 = GEOSGetNumGeometries (g1_segments);
4176
nItems2 = GEOSGetNumGeometries (g2_points);
4177
for (it1 = 0; it1 < nItems1; it1++)
4179
g1_item = GEOSGetGeometryN (g1_segments, it1);
4180
for (it2 = 0; it2 < nItems2; it2++)
4182
g2_item = GEOSGetGeometryN (g2_points, it2);
4183
if (GEOSDistance (g1_item, g2_item, &dist))
4185
if (dist < min_dist)
4187
/* saving min-dist points */
4188
projection = GEOSProject (g1_item, g2_item);
4189
g_pt = GEOSInterpolate (g1_item, projection);
4193
cs = GEOSGeom_getCoordSeq (g_pt);
4194
GEOSCoordSeq_getDimensions (cs, &dims);
4197
GEOSCoordSeq_getX (cs, 0, &x_ini);
4198
GEOSCoordSeq_getY (cs, 0, &y_ini);
4199
GEOSCoordSeq_getZ (cs, 0, &z_ini);
4203
GEOSCoordSeq_getX (cs, 0, &x_ini);
4204
GEOSCoordSeq_getY (cs, 0, &y_ini);
4207
cs = GEOSGeom_getCoordSeq (g2_item);
4208
GEOSCoordSeq_getDimensions (cs, &dims);
4211
GEOSCoordSeq_getX (cs, 0, &x_fin);
4212
GEOSCoordSeq_getY (cs, 0, &y_fin);
4213
GEOSCoordSeq_getZ (cs, 0, &z_fin);
4217
GEOSCoordSeq_getX (cs, 0, &x_fin);
4218
GEOSCoordSeq_getY (cs, 0, &y_fin);
4221
GEOSGeom_destroy (g_pt);
4229
GEOSGeom_destroy (g1_points);
4231
GEOSGeom_destroy (g1_segments);
4233
GEOSGeom_destroy (g2_points);
4235
GEOSGeom_destroy (g2_segments);
4236
if (min_dist == DBL_MAX || min_dist <= 0.0)
4239
/* building the shortest line */
4240
switch (geom1->DimensionModel)
4243
result = gaiaAllocGeomCollXYZ ();
4246
result = gaiaAllocGeomCollXYM ();
4249
result = gaiaAllocGeomCollXYZM ();
4252
result = gaiaAllocGeomColl ();
4255
result->Srid = geom1->Srid;
4256
ln = gaiaAddLinestringToGeomColl (result, 2);
4257
switch (ln->DimensionModel)
4260
gaiaSetPointXYZ (ln->Coords, 0, x_ini, y_ini, z_ini);
4261
gaiaSetPointXYZ (ln->Coords, 1, x_fin, y_fin, z_fin);
4264
gaiaSetPointXYM (ln->Coords, 0, x_ini, y_ini, 0.0);
4265
gaiaSetPointXYM (ln->Coords, 1, x_fin, y_fin, 0.0);
4268
gaiaSetPointXYZM (ln->Coords, 0, x_ini, y_ini, z_ini, 0.0);
4269
gaiaSetPointXYZM (ln->Coords, 1, x_fin, y_fin, z_fin, 0.0);
4272
gaiaSetPoint (ln->Coords, 0, x_ini, y_ini);
4273
gaiaSetPoint (ln->Coords, 1, x_fin, y_fin);
4279
GAIAGEO_DECLARE gaiaGeomCollPtr
4280
gaiaSnap (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2, double tolerance)
4282
/* attempts to "snap" geom1 on geom2 using the given tolerance */
4286
gaiaGeomCollPtr result;
4287
if (!geom1 || !geom2)
4290
g1 = gaiaToGeos (geom1);
4291
g2 = gaiaToGeos (geom2);
4292
g3 = GEOSSnap (g1, g2, tolerance);
4293
GEOSGeom_destroy (g1);
4294
GEOSGeom_destroy (g2);
4297
if (geom1->DimensionModel == GAIA_XY_Z)
4298
result = gaiaFromGeos_XYZ (g3);
4299
else if (geom1->DimensionModel == GAIA_XY_M)
4300
result = gaiaFromGeos_XYM (g3);
4301
else if (geom1->DimensionModel == GAIA_XY_Z_M)
4302
result = gaiaFromGeos_XYZM (g3);
4304
result = gaiaFromGeos_XY (g3);
4305
GEOSGeom_destroy (g3);
4308
result->Srid = geom1->Srid;
4312
GAIAGEO_DECLARE gaiaGeomCollPtr
4313
gaiaLineMerge (gaiaGeomCollPtr geom)
4315
/* attempts to reassemble lines from a collection of sparse fragments */
4318
gaiaGeomCollPtr result;
4321
if (gaiaIsToxic (geom))
4324
g1 = gaiaToGeos (geom);
4325
g2 = GEOSLineMerge (g1);
4326
GEOSGeom_destroy (g1);
4329
if (geom->DimensionModel == GAIA_XY_Z)
4330
result = gaiaFromGeos_XYZ (g2);
4331
else if (geom->DimensionModel == GAIA_XY_M)
4332
result = gaiaFromGeos_XYM (g2);
4333
else if (geom->DimensionModel == GAIA_XY_Z_M)
4334
result = gaiaFromGeos_XYZM (g2);
4336
result = gaiaFromGeos_XY (g2);
4337
GEOSGeom_destroy (g2);
4340
result->Srid = geom->Srid;
4344
GAIAGEO_DECLARE gaiaGeomCollPtr
4345
gaiaUnaryUnion (gaiaGeomCollPtr geom)
4347
/* Unary Union (single Collection) */
4350
gaiaGeomCollPtr result;
4353
if (gaiaIsToxic (geom))
4355
g1 = gaiaToGeos (geom);
4356
g2 = GEOSUnaryUnion (g1);
4357
GEOSGeom_destroy (g1);
4360
if (geom->DimensionModel == GAIA_XY_Z)
4361
result = gaiaFromGeos_XYZ (g2);
4362
else if (geom->DimensionModel == GAIA_XY_M)
4363
result = gaiaFromGeos_XYM (g2);
4364
else if (geom->DimensionModel == GAIA_XY_Z_M)
4365
result = gaiaFromGeos_XYZM (g2);
4367
result = gaiaFromGeos_XY (g2);
4368
GEOSGeom_destroy (g2);
4371
result->Srid = geom->Srid;
4376
rotateRingBeforeCut (gaiaLinestringPtr ln, gaiaPointPtr node)
4378
/* rotating a Ring, so to ensure that Start/End points match the node */
4387
gaiaLinestringPtr new_ln = NULL;
4389
if (ln->DimensionModel == GAIA_XY_Z)
4390
new_ln = gaiaAllocLinestringXYZ (ln->Points);
4391
else if (ln->DimensionModel == GAIA_XY_M)
4392
new_ln = gaiaAllocLinestringXYM (ln->Points);
4393
else if (ln->DimensionModel == GAIA_XY_Z_M)
4394
new_ln = gaiaAllocLinestringXYZM (ln->Points);
4396
new_ln = gaiaAllocLinestring (ln->Points);
4399
for (iv = 0; iv < ln->Points; iv++)
4401
if (ln->DimensionModel == GAIA_XY_Z)
4403
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
4405
else if (ln->DimensionModel == GAIA_XY_M)
4407
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
4409
else if (ln->DimensionModel == GAIA_XY_Z_M)
4411
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
4415
gaiaGetPoint (ln->Coords, iv, &x, &y);
4417
if (!copy) /* CAZZO */
4419
if (ln->DimensionModel == GAIA_XY_Z
4420
|| ln->DimensionModel == GAIA_XY_Z_M)
4422
if (node->X == x && node->Y == y && node->Z == z)
4428
else if (node->X == x && node->Y == y)
4436
/* copying points */
4437
if (ln->DimensionModel == GAIA_XY_Z)
4439
gaiaSetPointXYZ (new_ln->Coords, io, x, y, z);
4441
else if (ln->DimensionModel == GAIA_XY_M)
4443
gaiaSetPointXYM (new_ln->Coords, io, x, y, m);
4445
else if (ln->DimensionModel == GAIA_XY_Z_M)
4447
gaiaSetPointXYZM (new_ln->Coords, io, x, y, z, m);
4451
gaiaSetPoint (new_ln->Coords, io, x, y);
4458
gaiaFreeLinestring (new_ln);
4463
for (iv = 1; iv <= base_idx; iv++)
4465
if (ln->DimensionModel == GAIA_XY_Z)
4467
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
4469
else if (ln->DimensionModel == GAIA_XY_M)
4471
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
4473
else if (ln->DimensionModel == GAIA_XY_Z_M)
4475
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
4479
gaiaGetPoint (ln->Coords, iv, &x, &y);
4481
if (ln->DimensionModel == GAIA_XY_Z)
4483
gaiaSetPointXYZ (new_ln->Coords, io, x, y, z);
4485
else if (ln->DimensionModel == GAIA_XY_M)
4487
gaiaSetPointXYM (new_ln->Coords, io, x, y, m);
4489
else if (ln->DimensionModel == GAIA_XY_Z_M)
4491
gaiaSetPointXYZM (new_ln->Coords, io, x, y, z, m);
4495
gaiaSetPoint (new_ln->Coords, io, x, y);
4501
for (iv = 0; iv < new_ln->Points; iv++)
4503
if (ln->DimensionModel == GAIA_XY_Z)
4505
gaiaGetPointXYZ (new_ln->Coords, iv, &x, &y, &z);
4507
else if (ln->DimensionModel == GAIA_XY_M)
4509
gaiaGetPointXYM (new_ln->Coords, iv, &x, &y, &m);
4511
else if (ln->DimensionModel == GAIA_XY_Z_M)
4513
gaiaGetPointXYZM (new_ln->Coords, iv, &x, &y, &z, &m);
4517
gaiaGetPoint (new_ln->Coords, iv, &x, &y);
4519
if (ln->DimensionModel == GAIA_XY_Z)
4521
gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
4523
else if (ln->DimensionModel == GAIA_XY_M)
4525
gaiaSetPointXYM (ln->Coords, iv, x, y, m);
4527
else if (ln->DimensionModel == GAIA_XY_Z_M)
4529
gaiaSetPointXYZM (ln->Coords, iv, x, y, z, m);
4533
gaiaSetPoint (ln->Coords, iv, x, y);
4536
gaiaFreeLinestring (new_ln);
4540
extractSubLine (gaiaGeomCollPtr result, gaiaLinestringPtr ln, int i_start,
4543
/* extracting s SubLine */
4546
int pts = i_end - i_start + 1;
4547
gaiaLinestringPtr new_ln = NULL;
4553
new_ln = gaiaAddLinestringToGeomColl (result, pts);
4555
for (iv = i_start; iv <= i_end; iv++)
4557
if (ln->DimensionModel == GAIA_XY_Z)
4559
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
4561
else if (ln->DimensionModel == GAIA_XY_M)
4563
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
4565
else if (ln->DimensionModel == GAIA_XY_Z_M)
4567
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
4571
gaiaGetPoint (ln->Coords, iv, &x, &y);
4573
if (ln->DimensionModel == GAIA_XY_Z)
4575
gaiaSetPointXYZ (new_ln->Coords, io, x, y, z);
4577
else if (ln->DimensionModel == GAIA_XY_M)
4579
gaiaSetPointXYM (new_ln->Coords, io, x, y, m);
4581
else if (ln->DimensionModel == GAIA_XY_Z_M)
4583
gaiaSetPointXYZM (new_ln->Coords, io, x, y, z, m);
4587
gaiaSetPoint (new_ln->Coords, io, x, y);
4594
cutLineAtNodes (gaiaLinestringPtr ln, gaiaPointPtr pt_base,
4595
gaiaGeomCollPtr result)
4597
/* attempts to cut a single Line accordingly to given nodes */
4607
gaiaPointPtr node = NULL;
4609
if (gaiaIsClosed (ln))
4612
for (iv = 0; iv < ln->Points; iv++)
4614
if (ln->DimensionModel == GAIA_XY_Z)
4616
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
4618
else if (ln->DimensionModel == GAIA_XY_M)
4620
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
4622
else if (ln->DimensionModel == GAIA_XY_Z_M)
4624
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
4628
gaiaGetPoint (ln->Coords, iv, &x, &y);
4633
if (ln->DimensionModel == GAIA_XY_Z
4634
|| ln->DimensionModel == GAIA_XY_Z_M)
4636
if (pt->X == x && pt->Y == y && pt->Z == z)
4642
else if (pt->X == x && pt->Y == y)
4652
rotateRingBeforeCut (ln, node);
4655
for (iv = 1; iv < ln->Points - 1; iv++)
4657
/* identifying sub-linestrings */
4658
if (ln->DimensionModel == GAIA_XY_Z)
4660
gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
4662
else if (ln->DimensionModel == GAIA_XY_M)
4664
gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
4666
else if (ln->DimensionModel == GAIA_XY_Z_M)
4668
gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
4672
gaiaGetPoint (ln->Coords, iv, &x, &y);
4678
if (ln->DimensionModel == GAIA_XY_Z
4679
|| ln->DimensionModel == GAIA_XY_Z_M)
4681
if (pt->X == x && pt->Y == y && pt->Z == z)
4687
else if (pt->X == x && pt->Y == y)
4696
/* cutting the line */
4697
extractSubLine (result, ln, i_start, iv);
4701
if (i_start != 0 && i_start != ln->Points - 1)
4703
/* extracting the last SubLine */
4704
extractSubLine (result, ln, i_start, ln->Points - 1);
4708
/* cloning the untouched Line */
4709
extractSubLine (result, ln, 0, ln->Points - 1);
4713
GAIAGEO_DECLARE gaiaGeomCollPtr
4714
gaiaLinesCutAtNodes (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
4716
/* attempts to cut lines accordingly to nodes */
4724
gaiaLinestringPtr ln;
4726
gaiaGeomCollPtr result = NULL;
4733
/* both Geometryes should have identical Dimensions */
4734
if (geom1->DimensionModel != geom2->DimensionModel)
4737
pt = geom1->FirstPoint;
4743
ln = geom1->FirstLinestring;
4749
pg = geom1->FirstPolygon;
4755
pt = geom2->FirstPoint;
4761
ln = geom2->FirstLinestring;
4767
pg = geom2->FirstPolygon;
4774
/* the first Geometry is expected to contain one or more Linestring(s) */
4775
if (pts1 == 0 && lns1 > 0 && pgs1 == 0)
4779
/* the second Geometry is expected to contain one or more Point(s) */
4780
if (pts2 > 0 && lns2 == 0 && pgs2 == 0)
4785
/* attempting to cut Lines accordingly to Nodes */
4786
if (geom1->DimensionModel == GAIA_XY_Z)
4787
result = gaiaAllocGeomCollXYZ ();
4788
else if (geom1->DimensionModel == GAIA_XY_M)
4789
result = gaiaAllocGeomCollXYM ();
4790
else if (geom1->DimensionModel == GAIA_XY_Z_M)
4791
result = gaiaAllocGeomCollXYZM ();
4793
result = gaiaAllocGeomColl ();
4794
ln = geom1->FirstLinestring;
4797
cutLineAtNodes (ln, geom2->FirstPoint, result);
4800
if (result->FirstLinestring == NULL)
4802
gaiaFreeGeomColl (result);
4805
result->Srid = geom1->Srid;
4809
#endif /* end GEOS advanced features */
4811
#ifdef GEOS_TRUNK /* GEOS experimental features */
4813
GAIAGEO_DECLARE gaiaGeomCollPtr
4814
gaiaDelaunayTriangulation (gaiaGeomCollPtr geom, double tolerance,
4817
/* Delaunay Triangulation */
4820
gaiaGeomCollPtr result;
4823
g1 = gaiaToGeos (geom);
4824
g2 = GEOSDelaunayTriangulation (g1, tolerance, only_edges);
4825
GEOSGeom_destroy (g1);
4828
if (geom->DimensionModel == GAIA_XY_Z)
4829
result = gaiaFromGeos_XYZ (g2);
4830
else if (geom->DimensionModel == GAIA_XY_M)
4831
result = gaiaFromGeos_XYM (g2);
4832
else if (geom->DimensionModel == GAIA_XY_Z_M)
4833
result = gaiaFromGeos_XYZM (g2);
4835
result = gaiaFromGeos_XY (g2);
4836
GEOSGeom_destroy (g2);
4839
result->Srid = geom->Srid;
4841
result->DeclaredType = GAIA_MULTILINESTRING;
4843
result->DeclaredType = GAIA_MULTIPOLYGON;
4847
GAIAGEO_DECLARE gaiaGeomCollPtr
4848
gaiaVoronojDiagram (gaiaGeomCollPtr geom, double extra_frame_size,
4849
double tolerance, int only_edges)
4851
/* Voronoj Diagram */
4854
gaiaGeomCollPtr result;
4861
g1 = gaiaToGeos (geom);
4862
g2 = GEOSDelaunayTriangulation (g1, tolerance, 0);
4863
GEOSGeom_destroy (g1);
4866
if (geom->DimensionModel == GAIA_XY_Z)
4867
result = gaiaFromGeos_XYZ (g2);
4868
else if (geom->DimensionModel == GAIA_XY_M)
4869
result = gaiaFromGeos_XYM (g2);
4870
else if (geom->DimensionModel == GAIA_XY_Z_M)
4871
result = gaiaFromGeos_XYZM (g2);
4873
result = gaiaFromGeos_XY (g2);
4874
GEOSGeom_destroy (g2);
4877
pg = result->FirstPolygon;
4880
/* counting how many triangles are in Delaunay */
4881
if (delaunay_triangle_check (pg))
4887
if (pgs == 0 || errs)
4889
gaiaFreeGeomColl (result);
4893
/* building the Voronoj Diagram from Delaunay */
4894
voronoj = voronoj_build (pgs, result->FirstPolygon, extra_frame_size);
4895
gaiaFreeGeomColl (result);
4897
/* creating the Geometry representing Voronoj */
4898
if (geom->DimensionModel == GAIA_XY_Z)
4899
result = gaiaAllocGeomCollXYZ ();
4900
else if (geom->DimensionModel == GAIA_XY_M)
4901
result = gaiaAllocGeomCollXYM ();
4902
else if (geom->DimensionModel == GAIA_XY_Z_M)
4903
result = gaiaAllocGeomCollXYZM ();
4905
result = gaiaAllocGeomColl ();
4906
result = voronoj_export (voronoj, result, only_edges);
4907
voronoj_free (voronoj);
4909
result->Srid = geom->Srid;
4911
result->DeclaredType = GAIA_MULTILINESTRING;
4913
result->DeclaredType = GAIA_MULTIPOLYGON;
4917
GAIAGEO_DECLARE gaiaGeomCollPtr
4918
gaiaConcaveHull (gaiaGeomCollPtr geom, double factor, double tolerance,
4924
gaiaGeomCollPtr result;
4925
gaiaGeomCollPtr concave_hull;
4931
g1 = gaiaToGeos (geom);
4932
g2 = GEOSDelaunayTriangulation (g1, tolerance, 0);
4933
GEOSGeom_destroy (g1);
4936
if (geom->DimensionModel == GAIA_XY_Z)
4937
result = gaiaFromGeos_XYZ (g2);
4938
else if (geom->DimensionModel == GAIA_XY_M)
4939
result = gaiaFromGeos_XYM (g2);
4940
else if (geom->DimensionModel == GAIA_XY_Z_M)
4941
result = gaiaFromGeos_XYZM (g2);
4943
result = gaiaFromGeos_XY (g2);
4944
GEOSGeom_destroy (g2);
4947
pg = result->FirstPolygon;
4950
/* counting how many triangles are in Delaunay */
4951
if (delaunay_triangle_check (pg))
4957
if (pgs == 0 || errs)
4959
gaiaFreeGeomColl (result);
4963
/* building the Concave Hull from Delaunay */
4965
concave_hull_build (result->FirstPolygon, geom->DimensionModel, factor,
4967
gaiaFreeGeomColl (result);
4970
result = concave_hull;
4972
result->Srid = geom->Srid;
4976
#endif /* end GEOS experimental features */
4978
3988
#endif /* end including GEOS */