W tym przypadku istnieją trzy problemy:
- Otwory
- Linie między wielokątami
- Linie końcowe
Otwory
Ponieważ dowolna linia w otworze zostanie zachowana, usuń otwory z wielokątów. W poniższym skrypcie robię to za pomocą kursorów i geometrii.
Linie między wielokątami
Linie dotykające dwóch wielokątów muszą zostać usunięte. W poniższym skrypcie robię to, wykonując sprzężenie przestrzenne one to many
z moimi liniami jako moją klasą elementów wejściowych, a wielokątami jako moją klasą elementów złączonych. Każda linia, która zostanie wygenerowana dwukrotnie, dotyka dwóch wielokątów i jest usuwana.
Linie końcowe
Aby usunąć linie dotykające tylko wielokąta na jednym końcu, przekształcam linie w punkty końcowe. Następnie używam warstw obiektów i selekcji, aby ustalić, które punkty końcowe są zmiennoprzecinkowe. Wybieram punkty końcowe, które przecinają wielokąty. Następnie zmieniam wybór. To wybiera punkty końcowe, które nie przecinają wielokątów. Zaznaczam dowolną linię, która przecina te wybrane punkty i usuwam je.
Wynik
Założenia
- Dane wejściowe to klasy obiektów geobazy danych
- Dostępna jest zaawansowana licencja ArcGIS (ze względu na
erase
i feature vertices to points
)
- Ciągłe, połączone linie są pojedynczą funkcją
- Wieloboki nie nakładają się
- Nie ma wieloczęściowych wielokątów
Scenariusz
Poniższy skrypt generuje klasę obiektów o nazwie twojej klasy obiektów liniowych plus _GreedyClip
, w tej samej geobazie, co twoja klasa obiektów liniowych. Potrzebna jest również lokalizacja obszaru roboczego.
#input polygon feature class
polyFc = r"C:\Users\e1b8\Desktop\E1B8\Workspace\Workspace.gdb\testPolygon2"
#input line feature class
lineFc = r"C:\Users\e1b8\Desktop\E1B8\Workspace\Workspace.gdb\testLine"
#workspace
workspace = r"in_memory"
print "importing"
import arcpy
import os
#generate a unique ArcGIS file name
def UniqueFileName(location = "in_memory", name = "file", extension = ""):
if extension:
outName = os.path.join (location, name + "." + extension)
else:
outName = os.path.join (location, name)
i = 0
while arcpy.Exists (outName):
i += 1
if extension:
outName = os.path.join (location, "{0}_{1}.{2}".format (name, i, extension))
else:
outName = os.path.join (location, "{0}_{1}".format (name, i))
return outName
#remove holes from polygons
def RemoveHoles (inFc, workspace):
outFc = UniqueFileName (workspace)
array = arcpy.Array ()
sr = arcpy.Describe (inFc).spatialReference
outPath, outName = os.path.split (outFc)
arcpy.CreateFeatureclass_management (outPath, outName, "POLYGON", spatial_reference = sr)
with arcpy.da.InsertCursor (outFc, "SHAPE@") as iCurs:
with arcpy.da.SearchCursor (inFc, "SHAPE@") as sCurs:
for geom, in sCurs:
try:
part = geom.getPart (0)
except:
continue
for pnt in part:
if not pnt:
break
array.add (pnt)
polygon = arcpy.Polygon (array)
array.removeAll ()
row = (polygon,)
iCurs.insertRow (row)
del iCurs
del sCurs
return outFc
#split line fc by polygon fc
def SplitLinesByPolygon (lineFc, polygonFc, workspace):
#clip
clipFc = UniqueFileName(workspace)
arcpy.Clip_analysis (lineFc, polygonFc, clipFc)
#erase
eraseFc = UniqueFileName(workspace)
arcpy.Erase_analysis (lineFc, polygonFc, eraseFc)
#merge
mergeFc = UniqueFileName(workspace)
arcpy.Merge_management ([clipFc, eraseFc], mergeFc)
#multipart to singlepart
outFc = UniqueFileName(workspace)
arcpy.MultipartToSinglepart_management (mergeFc, outFc)
#delete intermediate data
for trash in [clipFc, eraseFc, mergeFc]:
arcpy.Delete_management (trash)
return outFc
#remove lines between two polygons and end lines
def RemoveLines (inFc, polygonFc, workspace):
#check if "TARGET_FID" is in fields
flds = [f.name for f in arcpy.ListFields (inFc)]
if "TARGET_FID" in flds:
#delete "TARGET_FID" field
arcpy.DeleteField_management (inFc, "TARGET_FID")
#spatial join
sjFc = UniqueFileName(workspace)
arcpy.SpatialJoin_analysis (inFc, polygonFc, sjFc, "JOIN_ONE_TO_MANY")
#list of TARGET_FIDs
targetFids = [fid for fid, in arcpy.da.SearchCursor (sjFc, "TARGET_FID")]
#target FIDs with multiple occurances
deleteFids = [dFid for dFid in targetFids if targetFids.count (dFid) > 1]
if deleteFids:
#delete rows with update cursor
with arcpy.da.UpdateCursor (inFc, "OID@") as cursor:
for oid, in cursor:
if oid in deleteFids:
cursor.deleteRow ()
del cursor
#feature vertices to points
vertFc = UniqueFileName(workspace)
arcpy.FeatureVerticesToPoints_management (inFc, vertFc, "BOTH_ENDS")
#select points intersecting polygons
arcpy.MakeFeatureLayer_management (vertFc, "vertLyr")
arcpy.SelectLayerByLocation_management ("vertLyr", "", polygonFc, "1 FEET")
#switch selection
arcpy.SelectLayerByAttribute_management ("vertLyr", "SWITCH_SELECTION")
arcpy.MakeFeatureLayer_management (inFc, "lineLyr")
#check for selection
if arcpy.Describe ("vertLyr").FIDSet:
#select lines by selected points
arcpy.SelectLayerByLocation_management ("lineLyr", "", "vertLyr", "1 FEET")
#double check selection (should always have selection)
if arcpy.Describe ("lineLyr").FIDSet:
#delete selected rows
arcpy.DeleteFeatures_management ("lineLyr")
#delete intermediate data
for trash in [sjFc, "vertLyr", "lineLyr"]:
arcpy.Delete_management (trash)
#main script
def main (polyFc, lineFc, workspace):
#remove holes
print "removing holes"
holelessPolyFc = RemoveHoles (polyFc, workspace)
#split line at polygons
print "splitting lines at polygons"
splitFc = SplitLinesByPolygon (lineFc, holelessPolyFc, workspace)
#delete unwanted lines
print "removing unwanted lines"
RemoveLines (splitFc, polyFc, workspace)
#create output feature class
outFc = lineFc + "_GreedyClip"
outFcPath, outFcName = os.path.split (outFc)
outFc = UniqueFileName (outFcPath, outFcName)
arcpy.CopyFeatures_management (splitFc, outFc)
print "created:"
print outFc
print
print "cleaning up"
#delete intermediate data
for trash in [holelessPolyFc, splitFc]:
arcpy.Delete_management (trash)
print "done"
if __name__ == "__main__":
main (polyFc, lineFc, workspace)