Getting started

If you have not installed GeomCompare yet, you can follow the installation instructions.

Input/Output

Load a geometry dataset from disk

Load geometrical features from a Shapefile:

from geomcompare.io import extract_geoms_from_file

filename = "/path/to/my/file.shp"

# The names of supported OGR/GDAL drivers for opening files with
# geometrical features are listed in
# https://gdal.org/drivers/vector/index.html
driver_name = "ESRI Shapefile" # driver name for opening shapefiles

# Get an iterator of the geometries
geoms = extract_geoms_from_file(filename, driver_name)

# Note: the file will only be closed after the
# "extract_geoms_from_file" has yielded the last geometry.
# If you intend to iterate through "geoms" multiple times, you can
# store the geometries in a list instead
geoms_list = list(geoms) # now the file is closed

Filtering the extracted geometrical features:

from geomcompare.io import extract_geoms_from_file, LayerFilter

filename = "/path/to/my/file.json"
driver_name = "GeoJSON"

# Extract only geometrical features from the layer "my_lyr"
geoms_my_lyr = extract_geoms_from_file(
    filename=filename,
    driver_name=driver_name,
    layers=["my_lyr"],
)

# Extract only the first 10 geometrical features from the layer
# "my_lyr"
lyr_filter = LayerFilter(fids=list(range(10)))
geoms_my_lyr_10 = extract_geoms_from_file(
    filename=filename,
    driver_name=driver_name,
    layers=["my_lyr"],
    layer_filters=[lyr_filter],
)

# Area of interest
aoi = list(
    extract_geoms_from_file("/path/to/aoi_poly.shp", "ESRI Shapefile")
)[0]

# Extract features from the layer "large_lyr" that are within the
# aoi polygon, as well as all features from other layers
lyr_filter = LayerFilter(layer_id="large_lyr", aoi=aoi)
filtered_geoms = extract_geoms_from_file(
    filename=filename,
    driver_name=driver_name,
    layer_filters=[lyr_filter],
)

# Extract only features which "distance" attribute is inferior to
# 1000
lyr_filter = LayerFilter(attr_filter="distance < 1000")
geoms_dist_inf_1000 = extract_geoms_from_file(
    filename=filename,
    driver_name=driver_name,
    layer_filters=[lyr_filter],
)

Load a geometry dataset from a PostGIS database

from geomcompare.io import fetch_geoms_from_pg, ConnectionParameters, SchemaTableColumn

# Pass the correct values to keyword parameters
conn_params = ConnectionParameters(
    host="host_name",
    dbname="db_name",
    user="my_user",
    password="my_pwd",
    port=5432,
)

# Using some fictive database layout
geoms_location = SchemaTableColumn(
    schema="building",
    table="public",
    column="geom",
)

# Open a connection to the database and get an iterator of the
# geometries. The connection stays opened until the function has
# yielded the last geometry at that location in the database.
geoms = fetch_geoms_from_pg(
    conn_params=conn_params, geoms_col_loc=geoms_location,
)

# Store the geometries in a list and close the connection.
geoms_list = list(geoms)

# Get the same geometries, but this time using the "sql_query"
# parameter instead of the "geoms_col_loc" parameter. Any SQL query
# which return geometrical features can be passed as argument.
geoms_list = list(fetch_geoms_from_pg(
    conn_params=conn_params,
    sql_query="SELECT geom FROM building.public;",
))

# Area of interest
aoi = list(
    extract_geoms_from_file("/path/to/aoi_poly.shp", "ESRI Shapefile")
)[0]
# Get an iterator of the geometries from the same geometry column,
# but only those which lie within the aoi polygon. The
# "output_epsg" parameter can be use to reproject the geometries to
# the wanted spatial reference system.
geoms = fetch_geoms_from_pg(
    conn_params=conn_params,
    geoms_col_loc=geoms_location,
    aoi=aoi,
    output_epsg=25833,
)

Write a geometry dataset to disk

Warning

When writing to disk, GeomCompare assumes that all geometrical features have the same geometry type. write_geoms_to_file() will not check for geometry type homogeneity and will instead throw an error if the features have different geometry types. If the features have different geometry types, you can still group them into multiple datasets of homogeneous geometry type, and write these datasets to the same file on different layers, if the data format supports it, as shown below.

Write a list of geometrical features to Shapefile:

from geomcompare.io import write_geoms_to_file

filename = "/path/to/output/file.shp"
driver_name = "ESRI Shapefile"

# "geoms_list" is our list of geometrical features
write_geoms_to_file(
    filename=filename,
    driver_name=driver_name,
    geoms_iter=geoms_list,
    geoms_epsg=4326, # not required, but good practice if available
)

Write two datasets with different geometry types to the same GeoPackage file:

from geomcompare.io import write_geoms_to_file

filename = "/path/to/output/file.gpkg"
driver_name = "GPKG"

write_geoms_to_file(
    filename=filename,
    driver_name=driver_name,
    geoms_iter=points_list,
    geoms_epsg=25833,
    layer="my_point_layer",
)

write_geoms_to_file(
    filename=filename,
    driver_name=driver_name,
    geoms_iter=polygons_list,
    geoms_epsg=4326,
    layer="my_polygon_layer",
    mode="update",
)

Note

If the geoms_epsg parameter is given, and the layer where the geometrical features are to be written on has a different Spatial Reference System, the geometries’ coordinates will be re-projected on-the-fly.

Comparing datasets

GeomCompare provides three main classes that can be used to compare two datasets of geometrical features:

These classes present an interface to store or give access to a reference dataset/database of geometrical features, to which a test dataset can be compared. Instances of these classes present a similar API, but they all have pros and cons when compared against each others. Presently, the class SQLiteGeomRefDB gives more flexibility to the user and will therefore be used in the following examples.

Comparison of two geometries

The main classes provided by GeomCompare delegates the comparison of two geometrical features to an external function. This can be a user-defined function, or one of the few comparison functions provided by GeomCompare. These functions’ signature must match the following template:

comparison_function(gtest, gref) -> bool

where the first positional argument gtest is the test geometry (shapely geometrical object), and where the second positional argument gref is the reference geometry. If the comparison function finds that the input geometries are similar, it must return True. It must return False for different geometries.

from shapely.geometry import Polygon

from geomcompare.comparefunc import polygons_area_match

# The dispatch function "polygons_area_match" is not itself a
# comparison function, but it returns comparison functions with the
# right signature instead. The way the returned function compare
# two geometries depends on the values passed as arguments to
# "polygons_area_match".

# Use Intersection over Union metric for comparison
strategy = "IoU"
threshold = 0.7
comparison_f = polygons_area_match(strategy, threshold)

# Reference polygon
poly_ref = Polygon(((0, 0), (1, 0), (1, 1), (0, 1)))

# Test polygons
poly_test1 = Polygon(((0, 0), (0.5, 0), (0.5, 1), (0, 1)))
poly_test2 = Polygon(((0, 0), (0.75, 0), (0.75, 1), (0, 1)))

comparison_f(poly_test1, poly_ref) # returns False: IoU < 0.7
comparison_f(poly_test1, poly_ref) # returns True: IoU >= 0.7

The comparison function will be passed as argument to one of the methods of the main classes’ instances to compare test and reference geometries.

Managing a reference dataset

The following code examples shows how to manage a reference geometry dataset using the SQLiteGeomRefDB class. Internally, instances of this class uses a SQLite database (with spatialite extension) to store the reference geometries.

Initialize a SQLiteGeomRefDB instance and populate it with geometries:

from geomcompare import SQLiteGeomRefDB

# Start with an empty instance.
geomref = SQLiteGeomRefDB()

filename = "/path/to/reference/dataset.shp"
driver_name = "ESRI Shapefile" # driver name for opening shapefiles

# Get an iterator of the reference geometries, let us assume that
# the geometries are polygons.
ref_polys = extract_geoms_from_file(filename, driver_name)

# Add the geometries to the SQLiteGeomRefDB instance.
geomref.add_geometries(
    ref_polys,
    geom_type="Polygon",
    geoms_epsg=25833,
    geoms_tab_name="my_ref_polys",
)

The code above instantiates a SQLiteGeomRefDB object, which internally creates a SQLite database in RAM, and adds reference polygons from a shapefile to a table named “my_ref_polys”. As we have created a new database, the geom_type and parameter of add_geometries() must be passed an argument, since the geometry type is required by spatialite when creating a new geometry column in a table of the database. If the default_epsg was not set (either when creating the instance or at least before adding the new geometries), geoms_epsg (identifying the spatial reference system of the input reference geometries) must also be given when calling add_geometries().