<div dir="ltr">

<span style="font-size:12.8px;text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">The implementation I suggested is fully compatible with the current &&& semantics (and thus no<span> </span></span><span style="font-size:12.8px;text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">backward compatibility issues) but generalizes to the three new operators that are currently commented out.</span>

<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jul 30, 2018 at 3:32 PM, Paul Ramsey <span dir="ltr"><<a href="mailto:pramsey@cleverelephant.ca" target="_blank">pramsey@cleverelephant.ca</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I'm sure I initially implemented with just "relevant dimensions" and<br>
then switch, but I cannot for the life of my remember *why*. I know<br>
that changing the semantics of the &&& index are either a "no, never"<br>
thing, or a "only a 3.0" thing, so it might involves another operator<br>
or opclass for backwards compatibility reasons.<br>
<br>
P<br>
<div><div class="h5"><br>
On Mon, Jul 30, 2018 at 2:41 AM, Esteban Zimanyi <<a href="mailto:ezimanyi@ulb.ac.be">ezimanyi@ulb.ac.be</a>> wrote:<br>
><br>
> As a follow-up to my question, in mobility applications we often need to<br>
> compare geometries of mixed dimensions. Suppose that we have 2D geometries<br>
> representing, e.g., provinces, and 3D trajectories of moving objects (e.g.,<br>
> cars) where the temporal features are encoded in the M dimension. We would<br>
> need queries such as the following ones<br>
><br>
> -- Spatial-only query<br>
> SELECT * FROM Trips WHERE Trip &&& geometry 'Polygon((0 0,0 1,1 1,1 0,0<br>
> 0))';<br>
> -- Temporal-only query<br>
> SELECT * FROM Trips WHERE Trip &&& tsrange '[2001-01-01, 2001-01-05)';<br>
> -- Spatiotemporal query<br>
> SELECT * FROM Trips WHERE Trip &&& geometry 'LINESTRING M (0 0 978307200,1 1<br>
> 978393600,1 1 978652800)'<br>
><br>
> where the last geometry is equivalent to '[Point(0 0)@2001-01-01, Point(1<br>
> 1)@2001-01-02, Point(1 1)@2001-01-05)'. The above approach can be<br>
> generalized when we have 4D trajectories of flying objects (e.g., drones or<br>
> planes) with both Z and M. Notice that in such scenarios the four operators<br>
> &&& (overlaps), ~ (contains), @ (within), and ~= (equals) would be useful<br>
> and index support for these operators is essential.<br>
><br>
> The current approach followed in PostGIS is to extend the missing dimensions<br>
> of the arguments of the index predicate with a default value  +-infinity.<br>
> However, this approach only works for the overlaps and within operators.<br>
> When the missing dimensions are extended with +-infinity, the other<br>
> operators equals and contains will always evaluate to false, giving a wrong<br>
> result.<br>
><br>
> An easy way to cope with this issue is to **only** compare the common<br>
> dimensions of the left and right arguments, ignoring the missing dimensions.<br>
> This requires minor changes in three functions of the file<br>
> gserialized_gist_nd.c<br>
><br>
> /*<br>
> ** Overlapping GIDX box test.<br>
> **<br>
> ** Box(A) Overlaps Box(B) IFF for every common dimension d of both operands:<br>
> **   min(A,d) <= max(B,d) && max(A,d) => min(B,d)<br>
> **<br>
> ** Any missing dimension is ignored. Empty boxes never overlap.<br>
> */<br>
> bool gidx_overlaps(GIDX *a, GIDX *b)<br>
> {<br>
> int i, dims_a, dims_b;<br>
><br>
> POSTGIS_DEBUG(5, "entered function");<br>
><br>
> if ( (a == NULL) || (b == NULL) ) return false;<br>
><br>
> if ( gidx_is_unknown(a) || gidx_is_unknown(b) )<br>
> return false;<br>
><br>
> dims_a = GIDX_NDIMS(a);<br>
> dims_b = GIDX_NDIMS(b);<br>
> /* For all common dimensions min(a) > max(b) and min(b) > max(a) */<br>
> for ( i = 0; i < Min(dims_a, dims_b); i++ )<br>
> {<br>
> /* If the missing dimension was not padded with -+FLT_MAX */<br>
> if ( GIDX_GET_MAX(a,i) != FLT_MAX && GIDX_GET_MAX(b,i) != FLT_MAX )<br>
> if ( GIDX_GET_MIN(a,i) > GIDX_GET_MAX(b,i) )<br>
> return false;<br>
> if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(a,i) )<br>
> return false;<br>
> }<br>
><br>
> return true;<br>
> }<br>
><br>
> /*<br>
> ** Containment GIDX test.<br>
> **<br>
> ** Box(A) CONTAINS Box(B) IFF for every common dimension d of both operands:<br>
> **  (pt(A)LL < pt(B)LL) && (pt(A)UR > pt(B)UR)<br>
> **<br>
> ** Any missing dimension is ignored.<br>
> */<br>
> bool gidx_contains(GIDX *a, GIDX *b)<br>
> {<br>
> int i, dims_a, dims_b;<br>
><br>
> POSTGIS_DEBUG(5, "entered function");<br>
><br>
> if ( (a == NULL) || (b == NULL) ) return false;<br>
><br>
> if ( gidx_is_unknown(a) || gidx_is_unknown(b) )<br>
> return false;<br>
><br>
> dims_a = GIDX_NDIMS(a);<br>
> dims_b = GIDX_NDIMS(b);<br>
><br>
> /* For all common dimensions min(a) > min(b) and max(a) < max(b) */<br>
> for (i = 0; i < Min(dims_a, dims_b); i++)<br>
> {<br>
> /* If the missing dimension was not padded with -+FLT_MAX */<br>
> if ( GIDX_GET_MAX(a,i) != FLT_MAX && GIDX_GET_MAX(b,i) != FLT_MAX )<br>
> if ( GIDX_GET_MIN(a,i) > GIDX_GET_MIN(b,i) )<br>
> return false;<br>
> if ( GIDX_GET_MAX(a,i) < GIDX_GET_MAX(b,i) )<br>
> return false;<br>
> }<br>
><br>
> return true;<br>
> }<br>
><br>
> /*<br>
> ** Equality GIDX test.<br>
> **<br>
> ** Box(A) EQUALS Box(B) IFF for every common dimension d of both operands:<br>
> **   (pt(A)LL == pt(B)LL) && (pt(A)UR == pt(B)UR)<br>
> **<br>
> ** Any missing dimension is ignored.<br>
> */<br>
> bool gidx_equals(GIDX *a, GIDX *b)<br>
> {<br>
> uint32_t i;<br>
> int dims_a, dims_b;<br>
><br>
> POSTGIS_DEBUG(5, "entered function");<br>
><br>
> if ( (a == NULL) && (b == NULL) ) return true;<br>
> if ( (a == NULL) || (b == NULL) ) return false;<br>
><br>
> if ( gidx_is_unknown(a) && gidx_is_unknown(b) )<br>
> return true;<br>
><br>
> if ( gidx_is_unknown(a) || gidx_is_unknown(b) )<br>
> return false;<br>
><br>
> dims_a = GIDX_NDIMS(a);<br>
> dims_b = GIDX_NDIMS(b);<br>
><br>
> /* For all common dimensions min(a) == min(b), max(a) == max(b) */<br>
> for (i = 0; i < Min(dims_a, dims_b); i++)<br>
> {<br>
> /* If the missing dimension was not padded with -+FLT_MAX */<br>
> if ( GIDX_GET_MAX(a,i) != FLT_MAX && GIDX_GET_MAX(b,i) != FLT_MAX )<br>
> if ( GIDX_GET_MIN(a,i) != GIDX_GET_MIN(b,i) )<br>
> return false;<br>
> if ( GIDX_GET_MAX(a,i) != GIDX_GET_MAX(b,i) )<br>
> return false;<br>
> }<br>
> return true;<br>
> }<br>
><br>
> I have tested this approach and works perfectly. I can prepare a PR with the<br>
> patches and the regression tests.<br>
><br>
><br>
><br>
</div></div>> ______________________________<wbr>_________________<br>
> postgis-devel mailing list<br>
> <a href="mailto:postgis-devel@lists.osgeo.org">postgis-devel@lists.osgeo.org</a><br>
> <a href="https://lists.osgeo.org/mailman/listinfo/postgis-devel" rel="noreferrer" target="_blank">https://lists.osgeo.org/<wbr>mailman/listinfo/postgis-devel</a><br>
______________________________<wbr>_________________<br>
postgis-devel mailing list<br>
<a href="mailto:postgis-devel@lists.osgeo.org">postgis-devel@lists.osgeo.org</a><br>
<a href="https://lists.osgeo.org/mailman/listinfo/postgis-devel" rel="noreferrer" target="_blank">https://lists.osgeo.org/<wbr>mailman/listinfo/postgis-devel</a></blockquote></div><br></div>