static GBOX* parse_geohash(char *geohash, int precision) { GBOX *box = NULL; double lat[2], lon[2]; POSTGIS_DEBUG(2, "parse_geohash called."); if (NULL == geohash) { geohash_lwpgerror("invalid GeoHash representation", 2); } decode_geohash_bbox(geohash, lat, lon, precision); POSTGIS_DEBUGF(2, "ST_Box2dFromGeoHash sw: %.20f, %.20f", lon[0], lat[0]); POSTGIS_DEBUGF(2, "ST_Box2dFromGeoHash ne: %.20f, %.20f", lon[1], lat[1]); box = gbox_new(gflags(0, 0, 1)); box->xmin = lon[0]; box->ymin = lat[0]; box->xmax = lon[1]; box->ymax = lat[1]; POSTGIS_DEBUG(2, "parse_geohash finished."); return box; }
Datum gserialized_gist_penalty_2d(PG_FUNCTION_ARGS) { GISTENTRY *origentry = (GISTENTRY*) PG_GETARG_POINTER(0); GISTENTRY *newentry = (GISTENTRY*) PG_GETARG_POINTER(1); float *result = (float*) PG_GETARG_POINTER(2); BOX2DF *gbox_index_orig, *gbox_index_new; float size_union, size_orig; POSTGIS_DEBUG(4, "[GIST] 'penalty' function called"); gbox_index_orig = (BOX2DF*)DatumGetPointer(origentry->key); gbox_index_new = (BOX2DF*)DatumGetPointer(newentry->key); /* Drop out if we're dealing with null inputs. Shouldn't happen. */ if ( (gbox_index_orig == NULL) && (gbox_index_new == NULL) ) { POSTGIS_DEBUG(4, "[GIST] both inputs NULL! returning penalty of zero"); *result = 0.0; PG_RETURN_FLOAT8(*result); } /* Calculate the size difference of the boxes. */ size_union = box2df_union_size(gbox_index_orig, gbox_index_new); size_orig = box2df_size(gbox_index_orig); *result = size_union - size_orig; POSTGIS_DEBUGF(4, "[GIST] 'penalty', union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result); PG_RETURN_POINTER(result); }
static LWGEOM* parse_geojson_linestring(json_object *geojson, bool *hasz, int *root_srid) { LWGEOM *geom; POINTARRAY *pa; json_object* points = NULL; int i = 0; POSTGIS_DEBUG(2, "parse_geojson_linestring called."); points = findMemberByName( geojson, "coordinates" ); if ( ! points ) geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4); pa = ptarray_construct_empty(1, 0, 1); if( json_type_array == json_object_get_type( points ) ) { const int nPoints = json_object_array_length( points ); for(i = 0; i < nPoints; ++i) { json_object* coords = NULL; coords = json_object_array_get_idx( points, i ); parse_geojson_coord(coords, hasz, pa); } } geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa); POSTGIS_DEBUG(2, "parse_geojson_linestring finished."); return geom; }
/* ** Peak into a geography to find the bounding box. If the ** box is there, copy it out and return it. If not, calculate the box from the ** full geography and return the box based on that. If no box is available, ** return G_FAILURE, otherwise G_SUCCESS. */ int geography_gidx(GSERIALIZED *g, GIDX *gidx) { int result = G_SUCCESS; POSTGIS_DEBUG(4, "entered function"); POSTGIS_DEBUGF(4, "got flags %d", g->flags); if ( FLAGS_GET_BBOX(g->flags) && FLAGS_GET_GEODETIC(g->flags) ) { const size_t size = 2 * 3 * sizeof(float); POSTGIS_DEBUG(4, "copying box out of serialization"); memcpy(gidx->c, g->data, size); SET_VARSIZE(gidx, VARHDRSZ + size); } else { GBOX gbox; POSTGIS_DEBUG(4, "calculating new box from scratch"); if ( gserialized_calculate_gbox_geocentric_p(g, &gbox) == G_FAILURE ) { POSTGIS_DEBUG(4, "calculated null bbox, returning null"); return G_FAILURE; } result = gidx_from_gbox_p(gbox, gidx); } if ( result == G_SUCCESS ) { POSTGIS_DEBUGF(4, "got gidx %s", gidx_to_string(gidx)); } return result; }
Datum LWGEOM_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); int32 geom_typmod = -1; GSERIALIZED *geom; LWGEOM *lwgeom; if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) { geom_typmod = PG_GETARG_INT32(2); } lwgeom = lwgeom_from_wkb((uint8_t*)buf->data, buf->len, LW_PARSER_CHECK_ALL); if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom); /* Set cursor to the end of buffer (so the backend is happy) */ buf->cursor = buf->len; geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); if ( geom_typmod >= 0 ) { postgis_valid_typmod(geom, geom_typmod); POSTGIS_DEBUG(3, "typmod and geometry were consistent"); } else { POSTGIS_DEBUG(3, "typmod was -1"); } PG_RETURN_POINTER(geom); }
/** * Peak into a #GSERIALIZED datum to find the bounding box. If the * box is there, copy it out and return it. If not, calculate the box from the * full object and return the box based on that. If no box is available, * return #LW_FAILURE, otherwise #LW_SUCCESS. */ int gserialized_datum_get_gidx_p(Datum gsdatum, GIDX *gidx) { GSERIALIZED *gpart; int result = LW_SUCCESS; POSTGIS_DEBUG(4, "entered function"); /* ** The most info we need is the 8 bytes of serialized header plus the 32 bytes ** of floats necessary to hold the 8 floats of the largest XYZM index ** bounding box, so 40 bytes. */ gpart = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(gsdatum, 0, 40); POSTGIS_DEBUGF(4, "got flags %d", gpart->flags); /* Do we even have a serialized bounding box? */ if ( FLAGS_GET_BBOX(gpart->flags) ) { /* Yes! Copy it out into the GIDX! */ size_t size = gbox_serialized_size(gpart->flags); POSTGIS_DEBUG(4, "copying box out of serialization"); memcpy(gidx->c, gpart->data, size); /* if M is present but Z is not, pad Z and shift M */ if ( FLAGS_GET_M(gpart->flags) && ! FLAGS_GET_Z(gpart->flags) ) { size += 2 * sizeof(float); GIDX_SET_MIN(gidx,3,GIDX_GET_MIN(gidx,2)); GIDX_SET_MAX(gidx,3,GIDX_GET_MAX(gidx,2)); GIDX_SET_MIN(gidx,2,-1*FLT_MAX); GIDX_SET_MAX(gidx,2,FLT_MAX); } SET_VARSIZE(gidx, VARHDRSZ + size); result = LW_SUCCESS; } else { /* No, we need to calculate it from the full object. */ GSERIALIZED *g = (GSERIALIZED*)PG_DETOAST_DATUM(gsdatum); LWGEOM *lwgeom = lwgeom_from_gserialized(g); GBOX gbox; if ( lwgeom_calculate_gbox(lwgeom, &gbox) == LW_FAILURE ) { POSTGIS_DEBUG(4, "could not calculate bbox, returning failure"); lwgeom_free(lwgeom); return LW_FAILURE; } lwgeom_free(lwgeom); result = gidx_from_gbox_p(gbox, gidx); } if ( result == LW_SUCCESS ) { POSTGIS_DEBUGF(4, "got gidx %s", gidx_to_string(gidx)); } return result; }
Datum geography_gist_consistent(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); bool result; char gidxmem[GIDX_MAX_SIZE]; GIDX *query_gbox_index = (GIDX*)gidxmem; #if POSTGIS_PGSQL_VERSION >= 84 /* PostgreSQL 8.4 and later require the RECHECK flag to be set here, rather than being supplied as part of the operator class definition */ bool *recheck = (bool *) PG_GETARG_POINTER(4); /* We set recheck to false to avoid repeatedly pulling every "possibly matched" geometry out during index scans. For cases when the geometries are large, rechecking can make things twice as slow. */ *recheck = false; #endif POSTGIS_DEBUG(4, "[GIST] 'consistent' function called"); /* Quick sanity check on query argument. */ if ( DatumGetPointer(PG_GETARG_DATUM(1)) == NULL ) { POSTGIS_DEBUG(4, "[GIST] null query pointer (!?!), returning false"); PG_RETURN_BOOL(FALSE); /* NULL query! This is screwy! */ } /* Quick sanity check on entry key. */ if ( DatumGetPointer(entry->key) == NULL ) { POSTGIS_DEBUG(4, "[GIST] null index entry, returning false"); PG_RETURN_BOOL(FALSE); /* NULL entry! */ } /* Null box should never make this far. */ if ( geography_datum_gidx(PG_GETARG_DATUM(1), query_gbox_index) == G_FAILURE ) { POSTGIS_DEBUG(4, "[GIST] null query_gbox_index!"); PG_RETURN_BOOL(FALSE); } /* Treat leaf node tests different from internal nodes */ if (GIST_LEAF(entry)) { result = geography_gist_consistent_leaf( (GIDX*)DatumGetPointer(entry->key), query_gbox_index, strategy); } else { result = geography_gist_consistent_internal( (GIDX*)DatumGetPointer(entry->key), query_gbox_index, strategy); } PG_RETURN_BOOL(result); }
/* * return -1 iff point outside multipolygon * return 0 iff point on multipolygon boundary * return 1 iff point inside multipolygon */ int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point) { int i, j, result, in_ring; POINT2D pt; POSTGIS_DEBUG(2, "point_in_polygon called."); getPoint2d_p(point->point, 0, &pt); /* assume bbox short-circuit has already been attempted */ result = -1; for (j = 0; j < mpolygon->ngeoms; j++ ) { LWPOLY *polygon = mpolygon->geoms[j]; /* everything is outside of an empty polygon */ if ( polygon->nrings == 0 ) continue; in_ring = point_in_ring(polygon->rings[0], &pt); if ( in_ring == -1) /* outside the exterior ring */ { POSTGIS_DEBUG(3, "point_in_polygon: outside exterior ring."); continue; } if ( in_ring == 0 ) { return 0; } result = in_ring; for (i=1; i<polygon->nrings; i++) { in_ring = point_in_ring(polygon->rings[i], &pt); if (in_ring == 1) /* inside a hole => outside the polygon */ { POSTGIS_DEBUGF(3, "point_in_polygon: within hole %d.", i); result = -1; break; } if (in_ring == 0) /* on the edge of a hole */ { POSTGIS_DEBUGF(3, "point_in_polygon: on edge of hole %d.", i); return 0; } } if ( result != -1) { return result; } } return result; }
Datum lwgeom_lt(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); GBOX box1; GBOX box2; POSTGIS_DEBUG(2, "lwgeom_lt called"); if (gserialized_get_srid(geom1) != gserialized_get_srid(geom2)) { elog(BTREE_SRID_MISMATCH_SEVERITY, "Operation on two GEOMETRIES with different SRIDs\n"); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); PG_RETURN_NULL(); } POSTGIS_DEBUG(3, "lwgeom_lt passed getSRID test"); gserialized_get_gbox_p(geom1, &box1); gserialized_get_gbox_p(geom2, &box2); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); POSTGIS_DEBUG(3, "lwgeom_lt getbox2d_p passed"); if ( ! FPeq(box1.xmin , box2.xmin) ) { if (box1.xmin < box2.xmin) PG_RETURN_BOOL(TRUE); } if ( ! FPeq(box1.ymin , box2.ymin) ) { if (box1.ymin < box2.ymin) PG_RETURN_BOOL(TRUE); } if ( ! FPeq(box1.xmax , box2.xmax) ) { if (box1.xmax < box2.xmax) PG_RETURN_BOOL(TRUE); } if ( ! FPeq(box1.ymax , box2.ymax) ) { if (box1.ymax < box2.ymax) PG_RETURN_BOOL(TRUE); } PG_RETURN_BOOL(FALSE); }
static int CircTreePIP(const CIRC_NODE* tree1, const GSERIALIZED* g1, const POINT4D* in_point) { int tree1_type = gserialized_get_type(g1); GBOX gbox1; GEOGRAPHIC_POINT in_gpoint; POINT3D in_point3d; POSTGIS_DEBUGF(3, "tree1_type=%d", tree1_type); /* If the tree'ed argument is a polygon, do the P-i-P using the tree-based P-i-P */ if ( tree1_type == POLYGONTYPE || tree1_type == MULTIPOLYGONTYPE ) { POSTGIS_DEBUG(3, "tree is a polygon, using tree PiP"); /* Need a gbox to calculate an outside point */ if ( LW_FAILURE == gserialized_get_gbox_p(g1, &gbox1) ) { LWGEOM* lwgeom1 = lwgeom_from_gserialized(g1); POSTGIS_DEBUG(3, "unable to read gbox from gserialized, calculating from scratch"); lwgeom_calculate_gbox_geodetic(lwgeom1, &gbox1); lwgeom_free(lwgeom1); } /* Flip the candidate point into geographics */ geographic_point_init(in_point->x, in_point->y, &in_gpoint); geog2cart(&in_gpoint, &in_point3d); /* If the candidate isn't in the tree box, it's not in the tree area */ if ( ! gbox_contains_point3d(&gbox1, &in_point3d) ) { POSTGIS_DEBUG(3, "in_point3d is not inside the tree gbox, CircTreePIP returning FALSE"); return LW_FALSE; } /* The candidate point is in the box, so it *might* be inside the tree */ else { POINT2D pt2d_outside; /* latlon */ POINT2D pt2d_inside; pt2d_inside.x = in_point->x; pt2d_inside.y = in_point->y; /* Calculate a definitive outside point */ gbox_pt_outside(&gbox1, &pt2d_outside); POSTGIS_DEBUGF(3, "p2d_inside=POINT(%g %g) p2d_outside=POINT(%g %g)", pt2d_inside.x, pt2d_inside.y, pt2d_outside.x, pt2d_outside.y); /* Test the candidate point for strict containment */ POSTGIS_DEBUG(3, "calling circ_tree_contains_point for PiP test"); return circ_tree_contains_point(tree1, &pt2d_inside, &pt2d_outside, NULL); } } else { POSTGIS_DEBUG(3, "tree1 not polygonal, so CircTreePIP returning FALSE"); return LW_FALSE; } }
/** * Peak into a #GSERIALIZED datum to find the bounding box. If the * box is there, copy it out and return it. If not, calculate the box from the * full object and return the box based on that. If no box is available, * return #LW_FAILURE, otherwise #LW_SUCCESS. */ static int gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df) { GSERIALIZED *gpart; uint8_t flags; int result = LW_SUCCESS; POSTGIS_DEBUG(4, "entered function"); /* ** The most info we need is the 8 bytes of serialized header plus the ** of floats necessary to hold the bounding box. */ gpart = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(gsdatum, 0, 8 + sizeof(BOX2DF)); flags = gpart->flags; POSTGIS_DEBUGF(4, "got flags %d", gpart->flags); /* Do we even have a serialized bounding box? */ if ( FLAGS_GET_BBOX(flags) ) { /* Yes! Copy it out into the box! */ POSTGIS_DEBUG(4, "copying box out of serialization"); memcpy(box2df, gpart->data, sizeof(BOX2DF)); result = LW_SUCCESS; } else { /* No, we need to calculate it from the full object. */ GBOX gbox; GSERIALIZED *g = (GSERIALIZED*)PG_DETOAST_DATUM(gsdatum); LWGEOM *lwgeom = lwgeom_from_gserialized(g); if ( lwgeom_calculate_gbox(lwgeom, &gbox) == LW_FAILURE ) { POSTGIS_DEBUG(4, "could not calculate bbox, returning failure"); lwgeom_free(lwgeom); return LW_FAILURE; } lwgeom_free(lwgeom); result = box2df_from_gbox_p(&gbox, box2df); } if ( result == LW_SUCCESS ) { POSTGIS_DEBUGF(4, "got box2df %s", box2df_to_string(box2df)); } return result; }
Datum gserialized_gist_distance_2d(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0); BOX2DF query_box; BOX2DF *entry_box; StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); double distance; POSTGIS_DEBUG(4, "[GIST] 'distance' function called"); /* We are using '13' as the gist distance-betweeen-centroids strategy number * and '14' as the gist distance-between-boxes strategy number */ if ( strategy != 13 && strategy != 14 ) { elog(ERROR, "unrecognized strategy number: %d", strategy); PG_RETURN_FLOAT8(MAXFLOAT); } /* Null box should never make this far. */ if ( gserialized_datum_get_box2df_p(PG_GETARG_DATUM(1), &query_box) == LW_FAILURE ) { POSTGIS_DEBUG(4, "[GIST] null query_gbox_index!"); PG_RETURN_FLOAT8(MAXFLOAT); } /* Get the entry box */ entry_box = (BOX2DF*)DatumGetPointer(entry->key); /* Box-style distance test */ if ( strategy == 14 ) { distance = (double)box2df_distance(entry_box, &query_box); PG_RETURN_FLOAT8(distance); } /* Treat leaf node tests different from internal nodes */ if (GIST_LEAF(entry)) { /* Calculate distance to leaves */ distance = (double)box2df_distance_leaf_centroid(entry_box, &query_box); } else { /* Calculate distance for internal nodes */ distance = (double)box2df_distance_node_centroid(entry_box, &query_box); } PG_RETURN_FLOAT8(distance); }
/* Calculate the volume of the intersection of the boxes. */ static float gidx_inter_volume(GIDX *a, GIDX *b) { int i; float result; POSTGIS_DEBUG(5,"entered function"); if ( a == NULL || b == NULL ) { elog(ERROR, "gidx_inter_volume received a null argument"); return 0.0; } /* Ensure 'a' has the most dimensions. */ gidx_dimensionality_check(&a, &b); /* Initialize with minimal length of first dimension. */ result = Min(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Max(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0)); /* If they are disjoint (max < min) then return zero. */ if ( result < 0.0 ) return 0.0; /* Continue for remaining dimensions. */ for ( i = 1; i < GIDX_NDIMS(b); i++ ) { float width = Min(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Max(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)); if ( width < 0.0 ) return 0.0; /* Multiply by minimal length of remaining dimensions. */ result *= width; } POSTGIS_DEBUGF(5, "volume( %s intersection %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result); return result; }
Datum gserialized_gist_union_2d(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); int *sizep = (int *) PG_GETARG_POINTER(1); /* Size of the return value */ int numranges, i; BOX2DF *box_cur, *box_union; POSTGIS_DEBUG(4, "[GIST] 'union' function called"); numranges = entryvec->n; box_cur = (BOX2DF*) DatumGetPointer(entryvec->vector[0].key); box_union = box2df_copy(box_cur); for ( i = 1; i < numranges; i++ ) { box_cur = (BOX2DF*) DatumGetPointer(entryvec->vector[i].key); box2df_merge(box_union, box_cur); } *sizep = sizeof(BOX2DF); POSTGIS_DEBUGF(4, "[GIST] 'union', numranges(%i), pageunion %s", numranges, box2df_to_string(box_union)); PG_RETURN_POINTER(box_union); }
/* ** Equality GIDX test. ** ** Box(A) EQUALS Box(B) IFF (pt(A)LL == pt(B)LL) && (pt(A)UR == pt(B)UR) */ static bool gidx_equals(GIDX *a, GIDX *b) { int i; POSTGIS_DEBUG(5, "entered function"); if ( (a == NULL) && (b == NULL) ) return TRUE; if ( (a == NULL) || (b == NULL) ) return FALSE; /* Ensure 'a' has the most dimensions. */ gidx_dimensionality_check(&a, &b); /* For all shared dimensions min(a) == min(b), max(a) == max(b) */ for (i = 0; i < GIDX_NDIMS(b); i++) { if ( GIDX_GET_MIN(a,i) != GIDX_GET_MIN(b,i) ) return FALSE; if ( GIDX_GET_MAX(a,i) != GIDX_GET_MAX(b,i) ) return FALSE; } /* For all unshared dimensions min(a) == 0.0, max(a) == 0.0 */ for (i = GIDX_NDIMS(b); i < GIDX_NDIMS(a); i++) { if ( GIDX_GET_MIN(a,i) != 0.0 ) return FALSE; if ( GIDX_GET_MAX(a,i) != 0.0 ) return FALSE; } return TRUE; }
/* ** Overlapping GIDX box test. ** ** Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */ static bool gidx_overlaps(GIDX *a, GIDX *b) { int i; int ndims_b; POSTGIS_DEBUG(5, "entered function"); if ( (a == NULL) || (b == NULL) ) return FALSE; /* Ensure 'a' has the most dimensions. */ gidx_dimensionality_check(&a, &b); ndims_b = GIDX_NDIMS(b); /* compare within the dimensions of (b) */ for ( i = 0; i < ndims_b; i++ ) { if ( GIDX_GET_MIN(a,i) > GIDX_GET_MAX(b,i) ) return FALSE; if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(a,i) ) return FALSE; } /* compare to zero those dimensions in (a) absent in (b) */ for ( i = ndims_b; i < GIDX_NDIMS(a); i++ ) { if ( GIDX_GET_MIN(a,i) > 0.0 ) return FALSE; if ( GIDX_GET_MAX(a,i) < 0.0 ) return FALSE; } return TRUE; }
static float box2df_union_size(const BOX2DF *a, const BOX2DF *b) { float result; POSTGIS_DEBUG(5,"entered function"); if ( a == NULL && b == NULL ) { elog(ERROR, "box2df_union_size received two null arguments"); return 0.0; } if ( a == NULL ) return box2df_size(b); if ( b == NULL ) return box2df_size(a); result = ((double)Max(a->xmax,b->xmax) - (double)Min(a->xmin,b->xmin)) * ((double)Max(a->ymax,b->ymax) - (double)Min(a->ymin,b->ymin)); POSTGIS_DEBUGF(5, "union size of %s and %s is %.8g", box2df_to_string(a), box2df_to_string(b), result); return result; }
Datum LWGEOM_asText(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWGEOM *lwgeom; char *wkt; size_t wkt_size; text *result; POSTGIS_DEBUG(2, "Called."); geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); lwgeom = lwgeom_from_gserialized(geom); /* Write to WKT and free the geometry */ wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, &wkt_size); lwgeom_free(lwgeom); POSTGIS_DEBUGF(3, "WKT size = %d, WKT length = %d", wkt_size, strlen(wkt)); /* Write to text and free the WKT */ result = cstring2text(wkt); pfree(wkt); /* Return the text */ PG_FREE_IF_COPY(geom, 0); PG_RETURN_TEXT_P(result); }
Datum LWGEOM_from_text(PG_FUNCTION_ARGS) { text *wkttext = PG_GETARG_TEXT_P(0); char *wkt = text2cstring(wkttext); LWGEOM_PARSER_RESULT lwg_parser_result; GSERIALIZED *geom_result = NULL; LWGEOM *lwgeom; POSTGIS_DEBUG(2, "LWGEOM_from_text"); POSTGIS_DEBUGF(3, "wkt: [%s]", wkt); if (lwgeom_parse_wkt(&lwg_parser_result, wkt, LW_PARSER_CHECK_ALL) == LW_FAILURE) PG_PARSER_ERROR(lwg_parser_result); lwgeom = lwg_parser_result.geom; if ( lwgeom->srid != SRID_UNKNOWN ) { elog(WARNING, "OGC WKT expected, EWKT provided - use GeomFromEWKT() for this"); } /* read user-requested SRID if any */ if ( PG_NARGS() > 1 ) lwgeom_set_srid(lwgeom, PG_GETARG_INT32(1)); geom_result = geometry_serialize(lwgeom); lwgeom_parser_result_free(&lwg_parser_result); PG_RETURN_POINTER(geom_result); }
Datum geography_gist_union(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); int *sizep = (int *) PG_GETARG_POINTER(1); /* Size of the return value */ int numranges, i; GIDX *box_cur, *box_union; POSTGIS_DEBUG(4, "[GIST] 'union' function called"); numranges = entryvec->n; box_cur = (GIDX*) DatumGetPointer(entryvec->vector[0].key); box_union = gidx_copy(box_cur); for ( i = 1; i < numranges; i++ ) { box_cur = (GIDX*) DatumGetPointer(entryvec->vector[i].key); gidx_merge(&box_union, box_cur); } *sizep = VARSIZE(box_union); POSTGIS_DEBUGF(4, "[GIST] union called, numranges(%i), pageunion %s", numranges, gidx_to_string(box_union)); PG_RETURN_POINTER(box_union); }
static bool box2df_within(const BOX2DF *a, const BOX2DF *b) { if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */ POSTGIS_DEBUG(5, "entered function"); return box2df_contains(b,a); }
Datum LWGEOM_curve_segmentize(PG_FUNCTION_ARGS) { GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0); int32 perQuad = PG_GETARG_INT32(1); GSERIALIZED *ret; LWGEOM *igeom = NULL, *ogeom = NULL; POSTGIS_DEBUG(2, "LWGEOM_curve_segmentize called."); if (perQuad < 0) { elog(ERROR, "2nd argument must be positive."); PG_RETURN_NULL(); } POSTGIS_DEBUGF(3, "perQuad = %d", perQuad); igeom = lwgeom_from_gserialized(geom); ogeom = lwgeom_stroke(igeom, perQuad); lwgeom_free(igeom); if (ogeom == NULL) PG_RETURN_NULL(); ret = geometry_serialize(ogeom); lwgeom_free(ogeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(ret); }
/* * return 0 iff point outside polygon or on boundary * return 1 iff point inside polygon */ int point_in_polygon_rtree(RTREE_NODE **root, int ringCount, LWPOINT *point) { int i; POINT2D pt; POSTGIS_DEBUGF(2, "point_in_polygon called for %p %d %p.", root, ringCount, point); getPoint2d_p(point->point, 0, &pt); /* assume bbox short-circuit has already been attempted */ if (point_in_ring_rtree(root[0], &pt) != 1) { POSTGIS_DEBUG(3, "point_in_polygon_rtree: outside exterior ring."); return 0; } for (i=1; i<ringCount; i++) { if (point_in_ring_rtree(root[i], &pt) != -1) { POSTGIS_DEBUGF(3, "point_in_polygon_rtree: within hole %d.", i); return 0; } } return 1; }
/* ** Where the picksplit algorithm cannot find any basis for splitting one way ** or another, we simply split the overflowing node in half. */ static void geography_gist_picksplit_fallback(GistEntryVector *entryvec, GIST_SPLITVEC *v) { OffsetNumber i, maxoff; GIDX *unionL = NULL; GIDX *unionR = NULL; int nbytes; POSTGIS_DEBUG(4, "[GIST] in fallback picksplit function"); maxoff = entryvec->n - 1; nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber*) palloc(nbytes); v->spl_right = (OffsetNumber*) palloc(nbytes); v->spl_nleft = v->spl_nright = 0; for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { GIDX *cur = (GIDX*)DatumGetPointer(entryvec->vector[i].key); if (i <= (maxoff - FirstOffsetNumber + 1) / 2) { v->spl_left[v->spl_nleft] = i; if (unionL == NULL) { unionL = gidx_copy(cur); } else { gidx_merge(&unionL, cur); } v->spl_nleft++; } else { v->spl_right[v->spl_nright] = i; if (unionR == NULL) { unionR = gidx_copy(cur); } else { gidx_merge(&unionR, cur); } v->spl_nright++; } } if (v->spl_ldatum_exists) gidx_merge(&unionL, (GIDX*)DatumGetPointer(v->spl_ldatum)); v->spl_ldatum = PointerGetDatum(unionL); if (v->spl_rdatum_exists) gidx_merge(&unionR, (GIDX*)DatumGetPointer(v->spl_rdatum)); v->spl_rdatum = PointerGetDatum(unionR); v->spl_ldatum_exists = v->spl_rdatum_exists = false; }
/* * return -1 if point outside polygon * return 0 if point on boundary * return 1 if point inside polygon * * Expected **root order is each exterior ring followed by its holes, eg. EIIEIIEI */ int point_in_multipolygon_rtree(RTREE_NODE **root, int polyCount, int *ringCounts, LWPOINT *point) { int i, p, r, in_ring; POINT2D pt; int result = -1; POSTGIS_DEBUGF(2, "point_in_multipolygon_rtree called for %p %d %p.", root, polyCount, point); getPoint2d_p(point->point, 0, &pt); /* assume bbox short-circuit has already been attempted */ i = 0; /* the current index into the root array */ /* is the point inside any of the sub-polygons? */ for ( p = 0; p < polyCount; p++ ) { in_ring = point_in_ring_rtree(root[i], &pt); POSTGIS_DEBUGF(4, "point_in_multipolygon_rtree: exterior ring (%d), point_in_ring returned %d", p, in_ring); if ( in_ring == -1 ) /* outside the exterior ring */ { POSTGIS_DEBUG(3, "point_in_multipolygon_rtree: outside exterior ring."); } else if ( in_ring == 0 ) /* on the boundary */ { POSTGIS_DEBUGF(3, "point_in_multipolygon_rtree: on edge of exterior ring %d", p); return 0; } else { result = in_ring; for(r=1; r<ringCounts[p]; r++) { in_ring = point_in_ring_rtree(root[i+r], &pt); POSTGIS_DEBUGF(4, "point_in_multipolygon_rtree: interior ring (%d), point_in_ring returned %d", r, in_ring); if (in_ring == 1) /* inside a hole => outside the polygon */ { POSTGIS_DEBUGF(3, "point_in_multipolygon_rtree: within hole %d of exterior ring %d", r, p); result = -1; break; } if (in_ring == 0) /* on the edge of a hole */ { POSTGIS_DEBUGF(3, "point_in_multipolygon_rtree: on edge of hole %d of exterior ring %d", r, p); return 0; } } /* if we have a positive result, we can short-circuit and return it */ if ( result != -1) { return result; } } /* increment the index by the total number of rings in the sub-poly */ /* we do this here in case we short-cutted out of the poly before looking at all the rings */ i += ringCounts[p]; } return result; /* -1 = outside, 0 = boundary, 1 = inside */ }
Datum gserialized_contains_2d(PG_FUNCTION_ARGS) { POSTGIS_DEBUG(3, "entered function"); if ( gserialized_datum_predicate_2d(PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), box2df_contains) == LW_TRUE ) PG_RETURN_BOOL(TRUE); PG_RETURN_BOOL(FALSE); }
Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; LWGEOM_INSPECTED *inspected; LWLINE *line = NULL; POINTARRAY *pts; LWPOINT *point; PG_LWGEOM *result; int i, type; POSTGIS_DEBUG(2, "LWGEOM_startpoint_linestring called."); geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); /* * Curved polygons and compound curves are both collections * that should not be traversed looking for linestrings. */ type = lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]); if (type == CURVEPOLYTYPE || type == COMPOUNDTYPE) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } inspected = lwgeom_inspect(SERIALIZED_FORM(geom)); for (i=0; i<inspected->ngeometries; i++) { line = lwgeom_getline_inspected(inspected, i); if ( line ) break; } if ( line == NULL ) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } /* Ok, now we have a line. */ /* Construct a point array */ pts = pointArray_construct(getPoint_internal(line->points, 0), TYPE_HASZ(line->type), TYPE_HASM(line->type), 1); lwgeom_release((LWGEOM *)line); /* Construct an LWPOINT */ point = lwpoint_construct(pglwgeom_getSRID(geom), NULL, pts); /* Construct a PG_LWGEOM */ result = pglwgeom_serialize((LWGEOM *)point); lwgeom_release((LWGEOM *)point); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
static uint8_t gserialized_datum_get_flags(Datum gsdatum) { GSERIALIZED *gpart; POSTGIS_DEBUG(4, "entered function"); gpart = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(gsdatum, 0, 40); POSTGIS_DEBUGF(4, "got flags %d", gpart->flags); return gpart->flags; }
GSERIALIZED* gserialized_geography_from_lwgeom(LWGEOM *lwgeom, int32 geog_typmod) { GSERIALIZED *g_ser = NULL; /* Set geodetic flag */ lwgeom_set_geodetic(lwgeom, true); /* Check that this is a type we can handle */ geography_valid_type(lwgeom->type); /* Check that the coordinates are in range */ if ( lwgeom_check_geodetic(lwgeom) == LW_FALSE ) { if ( (! lwgeom_nudge_geodetic(lwgeom)) || lwgeom_check_geodetic(lwgeom) == LW_FALSE ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Coordinate values are out of range [-180 -90, 180 90] for GEOGRAPHY type" ))); } } /* Force default SRID to the default */ if ( (int)lwgeom->srid <= 0 ) lwgeom->srid = SRID_DEFAULT; /* ** Serialize our lwgeom and set the geodetic flag so subsequent ** functions do the right thing. */ g_ser = geography_serialize(lwgeom); /* Check for typmod agreement */ if ( geog_typmod >= 0 ) { postgis_valid_typmod(g_ser, geog_typmod); POSTGIS_DEBUG(3, "typmod and geometry were consistent"); } else { POSTGIS_DEBUG(3, "typmod was -1"); } return g_ser; }
Datum geography_gist_penalty(PG_FUNCTION_ARGS) { GISTENTRY *origentry = (GISTENTRY*) PG_GETARG_POINTER(0); GISTENTRY *newentry = (GISTENTRY*) PG_GETARG_POINTER(1); float *result = (float*) PG_GETARG_POINTER(2); GIDX *gbox_index_orig, *gbox_index_new; float size_union, size_orig; POSTGIS_DEBUG(4, "[GIST] 'penalty' function called"); gbox_index_orig = (GIDX*)DatumGetPointer(origentry->key); gbox_index_new = (GIDX*)DatumGetPointer(newentry->key); /* Drop out if we're dealing with null inputs. Shouldn't happen. */ if ( (gbox_index_orig == NULL) && (gbox_index_new == NULL) ) { POSTGIS_DEBUG(4, "[GIST] both inputs NULL! returning penalty of zero"); *result = 0.0; PG_RETURN_FLOAT8(*result); } /* Calculate the size difference of the boxes (volume difference in this case). */ size_union = gidx_union_volume(gbox_index_orig, gbox_index_new); size_orig = gidx_volume(gbox_index_orig); *result = size_union - size_orig; /* All things being equal, we prefer to expand small boxes rather than large boxes. NOTE: This code seemed to be causing badly balanced trees to be built and therefore has been commented out. Not sure why it didn't work, but it didn't. if( FP_IS_ZERO(*result) ) if( FP_IS_ZERO(size_orig) ) *result = 0.0; else *result = 1.0 - (1.0/(1.0 + size_orig)); else *result += 1.0; */ POSTGIS_DEBUGF(4, "[GIST] union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result); PG_RETURN_POINTER(result); }