コード例 #1
0
ファイル: lwgeom_ogc.c プロジェクト: gravitystorm/postgis
Datum LWGEOM_asText(PG_FUNCTION_ARGS)
{
	GSERIALIZED *geom;
	LWGEOM *lwgeom;
	char *wkt;
	size_t wkt_size;
	text *result;

	POSTGIS_DEBUG(2, "Called.");

	geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
	lwgeom = lwgeom_from_gserialized(geom);

	/* Write to WKT and free the geometry */
	wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, &wkt_size);
	lwgeom_free(lwgeom);
	POSTGIS_DEBUGF(3, "WKT size = %d, WKT length = %d", wkt_size, strlen(wkt));

	/* Write to text and free the WKT */
	result = cstring2text(wkt);
	pfree(wkt);

	/* Return the text */
	PG_FREE_IF_COPY(geom, 0);
	PG_RETURN_TEXT_P(result);
}
コード例 #2
0
ファイル: cu_gdal.c プロジェクト: ahinz/postgis
static char *
lwgeom_to_text(const LWGEOM *lwgeom) {
	char *wkt;
	size_t wkt_size;

	wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, &wkt_size);

	return wkt;
}
コード例 #3
0
ファイル: cu_misc.c プロジェクト: gbroccolo/postgis
static void test_misc_wkb(void)
{
	static char *wkb = "010A0000000200000001080000000700000000000000000000C00000000000000000000000000000F0BF000000000000F0BF00000000000000000000000000000000000000000000F03F000000000000F0BF000000000000004000000000000000000000000000000000000000000000004000000000000000C00000000000000000010200000005000000000000000000F0BF00000000000000000000000000000000000000000000E03F000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F0BF0000000000000000";
	LWGEOM *geom = lwgeom_from_hexwkb(wkb, LW_PARSER_CHECK_ALL);
	char *str = lwgeom_to_wkt(geom, WKB_ISO, 8, 0);
	CU_ASSERT_STRING_EQUAL(str, "CURVEPOLYGON(CIRCULARSTRING(-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0),(-1 0,0 0.5,1 0,0 1,-1 0))");
	lwfree(str);
	lwgeom_free(geom);
		
}
コード例 #4
0
ファイル: cu_in_wkt.c プロジェクト: bnordgren/postgis
/* 
* Return a char* that results from taking the input 
* WKT, creating an LWGEOM, then writing it back out
* as an output WKT using the supplied variant.
* If there is an error, return that.
*/
static char* cu_wkt_in(char *wkt, uint8_t variant)
{
	LWGEOM_PARSER_RESULT p;
	int rv = 0;
	char *s = 0;
	
	rv = lwgeom_parse_wkt(&p, wkt, 0);
	if( p.errcode ) {
		return strdup(p.message);
	}
	s = lwgeom_to_wkt(p.geom, variant, 8, NULL);
	lwgeom_parser_result_free(&p);
	return s;
}
コード例 #5
0
ファイル: lwgeom.c プロジェクト: abuhamid/bd_geonode
/**
 * Return an alloced string
 */
char*
lwgeom_to_ewkt(const LWGEOM *lwgeom)
{
	char* wkt = NULL;
	size_t wkt_size = 0;
	
	wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, 12, &wkt_size);

	if ( ! wkt )
	{
		lwerror("Error writing geom %p to WKT", lwgeom);
	}

	return wkt;
}
コード例 #6
0
ファイル: geography_inout.c プロジェクト: bnordgren/postgis
Datum geography_as_text(PG_FUNCTION_ARGS)
{
	GSERIALIZED *g = NULL;
	LWGEOM *lwgeom = NULL;
	char *wkt = NULL;
	text *result = NULL;
	size_t len = 0;

	g = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));

	/* Convert to lwgeom so we can run the old functions */
	lwgeom = lwgeom_from_gserialized(g);

	/* Generate WKT */
	wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, &len);

	/* Copy into text obect */
	result = cstring2text(wkt);
	pfree(wkt);
	lwgeom_free(lwgeom);

	PG_RETURN_TEXT_P(result);
}
コード例 #7
0
ファイル: cu_ptarray.c プロジェクト: NianYue/pipelinedb
static void test_ptarray_desegmentize() 
{
	LWGEOM *in, *out;
	char *str;

	/* It would be nice if this example returned two arcs (it's the intersection of two circles)
	   but it looks like the intersection itself is too sloppy in generating the derived point
	   to accurately reconstruct the circles.
	in = lwgeom_from_text("POLYGON((0.5 0,0.471177920604846 -0.292635483024192,0.38581929876693 -0.574025148547634,0.247204418453818 -0.833355349529403,0.0606601717798223 -1.06066017177982,-5.44089437167602e-17 -1.11044268820754,-0.0606601717798188 -1.06066017177982,-0.247204418453816 -0.833355349529406,-0.385819298766929 -0.574025148547639,-0.471177920604845 -0.292635483024197,-0.5 -4.84663372329776e-15,-0.471177920604847 0.292635483024187,-0.385819298766932 0.57402514854763,-0.247204418453821 0.833355349529398,-0.0606601717798256 1.06066017177982,3.45538806345173e-16 1.11044268820754,0.0606601717798183 1.06066017177982,0.247204418453816 0.833355349529407,0.385819298766929 0.574025148547638,0.471177920604845 0.292635483024196,0.5 0))");
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	printf("%s\n", str);
	CU_ASSERT_STRING_EQUAL(str, "CIRCULARSTRING(-1 0,0 1,0 -1)");
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);	
	*/
	
	in = lwgeom_from_text("CIRCULARSTRING(-1 0,0 1,0 -1)");
	out = lwgeom_segmentize(in,8);
	lwgeom_free(in);
	in = out;
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	// printf("%s\n", str);
	CU_ASSERT_STRING_EQUAL(str, "CIRCULARSTRING(-1 0,0.70710678 0.70710678,0 -1)");
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);	

	in = lwgeom_from_text("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,-1 -1))");
	out = lwgeom_segmentize(in,8);
	lwgeom_free(in);
	in = out;
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	// printf("%s\n", str);
	CU_ASSERT_STRING_EQUAL(str, "COMPOUNDCURVE(CIRCULARSTRING(-1 0,0.70710678 0.70710678,0 -1),(0 -1,-1 -1))");
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);	

	in = lwgeom_from_text("COMPOUNDCURVE((-3 -3,-1 0),CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,0 -1.5,0 -2),CIRCULARSTRING(0 -2,-1 -3,1 -3),(1 -3,5 5))");
	out = lwgeom_segmentize(in,8);
	lwgeom_free(in);
	in = out;
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	// printf("%s\n", str);
	CU_ASSERT_STRING_EQUAL(str, "COMPOUNDCURVE((-3 -3,-1 0),CIRCULARSTRING(-1 0,0.70710678 0.70710678,0 -1),(0 -1,0 -1.5,0 -2),CIRCULARSTRING(0 -2,-0.70710678 -3.7071068,1 -3),(1 -3,5 5))");
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);	

	in = lwgeom_from_text("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),CIRCULARSTRING(0 -1,-1 -2,1 -2))");
	out = lwgeom_segmentize(in,8);
	lwgeom_free(in);
	in = out;
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	// printf("%s\n", str);
	CU_ASSERT_STRING_EQUAL(str, "COMPOUNDCURVE(CIRCULARSTRING(-1 0,0.70710678 0.70710678,0 -1),CIRCULARSTRING(0 -1,-0.70710678 -2.7071068,1 -2))");
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);	
	
	in = lwgeom_from_text("COMPOUNDCURVE((0 0, 1 1), CIRCULARSTRING(1 1, 2 2, 3 1), (3 1, 4 4))");
	out = lwgeom_segmentize(in,8);
	lwgeom_free(in);
	in = out;
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	CU_ASSERT_STRING_EQUAL(str, "COMPOUNDCURVE((0 0,1 1),CIRCULARSTRING(1 1,2 2,3 1),(3 1,4 4))");
	lwgeom_free(in);
	lwgeom_free(out);
	// printf("%s\n", str);
	lwfree(str);		
	
	// See http://trac.osgeo.org/postgis/ticket/2425 
	// and http://trac.osgeo.org/postgis/ticket/2420 
	in = lwgeom_from_text("LINESTRING(0 0,10 0,10 10,0 10,0 0)");
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	CU_ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,10 0,10 10,0 10,0 0)");
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);	

	in = lwgeom_from_text("LINESTRING(10 10,0 10,0 0,10 0)");
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	CU_ASSERT_STRING_EQUAL(str, "LINESTRING(10 10,0 10,0 0,10 0)");
	// printf("%s\n", str);
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);

	in = lwgeom_from_text("LINESTRING(0 0,10 0,10 10,0 10)");
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	CU_ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,10 0,10 10,0 10)");
	// printf("%s\n", str);
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);

	// See http://trac.osgeo.org/postgis/ticket/2412
	in = lwgeom_from_text("LINESTRING(0 0, 1 1)");
	out = lwgeom_desegmentize(in);
	str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
	// printf("%s\n", str);
	CU_ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,1 1)");
	lwgeom_free(in);
	lwgeom_free(out);
	lwfree(str);		

}
コード例 #8
0
ファイル: cu_ptarray.c プロジェクト: NianYue/pipelinedb
static char* lwgeom_to_text(const LWGEOM *geom)
{
	return lwgeom_to_wkt(geom, WKT_ISO, 8, NULL);
}
コード例 #9
0
ファイル: shp2pgsql-core.c プロジェクト: sensorseverywhere/se
/**
 * @brief Generate an allocated geometry string for shapefile object obj using the state parameters
 *
 * This function basically deals with the polygon case. It sorts the polys in order of outer,
 * inner,inner, so that inners always come after outers they are within.
 *
 */
int
GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry)
{
	Ring **Outer;
	int polygon_total, ring_total;
	int pi, vi; /* part index and vertex index */

	LWGEOM **lwpolygons;
	LWGEOM *lwgeom;

	POINT4D point4d;

	int dims = 0;

	char *mem;
	size_t mem_length;

	FLAGS_SET_Z(dims, state->has_z);
	FLAGS_SET_M(dims, state->has_m);

	polygon_total = FindPolygons(obj, &Outer);

	if (state->config->simple_geometries == 1 && polygon_total != 1) /* We write Non-MULTI geometries, but have several parts: */
	{
		snprintf(state->message, SHPLOADERMSGLEN, _("We have a Multipolygon with %d parts, can't use -S switch!"), polygon_total);

		return SHPLOADERERR;
	}

	/* Allocate memory for our array of LWPOLYs */
	lwpolygons = malloc(sizeof(LWPOLY *) * polygon_total);

	/* Cycle through each individual polygon */
	for (pi = 0; pi < polygon_total; pi++)
	{
		LWPOLY *lwpoly = lwpoly_construct_empty(state->from_srid, state->has_z, state->has_m);
		
		Ring *polyring;
		int ring_index = 0;

		/* Firstly count through the total number of rings in this polygon */
		ring_total = 0;
		polyring = Outer[pi];
		while (polyring)
		{
			ring_total++;
			polyring = polyring->next;
		}

		/* Cycle through each ring within the polygon, starting with the outer */
		polyring = Outer[pi];

		while (polyring)
		{
			/* Create a POINTARRAY containing the points making up the ring */
			POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, polyring->n);

			for (vi = 0; vi < polyring->n; vi++)
			{
				/* Build up a point array of all the points in this ring */
				point4d.x = polyring->list[vi].x;
				point4d.y = polyring->list[vi].y;

				if (state->has_z)
					point4d.z = polyring->list[vi].z;
				if (state->has_m)
					point4d.m = polyring->list[vi].m;

				ptarray_append_point(pa, &point4d, LW_TRUE);
			}

			/* Copy the POINTARRAY pointer so we can use the LWPOLY constructor */
			lwpoly_add_ring(lwpoly, pa);

			polyring = polyring->next;
			ring_index++;
		}

		/* Generate the LWGEOM */
		lwpolygons[pi] = lwpoly_as_lwgeom(lwpoly);
	}

	/* If using MULTIPOLYGONS then generate the serialized collection, otherwise just a single POLYGON */
	if (state->config->simple_geometries == 0)
	{
		lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTIPOLYGONTYPE, state->from_srid, NULL, polygon_total, lwpolygons));
	}
	else
	{
		lwgeom = lwpolygons[0];
		lwfree(lwpolygons);
	}

	if (!state->config->use_wkt)
		mem = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &mem_length);
	else
		mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length);

	if ( !mem )
	{
		snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry");
		return SHPLOADERERR;
	}

	/* Free all of the allocated items */
	lwgeom_free(lwgeom);

	/* Free the linked list of rings */
	ReleasePolygons(Outer, polygon_total);

	/* Return the string - everything ok */
	*geometry = mem;

	return SHPLOADEROK;
}
コード例 #10
0
ファイル: shp2pgsql-core.c プロジェクト: sensorseverywhere/se
/**
 * @brief Generate an allocated geometry string for shapefile object obj using the state parameters
 */
int
GenerateLineStringGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry)
{

	LWGEOM **lwmultilinestrings;
	LWGEOM *lwgeom = NULL;
	POINT4D point4d;
	int dims = 0;
	int u, v, start_vertex, end_vertex;
	char *mem;
	size_t mem_length;


	FLAGS_SET_Z(dims, state->has_z);
	FLAGS_SET_M(dims, state->has_m);

	if (state->config->simple_geometries == 1 && obj->nParts > 1)
	{
		snprintf(state->message, SHPLOADERMSGLEN, _("We have a Multilinestring with %d parts, can't use -S switch!"), obj->nParts);

		return SHPLOADERERR;
	}

	/* Allocate memory for our array of LWLINEs and our dynptarrays */
	lwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts);

	/* We need an array of pointers to each of our sub-geometries */
	for (u = 0; u < obj->nParts; u++)
	{
		/* Create a ptarray containing the line points */
		POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, obj->nParts);

		/* Set the start/end vertices depending upon whether this is
		a MULTILINESTRING or not */
		if ( u == obj->nParts-1 )
			end_vertex = obj->nVertices;
		else
			end_vertex = obj->panPartStart[u + 1];

		start_vertex = obj->panPartStart[u];

		for (v = start_vertex; v < end_vertex; v++)
		{
			/* Generate the point */
			point4d.x = obj->padfX[v];
			point4d.y = obj->padfY[v];

			if (state->has_z)
				point4d.z = obj->padfZ[v];
			if (state->has_m)
				point4d.m = obj->padfM[v];

			ptarray_append_point(pa, &point4d, LW_FALSE);
		}

		/* Generate the LWLINE */
		lwmultilinestrings[u] = lwline_as_lwgeom(lwline_construct(state->from_srid, NULL, pa));
	}

	/* If using MULTILINESTRINGs then generate the serialized collection, otherwise just a single LINESTRING */
	if (state->config->simple_geometries == 0)
	{
		lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTILINETYPE, state->from_srid, NULL, obj->nParts, lwmultilinestrings));
	}
	else
	{
		lwgeom = lwmultilinestrings[0];
		lwfree(lwmultilinestrings);
	}

	if (!state->config->use_wkt)
		mem = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &mem_length);
	else
		mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length);

	if ( !mem )
	{
		snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry");
		return SHPLOADERERR;
	}

	/* Free all of the allocated items */
	lwgeom_free(lwgeom);

	/* Return the string - everything ok */
	*geometry = mem;

	return SHPLOADEROK;
}
コード例 #11
0
ファイル: shp2pgsql-core.c プロジェクト: sensorseverywhere/se
/**
 * @brief Generate an allocated geometry string for shapefile object obj using the state parameters
 * if "force_multi" is true, single points will instead be created as multipoints with a single vertice.
 */
int
GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, int force_multi)
{
	LWGEOM **lwmultipoints;
	LWGEOM *lwgeom = NULL;

	POINT4D point4d;

	int dims = 0;
	int u;

	char *mem;
	size_t mem_length;

	FLAGS_SET_Z(dims, state->has_z);
	FLAGS_SET_M(dims, state->has_m);

	/* Allocate memory for our array of LWPOINTs and our dynptarrays */
	lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices);

	/* We need an array of pointers to each of our sub-geometries */
	for (u = 0; u < obj->nVertices; u++)
	{
		/* Create a ptarray containing a single point */
		POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, 1);
		
		/* Generate the point */
		point4d.x = obj->padfX[u];
		point4d.y = obj->padfY[u];

		if (state->has_z)
			point4d.z = obj->padfZ[u];
		if (state->has_m)
			point4d.m = obj->padfM[u];

		/* Add in the point! */
		ptarray_append_point(pa, &point4d, LW_TRUE);

		/* Generate the LWPOINT */
		lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(state->from_srid, NULL, pa));
	}

	/* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT
	rather than a POINT */
	if ((obj->nVertices > 1) || force_multi)
	{
		lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTIPOINTTYPE, state->from_srid, NULL, obj->nVertices, lwmultipoints));
	}
	else
	{
		lwgeom = lwmultipoints[0];
		lwfree(lwmultipoints);
	}

	if (state->config->use_wkt)
	{
		mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length);
	}
	else
	{
		mem = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &mem_length);
	}

	if ( !mem )
	{
		snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry");
		return SHPLOADERERR;
	}

	/* Free all of the allocated items */
	lwgeom_free(lwgeom);
	
	/* Return the string - everything ok */
	*geometry = mem;

	return SHPLOADEROK;
}
コード例 #12
0
ファイル: g_serialized.c プロジェクト: NianYue/pipelinedb
char* gserialized_to_string(const GSERIALIZED *g)
{
	return lwgeom_to_wkt(lwgeom_from_gserialized(g), WKT_ISO, 12, 0);
}
コード例 #13
0
ファイル: cu_surface.c プロジェクト: NianYue/pipelinedb
void triangle_parse(void)
{
	LWGEOM *geom;
	GSERIALIZED *g;
	char *tmp;

	cu_error_msg_reset();	/* Because i don't trust that much prior tests...  ;) */

	/* 2 dims */
	geom = lwgeom_from_wkt("TRIANGLE((0 1,2 3,4 5,0 1))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_EQUAL(strlen(cu_error_msg), 0);
	CU_ASSERT_EQUAL(geom->type, TRIANGLETYPE);
	tmp = lwgeom_to_ewkt(geom);
	CU_ASSERT_STRING_EQUAL("TRIANGLE((0 1,2 3,4 5,0 1))", tmp);
	lwfree(tmp);
	lwgeom_free(geom);
	/* 3DM */
	geom = lwgeom_from_wkt("TRIANGLEM((0 1 2,3 4 5,6 7 8,0 1 2))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_EQUAL(strlen(cu_error_msg), 0);
	CU_ASSERT_EQUAL(geom->type, TRIANGLETYPE);
	tmp = lwgeom_to_ewkt(geom);
	CU_ASSERT_STRING_EQUAL("TRIANGLEM((0 1 2,3 4 5,6 7 8,0 1 2))", tmp);
	lwfree(tmp);
	lwgeom_free(geom);

	/* ERROR: a missing Z values */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2,3 4 5,6 7,0 1 2))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_STRING_EQUAL("can not mix dimensionality in a geometry", cu_error_msg);
	cu_error_msg_reset();
	lwgeom_free(geom);

	/* ERROR: non closed rings */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2,3 4 5,6 7 8,0 0 2))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_STRING_EQUAL("geometry contains non-closed rings", cu_error_msg);
	cu_error_msg_reset();
	lwgeom_free(geom);

	/* ERROR: non closed face in Z dim */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2,3 4 5,6 7 8,0 1 3))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_STRING_EQUAL("geometry contains non-closed rings", cu_error_msg);
	cu_error_msg_reset();
	lwgeom_free(geom);

	/* ERROR: non closed face in Z dim, with a 4D geom */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2 3,4 5 6 7,8 9 10 11,0 1 3 3))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_STRING_EQUAL("geometry contains non-closed rings", cu_error_msg);
	cu_error_msg_reset();
	lwgeom_free(geom);

	/* ERROR: only 3 points in a face */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2,3 4 5,0 1 2))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_STRING_EQUAL("triangle must have exactly 4 points", cu_error_msg);
	cu_error_msg_reset();
	lwgeom_free(geom);

	/* ERROR: more than 4 points in a face */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2,3 4 5,6 7 8,9 10 11,0 1 2))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_STRING_EQUAL("triangle must have exactly 4 points", cu_error_msg);
	cu_error_msg_reset();
	lwgeom_free(geom);

	/* ERROR: no interior rings allowed */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2,3 4 5,6 7 8,0 1 2),(9 10 11,12 13 14,15 16 17,9 10 11)", LW_PARSER_CHECK_NONE);
	CU_ASSERT_STRING_EQUAL("parse error - invalid geometry", cu_error_msg);
	cu_error_msg_reset();
	lwgeom_free(geom);

	/* EMPTY face */
	geom = lwgeom_from_wkt("TRIANGLE EMPTY", LW_PARSER_CHECK_NONE);
	CU_ASSERT_EQUAL(strlen(cu_error_msg), 0);
	CU_ASSERT_EQUAL(geom->type, TRIANGLETYPE);
	tmp = lwgeom_to_wkt(geom, LW_PARSER_CHECK_NONE, 0, 0);
	CU_ASSERT_STRING_EQUAL("TRIANGLE EMPTY", tmp);
	lwfree(tmp);
	lwgeom_free(geom);

	/* explicit SRID */
	geom = lwgeom_from_wkt("SRID=4326;TRIANGLE((0 1 2,3 4 5,6 7 8,0 1 2))", LW_PARSER_CHECK_NONE);
	CU_ASSERT_EQUAL(strlen(cu_error_msg), 0);
	CU_ASSERT_EQUAL(geom->type, TRIANGLETYPE);
	CU_ASSERT_EQUAL(geom->srid, 4326);
	tmp = lwgeom_to_ewkt(geom);
	CU_ASSERT_STRING_EQUAL("SRID=4326;TRIANGLE((0 1 2,3 4 5,6 7 8,0 1 2))", tmp);
	lwfree(tmp);
	lwgeom_free(geom);

	/* geography support */
	geom = lwgeom_from_wkt("TRIANGLE((0 1 2,3 4 5,6 7 8,0 1 2))", LW_PARSER_CHECK_NONE);
	g = gserialized_from_lwgeom(geom, 1, 0);
	CU_ASSERT_EQUAL(gserialized_get_type(g), TRIANGLETYPE);
	lwgeom_free(geom);
	lwfree(g);
}