def test_length_geom_linestring_missing_epsg_from_global_settings(session): if session.bind.name == "postgresql": pytest.skip( "Postgres already has a constrain that checks on the length") factories.ChannelFactory(the_geom="SRID=4326;LINESTRING(" "-0.38222938832999598 -0.13872236685816669, " "-0.38222930900909202 -0.13872236685816669)", ) factories.ChannelFactory(the_geom="SRID=4326;LINESTRING(" "-0.38222938468305784 -0.13872235682908687, " "-0.38222931083256106 -0.13872235591735235, " "-0.38222930992082654 -0.13872207236791409, " "-0.38222940929989008 -0.13872235591735235)", ) q = Query(models.Channel).filter( geo_func.ST_Length( geo_func.ST_Transform( models.Channel.the_geom, Query(models.GlobalSetting.epsg_code).limit(1))) < 0.05) check_length_linestring = QueryCheck( column=models.Channel.the_geom, invalid=q, message= "Length of the v2_channel is too short, should be at least 0.05m", ) errors = check_length_linestring.get_invalid(session) assert len(errors) == 0
def test_length_geom_linestring_in_28992(session): if session.bind.name == "postgresql": pytest.skip( "Postgres already has a constrain that checks on the length") # around 0.109m factories.ChannelFactory( the_geom="SRID=4326;LINESTRING(" "122829.98048471771471668 473589.68720115750329569, " "122830.00490918199648149 473589.68720115750329569, " "122829.95687440223991871 473589.70983449439518154, " "122829.9793449093849631 473589.68850379559444264)") # around 0.001m channel_too_short = factories.ChannelFactory( the_geom="SRID=4326;LINESTRING(" "122829.98185859377554152 473589.69248294795397669, " "122829.98260150455462281 473589.69248294795397669)", ) check_length_linestring = QueryCheck( column=models.Channel.the_geom, invalid=Query(models.Channel).filter( geo_func.ST_Length(models.Channel.the_geom) < 0.05), message= "Length of the v2_channel is too short, should be at least 0.05m", ) errors = check_length_linestring.get_invalid(session) assert len(errors) == 1 assert errors[0].id == channel_too_short.id
def elevation(conn: directive.connection, tables: directive.tables, dem: directive.dem_file, oid: hug.types.number, segments: hug.types.in_range(1, 500) = 100): "Return the elevation profile of the route." if dem is None: raise hug.HTTPNotFound() r = tables.routes.data sel = sa.select([gf.ST_Points(gf.ST_Collect( gf.ST_PointN(r.c.geom, 1), gf.ST_LineInterpolatePoints(r.c.geom, 1.0/segments))), sa.func.ST_Length2dSpheroid(gf.ST_Transform(r.c.geom, 4326), 'SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]]') ]).where(r.c.id == oid)\ .where(r.c.geom.ST_GeometryType() == 'ST_LineString') res = conn.execute(sel).first() if res is not None: geom = to_shape(res[0]) ele = RouteElevation(oid, dem, geom.bounds) xcoord, ycoord = zip(*((p.x, p.y) for p in geom)) geomlen = res[1] pos = [geomlen * i / float(segments) for i in range(segments + 1)] ele.add_segment(xcoord, ycoord, pos) return ele.as_dict() # special treatment for multilinestrings sel = sa.select([r.c.geom, sa.literal_column("""ST_Length2dSpheroid(ST_MakeLine(ARRAY[ST_Points(ST_Transform(geom,4326))]), 'SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY["EPSG",\"7030\"]]')"""), r.c.geom.ST_NPoints(), gf.ST_Length(r.c.geom)])\ .where(r.c.id == oid) res = conn.execute(sel).first() if res is None or res[0] is None: raise hug.HTTPNotFound() geom = to_shape(res[0]) # Computing length in Mercator is slightly off, correct it via the # actual length. dist_fac = res[1] / res[3] ele = RouteElevation(oid, dem, geom.bounds) if res[2] > 10000: geom = geom.simplify(res[2] / 500, preserve_topology=False) elif res[2] > 4000: geom = geom.simplify(res[2] / 1000, preserve_topology=False) prev = None for seg in geom: p = seg.coords[0] xcoords = array('d', [p[0]]) ycoords = array('d', [p[1]]) pos = array('d') if prev is not None: pos.append(prev[2][-1] + \ Point(prev[0][-1], prev[1][-1]).distance(Point(*p)) * dist_fac) else: pos.append(0.0) for p in seg.coords[1:]: pos.append(pos[-1] + Point(xcoords[-1], ycoords[-1]).distance(Point(*p)) * dist_fac) xcoords.append(p[0]) ycoords.append(p[1]) ele.add_segment(xcoords, ycoords, pos) prev = (xcoords, ycoords, pos) return ele.as_dict()
def length(col): return geo_func.ST_Length(transform(col))
def elevation(conn: directive.connection, tables: directive.tables, dem: directive.dem_file, oid: hug.types.number, segments: hug.types.in_range(1, 500) = 100): "Return the elevation profile of the way." if dem is None: raise hug.HTTPNotFound() w = tables.ways.data ws = tables.joined_ways.data sql = sa.select([gf.ST_LineMerge(gf.ST_Collect(w.c.geom)).label('geom')])\ .where(w.c.id == ws.c.child)\ .where(ws.c.id == oid)\ .alias() sel = sa.select([ sql.c.geom, sa.literal_column( """ST_Length2dSpheroid(ST_MakeLine(ARRAY[ST_Points(ST_Transform(geom,4326))]), 'SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY["EPSG",\"7030\"]]')""" ), sql.c.geom.ST_NPoints(), gf.ST_Length(sql.c.geom) ]) res = conn.execute(sel).first() if res is None or res[0] is None: raise hug.HTTPNotFound() geom = to_shape(res[0]) # Computing length in Mercator is slightly off, correct it via the # actual length. dist_fac = res[1] / res[3] ele = RouteElevation(oid, dem, geom.bounds) if res[2] > 10000: geom = geom.simplify(res[2] / 500, preserve_topology=False) elif res[2] > 4000: geom = geom.simplify(res[2] / 1000, preserve_topology=False) if geom.geom_type == 'LineString': geom = [geom] prev = None for seg in geom: p = seg.coords[0] xcoords = array('d', [p[0]]) ycoords = array('d', [p[1]]) pos = array('d') if prev is not None: pos.append(prev[2][-1] + \ Point(prev[0][-1], prev[1][-1]).distance(Point(*p)) * dist_fac) else: pos.append(0.0) for p in seg.coords[1:]: pos.append(pos[-1] + Point(xcoords[-1], ycoords[-1]).distance(Point(*p)) * dist_fac) xcoords.append(p[0]) ycoords.append(p[1]) ele.add_segment(xcoords, ycoords, pos) prev = (xcoords, ycoords, pos) return ele.as_dict()
def get_route_length(route_id: uuid.UUID, db_session: Session) -> float: return (db_session.query(functions.ST_Length( Route.way_points, True)).filter_by(id=route_id).limit(1).scalar())