SlideShare a Scribd company logo
1 of 46
Download to read offline
GEOGRAPHIC SCRIPTING IN GVSIG
HALFWAY BETWEEN USER AND DEVELOPER
Geoinformation Research Group,
Department of Geography
University of Potsdam
21-25 November 2016
Andrea Antonello
PART 4: GEOGRAPHIC SCRIPTING
GEO-SCRIPTING IN GVSIG
In gvSIG geographic scripting is done using the Python programming
language syntax (the actual engine is called Jython).
As proposed when creating a new script, most geo-related operations are
done using the gvsig module. Also, a main method needs to be defined, for
the script to work:
import gvsig
def main(*args):
# do some scripting here
GEO-SCRIPTING IN GVSIG
gvSIG imports will be used in several ways throughout the course, mostly
because the way one uses imports depends on what he/she is writing...
and also in order to make you better understand how things work.
Let's see an example of two different ways to handle imports:
from gvsig import *
from gvsig.geom import *
def main(*args):
point = createPoint(D2, 30, 10)
print "Point: ", point
project = currentProject()
print "Project name: ", project.name
import gvsig
from gvsig import geom
def main(*args):
point = geom.createPoint(geom.D2, 30, 10)
print "Point: ", point
project = gvsig.currentProject()
print "Project name: ", project.name
BUILDING GEOMETRIES
Geometries can be built through the use of their constructors, which is
the usual way to create geometries programmatically:
# build 2D geometries by constructor
# simple geometries
# point
point = geom.createPoint(geom.D2, 30, 10)
print point
# line
line = geom.createLine(geom.D2, [(30,10), (10,30), (20,40), (40,40)])
print line.convertToWKT()
# but also using points already created
line = geom.createLine(geom.D2, [point, (10,30), (20,40), (40,40)])
print line.convertToWKT()
# polygon
polygon = geom.createPolygon(geom.D2, [[35,10],[10,20],[15,40],[45,45],[35,10]])
print polygon.convertToWKT()
BUILDING GEOMETRIES
The same applies to the multi-geometries:
# multi-geometries
# multipoint
p1 = geom.createPoint(geom.D2, 10,40)
p2 = geom.createPoint(geom.D2, 40,30)
p3 = geom.createPoint(geom.D2, 20,20)
p4 = geom.createPoint(geom.D2, 30,10)
multiPoint = geom.createMultiPoint(points=[p1, p2, p3, p4])
print multiPoint.convertToWKT()
# multiline
l1 = geom.createLine(geom.D2, [(10,10),(20,20),(10,40)])
l2 = geom.createLine(geom.D2, [(40,40),(30,30),(40,20),(30,10)])
multiline = geom.createMultiLine()
multiline.addCurve(l1)
multiline.addCurve(l2)
# for multipolygons the same approach as with lines can be used
BUILDING GEOMETRIES
Also the well known text (WKT) representation can be used:
# build geometries by wkt
# simple
g = geom.createGeometryFromWKT("POINT (30 10)")
print "POINT: " + g.convertToWKT()
g = geom.createGeometryFromWKT("LINESTRING (30 10, 10 30, 20 40, 40 40)")
print "LINESTRING: " + g.convertToWKT()
g = geom.createGeometryFromWKT("POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))")
print "POLYGON: " + g.convertToWKT()
g = geom.createGeometryFromWKT("POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10), " +
"(20 30, 35 35, 30 20, 20 30))")
print "POLYGON: " + g.convertToWKT()
g = geom.createGeometryFromWKT("MULTIPOINT (10 40, 40 30, 20 20, 30 10)")
# multi
print "MULTIPOINT: " + g.convertToWKT()
g = geom.createGeometryFromWKT("MULTILINESTRING ((10 10, 20 20, 10 40), " +
"(40 40, 30 30, 40 20, 30 10))")
print "MULTILINESTRING: " + g.convertToWKT()
g = geom.createGeometryFromWKT("MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), " +
"((15 5, 40 10, 10 20, 5 10, 15 5)))")
print "MULTIPOLYGON: " + g.convertToWKT()
BUILDING GEOMETRIES
If the geometries are 2D simplified constructors are available:
# for 2D geometries a simpler constructor can be used
# point
point = geom.createPoint2D(30, 10)
print point
# as opposed to a 4D point
point3DM = geom.createPoint(geom.D3M,30,10,1005,23)
print point3DM.convertToWKT()
# line
line = geom.createLine2D([(30,10), (10,30), (20,40), (40,40)])
print line.convertToWKT()
# polygon
polygon = geom.createPolygon2D([[35,10],[10,20],[15,40],[45,45],[35,10]])
print polygon.convertToWKT()
A TEST SET OF GEOMETRIES TO USE AS REFERENCE
To better explain the various functions and predicates we will start by
creating a set of geometries on which to apply the operations.
You are now able to create the following points, line and polygons:
0
5
0 5
g1
g5
g2
g3
g4
g6
BUILDING GEOMETRIES
In order to visualize intermediate results we will create a view document
(the map view) and make it active. Geometries will be loaded on top of it.
Let's create the example dataset, using wildcards for imports in order to
have a more readable code:
from gvsig import *
from gvsig.geom import *
def main(*args):
# build the example dataset
g1 = createGeometryFromWKT("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))")
g2 = createGeometryFromWKT("POLYGON ((5 0, 5 2, 7 2, 7 0, 5 0))")
g3 = createGeometryFromWKT("POINT (4 1)")
g4 = createGeometryFromWKT("POINT (5 4)")
g5 = createGeometryFromWKT("LINESTRING (1 0, 1 6)")
g6 = createGeometryFromWKT("POLYGON ((3 3, 3 6, 6 6, 6 3, 3 3))")
And now that it is build, how do we check if it is correct?
BUILDING GEOMETRIES
We can exploit the map view to check geometries:
# get the current active view
view = currentView()
# create an envelope containing our
# geometries
bbox = createEnvelope([-4,-4],[10,10])
# zoom to the envelope
view.centerView(bbox)
# get the view's graphics layer and
# draw the geometries
gr = view.getGraphicsLayer()
gr.clearAllGraphics()
c1 = getColorFromRGB(255, 0, 0, 128)
g1Sym = simplePolygonSymbol(c1)
idG1 = gr.addSymbol(g1Sym)
gr.addGraphic("g1", g1, idG1, "g1")
c2 = getColorFromRGB(255, 255, 0, 128)
g2Sym = simplePolygonSymbol(c2)
idG2 = gr.addSymbol(g2Sym)
gr.addGraphic("g2", g2, idG2, "g2")
c3 = getColorFromRGB(0, 255, 0, 128)
g3Sym = simplePointSymbol(c3)
g3Sym.setSize(10)
idG3 = gr.addSymbol(g3Sym)
gr.addGraphic("g3", g3, idG3, "g3")
c4 = getColorFromRGB(0, 255, 0, 128)
g4Sym = simplePointSymbol(c4)
g4Sym.setSize(10)
idG4 = gr.addSymbol(g4Sym)
gr.addGraphic("g4", g4, idG4, "g4")
c5 = getColorFromRGB(0, 255, 255, 128)
g5Sym = simpleLineSymbol(c5)
g5Sym.setLineWidth(3)
idG5 = gr.addSymbol(g5Sym)
gr.addGraphic("g5", g5, idG5, "g5")
c6 = getColorFromRGB(0, 0, 255, 128)
g6Sym = simplePolygonSymbol(c6)
idG6 = gr.addSymbol(g6Sym)
gr.addGraphic("g6", g6, idG6, "g6")
# refresh the view
view.getMapContext().invalidate()
BUILDING GEOMETRIES
The graphics layer is a layer that can be used to draw on top of the map
layers. If we have the countries layer loaded, and execute the script, we
should see some shapes appear near the equator (this is true only if the
view has been created with CRS EPSG:4326, which is the default for the
new map views) :
PREDICATES
INTERSECTS
Let's see which geometries intersect with g1 and print the result:
print g1.intersects(g2) # True
print g1.intersects(g3) # True
print g1.intersects(g4) # True
print g1.intersects(g5) # True
print g1.intersects(g6) # True
Note that geometries that touch (like g1 and g2) also intersect.
TOUCHES
Let's see which geometries touch with g1 and print the result:
print g1.touches(g2) # True
print g1.touches(g3) # False
print g1.touches(g4) # True
print g1.touches(g5) # False
print g1.touches(g6) # False
PREDICATES
CONTAINS
Let's see which geometries are contained in g1 and print the result:
print g1.contains(g2) # False
print g1.contains(g3) # True
print g1.contains(g4) # False
print g1.contains(g5) # False
print g1.contains(g6) # False
Mind that a point on the border is not contained, so only g3 is contained.
This can be solved through the covers predicate.
COVERS
print g1.covers(g2) # False
print g1.covers(g3) # True
print g1.covers(g4) # True
print g1.covers(g5) # False
print g1.covers(g6) # False
FUNCTIONS: INTERSECTION
Let's see which geometries are contained in g1 and print the result:
# the intersection of polygons returns a polygon
g1_inter_g6 = g1.intersection(g6)
print g1_inter_g6
# the intersection of touching polygons returns a line
print g1.intersection(g2)
# the intersection of a polygon with a point is a point
print g1.intersection(g3)
# the intersection of a polygon with a line is a point
print g1.intersection(g5)
# view the intersection of g1 and g6
gr.clearAllGraphics()
c = getColorFromRGB(255, 0, 0, 128)
gSym = simplePolygonSymbol(c)
idG = gr.addSymbol(gSym)
gr.addGraphic("g", g1, idG, "g")
c = getColorFromRGB(0, 0, 255, 128)
gSym = simplePolygonSymbol(c)
idG = gr.addSymbol(gSym)
gr.addGraphic("g", g6, idG, "g")
c = getColorFromRGB(0, 255, 0, 128)
gSym = simplePolygonSymbol(c)
idG = gr.addSymbol(gSym)
gr.addGraphic("g", g1_inter_g6, idG, "g")
0
5
0 5
g1
g5
g2
g3
g4
g6
FUNCTIONS: SYMDIFFERENCE
What is the resulting geometry of the symdifference (portions not shared)
of different geometry types?
# the symDifference of intersecting polygons returns a multipolygon
g1jts = g1.getJTS()
symDiff16 = g1jts.symDifference(g6.getJTS())
print symDiff16
# but the symDifference of touching polygons returns the polygons union
print g1jts.symDifference(g2.getJTS())
# the symDifference of a polygon with a contained point returns the original polygon
print g1jts.symDifference(g3.getJTS())
# the symDifference of a polygon with a line is a hybrid collection (line + polygon)
print g1jts.symDifference(g5.getJTS())
# to get back a gvsig geometry
multiPolygon2d = createGeometryFromWKT(symDiff16)
print multiPolygon2d
0
5
0 5
g1
g5
g2
g3
g4
g6
Note that the symDifference is not implemented
in gvSIG. In that case it is possible to access
directly the JTS geometries and use the function
on those. Afterwards through the WKT
definition they can be converted back.
FUNCTIONS: UNION
What is the resulting geometry of the union of different geometry types?
# the union of intersecting polygons returns a polygon
print g1.union(g6).convertToWKT()
# same as the union of touching polygons
print g1.union(g2).convertToWKT()
# the union of a polygon with a contained point returns the original polygon
print g1.union(g3).convertToWKT()
# the union of a polygon with a line doesn't result in a valid geometry
print g1.union(g5)
The following shows the union of
polygons g1 and g6:
0
5
0 5
g1
g5
g2
g3
g4
g6
FUNCTIONS: DIFFERENCE
The difference of geometries obviously depends on the calling object:
# this returns g1 minus the overlapping part of g6
print g1.difference(g6).convertToWKT()
# while this returns g6 minus the overlapping part of g1
print g6.difference(g1).convertToWKT()
# in the case of difference with lines, the result is the original polygon
# with additional points in the intersections
print g1.difference(g5).convertToWKT()
# the difference of polygon and point is the original polygon
print g1.difference(g3).convertToWKT()
The following shows the difference
of polygons g1 and g6:
0
5
0 5
g1
g5
g2
g3
g4
g6
JTS GEOMETRIES
Some functions are not supported in the gvSIG scripting API. But it is
possible to access the underlying JTS geometries.
JTS stands for , the most well known spatial
predicates and geometry processing library available in the open source
panorama.
This is how to get back and forth between gvSIG and JTS:
Java Topology Suite
# create a gvsig geometry
polygonGvsig = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))")
# get the JTS geometry
polygonJTS = polygonGvsig.getJTS()
# do some advanced processing... for example get the centroid
centroidJTS = polygonJTS.getCentroid();
# print the gvsig geometry
print "gvSIG polygon WKT: " + polygonGvsig.convertToWKT()
# print the JTS geometry
print "JTS polygon WKT: %s" % polygonJTS
# get back to a gvsig geometry
centroidGvsig = createGeometryFromWKT(centroidJTS)
print "gvSIG centroid WKT: " + centroidGvsig.convertToWKT()
FUNCTIONS: BUFFER
Creating a buffer around a geometry always generates a polygon
geometry. The behavior can be tweaked, depending on the geometry type:
from com.vividsolutions.jts.operation.buffer import BufferParameters
g3jts = g3.getJTS()
g5jts = g5.getJTS()
# the buffer of a point
b1 = g3jts.buffer(1.0)
# the buffer of a point with few quandrant segments
b2 = g3jts.buffer(1.0, 1)
# round end cap style, few points
b3 = g5jts.buffer(1.0, 2, BufferParameters.CAP_ROUND)
# round end cap style, more points
b4 = g5jts.buffer(1.0, 10, BufferParameters.CAP_ROUND)
# square end cap style
b5 = g5jts.buffer(1.0, -1, BufferParameters.CAP_SQUARE)
# flat end cap style
b6 = g5jts.buffer(1.0, -1, BufferParameters.CAP_FLAT)
geoms = [b1, b2, b3, b4, b5, b6]
gr.clearAllGraphics()
c = getColorFromRGB(255, 0, 0, 80)
gSym = simplePolygonSymbol(c)
idG = gr.addSymbol(gSym)
for g in geoms:
gr.addGraphic("g", createGeometryFromWKT(g.toText()), idG, "g")
JTS gives more control
about buffering, it just
requires us to import the
BufferParameters module.
FUNCTIONS IN JTS: CONVEXHULL
Some functions are not available through the gvSIG API. We saw this
already in the buffer functions and symDifference. Another example is the
convex hull.
So let's try working the JTS way. First, we create the geometries as JTS
geometries:
# build the example dataset
g1 = createGeometryFromWKT("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))").getJTS()
g2 = createGeometryFromWKT("POLYGON ((5 0, 5 2, 7 2, 7 0, 5 0))").getJTS()
g3 = createGeometryFromWKT("POINT (4 1)").getJTS()
g4 = createGeometryFromWKT("POINT (5 4)").getJTS()
g5 = createGeometryFromWKT("LINESTRING (1 0, 1 6)").getJTS()
g6 = createGeometryFromWKT("POLYGON ((3 3, 3 6, 6 6, 6 3, 3 3))").getJTS()
geoms = [g1, g2, g3, g4, g5, g6]
FUNCTIONS IN JTS: CONVEXHULL
Once we have the geometries, we need to create a collection of
geometries, which will require us to import a few classes.
from com.vividsolutions.jts.geom import GeometryCollection, GeometryFactory
gc = GeometryCollection(geoms, GeometryFactory())
with a GeometryCollection it is very simple to create a convex hull and
visualize it:
convexHull = gc.convexHull()
gr = view.getGraphicsLayer()
gr.clearAllGraphics()
c = getColorFromRGB(255, 0, 0, 80)
gSym = simplePolygonSymbol(c)
idG = gr.addSymbol(gSym)
for g in geoms:
gr.addGraphic("g", createGeometryFromWKT(convexHull.toText()), idG, "g")
view.getMapContext().invalidate()
FUNCTIONS IN JTS: TRANSFORMATIONS
Also for operations of translation, scaling and rotation we can make use of
the JTS capabilities.
It all boils down to a single class, the AffineTransformation, which we can
import as:
from com.vividsolutions.jts.geom.util import AffineTransformation as AT
import math # used for conversion to radians
It has direct methods to access to the different transformations:
# create the jts polygon
square = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))")
square = square.getJTS()
# this is how affine transformations are created
scaleAffineTransformation = AT.scaleInstance(4,4)
translationAffineTransformation = AT.translationInstance(2,2)
rotationAffineTransformation = AT.rotationInstance(math.radians(45))
shearAffineTransformation = AT.shearInstance(0.75, 0)
# this is how transformations are applied to geometries
scaledSquare = scaleAffineTransformation.transform(square)
print "Original: %s" % square
print "Scaled: %s" % scaledSquare
FUNCTIONS IN JTS: TRANSFORMATIONSLet's see how all the transformations work:
square = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))").getJTS()
# scale the square by 4 times
squareLarge = AT.scaleInstance(4,4).transform(square)
# move it by x, y units
squareTranslate = AT.translationInstance(2,2).transform(square)
# move it and then rotate it by 45 degrees
squareTranslateRotate = AT.rotationInstance(math.radians(45)
).transform(squareTranslate)
# realize that the order of things are there for a reason
squareRotate = AT.rotationInstance(math.radians(45)).transform(square)
squareRotateTranslate = AT.translationInstance(2,2).transform(squareRotate)
# rotate around a defined center
squareTranslateRotateCenter = AT.rotationInstance(math.radians(45),
2.5, 2.5).transform(squareTranslate)
# shear the square
squareShear = AT.shearInstance(0.75,0).transform(square)
geoms = [square, squareLarge, squareTranslate,
squareTranslateRotate, squareRotateTranslate,
squareTranslateRotateCenter, squareShear]
view = currentView()
gr = view.getGraphicsLayer()
gr.clearAllGraphics()
c = getColorFromRGB(255, 0, 0, 80)
gSym = simplePolygonSymbol(c)
idG = gr.addSymbol(gSym)
for g in geoms:
gr.addGraphic("g", createGeometryFromWKT(g), idG, "g")
view.mapContext.invalidate()
PROJECTIONS
Geometries can be reprojected directly using the crs objects. These can
be created in several ways. The simplest is through the use of the EPSG
code:
from gvsig import *
from gvsig.geom import *
def main(*args):
# create the source and destination crs
# usign the EPSG codes
crs1 = getCRS('EPSG:4326')
crs2 = getCRS('EPSG:32632')
# get the transformation object
transform = crs1.getCT(crs2)
# reproject a point from 4326 to 32632
point = createPoint2D(11, 46)
print "Original point in lat/long: " + str(point)
point.reProject(transform)
print "and the reprojected point: " + str(point)
# get the WKT representation of the crs object
print crs2.getWKT()
PROJECTIONS
Sometimes it is necessary to modify the crs definition. If you load the data
in a GIS and they do not appear where they should, it might be a problem
of the false easting, but also the units might not be right.
PROJCS["WGS 84 / UTM zone 32N",
GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
UNIT["degree", 0.017453292519943295],
AXIS["Longitude", EAST],
AXIS["Latitude", NORTH],
AUTHORITY["EPSG","4326"]],
PROJECTION["Transverse_Mercator"],
PARAMETER["central_meridian", 9.0],
PARAMETER["latitude_of_origin", 0.0],
PARAMETER["scale_factor", 0.9996],
PARAMETER["false_easting", 500000.0], # sometimes a different false easting is used
PARAMETER["false_northing", 0.0],
UNIT["m", 1.0], # sometimes millimeters are used, with scale 0.001
AXIS["Easting", EAST],
AXIS["Northing", NORTH],
AUTHORITY["EPSG","32632"]]
PROJECTIONS
Converting from WKT to a crs is only an import statement away:
from org.gvsig.fmap.crs import CRSFactory
factory = CRSFactory.getCRSFactory()
prjWkt = """PROJCS["WGS 84 / UTM zone 32N",
GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
UNIT["degree", 0.017453292519943295],
AXIS["Longitude", EAST],
AXIS["Latitude", NORTH],
AUTHORITY["EPSG","4326"]],
PROJECTION["Transverse_Mercator"],
PARAMETER["central_meridian", 9.0],
PARAMETER["latitude_of_origin", 0.0],
PARAMETER["scale_factor", 0.9996],
PARAMETER["false_easting", 500000.0],
PARAMETER["false_northing", 0.0],
UNIT["m", 1.0],
AXIS["Easting", EAST],
AXIS["Northing", NORTH],
AUTHORITY["EPSG","32632"]]
"""
crs2 = factory.get("wkt", prjWkt)
CREATING THE FIRST SHAPEFILE
When we talk about "writing GIS stuff", we are usually talking about
creating a shapefile. Let's see the steps to create our first shapefile:
# place here the usual imports and main definition
# create the blueprint of the shapefile
schema = createFeatureType()
schema.append("name", "STRING", 20)
schema.append("GEOMETRY", "GEOMETRY")
schema.get("GEOMETRY").setGeometryType(POINT, D2)
# create the shapefile
shape = createShape(schema, CRS="EPSG:4326")
# edit the shapefile and add features
shape.edit()
point1 = createPoint2D(-122.42, 37.78)
shape.append(name='San Francisco', GEOMETRY=point1)
point2 = createPoint2D(-73.98, 40.47)
shape.append(name='New York', GEOMETRY=point2)
shape.commit()
# add the shapefile as layer to the view
currentView().addLayer(shape)
# print the path of the shapefile
print "path: ", shape.getDataStore().getFullName()
CREATING THE FIRST SHAPEFILE
Let's see a slightly more complex example:
# place here the usual imports and main definition
# create the blueprint of the shapefile
schema = createFeatureType()
schema.append("name", "STRING", 20)
schema.append("population", "INTEGER", 4)
schema.append("lat", "DOUBLE", 8)
schema.append("lon", "DOUBLE", 8)
schema.append("GEOMETRY", "GEOMETRY")
schema.get("GEOMETRY").setGeometryType(POINT, D2)
# create the shapefile
shape = createShape(schema, prefixname="complex", CRS="EPSG:4326")
# edit the shapefile and add features
shape.edit()
point = createPoint2D(-73.98, 40.47)
shape.append(name='New York',population=19040000,
lat=40.749979064, lon=-73.9800169288,
GEOMETRY=point)
shape.commit()
# add the shapefile as layer to the view
currentView().addLayer(shape)
CREATING THE FIRST SHAPEFILE
Once the scripts are run, you should see the following in the map view:
BUILD A VIEW AND LOAD DATALet's start from scratch and go through the whole process again.
1) imports
# the most used imports are...
from gvsig import *
from gvsig.geom import *
2) create the data blueprint
# define a working crs
epsg = "EPSG:4326"
# create the blueprint of the shapefile
schema = createFeatureType()
schema.append("name", "STRING", 20)
schema.append("GEOMETRY", "GEOMETRY")
schema.get("GEOMETRY").setGeometryType(POINT, D2)
# create the shapefile
shape = createShape(schema, prefixname="simple", CRS=epsg)
# edit the shapefile and add a feature
shape.edit()
x = -122.42
y = 37.78
point = createPoint2D(x, y)
shape.append(name='New York', GEOMETRY=point)
shape.commit()
3) create some data
BUILD A VIEW AND LOAD DATA
3) load an external shapefile into a layer
# first add some background shp
background = loadLayer("Shape",
shpFile="/home/hydrologis/data/natural_earth/ne_10m_admin_0_countries.shp",
CRS=epsg)
4) create a new map view with name and crs and load the layers into it
# zoom to the feature
boxDelta = 0.05
newview.centerView(createEnvelope([x-boxDelta,y-boxDelta],[x+boxDelta,y+boxDelta]))
5) zoom to the created feature
# create a new view and set its projection
newview = currentProject().createView("Example view")
newview.setProjection(getCRS(epsg))
newview.addLayer(background)
newview.addLayer(shape)
newview.showWindow()
INVESTIGATING A VECTOR LAYER
Let's see how accessing views and layers is done...
# define view and layer to investigate
viewName = "Example view"
layerName = "ne_10m_admin_0_countries"
# get the view and layers
view = currentProject().getView(viewName)
if view is None:
print "ERROR: view ", viewName, " is not available in the current project"
return
layers = view.getLayers()
# pick the right layer
layerToRead = None
print "Iterate through the layers: "
for layer in layers:
print "tLayer: ", layer.getName()
if layer.getName() == layerName:
layerToRead = layer
INVESTIGATING A VECTOR LAYER
...and what about the layer's schema content?
# investigate its schema
if layerToRead is not None:
schema = layerToRead.getSchema()
# show the attributes
attrSchema = schema.getAttrNames()
print "nnSchema attr: ", attrSchema
print "nnFields description"
for field in schema:
print " Name: ", field.getName(),
print " tDataTypeName: ", field.getDataTypeName(),
print " tPrecision: ", field.getPrecision(),
print " tSize: ", field.getSize()
if field.getDataTypeName() == 'Geometry':
geomType = field.getGeomType()
print " tGeom Name: ", geomType.getName()
print " tGeom FullName: ", geomType.getFullName()
print " tDimension: ", geomType.getDimension()
else:
print "ERROR: layer ", layerName, " is not available in view: ", viewName
INVESTIGATING A VECTOR LAYER
...and what about the data?
# define view and layer to investigate
viewName = "Example view"
layerName = "ne_10m_admin_0_countries"
# get the view
view = currentProject().getView(viewName)
# get the layer by its name
layer = view.getLayer(layerName)
# get the features set
features = layer.features()
print "Features available in layer: ", features.getSize()
# loop through the features
for feature in features:
print feature.getValues()
INVESTIGATING A VECTOR LAYER
How to access the feature attributes:
layer = currentView().getLayer("ne_10m_admin_0_countries")
features = layer.features()
for feature in features:
print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants."
It is possible to get only the features selected by the user with:
features = layer.getSelection()
INVESTIGATING A VECTOR LAYER
Features can be extracted from a layer by means of filters and sorted by a
given attribute.
Extract the population less than 1000 and major than 0, in ascending
order:
layer = currentView().getLayer("ne_10m_admin_0_countries")
features = layer.features("POP_EST < 1000 and POP_EST > 0", sortby="POP_EST", asc=True)
for feature in features:
print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants."
And here a simple way to get the country with largest population:
features = layer.features(sortby="POP_EST", asc=False)
for feature in features:
print "The country with most inhabitants is ", feature.NAME , " with ", feature.POP_EST
break
SELECT FEATURES IN A VECTOR LAYER
Features can be selected or deselected in a view/layer using the selection
object of the layer.
Example: select an print the countries with more than 1E9 inhabitants
# select features
selection = layer.getSelection()
selection.deselectAll()
features = layer.features("POP_EST > 1E9")
for feature in features:
selection.select(feature)
print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants."
selection.deselect(feature)
Single features can be removed from the selection through:
CREATE A COUNTRIES CENTROIDS LAYER
It is no rocket science to apply all we have seen until this point to create a
shapefile containing the centroids of the countries.
All you need to know is that the geometry has a method that extracts the
centroid for you: centroid
countriesLayer = currentView().getLayer("ne_10m_admin_0_countries")
shpPath = "/home/hydrologis/TMP/centroids.shp"
epsg = "EPSG:4326"
schema = createFeatureType()
schema.append("name", "STRING", 20)
schema.append("GEOMETRY", "GEOMETRY")
schema.get("GEOMETRY").setGeometryType(POINT, D2)
shape = createShape(schema, filename=shpPath, CRS=epsg)
shape.edit()
countries = countriesLayer.features()
for country in countries:
geometry = country.GEOMETRY
centroid = geometry.centroid()
shape.append(name=country.NAME, GEOMETRY=centroid)
shape.commit()
currentView().addLayer(shape)
STYLING YOUR LAYERS
Let's see how styling of the different feature/geometries types is done.
To do so, we first load a layer of each type: point, line, polygon
basePath = "/home/hydrologis/data/natural_earth/"
countries = basePath + "ne_10m_admin_0_countries.shp"
places = basePath + "ne_10m_populated_places.shp"
roads = basePath + "ne_10m_roads.shp"
# create a new view and set its projection
epsg = "EPSG:4326"
newview = currentProject().createView("Example view")
newview.setProjection(getCRS(epsg))
newview.showWindow()
countriesLayer = loadLayer("Shape", shpFile=countries, CRS=epsg)
placesLayer = loadLayer("Shape", shpFile=places, CRS=epsg)
roadsLayer = loadLayer("Shape", shpFile=roads, CRS=epsg)
newview.addLayer(countriesLayer)
newview.addLayer(roadsLayer)
newview.addLayer(placesLayer)
SIMPLE STYLING OF POINTS
Styling of shapes is done by creating a symbol and set it in the layer's
legend:
# get the layer's legend
pointsLegend = placesLayer.getLegend()
# create and modify the symbol
pointSymbol = simplePointSymbol()
pointSymbol.setSize(15);
pointSymbol.setColor(getColorFromRGB(0,0,255,128)); # blue
pointSymbol.setOutlined(True);
pointSymbol.setOutlineColor(getColorFromRGB(255,255,0)); # yellow
pointSymbol.setOutlineSize(1);
# circle = 0; square = 1; cross = 2; diamond = 3; X = 4; triangle = 5; star = 6; vertical line = 7;
pointSymbol.setStyle(5);
# set symbol to legend and legend to layer
pointsLegend.setDefaultSymbol(pointSymbol)
placesLayer.setLegend(pointsLegend)
# then zoom
x = 11
y = 46
boxDelta = 2
newview.centerView(createEnvelope([x-boxDelta,y-boxDelta],[x+boxDelta,y+boxDelta]))
SIMPLE STYLING OF LINES
Styling of lines is similar to that of points:
lineSymbol = simpleLineSymbol()
lineSymbol.setLineWidth(2);
lineSymbol.setLineColor(getColorFromRGB(128,128,128));
linesLegend = roadsLayer.getLegend()
linesLegend.setDefaultSymbol(lineSymbol)
roadsLayer.setLegend(linesLegend)
While styling of polygons is done in two steps: outline and fill
# first create the outline symbol and style it
polygonOutlineSymbol = simpleLineSymbol()
polygonOutlineSymbol.setLineWidth(2)
polygonOutlineSymbol.setLineColor(getColorFromRGB(255,0,0))
# then the fill
polygonFillSymbol = simplePolygonSymbol()
polygonFillSymbol.setOutline(polygonOutlineSymbol)
polygonFillSymbol.setFillColor(getColorFromRGB(255,0,0,70))
polygonLegend = countriesLayer.getLegend()
polygonLegend.setDefaultSymbol(polygonFillSymbol)
countriesLayer.setLegend(polygonLegend)
SIMPLE STYLING OF POLYGONS
Once run, the script should create a new view that looks like:
HOW TO REUSE CODE?
Often pieces of code are repeated for different variables and could be
reused. This can be easily done with functions. Functions are defined
using the "def" construct.
The following is a simple example that shows how one can use a function
to set the symbol in the layer's legend, using one line instead of repeating
three lines for each layer:
def setSymbolInLayer(symbol, layer):
legend = layer.getLegend()
legend.setDefaultSymbol(symbol)
layer.setLegend(legend)
SIMPLE STYLING OF POLYGONS
It is also possible to style using a color-ramp based on an attribute of the
layer. In that case it will be necessary to add one import:
from org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl import VectorialIntervalLegend
Then, using the interval legend, it is quite straight forward:
# create an interval legend
intervalLegend = VectorialIntervalLegend(POLYGON)
intervalLegend.setStartColor(Color.gray)
intervalLegend.setEndColor(Color.red)
intervalLegend.setIntervalType(1) # natural = 1, quantile = 2
store = countriesLayer.getFeatureStore()
# calculate the intervals using the field name and the desired number of intervals
intervals = intervalLegend.calculateIntervals(store, "POP_EST", 5, POLYGON)
intervalLegend.setIntervals(intervals)
countriesLayer.setLegend(intervalLegend)
SIMPLE STYLING OF POLYGONS
...which the should look like a choropleth map:
<license>
This work is released under Creative Commons Attribution Share Alike (CC-BY-SA).
</license>
<sources>
Much of the knowledge needed to create this training material has been produced
by the sparkling knights of the
<a href="http:www.osgeo.org">Osgeo</a>,
<a href="http://tsusiatsoftware.net/">JTS</a>,
<a href="http://www.jgrasstools.org">JGrasstools</a> and
<a href="http:www.gvsig.org">gvSIG</a> communities.
Their websites are filled up with learning material that can be use to grow
knowledge beyond the boundaries of this set of tutorials.
Another essential source has been the Wikipedia project.
</sources>
<acknowledgments>
Particular thanks go to those friends that directly or indirectly helped out in
the creation and review of this series of handbooks.
Thanks to Antonio Falciano for proofreading the course and Oscar Martinez for the
documentation about gvSIG scripting.
</acknowledgments>
<footer>
This tutorial is brought to you by <a href="http:www.hydrologis.com">HydroloGIS</a>.
<footer>

More Related Content

What's hot

Xi CBSE Computer Science lab programs
Xi CBSE Computer Science lab programsXi CBSE Computer Science lab programs
Xi CBSE Computer Science lab programsProf. Dr. K. Adisesha
 
Chapter 8 c solution
Chapter 8 c solutionChapter 8 c solution
Chapter 8 c solutionAzhar Javed
 
Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014Pebble Technology
 
Data Structure in C Programming Language
Data Structure in C Programming LanguageData Structure in C Programming Language
Data Structure in C Programming LanguageArkadeep Dey
 
Let us C (by yashvant Kanetkar) chapter 3 Solution
Let us C   (by yashvant Kanetkar) chapter 3 SolutionLet us C   (by yashvant Kanetkar) chapter 3 Solution
Let us C (by yashvant Kanetkar) chapter 3 SolutionHazrat Bilal
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheetDr. Volkan OBAN
 
Generic Functional Programming with Type Classes
Generic Functional Programming with Type ClassesGeneric Functional Programming with Type Classes
Generic Functional Programming with Type ClassesTapio Rautonen
 
COMPUTER SCIENCE CLASS 12 PRACTICAL FILE
COMPUTER SCIENCE CLASS 12 PRACTICAL FILECOMPUTER SCIENCE CLASS 12 PRACTICAL FILE
COMPUTER SCIENCE CLASS 12 PRACTICAL FILEAnushka Rai
 
Basic c programs updated on 31.8.2020
Basic c programs updated on 31.8.2020Basic c programs updated on 31.8.2020
Basic c programs updated on 31.8.2020vrgokila
 
R Programming: Numeric Functions In R
R Programming: Numeric Functions In RR Programming: Numeric Functions In R
R Programming: Numeric Functions In RRsquared Academy
 
C programs Set 2
C programs Set 2C programs Set 2
C programs Set 2Koshy Geoji
 
A Beginners Guide to Weather & Climate Data, Margriet Groenendijk
A Beginners Guide to Weather & Climate Data, Margriet GroenendijkA Beginners Guide to Weather & Climate Data, Margriet Groenendijk
A Beginners Guide to Weather & Climate Data, Margriet GroenendijkPôle Systematic Paris-Region
 
Numerical analysis
Numerical analysisNumerical analysis
Numerical analysisVishal Singh
 
Console programms
Console programmsConsole programms
Console programmsYasir Khan
 

What's hot (20)

Cs practical file
Cs practical fileCs practical file
Cs practical file
 
Xi CBSE Computer Science lab programs
Xi CBSE Computer Science lab programsXi CBSE Computer Science lab programs
Xi CBSE Computer Science lab programs
 
Chapter 8 c solution
Chapter 8 c solutionChapter 8 c solution
Chapter 8 c solution
 
Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014Advanced Techniques: Graphics | Pebble Developer Retreat 2014
Advanced Techniques: Graphics | Pebble Developer Retreat 2014
 
Data Structure in C Programming Language
Data Structure in C Programming LanguageData Structure in C Programming Language
Data Structure in C Programming Language
 
Let us C (by yashvant Kanetkar) chapter 3 Solution
Let us C   (by yashvant Kanetkar) chapter 3 SolutionLet us C   (by yashvant Kanetkar) chapter 3 Solution
Let us C (by yashvant Kanetkar) chapter 3 Solution
 
Hive function-cheat-sheet
Hive function-cheat-sheetHive function-cheat-sheet
Hive function-cheat-sheet
 
Code optimization
Code optimization Code optimization
Code optimization
 
Generic Functional Programming with Type Classes
Generic Functional Programming with Type ClassesGeneric Functional Programming with Type Classes
Generic Functional Programming with Type Classes
 
COMPUTER SCIENCE CLASS 12 PRACTICAL FILE
COMPUTER SCIENCE CLASS 12 PRACTICAL FILECOMPUTER SCIENCE CLASS 12 PRACTICAL FILE
COMPUTER SCIENCE CLASS 12 PRACTICAL FILE
 
Basic c programs updated on 31.8.2020
Basic c programs updated on 31.8.2020Basic c programs updated on 31.8.2020
Basic c programs updated on 31.8.2020
 
Stl algorithm-Basic types
Stl algorithm-Basic typesStl algorithm-Basic types
Stl algorithm-Basic types
 
R Programming: Numeric Functions In R
R Programming: Numeric Functions In RR Programming: Numeric Functions In R
R Programming: Numeric Functions In R
 
C programs Set 2
C programs Set 2C programs Set 2
C programs Set 2
 
C- Programming Assignment 3
C- Programming Assignment 3C- Programming Assignment 3
C- Programming Assignment 3
 
R basic programs
R basic programsR basic programs
R basic programs
 
A Beginners Guide to Weather & Climate Data, Margriet Groenendijk
A Beginners Guide to Weather & Climate Data, Margriet GroenendijkA Beginners Guide to Weather & Climate Data, Margriet Groenendijk
A Beginners Guide to Weather & Climate Data, Margriet Groenendijk
 
Numerical analysis
Numerical analysisNumerical analysis
Numerical analysis
 
Vb.net programs
Vb.net programsVb.net programs
Vb.net programs
 
Console programms
Console programmsConsole programms
Console programms
 

Similar to PART 4: GEOGRAPHIC SCRIPTING

Opensource gis development - part 3
Opensource gis development - part 3Opensource gis development - part 3
Opensource gis development - part 3Andrea Antonello
 
GeoScript - Spatial Capabilities for Scripting Languages
GeoScript - Spatial Capabilities for Scripting LanguagesGeoScript - Spatial Capabilities for Scripting Languages
GeoScript - Spatial Capabilities for Scripting LanguagesJustin Deoliveira
 
The graph above is just an example that shows the differences in dis.pdf
The graph above is just an example that shows the differences in dis.pdfThe graph above is just an example that shows the differences in dis.pdf
The graph above is just an example that shows the differences in dis.pdfjyothimuppasani1
 
implement the following funtions. myg1 and myg2 are seperate. x and .pdf
implement the following funtions. myg1 and myg2 are seperate. x and .pdfimplement the following funtions. myg1 and myg2 are seperate. x and .pdf
implement the following funtions. myg1 and myg2 are seperate. x and .pdfforladies
 
bfd23fd7-0d89-45c0-8b82-c991b30ed375.pdf
bfd23fd7-0d89-45c0-8b82-c991b30ed375.pdfbfd23fd7-0d89-45c0-8b82-c991b30ed375.pdf
bfd23fd7-0d89-45c0-8b82-c991b30ed375.pdfshehabhamad_90
 
04 Geographic scripting in uDig - halfway between user and developer
04 Geographic scripting in uDig - halfway between user and developer04 Geographic scripting in uDig - halfway between user and developer
04 Geographic scripting in uDig - halfway between user and developerAndrea Antonello
 
Computer graphics lab assignment
Computer graphics lab assignmentComputer graphics lab assignment
Computer graphics lab assignmentAbdullah Al Shiam
 
Introduction To PostGIS
Introduction To PostGISIntroduction To PostGIS
Introduction To PostGISmleslie
 
Computer graphics
Computer graphicsComputer graphics
Computer graphicsamitsarda3
 
OpenGL L07-Skybox and Terrian
OpenGL L07-Skybox and TerrianOpenGL L07-Skybox and Terrian
OpenGL L07-Skybox and TerrianMohammad Shaker
 
Data visualization using the grammar of graphics
Data visualization using the grammar of graphicsData visualization using the grammar of graphics
Data visualization using the grammar of graphicsRupak Roy
 
PyDX Presentation about Python, GeoData and Maps
PyDX Presentation about Python, GeoData and MapsPyDX Presentation about Python, GeoData and Maps
PyDX Presentation about Python, GeoData and MapsHannes Hapke
 
Loom & Functional Graphs in Clojure @ LambdaConf 2015
Loom & Functional Graphs in Clojure @ LambdaConf 2015Loom & Functional Graphs in Clojure @ LambdaConf 2015
Loom & Functional Graphs in Clojure @ LambdaConf 2015Aysylu Greenberg
 
Go generics. what is this fuzz about?
Go generics. what is this fuzz about?Go generics. what is this fuzz about?
Go generics. what is this fuzz about?Gabriel Habryn
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2goMoriyoshi Koizumi
 
Getting more out of Matplotlib with GR
Getting more out of Matplotlib with GRGetting more out of Matplotlib with GR
Getting more out of Matplotlib with GRJosef Heinen
 

Similar to PART 4: GEOGRAPHIC SCRIPTING (20)

Opensource gis development - part 3
Opensource gis development - part 3Opensource gis development - part 3
Opensource gis development - part 3
 
GeoScript - Spatial Capabilities for Scripting Languages
GeoScript - Spatial Capabilities for Scripting LanguagesGeoScript - Spatial Capabilities for Scripting Languages
GeoScript - Spatial Capabilities for Scripting Languages
 
The graph above is just an example that shows the differences in dis.pdf
The graph above is just an example that shows the differences in dis.pdfThe graph above is just an example that shows the differences in dis.pdf
The graph above is just an example that shows the differences in dis.pdf
 
implement the following funtions. myg1 and myg2 are seperate. x and .pdf
implement the following funtions. myg1 and myg2 are seperate. x and .pdfimplement the following funtions. myg1 and myg2 are seperate. x and .pdf
implement the following funtions. myg1 and myg2 are seperate. x and .pdf
 
bfd23fd7-0d89-45c0-8b82-c991b30ed375.pdf
bfd23fd7-0d89-45c0-8b82-c991b30ed375.pdfbfd23fd7-0d89-45c0-8b82-c991b30ed375.pdf
bfd23fd7-0d89-45c0-8b82-c991b30ed375.pdf
 
04 Geographic scripting in uDig - halfway between user and developer
04 Geographic scripting in uDig - halfway between user and developer04 Geographic scripting in uDig - halfway between user and developer
04 Geographic scripting in uDig - halfway between user and developer
 
Computer graphics lab assignment
Computer graphics lab assignmentComputer graphics lab assignment
Computer graphics lab assignment
 
Introduction To PostGIS
Introduction To PostGISIntroduction To PostGIS
Introduction To PostGIS
 
Computer graphics
Computer graphicsComputer graphics
Computer graphics
 
Drawing Figures
Drawing FiguresDrawing Figures
Drawing Figures
 
OpenGL L07-Skybox and Terrian
OpenGL L07-Skybox and TerrianOpenGL L07-Skybox and Terrian
OpenGL L07-Skybox and Terrian
 
Data visualization using the grammar of graphics
Data visualization using the grammar of graphicsData visualization using the grammar of graphics
Data visualization using the grammar of graphics
 
PyDX Presentation about Python, GeoData and Maps
PyDX Presentation about Python, GeoData and MapsPyDX Presentation about Python, GeoData and Maps
PyDX Presentation about Python, GeoData and Maps
 
Python gis
Python gisPython gis
Python gis
 
Loom & Functional Graphs in Clojure @ LambdaConf 2015
Loom & Functional Graphs in Clojure @ LambdaConf 2015Loom & Functional Graphs in Clojure @ LambdaConf 2015
Loom & Functional Graphs in Clojure @ LambdaConf 2015
 
Go generics. what is this fuzz about?
Go generics. what is this fuzz about?Go generics. what is this fuzz about?
Go generics. what is this fuzz about?
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2go
 
Getting more out of Matplotlib with GR
Getting more out of Matplotlib with GRGetting more out of Matplotlib with GR
Getting more out of Matplotlib with GR
 
7. chapter vi
7. chapter vi7. chapter vi
7. chapter vi
 
Introduction to graphics programming in c
Introduction to graphics programming in cIntroduction to graphics programming in c
Introduction to graphics programming in c
 

More from Andrea Antonello

Smash & Geopaparazzi - State of the art 2021
Smash & Geopaparazzi - State of the art 2021Smash & Geopaparazzi - State of the art 2021
Smash & Geopaparazzi - State of the art 2021Andrea Antonello
 
GEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATIONGEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATIONAndrea Antonello
 
GEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATIONGEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATIONAndrea Antonello
 
Geopaparazzi Survey Server workshop
Geopaparazzi Survey Server workshopGeopaparazzi Survey Server workshop
Geopaparazzi Survey Server workshopAndrea Antonello
 
Geopaparazzi Survey Server Installation
Geopaparazzi Survey Server InstallationGeopaparazzi Survey Server Installation
Geopaparazzi Survey Server InstallationAndrea Antonello
 
Modelling natural hazards in gvSIG with the HortonMachine plugins
Modelling natural hazards in gvSIG with the HortonMachine pluginsModelling natural hazards in gvSIG with the HortonMachine plugins
Modelling natural hazards in gvSIG with the HortonMachine pluginsAndrea Antonello
 
GEOPAPARAZZI: STATE OF THE ART
GEOPAPARAZZI: STATE OF THE ARTGEOPAPARAZZI: STATE OF THE ART
GEOPAPARAZZI: STATE OF THE ARTAndrea Antonello
 
Geopaparazzi - NEVER OUT OF DATA IN THE FIELD
Geopaparazzi - NEVER OUT OF DATA IN THE FIELDGeopaparazzi - NEVER OUT OF DATA IN THE FIELD
Geopaparazzi - NEVER OUT OF DATA IN THE FIELDAndrea Antonello
 
The HortonMachine, for data analysis to help scientists... and not only
The HortonMachine, for data analysis to help scientists... and not onlyThe HortonMachine, for data analysis to help scientists... and not only
The HortonMachine, for data analysis to help scientists... and not onlyAndrea Antonello
 
Geopaparazzi & gvSIG Mobile - state of the art
Geopaparazzi & gvSIG Mobile - state of the artGeopaparazzi & gvSIG Mobile - state of the art
Geopaparazzi & gvSIG Mobile - state of the artAndrea Antonello
 
Foss4g2016 Geopaparazzi Workshop
Foss4g2016 Geopaparazzi WorkshopFoss4g2016 Geopaparazzi Workshop
Foss4g2016 Geopaparazzi WorkshopAndrea Antonello
 
New tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIG
New tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIGNew tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIG
New tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIGAndrea Antonello
 
Digital field mapping with Geopaparazzi and gvSIG
Digital field mapping with Geopaparazzi and gvSIGDigital field mapping with Geopaparazzi and gvSIG
Digital field mapping with Geopaparazzi and gvSIGAndrea Antonello
 
Geopaparazzi, history of a digital mapping kid
Geopaparazzi, history of a digital mapping kidGeopaparazzi, history of a digital mapping kid
Geopaparazzi, history of a digital mapping kidAndrea Antonello
 
Geopaparazzi, state of the art
Geopaparazzi, state of the artGeopaparazzi, state of the art
Geopaparazzi, state of the artAndrea Antonello
 
Geographic scripting in uDig
Geographic scripting in uDigGeographic scripting in uDig
Geographic scripting in uDigAndrea Antonello
 
LESTO - a GIS toolbox for LiDAR empowered sciences
LESTO - a GIS toolbox for LiDAR empowered sciencesLESTO - a GIS toolbox for LiDAR empowered sciences
LESTO - a GIS toolbox for LiDAR empowered sciencesAndrea Antonello
 
03 Geographic scripting in uDig - halfway between user and developer
03 Geographic scripting in uDig - halfway between user and developer03 Geographic scripting in uDig - halfway between user and developer
03 Geographic scripting in uDig - halfway between user and developerAndrea Antonello
 
02 Geographic scripting in uDig - halfway between user and developer
02 Geographic scripting in uDig - halfway between user and developer02 Geographic scripting in uDig - halfway between user and developer
02 Geographic scripting in uDig - halfway between user and developerAndrea Antonello
 
05 Geographic scripting in uDig - halfway between user and developer
05 Geographic scripting in uDig - halfway between user and developer05 Geographic scripting in uDig - halfway between user and developer
05 Geographic scripting in uDig - halfway between user and developerAndrea Antonello
 

More from Andrea Antonello (20)

Smash & Geopaparazzi - State of the art 2021
Smash & Geopaparazzi - State of the art 2021Smash & Geopaparazzi - State of the art 2021
Smash & Geopaparazzi - State of the art 2021
 
GEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATIONGEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI: STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
 
GEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATIONGEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
GEOPAPARAZZI STATE OF THE ART OF THE DIGITAL FIELD MAPPING APPLICATION
 
Geopaparazzi Survey Server workshop
Geopaparazzi Survey Server workshopGeopaparazzi Survey Server workshop
Geopaparazzi Survey Server workshop
 
Geopaparazzi Survey Server Installation
Geopaparazzi Survey Server InstallationGeopaparazzi Survey Server Installation
Geopaparazzi Survey Server Installation
 
Modelling natural hazards in gvSIG with the HortonMachine plugins
Modelling natural hazards in gvSIG with the HortonMachine pluginsModelling natural hazards in gvSIG with the HortonMachine plugins
Modelling natural hazards in gvSIG with the HortonMachine plugins
 
GEOPAPARAZZI: STATE OF THE ART
GEOPAPARAZZI: STATE OF THE ARTGEOPAPARAZZI: STATE OF THE ART
GEOPAPARAZZI: STATE OF THE ART
 
Geopaparazzi - NEVER OUT OF DATA IN THE FIELD
Geopaparazzi - NEVER OUT OF DATA IN THE FIELDGeopaparazzi - NEVER OUT OF DATA IN THE FIELD
Geopaparazzi - NEVER OUT OF DATA IN THE FIELD
 
The HortonMachine, for data analysis to help scientists... and not only
The HortonMachine, for data analysis to help scientists... and not onlyThe HortonMachine, for data analysis to help scientists... and not only
The HortonMachine, for data analysis to help scientists... and not only
 
Geopaparazzi & gvSIG Mobile - state of the art
Geopaparazzi & gvSIG Mobile - state of the artGeopaparazzi & gvSIG Mobile - state of the art
Geopaparazzi & gvSIG Mobile - state of the art
 
Foss4g2016 Geopaparazzi Workshop
Foss4g2016 Geopaparazzi WorkshopFoss4g2016 Geopaparazzi Workshop
Foss4g2016 Geopaparazzi Workshop
 
New tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIG
New tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIGNew tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIG
New tools for LiDAR, forestry, river management and hydro-geomorphology in gvSIG
 
Digital field mapping with Geopaparazzi and gvSIG
Digital field mapping with Geopaparazzi and gvSIGDigital field mapping with Geopaparazzi and gvSIG
Digital field mapping with Geopaparazzi and gvSIG
 
Geopaparazzi, history of a digital mapping kid
Geopaparazzi, history of a digital mapping kidGeopaparazzi, history of a digital mapping kid
Geopaparazzi, history of a digital mapping kid
 
Geopaparazzi, state of the art
Geopaparazzi, state of the artGeopaparazzi, state of the art
Geopaparazzi, state of the art
 
Geographic scripting in uDig
Geographic scripting in uDigGeographic scripting in uDig
Geographic scripting in uDig
 
LESTO - a GIS toolbox for LiDAR empowered sciences
LESTO - a GIS toolbox for LiDAR empowered sciencesLESTO - a GIS toolbox for LiDAR empowered sciences
LESTO - a GIS toolbox for LiDAR empowered sciences
 
03 Geographic scripting in uDig - halfway between user and developer
03 Geographic scripting in uDig - halfway between user and developer03 Geographic scripting in uDig - halfway between user and developer
03 Geographic scripting in uDig - halfway between user and developer
 
02 Geographic scripting in uDig - halfway between user and developer
02 Geographic scripting in uDig - halfway between user and developer02 Geographic scripting in uDig - halfway between user and developer
02 Geographic scripting in uDig - halfway between user and developer
 
05 Geographic scripting in uDig - halfway between user and developer
05 Geographic scripting in uDig - halfway between user and developer05 Geographic scripting in uDig - halfway between user and developer
05 Geographic scripting in uDig - halfway between user and developer
 

Recently uploaded

"Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ..."Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ...Erbil Polytechnic University
 
Comprehensive energy systems.pdf Comprehensive energy systems.pdf
Comprehensive energy systems.pdf Comprehensive energy systems.pdfComprehensive energy systems.pdf Comprehensive energy systems.pdf
Comprehensive energy systems.pdf Comprehensive energy systems.pdfalene1
 
Katarzyna Lipka-Sidor - BIM School Course
Katarzyna Lipka-Sidor - BIM School CourseKatarzyna Lipka-Sidor - BIM School Course
Katarzyna Lipka-Sidor - BIM School Coursebim.edu.pl
 
US Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of ActionUS Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of ActionMebane Rash
 
2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.
2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.
2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.elesangwon
 
11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdf11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdfHafizMudaserAhmad
 
Engineering Drawing section of solid
Engineering Drawing     section of solidEngineering Drawing     section of solid
Engineering Drawing section of solidnamansinghjarodiya
 
Ch10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdfCh10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdfChristianCDAM
 
OOP concepts -in-Python programming language
OOP concepts -in-Python programming languageOOP concepts -in-Python programming language
OOP concepts -in-Python programming languageSmritiSharma901052
 
Turn leadership mistakes into a better future.pptx
Turn leadership mistakes into a better future.pptxTurn leadership mistakes into a better future.pptx
Turn leadership mistakes into a better future.pptxStephen Sitton
 
CME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTES
CME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTESCME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTES
CME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTESkarthi keyan
 
Module-1-(Building Acoustics) Noise Control (Unit-3). pdf
Module-1-(Building Acoustics) Noise Control (Unit-3). pdfModule-1-(Building Acoustics) Noise Control (Unit-3). pdf
Module-1-(Building Acoustics) Noise Control (Unit-3). pdfManish Kumar
 
SOFTWARE ESTIMATION COCOMO AND FP CALCULATION
SOFTWARE ESTIMATION COCOMO AND FP CALCULATIONSOFTWARE ESTIMATION COCOMO AND FP CALCULATION
SOFTWARE ESTIMATION COCOMO AND FP CALCULATIONSneha Padhiar
 
multiple access in wireless communication
multiple access in wireless communicationmultiple access in wireless communication
multiple access in wireless communicationpanditadesh123
 
Python Programming for basic beginners.pptx
Python Programming for basic beginners.pptxPython Programming for basic beginners.pptx
Python Programming for basic beginners.pptxmohitesoham12
 
Mine Environment II Lab_MI10448MI__________.pptx
Mine Environment II Lab_MI10448MI__________.pptxMine Environment II Lab_MI10448MI__________.pptx
Mine Environment II Lab_MI10448MI__________.pptxRomil Mishra
 
Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________Romil Mishra
 
DEVICE DRIVERS AND INTERRUPTS SERVICE MECHANISM.pdf
DEVICE DRIVERS AND INTERRUPTS  SERVICE MECHANISM.pdfDEVICE DRIVERS AND INTERRUPTS  SERVICE MECHANISM.pdf
DEVICE DRIVERS AND INTERRUPTS SERVICE MECHANISM.pdfAkritiPradhan2
 
THE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTION
THE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTIONTHE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTION
THE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTIONjhunlian
 

Recently uploaded (20)

"Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ..."Exploring the Essential Functions and Design Considerations of Spillways in ...
"Exploring the Essential Functions and Design Considerations of Spillways in ...
 
Designing pile caps according to ACI 318-19.pptx
Designing pile caps according to ACI 318-19.pptxDesigning pile caps according to ACI 318-19.pptx
Designing pile caps according to ACI 318-19.pptx
 
Comprehensive energy systems.pdf Comprehensive energy systems.pdf
Comprehensive energy systems.pdf Comprehensive energy systems.pdfComprehensive energy systems.pdf Comprehensive energy systems.pdf
Comprehensive energy systems.pdf Comprehensive energy systems.pdf
 
Katarzyna Lipka-Sidor - BIM School Course
Katarzyna Lipka-Sidor - BIM School CourseKatarzyna Lipka-Sidor - BIM School Course
Katarzyna Lipka-Sidor - BIM School Course
 
US Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of ActionUS Department of Education FAFSA Week of Action
US Department of Education FAFSA Week of Action
 
2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.
2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.
2022 AWS DNA Hackathon 장애 대응 솔루션 jarvis.
 
11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdf11. Properties of Liquid Fuels in Energy Engineering.pdf
11. Properties of Liquid Fuels in Energy Engineering.pdf
 
Engineering Drawing section of solid
Engineering Drawing     section of solidEngineering Drawing     section of solid
Engineering Drawing section of solid
 
Ch10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdfCh10-Global Supply Chain - Cadena de Suministro.pdf
Ch10-Global Supply Chain - Cadena de Suministro.pdf
 
OOP concepts -in-Python programming language
OOP concepts -in-Python programming languageOOP concepts -in-Python programming language
OOP concepts -in-Python programming language
 
Turn leadership mistakes into a better future.pptx
Turn leadership mistakes into a better future.pptxTurn leadership mistakes into a better future.pptx
Turn leadership mistakes into a better future.pptx
 
CME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTES
CME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTESCME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTES
CME 397 - SURFACE ENGINEERING - UNIT 1 FULL NOTES
 
Module-1-(Building Acoustics) Noise Control (Unit-3). pdf
Module-1-(Building Acoustics) Noise Control (Unit-3). pdfModule-1-(Building Acoustics) Noise Control (Unit-3). pdf
Module-1-(Building Acoustics) Noise Control (Unit-3). pdf
 
SOFTWARE ESTIMATION COCOMO AND FP CALCULATION
SOFTWARE ESTIMATION COCOMO AND FP CALCULATIONSOFTWARE ESTIMATION COCOMO AND FP CALCULATION
SOFTWARE ESTIMATION COCOMO AND FP CALCULATION
 
multiple access in wireless communication
multiple access in wireless communicationmultiple access in wireless communication
multiple access in wireless communication
 
Python Programming for basic beginners.pptx
Python Programming for basic beginners.pptxPython Programming for basic beginners.pptx
Python Programming for basic beginners.pptx
 
Mine Environment II Lab_MI10448MI__________.pptx
Mine Environment II Lab_MI10448MI__________.pptxMine Environment II Lab_MI10448MI__________.pptx
Mine Environment II Lab_MI10448MI__________.pptx
 
Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________Gravity concentration_MI20612MI_________
Gravity concentration_MI20612MI_________
 
DEVICE DRIVERS AND INTERRUPTS SERVICE MECHANISM.pdf
DEVICE DRIVERS AND INTERRUPTS  SERVICE MECHANISM.pdfDEVICE DRIVERS AND INTERRUPTS  SERVICE MECHANISM.pdf
DEVICE DRIVERS AND INTERRUPTS SERVICE MECHANISM.pdf
 
THE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTION
THE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTIONTHE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTION
THE SENDAI FRAMEWORK FOR DISASTER RISK REDUCTION
 

PART 4: GEOGRAPHIC SCRIPTING

  • 1. GEOGRAPHIC SCRIPTING IN GVSIG HALFWAY BETWEEN USER AND DEVELOPER Geoinformation Research Group, Department of Geography University of Potsdam 21-25 November 2016 Andrea Antonello PART 4: GEOGRAPHIC SCRIPTING
  • 2. GEO-SCRIPTING IN GVSIG In gvSIG geographic scripting is done using the Python programming language syntax (the actual engine is called Jython). As proposed when creating a new script, most geo-related operations are done using the gvsig module. Also, a main method needs to be defined, for the script to work: import gvsig def main(*args): # do some scripting here
  • 3. GEO-SCRIPTING IN GVSIG gvSIG imports will be used in several ways throughout the course, mostly because the way one uses imports depends on what he/she is writing... and also in order to make you better understand how things work. Let's see an example of two different ways to handle imports: from gvsig import * from gvsig.geom import * def main(*args): point = createPoint(D2, 30, 10) print "Point: ", point project = currentProject() print "Project name: ", project.name import gvsig from gvsig import geom def main(*args): point = geom.createPoint(geom.D2, 30, 10) print "Point: ", point project = gvsig.currentProject() print "Project name: ", project.name
  • 4. BUILDING GEOMETRIES Geometries can be built through the use of their constructors, which is the usual way to create geometries programmatically: # build 2D geometries by constructor # simple geometries # point point = geom.createPoint(geom.D2, 30, 10) print point # line line = geom.createLine(geom.D2, [(30,10), (10,30), (20,40), (40,40)]) print line.convertToWKT() # but also using points already created line = geom.createLine(geom.D2, [point, (10,30), (20,40), (40,40)]) print line.convertToWKT() # polygon polygon = geom.createPolygon(geom.D2, [[35,10],[10,20],[15,40],[45,45],[35,10]]) print polygon.convertToWKT()
  • 5. BUILDING GEOMETRIES The same applies to the multi-geometries: # multi-geometries # multipoint p1 = geom.createPoint(geom.D2, 10,40) p2 = geom.createPoint(geom.D2, 40,30) p3 = geom.createPoint(geom.D2, 20,20) p4 = geom.createPoint(geom.D2, 30,10) multiPoint = geom.createMultiPoint(points=[p1, p2, p3, p4]) print multiPoint.convertToWKT() # multiline l1 = geom.createLine(geom.D2, [(10,10),(20,20),(10,40)]) l2 = geom.createLine(geom.D2, [(40,40),(30,30),(40,20),(30,10)]) multiline = geom.createMultiLine() multiline.addCurve(l1) multiline.addCurve(l2) # for multipolygons the same approach as with lines can be used
  • 6. BUILDING GEOMETRIES Also the well known text (WKT) representation can be used: # build geometries by wkt # simple g = geom.createGeometryFromWKT("POINT (30 10)") print "POINT: " + g.convertToWKT() g = geom.createGeometryFromWKT("LINESTRING (30 10, 10 30, 20 40, 40 40)") print "LINESTRING: " + g.convertToWKT() g = geom.createGeometryFromWKT("POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))") print "POLYGON: " + g.convertToWKT() g = geom.createGeometryFromWKT("POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10), " + "(20 30, 35 35, 30 20, 20 30))") print "POLYGON: " + g.convertToWKT() g = geom.createGeometryFromWKT("MULTIPOINT (10 40, 40 30, 20 20, 30 10)") # multi print "MULTIPOINT: " + g.convertToWKT() g = geom.createGeometryFromWKT("MULTILINESTRING ((10 10, 20 20, 10 40), " + "(40 40, 30 30, 40 20, 30 10))") print "MULTILINESTRING: " + g.convertToWKT() g = geom.createGeometryFromWKT("MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), " + "((15 5, 40 10, 10 20, 5 10, 15 5)))") print "MULTIPOLYGON: " + g.convertToWKT()
  • 7. BUILDING GEOMETRIES If the geometries are 2D simplified constructors are available: # for 2D geometries a simpler constructor can be used # point point = geom.createPoint2D(30, 10) print point # as opposed to a 4D point point3DM = geom.createPoint(geom.D3M,30,10,1005,23) print point3DM.convertToWKT() # line line = geom.createLine2D([(30,10), (10,30), (20,40), (40,40)]) print line.convertToWKT() # polygon polygon = geom.createPolygon2D([[35,10],[10,20],[15,40],[45,45],[35,10]]) print polygon.convertToWKT()
  • 8. A TEST SET OF GEOMETRIES TO USE AS REFERENCE To better explain the various functions and predicates we will start by creating a set of geometries on which to apply the operations. You are now able to create the following points, line and polygons: 0 5 0 5 g1 g5 g2 g3 g4 g6
  • 9. BUILDING GEOMETRIES In order to visualize intermediate results we will create a view document (the map view) and make it active. Geometries will be loaded on top of it. Let's create the example dataset, using wildcards for imports in order to have a more readable code: from gvsig import * from gvsig.geom import * def main(*args): # build the example dataset g1 = createGeometryFromWKT("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))") g2 = createGeometryFromWKT("POLYGON ((5 0, 5 2, 7 2, 7 0, 5 0))") g3 = createGeometryFromWKT("POINT (4 1)") g4 = createGeometryFromWKT("POINT (5 4)") g5 = createGeometryFromWKT("LINESTRING (1 0, 1 6)") g6 = createGeometryFromWKT("POLYGON ((3 3, 3 6, 6 6, 6 3, 3 3))") And now that it is build, how do we check if it is correct?
  • 10. BUILDING GEOMETRIES We can exploit the map view to check geometries: # get the current active view view = currentView() # create an envelope containing our # geometries bbox = createEnvelope([-4,-4],[10,10]) # zoom to the envelope view.centerView(bbox) # get the view's graphics layer and # draw the geometries gr = view.getGraphicsLayer() gr.clearAllGraphics() c1 = getColorFromRGB(255, 0, 0, 128) g1Sym = simplePolygonSymbol(c1) idG1 = gr.addSymbol(g1Sym) gr.addGraphic("g1", g1, idG1, "g1") c2 = getColorFromRGB(255, 255, 0, 128) g2Sym = simplePolygonSymbol(c2) idG2 = gr.addSymbol(g2Sym) gr.addGraphic("g2", g2, idG2, "g2") c3 = getColorFromRGB(0, 255, 0, 128) g3Sym = simplePointSymbol(c3) g3Sym.setSize(10) idG3 = gr.addSymbol(g3Sym) gr.addGraphic("g3", g3, idG3, "g3") c4 = getColorFromRGB(0, 255, 0, 128) g4Sym = simplePointSymbol(c4) g4Sym.setSize(10) idG4 = gr.addSymbol(g4Sym) gr.addGraphic("g4", g4, idG4, "g4") c5 = getColorFromRGB(0, 255, 255, 128) g5Sym = simpleLineSymbol(c5) g5Sym.setLineWidth(3) idG5 = gr.addSymbol(g5Sym) gr.addGraphic("g5", g5, idG5, "g5") c6 = getColorFromRGB(0, 0, 255, 128) g6Sym = simplePolygonSymbol(c6) idG6 = gr.addSymbol(g6Sym) gr.addGraphic("g6", g6, idG6, "g6") # refresh the view view.getMapContext().invalidate()
  • 11. BUILDING GEOMETRIES The graphics layer is a layer that can be used to draw on top of the map layers. If we have the countries layer loaded, and execute the script, we should see some shapes appear near the equator (this is true only if the view has been created with CRS EPSG:4326, which is the default for the new map views) :
  • 12. PREDICATES INTERSECTS Let's see which geometries intersect with g1 and print the result: print g1.intersects(g2) # True print g1.intersects(g3) # True print g1.intersects(g4) # True print g1.intersects(g5) # True print g1.intersects(g6) # True Note that geometries that touch (like g1 and g2) also intersect. TOUCHES Let's see which geometries touch with g1 and print the result: print g1.touches(g2) # True print g1.touches(g3) # False print g1.touches(g4) # True print g1.touches(g5) # False print g1.touches(g6) # False
  • 13. PREDICATES CONTAINS Let's see which geometries are contained in g1 and print the result: print g1.contains(g2) # False print g1.contains(g3) # True print g1.contains(g4) # False print g1.contains(g5) # False print g1.contains(g6) # False Mind that a point on the border is not contained, so only g3 is contained. This can be solved through the covers predicate. COVERS print g1.covers(g2) # False print g1.covers(g3) # True print g1.covers(g4) # True print g1.covers(g5) # False print g1.covers(g6) # False
  • 14. FUNCTIONS: INTERSECTION Let's see which geometries are contained in g1 and print the result: # the intersection of polygons returns a polygon g1_inter_g6 = g1.intersection(g6) print g1_inter_g6 # the intersection of touching polygons returns a line print g1.intersection(g2) # the intersection of a polygon with a point is a point print g1.intersection(g3) # the intersection of a polygon with a line is a point print g1.intersection(g5) # view the intersection of g1 and g6 gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 128) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) gr.addGraphic("g", g1, idG, "g") c = getColorFromRGB(0, 0, 255, 128) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) gr.addGraphic("g", g6, idG, "g") c = getColorFromRGB(0, 255, 0, 128) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) gr.addGraphic("g", g1_inter_g6, idG, "g") 0 5 0 5 g1 g5 g2 g3 g4 g6
  • 15. FUNCTIONS: SYMDIFFERENCE What is the resulting geometry of the symdifference (portions not shared) of different geometry types? # the symDifference of intersecting polygons returns a multipolygon g1jts = g1.getJTS() symDiff16 = g1jts.symDifference(g6.getJTS()) print symDiff16 # but the symDifference of touching polygons returns the polygons union print g1jts.symDifference(g2.getJTS()) # the symDifference of a polygon with a contained point returns the original polygon print g1jts.symDifference(g3.getJTS()) # the symDifference of a polygon with a line is a hybrid collection (line + polygon) print g1jts.symDifference(g5.getJTS()) # to get back a gvsig geometry multiPolygon2d = createGeometryFromWKT(symDiff16) print multiPolygon2d 0 5 0 5 g1 g5 g2 g3 g4 g6 Note that the symDifference is not implemented in gvSIG. In that case it is possible to access directly the JTS geometries and use the function on those. Afterwards through the WKT definition they can be converted back.
  • 16. FUNCTIONS: UNION What is the resulting geometry of the union of different geometry types? # the union of intersecting polygons returns a polygon print g1.union(g6).convertToWKT() # same as the union of touching polygons print g1.union(g2).convertToWKT() # the union of a polygon with a contained point returns the original polygon print g1.union(g3).convertToWKT() # the union of a polygon with a line doesn't result in a valid geometry print g1.union(g5) The following shows the union of polygons g1 and g6: 0 5 0 5 g1 g5 g2 g3 g4 g6
  • 17. FUNCTIONS: DIFFERENCE The difference of geometries obviously depends on the calling object: # this returns g1 minus the overlapping part of g6 print g1.difference(g6).convertToWKT() # while this returns g6 minus the overlapping part of g1 print g6.difference(g1).convertToWKT() # in the case of difference with lines, the result is the original polygon # with additional points in the intersections print g1.difference(g5).convertToWKT() # the difference of polygon and point is the original polygon print g1.difference(g3).convertToWKT() The following shows the difference of polygons g1 and g6: 0 5 0 5 g1 g5 g2 g3 g4 g6
  • 18. JTS GEOMETRIES Some functions are not supported in the gvSIG scripting API. But it is possible to access the underlying JTS geometries. JTS stands for , the most well known spatial predicates and geometry processing library available in the open source panorama. This is how to get back and forth between gvSIG and JTS: Java Topology Suite # create a gvsig geometry polygonGvsig = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))") # get the JTS geometry polygonJTS = polygonGvsig.getJTS() # do some advanced processing... for example get the centroid centroidJTS = polygonJTS.getCentroid(); # print the gvsig geometry print "gvSIG polygon WKT: " + polygonGvsig.convertToWKT() # print the JTS geometry print "JTS polygon WKT: %s" % polygonJTS # get back to a gvsig geometry centroidGvsig = createGeometryFromWKT(centroidJTS) print "gvSIG centroid WKT: " + centroidGvsig.convertToWKT()
  • 19. FUNCTIONS: BUFFER Creating a buffer around a geometry always generates a polygon geometry. The behavior can be tweaked, depending on the geometry type: from com.vividsolutions.jts.operation.buffer import BufferParameters g3jts = g3.getJTS() g5jts = g5.getJTS() # the buffer of a point b1 = g3jts.buffer(1.0) # the buffer of a point with few quandrant segments b2 = g3jts.buffer(1.0, 1) # round end cap style, few points b3 = g5jts.buffer(1.0, 2, BufferParameters.CAP_ROUND) # round end cap style, more points b4 = g5jts.buffer(1.0, 10, BufferParameters.CAP_ROUND) # square end cap style b5 = g5jts.buffer(1.0, -1, BufferParameters.CAP_SQUARE) # flat end cap style b6 = g5jts.buffer(1.0, -1, BufferParameters.CAP_FLAT) geoms = [b1, b2, b3, b4, b5, b6] gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 80) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) for g in geoms: gr.addGraphic("g", createGeometryFromWKT(g.toText()), idG, "g") JTS gives more control about buffering, it just requires us to import the BufferParameters module.
  • 20. FUNCTIONS IN JTS: CONVEXHULL Some functions are not available through the gvSIG API. We saw this already in the buffer functions and symDifference. Another example is the convex hull. So let's try working the JTS way. First, we create the geometries as JTS geometries: # build the example dataset g1 = createGeometryFromWKT("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))").getJTS() g2 = createGeometryFromWKT("POLYGON ((5 0, 5 2, 7 2, 7 0, 5 0))").getJTS() g3 = createGeometryFromWKT("POINT (4 1)").getJTS() g4 = createGeometryFromWKT("POINT (5 4)").getJTS() g5 = createGeometryFromWKT("LINESTRING (1 0, 1 6)").getJTS() g6 = createGeometryFromWKT("POLYGON ((3 3, 3 6, 6 6, 6 3, 3 3))").getJTS() geoms = [g1, g2, g3, g4, g5, g6]
  • 21. FUNCTIONS IN JTS: CONVEXHULL Once we have the geometries, we need to create a collection of geometries, which will require us to import a few classes. from com.vividsolutions.jts.geom import GeometryCollection, GeometryFactory gc = GeometryCollection(geoms, GeometryFactory()) with a GeometryCollection it is very simple to create a convex hull and visualize it: convexHull = gc.convexHull() gr = view.getGraphicsLayer() gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 80) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) for g in geoms: gr.addGraphic("g", createGeometryFromWKT(convexHull.toText()), idG, "g") view.getMapContext().invalidate()
  • 22. FUNCTIONS IN JTS: TRANSFORMATIONS Also for operations of translation, scaling and rotation we can make use of the JTS capabilities. It all boils down to a single class, the AffineTransformation, which we can import as: from com.vividsolutions.jts.geom.util import AffineTransformation as AT import math # used for conversion to radians It has direct methods to access to the different transformations: # create the jts polygon square = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))") square = square.getJTS() # this is how affine transformations are created scaleAffineTransformation = AT.scaleInstance(4,4) translationAffineTransformation = AT.translationInstance(2,2) rotationAffineTransformation = AT.rotationInstance(math.radians(45)) shearAffineTransformation = AT.shearInstance(0.75, 0) # this is how transformations are applied to geometries scaledSquare = scaleAffineTransformation.transform(square) print "Original: %s" % square print "Scaled: %s" % scaledSquare
  • 23. FUNCTIONS IN JTS: TRANSFORMATIONSLet's see how all the transformations work: square = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))").getJTS() # scale the square by 4 times squareLarge = AT.scaleInstance(4,4).transform(square) # move it by x, y units squareTranslate = AT.translationInstance(2,2).transform(square) # move it and then rotate it by 45 degrees squareTranslateRotate = AT.rotationInstance(math.radians(45) ).transform(squareTranslate) # realize that the order of things are there for a reason squareRotate = AT.rotationInstance(math.radians(45)).transform(square) squareRotateTranslate = AT.translationInstance(2,2).transform(squareRotate) # rotate around a defined center squareTranslateRotateCenter = AT.rotationInstance(math.radians(45), 2.5, 2.5).transform(squareTranslate) # shear the square squareShear = AT.shearInstance(0.75,0).transform(square) geoms = [square, squareLarge, squareTranslate, squareTranslateRotate, squareRotateTranslate, squareTranslateRotateCenter, squareShear] view = currentView() gr = view.getGraphicsLayer() gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 80) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) for g in geoms: gr.addGraphic("g", createGeometryFromWKT(g), idG, "g") view.mapContext.invalidate()
  • 24. PROJECTIONS Geometries can be reprojected directly using the crs objects. These can be created in several ways. The simplest is through the use of the EPSG code: from gvsig import * from gvsig.geom import * def main(*args): # create the source and destination crs # usign the EPSG codes crs1 = getCRS('EPSG:4326') crs2 = getCRS('EPSG:32632') # get the transformation object transform = crs1.getCT(crs2) # reproject a point from 4326 to 32632 point = createPoint2D(11, 46) print "Original point in lat/long: " + str(point) point.reProject(transform) print "and the reprojected point: " + str(point) # get the WKT representation of the crs object print crs2.getWKT()
  • 25. PROJECTIONS Sometimes it is necessary to modify the crs definition. If you load the data in a GIS and they do not appear where they should, it might be a problem of the false easting, but also the units might not be right. PROJCS["WGS 84 / UTM zone 32N", GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], UNIT["degree", 0.017453292519943295], AXIS["Longitude", EAST], AXIS["Latitude", NORTH], AUTHORITY["EPSG","4326"]], PROJECTION["Transverse_Mercator"], PARAMETER["central_meridian", 9.0], PARAMETER["latitude_of_origin", 0.0], PARAMETER["scale_factor", 0.9996], PARAMETER["false_easting", 500000.0], # sometimes a different false easting is used PARAMETER["false_northing", 0.0], UNIT["m", 1.0], # sometimes millimeters are used, with scale 0.001 AXIS["Easting", EAST], AXIS["Northing", NORTH], AUTHORITY["EPSG","32632"]]
  • 26. PROJECTIONS Converting from WKT to a crs is only an import statement away: from org.gvsig.fmap.crs import CRSFactory factory = CRSFactory.getCRSFactory() prjWkt = """PROJCS["WGS 84 / UTM zone 32N", GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], UNIT["degree", 0.017453292519943295], AXIS["Longitude", EAST], AXIS["Latitude", NORTH], AUTHORITY["EPSG","4326"]], PROJECTION["Transverse_Mercator"], PARAMETER["central_meridian", 9.0], PARAMETER["latitude_of_origin", 0.0], PARAMETER["scale_factor", 0.9996], PARAMETER["false_easting", 500000.0], PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["Easting", EAST], AXIS["Northing", NORTH], AUTHORITY["EPSG","32632"]] """ crs2 = factory.get("wkt", prjWkt)
  • 27. CREATING THE FIRST SHAPEFILE When we talk about "writing GIS stuff", we are usually talking about creating a shapefile. Let's see the steps to create our first shapefile: # place here the usual imports and main definition # create the blueprint of the shapefile schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) # create the shapefile shape = createShape(schema, CRS="EPSG:4326") # edit the shapefile and add features shape.edit() point1 = createPoint2D(-122.42, 37.78) shape.append(name='San Francisco', GEOMETRY=point1) point2 = createPoint2D(-73.98, 40.47) shape.append(name='New York', GEOMETRY=point2) shape.commit() # add the shapefile as layer to the view currentView().addLayer(shape) # print the path of the shapefile print "path: ", shape.getDataStore().getFullName()
  • 28. CREATING THE FIRST SHAPEFILE Let's see a slightly more complex example: # place here the usual imports and main definition # create the blueprint of the shapefile schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("population", "INTEGER", 4) schema.append("lat", "DOUBLE", 8) schema.append("lon", "DOUBLE", 8) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) # create the shapefile shape = createShape(schema, prefixname="complex", CRS="EPSG:4326") # edit the shapefile and add features shape.edit() point = createPoint2D(-73.98, 40.47) shape.append(name='New York',population=19040000, lat=40.749979064, lon=-73.9800169288, GEOMETRY=point) shape.commit() # add the shapefile as layer to the view currentView().addLayer(shape)
  • 29. CREATING THE FIRST SHAPEFILE Once the scripts are run, you should see the following in the map view:
  • 30. BUILD A VIEW AND LOAD DATALet's start from scratch and go through the whole process again. 1) imports # the most used imports are... from gvsig import * from gvsig.geom import * 2) create the data blueprint # define a working crs epsg = "EPSG:4326" # create the blueprint of the shapefile schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) # create the shapefile shape = createShape(schema, prefixname="simple", CRS=epsg) # edit the shapefile and add a feature shape.edit() x = -122.42 y = 37.78 point = createPoint2D(x, y) shape.append(name='New York', GEOMETRY=point) shape.commit() 3) create some data
  • 31. BUILD A VIEW AND LOAD DATA 3) load an external shapefile into a layer # first add some background shp background = loadLayer("Shape", shpFile="/home/hydrologis/data/natural_earth/ne_10m_admin_0_countries.shp", CRS=epsg) 4) create a new map view with name and crs and load the layers into it # zoom to the feature boxDelta = 0.05 newview.centerView(createEnvelope([x-boxDelta,y-boxDelta],[x+boxDelta,y+boxDelta])) 5) zoom to the created feature # create a new view and set its projection newview = currentProject().createView("Example view") newview.setProjection(getCRS(epsg)) newview.addLayer(background) newview.addLayer(shape) newview.showWindow()
  • 32. INVESTIGATING A VECTOR LAYER Let's see how accessing views and layers is done... # define view and layer to investigate viewName = "Example view" layerName = "ne_10m_admin_0_countries" # get the view and layers view = currentProject().getView(viewName) if view is None: print "ERROR: view ", viewName, " is not available in the current project" return layers = view.getLayers() # pick the right layer layerToRead = None print "Iterate through the layers: " for layer in layers: print "tLayer: ", layer.getName() if layer.getName() == layerName: layerToRead = layer
  • 33. INVESTIGATING A VECTOR LAYER ...and what about the layer's schema content? # investigate its schema if layerToRead is not None: schema = layerToRead.getSchema() # show the attributes attrSchema = schema.getAttrNames() print "nnSchema attr: ", attrSchema print "nnFields description" for field in schema: print " Name: ", field.getName(), print " tDataTypeName: ", field.getDataTypeName(), print " tPrecision: ", field.getPrecision(), print " tSize: ", field.getSize() if field.getDataTypeName() == 'Geometry': geomType = field.getGeomType() print " tGeom Name: ", geomType.getName() print " tGeom FullName: ", geomType.getFullName() print " tDimension: ", geomType.getDimension() else: print "ERROR: layer ", layerName, " is not available in view: ", viewName
  • 34. INVESTIGATING A VECTOR LAYER ...and what about the data? # define view and layer to investigate viewName = "Example view" layerName = "ne_10m_admin_0_countries" # get the view view = currentProject().getView(viewName) # get the layer by its name layer = view.getLayer(layerName) # get the features set features = layer.features() print "Features available in layer: ", features.getSize() # loop through the features for feature in features: print feature.getValues()
  • 35. INVESTIGATING A VECTOR LAYER How to access the feature attributes: layer = currentView().getLayer("ne_10m_admin_0_countries") features = layer.features() for feature in features: print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants." It is possible to get only the features selected by the user with: features = layer.getSelection()
  • 36. INVESTIGATING A VECTOR LAYER Features can be extracted from a layer by means of filters and sorted by a given attribute. Extract the population less than 1000 and major than 0, in ascending order: layer = currentView().getLayer("ne_10m_admin_0_countries") features = layer.features("POP_EST < 1000 and POP_EST > 0", sortby="POP_EST", asc=True) for feature in features: print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants." And here a simple way to get the country with largest population: features = layer.features(sortby="POP_EST", asc=False) for feature in features: print "The country with most inhabitants is ", feature.NAME , " with ", feature.POP_EST break
  • 37. SELECT FEATURES IN A VECTOR LAYER Features can be selected or deselected in a view/layer using the selection object of the layer. Example: select an print the countries with more than 1E9 inhabitants # select features selection = layer.getSelection() selection.deselectAll() features = layer.features("POP_EST > 1E9") for feature in features: selection.select(feature) print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants." selection.deselect(feature) Single features can be removed from the selection through:
  • 38. CREATE A COUNTRIES CENTROIDS LAYER It is no rocket science to apply all we have seen until this point to create a shapefile containing the centroids of the countries. All you need to know is that the geometry has a method that extracts the centroid for you: centroid countriesLayer = currentView().getLayer("ne_10m_admin_0_countries") shpPath = "/home/hydrologis/TMP/centroids.shp" epsg = "EPSG:4326" schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) shape = createShape(schema, filename=shpPath, CRS=epsg) shape.edit() countries = countriesLayer.features() for country in countries: geometry = country.GEOMETRY centroid = geometry.centroid() shape.append(name=country.NAME, GEOMETRY=centroid) shape.commit() currentView().addLayer(shape)
  • 39. STYLING YOUR LAYERS Let's see how styling of the different feature/geometries types is done. To do so, we first load a layer of each type: point, line, polygon basePath = "/home/hydrologis/data/natural_earth/" countries = basePath + "ne_10m_admin_0_countries.shp" places = basePath + "ne_10m_populated_places.shp" roads = basePath + "ne_10m_roads.shp" # create a new view and set its projection epsg = "EPSG:4326" newview = currentProject().createView("Example view") newview.setProjection(getCRS(epsg)) newview.showWindow() countriesLayer = loadLayer("Shape", shpFile=countries, CRS=epsg) placesLayer = loadLayer("Shape", shpFile=places, CRS=epsg) roadsLayer = loadLayer("Shape", shpFile=roads, CRS=epsg) newview.addLayer(countriesLayer) newview.addLayer(roadsLayer) newview.addLayer(placesLayer)
  • 40. SIMPLE STYLING OF POINTS Styling of shapes is done by creating a symbol and set it in the layer's legend: # get the layer's legend pointsLegend = placesLayer.getLegend() # create and modify the symbol pointSymbol = simplePointSymbol() pointSymbol.setSize(15); pointSymbol.setColor(getColorFromRGB(0,0,255,128)); # blue pointSymbol.setOutlined(True); pointSymbol.setOutlineColor(getColorFromRGB(255,255,0)); # yellow pointSymbol.setOutlineSize(1); # circle = 0; square = 1; cross = 2; diamond = 3; X = 4; triangle = 5; star = 6; vertical line = 7; pointSymbol.setStyle(5); # set symbol to legend and legend to layer pointsLegend.setDefaultSymbol(pointSymbol) placesLayer.setLegend(pointsLegend) # then zoom x = 11 y = 46 boxDelta = 2 newview.centerView(createEnvelope([x-boxDelta,y-boxDelta],[x+boxDelta,y+boxDelta]))
  • 41. SIMPLE STYLING OF LINES Styling of lines is similar to that of points: lineSymbol = simpleLineSymbol() lineSymbol.setLineWidth(2); lineSymbol.setLineColor(getColorFromRGB(128,128,128)); linesLegend = roadsLayer.getLegend() linesLegend.setDefaultSymbol(lineSymbol) roadsLayer.setLegend(linesLegend) While styling of polygons is done in two steps: outline and fill # first create the outline symbol and style it polygonOutlineSymbol = simpleLineSymbol() polygonOutlineSymbol.setLineWidth(2) polygonOutlineSymbol.setLineColor(getColorFromRGB(255,0,0)) # then the fill polygonFillSymbol = simplePolygonSymbol() polygonFillSymbol.setOutline(polygonOutlineSymbol) polygonFillSymbol.setFillColor(getColorFromRGB(255,0,0,70)) polygonLegend = countriesLayer.getLegend() polygonLegend.setDefaultSymbol(polygonFillSymbol) countriesLayer.setLegend(polygonLegend)
  • 42. SIMPLE STYLING OF POLYGONS Once run, the script should create a new view that looks like:
  • 43. HOW TO REUSE CODE? Often pieces of code are repeated for different variables and could be reused. This can be easily done with functions. Functions are defined using the "def" construct. The following is a simple example that shows how one can use a function to set the symbol in the layer's legend, using one line instead of repeating three lines for each layer: def setSymbolInLayer(symbol, layer): legend = layer.getLegend() legend.setDefaultSymbol(symbol) layer.setLegend(legend)
  • 44. SIMPLE STYLING OF POLYGONS It is also possible to style using a color-ramp based on an attribute of the layer. In that case it will be necessary to add one import: from org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl import VectorialIntervalLegend Then, using the interval legend, it is quite straight forward: # create an interval legend intervalLegend = VectorialIntervalLegend(POLYGON) intervalLegend.setStartColor(Color.gray) intervalLegend.setEndColor(Color.red) intervalLegend.setIntervalType(1) # natural = 1, quantile = 2 store = countriesLayer.getFeatureStore() # calculate the intervals using the field name and the desired number of intervals intervals = intervalLegend.calculateIntervals(store, "POP_EST", 5, POLYGON) intervalLegend.setIntervals(intervals) countriesLayer.setLegend(intervalLegend)
  • 45. SIMPLE STYLING OF POLYGONS ...which the should look like a choropleth map:
  • 46. <license> This work is released under Creative Commons Attribution Share Alike (CC-BY-SA). </license> <sources> Much of the knowledge needed to create this training material has been produced by the sparkling knights of the <a href="http:www.osgeo.org">Osgeo</a>, <a href="http://tsusiatsoftware.net/">JTS</a>, <a href="http://www.jgrasstools.org">JGrasstools</a> and <a href="http:www.gvsig.org">gvSIG</a> communities. Their websites are filled up with learning material that can be use to grow knowledge beyond the boundaries of this set of tutorials. Another essential source has been the Wikipedia project. </sources> <acknowledgments> Particular thanks go to those friends that directly or indirectly helped out in the creation and review of this series of handbooks. Thanks to Antonio Falciano for proofreading the course and Oscar Martinez for the documentation about gvSIG scripting. </acknowledgments> <footer> This tutorial is brought to you by <a href="http:www.hydrologis.com">HydroloGIS</a>. <footer>