def execute_CreateZone(r_flowdir, str_lakes, r_slope, minslope, str_frompoint, distance, bufferw, str_zonesfolder, messages): str_segments = str_zonesfolder + "\\segments" str_linesegments = str_zonesfolder + "\\line_segments.shp" str_bufferedsegments = str_zonesfolder + "\\buff_segments.shp" save_sourcepoints = str_zonesfolder + "\\sourcepoints.shp" str_r_lakes = str_zonesfolder + "\\r_lakes" flowdir = RasterIO(r_flowdir) if r_slope is not None: slope = RasterIO(r_slope) try: flowdir.checkMatch(slope) except Exception as e: messages.addErrorMessage(e.message) else: slope = None # Conversion des lacs en raster et copie arcpy.env.snapRaster = flowdir.raster arcpy.env.outputCoordinateSystem = flowdir.raster.spatialReference arcpy.env.extent = flowdir.raster arcpy.PolygonToRaster_conversion(str_lakes, arcpy.Describe(str_lakes).OIDFieldName, str_r_lakes, cellsize=flowdir.raster) lakes = RasterIO(arcpy.Raster(str_r_lakes)) arcpy.CopyFeatures_management(str_lakes, str_zonesfolder + "\\lakes.shp") str_lakes = str_zonesfolder + "\\lakes.shp" arcpy.AddGeometryAttributes_management(str_lakes, "EXTENT") ### Début du traitement perrmettant d'identifier les segments (sous forme de raster) ### raster_segments = RasterIO(r_flowdir, str_segments, int, -255) # numérotation des segments segnumber = 0 lakes_bci = {} toclip = {} inputpoints = {} # Pour chaque point de départ frompointcursor = arcpy.da.SearchCursor(str_frompoint, ["SHAPE@", "OID@"]) for frompoint in frompointcursor: # On prend l'objet géométrique (le point) associé à la ligne dans la table frompointshape = frompoint[0].firstPoint # Nouvelle rivière : on change de segment segnumber += 1 # Conversion des coordonnées currentcol = flowdir.XtoCol(frompointshape.X) currentrow = flowdir.YtoRow(frompointshape.Y) # Tests de sécurité pour s'assurer que le point de départ est à l'intérieurs des rasters intheraster = True if currentcol < 0 or currentcol >= flowdir.raster.width or currentrow < 0 or currentrow >= flowdir.raster.height: intheraster = False elif (flowdir.getValue(currentrow, currentcol) != 1 and flowdir.getValue(currentrow, currentcol) != 2 and flowdir.getValue(currentrow, currentcol) != 4 and flowdir.getValue(currentrow, currentcol) != 8 and flowdir.getValue(currentrow, currentcol) != 16 and flowdir.getValue(currentrow, currentcol) != 32 and flowdir.getValue(currentrow, currentcol) != 64 and flowdir.getValue(currentrow, currentcol) != 128): intheraster = False listpointsflowpath = [] totaldistance = 0 currentdistance = 0 inlake = True # True si la rivière (depuis le point de départ jusqu'au confluent) est composée d'au moins deux segments dividedriver = False # listtomerged contient la liste des segments trop courts, qui doivent être fusionnés avec segment précédent listtomerged = [] # Pour chaque cellule en suivant l'écoulement while (intheraster): waslake = inlake inlake = False lakevalue = lakes.getValue(currentrow, currentcol) inlake = (lakevalue != lakes.nodata) if not (inlake and waslake): # Distance parcourue depuis le début du segment totaldistance = totaldistance + currentdistance slope_criteria = True if slope is not None: slope_criteria = slope.getValue(currentrow, currentcol) > minslope # Test si on arrive à un lac if inlake and not waslake: # Segment trop court si de longueur inférieure à 30% de la distance voullue # Le segment doit être alors fusionné avec le segment précédent (qui existe uniquement si dividedriver = True) # ajout de l'info de clipper ensuite également coordX = flowdir.ColtoX(currentcol) coordY = flowdir.RowtoY(currentrow) fieldidlakes = arcpy.Describe(str_lakes).OIDFieldName shplakes = arcpy.da.SearchCursor(str_lakes, [ "SHAPE@", "EXT_MIN_X", "EXT_MAX_X", "EXT_MIN_Y", "EXT_MAX_Y", fieldidlakes ]) for shplake in shplakes: if shplake[0].contains(arcpy.Point(coordX, coordY)): lakes_bci[segnumber] = shplakes[5] distXmin = abs(coordX - shplake[1]) distXmax = abs(coordX - shplake[2]) distYmin = abs(coordY - shplake[3]) distYmax = abs(coordY - shplake[4]) mini = min(distXmin, distXmax, distYmin, distYmax) if mini == distXmin: toclip[segnumber] = ["Xmax", shplake[1]] messages.addMessage( str(segnumber) + " Xmax " + str(shplake[1])) if mini == distXmax: toclip[segnumber] = ["Xmin", shplake[2]] messages.addMessage( str(segnumber) + " Xmin " + str(shplake[2])) if mini == distYmin: toclip[segnumber] = ["Ymax", shplake[3]] messages.addMessage( str(segnumber) + " Ymax " + str(shplake[3])) if mini == distYmax: toclip[segnumber] = ["Ymin", shplake[4]] messages.addMessage( str(segnumber) + " Ymin " + str(shplake[4])) if totaldistance < 0.3 * distance and dividedriver: if segnumber in toclip: toclip[segnumber - 1] = toclip.pop(segnumber) listtomerged.append(segnumber) totaldistance = 0 segnumber += 1 dividedriver = False elif totaldistance > distance and slope_criteria: # Test si on a parcouru la distance voullue totaldistance = 0 segnumber += 1 dividedriver = True if not inlake: # On conseerve une liste des points traités, avec leur numéro de segment currentpoint = pointflowpath() currentpoint.row = currentrow currentpoint.col = currentcol currentpoint.X = flowdir.ColtoX(currentcol) currentpoint.Y = flowdir.RowtoY(currentrow) currentpoint.distance = totaldistance currentpoint.segnumber = segnumber currentpoint.frompointid = frompoint[1] listpointsflowpath.append(currentpoint) # On cherche le prochain point à partir du flow direction direction = flowdir.getValue(currentrow, currentcol) if (direction == 1): currentcol = currentcol + 1 currentdistance = flowdir.raster.meanCellWidth if (direction == 2): currentcol = currentcol + 1 currentrow = currentrow + 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) if (direction == 4): currentrow = currentrow + 1 currentdistance = flowdir.raster.meanCellHeight if (direction == 8): currentcol = currentcol - 1 currentrow = currentrow + 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) if (direction == 16): currentcol = currentcol - 1 currentdistance = flowdir.raster.meanCellWidth if (direction == 32): currentcol = currentcol - 1 currentrow = currentrow - 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) if (direction == 64): currentrow = currentrow - 1 currentdistance = flowdir.raster.meanCellHeight if (direction == 128): currentcol = currentcol + 1 currentrow = currentrow - 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) # Tests de sécurité pour s'assurer que l'on ne sorte pas des rasters if currentcol < 0 or currentcol >= flowdir.raster.width or currentrow < 0 or currentrow >= flowdir.raster.height: intheraster = False elif (flowdir.getValue(currentrow, currentcol) != 1 and flowdir.getValue(currentrow, currentcol) != 2 and flowdir.getValue(currentrow, currentcol) != 4 and flowdir.getValue(currentrow, currentcol) != 8 and flowdir.getValue(currentrow, currentcol) != 16 and flowdir.getValue(currentrow, currentcol) != 32 and flowdir.getValue(currentrow, currentcol) != 64 and flowdir.getValue(currentrow, currentcol) != 128): intheraster = False if intheraster: confluence_seg = raster_segments.getValue( currentrow, currentcol) if (confluence_seg != -255): # Atteinte d'un confluent déjà traité # Si le segment dans lequel on arrive est limité par un lac, le confluent peut l'être aussi # On copie l'item toclip pour limiter l'étendu de la zone # par contre on garde l'élévation à -999 (hfix sera le résultat de la simulation du cours d'eau confluent) if confluence_seg in listtomerged: confluence_seg -= 1 if confluence_seg in toclip: clipitem = list(toclip[confluence_seg]) toclip[segnumber] = clipitem if totaldistance < 0.3 * distance and dividedriver: # Segment trop court si de longueur inférieure à 30% de la distance voullue # Le segment doit être alors fusionné avec le segment précédent (qui existe uniquement si dividedriver = True) listtomerged.append(segnumber) if segnumber in toclip: toclip[segnumber - 1] = toclip.pop(segnumber) intheraster = False # Pour chaque point traité le long de l'écoulement for currentpoint in listpointsflowpath: # Si c'est un point d'un segment trop court, on remplace le numéro du segment par le numéro du segment précédent if currentpoint.segnumber in listtomerged: currentpoint.segnumber -= 1 # On enregistre le point raster_segments.setValue(currentpoint.row, currentpoint.col, currentpoint.segnumber) if currentpoint.segnumber not in inputpoints: newpoint = pointflowpath() newpoint.type = "main" newpoint.frompointid = currentpoint.frompointid # Coordonnées du point source newpoint.X = currentpoint.X newpoint.Y = currentpoint.Y inputpoints[currentpoint.segnumber] = newpoint raster_segments.save() ### Fin du traitement perrmettant d'identifier les segments ### ### Transformation du raster des segments en zones #### # Transformation en polyline tmp_segments = arcpy.env.scratchWorkspace + "\\tmpsegments.shp" arcpy.RasterToPolyline_conversion(str_segments, tmp_segments) arcpy.Dissolve_management(tmp_segments, str_linesegments, "GRID_CODE") arcpy.Delete_management(tmp_segments) # Création de la zone tampon # Harcoded : buffer longitudinal de 1/10 de l'extension latérale (obtenue par Euclidienne Allocation) tmp_segmentsbuf = arcpy.env.scratchWorkspace + "\\tmpsegments_buf.shp" arcpy.Buffer_analysis(str_linesegments, tmp_segmentsbuf, bufferw / 10.) segalloc = arcpy.sa.EucAllocation(raster_segments.raster, bufferw) arcpy.RasterToPolygon_conversion(segalloc, tmp_segments) arcpy.AddField_management(tmp_segments, "GRID_CODE", "LONG") arcpy.CalculateField_management(tmp_segments, "GRID_CODE", "!GRIDCODE!", "PYTHON_9.3") tmp_segments2 = arcpy.env.scratchWorkspace + "\\tmpsegments2.shp" arcpy.Merge_management([tmp_segmentsbuf, tmp_segments], tmp_segments2) arcpy.Dissolve_management(tmp_segments2, str_bufferedsegments, ["GRID_CODE"], multi_part="SINGLE_PART") arcpy.Delete_management(tmp_segments) arcpy.Delete_management(tmp_segments2) arcpy.Delete_management(str_lakes) # Création de la zone pour chaque segment arcpy.CreateFeatureclass_management( str_zonesfolder, "polyzones.shp", "POLYGON", str_bufferedsegments, spatial_reference=flowdir.raster.spatialReference) polyzones = str_zonesfolder + "\\polyzones.shp" arcpy.AddField_management(polyzones, "Lake_ID", "LONG") cursor = arcpy.da.InsertCursor(polyzones, ["GRID_CODE", "SHAPE@", "Lake_ID"]) segmentscursor = arcpy.da.UpdateCursor(str_bufferedsegments, ["GRID_CODE", "SHAPE@"]) for segment in segmentscursor: Xmin = segment[1].extent.XMin Ymin = segment[1].extent.YMin Xmax = segment[1].extent.XMax Ymax = segment[1].extent.YMax if segment[0] in toclip: if toclip[segment[0]][0] == "Xmin": Xmin = max(toclip[segment[0]][1], Xmin) if toclip[segment[0]][0] == "Xmax": Xmax = min(toclip[segment[0]][1], Xmax) if toclip[segment[0]][0] == "Ymin": Ymin = max(toclip[segment[0]][1], Ymin) if toclip[segment[0]][0] == "Ymax": Ymax = min(toclip[segment[0]][1], Ymax) segmentscursor.updateRow(segment) array = arcpy.Array([ arcpy.Point(Xmin, Ymin), arcpy.Point(Xmin, Ymax), arcpy.Point(Xmax, Ymax), arcpy.Point(Xmax, Ymin) ]) polygon = arcpy.Polygon(array) if segment[0] in lakes_bci: lakeid = lakes_bci[segment[0]] else: lakeid = -999 cursor.insertRow([segment[0], polygon, lakeid]) del cursor del segmentscursor arcpy.CreateFeatureclass_management( os.path.dirname(save_sourcepoints), os.path.basename(save_sourcepoints), "POINT", spatial_reference=flowdir.raster.spatialReference) arcpy.AddField_management(save_sourcepoints, "ZoneID", "LONG") arcpy.AddField_management(save_sourcepoints, "fpid", "LONG") pointcursor = arcpy.da.InsertCursor(save_sourcepoints, ["ZoneID", "fpid", "SHAPE@XY"]) for pointkey in inputpoints: pointcursor.insertRow([ pointkey, inputpoints[pointkey].frompointid, (inputpoints[pointkey].X, inputpoints[pointkey].Y) ]) del pointcursor return
def execute_orientedCS(r_flowdir, str_frompoints, str_ptscs, smoothingdistance, str_cs, messages, language="FR"): arcpy.env.outputCoordinateSystem = r_flowdir.spatialReference # Chargement des fichiers flowdir = RasterIO(r_flowdir) arcpy.env.extent = r_flowdir arcpy.env.snapRaster = r_flowdir randomname = binascii.hexlify(os.urandom(6)).decode() temp_cs2 = arcpy.env.scratchWorkspace + "\\" + str(randomname) arcpy.PointToRaster_conversion(str_ptscs, arcpy.Describe(str_ptscs).OIDFieldName, temp_cs2, cellsize=r_flowdir) temprastercs = RasterIO(arcpy.Raster(temp_cs2)) Result = RasterIO(r_flowdir, str_cs, float, -255) # Décompte du nombre de points de départ pour configurer de la barre de progression frompointcursor = arcpy.da.SearchCursor(str_frompoints, "OID@") count = 0 for frompoint in frompointcursor: count += 1 progtext = "Calcul de l'orientation des sections transversales" if language == "EN": progtext = "Processing" arcpy.SetProgressor("step", progtext, 0, count, 1) progres = 0 # Traitement effectué pour chaque point de départ frompointcursor = arcpy.da.SearchCursor(str_frompoints, "SHAPE@") for frompoint in frompointcursor: # Mise à jour de la barre de progression arcpy.SetProgressorPosition(progres) progres += 1 # On prend l'objet géométrique (le point) associé à la ligne dans la table frompointshape = frompoint[0].firstPoint # Conversion des coordonnées currentcol = flowdir.XtoCol(frompointshape.X) currentrow = flowdir.YtoRow(frompointshape.Y) # Tests de sécurité pour s'assurer que le point de départ est à l'intérieurs des rasters intheraster = True if currentcol < 0 or currentcol >= flowdir.raster.width or currentrow < 0 or currentrow >= flowdir.raster.height: intheraster = False elif (flowdir.getValue(currentrow, currentcol) != 1 and flowdir.getValue(currentrow, currentcol) != 2 and flowdir.getValue(currentrow, currentcol) != 4 and flowdir.getValue(currentrow, currentcol) != 8 and flowdir.getValue(currentrow, currentcol) != 16 and flowdir.getValue(currentrow, currentcol) != 32 and flowdir.getValue(currentrow, currentcol) != 64 and flowdir.getValue(currentrow, currentcol) != 128): intheraster = False totaldistance = 0 currentdistance = 0 confluencedist = 0 listpointsflowpath = [] afterconfluence = False # Traitement effectué sur chaque cellule le long de l'écoulement while (intheraster): # On stock différentes informations sur le point dans listpointsflowpath currentpoint = pointflowpath() currentpoint.row = currentrow currentpoint.col = currentcol currentpoint.X = flowdir.ColtoX(currentcol) currentpoint.Y = flowdir.RowtoY(currentrow) currentpoint.addeddistance = currentdistance totaldistance = totaldistance + currentdistance currentpoint.distance = totaldistance listpointsflowpath.append(currentpoint) # Les points traité sont mis à -999 (cela permet la détection des confluences) if not afterconfluence: Result.setValue(currentrow, currentcol, -999) # On cherche le prochain point à partir du flow direction direction = flowdir.getValue(currentrow, currentcol) if (direction == 1): currentcol = currentcol + 1 currentdistance = flowdir.raster.meanCellWidth if (direction == 2): currentcol = currentcol + 1 currentrow = currentrow + 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) if (direction == 4): currentrow = currentrow + 1 currentdistance = flowdir.raster.meanCellHeight if (direction == 8): currentcol = currentcol - 1 currentrow = currentrow + 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) if (direction == 16): currentcol = currentcol - 1 currentdistance = flowdir.raster.meanCellWidth if (direction == 32): currentcol = currentcol - 1 currentrow = currentrow - 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) if (direction == 64): currentrow = currentrow - 1 currentdistance = flowdir.raster.meanCellHeight if (direction == 128): currentcol = currentcol + 1 currentrow = currentrow - 1 currentdistance = math.sqrt(flowdir.raster.meanCellWidth * flowdir.raster.meanCellWidth + flowdir.raster.meanCellHeight * flowdir.raster.meanCellHeight) # Tests de sécurité pour s'assurer que l'on ne sorte pas des rasters if currentcol < 0 or currentcol >= flowdir.raster.width or currentrow < 0 or currentrow >= flowdir.raster.height: intheraster = False elif (flowdir.getValue(currentrow, currentcol) != 1 and flowdir.getValue(currentrow, currentcol) != 2 and flowdir.getValue(currentrow, currentcol) != 4 and flowdir.getValue(currentrow, currentcol) != 8 and flowdir.getValue(currentrow, currentcol) != 16 and flowdir.getValue(currentrow, currentcol) != 32 and flowdir.getValue(currentrow, currentcol) != 64 and flowdir.getValue(currentrow, currentcol) != 128): intheraster = False if intheraster: if (Result.getValue(currentrow, currentcol) != Result.nodata): # Atteinte d'un point déjà traité if confluencedist == 0: confluencedist = totaldistance + currentdistance afterconfluence = True # On continue encore sur la moitié de la distance de calcul de la pente après le confluent if (totaldistance + currentdistance - confluencedist) > smoothingdistance / 2: intheraster = False currentpointnumber = 0 # Traitement effectué sur la liste des points le long de l'écoulement while (currentpointnumber < len(listpointsflowpath)): currentpoint = listpointsflowpath[currentpointnumber] if temprastercs.getValue(currentpoint.row, currentpoint.col) != temprastercs.nodata: # Point pour lequel on doit calculer l'orientation de la section transversale listXforregression = [] listYforregression = [] listXforregression.append(currentpoint.X) listYforregression.append(currentpoint.Y) distancefromcurrentpoint = 0 nbcellsfromcurrentpoint = 0 try: # on ajoute dans listpointforregression les points situés avant le point courant, jusqu'à la distance souhaitée while (distancefromcurrentpoint <= smoothingdistance / 2): nbcellsfromcurrentpoint = nbcellsfromcurrentpoint - 1 if (currentpointnumber + nbcellsfromcurrentpoint > 0): distancefromcurrentpoint = distancefromcurrentpoint + listpointsflowpath[ currentpointnumber + nbcellsfromcurrentpoint].addeddistance listXforregression.append( listpointsflowpath[currentpointnumber + nbcellsfromcurrentpoint].X) listYforregression.append( listpointsflowpath[currentpointnumber + nbcellsfromcurrentpoint].Y) else: raise IndexError distancefromcurrentpoint = 0 nbcellsfromcurrentpoint = 0 # on ajoute également les points situé après le point courant, jusqu'à la distance souhaitée while (distancefromcurrentpoint < smoothingdistance / 2): nbcellsfromcurrentpoint = nbcellsfromcurrentpoint + 1 distancefromcurrentpoint = distancefromcurrentpoint + listpointsflowpath[ currentpointnumber + nbcellsfromcurrentpoint].addeddistance listXforregression.append( listpointsflowpath[currentpointnumber + nbcellsfromcurrentpoint].X) listYforregression.append( listpointsflowpath[currentpointnumber + nbcellsfromcurrentpoint].Y) # Variance et covariance prises avec 0 degrés de liberté varx = numpy.var(listXforregression) vary = numpy.var(listYforregression) covarxy = numpy.cov(listXforregression, listYforregression, bias=True)[0][1] slope = 0 if (covarxy != 0 and varx > 0 and vary > 0): # Formule pour la régression par axe majeur : Legendre et Legendre, 1998, Numerical Ecology, 2ème édition (p.507) slope = (vary - varx + math.sqrt( (vary - varx)**2 + 4 * covarxy**2)) / (2 * covarxy) angle = math.atan2(slope, 1) # angle perpendiculaire à l'écoulement: angle = angle + math.pi / 2 if (angle > math.pi): angle = angle - 2 * math.pi else: if varx == 0: angle = 0 elif vary == 0: angle = math.pi / 2 else: # la covariance est nulle # on compare l'évolution en x et en y entre le premier et le dernier point if (listXforregression[0] - listXforregression[-1] ) > (listYforregression[0] - listYforregression[-1]): angle = math.pi / 2 else: angle = 0 Result.setValue(currentpoint.row, currentpoint.col, angle) except IndexError: pass currentpointnumber = currentpointnumber + 1 Result.save() # On supprime les -999 du résultat final raster_res = arcpy.sa.SetNull(str_cs, str_cs, "VALUE = -999") raster_res.save(str_cs) # On supprime le fichier temporaire arcpy.Delete_management(temp_cs2) return
def execute_RiverWith(r_binary, r_flowdir, str_frompoints, r_cs, oriented, str_width, messages, language="FR"): # Chargement des fichiers binary = RasterIO(r_binary) flowdir = RasterIO(r_flowdir) cs = RasterIO(r_cs) try: flowdir.checkMatch(cs) except Exception as e: messages.addErrorMessage(e.message) Result = RasterIO(r_flowdir, str_width, float, -255) # Décompte du nombre de points de départ pour configurer de la barre de progression frompointcursor = arcpy.da.SearchCursor(str_frompoints, "OID@") count = 0 for frompoint in frompointcursor: count += 1 progtext = "Calcul de la largeur aux sections transversales" if language == "EN": progtext = "Processing" arcpy.SetProgressor("step", progtext, 0, count, 1) progres = 0 # Traitement effectué pour chaque point de départ frompointcursor = arcpy.da.SearchCursor(str_frompoints, "SHAPE@") for frompoint in frompointcursor: # Mise à jour de la barre de progression arcpy.SetProgressorPosition(progres) progres += 1 # On prend l'objet géométrique (le point) associé à la ligne dans la table frompointshape = frompoint[0].firstPoint # Conversion des coordonnées currentcol = flowdir.XtoCol(frompointshape.X) currentrow = flowdir.YtoRow(frompointshape.Y) intheraster = True # Tests de sécurité pour s'assurer que le point de départ est à l'intérieurs des rasters if currentcol < 0 or currentcol >= flowdir.raster.width or currentrow < 0 or currentrow >= flowdir.raster.height: intheraster = False elif (flowdir.getValue(currentrow, currentcol) != 1 and flowdir.getValue(currentrow, currentcol) != 2 and flowdir.getValue(currentrow, currentcol) != 4 and flowdir.getValue(currentrow, currentcol) != 8 and flowdir.getValue(currentrow, currentcol) != 16 and flowdir.getValue(currentrow, currentcol) != 32 and flowdir.getValue(currentrow, currentcol) != 64 and flowdir.getValue(currentrow, currentcol) != 128): intheraster = False # Traitement effectué sur chaque cellule le long de l'écoulement while (intheraster): # On se reprojète dans le système de coordonnées du raster binary colbinary = binary.XtoCol(flowdir.ColtoX(currentcol)) rowbinary = binary.YtoRow(flowdir.RowtoY(currentrow)) angle = cs.getValue(currentrow, currentcol) if angle != cs.nodata: if oriented: # calcul de la ligne et de la colonne du prochain point dans l'axe de la section transversale if (angle > math.pi / 4 and angle < 3 * math.pi / 4): rowinc = -1 colinc = math.cos(angle) else: colinc = 1 rowinc = -math.sin(angle) if angle > 3 * math.pi / 4: rowinc = -rowinc step = 0 while binary.getValue( rowbinary + int(rowinc * step), colbinary + int(colinc * step)) != binary.nodata: step += 1 # on répète les opérations précédentes en progressant dans l'autre sens le long de la section transversale step2 = 0 while binary.getValue( rowbinary - int(rowinc * step2), colbinary - int(colinc * step2)) != binary.nodata: step2 += 1 # if the process was not interrupted because an edge was reached if (rowbinary + int(rowinc * step)) >= 0 and ( colbinary + int(colinc * step) ) >= 0 and (rowbinary - int(rowinc * step2)) >= 0 and ( colbinary - int(colinc * step2) ) and (rowbinary + int(rowinc * step) ) < binary.raster.height and (colbinary + int( colinc * step)) < binary.raster.width and ( rowbinary - int(rowinc * step2) ) < binary.raster.height and (colbinary - int( colinc * step2)) < binary.raster.width: basedist = math.sqrt( (rowinc * binary.raster.meanCellHeight)**2 + (colinc * binary.raster.meanCellWidth)**2) width = basedist * (step + step2) Result.setValue(currentrow, currentcol, width) else: # on teste la largeur sur une étoile à 16 branches et on prend le minimum minwidth = None for star_i in range(1, 9): step = 0 step2 = 0 if star_i == 1: rowinc = 0 colinc = 1 if star_i == 2: rowinc = step % 2 colinc = 1 if star_i == 3: rowinc = 1 colinc = 1 if star_i == 4: rowinc = 1 colinc = step % 2 if star_i == 5: rowinc = 1 colinc = 0 if star_i == 6: rowinc = 1 colinc = -step % 2 if star_i == 7: rowinc = 1 colinc = -1 if star_i == 8: rowinc = step % 2 colinc = -1 while binary.getValue( rowbinary + int(rowinc * step), colbinary + int(colinc * step)) != binary.nodata: step += 1 while binary.getValue( rowbinary - int(rowinc * step2), colbinary - int(colinc * step2)) != binary.nodata: step2 += 1 width = None # if the process was not interrupted because an edge was reached if (rowbinary + int(rowinc * step)) >= 0 and ( colbinary + int(colinc * step) ) >= 0 and (rowbinary - int(rowinc * step2)) >= 0 and ( colbinary - int(colinc * step2) ) and (rowbinary + int(rowinc * step)) < binary.raster.height and ( colbinary + int(colinc * step) ) < binary.raster.width and ( rowbinary - int(rowinc * step2) ) < binary.raster.height and (colbinary - int( colinc * step2)) < binary.raster.width: basedist = math.sqrt( (rowinc * binary.raster.meanCellHeight)**2 + (colinc * binary.raster.meanCellWidth)**2) width = basedist * (step + step2) if minwidth is not None: if width is not None: minwidth = min(minwidth, width) else: minwidth = width if minwidth is not None: Result.setValue(currentrow, currentcol, minwidth) # On cherche le prochain point à partir du flow direction direction = flowdir.getValue(currentrow, currentcol) if (direction == 1): currentcol = currentcol + 1 if (direction == 2): currentcol = currentcol + 1 currentrow = currentrow + 1 if (direction == 4): currentrow = currentrow + 1 if (direction == 8): currentcol = currentcol - 1 currentrow = currentrow + 1 if (direction == 16): currentcol = currentcol - 1 if (direction == 32): currentcol = currentcol - 1 currentrow = currentrow - 1 if (direction == 64): currentrow = currentrow - 1 if (direction == 128): currentcol = currentcol + 1 currentrow = currentrow - 1 # Tests de sécurité pour s'assurer que l'on ne sorte pas des rasters if currentcol < 0 or currentcol >= flowdir.raster.width or currentrow < 0 or currentrow >= flowdir.raster.height: intheraster = False elif (flowdir.getValue(currentrow, currentcol) != 1 and flowdir.getValue(currentrow, currentcol) != 2 and flowdir.getValue(currentrow, currentcol) != 4 and flowdir.getValue(currentrow, currentcol) != 8 and flowdir.getValue(currentrow, currentcol) != 16 and flowdir.getValue(currentrow, currentcol) != 32 and flowdir.getValue(currentrow, currentcol) != 64 and flowdir.getValue(currentrow, currentcol) != 128): intheraster = False if intheraster: if (Result.getValue(currentrow, currentcol) != -255): # Atteinte d'un confluent intheraster = False Result.save() return
def execute_DefBCI(r_flowdir, r_flowacc, distoutput, percent, str_zonesfolder, r_dem, r_width, r_zbed, r_manning, r_mask, str_outputfolder, messages): save_inbci = str_zonesfolder + "\\inbci.shp" save_outbci = str_zonesfolder + "\\outbci.shp" # Chargement des fichiers flowdir = RasterIO(r_flowdir) flowacc = RasterIO(r_flowacc) dem = RasterIO(r_dem) try: flowdir.checkMatch(flowacc) flowdir.checkMatch(dem) except Exception as e: messages.addErrorMessage(e.message) # Création d'un nouveau fichier de zones en prenant les enveloppes zones = str_zonesfolder + "\\envelopezones.shp" arcpy.FeatureEnvelopeToPolygon_management( str_zonesfolder + "\\polyzones.shp", zones) # Clip du DEM zonesscursor = arcpy.da.SearchCursor(zones, ["GRID_CODE", "SHAPE@"]) for zoneshp in zonesscursor: Xmin = zoneshp[1].extent.XMin Ymin = zoneshp[1].extent.YMin Xmax = zoneshp[1].extent.XMax Ymax = zoneshp[1].extent.YMax envelope = str(Xmin) + " " + str(Ymin) + " " + str(Xmax) + " " + str( Ymax) arcpy.Clip_management(dem.raster, envelope, str_zonesfolder + "\\zone" + str(zoneshp[0])) # Listes des points source et des points de sortie listinputpoints = [] listoutputpoints = [] # Lectures des points source pour chaque zone sourcepointcursor = arcpy.da.SearchCursor( str_zonesfolder + "\\sourcepoints.shp", ["SHAPE@", "ZoneID", "fpid"]) for sourcepoint in sourcepointcursor: newpoint = pointflowpath() newpoint.type = "main" newpoint.frompointid = sourcepoint[2] # Coordonnées du point source newpoint.X = sourcepoint[0].firstPoint.X newpoint.Y = sourcepoint[0].firstPoint.Y # Raster de la zone newpoint.numzone = sourcepoint[1] # Valeur du flow accumulation col = flowacc.XtoCol(newpoint.X) row = flowacc.YtoRow(newpoint.Y) newpoint.flowacc = flowacc.getValue(row, col) listinputpoints.append(newpoint) ### Début de traitement pour la détection des points de sortie et des points sources latéraux ### listlateralinputpoints = [] # Pour chaque raster, on parcourt l'écoulement à partir du point source for mainpoint in listinputpoints: # Raster de la zone correspondante au point source localraster = RasterIO( arcpy.Raster(str_zonesfolder + r"\zone" + str(mainpoint.numzone))) # Conversion des coordonnées currentcol = flowdir.XtoCol(mainpoint.X) currentrow = flowdir.YtoRow(mainpoint.Y) localcol = localraster.XtoCol(mainpoint.X) localrow = localraster.YtoRow(mainpoint.Y) currentflowacc = flowacc.getValue(currentrow, currentcol) mainpoint.flowacc = currentflowacc lastflowacc = currentflowacc # Parcours de l'écoulement intheraster = True while (intheraster): prevcol = currentcol prevrow = currentrow currentflowacc = flowacc.getValue(currentrow, currentcol) if 100. * float(currentflowacc - lastflowacc) / float(lastflowacc) >= percent: newpoint = pointflowpath() newpoint.type = "lateral" newpoint.frompointid = mainpoint.frompointid # Coordonnées du point source newpoint.X = flowdir.ColtoX(currentcol) newpoint.Y = flowdir.RowtoY(currentrow) # Raster de la zone newpoint.numzone = mainpoint.numzone # Valeur du flow accumulation newpoint.flowacc = currentflowacc lastflowacc = currentflowacc listlateralinputpoints.append(newpoint) # On cherche le prochain point à partir du flow direction direction = flowdir.getValue(currentrow, currentcol) if (direction == 1): currentcol = currentcol + 1 localcol += 1 if (direction == 2): currentcol = currentcol + 1 currentrow = currentrow + 1 localcol += 1 localrow += 1 if (direction == 4): currentrow = currentrow + 1 localrow += 1 if (direction == 8): currentcol = currentcol - 1 currentrow = currentrow + 1 localcol -= 1 localrow += 1 if (direction == 16): currentcol = currentcol - 1 localcol -= 1 if (direction == 32): currentcol = currentcol - 1 currentrow = currentrow - 1 localcol -= 1 localrow -= 1 if (direction == 64): currentrow = currentrow - 1 localrow -= 1 if (direction == 128): currentcol = currentcol + 1 currentrow = currentrow - 1 localcol += 1 localrow -= 1 if currentcol < 0 or currentcol >= flowdir.raster.width or currentrow < 0 or currentrow >= flowdir.raster.height: intheraster = False elif (flowdir.getValue(currentrow, currentcol) != 1 and flowdir.getValue(currentrow, currentcol) != 2 and flowdir.getValue(currentrow, currentcol) != 4 and flowdir.getValue(currentrow, currentcol) != 8 and flowdir.getValue(currentrow, currentcol) != 16 and flowdir.getValue(currentrow, currentcol) != 32 and flowdir.getValue(currentrow, currentcol) != 64 and flowdir.getValue(currentrow, currentcol) != 128): intheraster = False if localcol < 0 or localcol >= localraster.raster.width or localrow < 0 or localrow >= localraster.raster.height: intheraster = False elif localraster.getValue(localrow, localcol) == localraster.nodata: intheraster = False # On enregistre un point de sortie au dernier point traité avant de sortir de la zone newpoint = pointflowpath() newpoint.numzone = mainpoint.numzone newpoint.X = flowdir.ColtoX(prevcol) newpoint.Y = flowdir.RowtoY(prevrow) # Il est nécessaire d'enregistrer le côté du raster par lequel on sort. # Ceci est fait en regardant la distance entre le dernier point traité et les coordonnées maximales de la zone # Le côté de sortie est le côté pour lequel cette distance est minimum distside = min(newpoint.X - localraster.raster.extent.XMin, localraster.raster.extent.XMax - newpoint.X, newpoint.Y - localraster.raster.extent.YMin, localraster.raster.extent.YMax - newpoint.Y) if distside == newpoint.X - localraster.raster.extent.XMin: newpoint.side = "W" if distside == localraster.raster.extent.XMax - newpoint.X: newpoint.side = "E" if distside == newpoint.Y - localraster.raster.extent.YMin: newpoint.side = "S" if distside == localraster.raster.extent.YMax - newpoint.Y: newpoint.side = "N" listoutputpoints.append(newpoint) listinputpoints.extend(listlateralinputpoints) ### Fin de traitement pour la détection des points de sortie et des points sources latéraux ### ### Début de traitement pour la configuration des fenêtres de sortie ### # Pour chaque point de sortie for point in listoutputpoints: raster = RasterIO( arcpy.Raster(str_zonesfolder + r"\zone" + str(point.numzone))) colinc = 0 rowinc = 0 distinc = 0 point.side2 = "0" point.lim3 = 0 point.lim4 = 0 # Selon le coté de sortie, on progressera horizontalement ou verticalement if point.side == "W" or point.side == "E": rowinc = 1 distinc = raster.raster.meanCellHeight else: colinc = 1 distinc = raster.raster.meanCellWidth currentcol = raster.XtoCol(point.X) currentrow = raster.YtoRow(point.Y) distance = 0 # On progresse sur dans une direction jusqu'à sortir du raster ou jusqu'à ce que la distance voullue soit attente while (not (currentcol < 0 or currentcol >= raster.raster.width or currentrow < 0 or currentrow >= raster.raster.height)) \ and raster.getValue(currentrow,currentcol) != raster.nodata and distance < distoutput/2: distance += distinc currentrow += rowinc currentcol += colinc # On prends les coordonnées avant de sortir du raster currentrow -= rowinc currentcol -= colinc if point.side == "W" or point.side == "E": point.lim1 = raster.RowtoY(currentrow) else: point.lim1 = raster.ColtoX(currentcol) # Si la procédure s'est arrêtée parce qu'on est sorti du raster, on tourne de 90 degrés et on continue if distance < distoutput / 2: distance -= distinc if point.side == "W": colinc = 1 rowinc = 0 distinc = raster.raster.meanCellWidth point.lim3 = raster.raster.extent.XMin + ( currentcol + 0.5) * raster.raster.meanCellWidth elif point.side == "E": colinc = -1 rowinc = 0 distinc = raster.raster.meanCellWidth point.lim3 = raster.raster.extent.XMin + ( currentcol + 0.5) * raster.raster.meanCellWidth elif point.side == "N": rowinc = 1 colinc = 0 distinc = raster.raster.meanCellHeight point.lim3 = max( raster.raster.extent.YMin, raster.raster.extent.YMax - (currentrow + 1) * raster.raster.meanCellHeight ) + 0.5 * raster.raster.meanCellHeight elif point.side == "S": rowinc = -1 colinc = 0 distinc = raster.raster.meanCellHeight point.lim3 = max( raster.raster.extent.YMin, raster.raster.extent.YMax - (currentrow + 1) * raster.raster.meanCellHeight ) + 0.5 * raster.raster.meanCellHeight # On progresse à nouveau jusqu'à sortir du raster ou jusqu'à ce que la distance voullue soit attente while (not (currentcol < 0 or currentcol >= raster.raster.width or currentrow < 0 or currentrow >= raster.raster.height)) \ and raster.getValue(currentrow, currentcol) != raster.nodata and distance < distoutput / 2: distance += distinc currentrow += rowinc currentcol += colinc currentrow -= rowinc currentcol -= colinc # On cherche sur quel coté on est après avoir tourné de 90 degrés if point.side == "W" or point.side == "E": point.side2 = "S" point.lim4 = raster.raster.extent.XMin + ( currentcol + 0.5) * raster.raster.meanCellWidth else: point.side2 = "E" point.lim4 = max( raster.raster.extent.YMin, raster.raster.extent.YMax - (currentrow + 1) * raster.raster.meanCellHeight ) + 0.5 * raster.raster.meanCellHeight # On recommence toute la procédure de l'autre côté du point de sortie colinc = 0 rowinc = 0 distinc = 0 if point.side == "W" or point.side == "E": rowinc = -1 distinc = raster.raster.meanCellHeight else: colinc = -1 distinc = raster.raster.meanCellWidth currentcol = raster.XtoCol(point.X) currentrow = raster.YtoRow(point.Y) distance = 0 while (not (currentcol < 0 or currentcol >= raster.raster.width or currentrow < 0 or currentrow >= raster.raster.height)) \ and raster.getValue(currentrow, currentcol) != raster.nodata and distance < distoutput / 2: distance += distinc currentrow += rowinc currentcol += colinc currentrow -= rowinc currentcol -= colinc if point.side == "W" or point.side == "E": point.lim2 = max( raster.raster.extent.YMin, raster.raster.extent.YMax - (currentrow + 1) * raster.raster.meanCellHeight ) + 0.5 * raster.raster.meanCellHeight else: point.lim2 = raster.raster.extent.XMin + ( currentcol + 0.5) * raster.raster.meanCellWidth # Si la procédure s'est arrêtée parce qu'on est sorti du raster, on tourne de 90 degrés et on continue if distance < distoutput / 2: distance -= distinc if point.side == "W": colinc = 1 rowinc = 0 distinc = raster.raster.meanCellWidth point.lim3 = raster.raster.extent.XMin + ( currentcol + 0.5) * raster.raster.meanCellWidth elif point.side == "E": colinc = -1 rowinc = 0 distinc = raster.raster.meanCellWidth point.lim3 = raster.raster.extent.XMin + ( currentcol + 0.5) * raster.raster.meanCellWidth elif point.side == "N": rowinc = 1 colinc = 0 distinc = raster.raster.meanCellHeight point.lim3 = max( raster.raster.extent.YMin, raster.raster.extent.YMax - (currentrow + 1) * raster.raster.meanCellHeight ) + 0.5 * raster.raster.meanCellHeight elif point.side == "S": rowinc = -1 colinc = 0 distinc = raster.raster.meanCellHeight point.lim3 = max( raster.raster.extent.YMin, raster.raster.extent.YMax - (currentrow + 1) * raster.raster.meanCellHeight ) + 0.5 * raster.raster.meanCellHeight while (not (currentcol < 0 or currentcol >= raster.raster.width or currentrow < 0 or currentrow >= raster.raster.height)) \ and raster.getValue(currentrow, currentcol) != raster.nodata and distance < distoutput / 2: distance += distinc currentrow += rowinc currentcol += colinc currentrow -= rowinc currentcol -= colinc if point.side == "W" or point.side == "E": point.side2 = "N" point.lim4 = raster.raster.extent.XMin + ( currentcol + 0.5) * raster.raster.meanCellWidth else: point.side2 = "W" point.lim4 = max( raster.raster.extent.YMin, raster.raster.extent.YMax - (currentrow + 1) * raster.raster.meanCellHeight ) + 0.5 * raster.raster.meanCellHeight ### Fin du traitement pour la configuration des fenêtres de sortie ### # Création des shapefiles inbci et outbci, avec les champs nécessaires arcpy.CreateFeatureclass_management( os.path.dirname(save_inbci), os.path.basename(save_inbci), "POINT", spatial_reference=flowdir.raster.spatialReference) arcpy.AddField_management(save_inbci, "zoneid", "LONG") arcpy.AddField_management(save_inbci, "flowacc", "LONG") arcpy.AddField_management(save_inbci, "type", "TEXT") arcpy.AddField_management(save_inbci, "fpid", "LONG") arcpy.CreateFeatureclass_management( os.path.dirname(save_outbci), os.path.basename(save_outbci), "POINT", spatial_reference=flowdir.raster.spatialReference) arcpy.AddField_management(save_outbci, "zoneid", "LONG") arcpy.AddField_management(save_outbci, "side", "TEXT", field_length=1) arcpy.AddField_management(save_outbci, "lim1", "LONG") arcpy.AddField_management(save_outbci, "lim2", "LONG") arcpy.AddField_management( save_outbci, "side2", "TEXT", field_length=1, ) arcpy.AddField_management(save_outbci, "lim3", "LONG") arcpy.AddField_management(save_outbci, "lim4", "LONG") # Enregistrement dans les shapefiles des informations contenues dans les listes pointcursor = arcpy.da.InsertCursor( save_inbci, ["zoneid", "flowacc", "type", "fpid", "SHAPE@XY"]) for point in listinputpoints: pointcursor.insertRow([ point.numzone, point.flowacc, point.type, point.frompointid, (point.X, point.Y) ]) pointcursor = arcpy.da.InsertCursor(save_outbci, [ "zoneid", "side", "lim1", "lim2", "side2", "lim3", "lim4", "SHAPE@XY" ]) for point in listoutputpoints: pointcursor.insertRow([ point.numzone, point.side, point.lim1, point.lim2, point.side2, point.lim3, point.lim4, (point.X, point.Y) ]) del pointcursor # Création des fichiers .bci à partir des information du fichier inbci.shp bcipointcursor = arcpy.da.SearchCursor( save_inbci, ["SHAPE@", "zoneid", "flowacc", "type"]) dictsegmentsin = {} for point in bcipointcursor: if point[1] not in dictsegmentsin: dictsegmentsin[point[1]] = [] dictsegmentsin[point[1]].append(point) for segment in dictsegmentsin.values(): for point in sorted(segment, key=lambda q: q[2]): if point[3] == "main": latnum = 0 pointshape = point[0].firstPoint # Création du fichier newfile = str_outputfolder + "\\zone" + str(point[1]) + ".bci" # Enregistrement des coordonnées pour le point source filebci = open(newfile, 'w') filebci.write("P\t" + str(int(pointshape.X)) + "\t" + str(int(pointshape.Y)) + "\tQVAR\tzone" + str(point[1]) + "\n") filebci.close() if point[3] == "lateral": pointshape = point[0].firstPoint latnum += 1 newfile = str_outputfolder + "\\zone" + str(point[1]) + ".bci" # Enregistrement des coordonnées et du débit pour le point source filebci = open(newfile, 'a') filebci.write("P\t" + str(int(pointshape.X)) + "\t" + str(int(pointshape.Y)) + "\tQVAR\tzone" + str(point[1]) + "_" + str(latnum) + "\n") filebci.close() # Ajout de la zone de sortie au .bci bcipointcursor = arcpy.da.SearchCursor( save_outbci, ["zoneid", "side", "lim1", "lim2", "side2", "lim3", "lim4", "SHAPE@"]) for point in bcipointcursor: newfile = str_outputfolder + "\\zone" + str(point[0]) + ".bci" filebci = open(newfile, 'a') filebci.write(point[1] + "\t" + str(point[2]) + "\t" + str(point[3]) + "\tHVAR\thvar") if str(point[4]) != "0": filebci.write("\n" + str(point[4]) + "\t" + str(point[5]) + "\t" + str(point[6]) + "\tHVAR\thvar") filebci.close() # Création des fichiers .par et conversion des rasters en fichiers ASCII (un par point source comme il n'y a qu'un seul point d'entrée par simulation) for segment in dictsegmentsin.values(): for point in sorted(segment, key=lambda q: q[2]): if point[3] == "main": arcpy.Clip_management( r_width, "#", str_zonesfolder + r"\wzone" + str(point[1]), str_zonesfolder + "\\zone" + str(point[1]), "#", "NONE", "MAINTAIN_EXTENT") arcpy.Clip_management( r_zbed, "#", str_zonesfolder + r"\dzone" + str(point[1]), str_zonesfolder + "\\zone" + str(point[1]), "#", "NONE", "MAINTAIN_EXTENT") arcpy.Clip_management( r_manning, "#", str_zonesfolder + r"\nzone" + str(point[1]), str_zonesfolder + "\\zone" + str(point[1]), "#", "NONE", "MAINTAIN_EXTENT") arcpy.RasterToASCII_conversion( str_zonesfolder + "\\zone" + str(point[1]), str_outputfolder + "\\zone" + str(point[1]) + ".txt") arcpy.RasterToASCII_conversion( str_zonesfolder + "\dzone" + str(point[1]), str_outputfolder + "\\dzone" + str(point[1]) + ".txt") arcpy.RasterToASCII_conversion( str_zonesfolder + "\wzone" + str(point[1]), str_outputfolder + "\\wzone" + str(point[1]) + ".txt") arcpy.RasterToASCII_conversion( str_zonesfolder + "\\nzone" + str(point[1]), str_outputfolder + "\\nzone" + str(point[1]) + ".txt") arcpy.Delete_management(str_zonesfolder + r"\wzone" + str(point[1])) arcpy.Delete_management(str_zonesfolder + r"\dzone" + str(point[1])) arcpy.Delete_management(str_zonesfolder + r"\nzone" + str(point[1])) arcpy.Clip_management( r_mask, "#", str_zonesfolder + r"\mzone" + str(point[1]), str_zonesfolder + "\\zone" + str(point[1]), "#", "NONE", "MAINTAIN_EXTENT") arcpy.RasterToASCII_conversion( str_zonesfolder + "\mzone" + str(point[1]), str_outputfolder + "\\mzone" + str(point[1]) + ".txt") arcpy.Delete_management(str_zonesfolder + r"\mzone" + str(point[1])) return