나는 화살표 기호가있는 순수한 미적 층을 가지고 있습니다. 선이 너무 작아 일부가 제대로 표시되지 않습니다. 이 줄을 주어진 숫자 (예 : 2 미터)로 확장해야하는 50 개의 레코드를 선택했습니다. 선 연장 도구는 선을 지정된 교차점까지만 연장하므로이 도구는 내가 원하는 것이 아닙니다.
셰이프 길이 필드를 편집하려고 시도했지만 허용되지 않습니다. 필드 계산기를 통해 또는 편집기 툴바 내에서이를 수행하는 간단한 방법이 있습니까?
나는 화살표 기호가있는 순수한 미적 층을 가지고 있습니다. 선이 너무 작아 일부가 제대로 표시되지 않습니다. 이 줄을 주어진 숫자 (예 : 2 미터)로 확장해야하는 50 개의 레코드를 선택했습니다. 선 연장 도구는 선을 지정된 교차점까지만 연장하므로이 도구는 내가 원하는 것이 아닙니다.
셰이프 길이 필드를 편집하려고 시도했지만 허용되지 않습니다. 필드 계산기를 통해 또는 편집기 툴바 내에서이를 수행하는 간단한 방법이 있습니까?
답변:
글쎄, 나는 모든 정점 수의 줄에 대해 그것을 내려 놓았다고 생각한다. 나는 아크 피로 엉망이 된 적이 없기 때문에 멀티 파트 라인을 시도하지 않았습니다. 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를 기반으로하는 범주의 경우 기호를 화살표로 설정하여 기능 간 구분을보다 쉽게 확인할 수 있습니다. 정점을 계산하도록 레이블이 설정되었습니다.
연장하려는 선을 선택하면 어떻게됩니까?
원하는 확장 량으로 해당 행을 버퍼링하십시오.
이것을 fc 줄로 변환하십시오.
그런 다음 교차로 확장하십시오.
중간에있는 줄이 겹치지 않도록 버퍼의 다른 쪽 끝을 끊고 삭제해야 할 수도 있습니다. (당신이 가지고 있거나하고 싶은 일의 스크린 샷을 보지 못했습니다)
또는 ettools에 도구가 있다고 생각합니다 (기능을 확인하고 무료인지 확인하고 있습니다)
et 도구에서 유용한 것을 찾지 못했습니다 (이전의) vb 코드에 대해이 스레드 를 찾으십시오 . 그리고 파이썬에 대한 요청. 당신은 그것을 따르고 ideas.arcgis.com 웹 사이트를 확인할 수 있습니다 .
다음은 임의의 수의 노드 점으로 구성된 다중 부분 폴리선으로 작동하는 방법입니다. 오픈 소스 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)
}