Skip to content

Commit

Permalink
Add mgist-postgis extension for geometry collections
Browse files Browse the repository at this point in the history
  • Loading branch information
mschoema committed Jun 27, 2024
1 parent e170461 commit 5ac8802
Show file tree
Hide file tree
Showing 201 changed files with 99,674 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*.o
*.so
.cache
build
compile_commands.json
40 changes: 40 additions & 0 deletions mgist-postgis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#-------------------------------------
# MGiST-Postgis Main CMake file
#-------------------------------------

cmake_minimum_required(VERSION 3.10)

# Disallow in-source builds
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(FATAL_ERROR "In-source builds not allowed.
Please make a new directory (called a build directory) and run CMake from there.
You may need to remove 'CMakeCache.txt' and 'CMakeFiles/'.")
endif()

# Specify search path for CMake modules to be loaded
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")

project(MGiST-Postgis VERSION 1.0.0)
message(STATUS "Building MGiST-Postgis version ${PROJECT_VERSION}")

# Find PostgreSQL
find_package(POSTGRESQL REQUIRED)
find_package(POSTGIS REQUIRED)
find_package(GEOS REQUIRED)
include_directories(SYSTEM ${POSTGRESQL_INCLUDE_DIR})

include_directories("${CMAKE_SOURCE_DIR}/ryu")
include_directories("${CMAKE_SOURCE_DIR}/liblwgeom")
add_subdirectory("${CMAKE_SOURCE_DIR}/liblwgeom" "liblwgeom")
add_subdirectory("${CMAKE_SOURCE_DIR}/ryu" "ryu")

set(PROJECT_OBJECTS ${PROJECT_OBJECTS} "$<TARGET_OBJECTS:ryu>")
set(PROJECT_OBJECTS ${PROJECT_OBJECTS} "$<TARGET_OBJECTS:liblwgeom>")
set(PROJECT_OBJECTS ${PROJECT_OBJECTS} "mgist_postgis.c")

add_library(mgist_postgis MODULE ${PROJECT_OBJECTS})

install(
FILES "${CMAKE_SOURCE_DIR}/mgist_postgis.control" "${CMAKE_SOURCE_DIR}/mgist_postgis--1.0.sql"
DESTINATION "${POSTGRESQL_SHARE_DIR}/extension")
install(TARGETS mgist_postgis DESTINATION "${POSTGRESQL_DYNLIB_DIR}")
38 changes: 38 additions & 0 deletions mgist-postgis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Multi-Entry GiST Indexing for PostGIS
========================================

This directory contains an implementation of Multi-Entry GiST indexes for the PostGIS geometry type.

Contrary to the traditional GiST index for PostGIS, MGiST will index collection types with one bounding box per element in the collection. This index will thus mainly benefit datasets containing collections such as multi-points or multi-polygons that are spread out over a large area. Tuples containing single geometries will be indexed using a single bounding box as usual.

The MGiST index for geometries currently provides speedups for overlaps `&&` and distance `<->` operators.
However, the PostGIS support functions are not yet implemented for MGiST indexes, so the index will not be used for queries using the `ST_Intersects` or `ST_Contains` functions. To provide speedup for these functions, you will need to add an explicit overlaps test to the query.

Dependencies
------------
- [PostgreSQL 16](https://www.postgresql.org/)
- [PostGIS 3.4](https://postgis.net/)
- [mgist](../mgist)

You should also set the following in postgresql.conf depending on the version of PostGIS you have installed (below we use PostGIS 3):

```
shared_preload_libraries = 'postgis-3'
```

Installation
------------
Compiling and installing the extension
```
make
sudo make install
```

Using the extension to create a Multi-Entry R-Tree on the geometry column `trip` from the table `trips(id, trip)`
```sql
CREATE EXTENSION mgist_mobilitydb CASCADE;
CREATE INDEX trips_mgist_trip on trips using mgist(trip);
```

Contact:
Maxime Schoemans <[email protected]>
218 changes: 218 additions & 0 deletions mgist-postgis/cmake/FindGEOS.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Find GEOS
# ~~~~~~~~~
# Taken from QGIS and made minimal modifications for MobilityDB,
# e.g., to allow 'dev' suffix in GEOS version
# Copyright (c) 2021, Esteban Zimanyi
#
# Copyright (c) 2008, Mateusz Loskot <[email protected]>
# (based on FindGDAL.cmake by Magnus Homann)
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
# CMake module to search for GEOS library
#
# If it's found it sets GEOS_FOUND to TRUE
# and following variables are set:
# GEOS_INCLUDE_DIR
# GEOS_LIBRARY
#

IF(APPLE)
FUNCTION (GET_VERSION_PLIST PLISTFILE OUTVAR)
SET (PVERSION "")
IF (EXISTS ${PLISTFILE})
FILE (READ "${PLISTFILE}" info_plist)
STRING (REGEX REPLACE "\n" "" info_plist "${info_plist}")
STRING (REGEX MATCH "<key>CFBundleShortVersionString</key>[ \t]*<string>([0-9\\.]*)</string>" PLISTVERSION "${info_plist}")
STRING (REGEX REPLACE "<key>CFBundleShortVersionString</key>[ \t]*<string>([0-9\\.]*)</string>" "\\1" PVERSION "${PLISTVERSION}")
ENDIF (EXISTS ${PLISTFILE})
SET (${OUTVAR} ${PVERSION} PARENT_SCOPE)
ENDFUNCTION (GET_VERSION_PLIST)
ENDIF(APPLE)

IF(WIN32)

IF (MINGW)
FIND_PATH(GEOS_INCLUDE_DIR geos_c.h "$ENV{LIB_DIR}/include" /usr/local/include /usr/include c:/msys/local/include)
FIND_LIBRARY(GEOS_LIBRARY NAMES geos_c PATHS "$ENV{LIB_DIR}/lib" /usr/local/lib /usr/lib c:/msys/local/lib)
ENDIF (MINGW)

IF (MSVC)
FIND_PATH(GEOS_INCLUDE_DIR geos_c.h $ENV{LIB_DIR}/include $ENV{INCLUDE})
FIND_LIBRARY(GEOS_LIBRARY NAMES geos_c_i geos_c PATHS
"$ENV{LIB_DIR}/lib"
$ENV{LIB}
)
ENDIF (MSVC)

ELSEIF(APPLE AND QGIS_MAC_DEPS_DIR)

FIND_PATH(GEOS_INCLUDE_DIR geos_c.h "$ENV{LIB_DIR}/include" )
FIND_LIBRARY(GEOS_LIBRARY NAMES geos_c PATHS "$ENV{LIB_DIR}/lib" )

ELSE(WIN32)

IF(UNIX)
# try to use framework on mac
# want clean framework path, not unix compatibility path
IF (APPLE)
IF (CMAKE_FIND_FRAMEWORK MATCHES "FIRST"
OR CMAKE_FRAMEWORK_PATH MATCHES "ONLY"
OR NOT CMAKE_FIND_FRAMEWORK)
SET (CMAKE_FIND_FRAMEWORK_save ${CMAKE_FIND_FRAMEWORK} CACHE STRING "" FORCE)
SET (CMAKE_FIND_FRAMEWORK "ONLY" CACHE STRING "" FORCE)
FIND_LIBRARY(GEOS_LIBRARY GEOS)
IF (GEOS_LIBRARY)
# they're all the same in a framework
SET (GEOS_INCLUDE_DIR ${GEOS_LIBRARY}/Headers CACHE PATH "Path to a file.")
# set GEOS_CONFIG to make later test happy, not used here, may not exist
SET (GEOS_CONFIG ${GEOS_LIBRARY}/unix/bin/geos-config CACHE FILEPATH "Path to a program.")
# version in info.plist
GET_VERSION_PLIST (${GEOS_LIBRARY}/Resources/Info.plist GEOS_VERSION)
IF (NOT GEOS_VERSION)
MESSAGE (FATAL_ERROR "Could not determine GEOS version from framework.")
ENDIF (NOT GEOS_VERSION)
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\1" GEOS_VERSION_MAJOR "${GEOS_VERSION}")
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\2" GEOS_VERSION_MINOR "${GEOS_VERSION}")
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\3" GEOS_VERSION_MICRO "${GEOS_VERSION}")
IF (GEOS_VERSION_MAJOR LESS 3)
MESSAGE (FATAL_ERROR "GEOS version is too old (${GEOS_VERSION}). Use 3.0.0 or higher.")
ENDIF (GEOS_VERSION_MAJOR LESS 3)
ENDIF (GEOS_LIBRARY)
SET (CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_save} CACHE STRING "" FORCE)
ENDIF ()
ENDIF (APPLE)

IF(CYGWIN)
FIND_LIBRARY(GEOS_LIBRARY NAMES geos_c PATHS /usr/lib /usr/local/lib)
ENDIF(CYGWIN)

IF (NOT GEOS_INCLUDE_DIR OR NOT GEOS_LIBRARY OR NOT GEOS_CONFIG)
# didn't find OS X framework, and was not set by user
SET(GEOS_CONFIG_PREFER_PATH "$ENV{GEOS_HOME}/bin" CACHE STRING "preferred path to GEOS (geos-config)")
FIND_PROGRAM(GEOS_CONFIG geos-config
${GEOS_CONFIG_PREFER_PATH}
$ENV{LIB_DIR}/bin
/usr/local/bin/
/usr/bin/
)
#MESSAGE("DBG GEOS_CONFIG ${GEOS_CONFIG}")

IF (GEOS_CONFIG)
execute_process(
COMMAND ${GEOS_CONFIG} --version
OUTPUT_VARIABLE GEOS_VERSION)
# Remove trailing newline
STRING(REGEX REPLACE "\n$" "" GEOS_VERSION "${GEOS_VERSION}")
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\1" GEOS_VERSION_MAJOR "${GEOS_VERSION}")
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\2" GEOS_VERSION_MINOR "${GEOS_VERSION}")
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\3" GEOS_VERSION_MICRO "${GEOS_VERSION}")

IF (GEOS_VERSION_MAJOR LESS 3 OR (GEOS_VERSION_MAJOR EQUAL 3 AND GEOS_VERSION_MINOR LESS 3) )
MESSAGE (FATAL_ERROR "GEOS version is too old (${GEOS_VERSION}). Use 3.3.0 or higher.")
ENDIF (GEOS_VERSION_MAJOR LESS 3 OR (GEOS_VERSION_MAJOR EQUAL 3 AND GEOS_VERSION_MINOR LESS 3) )

# set INCLUDE_DIR to prefix+include
execute_process(
COMMAND ${GEOS_CONFIG} --prefix
OUTPUT_VARIABLE GEOS_PREFIX)
# Remove trailing newline
STRING(REGEX REPLACE "\n$" "" GEOS_PREFIX "${GEOS_PREFIX}")
FIND_PATH(GEOS_INCLUDE_DIR
geos_c.h
${GEOS_PREFIX}/include
/usr/local/include
/usr/include
)

## extract link dirs for rpath
execute_process(
COMMAND ${GEOS_CONFIG} --libs
OUTPUT_VARIABLE GEOS_CONFIG_LIBS)
# Remove trailing newline
STRING(REGEX REPLACE "\n$" "" GEOS_CONFIG_LIBS "${GEOS_CONFIG_LIBS}")

## split off the link dirs (for rpath)
## use regular expression to match wildcard equivalent "-L*<endchar>"
## with <endchar> is a space or a semicolon
STRING(REGEX MATCHALL "[-][L]([^ ;])+"
GEOS_LINK_DIRECTORIES_WITH_PREFIX
"${GEOS_CONFIG_LIBS}" )
#MESSAGE("DBG GEOS_LINK_DIRECTORIES_WITH_PREFIX=${GEOS_LINK_DIRECTORIES_WITH_PREFIX}")

## remove prefix -L because we need the pure directory for LINK_DIRECTORIES

IF (GEOS_LINK_DIRECTORIES_WITH_PREFIX)
STRING(REGEX REPLACE "[-][L]" "" GEOS_LINK_DIRECTORIES ${GEOS_LINK_DIRECTORIES_WITH_PREFIX} )
ENDIF (GEOS_LINK_DIRECTORIES_WITH_PREFIX)

### XXX - mloskot: geos-config --libs does not return -lgeos_c, so set it manually
## split off the name
## use regular expression to match wildcard equivalent "-l*<endchar>"
## with <endchar> is a space or a semicolon
#STRING(REGEX MATCHALL "[-][l]([^ ;])+"
# GEOS_LIB_NAME_WITH_PREFIX
# "${GEOS_CONFIG_LIBS}" )
#MESSAGE("DBG GEOS_CONFIG_LIBS=${GEOS_CONFIG_LIBS}")
#MESSAGE("DBG GEOS_LIB_NAME_WITH_PREFIX=${GEOS_LIB_NAME_WITH_PREFIX}")
SET(GEOS_LIB_NAME_WITH_PREFIX -lgeos_c CACHE STRING INTERNAL)

## remove prefix -l because we need the pure name

IF (GEOS_LIB_NAME_WITH_PREFIX)
STRING(REGEX REPLACE "[-][l]" "" GEOS_LIB_NAME ${GEOS_LIB_NAME_WITH_PREFIX} )
ENDIF (GEOS_LIB_NAME_WITH_PREFIX)
#MESSAGE("DBG GEOS_LIB_NAME=${GEOS_LIB_NAME}")

IF (APPLE)
IF (NOT GEOS_LIBRARY)
# work around empty GEOS_LIBRARY left by framework check
# while still preserving user setting if given
# ***FIXME*** need to improve framework check so below not needed
SET(GEOS_LIBRARY ${GEOS_LINK_DIRECTORIES}/lib${GEOS_LIB_NAME}.dylib CACHE STRING INTERNAL FORCE)
ENDIF (NOT GEOS_LIBRARY)
ELSE (APPLE)
FIND_LIBRARY(GEOS_LIBRARY NAMES ${GEOS_LIB_NAME} PATHS ${GEOS_LIB_DIRECTORIES}/lib)
ENDIF (APPLE)
#MESSAGE("DBG GEOS_LIBRARY=${GEOS_LIBRARY}")

ELSE(GEOS_CONFIG)
MESSAGE("FindGEOS.cmake: geos-config not found. Please set it manually. GEOS_CONFIG=${GEOS_CONFIG}")
ENDIF(GEOS_CONFIG)
ENDIF(NOT GEOS_INCLUDE_DIR OR NOT GEOS_LIBRARY OR NOT GEOS_CONFIG)
ENDIF(UNIX)
ENDIF(WIN32)

IF(GEOS_INCLUDE_DIR AND NOT GEOS_VERSION)
FILE(READ ${GEOS_INCLUDE_DIR}/geos_c.h VERSIONFILE)
STRING(REGEX MATCH "#define GEOS_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+" GEOS_VERSION ${VERSIONFILE})
STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" GEOS_VERSION ${GEOS_VERSION})
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\1" GEOS_VERSION_MAJOR "${GEOS_VERSION}")
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\2" GEOS_VERSION_MINOR "${GEOS_VERSION}")
STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(dev)?" "\\3" GEOS_VERSION_MICRO "${GEOS_VERSION}")
ENDIF(GEOS_INCLUDE_DIR AND NOT GEOS_VERSION)

IF (GEOS_INCLUDE_DIR AND GEOS_LIBRARY)
SET(GEOS_FOUND TRUE)
ENDIF (GEOS_INCLUDE_DIR AND GEOS_LIBRARY)

IF (GEOS_FOUND)

IF (NOT GEOS_FIND_QUIETLY)
MESSAGE(STATUS "Found GEOS: ${GEOS_LIBRARY} (${GEOS_VERSION})")
ENDIF (NOT GEOS_FIND_QUIETLY)

ELSE (GEOS_FOUND)

MESSAGE(GEOS_INCLUDE_DIR=${GEOS_INCLUDE_DIR})
MESSAGE(GEOS_LIBRARY=${GEOS_LIBRARY})
MESSAGE(FATAL_ERROR "Could not find GEOS")

ENDIF (GEOS_FOUND)

message(STATUS "GEOS_INCLUDE_DIR: ${GEOS_INCLUDE_DIR}")
message(STATUS "GEOS_LIBRARY: ${GEOS_LIBRARY}")
message(STATUS "GEOS_VERSION: ${GEOS_VERSION}")
message(STATUS "GEOS_VERSION_MAJOR: ${GEOS_VERSION_MAJOR}")
message(STATUS "GEOS_VERSION_MINOR: ${GEOS_VERSION_MINOR}")
message(STATUS "GEOS_VERSION_MICRO: ${GEOS_VERSION_MICRO}")
76 changes: 76 additions & 0 deletions mgist-postgis/cmake/FindPOSTGIS.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# (c) 2015 pgRouting colaborators
#
# Finds the most recent postGIS for a particular postgreSQL
# We need this for the tests
#
# Usage:
# find_package(POSTGIS)
#
# The following variables are set if PostGIS is found:
# POSTGIS_FOUND - Set to true when PostGIS is found.
# POSTGIS_LIBRARY - if we ever need to link it
# POSTGIS_CONTROL - if we ever need to see the contents
# POSTGIS_VERSION - The full numbers
# POSTGIS_VERSION_STR - The th PostGIS prefix

if(POSTGIS_FOUND)
return()
endif()

if(NOT POSTGRESQL_FOUND)
find_package(POSTGRESQL REQUIRED)
endif()

# Find PostGIS library

# If specific version of PostGIS requested, choose that one, otherwise get all versions
if(POSTGIS_REQUIRED_VERSION)
message(STATUS "Selecting requested PostGIS version: Selecting postgis-${POSTGIS_REQUIRED_VERSION}")
file(GLOB POSTGIS_LIBRARY "${POSTGRESQL_DYNLIB_DIR}/postgis-${POSTGIS_REQUIRED_VERSION}.*")
else()
file(GLOB POSTGIS_LIBRARY "${POSTGRESQL_DYNLIB_DIR}/postgis-*.*")
endif()

if(POSTGIS_LIBRARY STREQUAL "")
message(FATAL_ERROR "No PostGIS library have been found in ${POSTGRESQL_DYNLIB_DIR}")
else()
# If several versions of PostGIS found, choose the first one
list(LENGTH POSTGIS_LIBRARY NO_POSTGIS_LIBRARIES)
if(NO_POSTGIS_LIBRARIES GREATER 1)
list(GET POSTGIS_LIBRARY 0 POSTGIS_LIBRARY)
message(STATUS "Several PostGIS versions found: Selecting ${POSTGIS_LIBRARY}")
endif()
endif()

message(STATUS "Looking for postgis.control file in ${POSTGRESQL_SHARE_DIR}/extension")
find_file(POSTGIS_CONTROL postgis.control
PATHS "${POSTGRESQL_SHARE_DIR}/extension")

if(POSTGIS_CONTROL)
file(READ ${POSTGIS_CONTROL} control_contents)
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" POSTGIS_VERSION ${control_contents})
set(POSTGIS_VERSION_STR "PostGIS ${POSTGIS_VERSION}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1" POSTGIS_VERSION_MAJOR ${POSTGIS_VERSION})
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\2" POSTGIS_VERSION_MINOR ${POSTGIS_VERSION})
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\3" POSTGIS_VERSION_MICRO ${POSTGIS_VERSION})
math(EXPR POSTGIS_VERSION_NUMBER "${POSTGIS_VERSION_MAJOR} * 10000 + ${POSTGIS_VERSION_MINOR} * 100 + ${POSTGIS_VERSION_MICRO}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(POSTGIS
FOUND_VAR POSTGIS_FOUND
REQUIRED_VARS POSTGIS_LIBRARY POSTGIS_CONTROL
VERSION_VAR POSTGIS_VERSION
FAIL_MESSAGE "Could NOT find PostGIS")

if(POSTGIS_FOUND)
mark_as_advanced(POSTGIS_LIBRARY POSTGIS_CONTROL POSTGIS_VERSION POSTGIS_VERSION_STR)
endif()

message(STATUS "POSTGRESQL_SHARE_DIR: ${POSTGRESQL_SHARE_DIR}")
message(STATUS "POSTGRESQL_DYNLIB_DIR: ${POSTGRESQL_DYNLIB_DIR}")
message(STATUS "POSTGIS_LIBRARY: ${POSTGIS_LIBRARY}")
message(STATUS "POSTGIS_CONTROL: ${POSTGIS_CONTROL}")
message(STATUS "POSTGIS_VERSION: ${POSTGIS_VERSION}")
message(STATUS "POSTGIS_VERSION_STR: ${POSTGIS_VERSION_STR}")
message(STATUS "POSTGIS_VERSION_NUMBER: ${POSTGIS_VERSION_NUMBER}")
Loading

0 comments on commit 5ac8802

Please sign in to comment.