Skip to content

Commit

Permalink
Improve isSimple function
Browse files Browse the repository at this point in the history
  • Loading branch information
estebanzimanyi committed Jun 26, 2024
1 parent 15e62af commit 9918ed5
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 39 deletions.
2 changes: 1 addition & 1 deletion meos/include/meos.h
Original file line number Diff line number Diff line change
Expand Up @@ -1944,7 +1944,7 @@ extern bool tpoint_direction(const Temporal *temp, double *result);
extern Temporal *tpoint_get_x(const Temporal *temp);
extern Temporal *tpoint_get_y(const Temporal *temp);
extern Temporal *tpoint_get_z(const Temporal *temp);
extern bool tpoint_is_simple(const Temporal *temp);
extern bool tpoint_is_simple(const Temporal *temp, bool *result);
extern double tpoint_length(const Temporal *temp);
extern Temporal *tpoint_speed(const Temporal *temp);
extern int tpoint_srid(const Temporal *temp);
Expand Down
4 changes: 2 additions & 2 deletions meos/include/meos_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,14 +942,14 @@ extern int tpointinst_srid(const TInstant *inst);
extern GSERIALIZED *tpointseq_trajectory(const TSequence *seq);
extern TSequenceSet *tpointseq_azimuth(const TSequence *seq);
extern TSequence *tpointseq_cumulative_length(const TSequence *seq, double prevlength);
extern bool tpointseq_is_simple(const TSequence *seq);
extern bool tpointseq_is_simple(const TSequence *seq, bool *result);
extern double tpointseq_length(const TSequence *seq);
extern TSequence *tpointseq_speed(const TSequence *seq);
extern int tpointseq_srid(const TSequence *seq);
extern STBox *tpointseq_stboxes(const TSequence *seq, int *count);
extern TSequenceSet *tpointseqset_azimuth(const TSequenceSet *ss);
extern TSequenceSet *tpointseqset_cumulative_length(const TSequenceSet *ss);
extern bool tpointseqset_is_simple(const TSequenceSet *ss);
extern bool tpointseqset_is_simple(const TSequenceSet *ss, bool *result);
extern double tpointseqset_length(const TSequenceSet *ss);
extern TSequenceSet *tpointseqset_speed(const TSequenceSet *ss);
extern int tpointseqset_srid(const TSequenceSet *ss);
Expand Down
126 changes: 91 additions & 35 deletions meos/src/point/tpoint_spatialfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1964,6 +1964,7 @@ geopointlinearr_make_trajectory(GSERIALIZED **points, int npoints,
* @note Since the sequence has been already validated there is no verification
* of the input in this function, in particular for geographies it is supposed
* that the composing points are geodetic
* @note The function does NOT remove repeated points
* @csqlfn #Tpoint_trajectory()
*/
GSERIALIZED *
Expand All @@ -1983,8 +1984,16 @@ tpointseq_trajectory(const TSequence *seq)
{
GSERIALIZED *gs =
DatumGetGserializedP(tinstant_val(TSEQUENCE_INST_N(seq, i)));
/* If linear interpolation, remove two consecutive equal points */
if (interp == DISCRETE ||
/* If linear interpolation, remove two consecutive equal points to solve a
* problem in PostGIS/GEOS
* select st_astext(st_intersection(geometry 'Linestring(3 3,3 3)',
* geometry 'Linestring(0 0,3 3)'));
* -- LINESTRING EMPTY
* select st_astext(st_intersection(geometry 'Point(3 3)',
* geometry 'Linestring(0 0,3 3)'));
* -- POINT(3 3)
*/
if (interp == DISCRETE || interp == STEP ||
(npoints == 0 || ! geopoint_same(gs, points[npoints - 1])))
points[npoints++] = gs;
}
Expand Down Expand Up @@ -5309,82 +5318,115 @@ tpointseq_linear_find_splits(const TSequence *seq, int *count)
*****************************************************************************/

/**
* @brief Return true if a temporal point does not self-intersect
* @brief Return true if there are stationary segments in the linear trajectory
* @note The function works only on 2D even if the input points are in 3D
* @param[in] seq Temporal point
* @pre The temporal point sequence has discrete or step interpolation
*/
static bool
tpointseq_discstep_is_simple(const TSequence *seq)
tpointseq_linear_has_stationary_segms(const TSequence *seq)
{
assert(seq->count > 1);
Datum *points = palloc(sizeof(Datum) * seq->count);
for (int i = 0; i < seq->count; i++)
points[i] = tinstant_val(TSEQUENCE_INST_N(seq, i));
datumarr_sort(points, seq->count, temptype_basetype(seq->temptype));
bool found = false;
assert(seq); assert(tgeo_type(seq->temptype));
assert(MEOS_FLAGS_LINEAR_INTERP(seq->flags));
const POINT2D *p1 = DATUM_POINT2D_P(tinstant_val(TSEQUENCE_INST_N(seq, 0)));
for (int i = 1; i < seq->count; i++)
{
if (datum_point_eq(points[i - 1], points[i]))
{
found = true;
break;
}
const POINT2D *p2 = DATUM_POINT2D_P(tinstant_val(TSEQUENCE_INST_N(seq, i)));
/* If stationary segment */
if (p1->x == p2->x && p1->y == p2->y)
return true;
p1 = p2;
}
pfree(points);
return ! found;
return false;
}

/**
* @ingroup meos_internal_temporal_spatial_accessor
* @brief Return true if a temporal point does not self-intersect
* @param[in] seq Temporal point
* @param[out] result Result
* @return On error return false, otherwise return true
* @csqlfn #Tpoint_is_simple()
*/
bool
tpointseq_is_simple(const TSequence *seq)
tpointseq_is_simple(const TSequence *seq, bool *result)
{
assert(seq); assert(tgeo_type(seq->temptype));
assert(seq); assert(result); assert(tgeo_type(seq->temptype));
/* Instantaneous sequence */
if (seq->count == 1)
{
*result = true;
return true;
}

if (! MEOS_FLAGS_LINEAR_INTERP(seq->flags))
return tpointseq_discstep_is_simple(seq);

int numsplits;
bool *splits = tpointseq_linear_find_splits(seq, &numsplits);
pfree(splits);
return (numsplits == 0);
/* Call GEOS to verify whether the trajectory is simple */
GSERIALIZED *traj = tpointseq_trajectory(seq);
LWGEOM *lwgeom = lwgeom_from_gserialized(traj);
int issimple = lwgeom_is_simple(lwgeom);
pfree(traj); lwgeom_free(lwgeom);
if (issimple == -1)
{
/* Error */
meos_error(ERROR, MEOS_ERR_INTERNAL_ERROR,
"Error while making the temporal point simple");
return false;
}
else if (issimple == LW_FALSE)
*result = false;
else if (issimple == LW_TRUE)
{
if (MEOS_FLAGS_GET_INTERP(seq->flags) == LINEAR)
{
/* If the first point is equal to the last one or there are stationary
* segments it is not simple */
if (! datum_point_eq(tinstant_val(TSEQUENCE_INST_N(seq, 0)),
tinstant_val(TSEQUENCE_INST_N(seq, (seq->count - 1)))) &&
! tpointseq_linear_has_stationary_segms(seq))
*result = true;
else
*result = false;
}
else
*result = true;
}
return true;
}

/**
* @ingroup meos_internal_temporal_spatial_accessor
* @brief Return true if a temporal point does not self-intersect
* @param[in] ss Temporal sequence set
* @param[out] result Result
* @return On error return false, otherwise return true
* @csqlfn #Tpoint_is_simple()
*/
bool
tpointseqset_is_simple(const TSequenceSet *ss)
tpointseqset_is_simple(const TSequenceSet *ss, bool *result)
{
assert(ss); assert(tgeo_type(ss->temptype));
bool result = true;
bool resultseq;
*result = true;
for (int i = 0; i < ss->count; i++)
{
result &= tpointseq_is_simple(TSEQUENCESET_SEQ_N(ss, i));
bool err = tpointseq_is_simple(TSEQUENCESET_SEQ_N(ss, i), &resultseq);
if (err)
return false;
*result &= resultseq;
if (! result)
break;
}
return result;
return true;
}

/**
* @ingroup meos_temporal_spatial_accessor
* @brief Return true if a temporal point does not self-intersect
* @param[in] temp Temporal point
* @param[out] result Result
* @return On error return false, otherwise return true
* @csqlfn #Tpoint_is_simple()
*/
bool
tpoint_is_simple(const Temporal *temp)
tpoint_is_simple(const Temporal *temp, bool *result)
{
/* Ensure validity of the arguments */
if (! ensure_not_null((void *) temp) || ! ensure_tgeo_type(temp->temptype))
Expand All @@ -5394,11 +5436,12 @@ tpoint_is_simple(const Temporal *temp)
switch (temp->subtype)
{
case TINSTANT:
*result = true;
return true;
case TSEQUENCE:
return tpointseq_is_simple((TSequence *) temp);
return tpointseq_is_simple((TSequence *) temp, result);
default: /* TSEQUENCESET */
return tpointseqset_is_simple((TSequenceSet *) temp);
return tpointseqset_is_simple((TSequenceSet *) temp, result);
}
}

Expand Down Expand Up @@ -5504,6 +5547,7 @@ tpointcontseq_split(const TSequence *seq, bool *splits, int count)
* self-intersecting fragments
* @param[in] seq Temporal sequence point
* @param[out] count Number of elements in the resulting array
* @return On error return NULL
* @note This function is called for each sequence of a sequence set
* @csqlfn #Tpoint_make_simple()
*/
Expand All @@ -5523,7 +5567,19 @@ tpointseq_make_simple(const TSequence *seq, int *count)
return result;
}

int numsplits;
bool issimple;
if (! tpointseq_is_simple(seq, &issimple))
/* If error */
return NULL;
if (issimple)
{
result = palloc(sizeof(TSequence *));
result[0] = tsequence_copy(seq);
*count = 1;
return result;
}

int numsplits;
bool *splits = (interp == LINEAR) ?
tpointseq_linear_find_splits(seq, &numsplits) :
tpointseq_discstep_find_splits(seq, &numsplits);
Expand Down
4 changes: 3 additions & 1 deletion mobilitydb/src/point/tpoint_spatialfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,9 @@ Datum
Tpoint_is_simple(PG_FUNCTION_ARGS)
{
Temporal *temp = PG_GETARG_TEMPORAL_P(0);
bool result = tpoint_is_simple(temp);
bool result;
if (! tpoint_is_simple(temp, &result))
PG_RETURN_NULL();
PG_FREE_IF_COPY(temp, 0);
PG_RETURN_BOOL(result);
}
Expand Down

0 comments on commit 9918ed5

Please sign in to comment.