ArcGIS for Desktop에서 지정된 거리만큼 선을 연장 하시겠습니까?


11

나는 화살표 기호가있는 순수한 미적 층을 가지고 있습니다. 선이 너무 작아 일부가 제대로 표시되지 않습니다. 이 줄을 주어진 숫자 (예 : 2 미터)로 확장해야하는 50 개의 레코드를 선택했습니다. 선 연장 도구는 선을 지정된 교차점까지만 연장하므로이 도구는 내가 원하는 것이 아닙니다.

셰이프 길이 필드를 편집하려고 시도했지만 허용되지 않습니다. 필드 계산기를 통해 또는 편집기 툴바 내에서이를 수행하는 간단한 방법이 있습니까?


1
데이터가 gdb, fgdb입니까? 기본, 표준, 고급이 있습니까?
Brad Nesom

모양과 고급.
GISKid

폴리 라인 유형 쉐이프 파일의 모든 피처 또는 선택한 피처를 확장하고 싶습니까?

끝점을 기준으로 확장을 설정하려면 이전 정점으로 이동하여이 두 점 사이의 기울기를 결정할 수 있습니다. 그런 다음 해당 경사를 기준으로 끝점 꼭지점을 거리 x만큼 이동할 수 있습니다 .
Paul

@Paul, 나는 그것을하기 위해 스크립트를 작성하고 있지만 다중 부분 폴리 라인을 고려해야하기 때문에 조금 더 복잡합니다. 즉, 각 부품의 시작점과 끝점 및 인접 지점을 확인해야합니다. GISKid가 모든 기능을 먼저 확장하는 데 관심이 있음을 알아야합니다.

답변:


12

글쎄, 나는 모든 정점 수의 줄에 대해 그것을 내려 놓았다고 생각한다. 나는 아크 피로 엉망이 된 적이 없기 때문에 멀티 파트 라인을 시도하지 않았습니다. Geometry 객체의 lastPoint 속성에 대한 쓰기 액세스 권한이 없기 때문에 코딩이 조금 더 어려워졌습니다. 슬로프 (초기 생각)를 사용하는 대신 이 SO question 의 코드를 사용했습니다 . 삼각법에 의존하지 않으므로 약간 더 효율적이어야합니다. 다음 코드는 선의 끝점을 마지막 두 정점에서 선이 연장 된 새 좌표로 이동하여 작동합니다. 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)

OID를 기반으로하는 범주의 경우 기호를 화살표로 설정하여 기능 간 구분을보다 쉽게 ​​확인할 수 있습니다. 정점을 계산하도록 레이블이 설정되었습니다.여기에 이미지 설명을 입력하십시오


이것은 나에게 많은 도움이되었습니다! 그러나 거리 매개 변수가 원래 선 피처의 필드를 기반으로 할 수 있다면 특정 상황에서 훨씬 더 도움이 될 것입니다. 나는 이것을 직접 구현하려고 시도했지만 어떻게 든 "newvert ="줄의 거리를 반복해야하지만 그것을 구현하는 데 어려움을 겪고 있음을 알고 있습니다. 이 작업을 수행하기 위해 코드를 확장 할 수 있다면 매우 감사하겠습니다!
GeoJohn

파이썬 콘솔에서 스크립트를 실행했다면 뷰를 업데이트하는 것을 잊지 마십시오. 몇 번의 "성공하지 못한"시도 후에 나의 행은 정말로 길어졌다.
EikeMike

2

연장하려는 선을 선택하면 어떻게됩니까?
원하는 확장 량으로 해당 행을 버퍼링하십시오.
이것을 fc 줄로 변환하십시오.
그런 다음 교차로 확장하십시오.
중간에있는 줄이 겹치지 않도록 버퍼의 다른 쪽 끝을 끊고 삭제해야 할 수도 있습니다. (당신이 가지고 있거나하고 싶은 일의 스크린 샷을 보지 못했습니다)
또는 ettools에 도구가 있다고 생각합니다 (기능을 확인하고 무료인지 확인하고 있습니다)
et 도구에서 유용한 것을 찾지 못했습니다 (이전의) vb 코드에 대해이 스레드 를 찾으십시오 . 그리고 파이썬에 대한 요청. 당신은 그것을 따르고 ideas.arcgis.com 웹 사이트를 확인할 수 있습니다 .


2

다음은 임의의 수의 노드 점으로 구성된 다중 부분 폴리선으로 작동하는 방법입니다. 오픈 소스 GIS Whitebox GAT ( http://www.uoguelph.ca/~hydrogeo/Whitebox/ )를 사용합니다. Whitebox를 다운로드하고 Scripter (도구 모음의 스크립트 아이콘)를 열고 스크립팅 언어를 Groovy로 변경 한 후 다음 코드를 붙여 넣고 'ExtendVectorLines.groovy'로 저장하면됩니다. Scripter에서 실행하거나 다음에 Whitebox를 시작할 때 Vector Tools 도구 상자에 플러그인 도구로 표시됩니다. shapefile과 확장 거리를 입력으로 사용합니다. 다음 공개 버전의 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.