Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/contrib/gis/geos/linestring.py: 0%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

108 statements  

1from django.contrib.gis.geos import prototypes as capi 

2from django.contrib.gis.geos.coordseq import GEOSCoordSeq 

3from django.contrib.gis.geos.error import GEOSException 

4from django.contrib.gis.geos.geometry import GEOSGeometry, LinearGeometryMixin 

5from django.contrib.gis.geos.point import Point 

6from django.contrib.gis.shortcuts import numpy 

7 

8 

9class LineString(LinearGeometryMixin, GEOSGeometry): 

10 _init_func = capi.create_linestring 

11 _minlength = 2 

12 has_cs = True 

13 

14 def __init__(self, *args, **kwargs): 

15 """ 

16 Initialize on the given sequence -- may take lists, tuples, NumPy arrays 

17 of X,Y pairs, or Point objects. If Point objects are used, ownership is 

18 _not_ transferred to the LineString object. 

19 

20 Examples: 

21 ls = LineString((1, 1), (2, 2)) 

22 ls = LineString([(1, 1), (2, 2)]) 

23 ls = LineString(array([(1, 1), (2, 2)])) 

24 ls = LineString(Point(1, 1), Point(2, 2)) 

25 """ 

26 # If only one argument provided, set the coords array appropriately 

27 if len(args) == 1: 

28 coords = args[0] 

29 else: 

30 coords = args 

31 

32 if not ( 

33 isinstance(coords, (tuple, list)) 

34 or numpy 

35 and isinstance(coords, numpy.ndarray) 

36 ): 

37 raise TypeError("Invalid initialization input for LineStrings.") 

38 

39 # If SRID was passed in with the keyword arguments 

40 srid = kwargs.get("srid") 

41 

42 ncoords = len(coords) 

43 if not ncoords: 

44 super().__init__(self._init_func(None), srid=srid) 

45 return 

46 

47 if ncoords < self._minlength: 

48 raise ValueError( 

49 "%s requires at least %d points, got %s." 

50 % ( 

51 self.__class__.__name__, 

52 self._minlength, 

53 ncoords, 

54 ) 

55 ) 

56 

57 numpy_coords = not isinstance(coords, (tuple, list)) 

58 if numpy_coords: 

59 shape = coords.shape # Using numpy's shape. 

60 if len(shape) != 2: 

61 raise TypeError("Too many dimensions.") 

62 self._checkdim(shape[1]) 

63 ndim = shape[1] 

64 else: 

65 # Getting the number of coords and the number of dimensions -- which 

66 # must stay the same, e.g., no LineString((1, 2), (1, 2, 3)). 

67 ndim = None 

68 # Incrementing through each of the coordinates and verifying 

69 for coord in coords: 

70 if not isinstance(coord, (tuple, list, Point)): 

71 raise TypeError( 

72 "Each coordinate should be a sequence (list or tuple)" 

73 ) 

74 

75 if ndim is None: 

76 ndim = len(coord) 

77 self._checkdim(ndim) 

78 elif len(coord) != ndim: 

79 raise TypeError("Dimension mismatch.") 

80 

81 # Creating a coordinate sequence object because it is easier to 

82 # set the points using its methods. 

83 cs = GEOSCoordSeq(capi.create_cs(ncoords, ndim), z=bool(ndim == 3)) 

84 point_setter = cs._set_point_3d if ndim == 3 else cs._set_point_2d 

85 

86 for i in range(ncoords): 

87 if numpy_coords: 

88 point_coords = coords[i, :] 

89 elif isinstance(coords[i], Point): 

90 point_coords = coords[i].tuple 

91 else: 

92 point_coords = coords[i] 

93 point_setter(i, point_coords) 

94 

95 # Calling the base geometry initialization with the returned pointer 

96 # from the function. 

97 super().__init__(self._init_func(cs.ptr), srid=srid) 

98 

99 def __iter__(self): 

100 "Allow iteration over this LineString." 

101 for i in range(len(self)): 

102 yield self[i] 

103 

104 def __len__(self): 

105 "Return the number of points in this LineString." 

106 return len(self._cs) 

107 

108 def _get_single_external(self, index): 

109 return self._cs[index] 

110 

111 _get_single_internal = _get_single_external 

112 

113 def _set_list(self, length, items): 

114 ndim = self._cs.dims 

115 hasz = self._cs.hasz # I don't understand why these are different 

116 srid = self.srid 

117 

118 # create a new coordinate sequence and populate accordingly 

119 cs = GEOSCoordSeq(capi.create_cs(length, ndim), z=hasz) 

120 for i, c in enumerate(items): 

121 cs[i] = c 

122 

123 ptr = self._init_func(cs.ptr) 

124 if ptr: 

125 capi.destroy_geom(self.ptr) 

126 self.ptr = ptr 

127 if srid is not None: 

128 self.srid = srid 

129 self._post_init() 

130 else: 

131 # can this happen? 

132 raise GEOSException("Geometry resulting from slice deletion was invalid.") 

133 

134 def _set_single(self, index, value): 

135 self._cs[index] = value 

136 

137 def _checkdim(self, dim): 

138 if dim not in (2, 3): 

139 raise TypeError("Dimension mismatch.") 

140 

141 # #### Sequence Properties #### 

142 @property 

143 def tuple(self): 

144 "Return a tuple version of the geometry from the coordinate sequence." 

145 return self._cs.tuple 

146 

147 coords = tuple 

148 

149 def _listarr(self, func): 

150 """ 

151 Return a sequence (list) corresponding with the given function. 

152 Return a numpy array if possible. 

153 """ 

154 lst = [func(i) for i in range(len(self))] 

155 if numpy: 

156 return numpy.array(lst) # ARRRR! 

157 else: 

158 return lst 

159 

160 @property 

161 def array(self): 

162 "Return a numpy array for the LineString." 

163 return self._listarr(self._cs.__getitem__) 

164 

165 @property 

166 def x(self): 

167 "Return a list or numpy array of the X variable." 

168 return self._listarr(self._cs.getX) 

169 

170 @property 

171 def y(self): 

172 "Return a list or numpy array of the Y variable." 

173 return self._listarr(self._cs.getY) 

174 

175 @property 

176 def z(self): 

177 "Return a list or numpy array of the Z variable." 

178 if not self.hasz: 

179 return None 

180 else: 

181 return self._listarr(self._cs.getZ) 

182 

183 

184# LinearRings are LineStrings used within Polygons. 

185class LinearRing(LineString): 

186 _minlength = 4 

187 _init_func = capi.create_linearring 

188 

189 @property 

190 def is_counterclockwise(self): 

191 if self.empty: 

192 raise ValueError("Orientation of an empty LinearRing cannot be determined.") 

193 return self._cs.is_counterclockwise