def __init__(self, verbose_name=None, srid=4326, spatial_index=True, dim=2, **kwargs): """ The initialization function for geometry fields. Takes the following as keyword arguments: srid: The spatial reference system identifier, an OGC standard. Defaults to 4326 (WGS84). spatial_index: Indicates whether to create a spatial index. Defaults to True. Set this instead of 'db_index' for geographic fields since index creation is different for geometry columns. dim: The number of dimensions for this geometry. Defaults to 2. """ # Setting the index flag with the value of the `spatial_index` keyword. self._index = spatial_index # Setting the SRID and getting the units. Unit information must be # easily available in the field instance for distance queries. self._srid = srid self._unit, self._unit_name, self._spheroid = get_srid_info(srid) # Setting the dimension of the geometry field. self._dim = dim # Setting the verbose_name keyword argument with the positional # first parameter, so this works like normal fields. kwargs['verbose_name'] = verbose_name super(GeometryField, self).__init__(**kwargs) # Calling the parent initializtion function
def __init__(self, srid=4326, spatial_index=True, dim=2, **kwargs): """ The initialization function for geometry fields. Takes the following as keyword arguments: srid: The spatial reference system identifier, an OGC standard. Defaults to 4326 (WGS84). spatial_index: Indicates whether to create a spatial index. Defaults to True. Set this instead of 'db_index' for geographic fields since index creation is different for geometry columns. dim: The number of dimensions for this geometry. Defaults to 2. """ # Setting the index flag with the value of the `spatial_index` keyword. self._index = spatial_index # Setting the SRID and getting the units. Unit information must be # easily available in the field instance for distance queries. self._srid = srid self._unit, self._unit_name, self._spheroid = get_srid_info(srid) # Setting the dimension of the geometry field. self._dim = dim super(GeometryField, self).__init__(**kwargs) # Calling the parent initializtion function
def _distance_attribute(self, func, geom=None, tolerance=0.05, spheroid=False, **kwargs): """ DRY routine for GeoQuerySet distance attribute routines. """ # Setting up the distance procedure arguments. procedure_args, geo_field = self._spatial_setup(func, field_name=kwargs.get( 'field_name', None)) # If geodetic defaulting distance attribute to meters (Oracle and # PostGIS spherical distances return meters). Otherwise, use the # units of the geometry field. if geo_field.geodetic: dist_att = 'm' else: dist_att = Distance.unit_attname(geo_field._unit_name) # Shortcut booleans for what distance function we're using. distance = func == 'distance' length = func == 'length' perimeter = func == 'perimeter' if not (distance or length or perimeter): raise ValueError('Unknown distance function: %s' % func) # The field's get_db_prep_lookup() is used to get any # extra distance parameters. Here we set up the # parameters that will be passed in to field's function. lookup_params = [geom or 'POINT (0 0)', 0] # If the spheroid calculation is desired, either by the `spheroid` # keyword or wehn calculating the length of geodetic field, make # sure the 'spheroid' distance setting string is passed in so we # get the correct spatial stored procedure. if spheroid or (SpatialBackend.postgis and geo_field.geodetic and length): lookup_params.append('spheroid') where, params = geo_field.get_db_prep_lookup('distance_lte', lookup_params) # The `geom_args` flag is set to true if a geometry parameter was # passed in. geom_args = bool(geom) if SpatialBackend.oracle: if distance: procedure_fmt = '%(geo_col)s,%(geom)s,%(tolerance)s' elif length or perimeter: procedure_fmt = '%(geo_col)s,%(tolerance)s' procedure_args['tolerance'] = tolerance else: # Getting whether this field is in units of degrees since the field may have # been transformed via the `transform` GeoQuerySet method. if self.query.transformed_srid: u, unit_name, s = get_srid_info(self.query.transformed_srid) geodetic = unit_name in geo_field.geodetic_units else: geodetic = geo_field.geodetic if distance: if self.query.transformed_srid: # Setting the `geom_args` flag to false because we want to handle # transformation SQL here, rather than the way done by default # (which will transform to the original SRID of the field rather # than to what was transformed to). geom_args = False procedure_fmt = '%s(%%(geo_col)s, %s)' % ( SpatialBackend.transform, self.query.transformed_srid) if geom.srid is None or geom.srid == self.query.transformed_srid: # If the geom parameter srid is None, it is assumed the coordinates # are in the transformed units. A placeholder is used for the # geometry parameter. procedure_fmt += ', %%s' else: # We need to transform the geom to the srid specified in `transform()`, # so wrapping the geometry placeholder in transformation SQL. procedure_fmt += ', %s(%%%%s, %s)' % ( SpatialBackend.transform, self.query.transformed_srid) else: # `transform()` was not used on this GeoQuerySet. procedure_fmt = '%(geo_col)s,%(geom)s' if geodetic: # Spherical distance calculation is needed (because the geographic # field is geodetic). However, the PostGIS ST_distance_sphere/spheroid() # procedures may only do queries from point columns to point geometries # some error checking is required. if not isinstance(geo_field, PointField): raise TypeError( 'Spherical distance calculation only supported on PointFields.' ) if not str( SpatialBackend.Geometry(buffer( params[0].wkb)).geom_type) == 'Point': raise TypeError( 'Spherical distance calculation only supported with Point Geometry parameters' ) # The `function` procedure argument needs to be set differently for # geodetic distance calculations. if spheroid: # Call to distance_spheroid() requires spheroid param as well. procedure_fmt += ',%(spheroid)s' procedure_args.update({ 'function': SpatialBackend.distance_spheroid, 'spheroid': where[1] }) else: procedure_args.update( {'function': SpatialBackend.distance_sphere}) elif length or perimeter: procedure_fmt = '%(geo_col)s' if geodetic and length: # There's no `length_sphere` procedure_fmt += ',%(spheroid)s' procedure_args.update({ 'function': SpatialBackend.length_spheroid, 'spheroid': where[1] }) # Setting up the settings for `_spatial_attribute`. s = { 'select_field': DistanceField(dist_att), 'setup': False, 'geo_field': geo_field, 'procedure_args': procedure_args, 'procedure_fmt': procedure_fmt, } if geom_args: s['geom_args'] = ('geom', ) s['procedure_args']['geom'] = geom elif geom: # The geometry is passed in as a parameter because we handled # transformation conditions in this routine. s['select_params'] = [SpatialBackend.Adaptor(geom)] return self._spatial_attribute(func, s, **kwargs)
def _distance_attribute(self, func, geom=None, tolerance=0.05, spheroid=False, **kwargs): """ DRY routine for GeoQuerySet distance attribute routines. """ # Setting up the distance procedure arguments. procedure_args, geo_field = self._spatial_setup(func, field_name=kwargs.get('field_name', None)) # If geodetic defaulting distance attribute to meters (Oracle and # PostGIS spherical distances return meters). Otherwise, use the # units of the geometry field. if geo_field.geodetic: dist_att = 'm' else: dist_att = Distance.unit_attname(geo_field._unit_name) # Shortcut booleans for what distance function we're using. distance = func == 'distance' length = func == 'length' perimeter = func == 'perimeter' if not (distance or length or perimeter): raise ValueError('Unknown distance function: %s' % func) # The field's get_db_prep_lookup() is used to get any # extra distance parameters. Here we set up the # parameters that will be passed in to field's function. lookup_params = [geom or 'POINT (0 0)', 0] # If the spheroid calculation is desired, either by the `spheroid` # keyword or wehn calculating the length of geodetic field, make # sure the 'spheroid' distance setting string is passed in so we # get the correct spatial stored procedure. if spheroid or (SpatialBackend.postgis and geo_field.geodetic and length): lookup_params.append('spheroid') where, params = geo_field.get_db_prep_lookup('distance_lte', lookup_params) # The `geom_args` flag is set to true if a geometry parameter was # passed in. geom_args = bool(geom) if SpatialBackend.oracle: if distance: procedure_fmt = '%(geo_col)s,%(geom)s,%(tolerance)s' elif length or perimeter: procedure_fmt = '%(geo_col)s,%(tolerance)s' procedure_args['tolerance'] = tolerance else: # Getting whether this field is in units of degrees since the field may have # been transformed via the `transform` GeoQuerySet method. if self.query.transformed_srid: u, unit_name, s = get_srid_info(self.query.transformed_srid) geodetic = unit_name in geo_field.geodetic_units else: geodetic = geo_field.geodetic if distance: if self.query.transformed_srid: # Setting the `geom_args` flag to false because we want to handle # transformation SQL here, rather than the way done by default # (which will transform to the original SRID of the field rather # than to what was transformed to). geom_args = False procedure_fmt = '%s(%%(geo_col)s, %s)' % (SpatialBackend.transform, self.query.transformed_srid) if geom.srid is None or geom.srid == self.query.transformed_srid: # If the geom parameter srid is None, it is assumed the coordinates # are in the transformed units. A placeholder is used for the # geometry parameter. procedure_fmt += ', %%s' else: # We need to transform the geom to the srid specified in `transform()`, # so wrapping the geometry placeholder in transformation SQL. procedure_fmt += ', %s(%%%%s, %s)' % (SpatialBackend.transform, self.query.transformed_srid) else: # `transform()` was not used on this GeoQuerySet. procedure_fmt = '%(geo_col)s,%(geom)s' if geodetic: # Spherical distance calculation is needed (because the geographic # field is geodetic). However, the PostGIS ST_distance_sphere/spheroid() # procedures may only do queries from point columns to point geometries # some error checking is required. if not isinstance(geo_field, PointField): raise TypeError('Spherical distance calculation only supported on PointFields.') if not str(SpatialBackend.Geometry(buffer(params[0].wkb)).geom_type) == 'Point': raise TypeError('Spherical distance calculation only supported with Point Geometry parameters') # The `function` procedure argument needs to be set differently for # geodetic distance calculations. if spheroid: # Call to distance_spheroid() requires spheroid param as well. procedure_fmt += ',%(spheroid)s' procedure_args.update({'function' : SpatialBackend.distance_spheroid, 'spheroid' : where[1]}) else: procedure_args.update({'function' : SpatialBackend.distance_sphere}) elif length or perimeter: procedure_fmt = '%(geo_col)s' if geodetic and length: # There's no `length_sphere` procedure_fmt += ',%(spheroid)s' procedure_args.update({'function' : SpatialBackend.length_spheroid, 'spheroid' : where[1]}) # Setting up the settings for `_spatial_attribute`. s = {'select_field' : DistanceField(dist_att), 'setup' : False, 'geo_field' : geo_field, 'procedure_args' : procedure_args, 'procedure_fmt' : procedure_fmt, } if geom_args: s['geom_args'] = ('geom',) s['procedure_args']['geom'] = geom elif geom: # The geometry is passed in as a parameter because we handled # transformation conditions in this routine. s['select_params'] = [SpatialBackend.Adaptor(geom)] return self._spatial_attribute(func, s, **kwargs)