![最终产品图片](https://i-blog.csdnimg.cn/blog_migrate/d1b929a927c26ffb9de4c45a8d13eaaa.png)
在本教程中,我将向您展示如何拍摄SVG地图并将其作为矢量投影到地球上。 为了执行将地图投影到球体上所需的数学转换,我们必须使用Python脚本来读取地图数据并将其转换为地球图像。 本教程假定您正在运行最新可用的Python 3.4。
Inkscape具有某种Python API,可用于执行各种操作。 但是,由于我们仅对变换形状感兴趣,因此编写一个独立的程序即可更容易,该程序可以自行读取和打印SVG文件。
1.设置地图格式
我们想要的地图类型称为等矩形图。 在等角线地图中,地点的经度和纬度与其在地图上的x和y位置相对应。 可以在Wikimedia Commons (这是带有美国各州的版本 )上找到一个等矩形的世界地图。
SVG坐标可以通过多种方式定义。 例如,它们可以相对于先前定义的点,也可以相对于原点绝对定义。 为了使生活更轻松,我们希望将地图中的坐标转换为绝对形式。 Inkscape可以做到这一点。 转到Inkscape首选项(在“ 编辑”菜单下),然后在“ 输入/输出” >“ SVG输出”下 ,将“ 路径字符串格式”设置为“ 绝对” 。
![Inkscape首选项](https://cms-assets.tutsplus.com/uploads/users/715/posts/24275/image/Selection_018.png)
Inkscape不会自动转换坐标。 您必须在路径上执行某种转换才能使这种情况发生。 最简单的方法是选择所有内容,然后按一下向上和向下箭头中的每一个,将其上下移动。 然后重新保存文件。
2.启动您的Python脚本
创建一个新的Python文件。 导入以下模块:
import sys
import re
import math
import time
import datetime
import numpy as np
import xml.etree.ElementTree as ET
您将需要安装NumPy ,该库可让您执行某些矢量运算,例如点积和叉积。
3.透视投影的数学
将三维空间中的点投影到2D图像中涉及找到从相机到该点的向量,然后将该向量分成三个垂直向量。
垂直于相机矢量(相机面对的方向)的两个局部矢量成为正交投影图像的x和y坐标。 平行于相机矢量的局部矢量变为点的z距离。 要将正交图像转换为透视图像,请分别将x和y坐标除以z距离。
在这一点上,定义某些相机参数是有意义的。 首先,我们需要知道相机在3D空间中的位置。 将其x , y和z坐标存储在字典中。
camera = {'x': -15, 'y': 15, 'z': 30}
地球将位于原点,因此将照相机朝向其方位是有意义的。 这意味着相机方向向量将与相机位置相反。
cameraForward = {'x': -1*camera['x'], 'y': -1*camera['y'], 'z': -1*camera['z']}
仅仅确定相机朝向哪个方向还不够,还需要确定相机的旋转方向。 通过定义一个垂直于cameraForward
向量的向量来做到这cameraForward
。
cameraPerpendicular = {'x': cameraForward['y'], 'y': -1*cameraForward['x'], 'z': 0}
1.定义有用的向量函数
在程序中定义某些矢量函数将非常有帮助。 定义矢量幅度函数:
#magnitude of a 3D vector
def sumOfSquares(vector):
return vector['x']**2 + vector['y']**2 + vector['z']**2
def magnitude(vector):
return math.sqrt(sumOfSquares(vector))
我们需要能够将一个向量投影到另一个向量上。 由于此操作涉及点积,因此使用NumPy库要容易得多。 但是,NumPy采用列表形式的向量,没有显式的“ x”,“ y”,“ z”标识符,因此我们需要一个函数将向量转换为NumPy向量。
#converts dictionary vector to list vector
def vectorToList (vector):
return [vector['x'], vector['y'], vector['z']]
#projects u onto v
def vectorProject(u, v):
return np.dot(vectorToList (v), vectorToList (u))/magnitude(v)
很高兴有一个函数可以在给定矢量的方向上为我们提供单位矢量:
#get unit vector
def unitVector(vector):