#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <float.h>
#include <math.h>
#if defined(_WIN32) && !defined(__MINGW32__)
#include "config-msvc.h"
#else
#include "config.h"
#endif
#include <spatialite_private.h>
#include <spatialite/sqlite.h>
#include <spatialite/gaiageo.h>
#ifdef GEOS_ADVANCED
struct voronoj_triangle
{
double x1;
double y1;
double x2;
double y2;
double x3;
double y3;
double cx;
double cy;
double x_1_2;
double y_1_2;
double x_2_3;
double y_2_3;
double x_3_1;
double y_3_1;
struct voronoj_triangle *tri_1_2;
struct voronoj_triangle *tri_2_3;
struct voronoj_triangle *tri_3_1;
char trace_1_2;
char trace_2_3;
char trace_3_1;
};
struct voronoj_point
{
double coord;
struct voronoj_point *next;
};
struct voronoj_aux
{
struct voronoj_triangle *array;
int count;
double minx;
double miny;
double maxx;
double maxy;
struct voronoj_point *first_up;
struct voronoj_point *last_up;
struct voronoj_point *first_low;
struct voronoj_point *last_low;
struct voronoj_point *first_left;
struct voronoj_point *last_left;
struct voronoj_point *first_right;
struct voronoj_point *last_right;
};
struct concave_hull_str
{
double mean;
double quot;
double count;
};
static double *
voronoj_sorted_up (struct voronoj_aux *voronoj, int *count)
{
double *array = NULL;
int cnt = 0;
int ok = 1;
int i;
struct voronoj_point *pt = voronoj->first_up;
while (pt)
{
cnt++;
pt = pt->next;
}
*count = cnt;
if (cnt == 0)
return NULL;
array = malloc (sizeof (double) * *count);
cnt = 0;
pt = voronoj->first_up;
while (pt)
{
*(array + cnt++) = pt->coord;
pt = pt->next;
}
while (ok)
{
ok = 0;
for (i = 1; i < *count; i++)
{
if (*(array + i - 1) > *(array + i))
{
double save = *(array + i - 1);
*(array + i - 1) = *(array + i);
*(array + i) = save;
ok = 1;
}
}
}
return array;
}
static double *
voronoj_sorted_low (struct voronoj_aux *voronoj, int *count)
{
double *array = NULL;
int cnt = 0;
int ok = 1;
int i;
struct voronoj_point *pt = voronoj->first_low;
while (pt)
{
cnt++;
pt = pt->next;
}
*count = cnt;
if (cnt == 0)
return NULL;
array = malloc (sizeof (double) * *count);
cnt = 0;
pt = voronoj->first_low;
while (pt)
{
*(array + cnt++) = pt->coord;
pt = pt->next;
}
while (ok)
{
ok = 0;
for (i = 1; i < *count; i++)
{
if (*(array + i - 1) > *(array + i))
{
double save = *(array + i - 1);
*(array + i - 1) = *(array + i);
*(array + i) = save;
ok = 1;
}
}
}
return array;
}
static double *
voronoj_sorted_left (struct voronoj_aux *voronoj, int *count)
{
double *array = NULL;
int cnt = 0;
int ok = 1;
int i;
struct voronoj_point *pt = voronoj->first_left;
while (pt)
{
cnt++;
pt = pt->next;
}
*count = cnt;
if (cnt == 0)
return NULL;
array = malloc (sizeof (double) * *count);
cnt = 0;
pt = voronoj->first_left;
while (pt)
{
*(array + cnt++) = pt->coord;
pt = pt->next;
}
while (ok)
{
ok = 0;
for (i = 1; i < *count; i++)
{
if (*(array + i - 1) > *(array + i))
{
double save = *(array + i - 1);
*(array + i - 1) = *(array + i);
*(array + i) = save;
ok = 1;
}
}
}
return array;
}
static double *
voronoj_sorted_right (struct voronoj_aux *voronoj, int *count)
{
double *array = NULL;
int cnt = 0;
int ok = 1;
int i;
struct voronoj_point *pt = voronoj->first_right;
while (pt)
{
cnt++;
pt = pt->next;
}
*count = cnt;
if (cnt == 0)
return NULL;
array = malloc (sizeof (double) * *count);
cnt = 0;
pt = voronoj->first_right;
while (pt)
{
*(array + cnt++) = pt->coord;
pt = pt->next;
}
while (ok)
{
ok = 0;
for (i = 1; i < *count; i++)
{
if (*(array + i - 1) > *(array + i))
{
double save = *(array + i - 1);
*(array + i - 1) = *(array + i);
*(array + i) = save;
ok = 1;
}
}
}
return array;
}
static void
voronoj_add_frame_point (struct voronoj_aux *voronoj, double x, double y)
{
struct voronoj_point *pt = NULL;
if (x == voronoj->minx && y == voronoj->miny)
return;
if (x == voronoj->minx && y == voronoj->maxy)
return;
if (x == voronoj->maxx && y == voronoj->miny)
return;
if (x == voronoj->maxx && y == voronoj->maxy)
return;
if (x == voronoj->minx)
{
pt = malloc (sizeof (struct voronoj_point));
pt->coord = y;
pt->next = NULL;
if (voronoj->first_left == NULL)
voronoj->first_left = pt;
if (voronoj->last_left != NULL)
voronoj->last_left->next = pt;
voronoj->last_left = pt;
}
if (x == voronoj->maxx)
{
pt = malloc (sizeof (struct voronoj_point));
pt->coord = y;
pt->next = NULL;
if (voronoj->first_right == NULL)
voronoj->first_right = pt;
if (voronoj->last_right != NULL)
voronoj->last_right->next = pt;
voronoj->last_right = pt;
}
if (y == voronoj->miny)
{
pt = malloc (sizeof (struct voronoj_point));
pt->coord = x;
pt->next = NULL;
if (voronoj->first_low == NULL)
voronoj->first_low = pt;
if (voronoj->last_low != NULL)
voronoj->last_low->next = pt;
voronoj->last_low = pt;
}
if (y == voronoj->maxy)
{
pt = malloc (sizeof (struct voronoj_point));
pt->coord = x;
pt->next = NULL;
if (voronoj->first_up == NULL)
voronoj->first_up = pt;
if (voronoj->last_up != NULL)
voronoj->last_up->next = pt;
voronoj->last_up = pt;
}
}
static int
voronoj_same_edge (double ax1, double ay1, double ax2, double ay2, double bx1,
double by1, double bx2, double by2)
{
if (ax1 == bx1 && ay1 == by1 && ax2 == bx2 && ay2 == by2)
return 1;
if (ax1 == bx2 && ay1 == by2 && ax2 == bx1 && ay2 == by1)
return 1;
return 0;
}
static int
voronoj_internal (const void *p_cache, struct voronoj_triangle *triangle)
{
int ret;
gaiaGeomCollPtr pt = gaiaAllocGeomColl ();
gaiaGeomCollPtr tri = gaiaAllocGeomColl ();
gaiaPolygonPtr pg = gaiaAddPolygonToGeomColl (tri, 4, 0);
gaiaRingPtr rng = pg->Exterior;
gaiaSetPoint (rng->Coords, 0, triangle->x1, triangle->y1);
gaiaSetPoint (rng->Coords, 1, triangle->x2, triangle->y2);
gaiaSetPoint (rng->Coords, 2, triangle->x3, triangle->y3);
gaiaSetPoint (rng->Coords, 3, triangle->x1, triangle->y1);
gaiaAddPointToGeomColl (pt, triangle->cx, triangle->cy);
gaiaMbrGeometry (pt);
gaiaMbrGeometry (tri);
if (p_cache != NULL)
ret = gaiaGeomCollIntersects_r (p_cache, tri, pt);
else
ret = gaiaGeomCollIntersects (tri, pt);
gaiaFreeGeomColl (pt);
gaiaFreeGeomColl (tri);
return ret;
}
static double
voronoj_test_point (const void *p_cache, double x1, double y1, double x2,
double y2, double x, double y)
{
double dist;
gaiaGeomCollPtr pt = gaiaAllocGeomColl ();
gaiaGeomCollPtr segm = gaiaAllocGeomColl ();
gaiaLinestringPtr ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, x1, y1);
gaiaSetPoint (ln->Coords, 1, x2, y2);
gaiaAddPointToGeomColl (pt, x, y);
if (p_cache != NULL)
gaiaGeomCollDistance_r (p_cache, segm, pt, &dist);
else
gaiaGeomCollDistance (segm, pt, &dist);
gaiaFreeGeomColl (pt);
gaiaFreeGeomColl (segm);
return dist;
}
static int
voronoj_check_nearest_edge (const void *p_cache, struct voronoj_triangle *tri,
int which)
{
double d_1_2;
double d_2_3;
double d_3_1;
gaiaGeomCollPtr pt = gaiaAllocGeomColl ();
gaiaGeomCollPtr segm = gaiaAllocGeomColl ();
gaiaLinestringPtr ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, tri->x1, tri->y1);
gaiaSetPoint (ln->Coords, 1, tri->x2, tri->y2);
gaiaAddPointToGeomColl (pt, tri->cx, tri->cy);
if (p_cache != NULL)
gaiaGeomCollDistance_r (p_cache, segm, pt, &d_1_2);
else
gaiaGeomCollDistance (segm, pt, &d_1_2);
gaiaFreeGeomColl (segm);
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, tri->x2, tri->y2);
gaiaSetPoint (ln->Coords, 1, tri->x3, tri->y3);
if (p_cache != NULL)
gaiaGeomCollDistance_r (p_cache, segm, pt, &d_2_3);
else
gaiaGeomCollDistance (segm, pt, &d_2_3);
gaiaFreeGeomColl (segm);
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, tri->x3, tri->y3);
gaiaSetPoint (ln->Coords, 1, tri->x1, tri->y1);
if (p_cache != NULL)
gaiaGeomCollDistance_r (p_cache, segm, pt, &d_3_1);
else
gaiaGeomCollDistance (segm, pt, &d_3_1);
gaiaFreeGeomColl (segm);
gaiaFreeGeomColl (pt);
if (which == 12 && d_1_2 < d_2_3 && d_1_2 < d_3_1)
return 0;
if (which == 23 && d_2_3 < d_1_2 && d_2_3 < d_3_1)
return 0;
if (which == 31 && d_3_1 < d_1_2 && d_3_1 < d_2_3)
return 0;
return 1;
}
static void
voronoj_minmax (double x, double y, double *minx, double *miny, double *maxx,
double *maxy)
{
if (x < *minx)
*minx = x;
if (y < *miny)
*miny = y;
if (x > *maxx)
*maxx = x;
if (y > *maxy)
*maxy = y;
}
static void
voronoj_frame_point (const void *p_cache, double intercept, double slope,
struct voronoj_aux *voronoj, double cx, double cy,
double mx, double my, int direct, double *x, double *y)
{
double x_up;
double x_low;
double y_left;
double y_right;
double pre_x1 = DBL_MAX;
double pre_y1 = DBL_MAX;
double pre_x2 = DBL_MAX;
double pre_y2 = DBL_MAX;
double d1;
double d2;
if (slope == DBL_MAX)
{
x_up = cx;
x_low = cx;
y_left = DBL_MAX;
y_right = DBL_MAX;
}
else
{
x_up = (voronoj->maxy - intercept) / slope;
x_low = (voronoj->miny - intercept) / slope;
y_left = (slope * voronoj->minx) + intercept;
y_right = (slope * voronoj->maxx) + intercept;
}
if (x_up >= voronoj->minx && x_up <= voronoj->maxx)
{
if (pre_x1 == DBL_MAX && pre_y1 == DBL_MAX)
{
pre_x1 = x_up;
pre_y1 = voronoj->maxy;
}
else if (pre_x2 == DBL_MAX && pre_y2 == DBL_MAX)
{
pre_x2 = x_up;
pre_y2 = voronoj->maxy;
}
}
if (x_low >= voronoj->minx && x_low <= voronoj->maxx)
{
if (pre_x1 == DBL_MAX && pre_y1 == DBL_MAX)
{
pre_x1 = x_low;
pre_y1 = voronoj->miny;
}
else if (pre_x2 == DBL_MAX && pre_y2 == DBL_MAX)
{
pre_x2 = x_low;
pre_y2 = voronoj->miny;
}
}
if (y_left >= voronoj->miny && y_left <= voronoj->maxy)
{
if (pre_x1 == DBL_MAX && pre_y1 == DBL_MAX)
{
pre_x1 = voronoj->minx;
pre_y1 = y_left;
}
else if (pre_x2 == DBL_MAX && pre_y2 == DBL_MAX)
{
pre_x2 = voronoj->minx;
pre_y2 = y_left;
}
}
if (y_right >= voronoj->miny && y_right <= voronoj->maxy)
{
if (pre_x1 == DBL_MAX && pre_y1 == DBL_MAX)
{
pre_x1 = voronoj->maxx;
pre_y1 = y_right;
}
else if (pre_x2 == DBL_MAX && pre_y2 == DBL_MAX)
{
pre_x2 = voronoj->maxx;
pre_y2 = y_right;
}
}
if (direct)
{
d1 = voronoj_test_point (p_cache, cx, cy, pre_x1, pre_y1, mx, my);
d2 = voronoj_test_point (p_cache, cx, cy, pre_x2, pre_y2, mx, my);
if (d1 < d2)
{
*x = pre_x1;
*y = pre_y1;
}
else
{
*x = pre_x2;
*y = pre_y2;
}
}
else
{
d1 = voronoj_test_point (p_cache, cx, cy, pre_x1, pre_y1, mx, my);
d2 = voronoj_test_point (p_cache, cx, cy, pre_x2, pre_y2, mx, my);
if (d1 > d2)
{
*x = pre_x1;
*y = pre_y1;
}
else
{
*x = pre_x2;
*y = pre_y2;
}
}
}
SPATIALITE_PRIVATE void *
voronoj_build (int count, void *p_first, double extra_frame_size)
{
return voronoj_build_r (NULL, count, p_first, extra_frame_size);
}
SPATIALITE_PRIVATE void *
voronoj_build_r (const void *p_cache, int count, void *p_first,
double extra_frame_size)
{
gaiaPolygonPtr first = (gaiaPolygonPtr) p_first;
struct voronoj_aux *voronoj = NULL;
struct voronoj_triangle *triangle;
struct voronoj_triangle *tri2;
gaiaPolygonPtr pg;
gaiaRingPtr rng;
int ind = 0;
int i2;
int direct;
double x;
double y;
double z;
double m;
double xba;
double yba;
double xca;
double yca;
double bl;
double cl;
double d;
double mx;
double my;
double slope;
double intercept = 0.0;
double minx = DBL_MAX;
double miny = DBL_MAX;
double maxx = DBL_MIN;
double maxy = DBL_MIN;
double ext_x;
double ext_y;
double delta;
double delta2;
voronoj = malloc (sizeof (struct voronoj_aux));
voronoj->count = count;
voronoj->first_up = NULL;
voronoj->last_up = NULL;
voronoj->first_low = NULL;
voronoj->last_low = NULL;
voronoj->first_left = NULL;
voronoj->last_left = NULL;
voronoj->first_right = NULL;
voronoj->last_right = NULL;
voronoj->array = malloc (sizeof (struct voronoj_triangle) * count);
pg = first;
while (pg)
{
rng = pg->Exterior;
triangle = voronoj->array + ind;
if (pg->DimensionModel == GAIA_XY_Z)
{
gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
triangle->x1 = x;
triangle->y1 = y;
gaiaGetPointXYZ (rng->Coords, 1, &x, &y, &z);
triangle->x2 = x;
triangle->y2 = y;
gaiaGetPointXYZ (rng->Coords, 2, &x, &y, &z);
triangle->x3 = x;
triangle->y3 = y;
}
else if (pg->DimensionModel == GAIA_XY_M)
{
gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
triangle->x1 = x;
triangle->y1 = y;
gaiaGetPointXYM (rng->Coords, 1, &x, &y, &m);
triangle->x2 = x;
triangle->y2 = y;
gaiaGetPointXYM (rng->Coords, 2, &x, &y, &m);
triangle->x3 = x;
triangle->y3 = y;
}
else if (pg->DimensionModel == GAIA_XY_Z_M)
{
gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
triangle->x1 = x;
triangle->y1 = y;
gaiaGetPointXYZM (rng->Coords, 1, &x, &y, &z, &m);
triangle->x2 = x;
triangle->y2 = y;
gaiaGetPointXYZM (rng->Coords, 2, &x, &y, &z, &m);
triangle->x3 = x;
triangle->y3 = y;
}
else
{
gaiaGetPoint (rng->Coords, 0, &x, &y);
triangle->x1 = x;
triangle->y1 = y;
gaiaGetPoint (rng->Coords, 1, &x, &y);
triangle->x2 = x;
triangle->y2 = y;
gaiaGetPoint (rng->Coords, 2, &x, &y);
triangle->x3 = x;
triangle->y3 = y;
}
xba = triangle->x2 - triangle->x1;
yba = triangle->y2 - triangle->y1;
xca = triangle->x3 - triangle->x1;
yca = triangle->y3 - triangle->y1;
bl = xba * xba + yba * yba;
cl = xca * xca + yca * yca;
d = 0.5 / (xba * yca - yba * xca);
triangle->cx = triangle->x1 + ((yca * bl - yba * cl) * d);
triangle->cy = triangle->y1 + ((xba * cl - xca * bl) * d);
voronoj_minmax (triangle->x1, triangle->y1, &minx, &miny, &maxx,
&maxy);
voronoj_minmax (triangle->x2, triangle->y2, &minx, &miny, &maxx,
&maxy);
voronoj_minmax (triangle->x3, triangle->y3, &minx, &miny, &maxx,
&maxy);
voronoj_minmax (triangle->cx, triangle->cy, &minx, &miny, &maxx,
&maxy);
triangle->tri_1_2 = NULL;
triangle->tri_2_3 = NULL;
triangle->tri_3_1 = NULL;
triangle->trace_1_2 = 0;
triangle->trace_2_3 = 0;
triangle->trace_3_1 = 0;
ind++;
pg = pg->Next;
}
if (extra_frame_size < 0.0)
extra_frame_size = 5.0;
ext_x = maxx - minx;
ext_y = maxy - miny;
delta = (ext_x * extra_frame_size) / 100.0;
delta2 = (ext_y * extra_frame_size) / 100.0;
if (delta2 > delta)
delta = delta2;
voronoj->minx = minx - delta;
voronoj->miny = miny - delta;
voronoj->maxx = maxx + delta;
voronoj->maxy = maxy + delta;
for (ind = 0; ind < voronoj->count; ind++)
{
triangle = voronoj->array + ind;
for (i2 = ind + 1; i2 < voronoj->count; i2++)
{
tri2 = voronoj->array + i2;
if (triangle->tri_1_2 == NULL && tri2->tri_1_2 == NULL)
{
if (voronoj_same_edge
(triangle->x1, triangle->y1, triangle->x2,
triangle->y2, tri2->x1, tri2->y1, tri2->x2,
tri2->y2))
{
triangle->tri_1_2 = tri2;
triangle->trace_1_2 = 1;
tri2->tri_1_2 = triangle;
}
}
if (triangle->tri_1_2 == NULL && tri2->tri_2_3 == NULL)
{
if (voronoj_same_edge
(triangle->x1, triangle->y1, triangle->x2,
triangle->y2, tri2->x2, tri2->y2, tri2->x3,
tri2->y3))
{
triangle->tri_1_2 = tri2;
triangle->trace_1_2 = 1;
tri2->tri_2_3 = triangle;
}
}
if (triangle->tri_1_2 == NULL && tri2->tri_3_1 == NULL)
{
if (voronoj_same_edge
(triangle->x1, triangle->y1, triangle->x2,
triangle->y2, tri2->x3, tri2->y3, tri2->x1,
tri2->y1))
{
triangle->tri_1_2 = tri2;
triangle->trace_1_2 = 1;
tri2->tri_3_1 = triangle;
}
}
if (triangle->tri_2_3 == NULL && tri2->tri_1_2 == NULL)
{
if (voronoj_same_edge
(triangle->x2, triangle->y2, triangle->x3,
triangle->y3, tri2->x1, tri2->y1, tri2->x2,
tri2->y2))
{
triangle->tri_2_3 = tri2;
triangle->trace_2_3 = 1;
tri2->tri_1_2 = triangle;
}
}
if (triangle->tri_2_3 == NULL && tri2->tri_2_3 == NULL)
{
if (voronoj_same_edge
(triangle->x2, triangle->y2, triangle->x3,
triangle->y3, tri2->x2, tri2->y2, tri2->x3,
tri2->y3))
{
triangle->tri_2_3 = tri2;
triangle->trace_2_3 = 1;
tri2->tri_2_3 = triangle;
}
}
if (triangle->tri_2_3 == NULL && tri2->tri_3_1 == NULL)
{
if (voronoj_same_edge
(triangle->x2, triangle->y2, triangle->x3,
triangle->y3, tri2->x3, tri2->y3, tri2->x1,
tri2->y1))
{
triangle->tri_2_3 = tri2;
triangle->trace_2_3 = 1;
tri2->tri_3_1 = triangle;
}
}
if (triangle->tri_3_1 == NULL && tri2->tri_1_2 == NULL)
{
if (voronoj_same_edge
(triangle->x3, triangle->y3, triangle->x1,
triangle->y1, tri2->x1, tri2->y1, tri2->x2,
tri2->y2))
{
triangle->tri_3_1 = tri2;
triangle->trace_3_1 = 1;
tri2->tri_1_2 = triangle;
}
}
if (triangle->tri_3_1 == NULL && tri2->tri_2_3 == NULL)
{
if (voronoj_same_edge
(triangle->x3, triangle->y3, triangle->x1,
triangle->y1, tri2->x2, tri2->y2, tri2->x3,
tri2->y3))
{
triangle->tri_3_1 = tri2;
triangle->trace_3_1 = 1;
tri2->tri_2_3 = triangle;
}
}
if (triangle->tri_3_1 == NULL && tri2->tri_3_1 == NULL)
{
if (voronoj_same_edge
(triangle->x3, triangle->y3, triangle->x1,
triangle->y1, tri2->x3, tri2->y3, tri2->x1,
tri2->y1))
{
triangle->tri_3_1 = tri2;
triangle->trace_3_1 = 1;
tri2->tri_3_1 = triangle;
}
}
}
if (triangle->tri_1_2 == NULL)
{
mx = (triangle->x1 + triangle->x2) / 2.0;
my = (triangle->y1 + triangle->y2) / 2.0;
if (mx == triangle->cx)
slope = DBL_MAX;
else
{
slope = (my - triangle->cy) / (mx - triangle->cx);
intercept = my - (slope * mx);
}
direct = 1;
if (!voronoj_internal (p_cache, triangle))
direct = voronoj_check_nearest_edge (p_cache, triangle, 12);
voronoj_frame_point (p_cache, intercept, slope, voronoj,
triangle->cx, triangle->cy, mx, my, direct,
&x, &y);
triangle->x_1_2 = x;
triangle->y_1_2 = y;
}
if (triangle->tri_2_3 == NULL)
{
mx = (triangle->x2 + triangle->x3) / 2.0;
my = (triangle->y2 + triangle->y3) / 2.0;
if (mx == triangle->cx)
slope = DBL_MAX;
else
{
slope = (my - triangle->cy) / (mx - triangle->cx);
intercept = my - (slope * mx);
}
direct = 1;
if (!voronoj_internal (p_cache, triangle))
direct = voronoj_check_nearest_edge (p_cache, triangle, 23);
voronoj_frame_point (p_cache, intercept, slope, voronoj,
triangle->cx, triangle->cy, mx, my, direct,
&x, &y);
triangle->x_2_3 = x;
triangle->y_2_3 = y;
}
if (triangle->tri_3_1 == NULL)
{
mx = (triangle->x3 + triangle->x1) / 2.0;
my = (triangle->y3 + triangle->y1) / 2.0;
if (mx == triangle->cx)
slope = DBL_MAX;
else
{
slope = (my - triangle->cy) / (mx - triangle->cx);
intercept = my - (slope * mx);
}
direct = 1;
if (!voronoj_internal (p_cache, triangle))
direct = voronoj_check_nearest_edge (p_cache, triangle, 31);
voronoj_frame_point (p_cache, intercept, slope, voronoj,
triangle->cx, triangle->cy, mx, my, direct,
&x, &y);
triangle->x_3_1 = x;
triangle->y_3_1 = y;
}
}
return voronoj;
}
static void *
voronoj_export_common (const void *p_cache, void *p_voronoj, void *p_result,
int only_edges)
{
gaiaGeomCollPtr result = (gaiaGeomCollPtr) p_result;
gaiaGeomCollPtr lines;
struct voronoj_aux *voronoj = (struct voronoj_aux *) p_voronoj;
int ind;
gaiaLinestringPtr ln;
struct voronoj_triangle *triangle;
struct voronoj_triangle *tri2;
int i;
int count;
double last;
double *array;
for (ind = 0; ind < voronoj->count; ind++)
{
triangle = voronoj->array + ind;
if (triangle->tri_1_2 && triangle->trace_1_2)
{
tri2 = triangle->tri_1_2;
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, tri2->cx, tri2->cy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, tri2->cx, tri2->cy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, tri2->cx, tri2->cy, 0.0,
0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, triangle->cx, triangle->cy);
gaiaSetPoint (ln->Coords, 1, tri2->cx, tri2->cy);
}
}
if (triangle->tri_2_3 && triangle->trace_2_3)
{
tri2 = triangle->tri_2_3;
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, tri2->cx, tri2->cy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, tri2->cx, tri2->cy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, tri2->cx, tri2->cy, 0.0,
0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, triangle->cx, triangle->cy);
gaiaSetPoint (ln->Coords, 1, tri2->cx, tri2->cy);
}
}
if (triangle->tri_3_1 && triangle->trace_3_1)
{
tri2 = triangle->tri_3_1;
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, tri2->cx, tri2->cy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, tri2->cx, tri2->cy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, tri2->cx, tri2->cy, 0.0,
0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, triangle->cx, triangle->cy);
gaiaSetPoint (ln->Coords, 1, tri2->cx, tri2->cy);
}
}
if (triangle->tri_1_2 == NULL)
{
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, triangle->x_1_2,
triangle->y_1_2, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, triangle->x_1_2,
triangle->y_1_2, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, triangle->x_1_2,
triangle->y_1_2, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, triangle->cx, triangle->cy);
gaiaSetPoint (ln->Coords, 1, triangle->x_1_2,
triangle->y_1_2);
}
if (!only_edges)
voronoj_add_frame_point (voronoj, triangle->x_1_2,
triangle->y_1_2);
}
if (triangle->tri_2_3 == NULL)
{
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, triangle->x_2_3,
triangle->y_2_3, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, triangle->x_2_3,
triangle->y_2_3, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, triangle->x_2_3,
triangle->y_2_3, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, triangle->cx, triangle->cy);
gaiaSetPoint (ln->Coords, 1, triangle->x_2_3,
triangle->y_2_3);
}
if (!only_edges)
voronoj_add_frame_point (voronoj, triangle->x_2_3,
triangle->y_2_3);
}
if (triangle->tri_3_1 == NULL)
{
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, triangle->x_3_1,
triangle->y_3_1, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, triangle->x_3_1,
triangle->y_3_1, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, triangle->cx,
triangle->cy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, triangle->x_3_1,
triangle->y_3_1, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, triangle->cx, triangle->cy);
gaiaSetPoint (ln->Coords, 1, triangle->x_3_1,
triangle->y_3_1);
}
if (!only_edges)
voronoj_add_frame_point (voronoj, triangle->x_3_1,
triangle->y_3_1);
}
}
if (only_edges)
return result;
last = voronoj->minx;
array = voronoj_sorted_up (voronoj, &count);
if (array)
{
for (i = 0; i < count; i++)
{
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, last, voronoj->maxy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, *(array + i),
voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, last, voronoj->maxy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, *(array + i),
voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, last,
voronoj->maxy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, *(array + i),
voronoj->maxy, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, last, voronoj->maxy);
gaiaSetPoint (ln->Coords, 1, *(array + i), voronoj->maxy);
}
last = *(array + i);
}
free (array);
}
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, last, voronoj->maxy, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, voronoj->maxx, voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, last, voronoj->maxy, 0.0);
gaiaSetPointXYM (ln->Coords, 1, voronoj->maxx, voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, last, voronoj->maxy, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, voronoj->maxx,
voronoj->maxy, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, last, voronoj->maxy);
gaiaSetPoint (ln->Coords, 1, voronoj->maxx, voronoj->maxy);
}
last = voronoj->minx;
array = voronoj_sorted_low (voronoj, &count);
if (array)
{
for (i = 0; i < count; i++)
{
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, last, voronoj->miny, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, *(array + i),
voronoj->miny, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, last, voronoj->miny, 0.0);
gaiaSetPointXYM (ln->Coords, 1, *(array + i),
voronoj->miny, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, last,
voronoj->miny, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, *(array + i),
voronoj->miny, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, last, voronoj->miny);
gaiaSetPoint (ln->Coords, 1, *(array + i), voronoj->miny);
}
last = *(array + i);
}
free (array);
}
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, last, voronoj->miny, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, voronoj->maxx, voronoj->miny, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, last, voronoj->miny, 0.0);
gaiaSetPointXYM (ln->Coords, 1, voronoj->maxx, voronoj->miny, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, last, voronoj->miny, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, voronoj->maxx,
voronoj->miny, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, last, voronoj->miny);
gaiaSetPoint (ln->Coords, 1, voronoj->maxx, voronoj->miny);
}
last = voronoj->miny;
array = voronoj_sorted_left (voronoj, &count);
if (array)
{
for (i = 0; i < count; i++)
{
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, voronoj->minx, last, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, voronoj->minx,
*(array + i), 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, voronoj->minx, last, 0.0);
gaiaSetPointXYM (ln->Coords, 1, voronoj->minx,
*(array + i), 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, voronoj->minx,
last, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, voronoj->minx,
*(array + i), 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, voronoj->minx, last);
gaiaSetPoint (ln->Coords, 1, voronoj->minx, *(array + i));
}
last = *(array + i);
}
free (array);
}
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, voronoj->minx, last, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, voronoj->minx, voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, voronoj->minx, last, 0.0);
gaiaSetPointXYM (ln->Coords, 1, voronoj->minx, voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, voronoj->minx, last, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, voronoj->minx,
voronoj->maxy, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, voronoj->minx, last);
gaiaSetPoint (ln->Coords, 1, voronoj->minx, voronoj->maxy);
}
last = voronoj->miny;
array = voronoj_sorted_right (voronoj, &count);
if (array)
{
for (i = 0; i < count; i++)
{
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, voronoj->maxx, last, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, voronoj->maxx,
*(array + i), 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, voronoj->maxx, last, 0.0);
gaiaSetPointXYM (ln->Coords, 1, voronoj->maxx,
*(array + i), 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, voronoj->maxx,
last, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, voronoj->maxx,
*(array + i), 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, voronoj->maxx, last);
gaiaSetPoint (ln->Coords, 1, voronoj->maxx, *(array + i));
}
last = *(array + i);
}
free (array);
}
ln = gaiaAddLinestringToGeomColl (result, 2);
if (result->DimensionModel == GAIA_XY_Z)
{
gaiaSetPointXYZ (ln->Coords, 0, voronoj->maxx, last, 0.0);
gaiaSetPointXYZ (ln->Coords, 1, voronoj->maxx, voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_M)
{
gaiaSetPointXYM (ln->Coords, 0, voronoj->maxx, last, 0.0);
gaiaSetPointXYM (ln->Coords, 1, voronoj->maxx, voronoj->maxy, 0.0);
}
else if (result->DimensionModel == GAIA_XY_Z_M)
{
gaiaSetPointXYZM (ln->Coords, 0, voronoj->maxx, last, 0.0, 0.0);
gaiaSetPointXYZM (ln->Coords, 1, voronoj->maxx,
voronoj->maxy, 0.0, 0.0);
}
else
{
gaiaSetPoint (ln->Coords, 0, voronoj->maxx, last);
gaiaSetPoint (ln->Coords, 1, voronoj->maxx, voronoj->maxy);
}
lines = result;
if (p_cache != NULL)
result = gaiaPolygonize_r (p_cache, lines, 1);
else
result = gaiaPolygonize (lines, 1);
gaiaFreeGeomColl (lines);
return result;
}
SPATIALITE_PRIVATE void *
voronoj_export (void *p_voronoj, void *p_result, int only_edges)
{
return voronoj_export_common (NULL, p_voronoj, p_result, only_edges);
}
SPATIALITE_PRIVATE void *
voronoj_export_r (const void *p_cache, void *p_voronoj, void *p_result,
int only_edges)
{
return voronoj_export_common (p_cache, p_voronoj, p_result, only_edges);
}
SPATIALITE_PRIVATE void
voronoj_free (void *p_voronoj)
{
struct voronoj_aux *voronoj = (struct voronoj_aux *) p_voronoj;
struct voronoj_point *pt;
struct voronoj_point *ptn;
free (voronoj->array);
pt = voronoj->first_up;
while (pt)
{
ptn = pt->next;
free (pt);
pt = ptn;
}
pt = voronoj->first_low;
while (pt)
{
ptn = pt->next;
free (pt);
pt = ptn;
}
pt = voronoj->first_left;
while (pt)
{
ptn = pt->next;
free (pt);
pt = ptn;
}
pt = voronoj->first_right;
while (pt)
{
ptn = pt->next;
free (pt);
pt = ptn;
}
free (voronoj);
}
SPATIALITE_PRIVATE int
delaunay_triangle_check (void *ppg)
{
gaiaPolygonPtr pg = (gaiaPolygonPtr) ppg;
gaiaRingPtr rng = pg->Exterior;
if (rng->Points == 4 && pg->NumInteriors == 0)
return 1;
return 0;
}
static void
concave_hull_stats (struct concave_hull_str *concave, double length)
{
if (concave->count == 0)
{
concave->count = 1.0;
concave->mean = length;
return;
}
concave->count += 1.0;
concave->quot = concave->quot + (((concave->count - 1.0) *
((length - concave->mean) *
(length - concave->mean))) /
concave->count);
concave->mean = concave->mean + ((length - concave->mean) / concave->count);
}
static int
concave_hull_filter (const void *p_cache, double x1, double y1,
double x2, double y2, double x3, double y3, double limit)
{
gaiaGeomCollPtr segm;
gaiaLinestringPtr ln;
double length;
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, x1, y1);
gaiaSetPoint (ln->Coords, 1, x2, y2);
if (p_cache != NULL)
gaiaGeomCollLength_r (p_cache, segm, &length);
else
gaiaGeomCollLength (segm, &length);
gaiaFreeGeomColl (segm);
if (length >= limit)
return 0;
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, x2, y2);
gaiaSetPoint (ln->Coords, 1, x3, y3);
if (p_cache != NULL)
gaiaGeomCollLength_r (p_cache, segm, &length);
else
gaiaGeomCollLength (segm, &length);
gaiaFreeGeomColl (segm);
if (length >= limit)
return 0;
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, x3, y3);
gaiaSetPoint (ln->Coords, 1, x1, y1);
if (p_cache != NULL)
gaiaGeomCollLength_r (p_cache, segm, &length);
else
gaiaGeomCollLength (segm, &length);
gaiaFreeGeomColl (segm);
if (length >= limit)
return 0;
return 1;
}
static gaiaGeomCollPtr
concave_hull_no_holes (gaiaGeomCollPtr in)
{
gaiaGeomCollPtr out = NULL;
gaiaPolygonPtr pg_in;
gaiaPolygonPtr pg_out;
gaiaRingPtr rng_in;
gaiaRingPtr rng_out;
int iv;
double x;
double y;
double z;
double m;
if (in->DimensionModel == GAIA_XY_Z)
out = gaiaAllocGeomCollXYZ ();
else if (in->DimensionModel == GAIA_XY_M)
out = gaiaAllocGeomCollXYM ();
else if (in->DimensionModel == GAIA_XY_Z_M)
out = gaiaAllocGeomCollXYZM ();
else
out = gaiaAllocGeomColl ();
out->Srid = in->Srid;
pg_in = in->FirstPolygon;
while (pg_in)
{
rng_in = pg_in->Exterior;
pg_out = gaiaAddPolygonToGeomColl (out, rng_in->Points, 0);
rng_out = pg_out->Exterior;
for (iv = 0; iv < rng_in->Points; iv++)
{
if (in->DimensionModel == GAIA_XY_Z)
{
gaiaGetPointXYZ (rng_in->Coords, iv, &x, &y, &z);
gaiaSetPointXYZ (rng_out->Coords, iv, x, y, z);
}
else if (in->DimensionModel == GAIA_XY_M)
{
gaiaGetPointXYM (rng_in->Coords, iv, &x, &y, &m);
gaiaSetPointXYM (rng_out->Coords, iv, x, y, m);
}
else if (in->DimensionModel == GAIA_XY_Z_M)
{
gaiaGetPointXYZM (rng_in->Coords, iv, &x, &y, &z, &m);
gaiaSetPointXYZM (rng_out->Coords, iv, x, y, z, m);
}
else
{
gaiaGetPoint (rng_in->Coords, iv, &x, &y);
gaiaSetPoint (rng_out->Coords, iv, x, y);
}
}
pg_in = pg_in->Next;
}
return out;
}
static void *
concave_hull_build_common (const void *p_cache, void *p_first,
int dimension_model, double factor, int allow_holes)
{
struct concave_hull_str concave;
gaiaPolygonPtr first = (gaiaPolygonPtr) p_first;
gaiaPolygonPtr pg;
gaiaRingPtr rng;
gaiaPolygonPtr pg_out;
gaiaRingPtr rng_out;
gaiaGeomCollPtr segm;
gaiaGeomCollPtr result;
gaiaLinestringPtr ln;
double x;
double y;
double z;
double m;
double x1;
double y1;
double x2;
double y2;
double x3;
double y3;
double length;
double std_dev;
int count;
concave.mean = 0.0;
concave.quot = 0.0;
concave.count = 0.0;
pg = first;
while (pg)
{
rng = pg->Exterior;
if (pg->DimensionModel == GAIA_XY_Z)
{
gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
x1 = x;
y1 = y;
gaiaGetPointXYZ (rng->Coords, 1, &x, &y, &z);
x2 = x;
y2 = y;
gaiaGetPointXYZ (rng->Coords, 2, &x, &y, &z);
x3 = x;
y3 = y;
}
else if (pg->DimensionModel == GAIA_XY_M)
{
gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
x1 = x;
y1 = y;
gaiaGetPointXYM (rng->Coords, 1, &x, &y, &m);
x2 = x;
y2 = y;
gaiaGetPointXYM (rng->Coords, 2, &x, &y, &m);
x3 = x;
y3 = y;
}
else if (pg->DimensionModel == GAIA_XY_Z_M)
{
gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
x1 = x;
y1 = y;
gaiaGetPointXYZM (rng->Coords, 1, &x, &y, &z, &m);
x2 = x;
y2 = y;
gaiaGetPointXYZM (rng->Coords, 2, &x, &y, &z, &m);
x3 = x;
y3 = y;
}
else
{
gaiaGetPoint (rng->Coords, 0, &x, &y);
x1 = x;
y1 = y;
gaiaGetPoint (rng->Coords, 1, &x, &y);
x2 = x;
y2 = y;
gaiaGetPoint (rng->Coords, 2, &x, &y);
x3 = x;
y3 = y;
}
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, x1, y1);
gaiaSetPoint (ln->Coords, 1, x2, y2);
if (p_cache != NULL)
gaiaGeomCollLength_r (p_cache, segm, &length);
else
gaiaGeomCollLength (segm, &length);
gaiaFreeGeomColl (segm);
concave_hull_stats (&concave, length);
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, x2, y2);
gaiaSetPoint (ln->Coords, 1, x3, y3);
if (p_cache != NULL)
gaiaGeomCollLength_r (p_cache, segm, &length);
else
gaiaGeomCollLength (segm, &length);
gaiaFreeGeomColl (segm);
concave_hull_stats (&concave, length);
segm = gaiaAllocGeomColl ();
ln = gaiaAddLinestringToGeomColl (segm, 2);
gaiaSetPoint (ln->Coords, 0, x3, y3);
gaiaSetPoint (ln->Coords, 1, x1, y1);
if (p_cache != NULL)
gaiaGeomCollLength_r (p_cache, segm, &length);
else
gaiaGeomCollLength (segm, &length);
gaiaFreeGeomColl (segm);
concave_hull_stats (&concave, length);
pg = pg->Next;
}
std_dev = sqrt (concave.quot / concave.count);
if (dimension_model == GAIA_XY_Z)
result = gaiaAllocGeomCollXYZ ();
else if (dimension_model == GAIA_XY_M)
result = gaiaAllocGeomCollXYM ();
else if (dimension_model == GAIA_XY_Z_M)
result = gaiaAllocGeomCollXYZM ();
else
result = gaiaAllocGeomColl ();
count = 0;
pg = first;
while (pg)
{
rng = pg->Exterior;
if (pg->DimensionModel == GAIA_XY_Z)
{
gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
x1 = x;
y1 = y;
gaiaGetPointXYZ (rng->Coords, 1, &x, &y, &z);
x2 = x;
y2 = y;
gaiaGetPointXYZ (rng->Coords, 2, &x, &y, &z);
x3 = x;
y3 = y;
}
else if (pg->DimensionModel == GAIA_XY_M)
{
gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
x1 = x;
y1 = y;
gaiaGetPointXYM (rng->Coords, 1, &x, &y, &m);
x2 = x;
y2 = y;
gaiaGetPointXYM (rng->Coords, 2, &x, &y, &m);
x3 = x;
y3 = y;
}
else if (pg->DimensionModel == GAIA_XY_Z_M)
{
gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
x1 = x;
y1 = y;
gaiaGetPointXYZM (rng->Coords, 1, &x, &y, &z, &m);
x2 = x;
y2 = y;
gaiaGetPointXYZM (rng->Coords, 2, &x, &y, &z, &m);
x3 = x;
y3 = y;
}
else
{
gaiaGetPoint (rng->Coords, 0, &x, &y);
x1 = x;
y1 = y;
gaiaGetPoint (rng->Coords, 1, &x, &y);
x2 = x;
y2 = y;
gaiaGetPoint (rng->Coords, 2, &x, &y);
x3 = x;
y3 = y;
}
if (concave_hull_filter
(p_cache, x1, y1, x2, y2, x3, y3, std_dev * factor))
{
pg_out = gaiaAddPolygonToGeomColl (result, 4, 0);
rng_out = pg_out->Exterior;
if (pg->DimensionModel == GAIA_XY_Z)
{
gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
gaiaSetPointXYZ (rng_out->Coords, 0, x, y, z);
gaiaGetPointXYZ (rng->Coords, 1, &x, &y, &z);
gaiaSetPointXYZ (rng_out->Coords, 1, x, y, z);
gaiaGetPointXYZ (rng->Coords, 2, &x, &y, &z);
gaiaSetPointXYZ (rng_out->Coords, 2, x, y, z);
gaiaGetPointXYZ (rng->Coords, 3, &x, &y, &z);
gaiaSetPointXYZ (rng_out->Coords, 3, x, y, z);
}
else if (pg->DimensionModel == GAIA_XY_M)
{
gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
gaiaSetPointXYM (rng_out->Coords, 0, x, y, m);
gaiaGetPointXYM (rng->Coords, 1, &x, &y, &m);
gaiaSetPointXYM (rng_out->Coords, 1, x, y, m);
gaiaGetPointXYM (rng->Coords, 2, &x, &y, &m);
gaiaSetPointXYM (rng_out->Coords, 2, x, y, m);
gaiaGetPointXYM (rng->Coords, 3, &x, &y, &m);
gaiaSetPointXYM (rng_out->Coords, 3, x, y, m);
}
else if (pg->DimensionModel == GAIA_XY_Z_M)
{
gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
gaiaSetPointXYZM (rng_out->Coords, 0, x, y, z, m);
gaiaGetPointXYZM (rng->Coords, 1, &x, &y, &z, &m);
gaiaSetPointXYZM (rng_out->Coords, 1, x, y, z, m);
gaiaGetPointXYZM (rng->Coords, 2, &x, &y, &z, &m);
gaiaSetPointXYZM (rng_out->Coords, 2, x, y, z, m);
gaiaGetPointXYZM (rng->Coords, 3, &x, &y, &z, &m);
gaiaSetPointXYZM (rng_out->Coords, 3, x, y, z, m);
}
else
{
gaiaGetPoint (rng->Coords, 0, &x, &y);
gaiaSetPoint (rng_out->Coords, 0, x, y);
gaiaGetPoint (rng->Coords, 1, &x, &y);
gaiaSetPoint (rng_out->Coords, 1, x, y);
gaiaGetPoint (rng->Coords, 2, &x, &y);
gaiaSetPoint (rng_out->Coords, 2, x, y);
gaiaGetPoint (rng->Coords, 3, &x, &y);
gaiaSetPoint (rng_out->Coords, 3, x, y);
}
count++;
}
pg = pg->Next;
}
if (count == 0)
{
gaiaFreeGeomColl (result);
return NULL;
}
segm = result;
if (p_cache != NULL)
result = gaiaUnaryUnion_r (p_cache, segm);
else
result = gaiaUnaryUnion (segm);
gaiaFreeGeomColl (segm);
if (!result)
return NULL;
if (result->FirstPolygon == NULL)
{
gaiaFreeGeomColl (result);
return NULL;
}
if (allow_holes)
return result;
segm = result;
result = concave_hull_no_holes (segm);
gaiaFreeGeomColl (segm);
if (!result)
return NULL;
if (result->FirstPolygon == NULL)
{
gaiaFreeGeomColl (result);
return NULL;
}
return result;
}
SPATIALITE_PRIVATE void *
concave_hull_build (void *p_first, int dimension_model, double factor,
int allow_holes)
{
return concave_hull_build_common (NULL, p_first, dimension_model, factor,
allow_holes);
}
SPATIALITE_PRIVATE void *
concave_hull_build_r (const void *p_cache, void *p_first, int dimension_model,
double factor, int allow_holes)
{
return concave_hull_build_common (p_cache, p_first, dimension_model, factor,
allow_holes);
}
#endif