SpatiaLite  3.0.0-stable
demo2.c

This is a sample C source showing how to manipulate GEOMETRY within Spatialite. It essentially follows on from the functionality shown in the demo1.c example, and covers:

• creating geometries
• exploring geometries
• querying the basic properties of a geometry

Note that this does not require a database command line argument. Here is a typical run:

```\$ ./demo2
step#1: POINT           Dimension=0 IsValid=1
POINT 0/1 x=1.5000 y=2.7500

step#2: LINESTRING      Dimension=1 IsValid=1
LINESTRING 0/1 has 5 vertices
vertex 0/5 x=1.0000 y=1.0000
vertex 1/5 x=2.0000 y=1.0000
vertex 2/5 x=2.0000 y=2.0000
vertex 3/5 x=100.0000 y=2.0000
vertex 4/5 x=100.0000 y=100.0000

step#3: POLYGON Dimension=2 IsValid=1
POLYGON 0/1 has 2 holes
ExteriorRing has 5 vertices
vertex 0/5 x=0.0000 y=0.0000
vertex 1/5 x=50.0000 y=0.0000
vertex 2/5 x=50.0000 y=50.0000
vertex 3/5 x=0.0000 y=50.0000
vertex 4/5 x=0.0000 y=0.0000
InteriorRing 0/2 has 5 vertices
vertex 0/5 x=40.0000 y=40.0000
vertex 1/5 x=41.0000 y=40.0000
vertex 2/5 x=41.0000 y=41.0000
vertex 3/5 x=40.0000 y=41.0000
vertex 4/5 x=40.0000 y=40.0000
InteriorRing 1/2 has 5 vertices
vertex 0/5 x=30.0000 y=30.0000
vertex 1/5 x=31.0000 y=30.0000
vertex 2/5 x=31.0000 y=31.0000
vertex 3/5 x=30.0000 y=31.0000
vertex 4/5 x=30.0000 y=30.0000

step#4: MULTIPOINT      Dimension=0 IsValid=1
POINT 0/5 x=5.0000 y=5.0000
POINT 1/5 x=15.0000 y=5.0000
POINT 2/5 x=5.0000 y=15.0000
POINT 3/5 x=25.0000 y=5.0000
POINT 4/5 x=5.0000 y=25.0000

step#5: MULTILINESTRING Dimension=1 IsValid=1
LINESTRING 0/2 has 2 vertices
vertex 0/2 x=30.0000 y=10.0000
vertex 1/2 x=10.0000 y=30.0000
LINESTRING 1/2 has 2 vertices
vertex 0/2 x=40.0000 y=50.0000
vertex 1/2 x=50.0000 y=40.0000

step#6: MULTIPOLYGON    Dimension=2 IsValid=1
POLYGON 0/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=60.0000 y=60.0000
vertex 1/5 x=70.0000 y=60.0000
vertex 2/5 x=70.0000 y=70.0000
vertex 3/5 x=60.0000 y=70.0000
vertex 4/5 x=60.0000 y=60.0000
POLYGON 1/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=80.0000 y=80.0000
vertex 1/5 x=90.0000 y=80.0000
vertex 2/5 x=90.0000 y=90.0000
vertex 3/5 x=80.0000 y=90.0000
vertex 4/5 x=80.0000 y=80.0000

step#7: GEOMETRYCOLLECTION      Dimension=2 IsValid=1
POINT 0/2 x=100.0000 y=100.0000
POINT 1/2 x=100.0000 y=0.0000
LINESTRING 0/2 has 2 vertices
vertex 0/2 x=130.0000 y=110.0000
vertex 1/2 x=110.0000 y=130.0000
LINESTRING 1/2 has 2 vertices
vertex 0/2 x=140.0000 y=150.0000
vertex 1/2 x=150.0000 y=140.0000
POLYGON 0/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=160.0000 y=160.0000
vertex 1/5 x=170.0000 y=160.0000
vertex 2/5 x=170.0000 y=170.0000
vertex 3/5 x=160.0000 y=170.0000
vertex 4/5 x=160.0000 y=160.0000
POLYGON 1/2 has 0 holes
ExteriorRing has 5 vertices
vertex 0/5 x=180.0000 y=180.0000
vertex 1/5 x=190.0000 y=180.0000
vertex 2/5 x=190.0000 y=190.0000
vertex 3/5 x=180.0000 y=190.0000
vertex 4/5 x=180.0000 y=180.0000

step#8: checking WKT representations

GEOMETRYCOLLECTION(POINT(1.5 2.75))

GEOMETRYCOLLECTION(LINESTRING(1 1, 2 1, 2 2, 100 2, 100 100))

GEOMETRYCOLLECTION(POLYGON((0 0, 50 0, 50 50, 0 50, 0 0), (40 40, 41 40, 41 41, 40 41, 40 40), (30 30, 31 30, 31 31, 30 31, 30 30)))

GEOMETRYCOLLECTION(POINT(5 5), POINT(15 5), POINT(5 15), POINT(25 5), POINT(5 25))

GEOMETRYCOLLECTION(LINESTRING(30 10, 10 30), LINESTRING(40 50, 50 40))

GEOMETRYCOLLECTION(POLYGON((60 60, 70 60, 70 70, 60 70, 60 60)), POLYGON((80 80, 90 80, 90 90, 80 90, 80 80)))

GEOMETRYCOLLECTION(POINT(100 100), POINT(100 0), LINESTRING(130 110, 110 130), LINESTRING(140 150, 150 140), POLYGON((160 160, 170 160, 170 170, 160 170, 160 160)), POLYGON((180 180, 190 180, 190 190, 180 190, 180 180)))
```
```/*

demo2.c

Author: Sandro Furieri a-furieri@lqt.it

This software is provided 'as-is', without any express or implied
warranty.  In no event will the author be held liable for any
damages arising from the use of this software.

Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely

*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*
these headers are required in order to support
SQLite/SpatiaLite
*/

#include <geos_c.h>

#include <sqlite3.h>
#include <spatialite/gaiageo.h>
#include <spatialite.h>

static char *
geom_type (int type)
{
/* utility function returning corresponding GeometryType as a string */
static char *name = "EMPTY / NULL GEOMETRY";
if (type == GAIA_POINT)
name = "POINT";
if (type == GAIA_LINESTRING)
name = "LINESTRING";
if (type == GAIA_POLYGON)
name = "POLYGON";
if (type == GAIA_MULTIPOINT)
name = "MULTIPOINT";
if (type == GAIA_MULTILINESTRING)
name = "MULTILINESTRING";
if (type == GAIA_MULTIPOLYGON)
name = "MULTIPOLYGON";
if (type == GAIA_GEOMETRYCOLLECTION)
name = "GEOMETRYCOLLECTION";
return name;
}

static void
geometry_printout (gaiaGeomCollPtr geom)
{
/* utility function printing a generic Geometry object */
gaiaPointPtr pt;
gaiaLinestringPtr ln;
gaiaPolygonPtr pg;
gaiaRingPtr rng;
int n_pts = 0;
int n_lns = 0;
int n_pgs = 0;
int cnt;
int iv;
int ir;
double x;
double y;

/* we'll now count how many POINTs are there */
pt = geom->FirstPoint;
while (pt)
{
n_pts++;
pt = pt->Next;
}
/* we'll now count how many LINESTRINGs are there */
ln = geom->FirstLinestring;
while (ln)
{
n_lns++;
ln = ln->Next;
}
/* we'll now count how many POLYGONs are there */
pg = geom->FirstPolygon;
while (pg)
{
n_pgs++;
pg = pg->Next;
}

if (n_pts)
{
/* printing POINTs coordinates */
cnt = 0;
pt = geom->FirstPoint;
while (pt)
{
/* we'll now scan the linked list of POINTs */
printf ("\t\t\tPOINT %d/%d x=%1.4f y=%1.4f\n",
cnt, n_pts, pt->X, pt->Y);
cnt++;
pt = pt->Next;
}
}

if (n_lns)
{
/* printing LINESTRINGs coordinates */
cnt = 0;
ln = geom->FirstLinestring;
while (ln)
{
/* we'll now scan the linked list of LINESTRINGs */
printf ("\t\t\tLINESTRING %d/%d has %d vertices\n",
cnt, n_lns, ln->Points);
for (iv = 0; iv < ln->Points; iv++)
{
/* we'll now retrieve coordinates for each vertex */
gaiaGetPoint (ln->Coords, iv, &x, &y);
printf ("\t\t\t\tvertex %d/%d x=%1.4f y=%1.4f\n",
iv, ln->Points, x, y);
}
cnt++;
ln = ln->Next;
}
}

if (n_pgs)
{
/* printing POLYGONs coordinates */
cnt = 0;
pg = geom->FirstPolygon;
while (pg)
{
/* we'll now scan the linked list of POLYGONs */
printf ("\t\t\tPOLYGON %d/%d has %d hole%c\n",
cnt, n_pgs, pg->NumInteriors,
(pg->NumInteriors == 1) ? ' ' : 's');

/*
now we'll print out the Exterior ring
[surely a POLYGON has an Exterior ring
*/
rng = pg->Exterior;
printf ("\t\t\t\tExteriorRing has %d vertices\n", rng->Points);
for (iv = 0; iv < rng->Points; iv++)
{
/* we'll now retrieve coordinates for each vertex */
gaiaGetPoint (rng->Coords, iv, &x, &y);
printf ("\t\t\t\t\tvertex %d/%d x=%1.4f y=%1.4f\n",
iv, rng->Points, x, y);
}

for (ir = 0; ir < pg->NumInteriors; ir++)
{
/*
a POLYGON can contain an arbitrary number of Interior rings (including zero)
*/
rng = pg->Interiors + ir;
printf ("\t\t\t\tInteriorRing %d/%d has %d vertices\n",
ir, pg->NumInteriors, rng->Points);
for (iv = 0; iv < rng->Points; iv++)
{
/* we'll now retrieve coordinates for each vertex */
gaiaGetPoint (rng->Coords, iv, &x, &y);
printf
("\t\t\t\t\tvertex %d/%d x=%1.4f y=%1.4f\n",
iv, rng->Points, x, y);
}
}

cnt++;
pg = pg->Next;
}
}
}

int
main (int argc, char *argv[])
{
gaiaGeomCollPtr geo_pt = NULL;
gaiaGeomCollPtr geo_ln = NULL;
gaiaGeomCollPtr geo_pg = NULL;
gaiaGeomCollPtr geo_mpt = NULL;
gaiaGeomCollPtr geo_mln = NULL;
gaiaGeomCollPtr geo_mpg = NULL;
gaiaGeomCollPtr geo_coll = NULL;
gaiaLinestringPtr line;
gaiaPolygonPtr polyg;
gaiaRingPtr ring;
gaiaOutBuffer wkt;
int ret;
sqlite3 *handle;

/*

this demo does not strictly require any DB connection to be established

However you must initialize the SpatiaLite extension [and related]
and you *must* establish a "fake" DB connection in order to
properly initialize SpatiaLite and GEOS libraries

*/
spatialite_init (0);
ret = sqlite3_open_v2 (":memory:", &handle, SQLITE_OPEN_READONLY, NULL);
if (ret != SQLITE_OK)
{
printf ("cannot open '%s': %s\n", ":memory:",
sqlite3_errmsg (handle));
sqlite3_close (handle);
return -1;
}

#ifndef OMIT_GEOS               /* GEOS must be enabled */

/*
Step #1
creating and checking a POINT Geometry
*/

/* we'll allocate a Geometry object */
geo_pt = gaiaAllocGeomColl ();
/* then we insert a POINT, directly passing its coordinates */
/* now we'll print the main attributes for this geometry */
printf ("step#1: %s\t\tDimension=%d IsValid=%d\n",
geom_type (gaiaGeometryType (geo_pt)),
geometry_printout (geo_pt);

/*
Step #2
creating and checking a LINESTRING Geometry
*/
geo_ln = gaiaAllocGeomColl ();
/* then we insert a  LINESTRING, specifying how many vertices it contains */
/*
we've got a pointer referencing the linestring we've just inserted
now we'll set coordinates for each vertex
*/
gaiaSetPoint (line->Coords, 0, 1.0, 1.0);
gaiaSetPoint (line->Coords, 1, 2.0, 1.0);
gaiaSetPoint (line->Coords, 2, 2.0, 2.0);
gaiaSetPoint (line->Coords, 3, 100.0, 2.0);
gaiaSetPoint (line->Coords, 4, 100.0, 100.0);

printf ("\nstep#2: %s\tDimension=%d IsValid=%d\n",
geom_type (gaiaGeometryType (geo_ln)),
geometry_printout (geo_ln);

/*
Step #3
creating and checking a POLYGON Geometry
*/
geo_pg = gaiaAllocGeomColl ();
/*
then we insert a  POLYGON, specifying:
- how many vertices have to be allocated for the Exterior Ring
- how many Interior Rings it has
*/
polyg = gaiaAddPolygonToGeomColl (geo_pg, 5, 2);
/*
we've got a pointer referencing the polygon we've just inserted
now we'll get a pointer referencing its Exterior ring
*/
ring = polyg->Exterior;

/* now we'll set coordinates for each Exterior ring vertex */
gaiaSetPoint (ring->Coords, 0, 0.0, 0.0);
gaiaSetPoint (ring->Coords, 1, 50.0, 0.0);
gaiaSetPoint (ring->Coords, 2, 50.0, 50.0);
gaiaSetPoint (ring->Coords, 3, 0.0, 50.0);
/* please note: a Ring is a CLOSED figure, so last and first vertex have to be coincident */
gaiaSetPoint (ring->Coords, 4, 0.0, 0.0);

/*
we'll now get a pointer referencing the FIRST interior ring,
specifying how vertices have to be allocated
*/
ring = gaiaAddInteriorRing (polyg, 0, 5);
/* then setting coordinates for each Interior ring vertex */
gaiaSetPoint (ring->Coords, 0, 40.0, 40.0);
gaiaSetPoint (ring->Coords, 1, 41.0, 40.0);
gaiaSetPoint (ring->Coords, 2, 41.0, 41.0);
gaiaSetPoint (ring->Coords, 3, 40.0, 41.0);
gaiaSetPoint (ring->Coords, 4, 40.0, 40.0);

/*
we'll now get a pointer referencing the SECOND interior ring,
specifying how vertices have to be allocated
*/
ring = gaiaAddInteriorRing (polyg, 1, 5);
/* then setting coordinates for each Interior ring vertex */
gaiaSetPoint (ring->Coords, 0, 30.0, 30.0);
gaiaSetPoint (ring->Coords, 1, 31.0, 30.0);
gaiaSetPoint (ring->Coords, 2, 31.0, 31.0);
gaiaSetPoint (ring->Coords, 3, 30.0, 31.0);
gaiaSetPoint (ring->Coords, 4, 30.0, 30.0);

printf ("\nstep#3: %s\tDimension=%d IsValid=%d\n",
geom_type (gaiaGeometryType (geo_pg)),
geometry_printout (geo_pg);

/*
Step #4
creating and checking a MULTIPOINT Geometry
*/
geo_mpt = gaiaAllocGeomColl ();
/* then we'll insert some POINTs */
printf ("\nstep#4: %s\tDimension=%d IsValid=%d\n",
geom_type (gaiaGeometryType (geo_mpt)),
geometry_printout (geo_mpt);

/*
Step #5
creating and checking a MULTILINESTRING Geometry
*/
geo_mln = gaiaAllocGeomColl ();

/* then we'll insert two LINESTRINGs */
gaiaSetPoint (line->Coords, 0, 30.0, 10.0);
gaiaSetPoint (line->Coords, 1, 10.0, 30.0);

gaiaSetPoint (line->Coords, 0, 40.0, 50.0);
gaiaSetPoint (line->Coords, 1, 50.0, 40.0);

printf ("\nstep#5: %s\tDimension=%d IsValid=%d\n",
geom_type (gaiaGeometryType (geo_mln)),
geometry_printout (geo_mln);

/*
Step #6
creating and checking a MULTIPOLYGON Geometry
*/
geo_mpg = gaiaAllocGeomColl ();

/* then we'll insert two POLYGONs */
polyg = gaiaAddPolygonToGeomColl (geo_mpg, 5, 0);
ring = polyg->Exterior;
gaiaSetPoint (ring->Coords, 0, 60.0, 60.0);
gaiaSetPoint (ring->Coords, 1, 70.0, 60.0);
gaiaSetPoint (ring->Coords, 2, 70.0, 70.0);
gaiaSetPoint (ring->Coords, 3, 60.0, 70.0);
gaiaSetPoint (ring->Coords, 4, 60.0, 60.0);

polyg = gaiaAddPolygonToGeomColl (geo_mpg, 5, 0);
ring = polyg->Exterior;
gaiaSetPoint (ring->Coords, 0, 80.0, 80.0);
gaiaSetPoint (ring->Coords, 1, 90.0, 80.0);
gaiaSetPoint (ring->Coords, 2, 90.0, 90.0);
gaiaSetPoint (ring->Coords, 3, 80.0, 90.0);
gaiaSetPoint (ring->Coords, 4, 80.0, 80.0);

printf ("\nstep#6: %s\tDimension=%d IsValid=%d\n",
geom_type (gaiaGeometryType (geo_mpg)),
geometry_printout (geo_mpg);

/*
Step #7
creating and checking a GEOMETRYCOLLECTION Geometry
*/
geo_coll = gaiaAllocGeomColl ();

/* then we'll insert two POINTs */

/* then we'll insert two LINESTRINGs */
gaiaSetPoint (line->Coords, 0, 130.0, 110.0);
gaiaSetPoint (line->Coords, 1, 110.0, 130.0);

gaiaSetPoint (line->Coords, 0, 140.0, 150.0);
gaiaSetPoint (line->Coords, 1, 150.0, 140.0);

/* then we'll insert two POLYGONs */
polyg = gaiaAddPolygonToGeomColl (geo_coll, 5, 0);
ring = polyg->Exterior;
gaiaSetPoint (ring->Coords, 0, 160.0, 160.0);
gaiaSetPoint (ring->Coords, 1, 170.0, 160.0);
gaiaSetPoint (ring->Coords, 2, 170.0, 170.0);
gaiaSetPoint (ring->Coords, 3, 160.0, 170.0);
gaiaSetPoint (ring->Coords, 4, 160.0, 160.0);

polyg = gaiaAddPolygonToGeomColl (geo_coll, 5, 0);
ring = polyg->Exterior;
gaiaSetPoint (ring->Coords, 0, 180.0, 180.0);
gaiaSetPoint (ring->Coords, 1, 190.0, 180.0);
gaiaSetPoint (ring->Coords, 2, 190.0, 190.0);
gaiaSetPoint (ring->Coords, 3, 180.0, 190.0);
gaiaSetPoint (ring->Coords, 4, 180.0, 180.0);

printf ("\nstep#7: %s\tDimension=%d IsValid=%d\n",
geom_type (gaiaGeometryType (geo_coll)),
geometry_printout (geo_coll);

/*
Step #8
printing each geometry as Well Known Text (WKT)
*/

printf ("\nstep#8: checking WKT representations\n");

/* first we'll get the WKT corresponding to geometry */
gaiaOutBufferInitialize (&wkt);
gaiaOutWkt (&wkt, geo_pt);
/* we have to check wkt is not NULL */
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
/* printing the WKT */
printf ("\n%s\n", wkt.Buffer);

/* finally freeing the wkt temporary storage allocation */
gaiaOutBufferReset (&wkt);
}

gaiaOutBufferInitialize (&wkt);
gaiaOutWkt (&wkt, geo_ln);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf ("\n%s\n", wkt.Buffer);
gaiaOutBufferReset (&wkt);
}

gaiaOutBufferInitialize (&wkt);
gaiaOutWkt (&wkt, geo_pg);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf ("\n%s\n", wkt.Buffer);
gaiaOutBufferReset (&wkt);
}

gaiaOutBufferInitialize (&wkt);
gaiaOutWkt (&wkt, geo_mpt);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf ("\n%s\n", wkt.Buffer);
gaiaOutBufferReset (&wkt);
}

gaiaOutBufferInitialize (&wkt);
gaiaOutWkt (&wkt, geo_mln);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf ("\n%s\n", wkt.Buffer);
gaiaOutBufferReset (&wkt);
}

gaiaOutBufferInitialize (&wkt);
gaiaOutWkt (&wkt, geo_mpg);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf ("\n%s\n", wkt.Buffer);
gaiaOutBufferReset (&wkt);
}

gaiaOutBufferInitialize (&wkt);
gaiaOutWkt (&wkt, geo_coll);
if (wkt.Error == 0 && wkt.Buffer != NULL)
{
printf ("\n%s\n", wkt.Buffer);
gaiaOutBufferReset (&wkt);
}

#else
printf ("no GEOS support available: skipping any test\n");
#endif /* GEOS enabled/disabled */

/*
memory cleanup
we have to destroy each object using temporary storage before exit
*/
if (geo_pt)
gaiaFreeGeomColl (geo_pt);
if (geo_ln)
gaiaFreeGeomColl (geo_ln);
if (geo_pg)
gaiaFreeGeomColl (geo_pg);
if (geo_mpt)
gaiaFreeGeomColl (geo_mpt);
if (geo_mln)
gaiaFreeGeomColl (geo_mln);
if (geo_mpg)
gaiaFreeGeomColl (geo_mpg);
if (geo_coll)
gaiaFreeGeomColl (geo_coll);
sqlite3_close (handle);
return 0;
}
```