Bir hattın her iki yanında 10 km yükseklik profili


15

Bir arazi grubu için nasıl yükseklik profili alabilirim?

10 km içindeki en yüksek rakım (tanımlanan hattın her iki yanında) dikkate alınmalıdır.

Umarım sorum açıktır. Şimdiden çok teşekkür ederim.


Profilinizi tanımlayan çizgi basit bir düz çizgi mi yoksa köşeli birkaç segmentten mi oluşuyor?
Jake

Çizgi birkaç segmentten oluşur. Ancak tüm segmentler düz çizgidir. :) Yani eğri yok.
Kara

Sadece ... dedikleri gibi ... spitballing ... ama çizgiyi 10 km'lik bir tamponla tamponlayabilir misiniz? arabellekteki tüm özellikleri seçin ... sonra en yüksek değerleri seçin?
Ger

1
Elde etmek istediğiniz şeyin bir görüntüsünü sağlayabilir misiniz?
Alexandre Neto

@ Alex: İstediğim sonuç düzenli bir Yükseklik Grafiği. Ancak, seçilen yolun her iki tarafında en yüksek değerin 10 km olması için 10 km'lik bir tampon ile grafikte gösterilir.
Kara

Yanıtlar:


14

Yorumlardan sonra, dikey çizgi bölümleriyle çalışan bir sürüm. İyice test etmediğim için lütfen dikkatli kullanın!

Bu yöntem @ whuber'ın cevabından çok daha karmaşıktır - kısmen çok iyi bir programcı değilim ve kısmen de vektör işleme biraz faff olduğu için. Umarım en azından dikey çizgi segmentleri ihtiyacınız olan şeyse sizi başlatır.

Sen olması gerekir Düzgün , Fiona ve Numpy bu çalıştırmak için (bağımlılıkları ile birlikte) yüklü Python paketlerini.

#-------------------------------------------------------------------------------
# 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()

Aşağıdaki resim koddan çıktıya bir örnek göstermektedir. Orta çizginizi temsil eden bir şekil dosyasında beslersiniz ve dikey çizgilerin uzunluğunu ve aralıklarını belirtirsiniz. Çıktı, bu görüntüdeki her biri profilin başlangıcından itibaren mesafesini belirten ilişkili bir özniteliğe sahip kırmızı çizgileri içeren yeni bir şekil dosyasıdır.

Örnek komut dosyası çıktısı

@Whuber'ın yorumlarda söylediği gibi, bu aşamaya geldiğinizde geri kalanı oldukça kolaydır. Aşağıdaki resim, çıkışı ArcMap'e eklenmiş başka bir örneği göstermektedir.

resim açıklamasını buraya girin

Dikey çizgileri kategorik bir raster haline dönüştürmek için Özellik Raster aracını kullanın. Rasteri, çıktı şekil dosyasındaki alan VALUEolarak ayarlayın Dist. Ayrıca aracı ayarlamayı unutmayın Environmentski Extent, Cell sizeve Snap rastersizin yatan DEM aynıdır. Sonuç olarak, çizgilerinizin raster olarak gösterilmesi gerekir:

resim açıklamasını buraya girin

Son olarak, bu raster'ı bir tamsayı ızgarasına dönüştürün ( Int aracını veya raster hesap makinesini kullanarak) ve bunu Zonal İstatistikleri için Tablo aracı olarak giriş bölgeleri olarak kullanın. Bunun gibi bir çıktı tablosu elde etmelisiniz:

resim açıklamasını buraya girin

VALUEBu tablodaki alan özgün profil hattının başlangıcına kadar olan mesafeyi verir. Diğer sütunlar, her bir kesitteki değerler için çeşitli istatistikler (maksimum, ortalama vb.) Verir. Özet profilinizi çizmek için bu tabloyu kullanabilirsiniz.

Not: Bu yöntemle ilgili bariz bir sorun, orijinal çizginiz çok kıvrımlıysa, bazı enine çizgilerin üst üste gelebilmesidir. ArcGIS'teki bölgesel istatistik araçları çakışan bölgelerle başa çıkamaz, bu nedenle bu gerçekleştiğinde enine çizgilerinizden biri diğerine göre öncelikli olur. Bu, yaptığınız şey için bir sorun olabilir veya olmayabilir.

İyi şanslar!


3
+1 Bu büyük katkı için iyi bir başlangıç! İkinci şekle yakından bakarsanız, daha kısa kesitler fark edeceksiniz: bunlar virajların yakınında kesişenlerdir. Bunun nedeni, yanlış işlemleri hesaplamak için algoritmanızın her bir bölümün yer değiştirmesinin eşit olacağını varsayar spc, ancak kıvrımlar yer değiştirmeleri kısaltır. Bunun yerine, enine yön vektörünü normalleştirmelisiniz (bileşenlerini vektörün uzunluğuna bölmelisiniz) ve ardından bunu enlemenin istenen yarıçapı ile çarpmalısınız.
whuber

Çok haklısınız - @whuber geribildiriminiz için teşekkürler! Umarım şimdi düzeltildi ...
JamesS

Sevgili James, çok teşekkür ederim. Bu çözüm mükemmel bir şekilde uyuyor.
Kara

11

10 km içindeki en yüksek yükseklik, dairesel 10 km yarıçap ile hesaplanan mahalle maksimum değeridir, bu nedenle bu mahalle maksimum ızgarasının yörünge boyunca bir profilini çıkarın.

Misal

İşte yörüngeye sahip bir tepeli DEM (siyah çizgi aşağıdan yukarıya doğru):

DEM

Bu görüntü yaklaşık 17 x 10 kilometredir. Yöntemi göstermek için 10 km yerine sadece 1 km'lik bir yarıçap seçtim. 1 km'lik tamponu ana hatlarıyla sarı olarak gösterilmiştir.

Bir DEM'in maksimum komşu bölgesi her zaman biraz garip görünecektir, çünkü bir maksimumun (belki de bir tepenin üstü) 10 km'nin biraz altına düştüğü ve farklı bir yükseklikte başka bir maksimumun 10 km içinde geldiği noktalarda değer atlamaya eğilimli olacaktır. . Özellikle, çevrelerine hakim olan tepeler, yerel maksimum yükseklik noktasında merkezlenmiş mükemmel değer dairelerine katkıda bulunacaktır:

Mahalle maks.

Bu haritada daha koyu.

Orijinal DEM (mavi) ve maksimum mahalle (Kırmızı) profillerinin bir grafiği:

Profiller

Yörüngeyi 0,1 km aralıklarla düzenli olarak aralıklı noktalara bölerek (güney ucundan başlayarak), bu noktalardaki yüksekliklerin çıkarılması ve ortaya çıkan üçlülerin birleştirilmiş dağılım grafiğinin (başlangıç, yükseklik, maksimum yükseklik) bir araya getirilmesiyle hesaplanmıştır. 0,1 km'lik nokta aralığı, tampon yarıçapından önemli ölçüde daha küçük, ancak hesaplamayı hızlı bir şekilde yapacak kadar büyük olacak şekilde seçildi (anlık).


Bu tamamen doğru değil, değil mi? Her noktanın etrafında dairesel bir tampon yerine, altta yatan rasterleri örneklemek için 20 km uzunluğunda dik bir çizgi kullanılmamalıdır mı? En azından Kara'nın "hattın her iki tarafında 10 km'lik en yüksek değer" gereksinimini hesaba katarak bu şekilde yorumladım.
Jake

4
@jake "Yanlış" demezdim: sadece alternatif bir yorum sunuyorsun. "Her iki tarafında" daha iyi bir nitelik kullanabilen belirsiz bir terimdir. Seninki gibi yorumlara çözüm önerebilirim; bir yöntem maksimum bir bölge kullanır. Ancak, yürütülmesi daha karmaşık ve çok daha yavaştır. Neden OP'nin bu basit çözüm hakkında ne düşündüğünü ilk olarak görmüyoruz?
whuber

Kelimelerin kötü seçim, "doğru" kullanmamalıydım - bunun için üzgünüm
Jake

1
Profil aracını nasıl kullanacağınızı bildiğiniz için neredeyse bitti. QGIS, GRASS ile mahalle operasyonlarını içeren arayüzlere sahiptir. Komşuları maksimum işlemi r. Komşularını kullanarak uygulayın ve sonucunu profil yapın.
whuber

1
@JamesS Paralel kaydırma yapmak istemezsiniz, her çapraz profili orta hatta dik yapmak istersiniz. (Paralel kaydırma yaklaşımı, tam olarak burada açıkladığım gibi mahalle maksimum hesaplaması için uygun bir uzun ve sıska mahalle kullanarak uygulanabilir.) Eşit aralıklı dikey çizgi segmentleri setleri oluşturmak için bu sitede kod bulacağınızdan eminim. bir çoklu çizgi boyunca; bu zor kısmı. Diğer her şey sadece bu segmentler boyunca DEM değerlerinin çıkarılması ve özetlenmesi meselesidir.
whuber

6

Aynı sorunu yaşadım ve James S'in çözümünü denedim, ancak GDAL'ın Fiona ile çalışmasını sağlayamadım.

Sonra QGIS 2.4'te SAGA algoritması "Çapraz Profiller" i keşfettim ve tam olarak istediğim sonucu aldım ve sizin de aradığınızı varsayıyorum (aşağıya bakın).

resim açıklamasını buraya girin


Merhaba, birkaç yıl önce bu yazıyla karşılaştım. Ben iplik marş ile aynı sorunla karşı karşıya, ve, (Q) CBS için çok yeni olmakla birlikte, yukarıdaki resim kadar kazanılmış olmaktan mutluluk duyuyorum. Yine de verilerle nasıl çalışabilirim? Çapraz Profiller katmanı her örneklenen nokta için yüksekliği gösterir, ancak 1) her çapraz çizgi için maksimum yüksekliği bulma 2) orijinal yolla kesişme koordinatlarını bulma 3) 1 2'den koordinatlarla. Herkes yardım edebilir mi lütfen? Şimdiden çok teşekkürler! Mal
Cpt Reynolds

6

İlgilenen herkes için, burada sadece numpy ve osgeo kütüphanelerini kullanarak dikey çizgiler oluşturan JamesS kodunun değiştirilmiş bir versiyonu. JamesS sayesinde, yanıtı bugün bana çok yardımcı oldu!

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()

Teşekkürler ket - Bunu denedim ama maalesef tam olarak çalışmıyor. Komut dosyasına tek bir çoklu çizgi özelliği ile bir şekil dosyası verdim, ancak çıktım yalnızca "M100" değeri için sıfırlarla dolu özellik tablosudur - haritada gösterilen özellik yok. Fikirler?
davehughes87

Boş verin - betiğinizin, her "spc" metrede değil, çoklu çizginin her bir segmentinin ENDS'sinde dikey çizgiler hesapladığı görülmüştür. Bu, döngüde n_prof'a ulaşılmadan ve "nan" değerleri üretilmeden önce çalışmak için çok satırlı çalıştığım anlamına geliyor.
28.03.2015
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.