地图渲染的神器mapnik

mapnik真是做地图渲染的神器,搭配mod_tile便能轻松的发布地图服务。

这是使用高德地图的原始数据,通过TileMill简单配置得到效果。

mapnik

mapnik

mapnik

mapnik

mapnik

mapnik

mapnik

mapnik

mapnik

mapnik

在ec2上使用instavpn搭建vpn服务

今天发现一个非常易用的vpn软件instavpn。使用非常简单,用过的都说好。

the most user-friendly L2TP/IPsec VPN server

instavpn

通过ssh连接上的我的ec2主机。

安装instavpn

curl -sS https://sockeye.cc/instavpn.sh | sudo bash

然后没有然后了,这已经安装完成了。

现在可以通过http://IP-ADDRESS:8080访问web的管理界面。这里可以监控流量使用情况、配置用户。

由于ec2有Security Groups的权限控制。在连接之前,需要把L2TP和web管理工具使用的相关端口打开,分别是UDP 500 1701 4500和TCP 8080。

现在就可以连接我们的VPN了。

vpn

vpn

在ubuntu 12.04 LTS上搭建OpenStreetMap切片服务

为了简化配置,直接添加别人发布的软件仓库,里面包含发布地图服务需要的一切软件。

sudo add-apt-repository ppa:kakrueger/openstreetmap

更新apt

sudo apt-get update

安装libapache2-mod-tile

sudo apt-get install libapache2-mod-tile

这里会进行配置并创建数据库,需要注意的是,导入数据是需要使用这个用户操作。如果没有配置不对,可以通过sudo dpkg-reconfigure openstreetmap-postgis-db-setup重新配置。我这里加上了当前用户,如www-data,ubuntu。

下载osm数据,全球数据可以到http://planet.openstreetmap.org下载,同时http://download.geofabrik.de为我们提供了不同国家的小数据。我只下载了中国的

wget http://download.geofabrik.de/asia/china-latest.osm.pbf

导入数据库,如果数据大,这一步会非常耗时。调整osm2pgsql参数可加快速度。 这里使用的EC2主机,分配给100M内存和1个处理器,大概用十几分钟。由于EC2性能太低,不得已加上--cache-strategy sparse参数。

osm2pgsql --slim -C 100 --cache-strategy sparse --number-processes 1 china-latest.osm.pbf

设置数据导入时间

sudo touch /var/lib/mod_tile/planet-import-complete

重启渲染服务

sudo /etc/init.d/renderd restart

测试

http://localhost/osm/slippymap.html

http://localhost/osm/0/0/0.png

slippymap

PS: 如果地图显示不出来,查看渲染的日志

tail -f /var/log/syslog |grep renderd

数据更新

  • 自动实时更新

mod-tile中提供了增量数据更新工具openstreetmap-tiles-update-expire。试用出现不少问题,并没能成功。

  • 增量更新

下载增量数据,http://planet.openstreetmap.org/replication/可以找到每天、没小时和每分钟的增量更新包。部分区域每天更新的更新包可以从http://download.geofabrik.de/asia/china-updates/下载。

导入增量数据

osm2pgsql --append --slim -C 100 --cache-strategy sparse --number-processes 1 788.osc.gz

设置数据导入时间

sudo touch /var/lib/mod_tile/planet-import-complete

  • 完全更新

重新下载osm数据并导入数据。

设置数据导入时间

sudo touch /var/lib/mod_tile/planet-import-complete

PS:如果地图没有更新,可调用render_old重新渲染旧切片。同时把浏览器的缓存清除掉。

参考

http://switch2osm.org/serving-tiles/building-a-tile-server-from-packages/

http://blog.csdn.net/goldenhawking/article/details/7952303

使用Android toolchain编译GDAL

通常在Android上使用ndk-build编译C++代码。但大多开源库中并没有提供Android.mk文件。

这里只能使用单独的toolchain来编译。关于toolchain可参考 http://blog.csdn.net/smfwuxiao/article/details/6587709

准备工作

创建一套工具链

/Users/chaohan/Documents/android-ndk-r9d/build/tools/make-standalone-toolchain.sh --platform=android-8 --stl=stlport --install-dir=/Users/chaohan/Documents/android-8-toolchain

由于我的代码使用了stlport,这里增加--stl=stlport参数。生成的工具链的位置通过--install-dir设置。

设置环境变量

export PATH=$PATH:/Users/chaohan/Documents/android-8-toolchain/bin/

下载代码

git clone https://github.com/OSGeo/gdal.git

代码中的config.sub config.guess不认识android环境,这里需要更新

cd gdal
rm config.sub config.guess
wget http://git.savannah.gnu.org/cgit/config.git/plain/config.sub
wget http://git.savannah.gnu.org/cgit/config.git/plain/config.guess

编译

CFLAGS="-mthumb" CXXFLAGS="-mthumb" LIBS="-lstdc++"  ./configure --host=arm-linux-androideabi --prefix=/Users/chaohan/Documents/Git/gdal/out --without-gif --without-jpeg --with-threads --with-ogr  --with-geos --with-libz=internal

make

make install

我这里make时遇到isinf不认识。通过修改cpl_port.h文件去掉,不影响大局。

使用

Android.mk中增加

定义预编译静态库

include $(CLEAR_VARS)
LOCAL_MODULE := gdal
LOCAL_SRC_FILES := libgdal.a
include $(PREBUILT_STATIC_LIBRARY)

设置依赖

LOCAL_STATIC_LIBRARIES := gdal

参考

https://github.com/nutiteq/gdal/wiki/AndroidHowto http://trac.osgeo.org/gdal/wiki/BuildingForAndroid

问题和感想

在编译过程中遇到很多问题。主要的问题是

  • 运行configure出错,不认识arm-linux-androideabi。通过更新config.sub config.guess解决。

  • stl版本冲突。默认toolchain使用gnustl,而我的库使用stlport。通过在make-standalone-toolchain指定--stl=stlport解决。

  • 第三方库重定义。gdal包含gif、jpeg等库,我的库也包含它。通过在configure时--without-gif --without-jpeg去除。

真心觉得C++的编译环境复杂,不同平台有不同的编译工具。从make、autoconf、cmake、ndk-build、gyp等脚本到vs、xcode等IDE,用起来真是有各种坑。 希望C++也能有个Maven、cocoaPods、npm之类的工具解决软件包之间的依赖问题。

Drawing Text with Signed Distance Fields in Mapbox GL

上周,Ansis解释了在Mapbox GL标签被放置的方法,但一旦我们知道在何处放置标签,我们还是要弄清楚如何绘制他们。

甚至在2014年,OpenGL诞生后超过二十年,渲染文本也是不容易的,因为OpenGL的只能画出三角形和线条。地图渲染文本是更加困难的,因为我们需要在许多不同大小的字符,当用户旋转地图时文本位置的每帧都会变化。此外,我们需要画文本光晕已得到更好的对比度。

properties

使用字形图集

对于栅格化文字一般是使用开源库FreeType。绘制文本通常的工作方式是通过FreeType在临时缓冲区生成字形的单色位图,然后将缓冲区中的像素逐个混合目标位图正确的位置上去。这意味着,我们可以预先将需要的所有字形的染到一个共享的纹理中,称为纹理图集,然后为每个字形创建两个三角形映射到纹理上。Nicolas Rougier的freetype-gl也是通过这种方法实现的。

glyph-drawing

这很好的工作,直到你开始旋转文字。虽然OpenGL的线性插值是相当好的,但它仍然看起来相当模糊的,所以只是旋转字形并不能满足我们。

Signed Distance Fields

Distance fields (or distance transforms) have been around for ages and have lots of useful properties. In a distance field, every pixel indicates the distance to the closest “element”. Valve introduced the approach of using distance fields for rendering sharp decals in computer games a couple of years ago. And we decided to do just that when rendering glyphs as well.

To render text with signed distance fields, we create a glyph texture at font size 24 that stores the distance to the next outline in every pixel, rather than the actual value itself:

opensans-regular

Inside of a glyph, the distance is negative; outside it’s positive. As an additional optimization, to fit into a one-byte unsigned integer, we’re shifting everything so that values between 192 and 255 indicate “inside” a glyph and values from 0 to 191 indicate outside, plus we clamp the overflowing values. This gives the appearance above of a range of values from black (0) to white (255). In essence, we are using the pixel color values in the texture as a measure of distance from glyph edges.

Like in the previous technique, we create two triangles to form a quad and assign the corresponding texture coordinates so that the distance map of that glyph gets mapped onto that rectangle.

We enable OpenGL’s linear interpolation so that we get a smoothly scaled image. Then, the important part is the alpha test. Depending on how far we want to buffer the glyph, we choose a cutoff value and assign 1 as the alpha value to all pixels that are within the glyph outline and 0 to the ones outside. To get an antialiased look, we’re creating a small alpha gradient around the cutoff value with the smoothstep function. The entire pixel shader looks like this:

precision mediump float;

uniform sampler2D u_texture;
uniform vec4 u_color;
uniform float u_buffer;
uniform float u_gamma;

varying vec2 v_texcoord;

void main() {
    float dist = texture2D(u_texture, v_texcoord).r;
    float alpha = smoothstep(u_buffer - u_gamma, u_buffer + u_gamma, dist);
    gl_FragColor = vec4(u_color.rgb, alpha * u_color.a);
}

你可以在这个演示试试文本渲染。

Using signed distance fields for font rendering has a few advantages:

  • Free accurate halos by simply changing the alpha testing threshold.
  • Arbitrary text rotation.
  • Arbitrary text size, though it starts looking a bit off at very large text sizes.
  • A bitmap of a 24px glyph is about 20% smaller than the vector representation of that glyph.

There are a few minor drawbacks too:

  • Text appears a little more rounded.
  • No support for font hinting.

Font hinting changes the glyph outlines so that they fit better in a pixel grid, which is especially useful when rendering small text. However, FreeType disables hinting anyway as soon as you rotate a glyph with a transformation matrix. Additionally, many of our maps are being displayed on very high density (high-DPI or “retina”) screens built into smartphones or tablets, so hinting is much less important on these screens.

原文:https://www.mapbox.com/blog/text-signed-distance-fields/