|
0
|
1 |
from ctypes import c_uint |
|
|
2 |
from django.contrib.gis.geos.error import GEOSException |
|
|
3 |
from django.contrib.gis.geos.geometry import GEOSGeometry |
|
|
4 |
from django.contrib.gis.geos import prototypes as capi |
|
|
5 |
|
|
|
6 |
class Point(GEOSGeometry): |
|
|
7 |
_minlength = 2 |
|
|
8 |
_maxlength = 3 |
|
|
9 |
|
|
|
10 |
def __init__(self, x, y=None, z=None, srid=None): |
|
|
11 |
""" |
|
|
12 |
The Point object may be initialized with either a tuple, or individual |
|
|
13 |
parameters. |
|
|
14 |
|
|
|
15 |
For Example: |
|
|
16 |
>>> p = Point((5, 23)) # 2D point, passed in as a tuple |
|
|
17 |
>>> p = Point(5, 23, 8) # 3D point, passed in with individual parameters |
|
|
18 |
""" |
|
|
19 |
if isinstance(x, (tuple, list)): |
|
|
20 |
# Here a tuple or list was passed in under the `x` parameter. |
|
|
21 |
ndim = len(x) |
|
|
22 |
coords = x |
|
|
23 |
elif isinstance(x, (int, float, long)) and isinstance(y, (int, float, long)): |
|
|
24 |
# Here X, Y, and (optionally) Z were passed in individually, as parameters. |
|
|
25 |
if isinstance(z, (int, float, long)): |
|
|
26 |
ndim = 3 |
|
|
27 |
coords = [x, y, z] |
|
|
28 |
else: |
|
|
29 |
ndim = 2 |
|
|
30 |
coords = [x, y] |
|
|
31 |
else: |
|
|
32 |
raise TypeError('Invalid parameters given for Point initialization.') |
|
|
33 |
|
|
|
34 |
point = self._create_point(ndim, coords) |
|
|
35 |
|
|
|
36 |
# Initializing using the address returned from the GEOS |
|
|
37 |
# createPoint factory. |
|
|
38 |
super(Point, self).__init__(point, srid=srid) |
|
|
39 |
|
|
|
40 |
def _create_point(self, ndim, coords): |
|
|
41 |
""" |
|
|
42 |
Create a coordinate sequence, set X, Y, [Z], and create point |
|
|
43 |
""" |
|
|
44 |
if ndim < 2 or ndim > 3: |
|
|
45 |
raise TypeError('Invalid point dimension: %s' % str(ndim)) |
|
|
46 |
|
|
|
47 |
cs = capi.create_cs(c_uint(1), c_uint(ndim)) |
|
|
48 |
i = iter(coords) |
|
|
49 |
capi.cs_setx(cs, 0, i.next()) |
|
|
50 |
capi.cs_sety(cs, 0, i.next()) |
|
|
51 |
if ndim == 3: capi.cs_setz(cs, 0, i.next()) |
|
|
52 |
|
|
|
53 |
return capi.create_point(cs) |
|
|
54 |
|
|
|
55 |
def _set_list(self, length, items): |
|
|
56 |
ptr = self._create_point(length, items) |
|
|
57 |
if ptr: |
|
|
58 |
capi.destroy_geom(self.ptr) |
|
|
59 |
self._ptr = ptr |
|
|
60 |
self._set_cs() |
|
|
61 |
else: |
|
|
62 |
# can this happen? |
|
|
63 |
raise GEOSException('Geometry resulting from slice deletion was invalid.') |
|
|
64 |
|
|
|
65 |
def _set_single(self, index, value): |
|
|
66 |
self._cs.setOrdinate(index, 0, value) |
|
|
67 |
|
|
|
68 |
def __iter__(self): |
|
|
69 |
"Allows iteration over coordinates of this Point." |
|
|
70 |
for i in xrange(len(self)): |
|
|
71 |
yield self[i] |
|
|
72 |
|
|
|
73 |
def __len__(self): |
|
|
74 |
"Returns the number of dimensions for this Point (either 0, 2 or 3)." |
|
|
75 |
if self.empty: return 0 |
|
|
76 |
if self.hasz: return 3 |
|
|
77 |
else: return 2 |
|
|
78 |
|
|
|
79 |
def _get_single_external(self, index): |
|
|
80 |
if index == 0: |
|
|
81 |
return self.x |
|
|
82 |
elif index == 1: |
|
|
83 |
return self.y |
|
|
84 |
elif index == 2: |
|
|
85 |
return self.z |
|
|
86 |
|
|
|
87 |
_get_single_internal = _get_single_external |
|
|
88 |
|
|
|
89 |
def get_x(self): |
|
|
90 |
"Returns the X component of the Point." |
|
|
91 |
return self._cs.getOrdinate(0, 0) |
|
|
92 |
|
|
|
93 |
def set_x(self, value): |
|
|
94 |
"Sets the X component of the Point." |
|
|
95 |
self._cs.setOrdinate(0, 0, value) |
|
|
96 |
|
|
|
97 |
def get_y(self): |
|
|
98 |
"Returns the Y component of the Point." |
|
|
99 |
return self._cs.getOrdinate(1, 0) |
|
|
100 |
|
|
|
101 |
def set_y(self, value): |
|
|
102 |
"Sets the Y component of the Point." |
|
|
103 |
self._cs.setOrdinate(1, 0, value) |
|
|
104 |
|
|
|
105 |
def get_z(self): |
|
|
106 |
"Returns the Z component of the Point." |
|
|
107 |
if self.hasz: |
|
|
108 |
return self._cs.getOrdinate(2, 0) |
|
|
109 |
else: |
|
|
110 |
return None |
|
|
111 |
|
|
|
112 |
def set_z(self, value): |
|
|
113 |
"Sets the Z component of the Point." |
|
|
114 |
if self.hasz: |
|
|
115 |
self._cs.setOrdinate(2, 0, value) |
|
|
116 |
else: |
|
|
117 |
raise GEOSException('Cannot set Z on 2D Point.') |
|
|
118 |
|
|
|
119 |
# X, Y, Z properties |
|
|
120 |
x = property(get_x, set_x) |
|
|
121 |
y = property(get_y, set_y) |
|
|
122 |
z = property(get_z, set_z) |
|
|
123 |
|
|
|
124 |
### Tuple setting and retrieval routines. ### |
|
|
125 |
def get_coords(self): |
|
|
126 |
"Returns a tuple of the point." |
|
|
127 |
return self._cs.tuple |
|
|
128 |
|
|
|
129 |
def set_coords(self, tup): |
|
|
130 |
"Sets the coordinates of the point with the given tuple." |
|
|
131 |
self._cs[0] = tup |
|
|
132 |
|
|
|
133 |
# The tuple and coords properties |
|
|
134 |
tuple = property(get_coords, set_coords) |
|
|
135 |
coords = tuple |