class LinearReferencingTestCase(unittest.TestCase): def setUp(self): self.point = Point(1, 1) self.line1 = LineString(([0, 0], [2, 0])) self.line2 = LineString(([3, 0], [3, 6])) self.multiline = MultiLineString( [list(self.line1.coords), list(self.line2.coords)]) def test_line1_project(self): self.assertEqual(self.line1.project(self.point), 1.0) self.assertEqual(self.line1.project(self.point, normalized=True), 0.5) def test_line2_project(self): self.assertEqual(self.line2.project(self.point), 1.0) self.assertAlmostEqual(self.line2.project(self.point, normalized=True), 0.16666666666, 8) def test_multiline_project(self): self.assertEqual(self.multiline.project(self.point), 1.0) self.assertEqual(self.multiline.project(self.point, normalized=True), 0.125) def test_not_supported_project(self): with pytest.raises(shapely.GEOSException, match="IllegalArgumentException"): self.point.buffer(1.0).project(self.point) def test_not_on_line_project(self): # Points that aren't on the line project to 0. self.assertEqual(self.line1.project(Point(-10, -10)), 0.0) def test_line1_interpolate(self): self.assertTrue(self.line1.interpolate(0.5).equals(Point(0.5, 0.0))) self.assertTrue(self.line1.interpolate(-0.5).equals(Point(1.5, 0.0))) self.assertTrue( self.line1.interpolate(0.5, normalized=True).equals(Point(1, 0))) self.assertTrue( self.line1.interpolate(-0.5, normalized=True).equals(Point(1, 0))) def test_line2_interpolate(self): self.assertTrue(self.line2.interpolate(0.5).equals(Point(3.0, 0.5))) self.assertTrue( self.line2.interpolate(0.5, normalized=True).equals(Point(3, 3))) def test_multiline_interpolate(self): self.assertTrue(self.multiline.interpolate(0.5).equals(Point(0.5, 0))) self.assertTrue( self.multiline.interpolate(0.5, normalized=True).equals(Point(3.0, 2.0))) def test_line_ends_interpolate(self): # Distances greater than length of the line or less than # zero yield the line's ends. self.assertTrue(self.line1.interpolate(-1000).equals(Point(0.0, 0.0))) self.assertTrue(self.line1.interpolate(1000).equals(Point(2.0, 0.0)))
class LinearReferencingTestCase(unittest.TestCase): def setUp(self): self.point = Point(1, 1) self.line1 = LineString(([0, 0], [2, 0])) self.line2 = LineString(([3, 0], [3, 6])) self.multiline = MultiLineString([ list(self.line1.coords), list(self.line2.coords) ]) def test_line1_project(self): self.assertEqual(self.line1.project(self.point), 1.0) self.assertEqual(self.line1.project(self.point, normalized=True), 0.5) def test_line2_project(self): self.assertEqual(self.line2.project(self.point), 1.0) self.assertAlmostEqual(self.line2.project(self.point, normalized=True), 0.16666666666, 8) def test_multiline_project(self): self.assertEqual(self.multiline.project(self.point), 1.0) self.assertEqual(self.multiline.project(self.point, normalized=True), 0.125) def test_not_supported_project(self): self.assertRaises(TypeError, self.point.buffer(1.0).project, self.point) def test_not_on_line_project(self): # Points that aren't on the line project to 0. self.assertEqual(self.line1.project(Point(-10,-10)), 0.0) def test_line1_interpolate(self): self.failUnless(self.line1.interpolate(0.5).equals(Point(0.5, 0.0))) self.failUnless( self.line1.interpolate(0.5, normalized=True).equals( Point(1.0, 0.0))) def test_line2_interpolate(self): self.failUnless(self.line2.interpolate(0.5).equals(Point(3.0, 0.5))) self.failUnless( self.line2.interpolate(0.5, normalized=True).equals( Point(3.0, 3.0))) def test_multiline_interpolate(self): self.failUnless(self.multiline.interpolate(0.5).equals( Point(0.5, 0.0))) self.failUnless( self.multiline.interpolate(0.5, normalized=True).equals( Point(3.0, 2.0))) def test_line_ends_interpolate(self): # Distances greater than length of the line or less than # zero yield the line's ends. self.failUnless(self.line1.interpolate(-1000).equals(Point(0.0, 0.0))) self.failUnless(self.line1.interpolate(1000).equals(Point(2.0, 0.0)))
def get_center_point(segment): """ Get the centerpoint for a linestring or multiline string Args: segment - Geojson LineString or MultiLineString Returns: Geojson point """ if segment['geometry']['type'] == 'LineString': point = LineString(segment['geometry']['coordinates']).interpolate( .5, normalized=True) return point.x, point.y elif segment['geometry']['type'] == 'MultiLineString': # Make a rectangle around the multiline coords = [ item for coords in segment['geometry']['coordinates'] for item in coords ] minx = min([x[0] for x in coords]) maxx = max([x[0] for x in coords]) miny = min([x[1] for x in coords]) maxy = max([x[1] for x in coords]) point = LineString([[minx, miny], [maxx, maxy]]).interpolate(.5, normalized=True) mlstring = MultiLineString(segment['geometry']['coordinates']) point = mlstring.interpolate(mlstring.project(point)) return point.x, point.y return None, None
def generate_sample_points(points_X, points_Y): '''Generate 100 sampled points for a gesture. In this function, we should convert every gesture or template to a set of 100 points, such that we can compare the input gesture and a template computationally. :param points_X: A list of X-axis values of a gesture. :param points_Y: A list of Y-axis values of a gesture. :return: sample_points_X: A list of X-axis values of a gesture after sampling, containing 100 elements. sample_points_Y: A list of Y-axis values of a gesture after sampling, containing 100 elements. ''' sample_points_X, sample_points_Y = [], [] # TODO: Start sampling (12 points) final_len = 0 all_points = [] for i in range(len(points_X) - 1): for j in range(len(points_Y) - 1): point_1 = (points_X[i], points_Y[i]) point_2 = (points_X[i + 1], points_Y[i + 1]) line = LineString([point_1, point_2]) final_len += line.length all_points.append((point_1, point_2)) # print(all_points) t = final_len / 99 # print(final_len) cp = line.interpolate(t) lines = MultiLineString(all_points) splitter = MultiPoint( [lines.interpolate((i / 100), normalized=True) for i in range(1, 100)]) print(splitter) gs = GeoSeries(splitter) gs.plot(marker="$", color="red") return sample_points_X, sample_points_Y
class LinearReferencingTestCase(unittest.TestCase): def setUp(self): self.point = Point(1, 1) self.line1 = LineString(([0, 0], [2, 0])) self.line2 = LineString(([3, 0], [3, 6])) self.multiline = MultiLineString([ list(self.line1.coords), list(self.line2.coords) ]) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line1_project(self): self.assertEqual(self.line1.project(self.point), 1.0) self.assertEqual(self.line1.project(self.point, normalized=True), 0.5) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line2_project(self): self.assertEqual(self.line2.project(self.point), 1.0) self.assertAlmostEqual( self.line2.project(self.point, normalized=True), 0.16666666666, 8) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_multiline_project(self): self.assertEqual(self.multiline.project(self.point), 1.0) self.assertEqual( self.multiline.project(self.point, normalized=True), 0.125) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_not_supported_project(self): with self.assertRaises(TypeError): self.point.buffer(1.0).project(self.point) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_not_on_line_project(self): # Points that aren't on the line project to 0. self.assertEqual(self.line1.project(Point(-10, -10)), 0.0) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line1_interpolate(self): self.assertTrue(self.line1.interpolate(0.5).equals(Point(0.5, 0.0))) self.assertTrue( self.line1.interpolate(0.5, normalized=True).equals(Point(1, 0))) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line2_interpolate(self): self.assertTrue(self.line2.interpolate(0.5).equals(Point(3.0, 0.5))) self.assertTrue( self.line2.interpolate(0.5, normalized=True).equals(Point(3, 3))) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_multiline_interpolate(self): self.assertTrue(self.multiline.interpolate(0.5).equals(Point(0.5, 0))) self.assertTrue( self.multiline.interpolate(0.5, normalized=True).equals( Point(3.0, 2.0))) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line_ends_interpolate(self): # Distances greater than length of the line or less than # zero yield the line's ends. self.assertTrue(self.line1.interpolate(-1000).equals(Point(0.0, 0.0))) self.assertTrue(self.line1.interpolate(1000).equals(Point(2.0, 0.0)))
list_points = [] ## set the current distance to place the point current_dist = distance ## get the geometry of the line as wkt line_geom = ln.geometry().ExportToWkt() ## make shapely MultiLineString object shapely_line = MultiLineString(wkt.loads(line_geom)) ## get the total length of the line line_length = shapely_line.length ## append the starting coordinate to the list list_points.append(Point(list(shapely_line[0].coords)[0])) ## https://nathanw.net/2012/08/05/generating-chainage-distance-nodes-in-qgis/ ## while the current cumulative distance is less than the total length of the line while current_dist < line_length: ## use interpolate and increase the current distance list_points.append(shapely_line.interpolate(current_dist)) current_dist += distance ## append end coordinate to the list list_points.append(Point(list(shapely_line[0].coords)[-1])) ## add points to the layer ## for each point in the list for num, pt in enumerate(list_points, 1): ## create a point object pnt = ogr.Geometry(ogr.wkbPoint) pnt.AddPoint(pt.x, pt.y) feat_dfn = out_lyr.GetLayerDefn() feat = ogr.Feature(feat_dfn) feat.SetGeometry(pnt) ## populate the distance values for each point. ## start point
def create_points_at_uniform_length(str_net_path, str_diss_path, str_pts_path, p_interp_spacing_m): print('Dissolve line features...') lst_all=[] # Open the delineated stream network... with fiona.open(str_net_path) as lines: crs = lines.crs # Open an output file for dissolved lines...THIS IS NOT REALLY NEEDED, ONLY FOR TESTING schema = {'geometry':'MultiLineString', 'properties':{'linkno':'int:6'}} with fiona.open(str_diss_path, 'w', 'ESRI Shapefile', schema, crs) as output: for line in lines: lst_all.append(line['geometry']['coordinates']) output.write({'properties':{'linkno':9999}, 'geometry':{'type':'MultiLineString','coordinates':lst_all}}) print('Points along line features...') # Open the dissolve network...(skip this write/read step?) with fiona.open(str_diss_path) as line: crs = line.crs line = line[0] # NOTE: Need to check whether or not to convert units here! # Geometry transform function based on pyproj.transform to convert length between decimal degrees and meters project = partial( pyproj.transform, pyproj.Proj(init=crs['init']), pyproj.Proj(init='EPSG:26914')) # UTM14N For TX data; NOTE: HARDCODED FOR NOW! # Open output point shapefile... schema = {'geometry':'Point', 'properties':{'id':'int:6'}} with fiona.open(str_pts_path, 'w', 'ESRI Shapefile', schema, crs) as pt_output: line_shply = MultiLineString(line['geometry']['coordinates']) line2 = transform(project, line_shply) length_m = line2.length length_deg = line_shply.length # units depend on crs p_interp_spacing = (length_deg*p_interp_spacing_m)/(length_m) # convert from meters to dec. degrees step_lens = np.arange(0, length_deg, p_interp_spacing) # p_interp_spacing in projection units? # # Open the output line segment shapefile... # schema = {'geometry':'LineString', 'properties':{'id':'int:6', 'len_m':'float'}} # with fiona.open(str_segs_path, 'w', 'ESRI Shapefile', schema, crs) as ln_output: # i_pt_prev=np.empty(0) for i, step in enumerate(step_lens): # lambda here instead? i_pt = np.array(line_shply.interpolate(step)) # if i_pt_prev.any(): # ls = LineString([i_pt, i_pt_prev]) # # # Write out the lines (with length)... # len_m = transform(project, ls).length # # ln_output.write({'geometry': mapping(ls), 'properties':{'id':i, 'len_m':len_m}}) # # i_pt_prev = i_pt # Write out the point... pt_output.write({'properties':{'id':i}, 'geometry':{'type':'Point','coordinates':i_pt}})
class WaySet: ways_cache = ObjectCache() def __init__(self, lines): self.multiline = MultiLineString(lines) self.headings = [ Route.get_heading(l.coords[0][1], l.coords[0][0], l.coords[1][1], l.coords[1][0]) for l in lines ] @staticmethod def download_all_ways(sector, tram_only=False, timestamp=None): bbox = "%f,%f,%f,%f" % sector ext = 0.01 ext_bbox = "%f,%f,%f,%f" % (sector[0] - ext, sector[1] - ext, sector[2] + ext, sector[3] + ext) if tram_only: query = '[out:json]{{date}};(node({{ext_bbox}});way["railway"="tram"]({{bbox}}););out;' else: query = '[out:json]{{date}};(way["highway"]({{bbox}});node({{ext_bbox}}););out;' query = query.replace("{{bbox}}", bbox) query = query.replace("{{ext_bbox}}", ext_bbox) timestamp = "[date:\"%s\"]" % timestamp if timestamp is not None else "" query = query.replace("{{date}}", timestamp) ways = WaySet.ways_cache.get_from_cache(query) if ways is None: api = overpy.Overpass() try: result = api.query(query) except overpy.OverpassTooManyRequests: time.sleep(20) result = api.query(query) ways = [] for w in result.ways: try: nodes = w.get_nodes(resolve_missing=False) except overpy.exception.DataIncomplete: try: nodes = w.get_nodes(resolve_missing=True) except overpy.exception.DataIncomplete: print("Overpass can't resolve nodes. Skipping way.") continue nodes = [[float(n.lon), float(n.lat)] for n in nodes] ways += [nodes] WaySet.ways_cache.store_in_cache(query, ways) lines = [LineString(c) for c in ways] return WaySet(lines) def snap_point_to_lines(self, point, next_point, priority_line_index): distances = [line.distance(point) for line in self.multiline] if priority_line_index > -1: distances[priority_line_index] /= 2 min_distance = min(distances) i_dist = distances.index(min_distance) projection = self.multiline[i_dist].project(point) next_proj = 1 if next_point is None else self.multiline[ i_dist].project(next_point) new_point = self.multiline[i_dist].interpolate(projection) new_next_point = self.multiline[i_dist].interpolate(next_proj) heading = Route.get_heading(new_point.y, new_point.x, new_next_point.y, new_next_point.x) return new_point, i_dist, heading def snap_point_to_multilines(self, point): return self.multiline.interpolate(self.multiline.project(point)) def plot(self): for l in self.multiline: lon, lat = l.xy plt.plot(lon, lat) def get_closest_way(self, point): distances = [line.distance(point) for line in self.multiline] min_distance = min(distances) i_min_dist = distances.index(min_distance) return self.multiline[i_min_dist] def get_closest_way_with_heading(self, point, heading, heading_tolerance=45): heading = heading % 360 lines = self.multiline projections = [l.project(point, normalized=True) for l in lines] lines = [l for l, p in zip(lines, projections) if 0 < p < 1] headings = np.array([ WaySet.get_linestring_heading_at_projection(l, p) for l, p in zip(lines, projections) ]) headings_diff = np.abs(headings % 360 - heading) # print(headings_diff) if (headings_diff < heading_tolerance).any(): lines = [ l for l, hd in zip(lines, headings_diff) if hd < heading_tolerance ] distances = [line.distance(point) for line in lines] min_distance = min(distances) i_min_dist = distances.index(min_distance) return lines[i_min_dist] @staticmethod def get_linestring_heading_at_projection(linestring, projection): ps = [ linestring.project(Point(c), normalized=True) for c in linestring.coords ] for prev_c, c in zip(linestring.coords[:-1], linestring.coords[1:]): p = linestring.project(Point(c)) if p > projection: return Route.get_heading(prev_c[1], prev_c[0], c[1], c[0]) prev_c = linestring.coords[-2] c = linestring.coords[-1] return Route.get_heading(prev_c[1], prev_c[0], c[1], c[0]) def snap_points(self, points): last_way = None snapped_points = [] last_distance = None # headings before snapping headings = [] for i, p in enumerate(points): if i < len(points) - 1: next_point = points[i + 1] headings.append( Route.get_heading(p.y, p.x, next_point.y, next_point.x)) headings.append(headings[-1]) h_diff = [] for point_index in range(len(points)): point = points[point_index] heading = headings[point_index] # if last_way is not None: # projection = last_way.project(point) # distance = last_way.distance(point) # if 0 <= projection <= 1 and distance < 1.1 * last_distance: # snapped_point = last_way.interpolate(projection) # last_distance = distance # snapped_points += [snapped_point] # continue last_way = self.get_closest_way_with_heading(point, heading) # last_way = self.get_closest_way(point) projection = last_way.project(point) # last_distance = last_way.distance(point) snapped_point = last_way.interpolate(projection) h = WaySet.get_linestring_heading_at_projection( last_way, projection) h_diff += [headings[point_index] - h] snapped_points += [snapped_point] # plt.plot(h_diff) # plt.show() # headings after snapping headings = [] for i, p in enumerate(snapped_points): if i < len(snapped_points) - 1: next_point = snapped_points[i + 1] headings.append( Route.get_heading(p.y, p.x, next_point.y, next_point.x)) headings.append(headings[-1]) return Route.from_points(snapped_points, headings)