Django

Code

Changeset 5786

Show
Ignore:
Timestamp:
08/02/07 00:31:10 (1 year ago)
Author:
jbronn
Message:

gis: geos: fully-mutable geometries have landed; fixed GEOSPointer boolean value; equivalence now uses equals_exact (vertex-by-vertex matching); added in-place set operations; improved tests; getquoted() will return ST_* for PostGIS 1.2.2+.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/gis/django/contrib/gis/geos/base.py

    r5760 r5786  
    1313import re 
    1414from warnings import warn 
    15 from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, HAS_NUMPY, ISQLQuote 
     15from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, HAS_NUMPY, ISQLQuote, GEOM_FUNC_PREFIX 
    1616from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError 
    1717from django.contrib.gis.geos.coordseq import GEOSCoordSeq, create_cs 
     
    8888    def __del__(self): 
    8989        "Destroys this geometry -- only if the pointer is valid and whether or not it belongs to a parent." 
    90         #print 'Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, self._parent, self._ptr.valid) 
     90        #print 'base: Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, self._parent, self._ptr.valid) 
    9191        # Only calling destroy on valid pointers not spawned from a parent 
    9292        if self._ptr.valid and not self._parent: lgeos.GEOSGeom_destroy(self._ptr()) 
     
    102102    def __eq__(self, other): 
    103103        "Equivalence testing." 
    104         return self.equals(other) 
     104        return self.equals_exact(other) 
    105105 
    106106    def __ne__(self, other): 
    107107        "The not equals operator." 
    108         return not self.equals(other) 
     108        return not self.equals_exact(other) 
    109109 
    110110    ### Geometry set-like operations ### 
     
    116116        return self.union(other) 
    117117 
     118    # g1 |= g2 
     119    def __ior__(self, other): 
     120        "Reassigns this Geometry to the union of this Geometry and the other." 
     121        return self.union(other) 
     122 
    118123    # g = g1 & g2 
    119124    def __and__(self, other): 
     
    121126        return self.intersection(other) 
    122127 
     128    # g1 &= g2 
     129    def __iand__(self, other): 
     130        "Reassigns this Geometry to the intersection of this Geometry and the other." 
     131        return self.intersection(other) 
     132 
    123133    # g = g1 - g2 
    124134    def __sub__(self, other): 
     
    126136        return self.difference(other) 
    127137 
     138    # g1 -= g2 
     139    def __isub__(self, other): 
     140        "Reassigns this Geometry to the difference of this Geometry and the other." 
     141        return self.difference(other) 
     142 
    128143    # g = g1 ^ g2 
    129144    def __xor__(self, other): 
    130145        "Return the symmetric difference of this Geometry and the other." 
    131146        return self.sym_difference(other) 
     147 
     148    # g1 ^= g2 
     149    def __ixor__(self, other): 
     150        "Reassigns this Geometry to the symmetric difference of this Geometry and the other." 
     151        return self.sym_difference(other) 
     152 
     153    def _nullify(self): 
     154        """During initialization of geometries from other geometries, this routine is 
     155        used to nullify any parent geometries (since they will now be missing memory 
     156        components) and to nullify the geometry itself to prevent future access. 
     157        Only the address (an integer) of the current geometry is returned for use in 
     158        initializing the new geometry.""" 
     159        # First getting the memory address of the geometry. 
     160        address = self._ptr() 
     161 
     162        # If the geometry is a child geometry, then the parent geometry pointer is 
     163        #  nullified. 
     164        if self._parent: self._parent.nullify() 
     165 
     166        # Nullifying the geometry pointer 
     167        self._ptr.nullify() 
     168 
     169        return address 
     170 
     171    def _reassign(self, new_geom): 
     172        "Internal routine for reassigning internal pointer to a new geometry." 
     173        # Only can re-assign when given a pointer or a geometry. 
     174        if not isinstance(new_geom, (GEOSPointer, GEOSGeometry)): 
     175            raise TypeError, 'cannot reassign geometry on given type: %s' % type(new_geom) 
     176        gtype = new_geom.geom_type  
     177 
     178        # Re-assigning the internal GEOSPointer to the new geometry, nullifying 
     179        #  the new Geometry in the process. 
     180        if isinstance(new_geom, GEOSGeometry): self._ptr.set(new_geom._nullify()) 
     181        else: self._ptr = new_geom 
     182         
     183        # The new geometry class may be different from the original, so setting 
     184        #  the __class__ and populating the internal geometry or ring dictionary. 
     185        self.__class__ = GEOS_CLASSES[gtype] 
     186        if isinstance(self, (Polygon, GeometryCollection)): self._populate() 
    132187 
    133188    #### Psycopg2 database adaptor routines #### 
     
    141196    def getquoted(self): 
    142197        "Returns a properly quoted string for use in PostgresSQL/PostGIS." 
    143         return "GeometryFromText('%s', %s)" % (self.wkt, self.srid or -1) 
     198        # GeometryFromText() is ST_GeometryFromText() in PostGIS >= 1.2.2 
     199        return "%sGeometryFromText('%s', %s)" % (GEOM_FUNC_PREFIX, self.wkt, self.srid or -1) 
    144200     
    145201    #### Coordinate Sequence Routines #### 
     
    300356        "Gets the SRID for the geometry, returns None if no SRID is set." 
    301357        s = lgeos.GEOSGetSRID(self._ptr()) 
    302         if s == 0: 
    303             return None 
    304         else: 
    305             return s 
     358        if s == 0: return None 
     359        else: return s 
    306360 
    307361    def set_srid(self, srid): 
     
    405459    def clone(self): 
    406460        "Clones this Geometry." 
    407         return GEOSGeometry(lgeos.GEOSGeom_clone(self._ptr())
     461        return GEOSGeometry(lgeos.GEOSGeom_clone(self._ptr()), srid=self.srid
    408462 
    409463# Class mapping dictionary 
  • django/branches/gis/django/contrib/gis/geos/collections.py

    r5760 r5786  
    55from ctypes import c_int, c_uint, byref, cast 
    66from types import TupleType, ListType 
    7 from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, init_from_geom, get_pointer_arr, GEOM_PTR 
     7from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, get_pointer_arr, GEOM_PTR 
    88from django.contrib.gis.geos.base import GEOSGeometry 
    99from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError 
    1010from django.contrib.gis.geos.geometries import Point, LineString, LinearRing, Polygon 
    11  
    12 def init_from_poly(poly): 
    13     "Internal routine used for initializing Geometry Collections from Polygons." 
    14     # Constructing a new Polygon to take control of the rings. 
    15     p = Polygon(*tuple(ring for ring in poly)) 
    16      
    17     # If this Polygon came from a GeometryCollection, it is a child 
    18     #  and the parent geometry pointer is nullified. 
    19     if poly._parent: poly._parent.nullify() 
    20      
    21     # Nullifying the polygon pointer 
    22     poly._ptr.nullify() 
    23  
    24     # Returning the address of the new Polygon. 
    25     return p._ptr() 
    2611 
    2712class GeometryCollection(GEOSGeometry): 
     
    3015 
    3116    def __init__(self, *args, **kwargs): 
     17        "Initializes a Geometry Collection from a sequence of Geometry objects." 
     18        # Setting up the collection for creation 
    3219        self._ptr = GEOSPointer(0) # Initially NULL 
    3320        self._geoms = {} 
    34         self._parent = Fals
     21        self._parent = Non
    3522 
     23        # Checking the arguments 
    3624        if not args: 
    37             raise TypeError, 'Must provide at least one LinearRing to initialize Polygon.' 
     25            raise TypeError, 'Must provide at least one Geometry to initialize %s.' % self.__class__.__name__ 
    3826 
    3927        if len(args) == 1: # If only one geometry provided or a list of geometries is provided 
     
    5543        # Incrementing through each input geometry. 
    5644        for i in xrange(ngeom): 
    57             if isinstance(init_geoms[i], Polygon):  
    58                 # Special care is taken when importing from Polygons 
    59                 geoms[i] = cast(init_from_poly(init_geoms[i]), GEOM_PTR) 
    60             else:  
    61                 geoms[i] = cast(init_from_geom(init_geoms[i]), GEOM_PTR) 
    62  
     45            geoms[i] = cast(init_geoms[i]._nullify(), GEOM_PTR) 
     46         
    6347        # Calling the parent class, using the pointer returned from GEOS createCollection() 
    6448        super(GeometryCollection, self).__init__(lgeos.GEOSGeom_createCollection(c_int(self._typeid), byref(geoms), c_uint(ngeom)), **kwargs) 
     
    6650    def __del__(self): 
    6751        "Overloaded deletion method for Geometry Collections." 
    68         #print 'Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, self._parent, self._ptr.valid) 
     52        #print 'collection: Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, self._parent, self._ptr.valid) 
    6953        # If this geometry is still valid, it hasn't been modified by others. 
    7054        if self._ptr.valid: 
    7155            # Nullifying pointers to internal geometries, preventing any attempted future access. 
    7256            for k in self._geoms: self._geoms[k].nullify() 
    73             super(GeometryCollection, self).__del__() 
    7457        else: 
    7558            # Internal memory has become part of other Geometry objects, must delete the 
     
    8164                    lgeos.GEOSGeom_destroy(self._geoms[k].address) 
    8265                    self._geoms[k].nullify() 
     66        super(GeometryCollection, self).__del__() 
    8367             
    8468    def __getitem__(self, index): 
    85         "For indexing on the multiple geometries." 
     69        "Returns the Geometry from this Collection at the given index (0-based)." 
    8670        # Checking the index and returning the corresponding GEOS geometry. 
    8771        self._checkindex(index) 
    8872        return GEOSGeometry(self._geoms[index], parent=self._ptr, srid=self.srid) 
    8973 
     74    def __setitem__(self, index, geom): 
     75        "Sets the Geometry at the specified index." 
     76        self._checkindex(index) 
     77        if not isinstance(geom, self._allowed): 
     78            raise TypeError, 'Incompatible Geometry for collection.' 
     79 
     80        # Constructing the list of geometries that will go in the collection. 
     81        new_geoms = [] 
     82        for i in xrange(len(self)): 
     83            if i == index: new_geoms.append(geom) 
     84            else: new_geoms.append(self[i]) 
     85 
     86        # Creating a new geometry collection from the list, and 
     87        #  re-assigning the pointers. 
     88        new_collection = self.__class__(*new_geoms) 
     89        self._reassign(new_collection) 
     90         
    9091    def __iter__(self): 
    91         "For iteration on the multiple geometries." 
     92        "Iterates over each Geometry in the Collection." 
    9293        for i in xrange(len(self)): 
    9394            yield self.__getitem__(i) 
    9495 
    9596    def __len__(self): 
    96         "Returns the number of geometries in this collection." 
     97        "Returns the number of geometries in this Collection." 
    9798        return self.num_geom 
    9899 
     
    102103            raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) 
    103104 
     105    def _nullify(self): 
     106        "Overloaded from base method to nullify geometry references in this Collection." 
     107        # Nullifying the references to the internal Geometry objects from this Collection. 
     108        for k in self._geoms: self._geoms[k].nullify() 
     109        return super(GeometryCollection, self)._nullify() 
     110 
    104111    def _populate(self): 
    105112        "Populates the internal child geometry dictionary." 
     
    107114        for i in xrange(self.num_geom): 
    108115            self._geoms[i] = GEOSPointer(lgeos.GEOSGetGeometryN(self._ptr(), c_int(i))) 
    109  
    110116 
    111117# MultiPoint, MultiLineString, and MultiPolygon class definitions. 
  • django/branches/gis/django/contrib/gis/geos/geometries.py

    r5760 r5786  
    88from types import FloatType, IntType, ListType, TupleType 
    99from django.contrib.gis.geos.coordseq import GEOSCoordSeq, create_cs 
    10 from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, get_pointer_arr, init_from_geom, GEOM_PTR, HAS_NUMPY 
     10from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, get_pointer_arr, GEOM_PTR, HAS_NUMPY 
    1111from django.contrib.gis.geos.base import GEOSGeometry 
    1212from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError 
     
    2222        """ 
    2323 
     24        # Setting-up for Point Creation 
    2425        self._ptr = GEOSPointer(0) # Initially NULL 
     26        self._parent = None 
    2527 
    2628        if isinstance(x, (TupleType, ListType)): 
     
    133135          ls = LineString(Point(1, 1), Point(2, 2)) 
    134136        """ 
     137        # Setting up for LineString creation 
    135138        self._ptr = GEOSPointer(0) # Initially NULL 
     139        self._parent = None 
    136140 
    137141        # If only one argument was provided, then set the coords array appropriately 
     
    255259        """ 
    256260        self._ptr = GEOSPointer(0) # Initially NULL 
     261        self._parent = None 
    257262        self._rings = {}  
    258263        if not args: 
     
    278283        for i in xrange(nholes): 
    279284            # Casting to the Geometry Pointer type 
    280             holes[i] = cast(init_from_geom(init_holes[i]), GEOM_PTR) 
     285            holes[i] = cast(init_holes[i]._nullify(), GEOM_PTR) 
    281286                       
    282287        # Getting the shell pointer address,  
    283         shell = init_from_geom(ext_ring
     288        shell = ext_ring._nullify(
    284289 
    285290        # Calling with the GEOS createPolygon factory. 
     
    288293    def __del__(self): 
    289294        "Overloaded deletion method for Polygons." 
    290         #print 'Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, self._parent, self._ptr.valid) 
     295        #print 'polygon: Deleting %s (parent=%s, valid=%s)' % (self.__class__.__name__, self._parent, self._ptr.valid) 
    291296        # If this geometry is still valid, it hasn't been modified by others. 
    292297        if self._ptr.valid: 
    293298            # Nulling the pointers to internal rings, preventing any attempted future access 
    294299            for k in self._rings: self._rings[k].nullify() 
    295             super(Polygon, self).__del__() 
    296         else: 
     300        elif not self._parent:  
    297301            # Internal memory has become part of other objects; must delete the  
    298302            #  internal objects which are still valid individually, since calling 
    299303            #  destructor on entire geometry will result in an attempted deletion  
    300             #  of NULL pointers for the missing components. 
     304            #  of NULL pointers for the missing components.  Not performed on 
     305            #  children Polygons from MultiPolygon or GeometryCollection objects. 
    301306            for k in self._rings: 
    302307                if self._rings[k].valid: 
    303308                    lgeos.GEOSGeom_destroy(self._rings[k].address) 
    304309                    self._rings[k].nullify() 
     310        super(Polygon, self).__del__() 
    305311 
    306312    def __getitem__(self, index): 
    307313        """Returns the ring at the specified index.  The first index, 0, will always 
    308314        return the exterior ring.  Indices > 0 will return the interior ring.""" 
    309         if index < 0 or index > self.num_interior_rings: 
    310             raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) 
    311         else: 
    312             if index == 0: 
    313                 return self.exterior_ring 
    314             else: 
    315                 # Getting the interior ring, have to subtract 1 from the index. 
    316                 return self.get_interior_ring(index-1)  
     315        if index == 0: 
     316            return self.exterior_ring 
     317        else: 
     318            # Getting the interior ring, have to subtract 1 from the index. 
     319            return self.get_interior_ring(index-1)  
     320 
     321    def __setitem__(self, index, ring): 
     322        "Sets the ring at the specified index with the given ring." 
     323        # Checking the index and ring parameters. 
     324        self._checkindex(index) 
     325        if not isinstance(ring, LinearRing): 
     326            raise TypeError, 'must set Polygon index with a LinearRing object' 
     327 
     328        # Constructing the ring parameters 
     329        new_rings = [] 
     330        for i in xrange(len(self)): 
     331            if index == i: new_rings.append(ring) 
     332            else: new_rings.append(self[i]) 
     333 
     334        # Constructing the new Polygon with the ring parameters, and reassigning the internals. 
     335        new_poly = Polygon(*new_rings) 
     336        self._reassign(new_poly) 
    317337 
    318338    def __iter__(self): 
     
    325345        return self.num_interior_rings + 1 
    326346 
     347    def _checkindex(self, index): 
     348        "Internal routine for checking the given ring index." 
     349        if index < 0 or index >= len(self): 
     350            raise GEOSGeometryIndexError, 'invalid Polygon ring index: %s' % index 
     351 
     352    def _nullify(self): 
     353        "Overloaded from base method to nullify ring references as well." 
     354        # Nullifying the references to the internal rings of this Polygon. 
     355        for k in self._rings: self._rings[k].nullify() 
     356        return super(Polygon, self)._nullify() 
     357 
    327358    def _populate(self): 
    328359        "Populates the internal rings dictionary." 
     
    337368        """Gets the interior ring at the specified index, 
    338369        0 is for the first interior ring, not the exterior ring.""" 
    339  
    340         # Making sure the ring index is within range 
    341         if ring_i < 0 or ring_i >= self.num_interior_rings: 
    342             raise IndexError, 'ring index out of range' 
    343  
    344         # Returning the ring from the internal ring dictionary (have to 
    345         #   add one to the index) 
     370        # Returning the ring from the internal ring dictionary (have to add one 
     371        #   to index since all internal rings come after the exterior ring) 
     372        self._checkindex(ring_i+1) 
    346373        return GEOSGeometry(self._rings[ring_i+1], parent=self._ptr, srid=self.srid) 
    347374                                                         
     
    362389        return GEOSGeometry(self._rings[0], parent=self._ptr, srid=self.srid) 
    363390 
    364     def set_ext_ring(self): 
     391    def set_ext_ring(self, ring): 
    365392        "Sets the exterior ring of the Polygon." 
    366         # Sets the exterior ring 
    367         raise NotImplementedError 
     393        self[0] = ring 
    368394 
    369395    # properties for the exterior ring/shell 
    370     exterior_ring = property(get_ext_ring
    371     shell = property(get_ext_ring
     396    exterior_ring = property(get_ext_ring, set_ext_ring
     397    shell = property(get_ext_ring, set_ext_ring
    372398     
    373399    @property 
  • django/branches/gis/django/contrib/gis/geos/libgeos.py

    r5760 r5786  
    1919    HAS_NUMPY = False 
    2020 
    21 # Psycopg2 supported? 
     21# Are psycopg2 and GeoDjango models being used? 
    2222try: 
    2323    from psycopg2.extensions import ISQLQuote 
    24 except ImportError: 
     24    from django.contrib.gis.db.backend.postgis import GEOM_FUNC_PREFIX 
     25except (ImportError, EnvironmentError): 
    2526    ISQLQuote = None 
     27    GEOM_FUNC_PREFIX = None 
    2628 
    2729# Setting the appropriate name for the GEOS-C library, depending on which 
     
    7274lgeos.initGEOS(notice_h, error_h) 
    7375 
    74 #### GEOS Geometry Pointer utilities. #### 
     76#### GEOS Geometry Pointer object, related C data structures, and functions. #### 
    7577 
    7678# Opaque GEOS geometry structure 
     
    7880    "Opaque structure used when arrays of geometries are needed as parameters." 
    7981    pass 
     82 
    8083# Pointer to opaque geometry structure 
    8184GEOM_PTR = POINTER(GEOSGeom_t) 
     85 
    8286# Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection GEOS routines 
    8387def get_pointer_arr(n): 
     
    8690    return GeomArr() 
    8791 
    88 #### GEOS Pointer object and routines #### 
    8992class GEOSPointer(object): 
    9093    """The GEOSPointer provides a layer of abstraction in accessing the values returned by 
     
    109112        else: raise GEOSException, 'GEOS pointer no longer valid (was this geometry or the parent geometry deleted or modified?)' 
    110113 
    111     def __bool__(self): 
     114    def __nonzero__(self): 
    112115        "Returns True when the GEOSPointer is valid." 
    113116        return self.valid 
     
    115118    def __str__(self): 
    116119        return str(self.address) 
     120 
     121    def __repr__(self): 
     122        return 'GEOSPointer(%s)' % self.address 
    117123 
    118124    ### GEOSPointer Properties ### 
     
    162168        self.set(0) 
    163169        self.set(0, coordseq=True) 
    164  
    165 def init_from_geom(geom): 
    166     """During initialization of geometries from other geometries, this routine is  
    167     used to nullify any parent geometries (since they will now be missing memory  
    168     components) and to nullify the geometry itself to prevent future access.   
    169     Only the address (an integer) of the current geometry is returned for use in  
    170     initializing the new geometry.""" 
    171     # First getting the memory address of the geometry. 
    172     address = geom._ptr() 
    173  
    174     # If the geometry is a child geometry, then the parent geometry pointer is 
    175     #  nullified. 
    176     if geom._parent: geom._parent.nullify() 
    177  
    178     # Nullifying the geometry pointer 
    179     geom._ptr.nullify() 
    180  
    181     return address 
  • django/branches/gis/django/contrib/gis/tests/geometries.py

    r5742 r5786  
    116116 
    117117intersect_geoms = ( TestGeom('POLYGON ((5 5,5 0,0 0,0 5,5 5))'), 
    118                     TestGeom('POLYGON ((10 1, 11 3, 13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 8, 5 6, 7 4, 9 3, 10 1))') 
     118                    TestGeom('POLYGON ((10 1, 9 3, 7 4, 5 6, 4 8, 4 10, 5 12, 7 13, 9 12, 10 10, 11 12, 13 13, 15 12, 16 10, 16 8, 15 6, 13 4, 11 3, 10 1))'), 
    119119                    ) 
    120120 
    121121union_geoms = ( TestGeom('POLYGON ((-5 0,-5 10,5 10,5 5,10 5,10 -5,0 -5,0 0,-5 0))'), 
    122                 TestGeom('POLYGON ((2 0, 18 0, 18 15, 2 15, 2 0))'), 
     122                TestGeom('POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0))'), 
    123123                ) 
    124124 
    125125diff_geoms = ( TestGeom('POLYGON ((-5 0,-5 10,5 10,5 5,0 5,0 0,-5 0))'), 
    126                TestGeom('POLYGON ((2 0, 18 0, 18 15, 2 15, 2 0), (10 1, 11 3, 13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 8, 5 6, 7 4, 9 3, 10 1))'), 
     126               TestGeom('POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0), (10 1, 11 3, 13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 8, 5 6, 7 4, 9 3, 10 1))'), 
    127127               ) 
    128128 
    129129sdiff_geoms = ( TestGeom('MULTIPOLYGON (((-5 0,-5 10,5 10,5 5,0 5,0 0,-5 0)),((0 0,5 0,5 5,10 5,10 -5,0 -5,0 0)))'), 
    130                 TestGeom('POLYGON ((2 0, 18 0, 18 15, 2 15, 2 0), (10 1, 11 3, 13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 8, 5 6, 7 4, 9 3, 10 1))'), 
     130                TestGeom('POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0), (10 1, 11 3, 13 4, 15 6, 16 8, 16 10, 15 12, 13 13, 11 12, 10 10, 9 12, 7 13, 5 12, 4 10, 4 8, 5 6, 7 4, 9 3, 10 1))'), 
    131131                ) 
    132132 
  • django/branches/gis/django/contrib/gis/tests/__init__.py

    r5776 r5786  
    5757 
    5858    # Getting initial values. 
     59    old_debug = settings.DEBUG 
    5960    old_name = copy(settings.DATABASE_NAME) 
    6061    old_installed = copy(settings.INSTALLED_APPS) 
     62 
     63    # Want DEBUG to be set to False. 
     64    settings.DEBUG = False 
    6165 
    6266    # Creating the test suite, adding the test models to INSTALLED_APPS, and 
     
    8387    # Cleaning up, destroying the test spatial database and resetting the INSTALLED_APPS. 
    8488    destroy_test_db(old_name, verbosity) 
     89    settings.DEBUG = old_debug 
    8590    settings.INSTALLED_APPS = old_installed 
    8691     
  • django/branches/gis/django/contrib/gis/tests/test_geos.py

    r5742 r5786  
    1 import unittest 
     1import random, unittest 
    22from django.contrib.gis.geos import \ 
    33    GEOSException, GEOSGeometryIndexError, \ 
     
    167167            self.assertEqual(lr, LinearRing(*lr.tuple)) 
    168168            self.assertEqual(lr, LinearRing([list(tup) for tup in lr.tuple])) 
    169             if HAS_NUMPY: self.assertEqual(lr, LineString(array(lr.tuple))) 
     169            if HAS_NUMPY: self.assertEqual(lr, LinearRing(array(lr.tuple))) 
    170170     
    171171    def test05a_polygons(self): 
     
    201201                self.assertEqual(p.ext_ring_cs, poly[0].tuple) # Testing __getitem__ 
    202202 
    203             # Testing __iter__ 
     203            # Testing __getitem__ and __setitem__ on invalid indices 
     204            self.assertRaises(GEOSGeometryIndexError, poly.__getitem__, len(poly)) 
     205            self.assertRaises(GEOSGeometryIndexError, poly.__setitem__, len(poly), False) 
     206            self.assertRaises(GEOSGeometryIndexError, poly.__getitem__, -1) 
     207 
     208            # Testing __iter__  
    204209            for r in poly: 
    205                 self.assertEqual(ring.geom_type, 'LinearRing') 
    206                 self.assertEqual(ring.geom_typeid, 2) 
     210                self.assertEqual(r.geom_type, 'LinearRing') 
     211                self.assertEqual(r.geom_typeid, 2) 
    207212 
    208213            # Testing polygon construction. 
     
    225230                pass 
    226231            poly[0][1] = newval # setting the second point in the polygon with the newvalue (based on the old) 
    227             self.assertEqual(newval, poly[0][1]) # The point in the polygon should be the 
    228             self.assertEqual(False, poly == prev) # Even different from the clone we just made 
     232            self.assertEqual(newval, poly[0][1]) # The point in the polygon should be the new value 
     233            self.assertEqual(False, poly == prev) # Should be different from the clone we just made 
    229234             
    230235    def test05b_multipolygons(self): 
     
    427432            b = GEOSGeometry(g_tup[1].wkt) 
    428433            i1 = GEOSGeometry(intersect_geoms[i].wkt)  
    429  
    430434            self.assertEqual(True, a.intersects(b)) 
    431435            i2 = a.intersection(b) 
    432436            self.assertEqual(i1, i2) 
    433             self.assertEqual(i1, a & b) 
     437            self.assertEqual(i1, a & b) # __and__ is intersection operator 
     438            a &= b # testing __iand__ 
     439            self.assertEqual(i1, a) 
    434440 
    435441    def test11_union(self): 
     
    442448            u2 = a.union(b) 
    443449            self.assertEqual(u1, u2) 
    444             self.assertEqual(u1, a | b) # Union ('|') operator 
     450            self.assertEqual(u1, a | b) # __or__ is union operator 
     451            a |= b # testing __ior__ 
     452            self.assertEqual(u1, a)  
    445453 
    446454    def test12_difference(self): 
     
    453461            d2 = a.difference(b) 
    454462            self.assertEqual(d1, d2) 
    455             self.assertEqual(d1, a - b) # Difference ('-') operator 
     463            self.assertEqual(d1, a - b) # __sub__ is difference operator 
     464            a -= b # testing __isub__ 
     465            self.assertEqual(d1, a) 
    456466 
    457467    def test13_symdifference(self): 
     
    464474            d2 = a.sym_difference(b) 
    465475            self.assertEqual(d1, d2) 
    466             self.assertEqual(d1, a ^ b) # Symmetric difference ('^') operator 
     476            self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference operator 
     477            a ^= b # testing __ixor__ 
     478            self.assertEqual(d1, a) 
    467479 
    468480    def test14_buffer(self): 
     
    493505                    self.assertAlmostEqual(exp_ring[k][1], buf_ring[k][1], 9) 
    494506 
     507    def test15_srid(self): 
     508        "Testing the SRID property and keyword." 
     509        # Testing SRID keyword on Point 
     510        pnt = Point(5, 23, srid=4326) 
     511        self.assertEqual(4326, pnt.srid) 
     512        pnt.srid = 3084 
     513        self.assertEqual(3084, pnt.srid) 
     514        self.assertRaises(TypeError, pnt.set_srid, '4326') 
     515 
     516        # Testing SRID keyword on fromstr(), and on Polygon rings. 
     517        poly = fromstr(polygons[1].wkt, srid=4269) 
     518        self.assertEqual(4269, poly.srid) 
     519        for ring in poly: self.assertEqual(4269, ring.srid) 
     520        poly.srid = 4326 
     521        self.assertEqual(4326, poly.shell.srid) 
     522 
     523        # Testing SRID keyword on GeometryCollection 
     524        gc = GeometryCollection(Point(5, 23), LineString((0, 0), (1.5, 1.5), (3, 3)), srid=32021) 
     525        self.assertEqual(32021, gc.srid) 
     526        for i in range(len(gc)): self.assertEqual(32021, gc[i].srid) 
     527 
     528    def test16_mutable_geometries(self): 
     529        "Testing the mutability of Polygons and Geometry Collections." 
     530        ### Testing the mutability of Polygons ### 
     531        for p in polygons: 
     532            poly = fromstr(p.wkt) 
     533 
     534            # Should only be able to use __setitem__ with LinearRing geometries. 
     535            self.assertRaises(TypeError, poly.__setitem__, 0, LineString((1, 1), (2, 2))) 
     536 
     537            # Constructing the new shell by adding 500 to every point in the old shell. 
     538            shell_tup = poly.shell.tuple 
     539            new_coords = [] 
     540            for point in shell_tup: new_coords.append((point[0] + 500., point[1] + 500.)) 
     541            shell1 = LinearRing(*tuple(new_coords)) 
     542            shell2 = shell1.clone()  
     543 
     544            # Assigning polygon's exterior ring w/the new shell 
     545            poly.exterior_ring = shell1 
     546            self.assertRaises(GEOSException, str, shell1) # shell1 should no longer be accessible 
     547            self.assertEqual(poly.exterior_ring, shell2) 
     548            self.assertEqual(poly[0], shell2) 
     549            del poly, shell1, shell_tup # cleaning up 
     550 
     551        ### Testing the mutability of Geometry Collections 
     552        for tg in multipoints: 
     553            mp = fromstr(tg.wkt) 
     554            for i in range(len(mp)): 
     555                # Creating a random point. 
     556                pnt = mp[i].clone() 
     557                new = Point(random.randint(1, 100), random.randint(1, 100)) 
     558                tmp = new.clone() 
     559                # Testing the assignmen 
     560                mp[i] = tmp 
     561                self.assertRaises(GEOSException, len, tmp) 
     562                self.assertEqual(mp[i], new) 
     563                self.assertEqual(mp[i].wkt, new.wkt) 
     564                self.assertNotEqual(pnt, mp[i]) 
     565            del mp 
     566 
     567        # Multipolygons involve much more memory management because each 
     568        #  polygon w/in the collection has its own rings. 
     569        for tg in multipolygons: 
     570            mpoly = fromstr(tg.wkt) 
     571            for i in xrange(len(mpoly)): 
     572                poly = mpoly[i].clone() 
     573                # Offsetting the each ring in the polygon by 500. 
     574                tmp = poly.clone() 
     575                for r in tmp:  
     576                    for j in xrange(len(r)): r[j] = (r[j][0] + 500., r[j][1] + 500.) 
     577                self.assertNotEqual(poly, tmp) 
     578                new = tmp.clone() # a 'reference' copy of the geometry used in assignment 
     579                # Testing the assignment 
     580                mpoly[i] = tmp 
     581                self.assertRaises(GEOSException, str, tmp) 
     582                self.assertEqual(mpoly[i], new) 
     583                self.assertNotEqual(poly, mpoly[i]) 
     584            del mpoly 
     585 
    495586def suite(): 
    496587    s = unittest.TestSuite()