지형 대역에 대한 고도 프로파일을 얻으려면 어떻게해야합니까?
10km 이내 (정의 된 선의 각 측면에서) 가장 높은 고도를 고려해야합니다.
내 질문이 명확하기를 바랍니다. 대단히 감사합니다.
지형 대역에 대한 고도 프로파일을 얻으려면 어떻게해야합니까?
10km 이내 (정의 된 선의 각 측면에서) 가장 높은 고도를 고려해야합니다.
내 질문이 명확하기를 바랍니다. 대단히 감사합니다.
답변:
주석에 이어 수직 선분과 함께 작동하는 버전이 있습니다. 철저히 테스트하지 않았으므로주의해서 사용하십시오!
이 방법은 @whuber의 답변보다 훨씬 더 복잡합니다. 부분적으로는 내가 훌륭한 프로그래머가 아니기 때문에, 벡터 처리가 약간의 문제이기 때문입니다. 수직 선분이 필요한 경우 적어도 시작하기를 바랍니다.
이것을 실행하려면 Shapely , Fiona 및 Numpy Python 패키지가 (종속성과 함께) 설치되어 있어야합니다.
#-------------------------------------------------------------------------------
# Name: perp_lines.py
# Purpose: Generates multiple profile lines perpendicular to an input line
#
# Author: JamesS
#
# Created: 13/02/2013
#-------------------------------------------------------------------------------
""" Takes a shapefile containing a single line as input. Generates lines
perpendicular to the original with the specified length and spacing and
writes them to a new shapefile.
The data should be in a projected co-ordinate system.
"""
import numpy as np
from fiona import collection
from shapely.geometry import LineString, MultiLineString
# ##############################################################################
# User input
# Input shapefile. Must be a single, simple line, in projected co-ordinates
in_shp = r'D:\Perp_Lines\Centre_Line.shp'
# The shapefile to which the perpendicular lines will be written
out_shp = r'D:\Perp_Lines\Output.shp'
# Profile spacing. The distance at which to space the perpendicular profiles
# In the same units as the original shapefile (e.g. metres)
spc = 100
# Length of cross-sections to calculate either side of central line
# i.e. the total length will be twice the value entered here.
# In the same co-ordinates as the original shapefile
sect_len = 1000
# ##############################################################################
# Open the shapefile and get the data
source = collection(in_shp, "r")
data = source.next()['geometry']
line = LineString(data['coordinates'])
# Define a schema for the output features. Add a new field called 'Dist'
# to uniquely identify each profile
schema = source.schema.copy()
schema['properties']['Dist'] = 'float'
# Open a new sink for the output features, using the same format driver
# and coordinate reference system as the source.
sink = collection(out_shp, "w", driver=source.driver, schema=schema,
crs=source.crs)
# Calculate the number of profiles to generate
n_prof = int(line.length/spc)
# Start iterating along the line
for prof in range(1, n_prof+1):
# Get the start, mid and end points for this segment
seg_st = line.interpolate((prof-1)*spc)
seg_mid = line.interpolate((prof-0.5)*spc)
seg_end = line.interpolate(prof*spc)
# Get a displacement vector for this segment
vec = np.array([[seg_end.x - seg_st.x,], [seg_end.y - seg_st.y,]])
# Rotate the vector 90 deg clockwise and 90 deg counter clockwise
rot_anti = np.array([[0, -1], [1, 0]])
rot_clock = np.array([[0, 1], [-1, 0]])
vec_anti = np.dot(rot_anti, vec)
vec_clock = np.dot(rot_clock, vec)
# Normalise the perpendicular vectors
len_anti = ((vec_anti**2).sum())**0.5
vec_anti = vec_anti/len_anti
len_clock = ((vec_clock**2).sum())**0.5
vec_clock = vec_clock/len_clock
# Scale them up to the profile length
vec_anti = vec_anti*sect_len
vec_clock = vec_clock*sect_len
# Calculate displacements from midpoint
prof_st = (seg_mid.x + float(vec_anti[0]), seg_mid.y + float(vec_anti[1]))
prof_end = (seg_mid.x + float(vec_clock[0]), seg_mid.y + float(vec_clock[1]))
# Write to output
rec = {'geometry':{'type':'LineString', 'coordinates':(prof_st, prof_end)},
'properties':{'Id':0, 'Dist':(prof-0.5)*spc}}
sink.write(rec)
# Tidy up
source.close()
sink.close()
아래 이미지는 스크립트 출력 결과를 보여줍니다. 중심선을 나타내는 쉐이프 파일을 입력하고 수직선의 길이와 간격을 지정합니다. 출력은이 이미지에 빨간색 선이 포함 된 새 shapefile이며, 각 프로파일에는 프로파일 시작과의 거리를 지정하는 관련 속성이 있습니다.
@ whuber가 의견에서 말했듯 이이 단계에 도달하면 나머지는 상당히 쉽습니다. 아래 이미지는 ArcMap에 출력이 추가 된 다른 예를 보여줍니다.
래스터에 피쳐 도구를 사용하여 수직선을 범주 형 래스터로 변환합니다. 래스터 VALUE
를 Dist
출력 셰이프 파일 의 필드로 설정하십시오 . 또한 도구 설정을 기억 Environments
하는 정도 Extent
, Cell size
그리고 Snap raster
당신의 기본 DEM과 동일합니다. 다음과 같이 라인의 래스터 표현으로 끝나야합니다.
마지막으로이 래스터를 정수 그리드 ( Int 도구 또는 래스터 계산기 사용)로 변환하고 영역 통계를 테이블로 도구 의 입력 영역으로 사용하십시오 . 다음과 같은 출력 테이블로 끝나야합니다.
VALUE
이 테이블 의 필드는 원래 프로파일 라인의 시작부터 거리를 제공합니다. 다른 열은 각 변환의 값에 대한 다양한 통계 (최대, 평균 등)를 제공합니다. 이 테이블을 사용하여 요약 프로파일을 플롯 할 수 있습니다.
주의 : 이 방법의 한 가지 명백한 문제는 원래 선이 매우 흔들리면 일부 가로 선이 겹칠 수 있다는 것입니다. ArcGIS의 구역 통계 도구는 겹치는 영역을 처리 할 수 없으므로이 경우 가로선 중 하나가 다른 가로선보다 우선합니다. 이것은 당신이하고있는 일에 문제가 될 수도 있고 아닐 수도 있습니다.
행운을 빕니다!
spc
하지만 굽힘이 변위를 단축시키기 때문입니다. 대신 가로 방향 벡터를 정규화하고 (구성 요소를 벡터 길이로 나눔) 원하는 가로 길이를 곱해야합니다.
10km 내에서 가장 높은 고도는 원형 10km 반경으로 계산 된 주변 최대 값이므로, 궤도를 따라이 주변 최대 그리드의 프로파일을 추출하십시오.
궤도가있는 언덕이있는 DEM은 다음과 같습니다 (검정색 선이 아래에서 위로)
이 이미지는 약 17 x 10 킬로미터입니다. 방법을 설명하기 위해 10km가 아닌 1km의 반경을 선택했습니다. 1km 버퍼는 노란색으로 표시되어 있습니다.
DEM의 이웃 최대 값은 항상 조금 이상하게 보일 것입니다. 왜냐하면 하나의 최대 값 (언덕 정상)이 10km를 약간 넘어서고 다른 높이의 다른 최대 값이 10km 이내에있는 지점에서 값이 급상승하는 경향이 있기 때문입니다. . 특히, 주변 환경을 지배하는 언덕은 지역 최대 고도 지점을 중심으로 완벽한 가치의 원을 제공합니다.
이지도에서 더 어둡습니다.
다음은 원래 DEM (파란색)과 인접 최대 값 (빨간색)의 프로파일을 나타냅니다.
궤적을 0.1km 간격으로 (남쪽 끝에서 시작하여) 일정한 간격으로 점으로 나누고, 그 점에서 표고를 추출하고 결과 삼중점의 결합 산점도 (처음부터의 거리, 표고, 최대 표고)를 만들어 계산했습니다. 0.1km의 포인트 간격은 버퍼 반경보다 실질적으로 작지만 계산을 빠르게 진행할 수있을만큼 충분히 크게 선택되었습니다 (즉시).
나는 같은 문제가 있었고 James S의 솔루션을 시도했지만 GDAL이 Fiona와 함께 작동하도록 할 수 없었습니다.
그런 다음 QGIS 2.4에서 SAGA 알고리즘 "Cross Profiles"를 발견하고 원하는 결과를 얻었으며 사용자도 찾고 있다고 가정합니다 (아래 참조).
관심있는 사람이라면 numpy 및 osgeo 라이브러리 만 사용하여 수직선을 만드는 JamesS 코드의 수정 버전이 있습니다. JamesS 덕분에 그의 대답은 오늘날 많은 도움이되었습니다!
import osgeo
from osgeo import ogr
import numpy as np
# ##############################################################################
# User input
# Input shapefile. Must be a single, simple line, in projected co-ordinates
in_shp = r'S:\line_utm_new.shp'
# The shapefile to which the perpendicular lines will be written
out_shp = r'S:\line_utm_neu_perp.shp'
# Profile spacing. The distance at which to space the perpendicular profiles
# In the same units as the original shapefile (e.g. metres)
spc = 100
# Length of cross-sections to calculate either side of central line
# i.e. the total length will be twice the value entered here.
# In the same co-ordinates as the original shapefile
sect_len = 1000
# ##############################################################################
# Open the shapefile and get the data
driverShp = ogr.GetDriverByName('ESRI Shapefile')
sourceShp = driverShp.Open(in_shp, 0)
layerIn = sourceShp.GetLayer()
layerRef = layerIn.GetSpatialRef()
# Go to first (and only) feature
layerIn.ResetReading()
featureIn = layerIn.GetNextFeature()
geomIn = featureIn.GetGeometryRef()
# Define a shp for the output features. Add a new field called 'M100' where the z-value
# of the line is stored to uniquely identify each profile
outShp = driverShp.CreateDataSource(out_shp)
layerOut = outShp.CreateLayer('line_utm_neu_perp', layerRef, osgeo.ogr.wkbLineString)
layerDefn = layerOut.GetLayerDefn() # gets parameters of the current shapefile
layerOut.CreateField(ogr.FieldDefn('M100', ogr.OFTReal))
# Calculate the number of profiles/perpendicular lines to generate
n_prof = int(geomIn.Length()/spc)
# Define rotation vectors
rot_anti = np.array([[0, -1], [1, 0]])
rot_clock = np.array([[0, 1], [-1, 0]])
# Start iterating along the line
for prof in range(1, n_prof):
# Get the start, mid and end points for this segment
seg_st = geomIn.GetPoint(prof-1) # (x, y, z)
seg_mid = geomIn.GetPoint(prof)
seg_end = geomIn.GetPoint(prof+1)
# Get a displacement vector for this segment
vec = np.array([[seg_end[0] - seg_st[0],], [seg_end[1] - seg_st[1],]])
# Rotate the vector 90 deg clockwise and 90 deg counter clockwise
vec_anti = np.dot(rot_anti, vec)
vec_clock = np.dot(rot_clock, vec)
# Normalise the perpendicular vectors
len_anti = ((vec_anti**2).sum())**0.5
vec_anti = vec_anti/len_anti
len_clock = ((vec_clock**2).sum())**0.5
vec_clock = vec_clock/len_clock
# Scale them up to the profile length
vec_anti = vec_anti*sect_len
vec_clock = vec_clock*sect_len
# Calculate displacements from midpoint
prof_st = (seg_mid[0] + float(vec_anti[0]), seg_mid[1] + float(vec_anti[1]))
prof_end = (seg_mid[0] + float(vec_clock[0]), seg_mid[1] + float(vec_clock[1]))
# Write to output
geomLine = ogr.Geometry(ogr.wkbLineString)
geomLine.AddPoint(prof_st[0],prof_st[1])
geomLine.AddPoint(prof_end[0],prof_end[1])
featureLine = ogr.Feature(layerDefn)
featureLine.SetGeometry(geomLine)
featureLine.SetFID(prof)
featureLine.SetField('M100',round(seg_mid[2],1))
layerOut.CreateFeature(featureLine)
# Tidy up
outShp.Destroy()
sourceShp.Destroy()