857 lines
24 KiB
C
857 lines
24 KiB
C
/**********************************************************************
|
|
*
|
|
* PostGIS - Spatial Types for PostgreSQL
|
|
* http://postgis.net
|
|
*
|
|
* Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
|
|
* Copyright (C) 2008 Paul Ramsey
|
|
*
|
|
* This is free software; you can redistribute and/or modify it under
|
|
* the terms of the GNU General Public Licence. See the COPYING file.
|
|
*
|
|
**********************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "CUnit/Basic.h"
|
|
#include "CUnit/CUnit.h"
|
|
|
|
#include "liblwgeom_internal.h"
|
|
#include "cu_tester.h"
|
|
|
|
|
|
static LWGEOM* lwgeom_from_text(const char *str)
|
|
{
|
|
LWGEOM_PARSER_RESULT r;
|
|
if( LW_FAILURE == lwgeom_parse_wkt(&r, (char*)str, LW_PARSER_CHECK_NONE) )
|
|
return NULL;
|
|
return r.geom;
|
|
}
|
|
|
|
static char* lwgeom_to_text(const LWGEOM *geom)
|
|
{
|
|
return lwgeom_to_wkt(geom, WKT_ISO, 8, NULL);
|
|
}
|
|
|
|
static void test_ptarray_append_point(void)
|
|
{
|
|
LWLINE *line;
|
|
char *wkt;
|
|
POINT4D p;
|
|
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,1 1)"));
|
|
p.x = 1;
|
|
p.y = 1;
|
|
ptarray_append_point(line->points, &p, LW_TRUE);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)");
|
|
lwfree(wkt);
|
|
|
|
ptarray_append_point(line->points, &p, LW_FALSE);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)");
|
|
lwfree(wkt);
|
|
|
|
lwline_free(line);
|
|
}
|
|
|
|
static void test_ptarray_insert_point(void)
|
|
{
|
|
LWLINE *line;
|
|
char *wkt;
|
|
POINT4D p;
|
|
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
|
|
p.x = 1;
|
|
p.y = 1;
|
|
ptarray_insert_point(line->points, &p, 0);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wkt,"LINESTRING(1 1)");
|
|
lwfree(wkt);
|
|
|
|
p.x = 2;
|
|
p.y = 20;
|
|
ptarray_insert_point(line->points, &p, 0);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wkt,"LINESTRING(2 20,1 1)");
|
|
lwfree(wkt);
|
|
|
|
p.x = 3;
|
|
p.y = 30;
|
|
ptarray_insert_point(line->points, &p, 1);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wkt,"LINESTRING(2 20,3 30,1 1)");
|
|
lwfree(wkt);
|
|
|
|
p.x = 4;
|
|
p.y = 40;
|
|
ptarray_insert_point(line->points, &p, 0);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wkt,"LINESTRING(4 40,2 20,3 30,1 1)");
|
|
lwfree(wkt);
|
|
|
|
p.x = 5;
|
|
p.y = 50;
|
|
ptarray_insert_point(line->points, &p, 4);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wkt,"LINESTRING(4 40,2 20,3 30,1 1,5 50)");
|
|
lwfree(wkt);
|
|
|
|
lwline_free(line);
|
|
}
|
|
|
|
static void test_ptarray_append_ptarray(void)
|
|
{
|
|
LWLINE *line1, *line2;
|
|
int ret;
|
|
char *wkt;
|
|
|
|
/* Empty first line */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,5 5)"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, -1);
|
|
CU_ASSERT(ret == LW_SUCCESS);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
|
|
ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,5 5)");
|
|
lwfree(wkt);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Empty second line */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 5 5, 6 3)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, -1);
|
|
CU_ASSERT(ret == LW_SUCCESS);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
|
|
ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,5 5,6 3)");
|
|
lwfree(wkt);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Both lines empty */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, -1);
|
|
CU_ASSERT(ret == LW_SUCCESS);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
|
|
ASSERT_STRING_EQUAL(wkt, "LINESTRING EMPTY");
|
|
lwfree(wkt);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Sane sewing */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5 7,12 43, 42 15)"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, 0);
|
|
CU_ASSERT(ret == LW_SUCCESS);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
|
|
ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,12 43,42 15)");
|
|
lwfree(wkt);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Untolerated sewing */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, 0);
|
|
CU_ASSERT(ret == LW_FAILURE);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Tolerated sewing */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, .7);
|
|
CU_ASSERT(ret == LW_SUCCESS);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
|
|
ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,5.5 7,12 43,42 15)");
|
|
lwfree(wkt);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Check user input trust (creates non-simple line */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, -1);
|
|
CU_ASSERT(ret == LW_SUCCESS);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
|
|
ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,0 0,0 10)");
|
|
lwfree(wkt);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Mixed dimensionality is not allowed */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10 0, 10 0 0)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)"));
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, -1);
|
|
CU_ASSERT(ret == LW_FAILURE);
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Appending a read-only pointarray is allowed */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10, 10 0)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)"));
|
|
FLAGS_SET_READONLY(line2->points->flags, 1);
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, -1);
|
|
CU_ASSERT(ret == LW_SUCCESS);
|
|
wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
|
|
ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 10,10 0,11 0)");
|
|
lwfree(wkt);
|
|
FLAGS_SET_READONLY(line2->points->flags, 0); /* for lwline_free */
|
|
lwline_free(line2);
|
|
lwline_free(line1);
|
|
|
|
/* Appending to a read-only pointarray is forbidden */
|
|
line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10, 10 0)"));
|
|
line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)"));
|
|
FLAGS_SET_READONLY(line1->points->flags, 1);
|
|
ret = ptarray_append_ptarray(line1->points, line2->points, -1);
|
|
CU_ASSERT(ret == LW_FAILURE);
|
|
lwline_free(line2);
|
|
FLAGS_SET_READONLY(line1->points->flags, 0); /* for lwline_free */
|
|
lwline_free(line1);
|
|
|
|
}
|
|
|
|
static void test_ptarray_locate_point(void)
|
|
{
|
|
LWLINE *line;
|
|
double loc, dist;
|
|
POINT4D p, l;
|
|
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4)"));
|
|
|
|
p = getPoint4d(line->points, 0);
|
|
loc = ptarray_locate_point(line->points, &p, &dist, &l);
|
|
CU_ASSERT_EQUAL(loc, 0);
|
|
CU_ASSERT_EQUAL(dist, 0.0);
|
|
|
|
p = getPoint4d(line->points, 1);
|
|
loc = ptarray_locate_point(line->points, &p, &dist, &l);
|
|
CU_ASSERT_EQUAL(loc, 1);
|
|
CU_ASSERT_EQUAL(dist, 0.0);
|
|
|
|
p.x = 21; p.y = 4;
|
|
loc = ptarray_locate_point(line->points, &p, &dist, NULL);
|
|
CU_ASSERT_EQUAL(loc, 1);
|
|
CU_ASSERT_EQUAL(dist, 1.0);
|
|
|
|
p.x = 0; p.y = 2;
|
|
loc = ptarray_locate_point(line->points, &p, &dist, &l);
|
|
CU_ASSERT_EQUAL(loc, 0);
|
|
CU_ASSERT_EQUAL(dist, 1.0);
|
|
|
|
lwline_free(line);
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,20 0,40 0)"));
|
|
|
|
p.x = 20; p.y = 0;
|
|
loc = ptarray_locate_point(line->points, &p, &dist, &l);
|
|
CU_ASSERT_EQUAL(loc, 0.5);
|
|
CU_ASSERT_EQUAL(dist, 0.0);
|
|
|
|
lwline_free(line);
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-40 0,0 0,20 0,40 0)"));
|
|
|
|
p.x = 20; p.y = 0;
|
|
loc = ptarray_locate_point(line->points, &p, &dist, &l);
|
|
CU_ASSERT_EQUAL(loc, 0.75);
|
|
CU_ASSERT_EQUAL(dist, 0.0);
|
|
|
|
lwline_free(line);
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING M (0 0 0, 10 0 20)"));
|
|
|
|
p.x = 5; p.y = 0;
|
|
loc = ptarray_locate_point(line->points, &p, &dist, &l);
|
|
CU_ASSERT_EQUAL(loc, 0.5);
|
|
CU_ASSERT_EQUAL(dist, 0.0);
|
|
CU_ASSERT_EQUAL(l.m, 10.0);
|
|
|
|
lwline_free(line);
|
|
|
|
}
|
|
|
|
static void test_ptarray_isccw(void)
|
|
{
|
|
LWLINE *line;
|
|
LWPOLY* poly;
|
|
int ccw;
|
|
|
|
/* clockwise rectangle */
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,10 10,10 0, 0 0)"));
|
|
ccw = ptarray_isccw(line->points);
|
|
CU_ASSERT_EQUAL(ccw, 0);
|
|
lwline_free(line);
|
|
|
|
/* clockwise triangle */
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4,20 3, 0 3)"));
|
|
ccw = ptarray_isccw(line->points);
|
|
CU_ASSERT_EQUAL(ccw, 0);
|
|
lwline_free(line);
|
|
|
|
/* counterclockwise triangle */
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 3,20 4, 0 3)"));
|
|
ccw = ptarray_isccw(line->points);
|
|
CU_ASSERT_EQUAL(ccw, 1);
|
|
lwline_free(line);
|
|
|
|
/* counterclockwise narrow ring (see ticket #1302) */
|
|
line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA284137894120A4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA2841C976BE1FA4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
|
|
ccw = ptarray_isccw(line->points);
|
|
CU_ASSERT_EQUAL(ccw, 1);
|
|
lwline_free(line);
|
|
|
|
/* clockwise narrow ring (see ticket #1302) */
|
|
line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA2841C976BE1FA4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA284137894120A4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
|
|
ccw = ptarray_isccw(line->points);
|
|
CU_ASSERT_EQUAL(ccw, 0);
|
|
lwline_free(line);
|
|
|
|
/* Clockwise narrow ring (see ticket #1302) */
|
|
poly = lwgeom_as_lwpoly(lwgeom_from_hexwkb("0103000000010000000500000000917E9BA468294100917E9B8AEA2841C976BE1FA4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA284137894120A4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
|
|
ccw = ptarray_isccw(poly->rings[0]);
|
|
CU_ASSERT_EQUAL(ccw, 0);
|
|
lwpoly_free(poly);
|
|
}
|
|
|
|
static void test_ptarray_signed_area()
|
|
{
|
|
LWLINE *line;
|
|
double area;
|
|
|
|
/* parallelogram */
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,1 1, 2 1, 1 0, 0 0)"));
|
|
area = ptarray_signed_area(line->points);
|
|
ASSERT_DOUBLE_EQUAL_TOLERANCE(area, 1.0, 0.0000001);
|
|
lwline_free(line);
|
|
|
|
/* square */
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 2, 2 2, 2 0, 0 0)"));
|
|
area = ptarray_signed_area(line->points);
|
|
ASSERT_DOUBLE_EQUAL_TOLERANCE(area, 4.0, 0.0000001);
|
|
lwline_free(line);
|
|
|
|
/* square backwares*/
|
|
line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,2 0, 2 2, 0 2, 0 0)"));
|
|
area = ptarray_signed_area(line->points);
|
|
//printf("%g\n",area);
|
|
ASSERT_DOUBLE_EQUAL_TOLERANCE(area, -4.0, 0.0000001);
|
|
lwline_free(line);
|
|
|
|
}
|
|
|
|
static void test_ptarray_contains_point()
|
|
{
|
|
/* int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt, int *winding_number) */
|
|
|
|
LWLINE *lwline;
|
|
POINTARRAY *pa;
|
|
POINT2D pt;
|
|
int rv;
|
|
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 1, 1 1, 1 0, 0 0)"));
|
|
pa = lwline->points;
|
|
|
|
/* Point in middle of square */
|
|
pt.x = 0.5;
|
|
pt.y = 0.5;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point on left edge of square */
|
|
pt.x = 0;
|
|
pt.y = 0.5;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
|
|
|
|
/* Point on top edge of square */
|
|
pt.x = 0.5;
|
|
pt.y = 1;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
|
|
|
|
/* Point on bottom left corner of square */
|
|
pt.x = 0;
|
|
pt.y = 0;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
|
|
|
|
/* Point on top left corner of square */
|
|
pt.x = 0;
|
|
pt.y = 1;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
|
|
|
|
/* Point outside top left corner of square */
|
|
pt.x = -0.1;
|
|
pt.y = 1;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/* Point outside top left corner of square */
|
|
pt.x = 0;
|
|
pt.y = 1.1;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/* Point outside left side of square */
|
|
pt.x = -0.2;
|
|
pt.y = 0.5;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
lwline_free(lwline);
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 1 1, 2 0, 0 0)"));
|
|
pa = lwline->points;
|
|
|
|
/* Point outside grazing top of triangle */
|
|
pt.x = 0;
|
|
pt.y = 1;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
lwline_free(lwline);
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 4, 1 4, 2 2, 3 4, 4 4, 4 0, 0 0)"));
|
|
pa = lwline->points;
|
|
|
|
/* Point outside grazing top of triangle */
|
|
pt.x = 1;
|
|
pt.y = 2;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point outside grazing top of triangle */
|
|
pt.x = 3;
|
|
pt.y = 2;
|
|
rv = ptarray_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
lwline_free(lwline);
|
|
}
|
|
|
|
static void test_ptarrayarc_contains_point()
|
|
{
|
|
/* int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt) */
|
|
|
|
LWLINE *lwline;
|
|
POINTARRAY *pa;
|
|
POINT2D pt;
|
|
int rv;
|
|
|
|
/*** Collection of semi-circles surrounding unit square ***/
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 -1, -2 0, -1 1, 0 2, 1 1, 2 0, 1 -1, 0 -2, -1 -1)"));
|
|
pa = lwline->points;
|
|
|
|
/* Point in middle of square */
|
|
pt.x = 0;
|
|
pt.y = 0;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point in left lobe */
|
|
pt.x = -1.1;
|
|
pt.y = 0.1;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point on boundary of left lobe */
|
|
pt.x = -1;
|
|
pt.y = 0;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point on boundary vertex */
|
|
pt.x = -1;
|
|
pt.y = 1;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
|
|
|
|
/* Point outside */
|
|
pt.x = -1.5;
|
|
pt.y = 1.5;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/*** Two-edge ring made up of semi-circles (really, a circle) ***/
|
|
lwline_free(lwline);
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 0 1, 1 0, 0 -1, -1 0)"));
|
|
pa = lwline->points;
|
|
|
|
/* Point outside */
|
|
pt.x = -1.5;
|
|
pt.y = 1.5;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/* Point more outside */
|
|
pt.x = 2.5;
|
|
pt.y = 1.5;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/* Point more outside */
|
|
pt.x = 2.5;
|
|
pt.y = 2.5;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/* Point inside at middle */
|
|
pt.x = 0;
|
|
pt.y = 0;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point inside offset from middle */
|
|
pt.x = 0.01;
|
|
pt.y = 0.01;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point on edge vertex */
|
|
pt.x = 0;
|
|
pt.y = 1;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
|
|
|
|
/*** Two-edge ring, closed ***/
|
|
lwline_free(lwline);
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(1 6, 6 1, 9 7, 6 10, 1 6)"));
|
|
pa = lwline->points;
|
|
|
|
/* Point to left of ring */
|
|
pt.x = 20;
|
|
pt.y = 4;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/*** One-edge ring, closed circle ***/
|
|
lwline_free(lwline);
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, -1 0)"));
|
|
pa = lwline->points;
|
|
|
|
/* Point inside */
|
|
pt.x = 0;
|
|
pt.y = 0;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_INSIDE);
|
|
|
|
/* Point outside */
|
|
pt.x = 0;
|
|
pt.y = 2;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
|
|
|
|
/* Point on boundary */
|
|
pt.x = 0;
|
|
pt.y = 1;
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
|
|
|
|
/*** Overshort ring ***/
|
|
lwline_free(lwline);
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0)"));
|
|
pa = lwline->points;
|
|
cu_error_msg_reset();
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
//printf("%s\n", cu_error_msg);
|
|
ASSERT_STRING_EQUAL("ptarrayarc_contains_point called with even number of points", cu_error_msg);
|
|
|
|
/*** Unclosed ring ***/
|
|
lwline_free(lwline);
|
|
lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, 2 0)"));
|
|
pa = lwline->points;
|
|
cu_error_msg_reset();
|
|
rv = ptarrayarc_contains_point(pa, &pt);
|
|
ASSERT_STRING_EQUAL("ptarrayarc_contains_point called on unclosed ring", cu_error_msg);
|
|
|
|
lwline_free(lwline);
|
|
}
|
|
|
|
static void test_ptarray_scale()
|
|
{
|
|
LWLINE *line;
|
|
POINTARRAY *pa;
|
|
POINT4D factor;
|
|
const char *wkt;
|
|
char *wktout;
|
|
|
|
wkt = "LINESTRING ZM (0 1 2 3,1 2 3 0,-2 -3 0 -1,-3 0 -1 -2)";
|
|
line = lwgeom_as_lwline(lwgeom_from_text(wkt));
|
|
pa = line->points;
|
|
|
|
factor.x = factor.y = factor.z = factor.m = 1;
|
|
ptarray_scale(pa, &factor);
|
|
wktout = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wktout, wkt);
|
|
lwfree(wktout);
|
|
|
|
factor.x = 2;
|
|
wkt = "LINESTRING ZM (0 1 2 3,2 2 3 0,-4 -3 0 -1,-6 0 -1 -2)";
|
|
ptarray_scale(pa, &factor);
|
|
wktout = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wktout, wkt);
|
|
lwfree(wktout);
|
|
|
|
factor.x = 1; factor.y = 3;
|
|
wkt = "LINESTRING ZM (0 3 2 3,2 6 3 0,-4 -9 0 -1,-6 0 -1 -2)";
|
|
ptarray_scale(pa, &factor);
|
|
wktout = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wktout, wkt);
|
|
lwfree(wktout);
|
|
|
|
factor.x = 1; factor.y = 1; factor.z = -2;
|
|
wkt = "LINESTRING ZM (0 3 -4 3,2 6 -6 0,-4 -9 0 -1,-6 0 2 -2)";
|
|
ptarray_scale(pa, &factor);
|
|
wktout = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wktout, wkt);
|
|
lwfree(wktout);
|
|
|
|
factor.x = 1; factor.y = 1; factor.z = 1; factor.m = 2;
|
|
wkt = "LINESTRING ZM (0 3 -4 6,2 6 -6 0,-4 -9 0 -2,-6 0 2 -4)";
|
|
ptarray_scale(pa, &factor);
|
|
wktout = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
ASSERT_STRING_EQUAL(wktout, wkt);
|
|
lwfree(wktout);
|
|
|
|
lwline_free(line);
|
|
}
|
|
|
|
static void test_ptarray_scroll()
|
|
{
|
|
LWLINE *line;
|
|
POINTARRAY *pa;
|
|
POINT4D scroll;
|
|
const char *wkt;
|
|
char *wktout;
|
|
int rv;
|
|
|
|
wkt = "LINESTRING ZM (1 1 1 1,2 2 2 2,3 3 3 3,4 4 4 4,1 1 1 1)";
|
|
line = lwgeom_as_lwline(lwgeom_from_text(wkt));
|
|
pa = line->points;
|
|
|
|
scroll.x = scroll.y = scroll.z = scroll.m = 2;
|
|
rv = ptarray_scroll_in_place(pa, &scroll);
|
|
CU_ASSERT_EQUAL(rv, LW_SUCCESS);
|
|
wktout = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
wkt = "LINESTRING ZM (2 2 2 2,3 3 3 3,4 4 4 4,1 1 1 1,2 2 2 2)";
|
|
ASSERT_STRING_EQUAL(wktout, wkt);
|
|
lwfree(wktout);
|
|
|
|
scroll.x = scroll.y = scroll.z = scroll.m = 1;
|
|
rv = ptarray_scroll_in_place(pa, &scroll);
|
|
CU_ASSERT_EQUAL(rv, LW_SUCCESS);
|
|
wktout = lwgeom_to_text(lwline_as_lwgeom(line));
|
|
wkt = "LINESTRING ZM (1 1 1 1,2 2 2 2,3 3 3 3,4 4 4 4,1 1 1 1)";
|
|
ASSERT_STRING_EQUAL(wktout, wkt);
|
|
lwfree(wktout);
|
|
|
|
scroll.x = scroll.y = scroll.z = scroll.m = 9;
|
|
rv = ptarray_scroll_in_place(pa, &scroll);
|
|
CU_ASSERT_EQUAL(rv, LW_FAILURE);
|
|
ASSERT_STRING_EQUAL(cu_error_msg, "ptarray_scroll_in_place: input POINTARRAY does not contain the given point");
|
|
|
|
lwline_free(line);
|
|
}
|
|
|
|
static void test_ptarray_closest_vertex_2d()
|
|
{
|
|
LWLINE *line;
|
|
POINTARRAY *pa;
|
|
double dist;
|
|
POINT2D qp;
|
|
const char *wkt;
|
|
int rv;
|
|
|
|
wkt = "LINESTRING (0 0 0, 1 0 0, 2 0 0, 3 0 10)";
|
|
line = lwgeom_as_lwline(lwgeom_from_text(wkt));
|
|
pa = line->points;
|
|
|
|
qp.x = qp.y = 0;
|
|
rv = ptarray_closest_vertex_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 0);
|
|
ASSERT_DOUBLE_EQUAL(dist, 0);
|
|
|
|
qp.x = qp.y = 1;
|
|
rv = ptarray_closest_vertex_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 1);
|
|
ASSERT_DOUBLE_EQUAL(dist, 1);
|
|
|
|
qp.x = 5; qp.y = 0;
|
|
rv = ptarray_closest_vertex_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 3);
|
|
ASSERT_DOUBLE_EQUAL(dist, 2);
|
|
|
|
|
|
lwline_free(line);
|
|
}
|
|
|
|
static void test_ptarray_closest_segment_2d()
|
|
{
|
|
LWLINE *line;
|
|
POINTARRAY *pa;
|
|
double dist;
|
|
POINT2D qp;
|
|
const char *wkt;
|
|
int rv;
|
|
|
|
wkt = "LINESTRING (0 0 0, 1 0 0, 2 0 0, 3 0 10)";
|
|
line = lwgeom_as_lwline(lwgeom_from_text(wkt));
|
|
pa = line->points;
|
|
|
|
qp.x = qp.y = 0;
|
|
rv = ptarray_closest_segment_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 0);
|
|
ASSERT_DOUBLE_EQUAL(dist, 0);
|
|
|
|
qp.x = 1;
|
|
rv = ptarray_closest_segment_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 0);
|
|
ASSERT_DOUBLE_EQUAL(dist, 0);
|
|
|
|
qp.y = 1;
|
|
rv = ptarray_closest_segment_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 0);
|
|
ASSERT_DOUBLE_EQUAL(dist, 1);
|
|
|
|
qp.x = 5; qp.y = 0;
|
|
rv = ptarray_closest_segment_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 2);
|
|
ASSERT_DOUBLE_EQUAL(dist, 2);
|
|
|
|
|
|
lwline_free(line);
|
|
|
|
/* See https://trac.osgeo.org/postgis/ticket/4990 */
|
|
/* Test modified to give more stable results */
|
|
wkt = "LINESTRING(4 31,7 31,7 34,4 34,4 31)";
|
|
line = lwgeom_as_lwline(lwgeom_from_text(wkt));
|
|
pa = line->points;
|
|
qp.x = 7.1; qp.y = 31.1;
|
|
rv = ptarray_closest_segment_2d(pa, &qp, &dist);
|
|
ASSERT_INT_EQUAL(rv, 1);
|
|
lwline_free(line);
|
|
}
|
|
|
|
static void test_ptarray_closest_point_on_segment(void)
|
|
{
|
|
POINT4D s0, s1, qp, cp;
|
|
|
|
s0.x = s0.y = 0; s0.z = 10; s0.m = 20;
|
|
s1.x = 0; s1.y = 10; s1.z = 0; s1.m = 10;
|
|
|
|
/* Closest is bottom point */
|
|
|
|
qp.x = -0.1; qp.y = 0;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 10);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 20);
|
|
|
|
qp.x = 0.1; qp.y = 0;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 10);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 20);
|
|
|
|
qp.x = 0; qp.y = -0.1;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 10);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 20);
|
|
|
|
/* Closest is top point */
|
|
|
|
qp.x = 0; qp.y = 10.1;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 10);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 10);
|
|
|
|
qp.x = 0.1; qp.y = 10;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 10);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 10);
|
|
|
|
qp.x = -0.1; qp.y = 10;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 10);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 10);
|
|
|
|
/* Closest is mid point */
|
|
|
|
qp.x = 0.1; qp.y = 5;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 5);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 5);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 15);
|
|
|
|
qp.x = -0.1; qp.y = 5;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 5);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 5);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 15);
|
|
|
|
qp.x = 0.1; qp.y = 2;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 2);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 8);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 18);
|
|
|
|
qp.x = -0.1; qp.y = 2;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 2);
|
|
ASSERT_DOUBLE_EQUAL(cp.z, 8);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 18);
|
|
|
|
qp.x = 0.1; qp.y = 8;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 8);
|
|
ASSERT_DOUBLE_EQUAL_TOLERANCE(cp.z, 2, 1e-5);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 12);
|
|
|
|
qp.x = -0.1; qp.y = 8;
|
|
closest_point_on_segment(&qp, &s0, &s1, &cp);
|
|
ASSERT_DOUBLE_EQUAL(cp.x, 0);
|
|
ASSERT_DOUBLE_EQUAL(cp.y, 8);
|
|
ASSERT_DOUBLE_EQUAL_TOLERANCE(cp.z, 2, 1e-5);
|
|
ASSERT_DOUBLE_EQUAL(cp.m, 12);
|
|
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
** Used by the test harness to register the tests in this file.
|
|
*/
|
|
void ptarray_suite_setup(void);
|
|
void ptarray_suite_setup(void)
|
|
{
|
|
CU_pSuite suite = CU_add_suite("ptarray", NULL, NULL);
|
|
PG_ADD_TEST(suite, test_ptarray_append_point);
|
|
PG_ADD_TEST(suite, test_ptarray_append_ptarray);
|
|
PG_ADD_TEST(suite, test_ptarray_locate_point);
|
|
PG_ADD_TEST(suite, test_ptarray_isccw);
|
|
PG_ADD_TEST(suite, test_ptarray_signed_area);
|
|
PG_ADD_TEST(suite, test_ptarray_insert_point);
|
|
PG_ADD_TEST(suite, test_ptarray_contains_point);
|
|
PG_ADD_TEST(suite, test_ptarrayarc_contains_point);
|
|
PG_ADD_TEST(suite, test_ptarray_scale);
|
|
PG_ADD_TEST(suite, test_ptarray_scroll);
|
|
PG_ADD_TEST(suite, test_ptarray_closest_vertex_2d);
|
|
PG_ADD_TEST(suite, test_ptarray_closest_segment_2d);
|
|
PG_ADD_TEST(suite, test_ptarray_closest_point_on_segment);
|
|
}
|