homework-jianmu/source/libs/geometry/src/geosWrapper.c

425 lines
16 KiB
C

/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "geosWrapper.h"
#include "tdef.h"
#include "types.h"
typedef char (*_geosRelationFunc_t)(GEOSContextHandle_t handle, const GEOSGeometry *g1, const GEOSGeometry *g2);
typedef char (*_geosPreparedRelationFunc_t)(GEOSContextHandle_t handle, const GEOSPreparedGeometry *pg1, const GEOSGeometry *g2);
void geosFreeBuffer(void *buffer) {
if (buffer) {
GEOSFree_r(getThreadLocalGeosCtx()->handle, buffer);
}
}
void geosErrMsgeHandler(const char *errMsg, void *userData) {
char* targetErrMsg = userData;
snprintf(targetErrMsg, 512, "%s", errMsg);
}
int32_t initCtxMakePoint() {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
if (geosCtx->handle == NULL) {
geosCtx->handle = GEOS_init_r();
if (geosCtx->handle == NULL) {
return code;
}
GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
}
if (geosCtx->WKBWriter == NULL) {
geosCtx->WKBWriter = GEOSWKBWriter_create_r(geosCtx->handle);
if (geosCtx->WKBWriter == NULL) {
return code;
}
}
return TSDB_CODE_SUCCESS;
}
// outputWKT is a zero ending string
// need to call geosFreeBuffer(*outputGeom) later
int32_t doMakePoint(double x, double y, unsigned char **outputGeom, size_t *size) {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
GEOSGeometry *geom = NULL;
unsigned char *wkb = NULL;
geom = GEOSGeom_createPointFromXY_r(geosCtx->handle, x, y);
if (geom == NULL) {
code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
goto _exit;
}
wkb = GEOSWKBWriter_write_r(geosCtx->handle, geosCtx->WKBWriter, geom, size);
if (wkb == NULL) {
goto _exit;
}
*outputGeom = wkb;
code = TSDB_CODE_SUCCESS;
_exit:
if (geom) {
GEOSGeom_destroy_r(geosCtx->handle, geom);
geom = NULL;
}
return code;
}
static int initWktRegex(pcre2_code **ppRegex, pcre2_match_data **ppMatchData) {
int ret = 0;
char *wktPatternWithSpace = taosMemoryCalloc(4, 1024);
sprintf(
wktPatternWithSpace,
"^( *)point( *)z?m?( *)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *)\\)))|linestring( *)z?m?( "
"*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))|polygon( *)z?m?( "
"*)((empty)|(\\(( *)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
"*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( "
"*)\\)))|multipoint( *)z?m?( *)((empty)|(\\(( "
"*)((([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}|((empty)|(\\(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *)\\))))(( *)(,)( "
"*)((([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}|((empty)|(\\(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *)\\))))( *))*( "
"*)\\)))|multilinestring( *)z?m?( *)((empty)|(\\(( *)((empty)|(\\(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
"*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( "
"*)\\)))|multipolygon( *)z?m?( *)((empty)|(\\(( *)((empty)|(\\(( *)((empty)|(\\(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
"*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( *)\\)))(( *)(,)( "
"*)((empty)|(\\(( *)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
"*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( *)\\)))( *))*( "
"*)\\)))|(GEOCOLLECTION\\((?R)(( *)(,)( *)(?R))*( *)\\))( *)$");
ret = doRegComp(ppRegex, ppMatchData, wktPatternWithSpace);
taosMemoryFree(wktPatternWithSpace);
return ret;
}
int32_t initCtxGeomFromText() {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
if (geosCtx->handle == NULL) {
geosCtx->handle = GEOS_init_r();
if (geosCtx->handle == NULL) {
return code;
}
GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
}
if (geosCtx->WKTReader == NULL) {
geosCtx->WKTReader = GEOSWKTReader_create_r(geosCtx->handle);
if (geosCtx->WKTReader == NULL) {
return code;
}
}
if (geosCtx->WKBWriter == NULL) {
geosCtx->WKBWriter = GEOSWKBWriter_create_r(geosCtx->handle);
if (geosCtx->WKBWriter == NULL) {
return code;
}
}
if (geosCtx->WKTRegex == NULL) {
if (initWktRegex(&geosCtx->WKTRegex, &geosCtx->WKTMatchData) != 0) return code;
}
return TSDB_CODE_SUCCESS;
}
// inputWKT is a zero ending string
// need to call geosFreeBuffer(*outputGeom) later
int32_t doGeomFromText(const char *inputWKT, unsigned char **outputGeom, size_t *size) {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
GEOSGeometry *geom = NULL;
unsigned char *wkb = NULL;
if (doRegExec(inputWKT, geosCtx->WKTRegex, geosCtx->WKTMatchData) != 0) {
code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
goto _exit;
}
geom = GEOSWKTReader_read_r(geosCtx->handle, geosCtx->WKTReader, inputWKT);
if (geom == NULL) {
code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
goto _exit;
}
wkb = GEOSWKBWriter_write_r(geosCtx->handle, geosCtx->WKBWriter, geom, size);
if (wkb == NULL) {
goto _exit;
}
*outputGeom = wkb;
code = TSDB_CODE_SUCCESS;
_exit:
if (geom) {
GEOSGeom_destroy_r(geosCtx->handle, geom);
geom = NULL;
}
return code;
}
int32_t initCtxAsText() {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
if (geosCtx->handle == NULL) {
geosCtx->handle = GEOS_init_r();
if (geosCtx->handle == NULL) {
return code;
}
GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
}
if (geosCtx->WKBReader == NULL) {
geosCtx->WKBReader = GEOSWKBReader_create_r(geosCtx->handle);
if (geosCtx->WKBReader == NULL) {
return code;
}
}
if (geosCtx->WKTWriter == NULL) {
geosCtx->WKTWriter = GEOSWKTWriter_create_r(geosCtx->handle);
if (geosCtx->WKTWriter) {
GEOSWKTWriter_setRoundingPrecision_r(geosCtx->handle, geosCtx->WKTWriter, 6);
GEOSWKTWriter_setTrim_r(geosCtx->handle, geosCtx->WKTWriter, 0);
} else {
return code;
}
}
return TSDB_CODE_SUCCESS;
}
// outputWKT is a zero ending string
// need to call geosFreeBuffer(*outputWKT) later
int32_t doAsText(const unsigned char *inputGeom, size_t size, char **outputWKT) {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
GEOSGeometry *geom = NULL;
unsigned char *wkt = NULL;
geom = GEOSWKBReader_read_r(geosCtx->handle, geosCtx->WKBReader, inputGeom, size);
if (geom == NULL) {
code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
goto _exit;
}
wkt = GEOSWKTWriter_write_r(geosCtx->handle, geosCtx->WKTWriter, geom);
if (wkt == NULL) {
code = TSDB_CODE_MSG_DECODE_ERROR;
goto _exit;
}
*outputWKT = wkt;
code = TSDB_CODE_SUCCESS;
_exit:
if (geom) {
GEOSGeom_destroy_r(geosCtx->handle, geom);
geom = NULL;
}
return code;
}
int32_t initCtxRelationFunc() {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
if (geosCtx->handle == NULL) {
geosCtx->handle = GEOS_init_r();
if (geosCtx->handle == NULL) {
return code;
}
GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
}
if (geosCtx->WKBReader == NULL) {
geosCtx->WKBReader = GEOSWKBReader_create_r(geosCtx->handle);
if (geosCtx->WKBReader == NULL) {
return code;
}
}
return TSDB_CODE_SUCCESS;
}
int32_t doGeosRelation(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res,
_geosRelationFunc_t relationFn,
_geosRelationFunc_t swappedRelationFn,
_geosPreparedRelationFunc_t preparedRelationFn,
_geosPreparedRelationFunc_t swappedPreparedRelationFn) {
int32_t code = TSDB_CODE_FAILED;
SGeosContext* geosCtx = getThreadLocalGeosCtx();
if (!preparedGeom1) {
if (!swapped) {
ASSERT(relationFn);
*res = relationFn(geosCtx->handle, geom1, geom2);
}
else {
ASSERT(swappedRelationFn);
*res = swappedRelationFn(geosCtx->handle, geom1, geom2);
}
}
else {
if (!swapped) {
ASSERT(preparedRelationFn);
*res = preparedRelationFn(geosCtx->handle, preparedGeom1, geom2);
}
else {
ASSERT(swappedPreparedRelationFn);
*res = swappedPreparedRelationFn(geosCtx->handle, preparedGeom1, geom2);
}
}
code = TSDB_CODE_SUCCESS;
return code;
}
int32_t doIntersects(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res) {
return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res,
GEOSIntersects_r, GEOSIntersects_r, GEOSPreparedIntersects_r, GEOSPreparedIntersects_r);
}
int32_t doEquals(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res) {
return doGeosRelation(geom1, NULL, geom2, swapped, res,
GEOSEquals_r, GEOSEquals_r, NULL, NULL); // no prepared version for eguals()
}
int32_t doTouches(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res) {
return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res,
GEOSTouches_r, GEOSTouches_r, GEOSPreparedTouches_r, GEOSPreparedTouches_r);
}
int32_t doCovers(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res) {
return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res,
GEOSCovers_r, GEOSCoveredBy_r, GEOSPreparedCovers_r, GEOSPreparedCoveredBy_r);
}
int32_t doContains(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res) {
return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res,
GEOSContains_r, GEOSWithin_r, GEOSPreparedContains_r, GEOSPreparedWithin_r);
}
int32_t doContainsProperly(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res) {
return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res,
NULL, NULL, GEOSPreparedContainsProperly_r, NULL);
}
// input is with VARSTR format
// need to call destroyGeometry(outputGeom, outputPreparedGeom) later
int32_t readGeometry(const unsigned char *input, GEOSGeometry **outputGeom, const GEOSPreparedGeometry **outputPreparedGeom) {
SGeosContext* geosCtx = getThreadLocalGeosCtx();
ASSERT(outputGeom); //it is not allowed if outputGeom is NULL
*outputGeom = NULL;
if (outputPreparedGeom) { //it means not to generate PreparedGeometry if outputPreparedGeom is NULL
*outputPreparedGeom = NULL;
}
if (varDataLen(input) == 0) { //empty value
return TSDB_CODE_SUCCESS;
}
*outputGeom = GEOSWKBReader_read_r(geosCtx->handle, geosCtx->WKBReader, varDataVal(input), varDataLen(input));
if (*outputGeom == NULL) {
return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
}
if (outputPreparedGeom) {
*outputPreparedGeom = GEOSPrepare_r(geosCtx->handle, *outputGeom);
if (*outputPreparedGeom == NULL) {
return TSDB_CODE_FAILED;
}
}
return TSDB_CODE_SUCCESS;
}
void destroyGeometry(GEOSGeometry **geom, const GEOSPreparedGeometry **preparedGeom) {
SGeosContext* geosCtx = getThreadLocalGeosCtx();
if (preparedGeom && *preparedGeom) {
GEOSPreparedGeom_destroy_r(geosCtx->handle, *preparedGeom);
*preparedGeom = NULL;
}
if (geom && *geom) {
GEOSGeom_destroy_r(geosCtx->handle, *geom);
*geom = NULL;
}
}