def get_additional_data_for_ellipse(location: geodetic_ellipse, buffer_distance, boundary_table, engine): """ Executes a contains query for a ellipse. :param location: location object :type location: :py:class:Geodetic2D :param boundary_table: The name of the service boundary table. :type boundary_table: `str` :param engine: SQLAlchemy database engine. :type engine: :py:class:`sqlalchemy.engine.Engine` :return: A list of dictionaries containing the contents of returned rows. """ # Pull out just the number from the SRID trimmed_srid = int(location.spatial_ref.split('::')[1]) long, lat = gc_geom.reproject_point(location.longitude, location.latitude, trimmed_srid, 4326) utmsrid = gc_geom.getutmsrid(long, lat) wkb_ellipse = location.to_wkbelement(project_to=4326) results = _get_additional_data_for_geometry(engine, wkb_ellipse, boundary_table) if results is None: results = _get_additional_data_for_geometry_with_buffer(engine, wkb_ellipse, boundary_table, buffer_distance, utmsrid) return results
def build_shapely_geometry(self) -> BaseGeometry: """ Builds the internal shapely representation of the geometry. This is used by other base class methods to build the other output types. :return: A shapely geometry specific to the derived type. :rtype: :py:class:`BaseGeometry` """ # Get the UTMSRID so we can transform the center point to a coordinate system where distance is # measured in meters. utmsrid: int = getutmsrid(self.longitude, self.latitude, self.sr_id) # Create the OGR Point center: ogr.Geometry = ogr.Geometry(ogr.wkbPoint) center.AssignSpatialReference(Geodetic2D.get_ogr_sr(self.sr_id)) center.AddPoint(self.longitude, self.latitude) # Project the point from its native projection to the UTM system. center = reproject_geom(center, self.sr_id, utmsrid) # adjust for the fact that we're not doing standard geometry - back up 90 degress # to start from north. start_angle: float = 90 - self.start_angle # find the end angle, which is the sweep relative to the start angle going clockwise so we subtract. end_angle: float = start_angle - self.opening_angle # plot a line for the outer arc. outer_arc_x, outer_arc_y = \ calculate_arc(center.GetX(), center.GetY(), self.outer_radius, start_angle, end_angle) # plot a line for the inner arc. inner_arc_x, inner_arc_y = \ calculate_arc(center.GetX(), center.GetY(), self.inner_radius, start_angle, end_angle) # reverse the inner arc to set is up to be welded to the outer arc into a polygon. inner_arc_x = np.flip(inner_arc_x, 0) inner_arc_y = np.flip(inner_arc_y, 0) # glue the arcs together band_x = np.append(outer_arc_x, inner_arc_x) band_y = np.append(outer_arc_y, inner_arc_y) # complete the ring by adding taking the first point and adding it again at the end. first_x = band_x[0] first_y = band_y[0] band_x = np.append(band_x, first_x) band_y = np.append(band_y, first_y) # smash the x and y arrays together to get coordinate pairs. ring_coordinates = np.column_stack([band_x, band_y]) # Build the shapely linear ring . . . line_string: shp_geom.LinearRing = shp_geom.LinearRing(ring_coordinates) # so we can build a shapely polygon . . . arc_band_polygon: shp_geom.Polygon = shp_geom.Polygon(line_string) # so we can create the OGR geometry . . . arcband: ogr.Geometry = ogr.CreateGeometryFromWkb(arc_band_polygon.wkb) # so we can reproject back to the original coordinate system arcband = reproject_geom(arcband, utmsrid, self._spatial_ref_id) # so we can build and return a shapely geometry. (Whew!) return loads(arcband.ExportToWkt())
def test_getutmsrid(self): """ Convert Long/Lat to UTM Zone WGS_1984_UTM_Zone_19N 32619 :return: """ longitude = -68.84724495254032 latitude = 46.899295967195435 result = getutmsrid(longitude, latitude) self.assertEqual(result, 32619)
def _transform_circle(long, lat, srid, radius, uom): """ Takes the fundamental bits of a circle and converts it to a descritized circle (polygon) transformed to 4326. :param long: The x coordinate of the center. :type long: `float` :param lat: The lat coordinate of the center. :type lat: `float` :param srid: The spatial reference id of the center point. :type srid: `str` :param radius: The radius of the circle. :type radius: `float` :param uom: The unit of measure of the radius. :type uom: `str` :return: A WKBElement representation of the circle. :rtype: :py:class:geoalchemy2.types.WKBElement """ # Source spatial reference. source = osr.SpatialReference() source.ImportFromEPSG(srid) # TODO - Need to handle different values for the incoming UOM # TODO - Must have a lookup table of some kind. # The target will depend on the value of uom, but we'll just assume # it's 9001/meters for now and project to 3857. target = osr.SpatialReference() #target.ImportFromEPSG(3857) target.ImportFromEPSG(gc_geom.getutmsrid(longitude=long, latitude=lat)) # Set up the transform. transform = osr.CoordinateTransformation(source, target) # Create a geometry we can use with the transform. center = ogr.CreateGeometryFromWkt('POINT({0} {1})'.format(long, lat)) # Transform it and apply the buffer. center.Transform(transform) circle = center.Buffer(radius) # Now transform it back and extract the wkt reverse_transform = osr.CoordinateTransformation(target, source) circle.Transform(reverse_transform) wkt_circle = circle.ExportToWkt() # load up a new Shapely Polygon from the WKT and convert it to a GeoAlchemy2 WKBElement # that we can use to query. poly = loads(wkt_circle) wkb_circle = from_shape(poly, srid) return wkb_circle
def build_shapely_geometry(self) -> BaseGeometry: """ Builds the internal shapely representation of the geometry. This is used by other base class methods to build the other output types. :return: A shapely geometry specific to the derived type. :rtype: :py:class:`BaseGeometry` """ # Get the UTMSRID so we can transform the center point to a coordinate system where distance is # measured in meters. utmsrid: int = getutmsrid(self.longitude, self.latitude, self.sr_id) # Create the OGR Point center: ogr.Geometry = ogr.Geometry(ogr.wkbPoint) center.AssignSpatialReference(Geodetic2D.get_ogr_sr(self.sr_id)) center.AddPoint(self.longitude, self.latitude) # Project the point from its native projection to the UTM system. center = reproject_geom(center, self.sr_id, utmsrid) # Buffer the point with the radius to get a polygon of the circle. circle: ogr.Geometry = center.Buffer(1) # Create the shapely object so we can do the ellipse magic. proto_ellipse: BaseGeometry = loads(circle.ExportToWkt()) # stretch the ellipse along the major and minor axes scaled_ellipse: BaseGeometry = affinity.scale(proto_ellipse, self.majorAxis, self.minorAxis) rotate_angle = calculate_orientation(self.orientation) rotated_ellipse: BaseGeometry = None if rotate_angle >= 0: # Let rotate the ellipse (clockwise, x axis pointing right): rotated_ellipse = affinity.rotate(scaled_ellipse, rotate_angle, use_radians=True) else: # If one need to rotate it clockwise along an upward pointing x axis: rotated_ellipse = affinity.rotate(scaled_ellipse, 90 - rotate_angle, use_radians=True) # According to the man, a positive value means a anti-clockwise angle, # and a negative one a clockwise angle. # Now build an OGR geometry so we can reproject. ogr_ellipse: ogr.Geometry = ogr.CreateGeometryFromWkt(rotated_ellipse.wkt) ogr_ellipse.AssignSpatialReference(Geodetic2D.get_ogr_sr(utmsrid)) ogr_ellipse = reproject_geom(ogr_ellipse, utmsrid, self.sr_id) return loads(ogr_ellipse.ExportToWkt())
def get_intersecting_boundaries_with_buffer(long, lat, engine, table_name, geom, buffer_distance, return_intersection_area = False): retval = None try: # Get a reference to the table we're going to look in. tbl_metadata = MetaData(bind=engine) the_table = Table(table_name, tbl_metadata, autoload=True) # Construct the "contains" query and execute it. utmsrid = gc_geom.getutmsrid(long, lat, geom.srid) if return_intersection_area: # include a calculation for the intersecting the area s = select([the_table, the_table.c.wkb_geometry.ST_AsGML(), func.ST_Area( func.ST_Intersection( func.ST_Buffer(func.ST_Transform(func.ST_SetSRID(geom, geom.srid), utmsrid), buffer_distance), the_table.c.wkb_geometry.ST_Transform(utmsrid))).label( 'AREA_RET')], func.ST_Intersects( func.ST_Buffer(func.ST_Transform(func.ST_SetSRID(geom, geom.srid), utmsrid), buffer_distance), the_table.c.wkb_geometry.ST_Transform(utmsrid))) else: s = select([the_table, the_table.c.wkb_geometry.ST_AsGML()], func.ST_Intersects(func.ST_Buffer(func.ST_Transform(func.ST_SetSRID(geom,4326), utmsrid), buffer_distance), the_table.c.wkb_geometry.ST_Transform(utmsrid))) retval = _execute_query(engine, s) except SQLAlchemyError as ex: logger.error(ex) raise SpatialQueryException( 'Unable to construct contains query.', ex) except SpatialQueryException as ex: logger.error(ex) raise return retval
def _get_nearest_point(long, lat, engine, table_name, geom, buffer_distance=None): """ Queries the given table for the nearest boundary :param engine: SQLAlchemy database engine :type engine: :py:class:`sqlalchemy.engine.Engine` :param table_name: The name of the service boundary table. :type table_name: `str` :param geom: The geometry to use in the search as a GeoAlchemy WKBElement. :type geom: :py:class:geoalchemy2.types.WKBElement :return: A list of dictionaries containing the contents of returned rows. """ retval = None try: # Get a reference to the table we're going to look in. tbl_metadata = MetaData(bind=engine) the_table = Table(table_name, tbl_metadata, autoload=True) # Construct the "contains" query and execute it. utmsrid = gc_geom.getutmsrid(long, lat) s = select([the_table, the_table.c.wkb_geometry.ST_AsGML(), the_table.c.wkb_geometry.ST_Distance(geom).label('DISTANCE')], the_table.c.wkb_geometry.ST_Intersects( func.ST_Transform( func.ST_Buffer( func.ST_Transform( func.st_centroid(geom), utmsrid ),buffer_distance, 32), 4326)) ).order_by('DISTANCE').limit(1) retval = _execute_query(engine, s) except SQLAlchemyError as ex: logger.error(ex) raise SpatialQueryException( 'Unable to construct contains query.', ex) except SpatialQueryException as ex: logger.error(ex) raise return retval
def build_shapely_geometry(self) -> BaseGeometry: """ Builds the internal shapely representation of the geometry. This is used by other base class methods to build the other output types. :return: A shapely geometry specific to the derived type. :rtype: :py:class:`BaseGeometry` """ # Get the UTMSRID so we can transform the center point to a coordinate system where distance is # measured in meters. utmsrid: int = getutmsrid(self.longitude, self.latitude, self.sr_id) # Create the OGR Point center: ogr.Geometry = ogr.Geometry(ogr.wkbPoint) center.AddPoint(self.longitude, self.latitude) # Project the point from its native projection to the UTM system. center = reproject_geom(center, self.sr_id, utmsrid) # Buffer the point with the radius to get a polygon of the circle. circle: ogr.Geometry = center.Buffer(self.radius) # Project the circle back to the original system. circle = reproject_geom(circle, utmsrid, self.sr_id) # Return a shapely object constructed from the WKT of the OGR polygon return loads(circle.ExportToWkt())
def get_additionaldata_for_polygon(location: geodetic_polygon, boundary_table, engine, buffer_distance): """ Executes an addtional data query for a polygon. :param location: location object :type location: :py:class:Geodetic2D :param boundary_table: The name of the service boundary table. :type boundary_table: `str` :param engine: SQLAlchemy database engine. :type engine: :py:class:`sqlalchemy.engine.Engine` :param return_intersection_area: Flag which triggers an area calculation on the Intersecting polygons :type return_intersection_area bool :return: A list of dictionaries containing the contents of returned rows. """ # Pull out just the number from the SRID trimmed_srid = int(location.spatial_ref.split('::')[1]) p= [] points = location.vertices for point in points: long, lat = gc_geom.reproject_point(point[0], point[1], trimmed_srid, 4326) p.append([long, lat]) utmsrid = gc_geom.getutmsrid(p[0][0], p[0][1]) ring = LinearRing(p) shapely_polygon = Polygon(ring) # load up a new Shapely Polygon from the WKT and convert it to a GeoAlchemy2 WKBElement # that we can use to query. poly = loads(shapely_polygon.wkt) wkb_poly = location.to_wkbelement(project_to=trimmed_srid) results = _get_additional_data_for_geometry(engine, wkb_poly, boundary_table) if results is None: results = _get_additional_data_for_geometry_with_buffer(engine, wkb_poly, boundary_table, buffer_distance, utmsrid) return results
def _transform_ellipse(long ,lat , major, minor, orientation, srid): """ Takes the fundamental bits of a ellipse and converts it to a descritized ellipse (polygon) transformed to 4326. :param long: :param lat: :param major: :param minor: :param orientation: :param srid: :return: """ # Source spatial reference. source = osr.SpatialReference() source.ImportFromEPSG(srid) # TODO - Need to handle different values for the incoming UOM # TODO - Must have a lookup table of some kind. # The target will depend on the value of uom, but we'll just assume # it's 9001/meters for now. target = osr.SpatialReference() # target.ImportFromEPSG(3857) target.ImportFromEPSG(gc_geom.getutmsrid(long, lat, srid)) # Set up the transform. transform = osr.CoordinateTransformation(source, target) # Create a geometry we can use with the transform. center = ogr.CreateGeometryFromWkt('POINT({0} {1})'.format(long, lat)) # Transform it and apply the buffer. center.Transform(transform) cir = center.Buffer(1) wkt_cir = cir.ExportToWkt() # load up a new Shapely Polygon from the WKT and convert it to a GeoAlchemy2 WKBElement # that we can use to query. circle = loads(wkt_cir) # Let create the ellipse along x and y: ell = affinity.scale(circle, major, minor) # xml.py parse method has already converted GML degree's to radians rotate_angle = calculate_orientation(orientation) if rotate_angle >= 0: # Let rotate the ellipse (clockwise, x axis pointing right): ellr = affinity.rotate(ell, rotate_angle, use_radians=True) else: # If one need to rotate it clockwise along an upward pointing x axis: ellr = affinity.rotate(ell, 90 - rotate_angle, use_radians=True) # According to the man, a positive value means a anti-clockwise angle, # and a negative one a clockwise angle. # Convert from shapely to org org_ellipse = ogr.CreateGeometryFromWkt(ellr.wkt) # Now transform it back to 4326 and extract the wkt reverse_transform = osr.CoordinateTransformation(target, source) org_ellipse.Transform(reverse_transform) wkt_ellipse = org_ellipse.ExportToWkt() # load up a new Shapely Polygon from the WKT and convert it to a GeoAlchemy2 WKBElement # that we can use to query. poly = loads(wkt_ellipse) wkb_ellipse = from_shape(poly, srid) return wkb_ellipse