我正在尝试使用qgis和“来自太空的世界” 投影http://spatialreference.org/ref/sr-org/6980/(本质上是正交投影)来创建球形视图。ArcGIS正确包装了形状,但是QGIS(2.01)产生了讨厌的工件。
我必须定期制作具有不同角度的地球仪,所以外面的人是否有解决此问题的想法?
我正在尝试使用qgis和“来自太空的世界” 投影http://spatialreference.org/ref/sr-org/6980/(本质上是正交投影)来创建球形视图。ArcGIS正确包装了形状,但是QGIS(2.01)产生了讨厌的工件。
我必须定期制作具有不同角度的地球仪,所以外面的人是否有解决此问题的想法?
Answers:
正如Andre所说,要使其正常工作,您需要在投影图层之前对其进行裁剪。安德烈(Andre)描述了一种手动方法,该方法在许多情况下都适用:将您的shapefile投影到具有与正交投影相同参数的方位角等距投影,创建一个覆盖半球的剪裁圆,该半球将在正交投影中可见,并且剪切shapefile。但是,由于投影到方位等距投影可能会导致与投影到正射投影类似的问题,因此该方法需要相当多的人工,并且不适用于所有投影参数。
这是一个脚本(现在也可以作为Clip to Hemisphere QGIS插件使用),该脚本采用稍有不同的方法:通过从正投影到源CRS投影一个圆,在原始shapefile的坐标参考系统中创建了一个裁剪层,但是另外确保覆盖整个可见半球,包括可见极。
这就是以30°N,110°E为中心的正交投影的裁剪层的外观:
然后,脚本将使用剪切层剪切当前选定的层,并将结果层添加到项目中。然后可以动态地或通过将其保存在正交CRS中将该层投影为正交投影:
这是脚本。确保将其保存在您的Python路径中,例如,作为“ cliportho.py”。然后,您可以使用将其导入QGIS Python控制台中import cliportho
。要剪辑图层,请调用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)
您必须将多边形数据裁剪到地球的可见部分,因为QGIS本身不会这样做。
我在这里写了一个教程:
编辑
您显示的图片实际上不是正交投影,因为它显示的是整个世界,而不仅仅是从外太空看到的可见的一半。对于世界地图,切割要容易一些,如下所述: