Memperluas garis dengan jarak yang ditentukan di ArcGIS untuk Desktop?

11

Saya memiliki lapisan estetika murni yang memiliki simbol panah. Beberapa tidak muncul dengan benar karena garis terlalu kecil. Saya telah memilih mungkin 50 catatan di mana saya perlu memperpanjang garis ini dengan angka yang diberikan (mis. 2 meter). Memperluas alat baris hanya memperluas garis ke persimpangan yang ditentukan, jadi alat ini bukan yang saya cari.

Saya sudah mencoba mengedit bidang panjang bentuk tetapi tidak membiarkan saya. Apakah ada cara sederhana untuk melakukan ini melalui kalkulator lapangan atau dalam bilah alat editor?

GISKid
sumber
1
apakah data dalam bentuk, gdb, fgdb? apakah Anda memiliki dasar, standar, lanjutan?
Brad Nesom
Bentuk dan tingkat lanjut.
GISKid
Bisakah saya mengklarifikasi, apakah Anda ingin memperluas setiap fitur dalam bentuk tipe polyline, atau hanya fitur yang dipilih?
Jika Anda ingin mendasarkan ekstensi Anda pada titik akhir, Anda bisa pergi ke titik sebelumnya dan menentukan kemiringan di antara kedua titik ini. Kemudian Anda dapat memindahkan titik akhir titik jarak Anda x berdasarkan pada kata slope.
Paul
@ Paul, saya sedang menulis skrip untuk melakukan hal itu, tetapi ini sedikit lebih rumit karena Anda perlu memperhitungkan multi-bagian polyline. Artinya, Anda perlu melihat titik awal dan akhir dan titik tetangga mereka untuk setiap bagian. Saya perlu tahu bahwa GISKid tertarik untuk memperluas semua fitur terlebih dahulu.

Jawaban:

12

Yah saya pikir saya sudah mendapatkannya untuk garis hitungan vertex. Saya belum pernah mencoba baris multi-bagian karena saya tidak pernah mengacaukannya di arcpy. Pengkodean dibuat sedikit lebih sulit karena tidak ada akses tulis ke properti lastPoint untuk objek Geometri. Alih-alih menggunakan kemiringan (yang merupakan pemikiran awal saya), saya menggunakan kode dari pertanyaan SO ini . Itu tidak bergantung pada trigonometri, jadi itu harus sedikit lebih efisien. Kode berikut ini berfungsi dengan memindahkan titik akhir dari sebuah garis ke koordinat baru yang terletak di sepanjang perpanjangan garis dari dua simpul terakhir. Saya mengujinya pada sebuah shapefile.

from math import hypot
import collections
from operator import add
import arcpy

layer = arcpy.GetParameterAsText(0)
distance = float(arcpy.GetParameterAsText(1))

#Computes new coordinates x3,y3 at a specified distance
#along the prolongation of the line from x1,y1 to x2,y2
def newcoord(coords, dist):
    (x1,y1),(x2,y2) = coords
    dx = x2 - x1
    dy = y2 - y1
    linelen = hypot(dx, dy)

    x3 = x2 + dx/linelen * dist
    y3 = y2 + dy/linelen * dist    
    return x3, y3

#accumulate([1,2,3,4,5]) --> 1 3 6 10 15
#Equivalent to itertools.accumulate() which isn't present in Python 2.7
def accumulate(iterable):    
    it = iter(iterable)
    total = next(it)
    yield total
    for element in it:
        total = add(total, element)
        yield total

#OID is needed to determine how to break up flat list of data by feature.
coordinates = [[row[0], row[1]] for row in
               arcpy.da.SearchCursor(layer, ["OID@", "SHAPE@XY"], explode_to_points=True)]

oid,vert = zip(*coordinates)

#Construct list of numbers that mark the start of a new feature class.
#This is created by counting OIDS and then accumulating the values.
vertcounts = list(accumulate(collections.Counter(oid).values()))

#Grab the last two vertices of each feature
lastpoint = [point for x,point in enumerate(vert) if x+1 in vertcounts or x+2 in vertcounts]

#Convert flat list of tuples to list of lists of tuples.
#Obtain list of tuples of new end coordinates.
newvert = [newcoord(y, distance) for y in zip(*[iter(lastpoint)]*2)]    

j = 0
with arcpy.da.UpdateCursor(layer, "SHAPE@XY", explode_to_points=True) as rows:
    for i,row in enumerate(rows):
        if i+1 in vertcounts:            
            row[0] = newvert[j]
            j+=1
            rows.updateRow(row)

Saya mengatur simbologi ke panah di akhir untuk kategori berdasarkan OID sehingga akan lebih mudah untuk melihat pemisahan antara fitur. Pelabelan diatur untuk menghitung simpul.masukkan deskripsi gambar di sini

Paul
sumber
Ini hanya banyak membantu saya! Namun, ini akan lebih membantu dalam situasi khusus saya jika parameter jarak dapat didasarkan pada bidang dalam fitur garis asli. Saya telah mencoba mengimplementasikan ini sendiri dan tahu bahwa saya entah bagaimana harus beralih melalui jarak di baris "newvert =" tapi saya kesulitan mengimplementasikannya. Jika Anda dapat memperluas kode Anda untuk melakukan ini, saya akan sangat berterima kasih!
GeoJohn
Jangan lupa untuk memperbarui tampilan Anda, jika Anda menjalankan skrip dari dalam konsol Python. Baris saya menjadi sangat panjang setelah beberapa kali mencoba "gagal".
EikeMike
2

Bagaimana jika Anda memilih garis yang ingin Anda perpanjang.
Buffer baris tersebut dengan jumlah ekstensi yang diinginkan.
Ubah itu menjadi garis fc.
Kemudian meluas ke persimpangan.
Anda mungkin harus mematahkan dan menghapus ujung buffer lainnya agar tidak tumpang tindih garis di tengah. (Saya belum melihat tangkapan layar dari apa yang Anda miliki atau ingin lakukan)
Atau saya pikir ada alat di ettools (saya memeriksa untuk melihat fungsionalitas dan jika gratis)
Tidak menemukan sesuatu yang berguna dalam alat et yang saya lakukan temukan utas ini untuk beberapa kode vb (lama). dan permintaan untuk beberapa python. Anda dapat mengikutinya dan memeriksa situs web ideas.arcgis.com .

Brad Nesom
sumber
2

Berikut adalah metode yang bekerja dengan multi-bagian polyline yang terdiri dari sejumlah titik node. Ia menggunakan open source GIS Whitebox GAT ( http://www.uoguelph.ca/~hydrogeo/Whitebox/ ). Cukup unduh Whitebox, buka Scripter (ikon skrip pada bilah alat), ubah bahasa skrip menjadi Groovy, rekatkan kode berikut, dan simpan sebagai 'ExtendVectorLines.groovy'. Anda dapat menjalankannya baik dari Scripter atau, saat berikutnya Anda meluncurkan Whitebox, itu akan muncul sebagai alat plugin dalam kotak alat Vector Tools. Dibutuhkan shapefile dan jarak yang diperluas sebagai input. Saya akan menyertakan alat dalam rilis publik Whitebox GAT berikutnya.

/*
 * Copyright (C) 2013 Dr. John Lindsay <[email protected]>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.awt.event.ActionListener
import java.awt.event.ActionEvent
import java.io.File
import java.util.concurrent.Future
import java.util.concurrent.*
import java.util.Date
import java.util.ArrayList
import whitebox.interfaces.WhiteboxPluginHost
import whitebox.geospatialfiles.ShapeFile
import whitebox.geospatialfiles.shapefile.*
import whitebox.ui.plugin_dialog.ScriptDialog
import whitebox.utilities.FileUtilities;
import groovy.transform.CompileStatic

// The following four variables are required for this 
// script to be integrated into the tool tree panel. 
// Comment them out if you want to remove the script.
def name = "ExtendVectorLines"
def descriptiveName = "Extend Vector Lines"
def description = "Extends vector polylines by a specified distance"
def toolboxes = ["VectorTools"]

public class ExtendVectorLines implements ActionListener {
private WhiteboxPluginHost pluginHost
private ScriptDialog sd;
private String descriptiveName

public ExtendVectorLines(WhiteboxPluginHost pluginHost, 
    String[] args, def descriptiveName) {
    this.pluginHost = pluginHost
    this.descriptiveName = descriptiveName

    if (args.length > 0) {
        final Runnable r = new Runnable() {
            @Override
            public void run() {
                execute(args)
            }
        }
        final Thread t = new Thread(r)
        t.start()
    } else {
        // Create a dialog for this tool to collect user-specified
        // tool parameters.
        sd = new ScriptDialog(pluginHost, descriptiveName, this)    

        // Specifying the help file will display the html help
        // file in the help pane. This file should be be located 
        // in the help directory and have the same name as the 
        // class, with an html extension.
        def helpFile = "ExtendVectorLines"
        sd.setHelpFile(helpFile)

        // Specifying the source file allows the 'view code' 
        // button on the tool dialog to be displayed.
        def pathSep = File.separator
        def scriptFile = pluginHost.getResourcesDirectory() + "plugins" + pathSep + "Scripts" + pathSep + "ExtendVectorLines.groovy"
        sd.setSourceFile(scriptFile)

        // add some components to the dialog
        sd.addDialogFile("Input file", "Input Vector Polyline File:", "open", "Vector Files (*.shp), SHP", true, false)
        sd.addDialogFile("Output file", "Output Vector File:", "close", "Vector Files (*.shp), SHP", true, false)
        sd.addDialogDataInput("Distance:", "Enter a distance", "", true, false)

        // resize the dialog to the standard size and display it
        sd.setSize(800, 400)
        sd.visible = true
    }
}

// The CompileStatic annotation can be used to significantly
// improve the performance of a Groovy script to nearly 
// that of native Java code.
@CompileStatic
private void execute(String[] args) {
    try {
        int i, f, progress, oldProgress, numPoints, numParts
        int part, startingPointInPart, endingPointInPart
        double x, y, x1, y1, x2, y2, xSt, ySt, xEnd, yEnd, slope;
        ShapefileRecordData recordData;
        double[][] geometry
        int[] partData
        if (args.length != 3) {
            pluginHost.showFeedback("Incorrect number of arguments given to tool.")
            return
        }
        // read the input parameters
        String inputFile = args[0]
        String outputFile = args[1]
        double d = Double.parseDouble(args[2]) // extended distance

        def input = new ShapeFile(inputFile)

        // make sure that input is of a POLYLINE base shapetype
        ShapeType shapeType = input.getShapeType()
        if (shapeType.getBaseType() != ShapeType.POLYLINE) {
            pluginHost.showFeedback("Input shapefile must be of a POLYLINE base shapetype.")
            return
        }

        int numFeatures = input.getNumberOfRecords()

        // set up the output files of the shapefile and the dbf
        ShapeFile output = new ShapeFile(outputFile, shapeType);
        FileUtilities.copyFile(new File(input.getDatabaseFile()), new File(output.getDatabaseFile()));

        int featureNum = 0;
        for (ShapeFileRecord record : input.records) {
            featureNum++;
            PointsList points = new PointsList();
            recordData = getXYFromShapefileRecord(record);
            geometry = recordData.getPoints();
            numPoints = geometry.length;
            partData = recordData.getParts();
            numParts = partData.length;

            for (part = 0; part < numParts; part++) {
                startingPointInPart = partData[part];
                if (part < numParts - 1) {
                    endingPointInPart = partData[part + 1] - 1;
                } else {
                    endingPointInPart = numPoints - 1;
                }

                // new starting poing
                x1 = geometry[startingPointInPart][0]
                y1 = geometry[startingPointInPart][1]

                x2 = geometry[startingPointInPart + 1][0]
                y2 = geometry[startingPointInPart + 1][2]

                if (x1 - x2 != 0) {
                    slope = Math.atan2((y1 - y2) , (x1 - x2))
                    xSt = x1 + d * Math.cos(slope)
                    ySt = y1 + d * Math.sin(slope)
                } else {
                    xSt = x1
                    if (y2 > y1) {
                        ySt = y1 - d
                    } else {
                        ySt = y1 + d
                    }
                }

                // new ending point
                x1 = geometry[endingPointInPart][0]
                y1 = geometry[endingPointInPart][3]

                x2 = geometry[endingPointInPart - 1][0]
                y2 = geometry[endingPointInPart - 1][4]

                if (x1 - x2 != 0) {
                    slope = Math.atan2((y1 - y2) , (x1 - x2))
                    xEnd = x1 + d * Math.cos(slope)
                    yEnd = y1 + d * Math.sin(slope)
                } else {
                    xEnd = x1
                    if (y2 < y1) {
                        yEnd = y1 - d
                    } else {
                        yEnd = y1 + d
                    }
                }

                points.addPoint(xSt, ySt)
                for (i = startingPointInPart; i <= endingPointInPart; i++) {
                    x = geometry[i][0]
                    y = geometry[i][5]
                    points.addPoint(x, y)
                }
                points.addPoint(xEnd, yEnd)

            }

            for (part = 0; part < numParts; part++) {
                partData[part] += part * 2
            }

            switch (shapeType) {
                case ShapeType.POLYLINE:
                    PolyLine line = new PolyLine(partData, points.getPointsArray());
                    output.addRecord(line);
                    break;
                case ShapeType.POLYLINEZ:
                    PolyLineZ polyLineZ = (PolyLineZ)(record.getGeometry());
                    PolyLineZ linez = new PolyLineZ(partData, points.getPointsArray(), polyLineZ.getzArray(), polyLineZ.getmArray());
                    output.addRecord(linez);
                    break;
                case ShapeType.POLYLINEM:
                    PolyLineM polyLineM = (PolyLineM)(record.getGeometry());
                    PolyLineM linem = new PolyLineM(partData, points.getPointsArray(), polyLineM.getmArray());
                    output.addRecord(linem);
                    break;
            }
        }

        output.write();

        // display the output image
        pluginHost.returnData(outputFile)

        // reset the progress bar
        pluginHost.updateProgress(0)
    } catch (Exception e) {
        pluginHost.showFeedback(e.getMessage())
    }
}


@CompileStatic
private ShapefileRecordData getXYFromShapefileRecord(ShapeFileRecord record) {
    int[] partData;
    double[][] points;
    ShapeType shapeType = record.getShapeType();
    switch (shapeType) {
        case ShapeType.POLYLINE:
            whitebox.geospatialfiles.shapefile.PolyLine recPolyLine =
                    (whitebox.geospatialfiles.shapefile.PolyLine) (record.getGeometry());
            points = recPolyLine.getPoints();
            partData = recPolyLine.getParts();
            break;
        case ShapeType.POLYLINEZ:
            PolyLineZ recPolyLineZ = (PolyLineZ) (record.getGeometry());
            points = recPolyLineZ.getPoints();
            partData = recPolyLineZ.getParts();
            break;
        case ShapeType.POLYLINEM:
            PolyLineM recPolyLineM = (PolyLineM) (record.getGeometry());
            points = recPolyLineM.getPoints();
            partData = recPolyLineM.getParts();
            break;
        default: // should never hit this.
            points = new double[1][2];
            points[1][0] = -1;
            points[1][6] = -1;
            break;
    }
    ShapefileRecordData ret = new ShapefileRecordData(points, partData)
    return ret;
}

@CompileStatic
class ShapefileRecordData {
    private final double[][] points
    private final int[] parts
    ShapefileRecordData(double[][] points, int[] parts) {
        this.points = points
        this.parts = parts
    }

    double[][] getPoints() {
        return points
    }

    int[] getParts() {
        return parts
    }

}

@Override
public void actionPerformed(ActionEvent event) {
    if (event.getActionCommand().equals("ok")) {
        final def args = sd.collectParameters()
        sd.dispose()
        final Runnable r = new Runnable() {
            @Override
            public void run() {
                execute(args)
            }
        }
        final Thread t = new Thread(r)
        t.start()
    }
}
}

if (args == null) {
pluginHost.showFeedback("Plugin arguments not set.")
} else {
def f = new ExtendVectorLines(pluginHost, args, descriptiveName)
}

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini


sumber
Saya baru saja memodifikasi kode sehingga Anda dapat secara opsional memilih untuk memperpanjang awal baris, akhir baris, atau kedua ujungnya. Beri tahu saya jika Anda tertarik dengan alat yang dimodifikasi.
Terima kasih atas bantuan Anda! Saya akan melihat ke WhiteBox, saya belum pernah mendengarnya sebelumnya. Senang melihat bahwa Guelph memiliki proyek seperti itu! Saya sendiri seorang siswa UWindsor.
GISKid
Windsor juga merupakan tempat yang sangat baik! Saya baru saja merilis versi terbaru (3.0.5) dan itu termasuk alat yang diperbarui untuk memperluas garis. Beri tahu saya jika Anda memiliki masalah atau umpan balik untuk saya.