Changeset 6978
- Timestamp:
- 12/25/07 15:27:56 (7 months ago)
- Files:
-
- django/branches/gis/django/contrib/gis/geos/base.py (modified) (29 diffs)
- django/branches/gis/django/contrib/gis/geos/collections.py (modified) (3 diffs)
- django/branches/gis/django/contrib/gis/geos/coordseq.py (modified) (5 diffs)
- django/branches/gis/django/contrib/gis/geos/geometries.py (modified) (7 diffs)
- django/branches/gis/django/contrib/gis/geos/__init__.py (modified) (1 diff)
- django/branches/gis/django/contrib/gis/geos/libgeos.py (modified) (3 diffs)
- django/branches/gis/django/contrib/gis/geos/prototypes/geom.py (modified) (1 diff)
- django/branches/gis/django/contrib/gis/tests/test_geos.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/gis/django/contrib/gis/geos/base.py
r6884 r6978 91 91 # geometries that do not have coordinate sequences) 92 92 self._set_cs() 93 94 @property 95 def ptr(self): 96 """ 97 Property for controlling access to the GEOS geometry pointer. Using 98 this raises an exception when the pointer is NULL, thus preventing 99 the C library from attempting to access an invalid memory location. 100 """ 101 if self._ptr: 102 return self._ptr 103 else: 104 raise GEOSException('NULL GEOS pointer encountered; was this geometry modified?') 93 105 94 106 def __del__(self): … … 98 110 """ 99 111 if self._ptr: destroy_geom(self._ptr) 112 113 def __copy__(self): 114 """ 115 Returns a clone because the copy of a GEOSGeometry may contain an 116 invalid pointer location if the original is garbage collected. 117 """ 118 return self.clone() 119 120 def __deepcopy__(self, memodict): 121 """ 122 The `deepcopy` routine is used by the `Node` class of django.utils.tree; 123 thus, the protocol routine needs to be implemented to return correct 124 copies (clones) of these GEOS objects, which use C pointers. 125 """ 126 return self.clone() 100 127 101 128 def __str__(self): … … 105 132 def __repr__(self): 106 133 "Short-hand representation because WKT may be very large." 107 return '<%s object at %s>' % (self.geom_type, hex(addressof(self. _ptr)))134 return '<%s object at %s>' % (self.geom_type, hex(addressof(self.ptr))) 108 135 109 136 # Comparison operators 110 137 def __eq__(self, other): 111 "Equivalence testing." 112 return self.equals_exact(other) 138 """ 139 Equivalence testing, a Geometry may be compared with another Geometry 140 or a WKT representation. 141 """ 142 if isinstance(other, basestring): 143 return self.wkt == other 144 else: 145 return self.equals_exact(other) 113 146 114 147 def __ne__(self, other): 115 148 "The not equals operator." 116 return not self.equals_exact(other)149 return not (self == other) 117 150 118 151 ### Geometry set-like operations ### … … 152 185 "Sets the coordinate sequence for this Geometry." 153 186 if self.has_cs: 154 self._cs = GEOSCoordSeq(get_cs(self. _ptr), self.hasz)187 self._cs = GEOSCoordSeq(get_cs(self.ptr), self.hasz) 155 188 else: 156 189 self._cs = None … … 165 198 def geom_type(self): 166 199 "Returns a string representing the Geometry type, e.g. 'Polygon'" 167 return geos_type(self. _ptr)200 return geos_type(self.ptr) 168 201 169 202 @property 170 203 def geom_typeid(self): 171 204 "Returns an integer representing the Geometry type." 172 return geos_typeid(self. _ptr)205 return geos_typeid(self.ptr) 173 206 174 207 @property 175 208 def num_geom(self): 176 209 "Returns the number of geometries in the Geometry." 177 return get_num_geoms(self. _ptr)210 return get_num_geoms(self.ptr) 178 211 179 212 @property 180 213 def num_coords(self): 181 214 "Returns the number of coordinates in the Geometry." 182 return get_num_coords(self. _ptr)215 return get_num_coords(self.ptr) 183 216 184 217 @property … … 190 223 def dims(self): 191 224 "Returns the dimension of this Geometry (0=point, 1=line, 2=surface)." 192 return get_dims(self. _ptr)225 return get_dims(self.ptr) 193 226 194 227 def normalize(self): 195 228 "Converts this Geometry to normal form (or canonical form)." 196 return geos_normalize(self. _ptr)229 return geos_normalize(self.ptr) 197 230 198 231 #### Unary predicates #### … … 203 236 are empty. 204 237 """ 205 return geos_isempty(self. _ptr)238 return geos_isempty(self.ptr) 206 239 207 240 @property 208 241 def hasz(self): 209 242 "Returns whether the geometry has a 3D dimension." 210 return geos_hasz(self. _ptr)243 return geos_hasz(self.ptr) 211 244 212 245 @property 213 246 def ring(self): 214 247 "Returns whether or not the geometry is a ring." 215 return geos_isring(self. _ptr)248 return geos_isring(self.ptr) 216 249 217 250 @property 218 251 def simple(self): 219 252 "Returns false if the Geometry not simple." 220 return geos_issimple(self. _ptr)253 return geos_issimple(self.ptr) 221 254 222 255 @property 223 256 def valid(self): 224 257 "This property tests the validity of this Geometry." 225 return geos_isvalid(self. _ptr)258 return geos_isvalid(self.ptr) 226 259 227 260 #### Binary predicates. #### 228 261 def contains(self, other): 229 262 "Returns true if other.within(this) returns true." 230 return geos_contains(self. _ptr, other._ptr)263 return geos_contains(self.ptr, other.ptr) 231 264 232 265 def crosses(self, other): … … 236 269 an area) 0******** (for two curves). 237 270 """ 238 return geos_crosses(self. _ptr, other._ptr)271 return geos_crosses(self.ptr, other.ptr) 239 272 240 273 def disjoint(self, other): … … 243 276 is FF*FF****. 244 277 """ 245 return geos_disjoint(self. _ptr, other._ptr)278 return geos_disjoint(self.ptr, other.ptr) 246 279 247 280 def equals(self, other): … … 250 283 is T*F**FFF*. 251 284 """ 252 return geos_equals(self. _ptr, other._ptr)285 return geos_equals(self.ptr, other.ptr) 253 286 254 287 def equals_exact(self, other, tolerance=0): … … 257 290 specified tolerance. 258 291 """ 259 return geos_equalsexact(self. _ptr, other._ptr, float(tolerance))292 return geos_equalsexact(self.ptr, other.ptr, float(tolerance)) 260 293 261 294 def intersects(self, other): 262 295 "Returns true if disjoint returns false." 263 return geos_intersects(self. _ptr, other._ptr)296 return geos_intersects(self.ptr, other.ptr) 264 297 265 298 def overlaps(self, other): … … 268 301 is T*T***T** (for two points or two surfaces) 1*T***T** (for two curves). 269 302 """ 270 return geos_overlaps(self. _ptr, other._ptr)303 return geos_overlaps(self.ptr, other.ptr) 271 304 272 305 def relate_pattern(self, other, pattern): … … 277 310 if not isinstance(pattern, StringType) or len(pattern) > 9: 278 311 raise GEOSException('invalid intersection matrix pattern') 279 return geos_relatepattern(self. _ptr, other._ptr, pattern)312 return geos_relatepattern(self.ptr, other.ptr, pattern) 280 313 281 314 def touches(self, other): … … 284 317 is FT*******, F**T***** or F***T****. 285 318 """ 286 return geos_touches(self. _ptr, other._ptr)319 return geos_touches(self.ptr, other.ptr) 287 320 288 321 def within(self, other): … … 291 324 is T*F**F***. 292 325 """ 293 return geos_within(self. _ptr, other._ptr)326 return geos_within(self.ptr, other.ptr) 294 327 295 328 #### SRID Routines #### 296 329 def get_srid(self): 297 330 "Gets the SRID for the geometry, returns None if no SRID is set." 298 s = geos_get_srid(self. _ptr)331 s = geos_get_srid(self.ptr) 299 332 if s == 0: return None 300 333 else: return s … … 302 335 def set_srid(self, srid): 303 336 "Sets the SRID for the geometry." 304 geos_set_srid(self. _ptr, srid)337 geos_set_srid(self.ptr, srid) 305 338 srid = property(get_srid, set_srid) 306 339 … … 315 348 def wkt(self): 316 349 "Returns the WKT (Well-Known Text) of the Geometry." 317 return to_wkt(self. _ptr)350 return to_wkt(self.ptr) 318 351 319 352 @property … … 326 359 # A possible faster, all-python, implementation: 327 360 # str(self.wkb).encode('hex') 328 return to_hex(self. _ptr, byref(c_size_t()))361 return to_hex(self.ptr, byref(c_size_t())) 329 362 330 363 @property 331 364 def wkb(self): 332 365 "Returns the WKB of the Geometry as a buffer." 333 bin = to_wkb(self. _ptr, byref(c_size_t()))366 bin = to_wkb(self.ptr, byref(c_size_t())) 334 367 return buffer(bin) 335 368 … … 375 408 if ptr: 376 409 # Reassigning pointer, and resetting the SRID. 377 destroy_geom(self. _ptr)410 destroy_geom(self.ptr) 378 411 self._ptr = ptr 379 412 self.srid = g.srid … … 389 422 def boundary(self): 390 423 "Returns the boundary as a newly allocated Geometry object." 391 return self._topology(geos_boundary(self. _ptr))424 return self._topology(geos_boundary(self.ptr)) 392 425 393 426 def buffer(self, width, quadsegs=8): … … 399 432 (Text from PostGIS documentation at ch. 6.1.3) 400 433 """ 401 return self._topology(geos_buffer(self. _ptr, width, quadsegs))434 return self._topology(geos_buffer(self.ptr, width, quadsegs)) 402 435 403 436 @property … … 408 441 "weight" to the centroid). 409 442 """ 410 return self._topology(geos_centroid(self. _ptr))443 return self._topology(geos_centroid(self.ptr)) 411 444 412 445 @property … … 416 449 in the Geometry. 417 450 """ 418 return self._topology(geos_convexhull(self. _ptr))451 return self._topology(geos_convexhull(self.ptr)) 419 452 420 453 def difference(self, other): … … 423 456 that do not make up other. 424 457 """ 425 return self._topology(geos_difference(self. _ptr, other._ptr))458 return self._topology(geos_difference(self.ptr, other.ptr)) 426 459 427 460 @property 428 461 def envelope(self): 429 462 "Return the envelope for this geometry (a polygon)." 430 return self._topology(geos_envelope(self. _ptr))463 return self._topology(geos_envelope(self.ptr)) 431 464 432 465 def intersection(self, other): 433 466 "Returns a Geometry representing the points shared by this Geometry and other." 434 return self._topology(geos_intersection(self. _ptr, other._ptr))467 return self._topology(geos_intersection(self.ptr, other.ptr)) 435 468 436 469 @property 437 470 def point_on_surface(self): 438 471 "Computes an interior point of this Geometry." 439 return self._topology(geos_pointonsurface(self. _ptr))472 return self._topology(geos_pointonsurface(self.ptr)) 440 473 441 474 def relate(self, other): 442 475 "Returns the DE-9IM intersection matrix for this Geometry and the other." 443 return geos_relate(self. _ptr, other._ptr)476 return geos_relate(self.ptr, other.ptr) 444 477 445 478 def simplify(self, tolerance=0.0, preserve_topology=False): … … 456 489 """ 457 490 if preserve_topology: 458 return self._topology(geos_preservesimplify(self. _ptr, tolerance))459 else: 460 return self._topology(geos_simplify(self. _ptr, tolerance))491 return self._topology(geos_preservesimplify(self.ptr, tolerance)) 492 else: 493 return self._topology(geos_simplify(self.ptr, tolerance)) 461 494 462 495 def sym_difference(self, other): … … 465 498 and the points in other not in this Geometry. 466 499 """ 467 return self._topology(geos_symdifference(self. _ptr, other._ptr))500 return self._topology(geos_symdifference(self.ptr, other.ptr)) 468 501 469 502 def union(self, other): 470 503 "Returns a Geometry representing all the points in this Geometry and other." 471 return self._topology(geos_union(self. _ptr, other._ptr))504 return self._topology(geos_union(self.ptr, other.ptr)) 472 505 473 506 #### Other Routines #### … … 475 508 def area(self): 476 509 "Returns the area of the Geometry." 477 return geos_area(self. _ptr, byref(c_double()))510 return geos_area(self.ptr, byref(c_double())) 478 511 479 512 def distance(self, other): … … 485 518 if not isinstance(other, GEOSGeometry): 486 519 raise TypeError('distance() works only on other GEOS Geometries.') 487 return geos_distance(self. _ptr, other._ptr, byref(c_double()))520 return geos_distance(self.ptr, other.ptr, byref(c_double())) 488 521 489 522 @property … … 493 526 circumfrence of a Polygon). 494 527 """ 495 return geos_length(self. _ptr, byref(c_double()))528 return geos_length(self.ptr, byref(c_double())) 496 529 497 530 def clone(self): 498 531 "Clones this Geometry." 499 return GEOSGeometry(geom_clone(self. _ptr), srid=self.srid)532 return GEOSGeometry(geom_clone(self.ptr), srid=self.srid) 500 533 501 534 # Class mapping dictionary django/branches/gis/django/contrib/gis/geos/collections.py
r6861 r6978 39 39 ngeoms = len(init_geoms) 40 40 geoms = get_pointer_arr(ngeoms) 41 for i in xrange(ngeoms): geoms[i] = geom_clone(init_geoms[i]. _ptr)41 for i in xrange(ngeoms): geoms[i] = geom_clone(init_geoms[i].ptr) 42 42 super(GeometryCollection, self).__init__(create_collection(c_int(self._typeid), byref(geoms), c_uint(ngeoms)), **kwargs) 43 43 … … 46 46 # Checking the index and returning the corresponding GEOS geometry. 47 47 self._checkindex(index) 48 return GEOSGeometry(geom_clone(get_geomn(self. _ptr, index)), srid=self.srid)48 return GEOSGeometry(geom_clone(get_geomn(self.ptr, index)), srid=self.srid) 49 49 50 50 def __setitem__(self, index, geom): … … 58 58 for i in xrange(ngeoms): 59 59 if i == index: 60 geoms[i] = geom_clone(geom. _ptr)60 geoms[i] = geom_clone(geom.ptr) 61 61 else: 62 geoms[i] = geom_clone(get_geomn(self. _ptr, i))62 geoms[i] = geom_clone(get_geomn(self.ptr, i)) 63 63 64 64 # Creating a new collection, and destroying the contents of the previous poiner. 65 prev_ptr = self. _ptr65 prev_ptr = self.ptr 66 66 srid = self.srid 67 67 self._ptr = create_collection(c_int(self._typeid), byref(geoms), c_uint(ngeoms)) django/branches/gis/django/contrib/gis/geos/coordseq.py
r6861 r6978 77 77 raise GEOSException('invalid ordinate dimension "%d"' % dim) 78 78 79 @property 80 def ptr(self): 81 """ 82 Property for controlling access to coordinate sequence pointer, 83 preventing attempted access to a NULL memory location. 84 """ 85 if self._ptr: return self._ptr 86 else: raise GEOSException('NULL coordinate sequence pointer encountered.') 87 79 88 #### Ordinate getting and setting routines #### 80 89 def getOrdinate(self, dimension, index): … … 82 91 self._checkindex(index) 83 92 self._checkdim(dimension) 84 return cs_getordinate(self. _ptr, index, dimension, byref(c_double()))93 return cs_getordinate(self.ptr, index, dimension, byref(c_double())) 85 94 86 95 def setOrdinate(self, dimension, index, value): … … 88 97 self._checkindex(index) 89 98 self._checkdim(dimension) 90 cs_setordinate(self. _ptr, index, dimension, value)99 cs_setordinate(self.ptr, index, dimension, value) 91 100 92 101 def getX(self, index): … … 118 127 def size(self): 119 128 "Returns the size of this coordinate sequence." 120 return cs_getsize(self. _ptr, byref(c_uint()))129 return cs_getsize(self.ptr, byref(c_uint())) 121 130 122 131 @property 123 132 def dims(self): 124 133 "Returns the dimensions of this coordinate sequence." 125 return cs_getdims(self. _ptr, byref(c_uint()))134 return cs_getdims(self.ptr, byref(c_uint())) 126 135 127 136 @property … … 136 145 def clone(self): 137 146 "Clones this coordinate sequence." 138 return GEOSCoordSeq(cs_clone(self. _ptr), self.hasz)147 return GEOSCoordSeq(cs_clone(self.ptr), self.hasz) 139 148 140 149 @property django/branches/gis/django/contrib/gis/geos/geometries.py
r6861 r6978 167 167 # Calling the base geometry initialization with the returned pointer 168 168 # from the function. 169 super(LineString, self).__init__(func(cs. _ptr), srid=srid)169 super(LineString, self).__init__(func(cs.ptr), srid=srid) 170 170 171 171 def __getitem__(self, index): … … 264 264 nholes = len(init_holes) 265 265 holes = get_pointer_arr(nholes) 266 for i in xrange(nholes): holes[i] = geom_clone(init_holes[i]. _ptr)266 for i in xrange(nholes): holes[i] = geom_clone(init_holes[i].ptr) 267 267 268 268 # Getting the shell pointer address, 269 shell = geom_clone(ext_ring. _ptr)269 shell = geom_clone(ext_ring.ptr) 270 270 271 271 # Calling with the GEOS createPolygon factory. … … 292 292 # Getting the shell 293 293 if index == 0: 294 shell = geom_clone(ring. _ptr)295 else: 296 shell = geom_clone(get_extring(self. _ptr))294 shell = geom_clone(ring.ptr) 295 else: 296 shell = geom_clone(get_extring(self.ptr)) 297 297 298 298 # Getting the interior rings (holes) … … 302 302 for i in xrange(nholes): 303 303 if i == (index-1): 304 holes[i] = geom_clone(ring. _ptr)304 holes[i] = geom_clone(ring.ptr) 305 305 else: 306 holes[i] = geom_clone(get_intring(self. _ptr, i))306 holes[i] = geom_clone(get_intring(self.ptr, i)) 307 307 holes_param = byref(holes) 308 308 else: … … 311 311 # Getting the current pointer, replacing with the newly constructed 312 312 # geometry, and destroying the old geometry. 313 prev_ptr = self. _ptr313 prev_ptr = self.ptr 314 314 srid = self.srid 315 315 self._ptr = create_polygon(shell, holes_param, c_uint(nholes)) … … 337 337 """ 338 338 self._checkindex(ring_i+1) 339 return GEOSGeometry(geom_clone(get_intring(self. _ptr, ring_i)), srid=self.srid)339 return GEOSGeometry(geom_clone(get_intring(self.ptr, ring_i)), srid=self.srid) 340 340 341 341 #### Polygon Properties #### … … 344 344 "Returns the number of interior rings." 345 345 # Getting the number of rings 346 return get_nrings(self. _ptr)346 return get_nrings(self.ptr) 347 347 348 348 def get_ext_ring(self): 349 349 "Gets the exterior ring of the Polygon." 350 return GEOSGeometry(geom_clone(get_extring(self. _ptr)), srid=self.srid)350 return GEOSGeometry(geom_clone(get_extring(self.ptr)), srid=self.srid) 351 351 352 352 def set_ext_ring(self, ring): django/branches/gis/django/contrib/gis/geos/__init__.py
r6861 r6978 33 33 from django.contrib.gis.geos.collections import GeometryCollection, MultiPoint, MultiLineString, MultiPolygon 34 34 from django.contrib.gis.geos.error import GEOSException, GEOSIndexError 35 from django.contrib.gis.geos.libgeos import geos_version 35 from django.contrib.gis.geos.libgeos import geos_version, geos_version_info 36 36 37 37 def fromfile(file_name): django/branches/gis/django/contrib/gis/geos/libgeos.py
r6861 r6978 7 7 get_pointer_arr(), and GEOM_PTR. 8 8 """ 9 import atexit, os, sys9 import atexit, os, re, sys 10 10 from ctypes import c_char_p, string_at, Structure, CDLL, CFUNCTYPE, POINTER 11 11 from django.contrib.gis.geos.error import GEOSException … … 22 22 from django.conf import settings 23 23 lib_name = settings.GEOS_LIBRARY_PATH 24 except (AttributeError, EnvironmentError ):24 except (AttributeError, EnvironmentError, ImportError): 25 25 lib_name = None 26 26 … … 97 97 return string_at(lgeos.GEOSversion()) 98 98 99 # Regular expression should be able to parse version strings such as 100 # '3.0.0rc4-CAPI-1.3.3', or '3.0.0-CAPI-1.4.1' 101 version_regex = re.compile(r'^(?P<version>\d+\.\d+\.\d+)(rc(?P<release_candidate>\d+))?-CAPI-(?P<capi_version>\d+\.\d+\.\d+)$') 102 def geos_version_info(): 103 """ 104 Returns a dictionary containing the various version metadata parsed from 105 the GEOS version string, including the version number, whether the version 106 is a release candidate (and what number release candidate), and the C API 107 version. 108 """ 109 ver = geos_version() 110 m = version_regex.match(ver) 111 if not m: raise GEOSException('Could not parse version info string "%s"' % ver) 112 return dict((key, m.group(key)) for key in ('version', 'release_candidate', 'capi_version')) 113 99 114 # Calling the finishGEOS() upon exit of the interpreter. 100 115 atexit.register(lgeos.finishGEOS) django/branches/gis/django/contrib/gis/geos/prototypes/geom.py
r6653 r6978 49 49 50 50 ### ctypes prototypes ### 51 52 # TODO: Tell all users to use GEOS 3.0.0, instead of the release 53 # candidates, and use the new Reader and Writer APIs (e.g., 54 # GEOSWKT[Reader|Writer], GEOSWKB[Reader|Writer]). A good time 55 # to do this will be when Refractions releases a Windows PostGIS 56 # installer using GEOS 3.0.0. 51 57 52 58 # Creation routines from WKB, HEX, WKT django/branches/gis/django/contrib/gis/tests/test_geos.py
r6884 r6978 1 1 import random, unittest, sys 2 2 from ctypes import ArgumentError 3 from django.contrib.gis.geos import \ 4 GEOSException, GEOSIndexError, \ 5 GEOSGeometry, Point, LineString, LinearRing, Polygon, \ 6 MultiPoint, MultiLineString, MultiPolygon, GeometryCollection, \ 7 fromstr, geos_version, HAS_NUMPY 3 from django.contrib.gis.geos import * 8 4 from django.contrib.gis.geos.base import HAS_GDAL 9 5 from django.contrib.gis.tests.geometries import * … … 90 86 self.assertEqual(srid, fromstr(poly.ewkt).srid) # Checking export 91 87 88 def test01i_eq(self): 89 "Testing equivalence with WKT." 90 p = fromstr('POINT(5 23)') 91 self.assertEqual(p, p.wkt) 92 self.assertNotEqual(p, 'foo') 93 ls = fromstr('LINESTRING(0 0, 1 1, 5 5)') 94 self.assertEqual(ls, ls.wkt) 95 self.assertNotEqual(p, 'bar') 96 92 97 def test02a_points(self): 93 98 "Testing Point objects." … … 479 484 # However, when HEX is exported, the SRID information is lost 480 485 # and set to -1. Essentially, the 'E' of the EWKB is not 481 # encoded in HEX by the GEOS C library for some reason. 486 # encoded in HEX by the GEOS C library unless the GEOSWKBWriter 487 # method is used. GEOS 3.0.0 will not encode -1 in the HEX 488 # as is done in the release candidates. 489 info = geos_version_info() 490 if info['version'] == '3.0.0' and info['release_candidate']: 491 exp_srid = -1 492 else: 493 exp_srid = None 494 482 495 p2 = fromstr(p1.hex) 483 self.assertEqual( -1, p2.srid)496 self.assertEqual(exp_srid, p2.srid) 484 497 p3 = fromstr(p1.hex, srid=-1) # -1 is intended. 485 498 self.assertEqual(-1, p3.srid) … … 651 664 self.assertEqual(g2.hex, g2.ogr.hex) 652 665 self.assertEqual('WGS 84', g2.srs.name) 653 666 667 def test22_copy(self): 668 "Testing use with the Python `copy` module." 669 import copy 670 poly = GEOSGeometry('POLYGON((0 0, 0 23, 23 23, 23 0, 0 0), (5 5, 5 10, 10 10, 10 5, 5 5))') 671 cpy1 = copy.copy(poly) 672 cpy2 = copy.deepcopy(poly) 673 self.assertNotEqual(poly._ptr, cpy1._ptr) 674 self.assertNotEqual(poly._ptr, cpy2._ptr) 675 654 676 def suite(): 655 677 s = unittest.TestSuite()
