<div dir="ltr"><div class="gmail_quote"><br><div dir="ltr"><div><div><div>As a follow-up to my question, in mobility applications we often need to compare geometries of mixed dimensions. Suppose that we have 2D geometries representing, e.g., provinces, and 3D trajectories of moving objects (e.g., cars) where the temporal features are encoded in the M dimension. We would need queries such as the following ones</div><div><br></div><div>-- Spatial-only query</div><div>SELECT * FROM Trips WHERE Trip &&& geometry 'Polygon((0 0,0 1,1 1,1 0,0 0))';</div><div>-- Temporal-only query</div><div>SELECT * FROM Trips WHERE Trip &&& tsrange '[2001-01-01, 2001-01-05)';</div><div>-- Spatiotemporal query</div><div>SELECT * FROM Trips WHERE Trip &&& geometry 'LINESTRING M (0 0 978307200,1 1 978393600,1 1 978652800)'</div><div><br></div><div>where the last geometry is equivalent to '[Point(0 0)@2001-01-01, Point(1 1)@2001-01-02, Point(1 1)@2001-01-05)'. The above approach can be generalized when we have 4D trajectories of flying objects (e.g., drones or planes) with both Z and M. Notice that in such scenarios the four operators &&& (overlaps), ~ (contains), @ (within), and ~= (equals) would be useful and index support for these operators is essential.</div><div><br></div><div>The current approach followed in PostGIS is to extend the missing dimensions of the arguments of the index predicate with a default value  +-infinity. However, this approach only works for the overlaps and within operators. When the missing dimensions are extended with 

<span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">+-infinity</span>, the other operators equals and contains will always evaluate to false, giving a wrong result.</div><div><br></div><div>An easy way to cope with this issue is to **only** compare the common dimensions of the left and right arguments, ignoring the missing dimensions. This requires minor changes in three functions of the file gserialized_gist_nd.c</div><div><br></div><div>/*</div><div>** Overlapping GIDX box test.</div><div>**</div><div>** Box(A) Overlaps Box(B) IFF for every common dimension d of both operands:</div><div>**   min(A,d) <= max(B,d) && max(A,d) => min(B,d)</div><div>**</div><div>** Any missing dimension is ignored. Empty boxes never overlap.</div><div>*/</div><div>bool gidx_overlaps(GIDX *a, GIDX *b)</div><div>{</div><div><span style="white-space:pre-wrap">  </span>int i, dims_a, dims_b;</div><div><br></div><div><span style="white-space:pre-wrap">  </span>POSTGIS_DEBUG(5, "entered function");</div><div><br></div><div><span style="white-space:pre-wrap"> </span>if ( (a == NULL) || (b == NULL) ) return false;</div><div><br></div><div><span style="white-space:pre-wrap"> </span>if ( gidx_is_unknown(a) || gidx_is_unknown(b) )</div><div><span style="white-space:pre-wrap">          </span>return false;</div><div><br></div><div><span style="white-space:pre-wrap">   </span>dims_a = GIDX_NDIMS(a);</div><div><span style="white-space:pre-wrap">  </span>dims_b = GIDX_NDIMS(b);</div><div><span style="white-space:pre-wrap">  </span></div><div><span style="white-space:pre-wrap"> </span>/* For all common dimensions min(a) > max(b) and min(b) > max(a) */</div><div><span style="white-space:pre-wrap">        </span>for ( i = 0; i < Min(dims_a, dims_b); i++ )</div><div><span style="white-space:pre-wrap">   </span>{</div><div><span style="white-space:pre-wrap">                </span>/* If the missing dimension was not padded with -+FLT_MAX */</div><div><span style="white-space:pre-wrap">             </span>if ( GIDX_GET_MAX(a,i) != FLT_MAX && GIDX_GET_MAX(b,i) != FLT_MAX )</div><div><span style="white-space:pre-wrap">                      </span>if ( GIDX_GET_MIN(a,i) > GIDX_GET_MAX(b,i) )</div><div><span style="white-space:pre-wrap">                          </span>return false;</div><div><span style="white-space:pre-wrap">                    </span>if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(a,i) )</div><div><span style="white-space:pre-wrap">                          </span>return false;</div><div><span style="white-space:pre-wrap">    </span>}</div><div><br></div><div><span style="white-space:pre-wrap">       </span>return true;</div><div>}</div><div><br></div><div>/*</div><div>** Containment GIDX test.</div><div>**</div><div>** Box(A) CONTAINS Box(B) IFF for every common dimension d of both operands:</div><div>**  (pt(A)LL < pt(B)LL) && (pt(A)UR > pt(B)UR)</div><div>**</div><div>** Any missing dimension is ignored.</div><div>*/</div><div>bool gidx_contains(GIDX *a, GIDX *b)</div><div>{</div><div><span style="white-space:pre-wrap">   </span>int i, dims_a, dims_b;</div><div><br></div><div><span style="white-space:pre-wrap">  </span>POSTGIS_DEBUG(5, "entered function");</div><div><br></div><div><span style="white-space:pre-wrap"> </span>if ( (a == NULL) || (b == NULL) ) return false;</div><div><br></div><div><span style="white-space:pre-wrap"> </span>if ( gidx_is_unknown(a) || gidx_is_unknown(b) )</div><div><span style="white-space:pre-wrap">          </span>return false;</div><div><br></div><div><span style="white-space:pre-wrap">   </span>dims_a = GIDX_NDIMS(a);</div><div><span style="white-space:pre-wrap">  </span>dims_b = GIDX_NDIMS(b);</div><div><br></div><div><span style="white-space:pre-wrap"> </span>/* For all common dimensions min(a) > min(b) and max(a) < max(b) */</div><div><span style="white-space:pre-wrap">        </span>for (i = 0; i < Min(dims_a, dims_b); i++)</div><div><span style="white-space:pre-wrap">     </span>{</div><div><span style="white-space:pre-wrap">                </span>/* If the missing dimension was not padded with -+FLT_MAX */</div><div><span style="white-space:pre-wrap">             </span>if ( GIDX_GET_MAX(a,i) != FLT_MAX && GIDX_GET_MAX(b,i) != FLT_MAX )</div><div><span style="white-space:pre-wrap">                      </span>if ( GIDX_GET_MIN(a,i) > GIDX_GET_MIN(b,i) )</div><div><span style="white-space:pre-wrap">                          </span>return false;</div><div><span style="white-space:pre-wrap">                    </span>if ( GIDX_GET_MAX(a,i) < GIDX_GET_MAX(b,i) )</div><div><span style="white-space:pre-wrap">                          </span>return false;</div><div><span style="white-space:pre-wrap">    </span>}</div><div><br></div><div><span style="white-space:pre-wrap">       </span>return true;</div><div>}</div><div><br></div><div>/*</div><div>** Equality GIDX test.</div><div>**</div><div>** Box(A) EQUALS Box(B) IFF for every common dimension d of both operands:</div><div>**   (pt(A)LL == pt(B)LL) && (pt(A)UR == pt(B)UR)</div><div>**</div><div>** Any missing dimension is ignored.</div><div>*/</div><div>bool gidx_equals(GIDX *a, GIDX *b)</div><div>{</div><div><span style="white-space:pre-wrap">    </span>uint32_t i;</div><div><span style="white-space:pre-wrap">      </span>int dims_a, dims_b;</div><div><br></div><div><span style="white-space:pre-wrap">     </span>POSTGIS_DEBUG(5, "entered function");</div><div><br></div><div><span style="white-space:pre-wrap"> </span>if ( (a == NULL) && (b == NULL) ) return true;</div><div><span style="white-space:pre-wrap">   </span>if ( (a == NULL) || (b == NULL) ) return false;</div><div><br></div><div><span style="white-space:pre-wrap"> </span>if ( gidx_is_unknown(a) && gidx_is_unknown(b) )</div><div><span style="white-space:pre-wrap">          </span>return true;</div><div><br></div><div><span style="white-space:pre-wrap">    </span>if ( gidx_is_unknown(a) || gidx_is_unknown(b) )</div><div><span style="white-space:pre-wrap">          </span>return false;</div><div><br></div><div><span style="white-space:pre-wrap">   </span>dims_a = GIDX_NDIMS(a);</div><div><span style="white-space:pre-wrap">  </span>dims_b = GIDX_NDIMS(b);</div><div><br></div><div><span style="white-space:pre-wrap"> </span>/* For all common dimensions min(a) == min(b), max(a) == max(b) */</div><div><span style="white-space:pre-wrap">       </span>for (i = 0; i < Min(dims_a, dims_b); i++)</div><div><span style="white-space:pre-wrap">     </span>{</div><div><span style="white-space:pre-wrap">                </span>/* If the missing dimension was not padded with -+FLT_MAX */</div><div><span style="white-space:pre-wrap">             </span>if ( GIDX_GET_MAX(a,i) != FLT_MAX && GIDX_GET_MAX(b,i) != FLT_MAX )</div><div><span style="white-space:pre-wrap">                      </span>if ( GIDX_GET_MIN(a,i) != GIDX_GET_MIN(b,i) )</div><div><span style="white-space:pre-wrap">                            </span>return false;</div><div><span style="white-space:pre-wrap">                    </span>if ( GIDX_GET_MAX(a,i) != GIDX_GET_MAX(b,i) )</div><div><span style="white-space:pre-wrap">                            </span>return false;</div><div><span style="white-space:pre-wrap">    </span>}</div><div><span style="white-space:pre-wrap">        </span>return true;</div><div>}</div><div><br></div><div>I have tested this approach and works perfectly. I can prepare a PR with the patches and the regression tests.</div><div><br></div><div><br></div></div></div></div></div></div>