예제 #1
0
    def test_hexewkb(self):
        "Testing (HEX)EWKB output."
        # For testing HEX(EWKB).
        ogc_hex = b'01010000000000000000000000000000000000F03F'
        ogc_hex_3d = b'01010000800000000000000000000000000000F03F0000000000000040'
        # `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));`
        hexewkb_2d = b'0101000020E61000000000000000000000000000000000F03F'
        # `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));`
        hexewkb_3d = b'01010000A0E61000000000000000000000000000000000F03F0000000000000040'

        pnt_2d = Point(0, 1, srid=4326)
        pnt_3d = Point(0, 1, 2, srid=4326)

        # OGC-compliant HEX will not have SRID value.
        self.assertEqual(ogc_hex, pnt_2d.hex)
        self.assertEqual(ogc_hex_3d, pnt_3d.hex)

        # HEXEWKB should be appropriate for its dimension -- have to use an
        # a WKBWriter w/dimension set accordingly, else GEOS will insert
        # garbage into 3D coordinate if there is none.  Also, GEOS has a
        # a bug in versions prior to 3.1 that puts the X coordinate in
        # place of Z; an exception should be raised on those versions.
        self.assertEqual(hexewkb_2d, pnt_2d.hexewkb)
        self.assertEqual(hexewkb_3d, pnt_3d.hexewkb)
        self.assertEqual(True, GEOSGeometry(hexewkb_3d).hasz)

        # Same for EWKB.
        self.assertEqual(memoryview(a2b_hex(hexewkb_2d)), pnt_2d.ewkb)
        self.assertEqual(memoryview(a2b_hex(hexewkb_3d)), pnt_3d.ewkb)

        # Redundant sanity check.
        self.assertEqual(4326, GEOSGeometry(hexewkb_2d).srid)
예제 #2
0
    def test_hexewkb(self):
        "Testing (HEX)EWKB output."
        # For testing HEX(EWKB).
        ogc_hex = b'01010000000000000000000000000000000000F03F'
        ogc_hex_3d = b'01010000800000000000000000000000000000F03F0000000000000040'
        # `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));`
        hexewkb_2d = b'0101000020E61000000000000000000000000000000000F03F'
        # `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));`
        hexewkb_3d = b'01010000A0E61000000000000000000000000000000000F03F0000000000000040'

        pnt_2d = Point(0, 1, srid=4326)
        pnt_3d = Point(0, 1, 2, srid=4326)

        # OGC-compliant HEX will not have SRID value.
        self.assertEqual(ogc_hex, pnt_2d.hex)
        self.assertEqual(ogc_hex_3d, pnt_3d.hex)

        # HEXEWKB should be appropriate for its dimension -- have to use an
        # a WKBWriter w/dimension set accordingly, else GEOS will insert
        # garbage into 3D coordinate if there is none.
        self.assertEqual(hexewkb_2d, pnt_2d.hexewkb)
        self.assertEqual(hexewkb_3d, pnt_3d.hexewkb)
        self.assertEqual(True, GEOSGeometry(hexewkb_3d).hasz)

        # Same for EWKB.
        self.assertEqual(memoryview(a2b_hex(hexewkb_2d)), pnt_2d.ewkb)
        self.assertEqual(memoryview(a2b_hex(hexewkb_3d)), pnt_3d.ewkb)

        # Redundant sanity check.
        self.assertEqual(4326, GEOSGeometry(hexewkb_2d).srid)
예제 #3
0
    def test04_wkbwriter(self):
        wkb_w = WKBWriter()

        # Representations of 'POINT (5 23)' in hex -- one normal and
        # the other with the byte order changed.
        g = GEOSGeometry('POINT (5 23)')
        hex1 = b'010100000000000000000014400000000000003740'
        wkb1 = memoryview(binascii.a2b_hex(hex1))
        hex2 = b'000000000140140000000000004037000000000000'
        wkb2 = memoryview(binascii.a2b_hex(hex2))

        self.assertEqual(hex1, wkb_w.write_hex(g))
        self.assertEqual(wkb1, wkb_w.write(g))

        # Ensuring bad byteorders are not accepted.
        for bad_byteorder in (-1, 2, 523, 'foo', None):
            # Equivalent of `wkb_w.byteorder = bad_byteorder`
            self.assertRaises(ValueError, wkb_w._set_byteorder, bad_byteorder)

        # Setting the byteorder to 0 (for Big Endian)
        wkb_w.byteorder = 0
        self.assertEqual(hex2, wkb_w.write_hex(g))
        self.assertEqual(wkb2, wkb_w.write(g))

        # Back to Little Endian
        wkb_w.byteorder = 1

        # Now, trying out the 3D and SRID flags.
        g = GEOSGeometry('POINT (5 23 17)')
        g.srid = 4326

        hex3d = b'0101000080000000000000144000000000000037400000000000003140'
        wkb3d = memoryview(binascii.a2b_hex(hex3d))
        hex3d_srid = b'01010000A0E6100000000000000000144000000000000037400000000000003140'
        wkb3d_srid = memoryview(binascii.a2b_hex(hex3d_srid))

        # Ensuring bad output dimensions are not accepted
        for bad_outdim in (-1, 0, 1, 4, 423, 'foo', None):
            # Equivalent of `wkb_w.outdim = bad_outdim`
            self.assertRaises(ValueError, wkb_w._set_outdim, bad_outdim)

        # These tests will fail on 3.0.0 because of a bug that was fixed in 3.1:
        # http://trac.osgeo.org/geos/ticket/216
        if not geos_version_info()['version'].startswith('3.0.'):
            # Now setting the output dimensions to be 3
            wkb_w.outdim = 3

            self.assertEqual(hex3d, wkb_w.write_hex(g))
            self.assertEqual(wkb3d, wkb_w.write(g))

            # Telling the WKBWriter to include the srid in the representation.
            wkb_w.srid = True
            self.assertEqual(hex3d_srid, wkb_w.write_hex(g))
            self.assertEqual(wkb3d_srid, wkb_w.write(g))
예제 #4
0
파일: test_io.py 프로젝트: Caramel/django
    def test04_wkbwriter(self):
        wkb_w = WKBWriter()

        # Representations of 'POINT (5 23)' in hex -- one normal and
        # the other with the byte order changed.
        g = GEOSGeometry('POINT (5 23)')
        hex1 = b'010100000000000000000014400000000000003740'
        wkb1 = memoryview(binascii.a2b_hex(hex1))
        hex2 = b'000000000140140000000000004037000000000000'
        wkb2 = memoryview(binascii.a2b_hex(hex2))

        self.assertEqual(hex1, wkb_w.write_hex(g))
        self.assertEqual(wkb1, wkb_w.write(g))

        # Ensuring bad byteorders are not accepted.
        for bad_byteorder in (-1, 2, 523, 'foo', None):
            # Equivalent of `wkb_w.byteorder = bad_byteorder`
            self.assertRaises(ValueError, wkb_w._set_byteorder, bad_byteorder)

        # Setting the byteorder to 0 (for Big Endian)
        wkb_w.byteorder = 0
        self.assertEqual(hex2, wkb_w.write_hex(g))
        self.assertEqual(wkb2, wkb_w.write(g))

        # Back to Little Endian
        wkb_w.byteorder = 1

        # Now, trying out the 3D and SRID flags.
        g = GEOSGeometry('POINT (5 23 17)')
        g.srid = 4326

        hex3d = b'0101000080000000000000144000000000000037400000000000003140'
        wkb3d = memoryview(binascii.a2b_hex(hex3d))
        hex3d_srid = b'01010000A0E6100000000000000000144000000000000037400000000000003140'
        wkb3d_srid = memoryview(binascii.a2b_hex(hex3d_srid))

        # Ensuring bad output dimensions are not accepted
        for bad_outdim in (-1, 0, 1, 4, 423, 'foo', None):
            # Equivalent of `wkb_w.outdim = bad_outdim`
            self.assertRaises(ValueError, wkb_w._set_outdim, bad_outdim)

        # These tests will fail on 3.0.0 because of a bug that was fixed in 3.1:
        # http://trac.osgeo.org/geos/ticket/216
        if not geos_version_info()['version'].startswith('3.0.'):
            # Now setting the output dimensions to be 3
            wkb_w.outdim = 3

            self.assertEqual(hex3d, wkb_w.write_hex(g))
            self.assertEqual(wkb3d, wkb_w.write(g))

            # Telling the WKBWriter to include the srid in the representation.
            wkb_w.srid = True
            self.assertEqual(hex3d_srid, wkb_w.write_hex(g))
            self.assertEqual(wkb3d_srid, wkb_w.write(g))
예제 #5
0
    def test_hexewkb(self):
        "Testing (HEX)EWKB output."
        # For testing HEX(EWKB).
        ogc_hex = b'01010000000000000000000000000000000000F03F'
        ogc_hex_3d = b'01010000800000000000000000000000000000F03F0000000000000040'
        # `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));`
        hexewkb_2d = b'0101000020E61000000000000000000000000000000000F03F'
        # `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));`
        hexewkb_3d = b'01010000A0E61000000000000000000000000000000000F03F0000000000000040'

        pnt_2d = Point(0, 1, srid=4326)
        pnt_3d = Point(0, 1, 2, srid=4326)

        # OGC-compliant HEX will not have SRID value.
        self.assertEqual(ogc_hex, pnt_2d.hex)
        self.assertEqual(ogc_hex_3d, pnt_3d.hex)

        # HEXEWKB should be appropriate for its dimension -- have to use an
        # a WKBWriter w/dimension set accordingly, else GEOS will insert
        # garbage into 3D coordinate if there is none.  Also, GEOS has a
        # a bug in versions prior to 3.1 that puts the X coordinate in
        # place of Z; an exception should be raised on those versions.
        self.assertEqual(hexewkb_2d, pnt_2d.hexewkb)
        if GEOS_PREPARE:
            self.assertEqual(hexewkb_3d, pnt_3d.hexewkb)
            self.assertEqual(True, GEOSGeometry(hexewkb_3d).hasz)
        else:
            try:
                hexewkb = pnt_3d.hexewkb
            except GEOSException:
                pass
            else:
                self.fail('Should have raised GEOSException.')

        # Same for EWKB.
        self.assertEqual(memoryview(a2b_hex(hexewkb_2d)), pnt_2d.ewkb)
        if GEOS_PREPARE:
            self.assertEqual(memoryview(a2b_hex(hexewkb_3d)), pnt_3d.ewkb)
        else:
            try:
                ewkb = pnt_3d.ewkb
            except GEOSException:
                pass
            else:
                self.fail('Should have raised GEOSException')

        # Redundant sanity check.
        self.assertEqual(4326, GEOSGeometry(hexewkb_2d).srid)
예제 #6
0
 def __setstate__(self, state):
     # Instantiating from the tuple state that was pickled.
     wkb, srid = state
     ptr = wkb_r().read(memoryview(wkb))
     if not ptr: raise GEOSException('Invalid Geometry loaded from pickled state.')
     self.ptr = ptr
     self._post_init(srid)
예제 #7
0
 def __setstate__(self, state):
     # Instantiating from the tuple state that was pickled.
     wkb, srid = state
     ptr = wkb_r().read(memoryview(wkb))
     if not ptr: raise GEOSException('Invalid Geometry loaded from pickled state.')
     self.ptr = ptr
     self._post_init(srid)
예제 #8
0
 def test_create_wkb(self):
     "Testing creation from WKB."
     for g in self.geometries.hex_wkt:
         wkb = memoryview(a2b_hex(g.hex.encode()))
         geom_h = GEOSGeometry(wkb)
         # we need to do this so decimal places get normalised
         geom_t = fromstr(g.wkt)
         self.assertEqual(geom_t.wkt, geom_h.wkt)
예제 #9
0
 def test_create_wkb(self):
     "Testing creation from WKB."
     for g in self.geometries.hex_wkt:
         wkb = memoryview(a2b_hex(g.hex.encode()))
         geom_h = GEOSGeometry(wkb)
         # we need to do this so decimal places get normalised
         geom_t = fromstr(g.wkt)
         self.assertEqual(geom_t.wkt, geom_h.wkt)
예제 #10
0
    def __init__(self, geom_input, srs=None):
        "Initializes Geometry on either WKT or an OGR pointer as input."

        str_instance = isinstance(geom_input, six.string_types)

        # If HEX, unpack input to a binary buffer.
        if str_instance and hex_regex.match(geom_input):
            geom_input = memoryview(a2b_hex(geom_input.upper().encode()))
            str_instance = False

        # Constructing the geometry,
        if str_instance:
            wkt_m = wkt_regex.match(geom_input)
            json_m = json_regex.match(geom_input)
            if wkt_m:
                if wkt_m.group('srid'):
                    # If there's EWKT, set the SRS w/value of the SRID.
                    srs = int(wkt_m.group('srid'))
                if wkt_m.group('type').upper() == 'LINEARRING':
                    # OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
                    #  See http://trac.osgeo.org/gdal/ticket/1992.
                    g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num)
                    capi.import_wkt(g, byref(c_char_p(wkt_m.group('wkt').encode())))
                else:
                    g = capi.from_wkt(byref(c_char_p(wkt_m.group('wkt').encode())), None, byref(c_void_p()))
            elif json_m:
                g = capi.from_json(geom_input.encode())
            else:
                # Seeing if the input is a valid short-hand string
                # (e.g., 'Point', 'POLYGON').
                OGRGeomType(geom_input)
                g = capi.create_geom(OGRGeomType(geom_input).num)
        elif isinstance(geom_input, memoryview):
            # WKB was passed in
            g = capi.from_wkb(bytes(geom_input), None, byref(c_void_p()), len(geom_input))
        elif isinstance(geom_input, OGRGeomType):
            # OGRGeomType was passed in, an empty geometry will be created.
            g = capi.create_geom(geom_input.num)
        elif isinstance(geom_input, self.ptr_type):
            # OGR pointer (c_void_p) was the input.
            g = geom_input
        else:
            raise OGRException('Invalid input type for OGR Geometry construction: %s' % type(geom_input))

        # Now checking the Geometry pointer before finishing initialization
        # by setting the pointer for the object.
        if not g:
            raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
        self.ptr = g

        # Assigning the SpatialReference object to the geometry, if valid.
        if srs:
            self.srs = srs

        # Setting the class depending upon the OGR Geometry Type
        self.__class__ = GEO_CLASSES[self.geom_type.num]
예제 #11
0
    def __init__(self, geom_input, srs=None):
        "Initializes Geometry on either WKT or an OGR pointer as input."

        str_instance = isinstance(geom_input, six.string_types)

        # If HEX, unpack input to a binary buffer.
        if str_instance and hex_regex.match(geom_input):
            geom_input = memoryview(a2b_hex(geom_input.upper().encode()))
            str_instance = False

        # Constructing the geometry,
        if str_instance:
            wkt_m = wkt_regex.match(geom_input)
            json_m = json_regex.match(geom_input)
            if wkt_m:
                if wkt_m.group('srid'):
                    # If there's EWKT, set the SRS w/value of the SRID.
                    srs = int(wkt_m.group('srid'))
                if wkt_m.group('type').upper() == 'LINEARRING':
                    # OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
                    #  See http://trac.osgeo.org/gdal/ticket/1992.
                    g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num)
                    capi.import_wkt(g, byref(c_char_p(wkt_m.group('wkt').encode())))
                else:
                    g = capi.from_wkt(byref(c_char_p(wkt_m.group('wkt').encode())), None, byref(c_void_p()))
            elif json_m:
                g = capi.from_json(geom_input.encode())
            else:
                # Seeing if the input is a valid short-hand string
                # (e.g., 'Point', 'POLYGON').
                ogr_t = OGRGeomType(geom_input)
                g = capi.create_geom(OGRGeomType(geom_input).num)
        elif isinstance(geom_input, memoryview):
            # WKB was passed in
            g = capi.from_wkb(bytes(geom_input), None, byref(c_void_p()), len(geom_input))
        elif isinstance(geom_input, OGRGeomType):
            # OGRGeomType was passed in, an empty geometry will be created.
            g = capi.create_geom(geom_input.num)
        elif isinstance(geom_input, self.ptr_type):
            # OGR pointer (c_void_p) was the input.
            g = geom_input
        else:
            raise OGRException('Invalid input type for OGR Geometry construction: %s' % type(geom_input))

        # Now checking the Geometry pointer before finishing initialization
        # by setting the pointer for the object.
        if not g:
            raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
        self.ptr = g

        # Assigning the SpatialReference object to the geometry, if valid.
        if bool(srs): self.srs = srs

        # Setting the class depending upon the OGR Geometry Type
        self.__class__ = GEO_CLASSES[self.geom_type.num]
예제 #12
0
 def wkb(self):
     "Returns the WKB representation of the Geometry."
     if sys.byteorder == 'little':
         byteorder = 1  # wkbNDR (from ogr_core.h)
     else:
         byteorder = 0  # wkbXDR
     sz = self.wkb_size
     # Creating the unsigned character buffer, and passing it in by reference.
     buf = (c_ubyte * sz)()
     capi.to_wkb(self.ptr, byteorder, byref(buf))
     # Returning a buffer of the string at the pointer.
     return memoryview(string_at(buf, sz))
예제 #13
0
파일: geometries.py 프로젝트: 007lva/mmddpp
 def wkb(self):
     "Returns the WKB representation of the Geometry."
     if sys.byteorder == 'little':
         byteorder = 1 # wkbNDR (from ogr_core.h)
     else:
         byteorder = 0 # wkbXDR
     sz = self.wkb_size
     # Creating the unsigned character buffer, and passing it in by reference.
     buf = (c_ubyte * sz)()
     wkb = capi.to_wkb(self.ptr, byteorder, byref(buf))
     # Returning a buffer of the string at the pointer.
     return memoryview(string_at(buf, sz))
예제 #14
0
    def test01_wktreader(self):
        # Creating a WKTReader instance
        wkt_r = WKTReader()
        wkt = 'POINT (5 23)'

        # read() should return a GEOSGeometry
        ref = GEOSGeometry(wkt)
        g1 = wkt_r.read(wkt.encode())
        g2 = wkt_r.read(wkt)

        for geom in (g1, g2):
            self.assertEqual(ref, geom)

        # Should only accept six.string_types objects.
        self.assertRaises(TypeError, wkt_r.read, 1)
        self.assertRaises(TypeError, wkt_r.read, memoryview(b'foo'))
예제 #15
0
파일: test_io.py 프로젝트: Caramel/django
    def test01_wktreader(self):
        # Creating a WKTReader instance
        wkt_r = WKTReader()
        wkt = 'POINT (5 23)'

        # read() should return a GEOSGeometry
        ref = GEOSGeometry(wkt)
        g1 = wkt_r.read(wkt.encode())
        g2 = wkt_r.read(wkt)

        for geom in (g1, g2):
            self.assertEqual(ref, geom)

        # Should only accept six.string_types objects.
        self.assertRaises(TypeError, wkt_r.read, 1)
        self.assertRaises(TypeError, wkt_r.read, memoryview(b'foo'))
예제 #16
0
    def test_errors(self):
        "Testing the Error handlers."
        # string-based
        for err in self.geometries.errors:
            with self.assertRaises((GEOSException, ValueError)):
                _ = fromstr(err.wkt)

        # Bad WKB
        self.assertRaises(GEOSException, GEOSGeometry, memoryview(b'0'))

        class NotAGeometry(object):
            pass

        # Some other object
        self.assertRaises(TypeError, GEOSGeometry, NotAGeometry())
        # None
        self.assertRaises(TypeError, GEOSGeometry, None)
예제 #17
0
    def test_errors(self):
        "Testing the Error handlers."
        # string-based
        for err in self.geometries.errors:
            with self.assertRaises((GEOSException, ValueError)):
                fromstr(err.wkt)

        # Bad WKB
        self.assertRaises(GEOSException, GEOSGeometry, memoryview(b'0'))

        class NotAGeometry(object):
            pass

        # Some other object
        self.assertRaises(TypeError, GEOSGeometry, NotAGeometry())
        # None
        self.assertRaises(TypeError, GEOSGeometry, None)
예제 #18
0
파일: test_io.py 프로젝트: Caramel/django
    def test03_wkbreader(self):
        # Creating a WKBReader instance
        wkb_r = WKBReader()

        hex = b'000000000140140000000000004037000000000000'
        wkb = memoryview(binascii.a2b_hex(hex))
        ref = GEOSGeometry(hex)

        # read() should return a GEOSGeometry on either a hex string or
        # a WKB buffer.
        g1 = wkb_r.read(wkb)
        g2 = wkb_r.read(hex)
        for geom in (g1, g2):
            self.assertEqual(ref, geom)

        bad_input = (1, 5.23, None, False)
        for bad_wkb in bad_input:
            self.assertRaises(TypeError, wkb_r.read, bad_wkb)
예제 #19
0
    def test03_wkbreader(self):
        # Creating a WKBReader instance
        wkb_r = WKBReader()

        hex = b'000000000140140000000000004037000000000000'
        wkb = memoryview(binascii.a2b_hex(hex))
        ref = GEOSGeometry(hex)

        # read() should return a GEOSGeometry on either a hex string or
        # a WKB buffer.
        g1 = wkb_r.read(wkb)
        g2 = wkb_r.read(hex)
        for geom in (g1, g2):
            self.assertEqual(ref, geom)

        bad_input = (1, 5.23, None, False)
        for bad_wkb in bad_input:
            self.assertRaises(TypeError, wkb_r.read, bad_wkb)
예제 #20
0
    def test_errors(self):
        "Testing the Error handlers."
        # string-based
        print("\nBEGIN - expecting GEOS_ERROR; safe to ignore.\n")
        for err in self.geometries.errors:
            try:
                g = fromstr(err.wkt)
            except (GEOSException, ValueError):
                pass

        # Bad WKB
        self.assertRaises(GEOSException, GEOSGeometry, memoryview(b'0'))

        print("\nEND - expecting GEOS_ERROR; safe to ignore.\n")

        class NotAGeometry(object):
            pass

        # Some other object
        self.assertRaises(TypeError, GEOSGeometry, NotAGeometry())
        # None
        self.assertRaises(TypeError, GEOSGeometry, None)
예제 #21
0
def fromfile(file_h):
    """
    Given a string file name, returns a GEOSGeometry. The file may contain WKB,
    WKT, or HEX.
    """
    # If given a file name, get a real handle.
    if isinstance(file_h, six.string_types):
        with open(file_h, "rb") as file_h:
            buf = file_h.read()
    else:
        buf = file_h.read()

    # If we get WKB need to wrap in memoryview(), so run through regexes.
    if isinstance(buf, bytes):
        try:
            decoded = buf.decode()
            if wkt_regex.match(decoded) or hex_regex.match(decoded):
                return GEOSGeometry(decoded)
        except UnicodeDecodeError:
            pass
    else:
        return GEOSGeometry(buf)

    return GEOSGeometry(memoryview(buf))
예제 #22
0
def fromfile(file_h):
    """
    Given a string file name, returns a GEOSGeometry. The file may contain WKB,
    WKT, or HEX.
    """
    # If given a file name, get a real handle.
    if isinstance(file_h, six.string_types):
        with open(file_h, 'rb') as file_h:
            buf = file_h.read()
    else:
        buf = file_h.read()

    # If we get WKB need to wrap in memoryview(), so run through regexes.
    if isinstance(buf, bytes):
        try:
            decoded = buf.decode()
            if wkt_regex.match(decoded) or hex_regex.match(decoded):
                return GEOSGeometry(decoded)
        except UnicodeDecodeError:
            pass
    else:
        return GEOSGeometry(buf)

    return GEOSGeometry(memoryview(buf))
예제 #23
0
    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.
        connection = connections[self.db]
        geodetic = geo_field.geodetic(connection)
        geography = geo_field.geography

        if geodetic:
            dist_att = 'm'
        else:
            dist_att = Distance.unit_attname(geo_field.units_name(connection))

        # Shortcut booleans for what distance function we're using and
        # whether the geometry field is 3D.
        distance = func == 'distance'
        length = func == 'length'
        perimeter = func == 'perimeter'
        if not (distance or length or perimeter):
            raise ValueError('Unknown distance function: %s' % func)
        geom_3d = geo_field.dim == 3

        # 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]

        # Getting the spatial backend operations.
        backend = connection.ops

        # If the spheroid calculation is desired, either by the `spheroid`
        # keyword or when 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 (backend.postgis and geodetic and
                        (not geography) and length):
            lookup_params.append('spheroid')
        lookup_params = geo_field.get_prep_value(lookup_params)
        params = geo_field.get_db_prep_lookup('distance_lte',
                                              lookup_params,
                                              connection=connection)

        # The `geom_args` flag is set to true if a geometry parameter was
        # passed in.
        geom_args = bool(geom)

        if backend.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,
                                                connection)
                geodetic = unit_name in geo_field.geodetic_units

            if backend.spatialite and geodetic:
                raise ValueError(
                    'SQLite does not support linear distance calculations on geodetic coordinate systems.'
                )

            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)' % (
                        backend.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.  `GeomFromText` constructor is also needed
                        # to wrap geom placeholder for SpatiaLite.
                        if backend.spatialite:
                            procedure_fmt += ', %s(%%%%s, %s)' % (
                                backend.from_text, self.query.transformed_srid)
                        else:
                            procedure_fmt += ', %%s'
                    else:
                        # We need to transform the geom to the srid specified in `transform()`,
                        # so wrapping the geometry placeholder in transformation SQL.
                        # SpatiaLite also needs geometry placeholder wrapped in `GeomFromText`
                        # constructor.
                        if backend.spatialite:
                            procedure_fmt += ', %s(%s(%%%%s, %s), %s)' % (
                                backend.transform, backend.from_text,
                                geom.srid, self.query.transformed_srid)
                        else:
                            procedure_fmt += ', %s(%%%%s, %s)' % (
                                backend.transform, self.query.transformed_srid)
                else:
                    # `transform()` was not used on this GeoQuerySet.
                    procedure_fmt = '%(geo_col)s,%(geom)s'

                if not geography and 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 backend.geography:
                        if not isinstance(geo_field, PointField):
                            raise ValueError(
                                'Spherical distance calculation only supported on PointFields.'
                            )
                        if not str(
                                Geometry(memoryview(
                                    params[0].ewkb)).geom_type) == 'Point':
                            raise ValueError(
                                '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': backend.distance_spheroid,
                            'spheroid': params[1]
                        })
                    else:
                        procedure_args.update(
                            {'function': backend.distance_sphere})
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s'
                if not geography and geodetic and length:
                    # There's no `length_sphere`, and `length_spheroid` also
                    # works on 3D geometries.
                    procedure_fmt += ",'%(spheroid)s'"
                    procedure_args.update({
                        'function': backend.length_spheroid,
                        'spheroid': params[1]
                    })
                elif geom_3d and backend.postgis:
                    # Use 3D variants of perimeter and length routines on PostGIS.
                    if perimeter:
                        procedure_args.update(
                            {'function': backend.perimeter3d})
                    elif length:
                        procedure_args.update({'function': backend.length3d})

        # 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'] = [backend.Adapter(geom)]
        return self._spatial_attribute(func, s, **kwargs)
예제 #24
0
파일: io.py 프로젝트: hexxter/django
 def write(self, geom):
     "Returns the WKB representation of the given geometry."
     return memoryview(wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))
예제 #25
0
    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.
        connection = connections[self.db]
        geodetic = geo_field.geodetic(connection)
        geography = geo_field.geography

        if geodetic:
            dist_att = 'm'
        else:
            dist_att = Distance.unit_attname(geo_field.units_name(connection))

        # Shortcut booleans for what distance function we're using and
        # whether the geometry field is 3D.
        distance = func == 'distance'
        length = func == 'length'
        perimeter = func == 'perimeter'
        if not (distance or length or perimeter):
            raise ValueError('Unknown distance function: %s' % func)
        geom_3d = geo_field.dim == 3

        # 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]

        # Getting the spatial backend operations.
        backend = connection.ops

        # If the spheroid calculation is desired, either by the `spheroid`
        # keyword or when 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 (backend.postgis and geodetic and
                        (not geography) and length):
            lookup_params.append('spheroid')
        lookup_params = geo_field.get_prep_value(lookup_params)
        params = geo_field.get_db_prep_lookup('distance_lte', lookup_params, connection=connection)

        # The `geom_args` flag is set to true if a geometry parameter was
        # passed in.
        geom_args = bool(geom)

        if backend.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, connection)
                geodetic = unit_name in geo_field.geodetic_units

            if backend.spatialite and geodetic:
                raise ValueError('SQLite does not support linear distance calculations on geodetic coordinate systems.')

            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)' % (backend.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.  `GeomFromText` constructor is also needed
                        # to wrap geom placeholder for SpatiaLite.
                        if backend.spatialite:
                            procedure_fmt += ', %s(%%%%s, %s)' % (backend.from_text, self.query.transformed_srid)
                        else:
                            procedure_fmt += ', %%s'
                    else:
                        # We need to transform the geom to the srid specified in `transform()`,
                        # so wrapping the geometry placeholder in transformation SQL.
                        # SpatiaLite also needs geometry placeholder wrapped in `GeomFromText`
                        # constructor.
                        if backend.spatialite:
                            procedure_fmt += ', %s(%s(%%%%s, %s), %s)' % (backend.transform, backend.from_text,
                                                                          geom.srid, self.query.transformed_srid)
                        else:
                            procedure_fmt += ', %s(%%%%s, %s)' % (backend.transform, self.query.transformed_srid)
                else:
                    # `transform()` was not used on this GeoQuerySet.
                    procedure_fmt  = '%(geo_col)s,%(geom)s'

                if not geography and 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 backend.geography:
                        if not isinstance(geo_field, PointField):
                            raise ValueError('Spherical distance calculation only supported on PointFields.')
                        if not str(Geometry(memoryview(params[0].ewkb)).geom_type) == 'Point':
                            raise ValueError('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' : backend.distance_spheroid, 'spheroid' : params[1]})
                    else:
                        procedure_args.update({'function' : backend.distance_sphere})
            elif length or perimeter:
                procedure_fmt = '%(geo_col)s'
                if not geography and geodetic and length:
                    # There's no `length_sphere`, and `length_spheroid` also
                    # works on 3D geometries.
                    procedure_fmt += ",'%(spheroid)s'"
                    procedure_args.update({'function' : backend.length_spheroid, 'spheroid' : params[1]})
                elif geom_3d and backend.postgis:
                    # Use 3D variants of perimeter and length routines on PostGIS.
                    if perimeter:
                        procedure_args.update({'function' : backend.perimeter3d})
                    elif length:
                        procedure_args.update({'function' : backend.length3d})

        # 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'] = [backend.Adapter(geom)]
        return self._spatial_attribute(func, s, **kwargs)
예제 #26
0
파일: io.py 프로젝트: schoonc/django
 def write(self, geom):
     "Returns the WKB representation of the given geometry."
     return memoryview(
         wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))