How To Calculate Frechet Distance In Django?
Solution 1:
In your SQLAlchemy example, you are doing something that you didn't do in the GeoDjango one and that is to cast the WKT string to Geometry.
What happens here essentially is that you are trying to use a PostGIS function but instead of a Geometry, you are passing it a string.
Another problem that we would stumble upon after fixing the first one would be the following exception:
django.core.exceptions.FieldError: Cannot resolve expression type, unknown output_field
and that is why we need to create a custom database function based on GeoFunc. That poses some problems of its own though and we will need to consider the following:
Our DB Function will receive 2 Geometries as arguments.
That is a bit convoluted, but if we look at the code of
GeoFuncwe will see that the class inherits a mixin called:GeoFuncMixinwhich has the attributegeom_param_pos = (0,)and specifies the positions of the function arguments that will be geometries. (Yeaahhh frameworks are fun :P)- Our function will output a
FloatField.
Therefore our custom DB Function should look like this:
from django.contrib.gis.db.models.functions import GeoFunc
from django.db.models.fields import FloatField
class FrechetDistance(GeoFunc):
function='ST_FrechetDistance'
geom_param_pos = (0, 1,)
output_field = FloatField()
Now we can use this function in our query to calculate the ST_FrechetDistance.
We will also need to address the original issue of passing geometries to the function and not just WKT strings:
def get_matched_segments(wkt: str, freche_threshold: float = 0.002) -> QuerySet:
forward_linestring = GEOSGeometry(wkt, srid=4326)
backward_linestring = GEOSGeometry(wkt, srid=4326)
backward_linestring.reverse()
backward_linestring.srid = 4326 # On Django 2.1.5 `srid` is lost after `reverse()`
transform_ls = linestring.transform(3857, clone=True)
frechet_annotation = HighwayOnlyMotor.objects.filter(
geom__dwithin=(transform_ls, D(m=20))
).annotate(
fre_forward=FrechetDistance(
Func(F('geom'), Value(4326), function='ST_Transform'),
Value(forward_linestring),
Value(0.1)
),
fre_backward=FrechetDistance(
Func(F('geom'), Value(4326), function='ST_Transform'),
Value(backward_linestring),
Value(0.1)
)
)
matched_segments = frechet_annotation.filter(
Q(fre_forward__lte=freche_threshold) |
Q(fre_backward__lte=freche_threshold)
)
return matched_segments
Post a Comment for "How To Calculate Frechet Distance In Django?"