กำลังขยายสายตามระยะทางที่ระบุใน ArcGIS สำหรับเดสก์ท็อป?


11

ฉันมีเลเยอร์ความงามล้วนๆซึ่งมีสัญลักษณ์ลูกศร บางคนไม่ปรากฏขึ้นเพราะสายมีขนาดเล็กเกินไป ฉันได้เลือกอาจจะ 50 ระเบียนที่ฉันต้องขยายบรรทัดนี้ด้วยตัวเลขที่กำหนด (เช่น 2 เมตร) เครื่องมือขยายบรรทัดจะขยายบรรทัดไปยังจุดตัดที่ระบุเท่านั้นดังนั้นเครื่องมือนี้ไม่ใช่สิ่งที่ฉันกำลังมองหา

ฉันลองแก้ไขฟิลด์ความยาวของรูปร่างแล้ว แต่จะไม่ยอมให้ฉันทำ มีวิธีง่ายๆในการทำเช่นนี้ผ่านเครื่องคิดเลขภาคสนามหรือภายในแถบเครื่องมือแก้ไข?


1
ข้อมูลมีรูปร่างเป็น gdb, fgdb หรือไม่ คุณมีพื้นฐานมาตรฐานขั้นสูงหรือไม่
Brad Nesom

รูปร่างและขั้นสูง
GISKid

ฉันสามารถอธิบายได้หรือไม่ว่าคุณต้องการที่จะขยายคุณสมบัติทุกอย่างในรูปร่าง polyline ประเภทหรือเพียงแค่เลือกคุณสมบัติ?

หากคุณต้องการขยายฐานของคุณไปยังจุดปลายคุณสามารถไปที่จุดยอดก่อนหน้าและกำหนดความชันระหว่างจุดสองจุดนี้ จากนั้นคุณสามารถเลื่อนจุดปลายจุดยอดของระยะทางxตามความชันดังกล่าว
พอล

@ พอลฉันเขียนสคริปต์เพื่อทำอย่างนั้น แต่มันซับซ้อนกว่านี้เล็กน้อยเพราะคุณจำเป็นต้องมีบัญชีสำหรับโพลีลีนหลายส่วน นั่นคือคุณต้องดูจุดเริ่มต้นและจุดสิ้นสุดและจุดที่อยู่ใกล้เคียงในแต่ละส่วน ฉันต้องรู้ว่า GISKid สนใจที่จะขยายคุณสมบัติทั้งหมดก่อน

คำตอบ:


12

ดีฉันคิดว่าฉันได้รับมันลงสำหรับบรรทัดของการนับจุดสุดยอดใด ๆ ฉันไม่ได้ลองหลายบรรทัดเพราะฉันไม่เคยยุ่งกับมันใน arcpy การเขียนโค้ดทำได้ยากขึ้นเล็กน้อยเนื่องจากไม่มีสิทธิ์ในการเขียนไปยังคุณสมบัติ LastPoint สำหรับวัตถุเรขาคณิต แทนที่จะใช้ความชัน (ซึ่งเป็นความคิดเริ่มต้นของฉัน) ฉันใช้รหัสจากคำถาม SOนี้ มันไม่ได้พึ่งพาตรีโกณมิติดังนั้นมันควรจะมีประสิทธิภาพมากกว่านี้เล็กน้อย รหัสต่อไปนี้ทำงานโดยการย้ายจุดสิ้นสุดของเส้นไปยังพิกัดใหม่ที่อยู่ตามแนวยาวของเส้นจากสองจุดสุดท้าย ฉันทดสอบมันในรูปร่างไฟล์

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)

ฉันตั้งค่าสัญลักษณ์ให้ลูกศรท้ายสำหรับหมวดหมู่ตาม OID เพื่อให้เห็นการแยกระหว่างคุณลักษณะต่างๆได้ง่ายขึ้น การติดฉลากถูกตั้งค่าให้นับจำนวนจุดยอดป้อนคำอธิบายรูปภาพที่นี่


แค่ช่วยฉันออกไปเยอะ! อย่างไรก็ตามสิ่งนี้จะมีประโยชน์มากยิ่งขึ้นในสถานการณ์เฉพาะของฉันหากพารามิเตอร์ระยะทางอาจเป็นไปตามเขตข้อมูลในคุณลักษณะของบรรทัดต้นฉบับ ฉันได้ลองใช้งานด้วยตัวเองและรู้ว่าฉันจะต้องทำซ้ำผ่านระยะทางในบรรทัด "newvert =" แต่ฉันมีปัญหาในการใช้งาน หากคุณสามารถขยายรหัสของคุณเพื่อทำสิ่งนี้ฉันจะขอบคุณมาก!
GeoJohn

อย่าลืมอัปเดตมุมมองของคุณหากคุณใช้งานสคริปต์จากภายในคอนโซล Python บรรทัดของฉันยาวมากหลังจากพยายาม "ไม่สำเร็จ" หลายครั้ง
EikeMike

2

จะทำอย่างไรถ้าคุณทำการเลือกบรรทัดที่คุณต้องการขยาย
บัฟเฟอร์บรรทัดเหล่านั้นตามจำนวนของส่วนขยายที่ต้องการ
แปลงมันเป็นเส้น fc
จากนั้นขยายไปถึงสี่แยก
คุณอาจต้องทำลายและลบปลายอีกด้านหนึ่งของบัฟเฟอร์เพื่อป้องกันไม่ให้เหลื่อมกันของเส้นตรงกลาง (ฉันไม่ได้เห็นภาพหน้าจอของสิ่งที่คุณมีหรือต้องการทำ)
หรือฉันคิดว่ามีเครื่องมือใน ettools (ฉันกำลังตรวจสอบเพื่อดูการทำงานและถ้ามันฟรี)
ไม่พบสิ่งที่มีประโยชน์ในเครื่องมือ et ฉัน ค้นหาหัวข้อนี้สำหรับบางรหัส vb (เก่า) และขอไพ ธ อนบางตัว คุณอาจติดตามและตรวจสอบเว็บไซต์ideas.arcgis.com


2

ต่อไปนี้เป็นวิธีการที่ใช้งานได้กับ polylines แบบหลายส่วนที่ประกอบด้วยจุดจำนวนโหนดใด ๆ มันใช้โอเพ่นซอร์ส GIS Whitebox GAT ( http://www.uoguelph.ca/~hydrogeo/Whitebox/ ) เพียงดาวน์โหลด Whitebox เปิด Scripter (ไอคอนสคริปต์บนแถบเครื่องมือ) เปลี่ยนภาษาสคริปต์เป็น Groovy วางรหัสต่อไปนี้แล้วบันทึกเป็น 'ExtendVectorLines.groovy' คุณสามารถเรียกใช้ได้จาก Scripter หรือครั้งต่อไปที่คุณเรียกใช้ Whitebox มันจะปรากฏเป็นเครื่องมือเสริมในกล่องเครื่องมือ Vector Tools มันใช้รูปร่างและระยะทางขยายเป็นอินพุต ฉันจะรวมเครื่องมือไว้ใน 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)
}

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่


ฉันเพิ่งแก้ไขรหัสเพื่อให้คุณสามารถเลือกที่จะขยายการเริ่มต้นบรรทัดสิ้นสุดบรรทัดหรือปลายทั้งสอง แจ้งให้เราทราบหากคุณสนใจเครื่องมือที่ปรับเปลี่ยนแล้ว

ขอบคุณสำหรับความช่วยเหลือของคุณ! ฉันจะดูเป็น WhiteBox ฉันไม่เคยได้ยินมาก่อน เจ๋งมากที่เห็นว่า Guelph มีโครงการเช่นนี้! ฉันเป็นนักเรียน UWindsor ด้วยตัวเอง
GISKid

วินด์เซอร์ก็เป็นสถานที่ที่ยอดเยี่ยมเช่นกัน! ฉันเพิ่งเปิดตัวเวอร์ชันล่าสุด (3.0.5) และมีเครื่องมือที่ได้รับการปรับปรุงสำหรับการขยายบรรทัด แจ้งให้เราทราบหากคุณมีปัญหาหรือข้อเสนอแนะสำหรับฉัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.