Coverage for pyguymer3/geo/buffer.py: 67%

33 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-08 18:47 +0000

1#!/usr/bin/env python3 

2 

3# Define function ... 

4def buffer( 

5 shape, 

6 dist, 

7 /, 

8 *, 

9 debug = __debug__, 

10 eps = 1.0e-12, 

11 fill = 1.0, 

12 fillSpace = "EuclideanSpace", 

13 keepInteriors = True, 

14 nAng = 9, 

15 nIter = 100, 

16 prefix = ".", 

17 ramLimit = 1073741824, 

18 simp = 0.1, 

19 tol = 1.0e-10, 

20): 

21 """Buffer a shape 

22 

23 This function reads in a shape that exists on the surface of the Earth and 

24 returns the same shape buffered by a constant distance (in metres). 

25 

26 Parameters 

27 ---------- 

28 shape : shapely.coords.CoordinateSequence, shapely.geometry.point.Point, shapely.geometry.multipoint.MultiPoint, shapely.geometry.polygon.LinearRing, shapely.geometry.linestring.LineString, shapely.geometry.multilinestring.MultiLineString, shapely.geometry.polygon.Polygon, shapely.geometry.multipolygon.MultiPolygon 

29 the shape 

30 dist : float 

31 the Geodesic distance to buffer each point within the shape by (in 

32 metres) 

33 debug : bool, optional 

34 print debug messages 

35 eps : float, optional 

36 the tolerance of the Vincenty formula iterations 

37 fill : float, optional 

38 the Euclidean or Geodesic distance to fill in between each point within 

39 the shapes by (in degrees or metres) 

40 fillSpace : str, optional 

41 the geometric space to perform the filling in (either "EuclideanSpace" 

42 or "GeodesicSpace") 

43 keepInteriors : bool, optional 

44 keep the interiors of the Polygon 

45 nAng : int, optional 

46 the number of angles around each point within the shape that are 

47 calculated when buffering 

48 nIter : int, optional 

49 the maximum number of iterations (particularly the Vincenty formula) 

50 prefix : str, optional 

51 change the name of the output debugging CSVs 

52 ramLimit : int, optional 

53 the maximum RAM usage of each "large" array (in bytes) 

54 simp : float, optional 

55 how much intermediary [Multi]Polygons are simplified by; negative values 

56 disable simplification (in degrees) 

57 tol : float, optional 

58 the Euclidean distance that defines two points as being the same (in 

59 degrees) 

60 

61 Returns 

62 ------- 

63 buff : shapely.geometry.polygon.Polygon, shapely.geometry.multipolygon.MultiPolygon 

64 the buffered shape 

65 

66 Notes 

67 ----- 

68 According to the `Shapely documentation for the method object.buffer() 

69 <https://shapely.readthedocs.io/en/stable/manual.html#object.buffer>`_ : 

70 

71 "Passed a distance of 0, buffer() can sometimes be used to "clean" 

72 self-touching or self-crossing polygons such as the classic "bowtie". 

73 Users have reported that very small distance values sometimes produce 

74 cleaner results than 0. Your mileage may vary when cleaning surfaces." 

75 

76 According to the `Shapely documentation for the function 

77 shapely.geometry.polygon.orient() 

78 <https://shapely.readthedocs.io/en/stable/manual.html#shapely.geometry.polygon.orient>`_ : 

79 

80 "A sign of 1.0 means that the coordinates of the product's exterior ring 

81 will be oriented counter-clockwise." 

82 

83 Copyright 2017 Thomas Guymer [1]_ 

84 

85 References 

86 ---------- 

87 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3 

88 """ 

89 

90 # Import special modules ... 

91 try: 

92 import shapely 

93 import shapely.geometry 

94 except: 

95 raise Exception("\"shapely\" is not installed; run \"pip install --user Shapely\"") from None 

96 

97 # Import sub-functions ... 

98 from .bufferSrc import buffer_CoordinateSequence 

99 from .bufferSrc import buffer_LinearRing 

100 from .bufferSrc import buffer_LineString 

101 from .bufferSrc import buffer_MultiLineString 

102 from .bufferSrc import buffer_MultiPoint 

103 from .bufferSrc import buffer_MultiPolygon 

104 from .bufferSrc import buffer_Point 

105 from .bufferSrc import buffer_Polygon 

106 

107 # ************************************************************************** 

108 

109 # Check what type it is ... 

110 match shape: 

111 case shapely.coords.CoordinateSequence(): 

112 # Return it buffered ... 

113 return buffer_CoordinateSequence( 

114 shape, 

115 dist, 

116 debug = debug, 

117 eps = eps, 

118 fill = fill, 

119 fillSpace = fillSpace, 

120 nAng = nAng, 

121 nIter = nIter, 

122 prefix = prefix, 

123 ramLimit = ramLimit, 

124 simp = simp, 

125 tol = tol, 

126 ) 

127 case shapely.geometry.point.Point(): 

128 # Return it buffered ... 

129 return buffer_Point( 

130 shape, 

131 dist, 

132 debug = debug, 

133 eps = eps, 

134 fill = fill, 

135 fillSpace = fillSpace, 

136 nAng = nAng, 

137 nIter = nIter, 

138 prefix = prefix, 

139 ramLimit = ramLimit, 

140 simp = simp, 

141 tol = tol, 

142 ) 

143 case shapely.geometry.multipoint.MultiPoint(): 

144 # Return it buffered ... 

145 return buffer_MultiPoint( 

146 shape, 

147 dist, 

148 debug = debug, 

149 eps = eps, 

150 fill = fill, 

151 fillSpace = fillSpace, 

152 nAng = nAng, 

153 nIter = nIter, 

154 prefix = prefix, 

155 ramLimit = ramLimit, 

156 simp = simp, 

157 tol = tol, 

158 ) 

159 case shapely.geometry.polygon.LinearRing(): 

160 # Return it buffered ... 

161 return buffer_LinearRing( 

162 shape, 

163 dist, 

164 debug = debug, 

165 eps = eps, 

166 fill = fill, 

167 fillSpace = fillSpace, 

168 nAng = nAng, 

169 nIter = nIter, 

170 prefix = prefix, 

171 ramLimit = ramLimit, 

172 simp = simp, 

173 tol = tol, 

174 ) 

175 case shapely.geometry.linestring.LineString(): 

176 # Return it buffered ... 

177 return buffer_LineString( 

178 shape, 

179 dist, 

180 debug = debug, 

181 eps = eps, 

182 fill = fill, 

183 fillSpace = fillSpace, 

184 nAng = nAng, 

185 nIter = nIter, 

186 prefix = prefix, 

187 ramLimit = ramLimit, 

188 simp = simp, 

189 tol = tol, 

190 ) 

191 case shapely.geometry.multilinestring.MultiLineString(): 

192 # Return it buffered ... 

193 return buffer_MultiLineString( 

194 shape, 

195 dist, 

196 debug = debug, 

197 eps = eps, 

198 fill = fill, 

199 fillSpace = fillSpace, 

200 nAng = nAng, 

201 nIter = nIter, 

202 prefix = prefix, 

203 ramLimit = ramLimit, 

204 simp = simp, 

205 tol = tol, 

206 ) 

207 case shapely.geometry.polygon.Polygon(): 

208 # Return it buffered ... 

209 return buffer_Polygon( 

210 shape, 

211 dist, 

212 debug = debug, 

213 eps = eps, 

214 fill = fill, 

215 fillSpace = fillSpace, 

216 keepInteriors = keepInteriors, 

217 nAng = nAng, 

218 nIter = nIter, 

219 prefix = prefix, 

220 ramLimit = ramLimit, 

221 simp = simp, 

222 tol = tol, 

223 ) 

224 case shapely.geometry.multipolygon.MultiPolygon(): 

225 # Return it buffered ... 

226 return buffer_MultiPolygon( 

227 shape, 

228 dist, 

229 debug = debug, 

230 eps = eps, 

231 fill = fill, 

232 fillSpace = fillSpace, 

233 keepInteriors = keepInteriors, 

234 nAng = nAng, 

235 nIter = nIter, 

236 prefix = prefix, 

237 ramLimit = ramLimit, 

238 simp = simp, 

239 tol = tol, 

240 ) 

241 case _: 

242 # Cry ... 

243 raise TypeError(f"\"shape\" is an unexpected type ({repr(type(shape))})") from None