在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上搭建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/

Mapbox GL中的文本标注方法

好的地图标签应该是在介于一个邋遢的地图和一个美观的地图之间的。标签必须清楚地识别功能,同时不遮挡图。

The normal requirements for map labelling are to place labels as clearly as possible without any overlap. Regular maps just need to avoid label overlap for a single, fixed zoom level and rotation.

在Mapbox GL中好的标签位置是一个需要解决的困难问题。我们标签需要在任何缩放和旋转时工作。我们需要标签位置是连续的,缩放或旋转时标签不要跳来跳去。我们标签需要能无缝的跨越瓦片。我们需要支持在缩放时改变字体大小。并且一切都要快速。

Placement needs to support both horizontal labels, as well as curved labels which follow a line. Both types of labels need to behave smoothly when zooming and rotating. Labels can never overlap, even when rotating. Horizontal labels stay horizontal and curved labels rotate with the map. Labels are flipped to avoid being drawn upside down and curved labels smoothly slide along roads.

There is plenty of academic research on label placement, but most of this applies to maps with fixed rotation and with separate zoom levels. Dynamic maps with continuous zooming, panning, and rotation need a completely different approach. Our implementation expands on a paper by Been and Yap that establishes four ideal requirements for continuous and interactive labelling:

  1. 标签不应该在放大时消失,在缩小时出现。
  2. 标签不应该在平移时消失或出现,除非滑出视图。
  3. 标签不应该跳来跳去,而是应该被锚定。
  4. 标签的位置应该是确定的,无论你怎么到当前视图。

The paper provides guidance on implementing this for horizontal labels, but we go further by supporting rotation and curved labels.

我们的实现有两个步骤:

  1. 预处理
  2. 渲染

The rendering step needs to be fast so that Mapbox GL can rerender the entire map every frame for smooth interaction. Most of the placement work happens in the preprocessing step:

  1. 为每个标签生成锚点。
  2. 计算相对于锚各个字形的位置。
  3. 计算该标签和符号可以没有重叠显示的缩放级别。
  4. 计算标签可以显示的旋转范围。

生成锚点

Each label has an anchor. An anchor is the point at which a label is positioned when zooming or rotating.

Labels for point features have a single anchor, the point.

For lines, we want to show multiple labels so we interpolate along the line adding an anchor every x pixels. Distance between labels changes when zooming, so we add a minimum zoom level for each anchor to maintain appropriate spacing. Fewer labels are shown at lower zoom levels and more appear as you zoom in.

生成每个锚定位字形

For each piece of text we already have a list of glyphs and their positions, but these positions need to be adjusted for curved labels.

During the render step we can only shift glyphs along a straight line. To draw curved text we need to add multiple copies of glyphs — one for each line segment a glyph appears on. Each of these glyphs have minimum and maximum zoom levels that hide the glyph when it slides off the end of a segment so that only one instance of each original glyph is shown at the same time.

Usually these glyphs are completely hidden when out of range, but here they are shown with a reduced opacity:

限制缩放范围

To avoid label collisions, we need to restrict the zoom level at which a label is first shown. As you zoom in, labels get spaced further apart, opening room for new labels. Once a label is shown, it will not be hidden as you zoom in.

We use an R-tree that contains already-placed labels to narrow down which labels might collide. We then calculate the zoom level at which the two labels will fit side-by-side. It is safe to show the label for any zoom level higher than this one.

限制旋转范围

The next step is calculating how far the label can be rotated before it collides with other labels. There are two types of collisions: a curved label colliding with a horizontal label, and a horizontal label colliding with a horizontal label.

水平-横向碰撞

There are eight possible angles at which a pair of horizontal labels could collide. Each of these possible collisions is checked with some trigonometry.

弯曲-水平旋转碰撞

A curved-horizontal collision occurs when a corner of one label’s bounding box intersects an edge of the other label’s bounding box. For each of the eight bounding box corners, we calculate the angles at which a circle (formed by that point being rotated around the label’s anchor) intersects the edges of the other box. These are the angles at which a collision would begin and end.

无缝性

Mapbox GL下载当前显示范围和缩放级别的矢量瓦片。当新的瓦片下载完成,它们的标签位置已经被旧瓦片的标签占据,可能需要隐藏让位给一个更重要的标签。这将在尚未实现的步骤由解析处理。

Mapbox GL

访问Mapbox GL博客查看和谈论更多的设计和开发工作。地图文本标注只是设备上实时高品质的地图中的一个小而必要的部分。

原文:https://www.mapbox.com/blog/placing-labels/