def bbox(self): """Compute the smallest rectangle that contains the entire track (border box).""" bbox = s2.LatLngRect() for line in self.polylines: for latlng in line: bbox = bbox.union(s2.LatLngRect.from_point(latlng.normalized())) return bbox
def make_clusters(flights: List[api.Flight], view_min: s2sphere.LatLng, view_max: s2sphere.LatLng) -> List[api.Cluster]: if not flights: return [] # Make the initial cluster points: List[Point] = [ Point(*geo.flatten( view_min, s2sphere.LatLng.from_degrees(flight.most_recent_position.lat, flight.most_recent_position.lng))) for flight in flights ] x_max, y_max = geo.flatten(view_min, view_max) clusters: List[Cluster] = [ Cluster(x_min=0, y_min=0, x_max=x_max, y_max=y_max, points=points) ] # TODO: subdivide cluster into many clusters result: List[api.Cluster] = [] for cluster in clusters: cluster = cluster.randomize() p1 = geo.unflatten(view_min, (cluster.x_min, cluster.y_min)) p2 = geo.unflatten(view_min, (cluster.x_max, cluster.y_max)) result.append( api.Cluster(corners=[ api.Position(lat=p1.lat().degrees, lng=p1.lng().degrees), api.Position(lat=p2.lat().degrees, lng=p2.lng().degrees) ], area_sqm=geo.area_of_latlngrect( s2sphere.LatLngRect(p1, p2)), number_of_flights=len(cluster.points))) return result
def _determine_bbox(self) -> s2sphere.LatLngRect: if self._center: log.info("Forcing heatmap center to %s", str(self._center)) dlat, dlng = 0, 0 if self._radius: er = 6378.1 quarter = er * math.pi / 2 dlat = 90 * self._radius / quarter scale = 1 / math.cos(self._center.lat().radians) dlng = scale * 90 * self._radius / quarter else: for tr in self.poster.tracks: for line in tr.polylines: for latlng in line: d = abs(self._center.lat().degrees - latlng.lat().degrees) dlat = max(dlat, d) d = abs(self._center.lng().degrees - latlng.lng().degrees) while d > 360: d -= 360 if d > 180: d = 360 - d dlng = max(dlng, d) return s2sphere.LatLngRect.from_center_size( self._center, s2sphere.LatLng.from_degrees(2 * dlat, 2 * dlng)) tracks_bbox = s2sphere.LatLngRect() for tr in self.poster.tracks: tracks_bbox = tracks_bbox.union(tr.bbox()) return tracks_bbox
def bounds(self) -> s2sphere.LatLngRect: """Return bounds of object :return: bounds of object :rtype: s2sphere.LatLngRect """ return s2sphere.LatLngRect()
def _compute_bbox(self): self._bbox = s2sphere.LatLngRect() for segment in self._segments: for point in segment: b = s2sphere.LatLngRect.from_point(point._lat_lng) self._bbox = self._bbox.union(b) if not self._bbox.is_empty(): self._bbox = self._bbox.expanded( s2sphere.LatLng.from_degrees(0.01, 0.01))
def object_bounds(self): if len(self._objects) == 0: return None bounds = s2.LatLngRect() print('bounds ', bounds) for obj in self._objects: bounds = bounds.union(obj.bounds()) print('returned bounds ', bounds) return bounds
def bounds(self) -> s2sphere.LatLngRect: """Return bounds of line :return: bounds of line :rtype: s2sphere.LatLngRect """ b = s2sphere.LatLngRect() for latlng in self.interpolate(): b = b.union(s2sphere.LatLngRect.from_point(latlng.normalized())) return b
def _determine_zoom(self, width: int, height: int, b: typing.Optional[s2sphere.LatLngRect], c: s2sphere.LatLng) -> typing.Optional[int]: if b is None: b = s2sphere.LatLngRect(c, c) else: b = b.union(s2sphere.LatLngRect(c, c)) assert b if b.is_point(): return self._clamp_zoom(15) pixel_margin = self.extra_pixel_bounds() w = (width - pixel_margin[0] - pixel_margin[2]) / self._tile_provider.tile_size() h = (height - pixel_margin[1] - pixel_margin[3]) / self._tile_provider.tile_size() # margins are bigger than target image size => ignore them if w <= 0 or h <= 0: w = width / self._tile_provider.tile_size() h = height / self._tile_provider.tile_size() min_y = (1.0 - math.log( math.tan(b.lat_lo().radians) + (1.0 / math.cos(b.lat_lo().radians)))) / (2 * math.pi) max_y = (1.0 - math.log( math.tan(b.lat_hi().radians) + (1.0 / math.cos(b.lat_hi().radians)))) / (2 * math.pi) dx = (b.lng_hi().degrees - b.lng_lo().degrees) / 360.0 if dx < 0: dx += math.ceil(math.fabs(dx)) if dx > 1: dx -= math.floor(dx) dy = math.fabs(max_y - min_y) for zoom in range(1, self._tile_provider.max_zoom()): tiles = 2**zoom if (dx * tiles > w) or (dy * tiles > h): return self._clamp_zoom(zoom - 1) return self._clamp_zoom(15)
def test_bounds() -> None: context = staticmaps.Context() assert context.object_bounds() is None context.add_object(staticmaps.Marker(staticmaps.create_latlng(48, 8))) bounds = context.object_bounds() assert bounds is not None assert bounds.is_point() context.add_object(staticmaps.Marker(staticmaps.create_latlng(47, 7))) assert context.object_bounds() is not None assert context.object_bounds() == s2sphere.LatLngRect( staticmaps.create_latlng(47, 7), staticmaps.create_latlng(48, 8)) context.add_object(staticmaps.Marker(staticmaps.create_latlng(47.5, 7.5))) assert context.object_bounds() is not None assert context.object_bounds() == s2sphere.LatLngRect( staticmaps.create_latlng(47, 7), staticmaps.create_latlng(48, 8)) context.add_bounds( s2sphere.LatLngRect(staticmaps.create_latlng(46, 6), staticmaps.create_latlng(49, 9))) assert context.object_bounds() is not None assert context.object_bounds() == s2sphere.LatLngRect( staticmaps.create_latlng(46, 6), staticmaps.create_latlng(49, 9)) context.add_bounds( s2sphere.LatLngRect(staticmaps.create_latlng(47.5, 7.5), staticmaps.create_latlng(48, 8))) assert context.object_bounds() is not None assert context.object_bounds() == s2sphere.LatLngRect( staticmaps.create_latlng(47, 7), staticmaps.create_latlng(48, 8))
def object_bounds(self) -> typing.Optional[s2sphere.LatLngRect]: """return maximum bounds of all objects :return: maximum of all object bounds :rtype: s2sphere.LatLngRect """ bounds = None if len(self._objects) != 0: bounds = s2sphere.LatLngRect() for obj in self._objects: assert bounds bounds = bounds.union(obj.bounds()) return self._custom_bounds(bounds)
def determine_center_zoom(self, width, height): if self._center is not None: if self._zoom is not None: return self._center, self.clamp_zoom(self._zoom) b = self.object_bounds() if b is None: return self._center, self.clamp_zoom(self._zoom) if self._zoom is not None: return b.get_center(), self.clamp_zoom(self._zoom) if self._center is not None: b = b.union(s2.LatLngRect(self._center, self._center)) if b.is_point(): return b.get_center(), None tile_size = self._tile_provider.tile_size() # TODO: + extra margin pixels margin = 4 w = (width - 2.0 * margin) / tile_size h = (height - 2.0 * margin) / tile_size minX = (b.lng_lo().degrees + 180.0) / 360.0 maxX = (b.lng_hi().degrees + 180.0) / 360.0 minY = (1.0 - math.log( math.tan(b.lat_lo().radians) + (1.0 / math.cos(b.lat_lo().radians))) / math.pi) / 2.0 maxY = (1.0 - math.log( math.tan(b.lat_hi().radians) + (1.0 / math.cos(b.lat_hi().radians))) / math.pi) / 2.0 print('in context determine zoom w h minX maxX minY maxY', w, h, minX, maxX, minY, maxY) dx = maxX - minX if dx < 0: dx += math.ceil(math.fabs(dx)) if dx > 1: dx -= math.floor(dx) dy = math.fabs(maxY - minY) for zoom in range(1, self._tile_provider.max_zoom()): tiles = 2**zoom if (dx * tiles > w) or (dy * tiles > h): print('111 b.get_center(), zoom - 1 ', b.get_center(), zoom - 1) return b.get_center(), zoom - 1 print('222 b.get_center(), zoom - 1 ', b.get_center(), zoom - 1) return b.get_center(), self._tile_provider.max_zoom()
def bounds(self): return s2.LatLngRect()