def test_is_outside(self): point = self.map_box.geometry.representative_point() self.assertFalse(np.all(geo.is_outside(self.map_box, point))) point = self.map_canyon.geometry.representative_point() self.assertFalse(np.all(geo.is_outside(self.map_canyon, point))) point_series = gpd.GeoSeries(point.array,crs=self.map_canyon.crs,index=[10,11]) pdt.assert_series_equal(geo.is_outside(self.map_canyon, point_series),pd.Series([False,False],index=[10,11]),check_names=False)
def test_random_walk(self): points = sim.random_walk(self.map_box,100,self.start,self.end,self.polygon) self.assertTrue(np.all(geo.is_outside(self.map_box,points.geometry))) self.assertTrue(all([self.polygon.contains(p) for p in points.geometry])) self.assertTrue(np.all(points["time"]>=np.datetime64('2020-09-01T09:00'))) self.assertTrue(np.all(points["time"]<=(np.datetime64('2020-09-01T10:00')+np.timedelta64(1,'ms')))) self.assertTrue(np.all(s.z>0 for s in points.geometry))
def test_point_process(self): points = sim.point_process(self.map_box, self.polygon.bounds, self.start, self.end, 100) self.assertTrue( np.all(points["time"] >= np.datetime64('2020-09-01T09:00'))) self.assertTrue( np.all(points["time"] <= np.datetime64('2020-09-01T10:00'))) self.assertTrue(np.all(s.z > 0 for s in points.geometry)) self.assertEqual(self.map_box.crs, points.crs) self.assertTrue(np.all(geo.is_outside(self.map_box, points.geometry))) self.assertTrue( all([self.polygon.contains(p) for p in points.geometry]))
def point_process(map_: Map, bounds: np.array, start: pd.Timestamp, end: pd.Timestamp, num_samples: int, cluster: str = 'none', cluster_args: dict = dict(), receiver_offset: float = 1.0) -> ReceiverPoints: """Generates a set of receiver locations using a clustered point process. Each cluster represents a set of receiver measurements. Child process can vary (none,random or levy walk, or a guided walk) Receiver locations are only returned if outside of buildings. Parameters ---------- map_ : Map bounds : np.array spatial bounds with minx,miny,maxx,maxy format start : pd.Timestamp lower time bound end : pd.Timestamp upper time bound num_samples : int number of receivers (parent process) to simulate cluster_args : dict passed to clustering (child) process, by default dict(). cluster : str, optional type of child process, by default 'none' receiver_offset : float, optional The altitude of receiver location above ground level, by default 1.0 Returns ------- ReceiverPoints """ cm.check.check_type(map_, 'map', raise_errors=True) xy, t = _poisson_cluster(bounds, start, end, num_samples, cluster, cluster_args) points = gpd.GeoSeries(gpd.points_from_xy(xy[0, :], xy[1, :]), crs=map_.crs) outside = is_outside(map_, points, box(*bounds)) z = ground_level(map_, points[outside]) + receiver_offset return gpd.GeoDataFrame({'time': t[outside]}, geometry=gpd.points_from_xy( xy[0, outside], xy[1, outside], z), crs=map_.crs)
def _xy_point_process(map_: gpd.GeoDataFrame, polygon: Polygon, num_samples: int) -> gpd.GeoSeries: """ Generates a geoseries of (2d) points outside map_ buildings and inside polygon""" minx, miny, maxx, maxy = polygon.bounds xy = np.empty(shape=(0, 2), dtype=float) n = num_samples - xy.shape[0] while n > 0: p = _rng.random( (n, 2)) * np.array([[maxx - minx, maxy - miny]]) + np.array( [[minx, miny]]) points = gpd.GeoSeries(gpd.points_from_xy(p[:, 0], p[:, 1]), crs=map_.crs) outside = p[is_outside(map_, points, polygon), :] xy = np.vstack((xy, outside)) n = num_samples - xy.shape[0] return gpd.GeoSeries(gpd.points_from_xy(xy[:, 0], xy[:, 1]), crs=map_.crs)
def test_xy_process(self): points = sim._xy_point_process(self.map_box,self.polygon,1000) self.assertEqual(len(points), 1000) self.assertEqual(self.map_box.crs,points.crs) self.assertTrue(np.all(geo.is_outside(self.map_box,points))) self.assertTrue(all([self.polygon.contains(p) for p in points]))
def random_walk(map_: gpd.GeoDataFrame, num_samples: int, start: pd.Timestamp, end: pd.Timestamp, polygon: Polygon = Polygon(), receiver_offset: float = 1., avg_speed: float = .1, sampling_rate: int = 5) -> gpd.GeoDataFrame: """Generates a set of receiver locations using a random point process. Receiver locations are within the map boundaries and outside of buildings. Parameters ---------- map_ : gpd.GeoDataFrame A gnssmapper map num_samples : int number of receiver locations to generate start : pd.Timestamp start boundary for observation time. end : pd.Timestamp end boundary for observation time. polygon : Polygon, optional A bounding polygon, by default empty. receiver_offset : float, optional The altitude of receiver location above ground level, by default 1.0 avg_speed : float, optional speed of random walk per second, by default .1 sampling_rate : int, optional frequency of readings in seconds, by default 5 Returns ------- gpd.GeoDataFrame Receiverpoints """ if num_samples <= 0: return gpd.GeoDataFrame() if polygon.is_empty: polygon = box(*map_.geometry.total_bounds) starting_point = _xy_point_process(map_, polygon, 1) x, y, s = [starting_point.x[0]], [starting_point.y[0]], [0] tempx, tempy, temps = x[-1], y[-1], s[-1] while len(x) != num_samples: orientation = _rng.uniform(0, 2 * np.pi) x_ = avg_speed * np.cos(orientation) y_ = avg_speed * np.sin(orientation) p = gpd.GeoSeries(Point(tempx + x_, tempy + y_), crs=map_.crs) if p.within(polygon)[0]: tempx += x_ tempy += y_ temps += 1 if temps % sampling_rate == 0 and is_outside(map_, p)[0]: x.append(tempx) y.append(tempy) s.append(temps) xy = gpd.GeoSeries(gpd.points_from_xy(x, y), crs=map_.crs) z = ground_level(map_, xy) + receiver_offset time_range = (end - start).total_seconds() bounded_s = pd.to_timedelta(np.mod(s, time_range), unit='S') t = start + bounded_s return gpd.GeoDataFrame({'time': t}, geometry=gpd.points_from_xy(xy.x, xy.y, z), crs=xy.crs)