gis_.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. '''
  2. @author: olivier.massot, 2018
  3. '''
  4. from osgeo import ogr, osr
  5. from path import Path
  6. GEOM_UNKNOWN = 0
  7. GEOM_POINT = 1
  8. GEOM_LINE = 2
  9. GEOM_POLYGON = 3
  10. GEOM_MULTIPOINT = 4
  11. GEOM_MULTILINE = 5
  12. GEOM_MULTIPOLYGON = 6
  13. GEOM_NAMES = {0: "(AUCUN)",
  14. 1: "POINT",
  15. 2: "LIGNE",
  16. 3: "POLYGONE",
  17. 4: "MULTI-POINT",
  18. 5:"MULTI-LIGNE",
  19. 6:"MULTI-POLYGONE",
  20. }
  21. def point_(x, y):
  22. point = ogr.Geometry(ogr.wkbPoint)
  23. point.AddPoint(x, y)
  24. return point
  25. class Datasource():
  26. DRIVER_NAME = "ESRI Shapefile"
  27. def __init__(self, filename, readonly=True):
  28. self.filename = Path(filename)
  29. driver = ogr.GetDriverByName(self.DRIVER_NAME)
  30. self._ogr_datasource = driver.Open(filename, 0 if readonly else 1)
  31. if not self._ogr_datasource:
  32. raise IOError("Unable to read the file {}".format(filename))
  33. @property
  34. def layer(self):
  35. return Layer(self._ogr_datasource.GetLayer())
  36. class LayerField():
  37. def __init__(self, ogr_field):
  38. self.name = ogr_field.GetName()
  39. self.type_ = ogr_field.GetType()
  40. self.type_name = ogr_field.GetFieldTypeName(self.type_)
  41. self.width = ogr_field.GetWidth()
  42. self.precision = ogr_field.GetPrecision()
  43. def __repr__(self):
  44. return "<Field: nom={}, type={}, longueur={}>".format(self.name, self.type_name, self.width)
  45. class Layer():
  46. def __init__(self, ogr_layer):
  47. self._ogr_layer = ogr_layer
  48. self.name = ogr_layer.GetName()
  49. self.srid = ogr_layer.GetSpatialRef().GetAttrValue('AUTHORITY',1)
  50. self.geom_type = ogr_layer.GetGeomType()
  51. _layer_def = self._ogr_layer.GetLayerDefn()
  52. self.fields = [LayerField(_layer_def.GetFieldDefn(i)) for i in range(_layer_def.GetFieldCount())]
  53. @property
  54. def geom_name(self):
  55. return GEOM_NAMES[self._ogr_layer.GetGeomType()]
  56. def __len__(self):
  57. return self._ogr_layer.GetFeatureCount()
  58. def __iter__(self):
  59. for f in self._ogr_layer.__iter__():
  60. yield Feature(f)
  61. self._ogr_layer.ResetReading()
  62. def __getitem__(self, i):
  63. return Feature(self._ogr_layer.GetFeature(i))
  64. class Feature():
  65. def __init__(self, ogr_feature):
  66. self._ogr_feature = ogr_feature
  67. self.geom = self._ogr_feature.GetGeometryRef()
  68. self.geom_type = self.geom.GetGeometryType()
  69. xmin, xmax, ymin, ymax = self.geom.GetEnvelope()
  70. self.bounding_box = (xmin, ymin, xmax, ymax)
  71. _def = ogr_feature.GetDefnRef()
  72. for i in range(_def.GetFieldCount()):
  73. field = _def.GetFieldDefn(i)
  74. value = ogr_feature[i]
  75. if value is None and field.GetType() == ogr.OFTString:
  76. value = ""
  77. self.__setattr__(field.GetName(), value)
  78. @property
  79. def geom_name(self):
  80. return GEOM_NAMES[self.geom.GetGeometryType()]
  81. def fields(self):
  82. layerDefinition = self._ogr_layer.GetLayerDefn()
  83. return [LayerField(layerDefinition.GetFieldDefn(i)) for i in range(layerDefinition.GetFieldCount())]
  84. @property
  85. def valid(self):
  86. return self.geom.IsValid()
  87. def __repr__(self):
  88. return "<Feature: type={}, bounding_box={}>".format(self.geom_name, self.bounding_box)
  89. @property
  90. def points(self):
  91. if self.geom_type != GEOM_POLYGON:
  92. return [point_(*p) for p in self.geom.GetPoints()]
  93. else:
  94. return [point_(*p) for p in self.geom.GetGeometryRef(0).GetPoints()]
  95. def almost_equal(self, feature, buffer_dist=1):
  96. if feature.geom_type == self.geom_type:
  97. buffer = self.geom.Buffer(buffer_dist)
  98. if buffer.Contains(feature.geom):
  99. return True
  100. return False
  101. @classmethod
  102. def union(cls, features):
  103. g = features[0].geom.Clone()
  104. for f in features[1:]:
  105. g = g.Union(f.geom)
  106. return g
  107. @classmethod
  108. def buffered_union(cls, features, buffer_dist=1):
  109. multi = ogr.Geometry(ogr.wkbMultiPolygon)
  110. for f in features:
  111. geom = f.geom if issubclass(f.__class__, Feature) else f # au cas où ce ne seraient pas des features, mais directement des geometries
  112. multi.AddGeometry(geom.Buffer(buffer_dist))
  113. return multi.UnionCascaded()
  114. if __name__ == "__main__":
  115. ds = Datasource(r"C:\dev\python\datacheck\work\STURNO_178AP1_REC_171121_OK\ARTERE_GEO.shp")
  116. layer = ds.layer
  117. print(layer.fields)
  118. # for f in layer:
  119. # print(f)
  120. f = layer[4]
  121. f2 = layer[5]
  122. f3 = layer[4]
  123. print(f)
  124. print(f.geom)
  125. print(f.AR_ID_INSE)
  126. gf = Feature.union(list(layer))
  127. print(gf)
  128. # gf = Feature.buffered_union(list(layer), 0.5)
  129. # print(gf)
  130. # save to file
  131. result_file = Path(r"C:\dev\python\datacheck\work\result.shp")
  132. driver = ogr.GetDriverByName("ESRI Shapefile")
  133. if result_file.exists():
  134. driver.DeleteDataSource(result_file)
  135. data_source = driver.CreateDataSource(result_file)
  136. srs = osr.SpatialReference()
  137. srs.ImportFromEPSG(3949)
  138. layer = data_source.CreateLayer("result", srs, gf.GetGeometryType())
  139. feature = ogr.Feature(layer.GetLayerDefn())
  140. feature.SetGeometry(gf)
  141. layer.CreateFeature(feature)