Ortho Projection tạo ra các đồ tạo tác


14

Tôi đang cố gắng tạo ra một khung nhìn giống như hình cầu bằng cách sử dụng qgis và "thế giới từ không gian" -projection http://spatialreference.org/ref/sr-org/6980/ (cần thiết là một phép chiếu trực giao). ArcGIS kết thúc các hình dạng một cách chính xác nhưng QGIS (2.01) tạo ra các tạo tác khó chịu.

nhập mô tả hình ảnh ở đây

Tôi phải sản xuất các quả cầu một cách thường xuyên với các góc độ khác nhau, vậy có ai có ý tưởng làm thế nào để khắc phục vấn đề này không?


1
báo cáo lỗi liên quan đến QGIS: hub.qgis.org/issues/2703
naught101

Có phải là một vấn đề kỹ thuật quá lớn để có một hình chiếu chính tả được tải sẵn, có thể được tập trung lại vào bất kỳ chế độ xem nào không?

Điều này không trả lời câu hỏi. Hãy tham quan để tìm hiểu làm thế nào để đặt một câu hỏi tập trung.
John Powell

Câu trả lời:


23

Như Andre đã nói, để điều này hoạt động, bạn sẽ cần cắt lớp của mình trước khi chiếu nó. Andre mô tả một phương pháp thủ công , hoạt động tốt trong nhiều trường hợp: Chiếu shapefile của bạn thành phép chiếu đẳng thức phương vị với các tham số tương tự như phép chiếu chính tả, tạo một vòng tròn cắt bao phủ bán cầu sẽ hiển thị trong hình chiếu chính tả và clip shapefile với điều đó. Tuy nhiên, phương pháp đó đòi hỏi một chút nỗ lực thủ công và không hoạt động đối với tất cả các tham số chiếu, vì việc chiếu lên phép chiếu tương đương phương vị có thể dẫn đến các vấn đề tương tự như chiếu lên phép chiếu chính tả.

Đây là một tập lệnh (hiện cũng có sẵn dưới dạng plugin Clip to Hemisphere QGIS ) có cách tiếp cận hơi khác: Một lớp cắt được tạo trong hệ thống tham chiếu tọa độ của shapefile ban đầu bằng cách chiếu một vòng tròn từ hình chính tả sang CRS nguồn, nhưng ngoài ra đảm bảo bao phủ toàn bộ bán cầu có thể nhìn thấy, bao gồm cả cực nhìn thấy được.

Đây là những gì lớp cắt trông giống như một hình chiếu chính tả tập trung vào 30 ° N, 110 ° E:

Kịch bản sau đó cắt lớp hiện đang được chọn với lớp cắt và thêm lớp kết quả vào dự án. Lớp đó sau đó có thể được chiếu lên hình chiếu chính tả, khi đang di chuyển hoặc bằng cách lưu nó trong CRS chính tả:

Đây là kịch bản. Đảm bảo lưu nó trong đường dẫn Python của bạn, ví dụ như 'cliportho.py'. Sau đó, bạn có thể nhập nó trong bảng điều khiển QGIS Python bằng cách sử dụng import cliportho. Để cắt một lớp, gọi cliportho.doClip(iface, lat=30, lon=110, filename='A.shp').


import numpy as np
from qgis.core import *
import qgis.utils

import sys, os, imp


def doClip(iface, lat=30, lon=110, filename='result.shp'):
    sourceLayer = iface.activeLayer()

    sourceCrs = sourceLayer.dataProvider().crs()

    targetProjString = "+proj=ortho +lat_0=" + str(lat) + " +lon_0=" + str(lon) + "+x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs"
    targetCrs = QgsCoordinateReferenceSystem()
    targetCrs.createFromProj4(targetProjString)

    transformTargetToSrc = QgsCoordinateTransform(targetCrs, sourceCrs).transform

    def circlePolygon(nPoints=20, radius=6370000, center=[0,0]):
        clipdisc = QgsVectorLayer("Polygon?crs=epsg:4326", "Clip disc", "memory")
        angles = np.linspace(0, 2*np.pi, nPoints, endpoint=False)
        circlePoints = np.array([ transformTargetToSrc(QgsPoint(center[0]+np.cos(angle)*radius, center[1]+np.sin(angle)*radius)) for angle in angles ])
        sortIdx = np.argsort(circlePoints[:,0])
        circlePoints = circlePoints[sortIdx,:]
        circlePoints = [ QgsPoint(point[0], point[1]) for point in circlePoints ]
        circlePoints.extend([QgsPoint(180,circlePoints[-1][1]), QgsPoint(180,np.sign(lat)*90), QgsPoint(-180,np.sign(lat)*90), QgsPoint(-180,circlePoints[0][1])])
        circle = QgsFeature()
        circle.setGeometry(QgsGeometry.fromPolygon( [circlePoints] ) )
        clipdisc.dataProvider().addFeatures([circle])
        QgsMapLayerRegistry.instance().addMapLayer(clipdisc)
        return clipdisc

    auxDisc = circlePolygon(nPoints = 3600)

    ###### The clipping stuff
    ## Code taken from the fTools plugin

    vproviderA = sourceLayer.dataProvider()
    vproviderB = auxDisc.dataProvider()

    inFeatA = QgsFeature()
    inFeatB = QgsFeature()
    outFeat = QgsFeature()

    fitA = vproviderA.getFeatures()

    nElement = 0  
    writer = QgsVectorFileWriter( filename, 'UTF8', vproviderA.fields(),
                                  vproviderA.geometryType(), vproviderA.crs() )

    index = QgsSpatialIndex()
    feat = QgsFeature()
    index = QgsSpatialIndex()
    fit = vproviderB.getFeatures()
    while fit.nextFeature( feat ):
        index.insertFeature( feat )

    while fitA.nextFeature( inFeatA ):
      nElement += 1
      geom = QgsGeometry( inFeatA.geometry() )
      atMap = inFeatA.attributes()
      intersects = index.intersects( geom.boundingBox() )
      first = True
      found = False
      if len( intersects ) > 0:
        for id in intersects:
          vproviderB.getFeatures( QgsFeatureRequest().setFilterFid( int( id ) ) ).nextFeature( inFeatB )
          tmpGeom = QgsGeometry( inFeatB.geometry() )
          if tmpGeom.intersects( geom ):
            found = True
            if first:
              outFeat.setGeometry( QgsGeometry( tmpGeom ) )
              first = False
            else:
              try:
                cur_geom = QgsGeometry( outFeat.geometry() )
                new_geom = QgsGeometry( cur_geom.combine( tmpGeom ) )
                outFeat.setGeometry( QgsGeometry( new_geom ) )
              except:
                GEOS_EXCEPT = False
                break
        if found:
          try:
            cur_geom = QgsGeometry( outFeat.geometry() )
            new_geom = QgsGeometry( geom.intersection( cur_geom ) )
            if new_geom.wkbType() == 0:
              int_com = QgsGeometry( geom.combine( cur_geom ) )
              int_sym = QgsGeometry( geom.symDifference( cur_geom ) )
              new_geom = QgsGeometry( int_com.difference( int_sym ) )
            try:
              outFeat.setGeometry( new_geom )
              outFeat.setAttributes( atMap )
              writer.addFeature( outFeat )
            except:
              FEAT_EXCEPT = False
              continue
          except:
            GEOS_EXCEPT = False
            continue
    del writer

    resultLayer = QgsVectorLayer(filename, sourceLayer.name() + " - Ortho: Lat " + str(lat) + ", Lon " + str(lon), "ogr")
    QgsMapLayerRegistry.instance().addMapLayer(resultLayer)

Có vẻ rất hứa hẹn - tôi chắc chắn sẽ thử điều này và rất vui khi cung cấp phản hồi. Tôi không biết nhiều về lập trình arcpy nhưng chưa bắt đầu với lập trình qgis - nhưng tôi sẽ cố gắng hiểu những gì bạn đang làm ;-) Một plugin (có thể hoạt động hàng loạt cho nhiều lớp) sẽ rất hữu ích!
dùng1523709

1
FYI, Tập lệnh này không còn hoạt động trong QGIS 2.16, do loại bỏ gói "fTools".
Spike Williams

2
@SpikeWilliams: Tôi đã cập nhật tập lệnh để loại bỏ sự phụ thuộc vào fTools.
Jake

5

Bạn phải cắt dữ liệu đa giác của mình thành một nửa toàn cầu, bởi vì QGIS không tự làm điều đó.

Tôi đã viết một hướng dẫn ở đây:

Các đa giác đã đi đâu sau khi chiếu bản đồ trong QGIS?


BIÊN TẬP

Hình ảnh bạn hiển thị thực sự không phải là hình chiếu trực giao, vì nó cho thấy toàn bộ thế giới, và không chỉ một nửa có thể nhìn thấy khi nhìn từ ngoài không gian. Đối với bản đồ thế giới, việc cắt dễ dàng hơn một chút, như được mô tả ở đây:

QGIS hiển thị các tệp hình dạng quốc gia trên thế giới tập trung vào đại dương Thái Bình Dương bằng cách sử dụng Robinson, Miller Hình trụ hoặc hình chiếu khác


Cảm ơn Andre, điều đó khá hữu ích để hiểu vấn đề - nhưng vì tôi phải tạo ra những quả cầu như vậy trên cơ sở gần hàng ngày và với những quan điểm thay đổi, nó đòi hỏi rất nhiều công việc thủ công. Bạn có biết bất kỳ plugin-vv. để tự động hóa giải pháp của bạn?
dùng1523709

Khi bạn đã tạo một vòng tròn cắt, phần còn lại có thể được thực hiện bằng cách sử dụng GDAL ở cấp dòng lệnh bằng cách sử dụng tập lệnh bó.
AndreJ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.