Coverage for pyguymer3/geo/bufferSrc/buffer_MultiPoint.py: 3%

29 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_MultiPoint( 

5 multipoint, 

6 dist, 

7 /, 

8 *, 

9 debug = __debug__, 

10 eps = 1.0e-12, 

11 fill = 1.0, 

12 fillSpace = "EuclideanSpace", 

13 nAng = 9, 

14 nIter = 100, 

15 prefix = ".", 

16 ramLimit = 1073741824, 

17 simp = 0.1, 

18 tol = 1.0e-10, 

19): 

20 """Buffer a MultiPoint 

21 

22 This function reads in a MultiPoint that exists on the surface of the Earth 

23 and returns a [Multi]Polygon of the same MultiPoint buffered by a constant 

24 distance (in metres). 

25 

26 Parameters 

27 ---------- 

28 multipoint : shapely.geometry.multipoint.MultiPoint 

29 the MultiPoint 

30 dist : float 

31 the Geodesic distance to buffer each point within the MultiPoint 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 nAng : int, optional 

44 the number of angles around each point within the MultiPoint that are 

45 calculated when buffering 

46 nIter : int, optional 

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

48 prefix : str, optional 

49 change the name of the output debugging CSVs 

50 ramLimit : int, optional 

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

52 simp : float, optional 

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

54 disable simplification (in degrees) 

55 tol : float, optional 

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

57 degrees) 

58 

59 Returns 

60 ------- 

61 buffs : shapely.geometry.polygon.Polygon, shapely.geometry.multipolygon.MultiPolygon 

62 the buffered MultiPoint 

63 

64 Notes 

65 ----- 

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

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

68 

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

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

71 Users have reported that very small distance values sometimes produce 

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

73 

74 According to the `Shapely documentation for the function 

75 shapely.geometry.polygon.orient() 

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

77 

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

79 will be oriented counter-clockwise." 

80 

81 Copyright 2017 Thomas Guymer [1]_ 

82 

83 References 

84 ---------- 

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

86 """ 

87 

88 # Import special modules ... 

89 try: 

90 import shapely 

91 import shapely.geometry 

92 import shapely.ops 

93 except: 

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

95 

96 # Import sub-functions ... 

97 from ..check import check 

98 from ..fillin import fillin 

99 from .buffer_Point import buffer_Point 

100 

101 # ************************************************************************** 

102 

103 # Check argument ... 

104 assert isinstance(multipoint, shapely.geometry.multipoint.MultiPoint), "\"multipoint\" is not a MultiPoint" 

105 if debug: 

106 check(multipoint, prefix = prefix) 

107 

108 # Initialize list ... 

109 buffs = [] 

110 

111 # Loop over Point ... 

112 for point in multipoint.geoms: 

113 # Append buffer of Point to list ... 

114 buffs.append( 

115 buffer_Point( 

116 point, 

117 dist, 

118 debug = debug, 

119 eps = eps, 

120 fill = fill, 

121 fillSpace = fillSpace, 

122 nAng = nAng, 

123 nIter = nIter, 

124 prefix = prefix, 

125 ramLimit = ramLimit, 

126 simp = simp, 

127 tol = tol, 

128 ) 

129 ) 

130 

131 # Convert list of [Multi]Polygons to a (unified) [Multi]Polygon ... 

132 buffs = shapely.ops.unary_union(buffs).simplify(tol) 

133 if debug: 

134 check(buffs, prefix = prefix) 

135 

136 # Check if the user wants to fill in the [Multi]Polygon ... 

137 # NOTE: This is only needed because the "shapely.ops.unary_union()" call 

138 # above includes a "simplify()". 

139 if simp < 0.0 < fill: 

140 # Fill in [Multi]Polygon ... 

141 buffs = fillin( 

142 buffs, 

143 fill, 

144 debug = debug, 

145 eps = eps, 

146 fillSpace = fillSpace, 

147 nIter = nIter, 

148 prefix = prefix, 

149 ramLimit = ramLimit, 

150 tol = tol, 

151 ) 

152 if debug: 

153 check(buffs, prefix = prefix) 

154 

155 # Check if the user wants to simplify the [Multi]Polygon ... 

156 # NOTE: This is only needed because the "shapely.ops.unary_union()" call 

157 # above might allow more simplification. 

158 if simp > 0.0: 

159 # Simplify [Multi]Polygon ... 

160 buffsSimp = buffs.simplify(simp) 

161 if debug: 

162 check(buffsSimp, prefix = prefix) 

163 

164 # Return simplified answer ... 

165 return buffsSimp 

166 

167 # Return answer ... 

168 return buffs