Mở rộng dòng theo khoảng cách được chỉ định trong ArcGIS cho Máy tính để bàn?


11

Tôi có một lớp thẩm mỹ hoàn toàn có biểu tượng mũi tên. Một số không hiển thị đúng vì dòng quá nhỏ. Tôi đã chọn có thể 50 bản ghi mà tôi cần mở rộng dòng này bằng một số cho trước (ví dụ: 2 mét). Công cụ dòng mở rộng chỉ mở rộng các dòng đến một giao lộ cụ thể, vì vậy công cụ này không phải là thứ tôi đang tìm kiếm.

Tôi đã thử chỉnh sửa trường chiều dài hình nhưng nó sẽ không cho phép tôi. Có một cách đơn giản để làm điều này thông qua máy tính trường hoặc trong thanh công cụ biên tập?


1
dữ liệu có hình dạng, gdb, fgdb? Bạn có cơ bản, chuẩn, nâng cao?
Brad Nesom

Hình dáng và tiên tiến.
GISKid

Tôi có thể làm rõ, bạn có muốn mở rộng mọi tính năng trong một shapefile kiểu đa tuyến hay chỉ các tính năng được chọn?

Nếu bạn muốn căn cứ vào phần mở rộng của mình trên điểm cuối, bạn có thể đi đến đỉnh trước đó và xác định độ dốc giữa hai điểm này. Sau đó, bạn có thể di chuyển đỉnh điểm cuối khoảng cách x của bạn dựa trên độ dốc đã nói.
Paul

@Paul, tôi đang viết một kịch bản để làm việc đó, nhưng nó phức tạp hơn một chút vì bạn cần tính đến các polylines đa phần. Đó là, bạn cần nhìn vào điểm bắt đầu và điểm kết thúc và các điểm lân cận của chúng cho từng phần. Tôi cần biết rằng GISKid quan tâm đến việc mở rộng tất cả các tính năng trước tiên.

Câu trả lời:


12

Vâng, tôi nghĩ rằng tôi đã nhận được nó cho các dòng của bất kỳ số đỉnh. Tôi đã không thử nhiều dòng vì tôi chưa bao giờ gặp rắc rối với nó trong Arcpy. Việc mã hóa trở nên khó khăn hơn một chút vì không có quyền truy cập ghi vào thuộc tính lastPoint cho các đối tượng Hình học. Thay vì sử dụng độ dốc (đó là suy nghĩ ban đầu của tôi), tôi đã sử dụng mã từ câu hỏi SO này . Nó không dựa vào lượng giác, vì vậy nó sẽ hiệu quả hơn một chút. Đoạn mã sau hoạt động bằng cách di chuyển điểm cuối của một dòng sang tọa độ mới nằm dọc theo sự kéo dài của một dòng từ hai đỉnh cuối cùng. Tôi đã thử nó trên một 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)

Tôi đặt ký hiệu thành mũi tên ở cuối cho các danh mục dựa trên OID để dễ thấy sự tách biệt giữa các tính năng. Ghi nhãn đã được đặt để đếm đỉnh.nhập mô tả hình ảnh ở đây


Điều này chỉ giúp tôi rất nhiều! Tuy nhiên, điều này thậm chí còn hữu ích hơn trong tình huống cụ thể của tôi nếu tham số khoảng cách có thể dựa trên một trường trong các tính năng dòng gốc. Tôi đã cố gắng tự thực hiện điều này và biết rằng bằng cách nào đó tôi sẽ phải lặp đi lặp lại qua các khoảng cách trong dòng "newvert =" nhưng tôi đang gặp khó khăn khi thực hiện nó. Nếu bạn có thể mở rộng mã của mình để làm điều này, tôi sẽ rất biết ơn!
GeoJohn

Đừng quên cập nhật chế độ xem của bạn, nếu bạn đang chạy tập lệnh từ trong bảng điều khiển Python. Dòng của tôi đã thực sự dài sau một số lần thử "không thành công".
EikeMike

2

Điều gì nếu bạn thực hiện lựa chọn các dòng bạn muốn mở rộng.
Đệm các dòng đó theo số lượng mở rộng mong muốn.
Chuyển đổi nó thành một dòng fc.
Sau đó kéo dài đến ngã tư.
Bạn có thể phải ngắt và xóa đầu kia của bộ đệm để không bị chồng chéo dòng ở giữa. (Tôi chưa thấy ảnh chụp màn hình về những gì bạn có hoặc muốn làm)
Hoặc tôi nghĩ có một công cụ trong ettools (Tôi đang kiểm tra để xem chức năng và nếu nó miễn phí)
Không tìm thấy gì hữu ích trong các công cụ et tôi đã làm tìm chủ đề này cho một số mã vb (cũ). và một yêu cầu cho một số con trăn. bạn có thể theo dõi nó và kiểm tra trang web idea.arcgis.com .


2

Đây là một phương thức hoạt động với các polylines đa phần bao gồm bất kỳ số điểm nút nào. Nó sử dụng GAT GIS Whitebox mã nguồn mở ( http://www.uoguelph.ca/~hydrogeo/Whitebox/ ). Chỉ cần tải xuống Whitebox, mở Scripter (biểu tượng tập lệnh trên thanh công cụ), thay đổi ngôn ngữ kịch bản thành Groovy, dán mã sau vào và lưu nó dưới dạng 'ExtendVectorLines.groovy'. Bạn có thể chạy nó từ Scripter hoặc lần sau khi bạn khởi chạy Whitebox, nó sẽ xuất hiện dưới dạng một công cụ plugin trong hộp công cụ Vector Tools. Nó cần một shapefile và một khoảng cách mở rộng làm đầu vào. Tôi sẽ bao gồm công cụ này trong bản phát hành công khai tiếp theo của Whitebox GAT.

/*
 * Copyright (C) 2013 Dr. John Lindsay <jlindsay@uoguelph.ca>
 *
 * 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)
}

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


Tôi vừa sửa đổi mã để bạn có thể tùy ý chọn mở rộng dòng bắt đầu, kết thúc dòng hoặc cả hai đầu. Hãy cho tôi biết nếu bạn quan tâm đến công cụ sửa đổi.

Cảm ơn bạn đã giúp đỡ! Tôi sẽ xem xét WhiteBox, tôi chưa bao giờ nghe về nó trước đây. Thật tuyệt khi thấy Guelph có những dự án như vậy! Bản thân tôi là một sinh viên UWindsor.
GISKid

Windsor là một nơi tuyệt vời quá! Tôi vừa phát hành phiên bản mới nhất (3.0.5) và nó bao gồm công cụ cập nhật để mở rộng dòng. Hãy cho tôi biết nếu bạn có bất kỳ vấn đề hoặc phản hồi cho tôi.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.