<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>绿色记忆 &#187; GIS</title>
	<atom:link href="https://blog.gmem.cc/category/work/gis/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.gmem.cc</link>
	<description></description>
	<lastBuildDate>Mon, 06 Apr 2026 12:46:48 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.14</generator>
	<item>
		<title>Cesium学习笔记</title>
		<link>https://blog.gmem.cc/cesium-study-note</link>
		<comments>https://blog.gmem.cc/cesium-study-note#comments</comments>
		<pubDate>Tue, 17 Mar 2015 01:46:14 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[GIS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[WebGL]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=4739</guid>
		<description><![CDATA[<p>Cesium简介 Cesium是一个基于JavaScript的开源框架，可用于在浏览器中绘制3D的地球，并在其上绘制地图（支持多种格式的瓦片服务），该框架不需要任何插件支持，但是浏览器必须支持WebGL。 Cesium支持多种数据可视化方式，可以绘制各种几何图形、导入图片，甚至3D模型。同时，Cesium还支持基于时间轴的动态数据展示，例如，我们可以用它绘制卫星运行轨迹。 Cesium HelloWorld 下面的例子在浏览器中显示一个太空背景、具有地图覆盖的3D地球： [crayon-69d4c2536478e599547526/] [crayon-69d4c25364794198197113/] 可以加快时间的运行，并且模拟日光照射效果： [crayon-69d4c25364797836419219/] 通过以下代码，可以设置镜头位置与指向，Cesium的Camera对象提供了多种操控镜头的方法： [crayon-69d4c25364799324480326/] 可以添加若干实体，实体可以用于组织多个可视化对象，下面的例子模拟了卫星波束的覆盖范围： [crayon-69d4c2536479d105201241/] 空间数据可视化 Cesium提供Entity API来绘制空间数据，例如点、标记、标签、线、3D模型、形状、立体形状（volume）。 Entity API简介 Cesium提供两类API： 面向图形开发人员的底层API，通常称为“Primitive API”。该API暴露最小限度的抽象，使用图形学术语，具有很大的灵活性，需要具有图形学编程的知识 <a class="read-more" href="https://blog.gmem.cc/cesium-study-note">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/cesium-study-note">Cesium学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">Cesium简介</span></div>
<p>Cesium是一个基于JavaScript的开源框架，可用于在浏览器中绘制3D的地球，并在其上绘制地图（支持多种格式的瓦片服务），该框架不需要任何插件支持，但是浏览器必须支持WebGL。</p>
<p>Cesium支持多种数据可视化方式，可以绘制各种几何图形、导入图片，甚至3D模型。同时，Cesium还支持基于时间轴的动态数据展示，例如，我们可以用它绘制卫星运行轨迹。</p>
<div class="blog_h1"><span class="graybg">Cesium HelloWorld</span></div>
<p>下面的例子在浏览器中显示一个太空背景、具有地图覆盖的3D地球：</p>
<pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"&gt;
&lt;title&gt;Cesium Example&lt;/title&gt;
&lt;script src="Cesium-1.7.1/Build/CesiumUnminified/Cesium.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" type="text/css" href="Cesium-1.7.1/Build/CesiumUnminified/Widgets/widgets.css"&gt;&lt;/link&gt;
&lt;style&gt;
html,body,#cesiumContainer {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div id="cesiumContainer"&gt;&lt;/div&gt;
    &lt;script type="text/javascript" src="index.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><br />
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer( 'cesiumContainer', {
    animation : false,//是否创建动画小器件，左下角仪表
    baseLayerPicker : false,//是否显示图层选择器
    fullscreenButton : false,//是否显示全屏按钮
    geocoder : false,//是否显示geocoder小器件，右上角查询按钮
    homeButton : false,//是否显示Home按钮
    infoBox : false,//是否显示信息框
    sceneModePicker : false,//是否显示3D/2D选择器
    selectionIndicator : false,//是否显示选取指示器组件
    timeline : false,//是否显示时间轴
    navigationHelpButton : false,//是否显示右上角的帮助按钮
    scene3DOnly : true,//如果设置为true，则所有几何图形以3D模式绘制以节约GPU资源
    clock : new Cesium.Clock(),//用于控制当前时间的时钟对象
    selectedImageryProviderViewModel : undefined,//当前图像图层的显示模型，仅baseLayerPicker设为true有意义
    imageryProviderViewModels : Cesium.createDefaultImageryProviderViewModels(),//可供BaseLayerPicker选择的图像图层ProviderViewModel数组
    selectedTerrainProviderViewModel : undefined,//当前地形图层的显示模型，仅baseLayerPicker设为true有意义
    terrainProviderViewModels : Cesium.createDefaultTerrainProviderViewModels(),//可供BaseLayerPicker选择的地形图层ProviderViewModel数组
    imageryProvider : new Cesium.OpenStreetMapImageryProvider( {
        credit :'',
        url : '//192.168.0.89:5539/planet-satellite/'
    } ),//图像图层提供者，仅baseLayerPicker设为false有意义
    terrainProvider : new Cesium.EllipsoidTerrainProvider(),//地形图层提供者，仅baseLayerPicker设为false有意义
    skyBox : new Cesium.SkyBox({
        sources : {
          positiveX : 'Cesium-1.7.1/Skybox/px.jpg',
          negativeX : 'Cesium-1.7.1/Skybox/mx.jpg',
          positiveY : 'Cesium-1.7.1/Skybox/py.jpg',
          negativeY : 'Cesium-1.7.1/Skybox/my.jpg',
          positiveZ : 'Cesium-1.7.1/Skybox/pz.jpg',
          negativeZ : 'Cesium-1.7.1/Skybox/mz.jpg'
        }
    }),//用于渲染星空的SkyBox对象
    fullscreenElement : document.body,//全屏时渲染的HTML元素,
    useDefaultRenderLoop : true,//如果需要控制渲染循环，则设为true
    targetFrameRate : undefined,//使用默认render loop时的帧率
    showRenderLoopErrors : false,//如果设为true，将在一个HTML面板中显示错误信息
    automaticallyTrackDataSourceClocks : true,//自动追踪最近添加的数据源的时钟设置
    contextOptions : undefined,//传递给Scene对象的上下文参数（scene.options）
    sceneMode : Cesium.SceneMode.SCENE3D,//初始场景模式
    mapProjection : new Cesium.WebMercatorProjection(),//地图投影体系
    dataSources : new Cesium.DataSourceCollection()
    //需要进行可视化的数据源的集合
} );
var scene = viewer.scene;
var canvas = viewer.canvas;
var clock = viewer.clock;
var camera = viewer.scene.camera;
var entities = viewer.entities;</pre>
<p>可以加快时间的运行，并且模拟日光照射效果：</p>
<pre class="crayon-plain-tag">//加快时钟的运行
clock.multiplier = 0.1 * 60 * 60;
//阳光照射区域高亮
scene.globe.enableLighting = true;</pre>
<p>通过以下代码，可以设置镜头位置与指向，Cesium的Camera对象提供了多种操控镜头的方法：</p>
<pre class="crayon-plain-tag">//设置镜头位置与方向
camera.setView( {
    //镜头的经纬度、高度。镜头默认情况下，在指定经纬高度俯视（pitch=-90）地球
    position : Cesium.Cartesian3.fromDegrees( 116.3, 39.9, 100000000 ),//北京100000公里上空
    //下面的几个方向正好反映默认值
    heading : Cesium.Math.toRadians( 0 ),
    pitch : Cesium.Math.toRadians( -90 ),
    roll : Cesium.Math.toRadians( 0 )
} );
//让镜头飞行（动画）到某个地点和方向
setTimeout( function()
{
    camera.flyTo( {
        destination : Cesium.Cartesian3.fromDegrees( 116, 15, 6000000 ),
        orientation : {
            heading : Cesium.Math.toRadians( -15 ),
            pitch : Cesium.Math.toRadians( -65 ),
            roll : Cesium.Math.toRadians( 0 )
        },
        duration : 3,//动画持续时间
        complete : function()//飞行完毕后执行的动作
        {
            addEntities();
        }
    } );
}, 1000 );

//监听键盘事件，用于平移或者旋转镜头
var ellipsoid = scene.globe.ellipsoid;
canvas.onclick = function()
{
    canvas.focus();
};
var flags = {
    looking : false,
    rotateLeft : false,
    rotateRight : false,
    moveUp : false,
    moveDown : false,
    moveLeft : false,
    moveRight : false
};
var handler = new Cesium.ScreenSpaceEventHandler( canvas );
function getFlagForKeyCode( keyCode )
{
    switch ( keyCode )
    {
        case 'W'.charCodeAt( 0 ) : //向下平移镜头
            return 'moveDown';
        case 'S'.charCodeAt( 0 ) : //向上平移镜头
            return 'moveUp';
        case 'A'.charCodeAt( 0 ) : //向右平移镜头
            return 'moveRight';
        case 'D'.charCodeAt( 0 ) : //向左平移镜头
            return 'moveLeft';
        case 'Q'.charCodeAt( 0 ) : //向右旋转镜头
            return 'rotateRight';
        case 'E'.charCodeAt( 0 ) : //向左旋转镜头
            return 'rotateLeft';
        default :
            return undefined;
    }
}
document.addEventListener( 'keydown', function( e )
{
    var flagName = getFlagForKeyCode( e.keyCode );
    if ( typeof flagName !== 'undefined' )
    {
        flags[flagName] = true;
    }
}, false );
document.addEventListener( 'keyup', function( e )
{
    var flagName = getFlagForKeyCode( e.keyCode );
    if ( typeof flagName !== 'undefined' )
    {
        flags[flagName] = false;
    }
}, false );
viewer.clock.onTick.addEventListener( function( clock )
{
    var cameraHeight = ellipsoid.cartesianToCartographic( camera.position ).height;
    var moveRate = cameraHeight / 100.0;

    if ( flags.rotateLeft )
    {
        camera.rotateLeft( 0.01 );
    }
    if ( flags.rotateRight )
    {
        camera.rotateRight( 0.01 );
    }
    if ( flags.moveUp )
    {
        camera.moveUp( moveRate );
    }
    if ( flags.moveDown )
    {
        camera.moveDown( moveRate );
    }
    if ( flags.moveLeft )
    {
        camera.moveLeft( moveRate );
    }
    if ( flags.moveRight )
    {
        camera.moveRight( moveRate );
    }
} );</pre>
<p>可以添加若干实体，实体可以用于组织多个可视化对象，下面的例子模拟了卫星波束的覆盖范围：</p>
<pre class="crayon-plain-tag">/**
 * 根据偏移量计算目标点经纬度
 * @param {} start  起始点经纬度数组，单位度
 * @param {} offset 东北方向的偏移量，单位米
 * @param {} 目标点经纬度数组，单位度
 */
function offsetToLongLat( start, offset )
{
    var er = 6378137;
    var lat = parseFloat( start[1] );
    var lon = parseFloat( start[0] );
    var dn = parseFloat( offset[1] );
    var de = parseFloat( offset[0] );

    dLat = dn / er;
    var pi = Math.PI;
    var dLon = de / ( er * Math.cos( pi * lat / 180 ) )
    return [
        lon + dLon * 180 / pi, lat + dLat * 180 / pi
    ];
}
/**
 * 通过绘制三角形模拟卫星光束效果
 * @param {} entities 实体集
 * @param {} stltPos 卫星三维坐标数组
 * @param {} points 地面点
 * @param {} color CSS颜色代码，例如#FF0000
 */
function lightShinePolygon( entities, stltPos, points, color )
{
    for ( var i = 0; i &lt; points.length; i += 2 )
    {
        var array = [
            stltPos[0], stltPos[1], stltPos[2], points[i], points[i + 1], 0
        ];
        if ( i + 2 == points.length )
        {
            array.push( points[0] );
            array.push( points[1] );
        }
        else
        {
            array.push( points[i + 2] );
            array.push( points[i + 3] );
        }
        array.push( 0 );
        entities.add( {
            polygon : {
                hierarchy : Cesium.Cartesian3.fromDegreesArrayHeights( array ),
                perPositionHeight : true,
                outline : false,
                material : Cesium.Color.fromAlpha( Cesium.Color.fromCssColorString( color ), .1 )
            }
        } );
    }
}
/**
 * 添加实体
 */
function addEntities()
{
    //卫星一
    {
        var stltPos = [
            110.0, 40.0, 2500000
        ];
        entities.add( {
            position : Cesium.Cartesian3.fromDegrees.apply( this, stltPos ),
            billboard : {
                image : 'images/satellite-1.png',
                horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
                verticalOrigin : Cesium.VerticalOrigin.BOTTOM, //垂直方向位置计算基准设为底部，默认中心
                width : 92,
                height : 36
            }
        } );
        //一个多边形覆盖范围
        {
            var color = '#FF0000';
            //模拟光照效果的若干多边形
            var points = [
                100, 48, 110, 40, 115, 40, 120, 43, 120, 55
            ];
            lightShinePolygon( entities, stltPos, points, color );
            //地面多边形
            entities.add( {
                polygon : {
                    hierarchy : Cesium.Cartesian3.fromDegreesArray( points ),
                    outline : true,
                    outlineColor : Cesium.Color.fromAlpha( Cesium.Color.fromCssColorString( color ), .4 ),
                    material : Cesium.Color.fromAlpha( Cesium.Color.fromCssColorString( color ), .3 )
                }
            } );
        }

        //一个圆形覆盖范围
        {
            var r = 600000;//半径
            var color = '#0000FF';
            //圆心
            var ecLong = 110.0;
            var ecLat = 30.0;
            var ec = Cesium.Cartesian3.fromDegrees( ecLong, ecLat, 0 );
            //模拟光照效果的若干多边形
            var points = [];
            for ( var i = 0; i &lt; 360; i += 30 )
            {
                var coord = offsetToLongLat( [
                    ecLong, ecLat
                ], [
                    Math.cos( Math.PI * i / 180 ) * r, Math.sin( Math.PI * i / 180 ) * r
                ] );
                points.push( coord[0] );
                points.push( coord[1] );
            }
            lightShinePolygon( entities, stltPos, points, color );
            //圆
            viewer.entities.add( {
                position : ec,
                ellipse : {
                    semiMinorAxis : r,
                    semiMajorAxis : r,
                    height : 0.0,
                    outline : true,
                    outlineColor : Cesium.Color.fromAlpha( Cesium.Color.fromCssColorString( color ), .4 ),
                    material : Cesium.Color.fromAlpha( Cesium.Color.fromCssColorString( color ), .3 )
                }
            } );
        }
    }
}</pre>
<div class="blog_h1"><span class="graybg">空间数据可视化</span></div>
<p>Cesium提供Entity API来绘制空间数据，例如点、标记、标签、线、3D模型、形状、立体形状（volume）。</p>
<div class="blog_h2"><span class="graybg">Entity API简介</span></div>
<p>Cesium提供两类API：</p>
<ol>
<li>面向图形开发人员的底层API，通常称为“Primitive API”。该API暴露最小限度的抽象，使用图形学术语，具有很大的灵活性，需要具有图形学编程的知识</li>
<li>高级别的数据驱动的API，称为“Entity API”。该API使用一致性设计的、高级别的对象来管理一组相关性的可视化对象，其底层使用Primitive API</li>
</ol>
<p>下面是Entity API的简单例子，用红色半透明区域标记出美国怀俄明州：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer('cesiumContainer'); //创建一个查看器（Viewer widget）
var wyoming = viewer.entities.add({  //添加一个实体，仅需要传递一个简单JSON对象，返回值是一个Entity对象
  name : 'Wyoming',
  polygon : {
    hierarchy : Cesium.Cartesian3.fromDegreesArray([//一组地理坐标
                              -109.080842,45.002073,
                              -105.91517,45.002073,
                              -104.058488,44.996596,
                              -104.053011,43.002989,
                              -104.053011,41.003906,
                              -105.728954,40.998429,
                              -107.919731,41.003906,
                              -109.04798,40.998429,
                              -111.047063,40.998429,
                              -111.047063,42.000709,
                              -111.047063,44.476286,
                              -111.05254,45.002073]),
    material : Cesium.Color.RED.withAlpha(0.5), //材质
    outline : true, //是否显示轮廓
    outlineColor : Cesium.Color.BLACK //轮廓的颜色
  }
});
viewer.zoomTo(wyoming);//缩放、平移视图使实体可见 </pre>
<div class="blog_h2"><span class="graybg">形状与立体（Shapes and Volumes）</span></div>
<div class="blog_h3"><span class="graybg">支持的形状与立体列表</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 120px; text-align: center;">形状 </td>
<td style="text-align: center;"> 代码示例</td>
</tr>
</thead>
<tbody>
<tr>
<td>立方体<br />(Boxes)</td>
<td>
<pre class="crayon-plain-tag">var blueBox = viewer.entities.add({
    name : 'Blue box',
     //中心的位置
    position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
    box : {
        //长宽高
        dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
        material : Cesium.Color.BLUE
    }
});

var redBox = viewer.entities.add({
    name : 'Red box with black outline',
    position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0),
    box : {
        dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
        material : Cesium.Color.RED,
        outline : true, //显示轮廓
        outlineColor : Cesium.Color.BLACK
    }
});

var outlineOnly = viewer.entities.add({
    name : 'Yellow box outline',
    position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 300000.0),
    box : {
        dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
        fill : false,  //不显示填充
        outline : true,
        outlineColor : Cesium.Color.YELLOW
    }
});</pre>
</td>
</tr>
<tr>
<td>圆和椭圆<br />(Circles Ellipses)</td>
<td>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer('cesiumContainer');
//浮空的绿色圆形
var greenCircle = viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(-111.0, 40.0, 150000.0),
    name : 'Green circle at height',
    ellipse : {
        semiMinorAxis : 300000.0,
        semiMajorAxis : 300000.0,
        height: 200000.0, //浮空
        material : Cesium.Color.GREEN
    }
});
//红色椭圆形，位于地表，带轮廓
var redEllipse = viewer.entities.add({
    //不带高度
    position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
    name : 'Red ellipse on surface with outline',
    ellipse : {
        semiMinorAxis : 250000.0,
        semiMajorAxis : 400000.0,
        material : Cesium.Color.RED.withAlpha(0.5),
        outline : true,
        outlineColor : Cesium.Color.RED
    }
});
//蓝色椭圆柱，旋转了角度
var blueEllipse = viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 100000.0),
    name : 'Blue translucent, rotated, and extruded ellipse',
    ellipse : {
        semiMinorAxis : 150000.0,
        semiMajorAxis : 300000.0,
        extrudedHeight : 200000.0,  //拉伸
        rotation : Cesium.Math.toRadians(45), //旋转
        material : Cesium.Color.BLUE.withAlpha(0.7),
        outline : true
    }
});

viewer.zoomTo(viewer.entities);</pre>
</td>
</tr>
<tr>
<td>走廊<br />(Corridor)</td>
<td>
<pre class="crayon-plain-tag">var redCorridor = viewer.entities.add({
    name : 'Red corridor on surface with rounded corners and outline',
    corridor : {
        positions : Cesium.Cartesian3.fromDegreesArray([
                                                        -100.0, 40.0,
                                                        -105.0, 40.0,
                                                        -105.0, 35.0
                                                    ]),
                                                    width : 200000.0,
        material : Cesium.Color.RED.withAlpha(0.5),
        outline : true,
        outlineColor : Cesium.Color.RED
    }
});

var greenCorridor = viewer.entities.add({
    name : 'Green corridor at height with mitered corners',
    corridor : {
        positions : Cesium.Cartesian3.fromDegreesArray(
        [    -90.0, 40.0,
             -95.0, 40.0,
             -95.0, 35.0
        ]),
        height: 100000.0,
        width : 200000.0,
        cornerType: Cesium.CornerType.MITERED,
        material : Cesium.Color.GREEN
    }
});

var blueCorridor = viewer.entities.add({
    name : 'Blue extruded corridor with beveled corners and outline',
    corridor : {
        positions : Cesium.Cartesian3.fromDegreesArray(
        [    80.0, 40.0,
             -85.0, 40.0,
             -85.0, 35.0
        ]),
        height : 200000.0,
        extrudedHeight : 100000.0,
        width : 200000.0,
        cornerType: Cesium.CornerType.BEVELED,
        material : Cesium.Color.BLUE.withAlpha(0.5),
        outline : true,
        outlineColor : Cesium.Color.BLUE
    }
});</pre>
</td>
</tr>
<tr>
<td>圆柱和圆锥<br />(Cylinder Cones)</td>
<td> <br />
<pre class="crayon-plain-tag">var greenCylinder = viewer.entities.add({
    name : 'Green cylinder with black outline',
    position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 200000.0),
    cylinder : { //圆柱
        length : 400000.0,
        topRadius : 200000.0,
        bottomRadius : 200000.0,
        material : Cesium.Color.GREEN,
        outline : true,
        outlineColor : Cesium.Color.DARK_GREEN
    }
});

var redCone = viewer.entities.add({
    name : 'Red cone',
    position: Cesium.Cartesian3.fromDegrees(-105.0, 40.0, 200000.0),
    cylinder : {//圆锥
        length : 400000.0,
        topRadius : 0.0,
        bottomRadius : 200000.0,
        material : Cesium.Color.RED
    }
});</pre>
</td>
</tr>
<tr>
<td>多边形<br />(Polygons)</td>
<td>
<pre class="crayon-plain-tag">var redPolygon = viewer.entities.add({
    name : '贴着地表的多边形',
    polygon : {
        hierarchy : Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0,
                                                        -115.0, 32.0,
                                                        -107.0, 33.0,
                                                        -102.0, 31.0,
                                                        -102.0, 35.0]),
        material : Cesium.Color.RED
    }
});

var greenPolygon = viewer.entities.add({
    name : '绿色拉伸多边形',
    polygon : {
        hierarchy : Cesium.Cartesian3.fromDegreesArray([-108.0, 42.0,
                                                        -100.0, 42.0,
                                                        -104.0, 40.0]),
        extrudedHeight: 500000.0,
        material : Cesium.Color.GREEN
    }
});

var orangePolygon = viewer.entities.add({
    name : '每个顶点具有不同拉伸高度的橘色多边形',
    polygon : {
        hierarchy : Cesium.Cartesian3.fromDegreesArrayHeights(
            [-108.0, 25.0, 100000,
             -100.0, 25.0, 100000,
             -100.0, 30.0, 100000,
             -108.0, 30.0, 300000]),
        extrudedHeight: 0,
        perPositionHeight : true,
        material : Cesium.Color.ORANGE,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});

var bluePolygon = viewer.entities.add({
    name : '具有挖空效果的蓝色多边形',
    polygon : {
        hierarchy : {
            positions : Cesium.Cartesian3.fromDegreesArray(
                [-99.0, 30.0,
                 -85.0, 30.0,
                 -85.0, 40.0,
                 -99.0, 40.0]),
            holes : [{
                positions : Cesium.Cartesian3.fromDegreesArray([
                    -97.0, 31.0,
                    -97.0, 39.0,
                    -87.0, 39.0,
                    -87.0, 31.0
                ]),
                holes : [{
                    positions : Cesium.Cartesian3.fromDegreesArray([
                        -95.0, 33.0,
                        -89.0, 33.0,
                        -89.0, 37.0,
                        -95.0, 37.0
                    ]),
                    holes : [{
                        positions : Cesium.Cartesian3.fromDegreesArray([
                            -93.0, 34.0,
                            -91.0, 34.0,
                            -91.0, 36.0,
                            -93.0, 36.0
                        ])
                    }]
                }]
            }]
        },
        material : Cesium.Color.BLUE,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});</pre>
</td>
</tr>
<tr>
<td>多段线<br />(Polylines)</td>
<td>
<pre class="crayon-plain-tag">var redLine = viewer.entities.add({
    name : '沿着地球表面的红线',
    polyline : {
        positions : Cesium.Cartesian3.fromDegreesArray(
            [-75, 35,
             -125, 35]),
        width : 5,
        material : Cesium.Color.RED
    }
});

var glowingLine = viewer.entities.add({
    name : '具有发光效果的线',
    polyline : {
        positions : Cesium.Cartesian3.fromDegreesArray(
            [-75, 37, -125, 37]
        ),
        width : 10,
        material : new Cesium.PolylineGlowMaterialProperty({
            glowPower : 0.2,
            color : Cesium.Color.BLUE
        })
    }
});

var orangeOutlined = viewer.entities.add({
    name : '具有一定高度的线',
    polyline : {
        positions : Cesium.Cartesian3.fromDegreesArrayHeights(
            [-75, 39, 250000,-125, 39, 250000]
        ),
        width : 5,
        material : new Cesium.PolylineOutlineMaterialProperty({
            color : Cesium.Color.ORANGE,
            outlineWidth : 2,
            outlineColor : Cesium.Color.BLACK
        })
    }
});

var yellowLine = viewer.entities.add({
    name : '不贴着地表的线',
    polyline : {
        positions : Cesium.Cartesian3.fromDegreesArrayHeights(
            [-75, 43, 500000,-125, 43, 500000]
        ),
        width : 3,
        followSurface : false,  //是否贴着地表
        material : Cesium.Color.PURPLE
    }
});</pre>
</td>
</tr>
<tr>
<td>多段线体<br />(Polyline Volumes)</td>
<td>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer('cesiumContainer');

function computeCircle(radius) {
    var positions = [];
    for (var i = 0; i &lt; 360; i++) {
        var radians = Cesium.Math.toRadians(i);
        positions.push(new Cesium.Cartesian2(
            radius * Math.cos(radians), radius * Math.sin(radians)));
    }
    return positions;
}

function computeStar(arms, rOuter, rInner) {
    var angle = Math.PI / arms;
    var length = 2 * arms;
    var positions = new Array(length);
    for (var i = 0; i &lt; length; i++) {
        var r = (i % 2) === 0 ? rOuter : rInner;
        positions[i] = new Cesium.Cartesian2(
            Math.cos(i * angle) * r, Math.sin(i * angle) * r);
    }
    return positions;
}

var redTube = viewer.entities.add({
    name : 'Red tube with rounded corners',
    polylineVolume : {
        positions : Cesium.Cartesian3.fromDegreesArray(
            [-85.0, 32.0,
             -85.0, 36.0,
             -89.0, 36.0]),
        shape : computeCircle(60000.0),
        material : Cesium.Color.RED
    }
});

var greenBox = viewer.entities.add({
    name : 'Green box with beveled corners and outline',
    polylineVolume : {
        positions : Cesium.Cartesian3.fromDegreesArrayHeights(
            [-90.0, 32.0, 0.0,
             -90.0, 36.0, 100000.0,
             -94.0, 36.0, 0.0]),
        shape :[new Cesium.Cartesian2(-50000, -50000),
                new Cesium.Cartesian2(50000, -50000),
                new Cesium.Cartesian2(50000, 50000),
                new Cesium.Cartesian2(-50000, 50000)],
        cornerType : Cesium.CornerType.BEVELED,
        material : Cesium.Color.GREEN,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});

var blueStar = viewer.entities.add({
    name : 'Blue star with mitered corners and outline',
    polylineVolume : {
        positions : Cesium.Cartesian3.fromDegreesArrayHeights(
            [-95.0, 32.0, 0.0,
             -95.0, 36.0, 100000.0,
             -99.0, 36.0, 200000.0]),
        shape : computeStar(7, 70000, 50000),
        cornerType : Cesium.CornerType.MITERED,
        material : Cesium.Color.BLUE,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});

viewer.zoomTo(viewer.entities);</pre>
</td>
</tr>
<tr>
<td>矩形<br />(Rectangles)</td>
<td>
<pre class="crayon-plain-tag">//红色矩形
var redRectangle = viewer.entities.add({
    name : 'Red translucent rectangle with outline',
    rectangle : {
        coordinates : Cesium.Rectangle.fromDegrees(-110.0, 20.0, -80.0, 25.0),
        material : Cesium.Color.RED.withAlpha(0.5),
        outline : true,
        outlineColor : Cesium.Color.RED
    }
});
//绿色旋转、拉伸的矩形
var greenRectangle = viewer.entities.add({
    name : 'Green translucent, rotated, and extruded rectangle',
    rectangle : {
        coordinates : Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0),
        material : Cesium.Color.GREEN.withAlpha(0.5),
        rotation : Cesium.Math.toRadians(45),
        extrudedHeight : 300000.0,
        height : 100000.0,
        outline : true,
        outlineColor : Cesium.Color.GREEN
    }
});</pre>
</td>
</tr>
<tr>
<td>球和椭球<br />(Spheres Ellipsoids)</td>
<td> <br />
<pre class="crayon-plain-tag">var blueEllipsoid = viewer.entities.add({
    name : 'Blue ellipsoid',
    position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
    ellipsoid : {
        //可以指定三个轴的半径
        radii : new Cesium.Cartesian3(200000.0, 200000.0, 300000.0),
        material : Cesium.Color.BLUE
    }
});

var redSphere = viewer.entities.add({
    name : 'Red sphere with black outline',
    position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0),
    ellipsoid : {
        //正球体
        radii : new Cesium.Cartesian3(300000.0, 300000.0, 300000.0),
        material : Cesium.Color.RED,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});

var outlineOnly = viewer.entities.add({
    name : 'Yellow ellipsoid outline',
    position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 300000.0),
    ellipsoid : {
        radii : new Cesium.Cartesian3(200000.0, 200000.0, 300000.0),
        fill : false,
        outline : true,
        outlineColor : Cesium.Color.YELLOW,
        slicePartitions : 24, //横向切割线
        stackPartitions : 36  //纵向切割线
    }
});</pre>
</td>
</tr>
<tr>
<td>墙<br />(Walls)</td>
<td>
<pre class="crayon-plain-tag">//东西方向的横墙
var redWall = viewer.entities.add({
    name : 'Red wall at height',
    wall : {
        positions : Cesium.Cartesian3.fromDegreesArrayHeights(
             [-115.0, 44.0, 200000.0,//坐标点
              -90.0, 44.0, 200000.0]
        ),
        minimumHeights : [100000.0, 100000.0], //按坐标点的最小高度数组
        material : Cesium.Color.RED
    }
});
//四边围墙
var greenWall = viewer.entities.add({
    name : 'Green wall from surface with outline',
    wall : {
        positions : Cesium.Cartesian3.fromDegreesArrayHeights(
            [-107.0, 43.0, 100000.0,
             -97.0, 43.0, 100000.0,
             -97.0, 40.0, 100000.0,
             -107.0, 40.0, 100000.0,
             -107.0, 43.0, 100000.0]),
        material : Cesium.Color.GREEN,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});
//曲折的墙
var blueWall = viewer.entities.add({
    name : 'Blue wall with sawtooth heights and outline',
    wall : {
        //坐标点，不指定高度
        positions : Cesium.Cartesian3.fromDegreesArray(
            [-115.0, 50.0,
             -112.5, 50.0,
             -110.0, 50.0,
             -107.5, 50.0,
             -105.0, 50.0,
             -102.5, 50.0,
             -100.0, 50.0,
             -97.5, 50.0,
             -95.0, 50.0,
             -92.5, 50.0,
             -90.0, 50.0]),
        maximumHeights : [ //上高
            100000, 200000, 100000, 200000, 100000, 200000, 
            100000, 200000, 100000, 200000, 100000],
        minimumHeights : [  //下高
            0, 100000,  0, 100000, 0, 100000, 0, 100000, 0,
            100000, 0],
        material : Cesium.Color.BLUE,
        outline : true,
        outlineColor : Cesium.Color.BLACK
    }
});</pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">材质（Material）与轮廓（Outline）</span></div>
<p>多数形状均支持通过一致的方式来设置属性、控制外观：</p>
<ol>
<li>fill：布尔型，用于指定目标形状是否被填充</li>
<li>outline：布尔型，用于指定是否绘制形状的边缘</li>
<li>material：如果fill为true，该属性可以控制填充的材质类型</li>
</ol>
<p>一个例外是多段线，可以设置outlineWidth 、outlineColor、glowPower 等属性。</p>
<div class="blog_h3"><span class="graybg">高度与拉伸（Extrusion）</span></div>
<p>所有的形状均默认均是沿着地表的，目前圆形、椭圆、矩形可以在一定高度浮空显示，或者拉伸为Volume。</p>
<p>需要注意：Cesium总是使用米、弧度、秒为度量单位。下面是一个例子：</p>
<pre class="crayon-plain-tag">wyoming.polygon.height = 200000;         //设置高度
wyoming.polygon.extrudedHeight = 250000; //设置拉伸高度</pre>
<div class="blog_h2"><span class="graybg">在Viewer中可用的Entity特性</span></div>
<p>除非显式禁用，点击实体后会显示SelectionIndicator小器件，以及一个信息框。通过设置Entity.description，可以在信息框中显示任何HTML内容。</p>
<div class="blog_h2"><span class="graybg">镜头控制</span></div>
<p>zoomTo方法可以立即定位到某个位置，而flyTo则是通过动画方式转移到某个位置，这两个方法均可以传递EntityCollection对象，并且均是异步方法，返回一个Promises对象</p>
<p>默认情况下，镜头是<span style="background-color: #c0c0c0;">朝北、45度倾斜</span>查看地球。下面的代码可以让镜头朝东、倾斜三十度查看：</p>
<pre class="crayon-plain-tag">//镜头顺时针旋转九十度，即东向
var heading = Cesium.Math.toRadians(90);
//镜头倾斜30度俯视
var pitch = Cesium.Math.toRadians(-30);
viewer.zoomTo(wyoming, new Cesium.HeadingPitchRange(heading, pitch)).then(function(result){
    //执行完毕后，进行的动作
    if (result) { //如果镜头切换成功，则result=true
        viewer.selectedEntity = wyoming;
    }
});</pre>
<p>有时需要镜头跟踪某个实体（使居中）而不是地球，可以使用如下代码：</p>
<pre class="crayon-plain-tag">wyoming.position = Cesium.Cartesian3.fromDegrees(-107.724, 42.68);
viewer.trackedEntity = wyoming;  //跟踪某个实体。如果调用zoomTo、flyTo自动取消跟踪</pre>
<div class="blog_h2"><span class="graybg">管理Entity</span></div>
<p>EntityCollection对象是一个从Entity Id到Entity的关联数组，其提供例如add、remove、removeAll之类的常规函数，用于添加或者删除某个Entity：</p>
<pre class="crayon-plain-tag">//添加一个实体，并且提供ID
viewer.entities.add({
  id : '182bdba4-2b3e-47ae-bf0b-83f6fde285fd'
});
//获取一个实体
var entity = viewer.entities.getById('uniqueId')
//获取一个实体，如果不存在则创建之
var entity = viewer.entities.getOrCreateEntity('uniqueId');

//当添加、删除、修改EntityCollection中的Entity时，可以获得事件通知
function onChanged(collection, added, removed, changed){
    //add、removed、changed是增删改的Entity数组
    for(var i = 0; i &lt; added.length; i++) {
        
    }
}
viewer.entities.collectionChanged.addEventListener(onChanged);

//大批量操作时，临时禁用事件可以提高性能
viewer.entities.suspendEvents();
//执行各种Entity操作
viewer.entities.resumeEvents();</pre>
<div class="blog_h2"><span class="graybg">点、图标和标签</span></div>
<p>添加一个点、标签或者图标很简单：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer( 'cesiumContainer' );

var citizensBankPark = viewer.entities.add( {
    name : 'Citizens Bank Park',
    position : Cesium.Cartesian3.fromDegrees( -75.166493, 39.9060534 ),
    point : { //点
        pixelSize : 5,
        color : Cesium.Color.RED,
        outlineColor : Cesium.Color.WHITE,
        outlineWidth : 2
    },
    label : { //文字标签
        text : 'Citizens Bank Park',
        font : '14pt monospace',
        style : Cesium.LabelStyle.FILL_AND_OUTLINE,
        outlineWidth : 2,
        verticalOrigin : Cesium.VerticalOrigin.BOTTOM, //垂直方向以底部来计算标签的位置
        pixelOffset : new Cesium.Cartesian2( 0, -9 )   //偏移量
    }
    billboard : { //图标
        image : 'http://localhost:81/images/2015/02-02/Philadelphia_Phillies.png',
        width : 64,
        height : 64
    },
} );

viewer.zoomTo( viewer.entities );</pre>
<div class="blog_h2"><span class="graybg">3D模型</span></div>
<p>Cesium支持glTF格式的3D模型，glTF是WebGL、 OpenGL ES、 OpenGL的一种运行时模型格式，在Cesium中创建3D模型很简单：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer('cesiumContainer');
var entity = viewer.entities.add({
    position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706),
    model : {
        uri : '../../SampleData/models/CesiumGround/Cesium_Ground.gltf'
    },
    scale : 1,//和原始大小相比的缩放比例
    minimumPixelSize :100 //最小尺寸，防止太小而看不见
});
viewer.trackedEntity = entity;</pre>
<p>默认情况下，模型竖直放置、并且面向东面。可以指定四元组（Quaternion）给Entity.orientation属性，以改变放置的方向：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer('cesiumContainer');
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706); //位置
var heading = Cesium.Math.toRadians(45.0);//绕垂直于地心的轴旋转
var pitch = Cesium.Math.toRadians(15.0);  //绕纬度线旋转
var roll = Cesium.Math.toRadians(0.0);    //绕经度线旋转
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);

var entity = viewer.entities.add({
    position : position,
	orientation : orientation,
    model : {
        uri : '../../SampleData/models/CesiumGround/Cesium_Ground.gltf'
    }
});
viewer.trackedEntity = entity;</pre>
<p>例子中的<span style="background-color: #c0c0c0;">heading（yaw）、pitch、roll</span>对应了绕<span style="background-color: #c0c0c0;">Z（垂直轴）、Y（维度方向）、X（经度方向）</span>进行旋转，正数表示顺时针旋转（由于相对运动，在浏览器上看起来是地球在逆时针旋转），可以参考下图理解（人面向北面，摇头heading、点头pitch、歪头roll）：<img class="aligncenter wp-image-4799 size-full" src="https://blog.gmem.cc/wp-content/uploads/2015/03/head-pitch-roll1.png" alt="head-pitch-roll" width="400" height="455" /><a href="/wp-content/uploads/2015/03/head-pitch-roll.png"><br /></a></p>
<div class="blog_h2"><span class="graybg">属性系统</span></div>
<p>Cesium提供了一些快捷方式来设置属性，例如outline:true，但是尝试使用e.polygon.outline这样的形式来获取轮廓时，会得到一个ConstantProperty对象，如果不使用快捷方式，则需要编写更多的代码，例如：</p>
<pre class="crayon-plain-tag">polygon.outline = new Cesium.ConstantProperty(true);
polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.BLACK);</pre>
<p>所有属性的实例均是Property的子类型，引入属性类层次而不是使用基本类型的原因是，某些属性是随着时间而变化的。</p>
<p>要得到属性的原始值，需要调用Property.getValue()方法，例如：</p>
<pre class="crayon-plain-tag">//获取当前时间点，多边形轮廓是否存在
polygon.outline.getValue(viewer.clock.currentTime)</pre>
<div class="blog_h1"><span class="graybg">几何图形与外观</span></div>
<p>我们可以通过Primitive API来操控几何图形及其外观，或者绘制各种特殊的形状。需要先得到Scene对象，然后在其上添加Primitive对象：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;

scene.primitives.add(new Cesium.RectanglePrimitive({
    //绘制矩形
    rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
    material : Cesium.Material.fromType('Dot')  //设置材质
}));</pre>
<p>Primitive由两个部分组成：</p>
<ol>
<li>几何形状（Geometry）：定义了Primitive的结构，例如三角形、线条、点等</li>
<li>外观（Appearance ）：定义Primitive的着色（Sharding），包括GLSL（OpenGL着色语言，OpenGL Shading Language）顶点着色器和片段着色器（ vertex and fragment shaders），以及渲染状态（render state）</li>
</ol>
<p>Cesium支持以下几何图形：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 220px; text-align: center;">几何图形 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>BoxGeometry</td>
<td>立方体</td>
</tr>
<tr>
<td>BoxOutlineGeometry</td>
<td>仅有轮廓的立方体</td>
</tr>
<tr>
<td>CircleGeometry</td>
<td>圆形或者拉伸的圆形</td>
</tr>
<tr>
<td>CircleOutlineGeometry</td>
<td>只有轮廓的圆形</td>
</tr>
<tr>
<td>CorridorGeometry</td>
<td>走廊：沿着地表的多段线，且具有一定的宽度，可以拉伸到一定的高度</td>
</tr>
<tr>
<td>CorridorOutlineGeometry</td>
<td>只有轮廓的走廊</td>
</tr>
<tr>
<td>CylinderGeometry</td>
<td>圆柱、圆锥或者截断的圆锥</td>
</tr>
<tr>
<td>CylinderOutlineGeometry</td>
<td>只有轮廓的圆柱、圆锥或者截断的圆锥</td>
</tr>
<tr>
<td>EllipseGeometry</td>
<td>椭圆或者拉伸的椭圆</td>
</tr>
<tr>
<td>EllipseOutlineGeometry</td>
<td>只有轮廓的椭圆或者拉伸的椭圆</td>
</tr>
<tr>
<td>EllipsoidGeometry</td>
<td>椭球体</td>
</tr>
<tr>
<td>EllipsoidOutlineGeometry</td>
<td>只有轮廓的椭球体</td>
</tr>
<tr>
<td>RectangleGeometry</td>
<td>矩形或者拉伸的矩形</td>
</tr>
<tr>
<td>RectangleOutlineGeometry</td>
<td>只有轮廓的矩形或者拉伸的矩形</td>
</tr>
<tr>
<td>PolygonGeometry</td>
<td>多边形，可以具有空洞或者拉伸一定的高度</td>
</tr>
<tr>
<td>PolygonOutlineGeometry</td>
<td>只有轮廓的多边形</td>
</tr>
<tr>
<td>PolylineGeometry</td>
<td>多段线，可以具有一定的宽度</td>
</tr>
<tr>
<td>SimplePolylineGeometry</td>
<td>简单的多段线</td>
</tr>
<tr>
<td>PolylineVolumeGeometry</td>
<td>多段线柱体</td>
</tr>
<tr>
<td>PolylineVolumeOutlineGeometry</td>
<td>只有轮廓的多段线柱体</td>
</tr>
<tr>
<td>SphereGeometry</td>
<td>球体</td>
</tr>
<tr>
<td>SphereOutlineGeometry</td>
<td>只有轮廓的球体</td>
</tr>
<tr>
<td>WallGeometry</td>
<td>墙</td>
</tr>
<tr>
<td>WallOutlineGeometry</td>
<td>只有轮廓的墙</td>
</tr>
</tbody>
</table>
<p>使用Geometry和Appearance 具有以下优势：</p>
<ol>
<li>性能：绘制大量Primitive时，可以将其合并为单个Geometry以减轻CPU负担、更好的使用GPU。合并Primitive由web worker线程执行，UI保持响应性</li>
<li>灵活性：Geometry与Appearance 解耦，两者可以分别进行修改</li>
<li>低级别访问：易于编写GLSL 顶点、片段着色器、使用自定义的渲染状态 </li>
</ol>
<p>同时，具有以下劣势：</p>
<ol>
<li>需要编写更多地代码</li>
<li>需要对图形编程有更多的理解，特别是OpenGL的知识</li>
</ol>
<p>使用来Geometry、Appearance 改写上面的例子，代码为：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
//GeometryInstance是Geometry的一个容器
var instance = new Cesium.GeometryInstance({
  geometry : new Cesium.RectangleGeometry({
    rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
    vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
  })
});
//使用抽象的Primitive而不是RectanglePrimitive
scene.primitives.add(new Cesium.Primitive({
  geometryInstances : instance,
  //使用该外观，可以使矩形覆盖在地球表面，或者悬浮一定的高度
  appearance : new Cesium.EllipsoidSurfaceAppearance({
    material : Cesium.Material.fromType('Dot')
  })
}));</pre>
<div class="blog_h2"><span class="graybg">合并几何图形（Combing Geometries）</span></div>
<p>合并多个GeometryInstances 为一个Primitive可以极大的提高性能，下面的例子创建了2592一颜色各异的矩形，覆盖整个地球 ：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer( 'cesiumContainer' );
var scene = viewer.scene;

var instances = [];

for ( var lon = -180.0; lon &lt; 180.0; lon += 5.0 )
{
    for ( var lat = -90.0; lat &lt; 90.0; lat += 5.0 )
    {
        instances.push( new Cesium.GeometryInstance( {
            geometry : new Cesium.RectangleGeometry( {
                rectangle : Cesium.Rectangle.fromDegrees( lon, lat, lon + 5.0, lat + 5.0 )
            } ),
            attributes : {
                color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.fromRandom( {
                    alpha : 0.5
                } ) )
            }
        } ) );
    }
}

scene.primitives.add( new Cesium.Primitive( {
    geometryInstances : instances, //合并
    //某些外观允许每个几何图形实例分别指定某个属性，例如：
    appearance : new Cesium.PerInstanceColorAppearance()
} ) );</pre>
<div class="blog_h2"><span class="graybg">选取几何图形（Picking）</span></div>
<p>即使多个 GeometryInstance被合并为单个Primitive，让然可以独立的被访问。我们可以为每一个GeometryInstance指定一个id，并且可以通过Scene.pick来判断该实例是否被选取：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer( 'cesiumContainer' );
var scene = viewer.scene;

var instance = new Cesium.GeometryInstance( {
    geometry : new Cesium.RectangleGeometry( {
        rectangle : Cesium.Rectangle.fromDegrees( -100.0, 30.0, -90.0, 40.0 )
    } ),
    id : 'rectangle-1',
    attributes : {
        color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.RED )
    }
} );

scene.primitives.add( new Cesium.Primitive( {
    geometryInstances : instance,
    appearance : new Cesium.PerInstanceColorAppearance()
} ) );

var handler = new Cesium.ScreenSpaceEventHandler( scene.canvas );
//设置单击事件的处理句柄
handler.setInputAction( function( movement )
{
    var pick = scene.pick( movement.position );
    if ( Cesium.defined( pick ) &amp;&amp; ( pick.id === 'rectangle-1' ) )
    {
        console.log( '矩形被选取' );
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK );</pre>
<div class="blog_h2"><span class="graybg">几何图形实例（Geometry Instances）</span></div>
<p>上面的例子中，我们已经用到了GeometryInstances，注意GeometryInstance与Geometry的关系：前者是后者的容器，多个Instance可以共用一个Geometry，并且可以通过GeometryInstances<span style="background-color: #c0c0c0;">.modelMatrix</span>属性提供不同position、scale、rotate等位置、缩放、旋转信息。例如，下面的例子使用同一个Geometry绘制了两个Instance，一个位于另一个的上方：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer( 'cesiumContainer' );
var scene = viewer.scene;

var ellipsoidGeometry = new Cesium.EllipsoidGeometry( {
    vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
    radii : new Cesium.Cartesian3( 300000.0, 200000.0, 150000.0 )//三轴半径
} );
//下方的实例
var cyanEllipsoidInstance = new Cesium.GeometryInstance( {
    geometry : ellipsoidGeometry,
    modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame( Cesium.Cartesian3.fromDegrees( -100.0, 40.0 ) ), new Cesium.Cartesian3( 0.0, 0.0, 150000.0 ) ),
    attributes : {
        color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.CYAN )
    }
} );
//上方的实例
var orangeEllipsoidInstance = new Cesium.GeometryInstance( {
    geometry : ellipsoidGeometry,
    modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame( Cesium.Cartesian3.fromDegrees( -100.0, 40.0 ) ), new Cesium.Cartesian3( 0.0, 0.0, 450000.0 ) ),
    attributes : {
        color : Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.ORANGE )
    }
} );

scene.primitives.add( new Cesium.Primitive( {
    geometryInstances : [
        cyanEllipsoidInstance, orangeEllipsoidInstance
    ],
    appearance : new Cesium.PerInstanceColorAppearance( {
        translucent : false,
        closed : true
    } )
} ) );</pre>
<div class="blog_h2"><span class="graybg">更新单个GeometryInstance的属性</span></div>
<p>在添加到Primitive中以后，让然可以修改几何图形的某些属性：</p>
<ol>
<li>颜色：如果Primitive设置了PerInstanceColorAppearance外观，则可以修改ColorGeometryInstanceAttribute类型的颜色</li>
<li>可见性：任何实例可以修改可见性</li>
</ol>
<p>示例代码：</p>
<pre class="crayon-plain-tag">var viewer = new Cesium.Viewer( 'cesiumContainer' );
var scene = viewer.scene;

var circleInstance = new Cesium.GeometryInstance( {
    geometry : new Cesium.CircleGeometry( {
        center : Cesium.Cartesian3.fromDegrees( -95.0, 43.0 ),
        radius : 250000.0,
        vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
    } ),
    attributes : {
        color : Cesium.ColorGeometryInstanceAttribute.fromColor( new Cesium.Color( 1.0, 0.0, 0.0, 0.5 ) ),
        show : new Cesium.ShowGeometryInstanceAttribute( true ) //显示或者隐藏
    },
    id : 'circle'
} );
var primitive = new Cesium.Primitive( {
    geometryInstances : circleInstance,
    appearance : new Cesium.PerInstanceColorAppearance( {
        translucent : false,
        closed : true
    } )
} );
scene.primitives.add( primitive );

//定期修改颜色
setInterval( function()
{
    var attributes = primitive.getGeometryInstanceAttributes( 'circle' );//获取某个实例的属性集
    attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue( Cesium.Color.fromRandom( {
        alpha : 1.0
    } ) );
}, 2000 );</pre>
<div class="blog_h2"><span class="graybg">外观（Appearances）</span></div>
<p>Primitive由两个重要部分组成：几何图形实例、外观，一个Primitive只能有一个外观，而可以有多个实例。几何图形定义了结构，外观定义了每个像素被如何着色，外观可能使用材质（Material）。这些对象的关系如下图所示：<img class="aligncenter size-full wp-image-4810" src="https://blog.gmem.cc/wp-content/uploads/2015/03/highleveldesign.png" alt="highleveldesign" width="504" height="400" /></p>
<p>Cesium支持下表列出的外观：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 220px; text-align: center;"> 外观</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>MaterialAppearance</td>
<td>支持各种Geometry类型的外观，支持使用材质来定义着色</td>
</tr>
<tr>
<td>EllipsoidSurfaceAppearance</td>
<td>MaterialAppearance的一个版本。假设几何图形与地表是平行的，并且依此来进行顶点属性（vertex attributes）的计算</td>
</tr>
<tr>
<td>PerInstanceColorAppearance</td>
<td>让每个实例使用自定义的颜色来着色</td>
</tr>
<tr>
<td>PolylineMaterialAppearance</td>
<td>支持使用材质来着色多段线</td>
</tr>
<tr>
<td>PolylineColorAppearance</td>
<td>使用每顶点或者每片段（per-vertex or per-segment ）的颜色来着色多段线</td>
</tr>
</tbody>
</table>
<p>外观定义了需要在GPU上执行的完整的GLSL顶点、片段着色器，通常不需要修改这一部分，除非需要定义自己的外观。</p>
<p>外观还定义了完整的render state，用于在绘制Primitive时控制GPU的状态，可以直接或者通过高层API来定义render state：</p>
<pre class="crayon-plain-tag">//下面的外观可用于定义一个Viewer不可进入的不透明盒子
var appearance = new Cesium.PerInstanceColorAppearance( {
    translucent : false,
    closed : true
} );
//下面的代码效果同上
var translucent = new Cesium.PerInstanceColorAppearance( {
    renderState : {
        depthTest : {
            enabled : true
        },
        cull : {
            enabled : true,
            face : Cesium.CullFace.BACK
        }
    }
} );</pre>
<p>一旦外观被创建，其render state就不可再变，但是其材质是可以替换的。另外Primitive的外观也是不可修改的。</p>
<p>大部分外观具有flat、faceForward属性，可以间接的控制GLSL 着色器：</p>
<ol>
<li>flat：扁平化着色，不考虑光线的作用</li>
<li>faceForward：布尔值，控制光照效果</li>
</ol>
<div class="blog_h2"><span class="graybg">Geometry与Appearance的兼容性</span></div>
<p>需要注意，不是所有外观和所有几何图形可以搭配使用，例如EllipsoidSurfaceAppearance与WallGeometry就不能搭配，原因是后者是垂直于地表的。</p>
<p>即使外观与几何图形兼容，它们还必须有匹配的顶点格式（vertex formats）—— 即几何图形必须具有外观可以作为输入的数据格式，在创建Geometry时可以提供VertexFormat。</p>
<p>为了简便，可以让Geometry计算所有顶点属性（vertex attributes），以使之适用于任何外观，但这样做效率较差：</p>
<pre class="crayon-plain-tag">var geometry = new Cesium.RectangleGeometry( {
    vertexFormat : Cesium.VertexFormat.ALL
} );</pre>
<p> 而如果我们使用外观EllipsoidSurfaceAppearance，其实只需要知道位置：</p>
<pre class="crayon-plain-tag">var geometry = new Ceisum.RectangleGeometry( {
    vertexFormat : Ceisum.VertexFormat.POSITION_ONLY
} );</pre>
<p>大部分外观具有vertexFormat属性或者VERTEX_FORMAT 静态常量，创建形状时只需要使用这些顶点格式即可：</p>
<pre class="crayon-plain-tag">var geometry = new Ceisum.RectangleGeometry( {
    vertexFormat : Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT
} );

var geometry2 = new Ceisum.RectangleGeometry( {
    vertexFormat : Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT
} );

var appearance = new Ceisum.MaterialAppearance();
var geometry3 = new Ceisum.RectangleGeometry( {
    vertexFormat : appearance.vertexFormat
} );</pre>
<p>此外，两个形状必须具有匹配的vertexFormat，才能被合并到一个Primitive中。</p>
<div class="blog_h1"><span class="graybg">3D模型</span></div>
<p>我们可以转换、加载并且在Cesium中使用3D模型。Cesium支持glTF（一个新兴的Web 3D模型工业标准）格式的3D模型，并且提供在线的 COLLADA - glTF转换工具。Cesium针对3D模型支持关键帧动画、皮肤、单独节点选取等特性。</p>
<p>Cesium自带了三个模型：飞机、车辆、人。下面的例子载入一个车辆模型：</p>
<pre class="crayon-plain-tag">var scene = viewer.scene;
//创建坐标
var coord = Cesium.Cartesian3.fromDegrees( -75.62898254394531, 40.02804946899414, 0.0 );
//创建一个东（X，红色）北（Y，绿色）上（Z，蓝色）的本地坐标系统
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( coord );
// 改变3D模型的模型矩阵，可以用于移动物体
// 物体的世界坐标 = 物体的模型坐标 * 世界矩阵
var model = scene.primitives.add( Cesium.Model.fromGltf( {//异步的加载模型
    url : '../../SampleData/models/CesiumGround/Cesium_Ground.gltf',
    modelMatrix : modelMatrix, //模型矩阵
    scale : 200.0 //缩放
} ) );</pre>
<p>Cesium自带的3个模型已经内嵌了动画关键桢，如果需要播放动画，可以在调用Model.fromGltf后添加以下代码：</p>
<pre class="crayon-plain-tag">Cesium.when( model.readyPromise ).then( function( model )
{
    model.activeAnimations.addAll( {//播放模型中全部动画，如果需要播放单个动画，可以调用add，传入动画id
        loop : Cesium.ModelAnimationLoop.REPEAT, //直到被移出activeAnimations，一直播放
         speedup : 0.5,  //加速播放
         reverse : true  //逆序播放
    } );
} );</pre>
<p>动画与Cesium的时钟系统同步化。</p>
<p>与其它Primitive一样，对3D模型的选取也是被支持的，当前点击的glTF node id、glTF mess一并被获取：</p>
<pre class="crayon-plain-tag">var handler = new Cesium.ScreenSpaceEventHandler( scene.canvas );
handler.setInputAction( function( movement )
{
    var pick = scene.pick( movement.endPosition );
    if ( Cesium.defined( pick ) &amp;&amp; Cesium.defined( pick.node ) &amp;&amp; Cesium.defined( pick.mesh ) )
    {
        console.log( 'node: ' + pick.node.name + '. mesh: ' + pick.mesh.name );
    }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE );</pre>
<div class="blog_h1"><span class="graybg">栅格图层</span></div>
<p>Cesium支持多种标准化格式的GIS瓦片服务，可以把栅格图层绘制到地球的表面。这些图层的亮度、对比度、色相均可以动态调整：</p>
<pre class="crayon-plain-tag">//初始化一个查看器，并且提供一个栅格图层
var viewer = new Cesium.Viewer( 'cesiumContainer', {
    imageryProvider : new Cesium.ArcGisMapServerImageryProvider( {
        url : 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
    } ),
    baseLayerPicker : false
} );
//添加另外一个图层
var layers = viewer.scene.imageryLayers;
var blackMarble = layers.addImageryProvider( new Cesium.TileMapServiceImageryProvider( {
    url : '//cesiumjs.org/tilesets/imagery/blackmarble',
    maximumLevel : 8,
    credit : 'Black Marble imagery courtesy NASA Earth Observatory'
} ) );
//设置图层的透明度
blackMarble.alpha = 0.5;
//设置图层的亮度
blackMarble.brightness = 2.0;

//添加一个图层，在特定位置绘制一个图片
layers.addImageryProvider(new Cesium.SingleTileImageryProvider({
    url : '../images/Cesium_Logo_overlay.png',
    rectangle : Cesium.Rectangle.fromDegrees(-75.0, 28.0, -67.0, 29.75)
}));</pre>
<div class="blog_h1"><span class="graybg">3D地形图</span></div>
<p>Cesium支持3D地形图、水体特效，下面的代码添加该特性：</p>
<pre class="crayon-plain-tag">var terrainProvider = new Cesium.CesiumTerrainProvider( {
    url : '//assets.agi.com/stk-terrain/world'
} );
viewer.terrainProvider = terrainProvider;</pre>
<p>需要注意的是，地形图、栅格图层是分别处理的，默认的栅格图层覆盖在地形图的上面。任何栅格图层均可与地形图搭配使用。</p>
<p>下面的代码可以启用光照、水体效果：</p>
<pre class="crayon-plain-tag">var terrainProvider = new Cesium.CesiumTerrainProvider( {
    url : '//assets.agi.com/stk-terrain/world',
    requestVertexNormals : true
} );
viewer.terrainProvider = terrainProvider;
viewer.scene.globe.enableLighting = true;</pre>
<div class="blog_h1"><span class="graybg">镜头</span></div>
<p>Cesium提供了以下默认鼠标行为：</p>
<ol>
<li>单击并拖拽球体：旋转地球，镜头俯角不变</li>
<li>单击并拖拽空间：滚动roll、俯仰pitch镜头</li>
<li>右击并拖拽、中键滚动：缩放镜头</li>
<li>中键拖拽：沿着地表的点旋转镜头</li>
</ol>
<p>调用camera.setView()可以设置相机的位置和方向：</p>
<pre class="crayon-plain-tag">camera.setView( {
    positionCartographic : new Cesium.Cartographic( longitude, latitude, height ),
    heading : headingAngle,
    pitch : pitchAngle,
    roll : rollAngle
} );

//确保指定的东西南北范围进入视野
var west = Cesium.Math.toRadians( -77.0 );
var south = Cesium.Math.toRadians( 38.0 );
var east = Cesium.Math.toRadians( -72.0 );
var north = Cesium.Math.toRadians( 42.0 );
var extent = new Cesium.Extent( west, south, east, north );
camera.viewExtent( extent, Cesium.Ellipsoid.WGS84 );</pre>
<p>Camera</p>
<p>相机对象表示当前镜头的位置（position）、方向（orientation）、参考坐标系（reference frame）、视见体（View Frustum）。</p>
<p>move*、zoom*方法用于沿着镜头的原点（orientation ）或者一个给定的矢量来变换（translate）镜头的位置。移动过程中方向保持固定：<img class="aligncenter size-full wp-image-4826" src="https://blog.gmem.cc/wp-content/uploads/2015/03/direction-up-right.png" alt="direction-up-right" width="497" height="442" /></p>
<p>look*、twist*方法用于依照direction、up、right向量来旋转方向，旋转过程中位置保持不变：<img class="aligncenter size-full wp-image-4827" src="https://blog.gmem.cc/wp-content/uploads/2015/03/look-twist.png" alt="look-twist" width="612" height="177" /></p>
<p>rotate*方法用于依据给定的矢量来变换位置、旋转方向。</p>
<div class="blog_h2"> </div>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/cesium-study-note">Cesium学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/cesium-study-note/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>TileStache知识集锦</title>
		<link>https://blog.gmem.cc/tilestache-faq</link>
		<comments>https://blog.gmem.cc/tilestache-faq#comments</comments>
		<pubDate>Sat, 24 Jan 2015 10:02:43 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[GIS]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=4868</guid>
		<description><![CDATA[<p>常见问题 如何缓存Bing、Yahoo等厂商提供的卫星图 添加代理（proxy）类型的图层，设置provider为相应的厂商。 [crayon-69d4c25365513726223321/] 内置的可用厂商可以到下面的代码中寻找： [crayon-69d4c25365517018088750/]</p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/tilestache-faq">TileStache知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h2"><span class="graybg">常见问题</span></div>
<div class="blog_h3"><span class="graybg">如何缓存Bing、Yahoo等厂商提供的卫星图</span></div>
<p>添加代理（proxy）类型的图层，设置provider为相应的厂商。</p>
<pre class="crayon-plain-tag">{
  "layers": 
  {
    ......
    "bing-satellite":
    {
      "provider":
      {
        "name" : "proxy",
        "provider" : "MICROSOFT_AERIAL"
      }
    }
  }
}</pre><br />
内置的可用厂商可以到下面的代码中寻找：<br />
<pre class="crayon-plain-tag"># a handy list of possible providers, which isn't
# to say that you can't go writing your own.
builtinProviders = {
    'OPENSTREETMAP':    OpenStreetMap.Provider,
    'OPEN_STREET_MAP':  OpenStreetMap.Provider,
    'BLUE_MARBLE':      BlueMarble.Provider,
    'MAPQUEST_ROAD':   MapQuest.RoadProvider,
    'MAPQUEST_AERIAL':   MapQuest.AerialProvider,
    'MICROSOFT_ROAD':   Microsoft.RoadProvider,
    'MICROSOFT_AERIAL': Microsoft.AerialProvider,
    'MICROSOFT_HYBRID': Microsoft.HybridProvider,
    'YAHOO_ROAD':       Yahoo.RoadProvider,
    'YAHOO_AERIAL':     Yahoo.AerialProvider,
    'YAHOO_HYBRID':     Yahoo.HybridProvider,
    'CLOUDMADE_ORIGINAL': CloudMade.OriginalProvider,
    'CLOUDMADE_FINELINE': CloudMade.FineLineProvider,
    'CLOUDMADE_TOURIST': CloudMade.TouristProvider,
    'CLOUDMADE_FRESH':  CloudMade.FreshProvider,
    'CLOUDMADE_PALEDAWN': CloudMade.PaleDawnProvider,
    'CLOUDMADE_MIDNIGHTCOMMANDER': CloudMade.MidnightCommanderProvider,
    'STAMEN_TONER': Stamen.TonerProvider,
    'STAMEN_TERRAIN': Stamen.TerrainProvider,
    'STAMEN_WATERCOLOR': Stamen.WatercolorProvider,
    }</pre> 
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/tilestache-faq">TileStache知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/tilestache-faq/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>基于OpenStreetMap的地图服务器的搭建</title>
		<link>https://blog.gmem.cc/setup-openstreetmap-server</link>
		<comments>https://blog.gmem.cc/setup-openstreetmap-server#comments</comments>
		<pubDate>Tue, 13 Jan 2015 02:56:55 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[GIS]]></category>
		<category><![CDATA[iD]]></category>
		<category><![CDATA[Leaflet]]></category>
		<category><![CDATA[Mapnik]]></category>
		<category><![CDATA[OpenLayers]]></category>
		<category><![CDATA[OSM]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[TileStache]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=3885</guid>
		<description><![CDATA[<p>GIS基础知识 GIS基本组件 地图数据库：提供地图数据，例如OSM的planet.osm可以导入PostgreSQL作为地图数据库 瓦片服务器：负责生成一系列的瓦片（tiles），这些瓦片通常为256像素的方块，瓦片组在一起形成地图。对于Google Map，瓦片服务器是Google提供的，用户不能接触其地图数据库；对于OSM，地图数据库是开放的，可以随意下载，需要自己搭建瓦片服务器 前端API：用于浏览器的JavaScript API，或者用于移动客户端的同功API。例如OpenLayers、Leaflet。 坐标参考系统（Coordinate Reference Systems） 又称空间参考系统（spatial reference system，SRS），是基于二维坐标的，用于定位局部、区域或者全球地理信息资源的体系。CRS定义了一种地图映射规则、与其它CRS之间进行转化的算法。CRS是GIS系统的基础。 最常用的两种CRS为：  CRS 说明  EPSG:4326 以经纬度直接作为X（经度）、Y（维度）坐标，南纬、西经采用负数表示 投影范围: -180.0000, -85.0600, 180.0000, <a class="read-more" href="https://blog.gmem.cc/setup-openstreetmap-server">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/setup-openstreetmap-server">基于OpenStreetMap的地图服务器的搭建</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">GIS基础知识</span></div>
<div class="blog_h2"><span class="graybg">GIS基本组件</span></div>
<ol>
<li>地图数据库：提供地图数据，例如OSM的planet.osm可以导入PostgreSQL作为地图数据库</li>
<li>瓦片服务器：负责生成一系列的瓦片（tiles），这些瓦片通常为256像素的方块，瓦片组在一起形成地图。对于Google Map，瓦片服务器是Google提供的，用户不能接触其地图数据库；对于OSM，地图数据库是开放的，可以随意下载，需要自己搭建瓦片服务器</li>
<li>前端API：用于浏览器的JavaScript API，或者用于移动客户端的同功API。例如OpenLayers、Leaflet。</li>
</ol>
<div class="blog_h2"><span class="graybg">坐标参考系统（Coordinate Reference Systems）</span></div>
<p>又称空间参考系统（spatial reference system，SRS），是基于二维坐标的，用于定位局部、区域或者全球地理信息资源的体系。CRS定义了一种地图映射规则、与其它CRS之间进行转化的算法。CRS是GIS系统的基础。</p>
<p>最常用的两种CRS为：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> CRS</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>EPSG:4326</td>
<td>
<p>以经纬度直接作为X（经度）、Y（维度）坐标，南纬、西经采用负数表示</p>
<p>投影范围: -180.0000, -85.0600, 180.0000, 85.0600</p>
</td>
</tr>
<tr>
<td>EPSG:3857</td>
<td>
<p>主要用于Web地图等应用程序，最初由Google地图提出，故经常称为900913，基于椭圆形墨卡托（ellipsoidal Mercator ）投影</p>
<p>投影范围： -180.0000, -90.0000, 180.0000, 90.0000</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">OpenStreetMap基础知识</span></div>
<div class="blog_h2"><span class="graybg">OpenStreetMap的优势</span></div>
<ol>
<li>地图数据开源，人人可以编辑，并且可以完整的下载，部署私有的地图服务器</li>
<li>内容丰富，比起ESRI Shapefiles的点、面、线，支持更多复杂的元素</li>
<li>生态圈活跃，从地图数据、数据库、地图渲染、瓦片服务器、前端API，到桌面、Web地图设计工具，具有大量优秀的开源组件</li>
</ol>
<div class="blog_h2"><span class="graybg">OpenStreetMap生态圈</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;">组件类型</td>
<td style="width: 150px; text-align: center;">组件名称 </td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">地图数据</td>
<td>planet.osm</td>
<td>
<p>提供开放的、人人可编辑的全球地图数据。使用osm2pgsql可以导入空间数据库</p>
<p>整个世界的地图解压后有500G。可以去下载部分地区、国家、城市的抽取。</p>
</td>
</tr>
<tr>
<td style="text-align: center;" rowspan="2">空间数据库</td>
<td>PostgreSQL</td>
<td>一个强大的对象——关系型数据库 </td>
</tr>
<tr>
<td>PostGIS</td>
<td>PostgreSQL的一个扩展，提供空间、地理对象</td>
</tr>
<tr>
<td style="text-align: center;">瓦片生成器</td>
<td>Mapnik</td>
<td>地图渲染引擎，采用C++编写，具有Python等语言的绑定。支持多种地图格式，包括SHP、PostGIS、Kismet、OSM XML。可以生成瓦片</td>
</tr>
<tr>
<td style="text-align: center;" rowspan="3">瓦片服务器<br />(HTTP、瓦片缓存)</td>
<td>TileStache</td>
<td>基于Python，可作为Mapnik的前端，调用Mapnik生成瓦片并缓存，并可对外提供HTTP服务</td>
</tr>
<tr>
<td>TileCache</td>
<td>基于Python，可作为Mapnik的前端，支持多种瓦片请求协议，包括WMS、WorldWind、TMS </td>
</tr>
<tr>
<td>Apache (mod_tile)</td>
<td>Apache Server的一个模块，可以调用Mapnik，OSM官方就是使用这种方式</td>
</tr>
<tr>
<td style="text-align: center; vertical-align: middle;" rowspan="3">一般工具</td>
<td>Osmosis</td>
<td>
<p>基于Java的处理OSM数据的命令行工具，可以：</p>
<ol>
<li>从数据库创建地图Dump</li>
<li>把地图Dump加载到数据库</li>
<li>基于数据库历史表生成变更集（Change sets）</li>
<li>把变更集应用到数据库</li>
<li>根据两个地图Dump生成变更集</li>
<li>重新排序Dump中的数据</li>
<li>根据多边形边界框来抽取地图数据</li>
</ol>
</td>
</tr>
<tr>
<td>osmium</td>
<td>
<p>基于C++、JavaScript的处理OSM数据的框架</p>
</td>
</tr>
<tr>
<td>osm2pgsql</td>
<td>
<p>基于C++的导入OSM到PostgreSQL的命令行工具</p>
</td>
</tr>
<tr>
<td style="text-align: center; vertical-align: middle;" rowspan="2">
<p>地址坐标转换<br />(geocoding)</p>
<p>&nbsp;</p>
</td>
<td>Nominatim</td>
<td>
<p>OpenStreetMap官方的地址坐标转换服务，硬件要求很高</p>
</td>
</tr>
<tr>
<td>OpenCage</td>
<td>
<p>可以提供基于Nominatim的地址坐标转换API</p>
</td>
</tr>
<tr>
<td style="text-align: center; vertical-align: middle;" rowspan="2">路径规划<br />(Routing)</td>
<td>OSRM</td>
<td>
<p>The Open Source Routing Machine，基于C++实现的高性能路径规划引擎</p>
</td>
</tr>
<tr>
<td>Graphhopper</td>
<td>基于Java的路径规划引擎</td>
</tr>
<tr>
<td style="text-align: center;" rowspan="6">前端API</td>
<td>MapQuest Open API</td>
<td>与MapQuest Open tiles联用，提供<span style="color: #292929;">routing（路径规划）、geocoding（地址坐标转换）等特性</span></td>
</tr>
<tr>
<td>OpenLayers</td>
<td>成熟、强大</td>
</tr>
<tr>
<td>Leaflet</td>
<td>轻量级、简单易用</td>
</tr>
<tr>
<td>Route-Me</td>
<td>IOS的前端API（已很久不更新）</td>
</tr>
<tr>
<td>osmdroid</td>
<td>Android的前端API</td>
</tr>
<tr>
<td>Mapstraction</td>
<td>一个JavaScript抽象层，可以在不改变代码的情况下切换使用不同类型的瓦片服务器</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">搭建地图服务器</span></div>
<div class="blog_h2"><span class="graybg">Windows下搭建OSM服务器的详细步骤</span></div>
<p>目前网络上的例子，大多是在Linux下搭建OSM服务器。实际项目中由于客户现场环境的限制，可能必须使用Windows Server，故本文详细记录Windows下的搭建步骤，供各位参考。</p>
<div class="blog_h3"><span class="graybg">系统架构</span></div>
<p><img class="aligncenter wp-image-3993" src="https://blog.gmem.cc/wp-content/uploads/2015/01/osm_arch-1024x8791.png" alt="osm_arch-1024x879" width="450" height="386" /></p>
<p>上图中红色部分为本文主要使用的组件，我们把这些组件全部安装到一个目录<span style="background-color: #c0c0c0;">%OSM_STACK%</span>下</p>
<div class="blog_h3"><span class="graybg">下载地图</span></div>
<p>区域地图，可从这里下载：<a href="http://download.geofabrik.de/">http://download.geofabrik.de/</a></p>
<p>全球地图，可从这里下载：<a href="http://ftp.heanet.ie/mirrors/openstreetmap.org/planet/2015/planet-150105.osm.bz2">http://ftp.heanet.ie/mirrors/openstreetmap.org/planet/2015/planet-150105.osm.bz2</a></p>
<div class="blog_h3"><span class="graybg">安装Python</span></div>
<p>安装Python 2.7.x到%OSM_STACK%\python，并加入PATH环境变量，下载地址：<a href="https://www.python.org/ftp/python/2.7.9/python-2.7.9.msi">https://www.python.org/ftp/python/2.7.9/python-2.7.9.msi</a></p>
<p>为避免后续需要下载依赖的模块，可以安装便携版的Python，集成了很多常用模块，安装后把App目录里面的所有文件拷贝到%OSM_STACK%\python即可，下载地址：<a href="http://ftp.osuosl.org/pub/portablepython/v2.7/PortablePython_2.7.6.1.exe">http://ftp.osuosl.org/pub/portablepython/v2.7/PortablePython_2.7.6.1.exe</a></p>
<div class="blog_h3"><span class="graybg">安装PostgreSQL和PostGIS</span></div>
<p>最好下载PostgreSQL 9.0以上或者 8.3版，8.4存在性能问题。</p>
<p>9.4的下载地址：<a href="http://get.enterprisedb.com/postgresql/postgresql-9.4.0-1-windows-binaries.zip">http://get.enterprisedb.com/postgresql/postgresql-9.4.0-1-windows-binaries.zip</a></p>
<p>解压到%OSM_STACK%\psql</p>
<p>下载PostGIS：<a href="http://download.osgeo.org/postgis/windows/pg94/postgis-bundle-pg94x32-2.1.5-2.zip">http://download.osgeo.org/postgis/windows/pg94/postgis-bundle-pg94x32-2.1.5-2.zip</a></p>
<p>解压覆盖到%OSM_STACK%\psql</p>
<p>注意：上述的PostgreSQL是绿色版的，对MSVC12有C运行时库、C++标准库有依赖，如果你的机器缺少msvcp120.dll、msvcr120.dll这两个DLL，可以下载：<a href="http://www.microsoft.com/en-gb/download/details.aspx?id=40784">Visual C++ Redistributable Packages for Visual Studio 2013</a>并安装，亦可直接拷贝这两个文件到%OSM_STACK%\psql\bin下</p>
<p>下面的脚本说明如何初始化PostgreSQL、创建用户gisuser、数据库gis、激活PostGIS：</p>
<pre class="crayon-plain-tag">@echo off

pushd "%~dp0"

SET "PGDATA=%PSQL_HOME%\data"
SET "PGDATABASE=postgres"
SET "PGUSER=postgres"
SET "PGPORT=5439"
SET "PGLOCALEDIR=%PSQL_HOME%\share\locale"
rem GIS databse name and owner
SET "GISDATABASE=gis"
SET "GISUSER=gisuser"

echo ****** Prepare to initializing PostgreSQL  ****** 
rem 初始化数据库，这将生成data目录，并且根据机器硬件环境生成配置文件
initdb -U %PGUSER% -A trust

echo ****** Prepare to start PostgreSQL  ****** 
rem 启动数据库，日志记录到pgsql.log，等待启动完成
pg_ctl -w -l %PSQL_HOME%\pgsql.log start

echo ****** Creating user %GISUSER%  ****** 
rem 创建GIS专门用户
createuser -U %PGUSER% %GISUSER%
echo ****** Creating database %GISDATABASE%  ****** 
rem 创建GIS专用数据库
createdb -U %PGUSER% -E UTF8 -O %GISUSER% %GISDATABASE%
echo ****** Installing procedural language into %GISDATABASE%  ****** 
rem 添加扩展
createlang -U %PGUSER% plpgsql %GISDATABASE%
echo ****** Activating PostGIS for %GISDATABASE%  ****** 
rem 为GIS数据库激活PostGIS支持
psql -U %PGUSER% -d %GISDATABASE% -f "%PSQL_HOME%\share\contrib\postgis-2.1\postgis.sql"
psql -U %PGUSER% -d %GISDATABASE% -f "%PSQL_HOME%\share\contrib\postgis-2.1\spatial_ref_sys.sql"
rem After the activation, the following command should list the tables geometry_columns and spatial_ref_sys:
rem 下面这一句不能在UTF-8代码页下运行，会报内存不足的错误
psql --username=%GISUSER% --dbname=%GISDATABASE% --command="\d"
rem 停止数据库
pg_ctl -w stop</pre>
<p>打开%OSM_STACK%\psql\data\postgresql.conf，修改以下参数，以提高性能（根据硬件配置调整）：</p>
<pre class="crayon-plain-tag">shared_buffers = 512MB  
checkpoint_segments = 20  
maintenance_work_mem = 256MB  
autovacuum = off  

kernel.shmmax=536870912</pre>
<div class="blog_h3"><span class="graybg">导入地图到数据库</span></div>
<p>使用命令行工具osm2pgsql 可以把OpenStreetMap地图数据导入到启用了postGIS的PostgreSQL数据库中。尽管mapnik可以直接渲染OSM XML原始数据，但是导入PostGIS可以使用更多的高级特性。</p>
<p>从这里下载此工具：<a href="http://customdebug.com/osm/osm2pgsql.zip">http://customdebug.com/osm/osm2pgsql.zip</a></p>
<p>使用示例：</p>
<pre class="crayon-plain-tag">osm2pgsql -c -d gis -U postgres -H localhost -P 5439 -S default.style  -C 600 beijing.osm.bz2</pre>
<p>default.style是 导入时需要的样式定义文件，内容如下：</p>
<pre class="crayon-plain-tag"># OsmType  Tag          DataType     Flags
node,way   access       text         linear
node,way   addr:housename      text  linear
node,way   addr:housenumber    text  linear
node,way   addr:interpolation  text  linear
node,way   admin_level  text         linear
node,way   aerialway    text         linear
node,way   aeroway      text         polygon
node,way   amenity      text         polygon
node,way   area         text         
node,way   barrier      text         linear
node,way   bicycle      text
node,way   brand        text         linear
node,way   bridge       text         linear
node,way   boundary     text         linear
node,way   building     text         polygon
node       capital      text         linear
node,way   construction text         linear
node,way   covered      text         linear
node,way   culvert      text         linear
node,way   cutting      text         linear
node,way   denomination text         linear
node,way   disused      text         linear
node       ele          text         linear
node,way   embankment   text         linear
node,way   foot         text         linear
node,way   generator:source    text  linear
node,way   harbour      text         polygon
node,way   highway      text         linear
node,way   historic     text         polygon
node,way   horse        text         linear
node,way   intermittent text         linear
node,way   junction     text         linear
node,way   landuse      text         polygon
node,way   layer        text         linear
node,way   leisure      text         polygon
node,way   lock         text         linear
node,way   man_made     text         polygon
node,way   military     text         polygon
node,way   motorcar     text         linear
node,way   name         text         linear
node,way   natural      text         polygon
node,way   office       text         polygon
node,way   oneway       text         linear
node,way   operator     text         linear
node,way   place        text         polygon
node       poi          text
node,way   population   text         linear
node,way   power        text         polygon
node,way   power_source text         linear
node,way   public_transport text     polygon
node,way   railway      text         linear
node,way   ref          text         linear
node,way   religion     text         nocache
node,way   route        text         linear
node,way   service      text         linear
node,way   shop         text         polygon
node,way   sport        text         polygon
node,way   surface      text         linear
node,way   toll         text         linear
node,way   tourism      text         polygon
node,way   tower:type   text         linear
way        tracktype    text         linear
node,way   tunnel       text         linear
node,way   water        text         polygon
node,way   waterway     text         polygon
node,way   wetland      text         polygon
node,way   width        text         linear
node,way   wood         text         linear
node,way   z_order      int4         linear
way        way_area     real</pre>
<div class="blog_h3"><span class="graybg">安装mapnik</span></div>
<p>从<a href="http://mapnik.org/download/">http://mapnik.org/download/</a>下载mapnik，解压到%OSM_STACK%\mapnik，将其bin、lib目录加入PATH环境变量，python\2.7\site-packages加入PYTHONPATH环境变量。</p>
<p>在mapnik中，一个Map可以包含若干个图层（Layer），每个层可以独立着色，即可为每个层定制样式（Style），每个样式由若干个规则组成（Rule），每个规则由是由若干个符号定制。</p>
<div class="blog_h3"><span class="graybg">生成mapnik的样式文件</span></div>
<p>从<a href="https://www.mapbox.com/tilemill/">https://www.mapbox.com/tilemill/</a>下载并安装TileMill，该工具用于编辑地图元素的样式，我们主要用它导出mapnik的样式文件。</p>
<p>OpenStreetMap官方使用的样式托管在GitHub上：<a href="https://github.com/gravitystorm/openstreetmap-carto">https://github.com/gravitystorm/openstreetmap-carto</a>。下载后解压到C:\Users\用户名\Documents\MapBox\project</p>
<p>打开Cygwin，或者在Linux下执行get-shapefiles.sh，下载并处理openstreetmap-cart中缺少的data目录：</p>
<pre class="crayon-plain-tag">#以Cygwin为例

apt-cyg install curl
apt-cyg install unzip

#编译gdal，在Ubuntu下只需要sudo apt-get install gdal-bin即可
#你也可以到http://download.gisinternals.com/下载编译好的二进制文件供Cygwin使用
wget http://download.osgeo.org/gdal/1.11.1/gdal-1.11.1.tar.gz
tar vzxf gdal-1.11.1.tar.gz
rm gdal-1.11.1.tar.gz
cd gdal-1.11.1/
./autogen.sh
./configure --host=mingw32 --without-libtool --without-python
make
make install

cd /cygdrive/c/Users/Suigintou/Documents/MapBox/project/openstreetmap-carto-master
./get-shapefiles.sh
#需要下载的数据较多，耐心等待
#如果出现Failed to connect to planet.openstreetmap.org port 80: Network is unreachable，则添加下一行到host文件
#193.63.75.107 planet.openstreetmap.org</pre>
<p>下载、处理完成后，打开TileMill，可以看到OpenStreetMap Carto这个项目，点击打开，然后点击右上角按钮，导出mapnik样式文件，如下图：<img class="aligncenter wp-image-4013" src="https://blog.gmem.cc/wp-content/uploads/2015/01/1.png" alt="1" width="600" height="453" /></p>
<p>导出成功后，打开XML文件，搜寻里面的类似：“C:\Users\用户名\Documents\MapBox\project\osm-carto\……”绝对路径，将其删除，并把路径中剩余部分的反斜杠改为正斜杠，修改完毕后，路径类似：“data/simplified-land-polygons-complete-3857/simplified_land_polygons.shp”，把文件移动到%OSM_STACK%\osm-carto目录下。</p>
<p>把整个openstreetmap-carto-master目录（就是TileMill编辑的工程）覆盖到%OSM_STACK%\osm-carto。</p>
<div class="blog_h3"><span class="graybg">安装和配置TileStache</span></div>
<p>安装便携版Python后，只需要执行下面的脚本：</p>
<pre class="crayon-plain-tag">easy_install tilestache

rem 可能需要检查以下依赖模块是否安装
easy_install PIL
easy_install ModestMaps
easy_install SimpleJSON</pre>
<p>在Windows上，如果使用的是Python 2.7.6，需要修改一下__init__.py的源码，否则运行时会报错：UnicodeDecodeError: utf8 codec can't decode byte 0xb0 in position 1: invalid start byte，这是Python的一个BUG。</p>
<pre class="crayon-plain-tag">import sys
reload(sys) 
sys.setdefaultencoding('gb18030') #添加上面三行即可
config_dict = json_load(urlopen(configpath))</pre>
<p>安装完毕后，通过下面的脚本即可启动TileStache的Web服务（基于 Werkzeug，一个<span style="color: #000000;">WSGI工具库</span>）：</p>
<pre class="crayon-plain-tag">echo ****** Prepare to start TileStache  ****** 
SET "TILE_STACHE_SCR=%PYTHON_HOME%\Scripts\tilestache-server.py"

python "%TILE_STACHE_SCR:\=/%"   -p 5539 -c tilestache.cfg</pre>
<p>其中tilestache.cfg是TileStache使用的配置文件，我们先使用下面这个做测试：</p>
<pre class="crayon-plain-tag">{
  "_comment": "tilestache.cfg包含两个顶级元素，分别实现缓存、图层的配置"
  "cache":
  {
    "name": "Disk",
    "path": "F:/Temp/tiles-cache"
  },
  "layers": 
  {
    "osm":
    {
        "provider": {"name": "proxy", "provider": "OPENSTREETMAP"}
    }
  }
}</pre>
<p>启动TileStache后，可以通过以下几个URL来测试：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;"> URL</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>http://127.0.0.1:5539/osm/preview.html</td>
<td>交互式的地图预览</td>
</tr>
<tr>
<td>http://127.0.0.1:5539/osm/0/0/0.png</td>
<td>
<p>显示一个静态瓦片，TileStache的URL风格类似于Google地图：</p>
<p>http://host:port/{layer name}/{zoom}/{column}/{row}.{extension} </p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">集成TileStache与mapnik</span></div>
<p> 下表列出集成mapnik时，tilestache.cfg可用的配置项：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 200px; text-align: center;"> JSON路径/属性</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2"><span style="background-color: #c0c0c0;">/cache</span></td>
</tr>
<tr>
<td>name</td>
<td>
<p>缓存的类型，可以是：</p>
<ol>
<li>Test：只是进行日志记录，不真正缓存，额外属性：
<ol>
<li>verbose：记录冗长的日志</li>
</ol>
</li>
<li>Disk：缓存到本地磁盘，额外属性：
<ol>
<li>path：缓存目录</li>
<li>umask：缓存文件的Unix权限，默认0022</li>
<li>dirs：目录创建风格，对于瓦片12/656/1582.png，portable将创建匹配的目录树，默认safe</li>
<li>gzip，一个数组，用于描述需要压缩的文件格式，默认["txt", "text", "json", "xml"]</li>
</ol>
</li>
<li>Multi：把瓦片缓存到多个、排序的缓存中，额外属性：
<ol>
<li>tiers：缓存配置列表</li>
</ol>
</li>
<li>Memcache：缓存到Memcache，依赖 python-memcached.
<ol>
<li>servers：缓存服务器的数组，例如 ["127.0.0.1:11211"]</li>
<li>revision：不考虑瓦片缓存期而大范围失效的修订版号，默认0</li>
<li>key prefix：缓存键的前缀</li>
</ol>
</li>
<li>Redis：缓存到Redis，依赖redis-py，需要redis server</li>
</ol>
</td>
</tr>
<tr>
<td colspan="2"><span style="background-color: #c0c0c0;">/layers/{layer_name}  <br />自定义的图层名称</span></td>
</tr>
<tr>
<td>stale lock timeout</td>
<td>该图层渲染等待超时时间，默认15秒</td>
</tr>
<tr>
<td>cache lifespan</td>
<td>瓦片缓存的秒数，默认0表示永久有效</td>
</tr>
<tr>
<td>projection</td>
<td>地理投影系统的名称，默认为spherical mercator（球形墨卡托）</td>
</tr>
<tr>
<td>write cache</td>
<td>可选参数，可以用于跳过缓存写入，默认为true</td>
</tr>
<tr>
<td>allowed origin</td>
<td>与HTTP响应头Access-Control-Allow-Origin有关</td>
</tr>
<tr>
<td>maximum cache age</td>
<td>最大缓存时间，TileStache会以此写HTTP响应头 Cache-Control、Expires</td>
</tr>
<tr>
<td>redirects</td>
<td>可选的扩展名重定向规则，例如可以设置 {"jpg": "png"}，导致jpg请求全部重定向到png</td>
</tr>
<tr>
<td>tile height</td>
<td>瓦片高度，默认256，一般不用改</td>
</tr>
<tr>
<td>jpeg options</td>
<td>JPEG图片选项</td>
</tr>
<tr>
<td>png options</td>
<td>PNG图片选项</td>
</tr>
<tr>
<td colspan="2"><span style="background-color: #c0c0c0;">/layers/{layer_name}/provider </span><br /><span style="background-color: #c0c0c0;">提供者是TileStache缓存静态文件并加速后续请求的组件</span></td>
</tr>
<tr>
<td>name</td>
<td>
<p>提供者的类型，可以是：</p>
<ol>
<li>mapnik：内置的mapnik提供者，根据Mapnik XML文件来渲染地图图像，额外属性：
<ol>
<li>mapfile： Mapnik XML文件的路径</li>
<li>fonts：可选的*.ttf字体目录</li>
</ol>
</li>
<li>proxy：穿透请求给其它地图服务器，并缓存瓦片，额外属性：
<ol>
<li>url：URL的模板，例如http://tile.openstreetmap.org/{Z}/{X}/{Y}.png</li>
<li>provider：可选的提供者名称，TileStache通过这个名称来寻找流行的地图服务器，例如OPENSTREETMAP</li>
</ol>
</li>
<li>vector：返回数据源中的矢量展示形式</li>
<li>url template：穿透请求给其它WMS服务器，并缓存瓦片，额外属性：
<ol>
<li>template：带有占位符的URL模板，占位符包括：width、height、srs、xmin、ymin、xmax、ymax、zoom</li>
<li>referer：可选的发送给目标WMS服务器的HTTP Referer URL </li>
<li>timeout：请求超时</li>
<li>source projection：使用的地理投影系统</li>
</ol>
</li>
<li>mbtiles：从 MBTiles tilesets中读取图像的提供者</li>
<li>mapnik grid：内置的Mapnik UTF Grid提供者，渲染Mapnik 2.0+的JSON光栅对象（JSON raster objects）</li>
</ol>
</td>
</tr>
<tr>
<td colspan="2">
<p><span style="background-color: #c0c0c0;">/layers/{layer_name}/metatile</span><br /><span style="background-color: #c0c0c0;">元瓦片，可选，使多个单独的瓦片能够同时渲染，以提高性能，主要用于mapnik之类的位图提供者</span></p>
</td>
</tr>
<tr>
<td>rows</td>
<td>高度跨越多少个瓦片，例如4</td>
</tr>
<tr>
<td>columns</td>
<td>宽度跨越多少个瓦片，例如4</td>
</tr>
<tr>
<td>buffer</td>
<td>元瓦片周围的缓冲区域大小，以像素为单位。对于渲染文字标签、图标的提供者很有用，防止 文字渲染不全，例如64</td>
</tr>
<tr>
<td colspan="2"><span style="background-color: #c0c0c0;">/layers/{layer_name}/bounds</span><br /><span style="background-color: #c0c0c0;">用于限制渲染可到达的地理区域</span></td>
</tr>
<tr>
<td>low</td>
<td>最小的缩放（zoom）级别，默认0</td>
</tr>
<tr>
<td>high</td>
<td>最大的缩放级别，默认31</td>
</tr>
<tr>
<td>north</td>
<td>北纬最大值，默认89</td>
</tr>
<tr>
<td>west</td>
<td>西经最大值，默认-180</td>
</tr>
<tr>
<td>south</td>
<td>南纬最大值，默认-89</td>
</tr>
<tr>
<td>east</td>
<td>东经最大之，默认180</td>
</tr>
<tr>
<td colspan="2"><span style="background-color: #c0c0c0;">/layers/{layer_name}/preview </span><br /><span style="background-color: #c0c0c0;">TileStache包含一个内置的 slippy map预览，所谓slippy map是指能够缩放、拖拽的Web地图</span></td>
</tr>
<tr>
<td>lat</td>
<td>维度</td>
</tr>
<tr>
<td>lon</td>
<td>经度</td>
</tr>
<tr>
<td>zoom</td>
<td>缩放级别</td>
</tr>
<tr>
<td>ext</td>
<td>扩展名，例如png</td>
</tr>
</tbody>
</table>
<p>tilestache.cfg可以配置为这样：</p>
<pre class="crayon-plain-tag">{
  "cache":
  {
    "name": "Disk",
    "path": "D:/Programs/OsmStack/tilestache/cache"
  },
  "layers": 
  {
    "osm":
    {
        "provider": {
            "name": "mapnik", 
            "mapfile": "file://D:/Programs/OsmStack/osm-carto/mapnik-style.xml",
            "fonts" : "D:/Programs/OsmStack/mapnik/fonts"
        },
        "metatile" : {
            "rows" : "4",
            "columns" : "4",
            "buffer" : "64"
        },
        "preview" : {
            "lat" : "39.9396",
            "lon" : "116.3488",
            "zoom" : "12",
            "ext" : "png"
        }
    }
  }
}</pre>
<p>注意其中的mapfile对应的路径，必须从Windows路径格式改为URI形式，例如：D:\Programs\Osmstack 改为 file://D:/Programs/Osmstack</p>
<p>tilestache.cfg改好后，启动TileStache Web服务，浏览器打开http://127.0.0.1:5539/osm/preview.html进行测试。</p>
<div class="blog_h3"><span class="graybg">绿化批处理脚本示意</span></div>
<p>在Windows下，可以参考下面三个脚本，分别完成地图服务器的初始化、启动、停止：</p>
<pre class="crayon-plain-tag">@echo off
chcp 437
pushd "%~dp0"

set "OSMSTACK_HOME=%CD%"
set "OSM_DIR=%OSMSTACK_HOME%\osm"
set "MAPNIK_HOME=%OSMSTACK_HOME%\mapnik"
set "PYTHON_HOME=%OSMSTACK_HOME%\python"
set "PSQL_HOME=%OSMSTACK_HOME%\psql"
set "OSM2PQSQL_HOME=%OSMSTACK_HOME%\osm2pgsql"
set "PATH=%OSM2PQSQL_HOME%;%MAPNIK_HOME%\lib;%MAPNIK_HOME%\bin;%PSQL_HOME%\bin;%PYTHON_HOME%;%PYTHON_HOME%\Scripts;%PATH%"
set "PYTHONPATH=%MAPNIK_HOME%\python\2.7\site-packages;%PYTHONPATH%"

SET "PGDATA=%PSQL_HOME%\data"
SET "PGDATABASE=postgres"
SET "PGUSER=postgres"
SET "PGPORT=5432"
SET "PGLOCALEDIR=%PSQL_HOME%\share\locale"
rem GIS databse name and owner
SET "GISDATABASE=gis"
SET "GISUSER=gisuser"

echo ****** Prepare to initializing PostgreSQL  ****** 
initdb -U %PGUSER% --auth=trust --auth-host=trust --auth-local=trust --pwprompt -E UTF8
copy %PSQL_HOME%\postgresql.conf %PSQL_HOME%\data\postgresql.conf /y

echo ****** Prepare to start PostgreSQL  ****** 
pg_ctl -w -l %PSQL_HOME%\pgsql.log start

echo ****** Creating user %GISUSER%  ****** 
createuser -U %PGUSER% -P %GISUSER%
echo ****** Creating database %GISDATABASE%  ****** 
createdb -U %PGUSER% -E UTF8 -O %GISUSER% %GISDATABASE%
echo ****** Installing procedural language into %GISDATABASE%  ****** 
createlang -U %PGUSER% plpgsql %GISDATABASE%
echo ****** Activating PostGIS for %GISDATABASE%  ****** 

psql -U %PGUSER% -d %GISDATABASE% -f "%PSQL_HOME%\share\contrib\postgis-2.1\postgis.sql"
psql -U %PGUSER% -d %GISDATABASE% -f "%PSQL_HOME%\share\contrib\postgis-2.1\spatial_ref_sys.sql"
rem After the activation, the following command should list the tables geometry_columns and spatial_ref_sys:
psql --username=%GISUSER% --dbname=%GISDATABASE% --command="\d"

echo ****** Installing extension hstore for %GISDATABASE%  ****** 
echo create extension hstore; | psql -U %PGUSER% -d %GISDATABASE%


echo ****** Import OSM data into %GISDATABASE%  ****** 
echo Please input osm package name ( without suffix '.osm.bz2' ), Press Enter to skip : 
set /p OSM_NAME=
if defined OSM_NAME (
    osm2pgsql -c -d gis -U %PGUSER% -H localhost -P %PGPORT%  --hstore -S %OSM2PQSQL_HOME%\openstreetmap-carto.style  -C 600 %OSM_DIR%\%OSM_NAME%.osm.bz2
)

echo ****** Processing TilesTache config file ****** 
set __OSM_PATH=%~p0
set __OSM_PATH=%__OSM_PATH:\=/%
python "tilestache/generate-cfg.py" %__OSM_PATH%

echo ****** Prepare to stop PostgreSQL  ****** 
pg_ctl -w stop

:end</pre><br />
<pre class="crayon-plain-tag">@echo off
chcp 437
pushd "%~dp0"

set "OSMSTACK_HOME=%CD%"
set "OSM_DIR=%OSMSTACK_HOME%\osm"
set "MAPNIK_HOME=%OSMSTACK_HOME%\mapnik"
set "PYTHON_HOME=%OSMSTACK_HOME%\python"
set "PSQL_HOME=%OSMSTACK_HOME%\psql"
set "OSM2PQSQL_HOME=%OSMSTACK_HOME%\osm2pgsql"
set "PATH=%OSM2PQSQL_HOME%;%MAPNIK_HOME%\lib;%MAPNIK_HOME%\bin;%PSQL_HOME%\bin;%PYTHON_HOME%;%PYTHON_HOME%\Scripts;%PATH%"
set "PYTHONPATH=%MAPNIK_HOME%\python\2.7\site-packages;%PYTHONPATH%"


SET "PGDATA=%PSQL_HOME%\data"
SET "PGDATABASE=postgres"
SET "PGUSER=postgres"
SET "PGPORT=5432"
SET "PGLOCALEDIR=%PSQL_HOME%\share\locale"

echo ****** Prepare to start PostgreSQL  ****** 
pg_ctl  -w  -l%PSQL_HOME%\pgsql.log start

echo ****** Prepare to start TileStache  ****** 
SET "TILE_STACHE_SCR=%PYTHON_HOME%\Scripts\tilestache-server.py"

python "%TILE_STACHE_SCR:\=/%"  -i 0.0.0.0 -p 5539 -c tilestache/osm.cfg</pre><br />
<pre class="crayon-plain-tag">@echo off
chcp 437
pushd "%~dp0"

set "OSMSTACK_HOME=%CD%"
set "MAPNIK_HOME=%OSMSTACK_HOME%\mapnik"
set "PYTHON_HOME=%OSMSTACK_HOME%\python"
set "PSQL_HOME=%OSMSTACK_HOME%\psql"
set "PATH=%MAPNIK_HOME%\lib;%MAPNIK_HOME%\bin;%PSQL_HOME%\bin;%PYTHON_HOME%;%PATH%"

SET "PGDATA=%PSQL_HOME%\data"
SET "PGDATABASE=postgres"
SET "PGUSER=postgres"
SET "PGPORT=5432"
SET "PGLOCALEDIR=%PSQL_HOME%\share\locale"

echo ****** Prepare to stop PostgreSQL  ****** 
pg_ctl -w stop</pre>
<div class="blog_h1"><span class="graybg">通过前端API使用OSM瓦片</span></div>
<div class="blog_h2"><span class="graybg">使用OpenLayers</span></div>
<p>OpenLayers很久以来一直是在网页中嵌入OSM地图的标准选择，它是一个成熟、综合的JS库，学习曲线较为平缓，提供大量的特性，包括完整的投影支持（<span style="color: #292929;">full projection support</span>）、矢量绘图、预览地图（<span style="color: #292929;">overview maps</span>）等等。</p>
<p>下面是一个简单的例子：</p>
<pre class="crayon-plain-tag">&lt;%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%&gt;
&lt;!doctype html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;link rel="stylesheet" href="openlayers3/ol.css" type="text/css"&gt;
    &lt;style&gt;
        html, body{ margin:0; height:100%; }
        #mapdiv { width:100%; height:100%; }
    &lt;/style&gt;
    &lt;script src="openlayers3/ol.js" type="text/javascript"&gt;&lt;/script&gt;
    &lt;title&gt;OpenLayers3 Example&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
 
&lt;div id="mapdiv" &gt;&lt;/div&gt;
&lt;script type="text/javascript"&gt;
    //定义一个矢量图像
    var image = new ol.style.Circle({
        radius: 5,
        fill: new ol.style.Stroke({color: '#F00'}),
        stroke: new ol.style.Stroke({color: '#000', width: 1})
    });
    //定义样式
    var styles = {
        'Point': [new ol.style.Style({
            image: image
        })],
        'Polygon': [new ol.style.Style({
            stroke: new ol.style.Stroke({
                color: '#00F',
                lineDash: [2],
                width: 1
            }),
            fill: new ol.style.Fill({
                color: 'rgba(0, 0, 255, 0.1)'
            })
        })]
    };
    //定义一个矢量图层
    var vectorSource = new ol.source.GeoJSON(
    ({
        object: {
            'type': 'FeatureCollection',
            //坐标参考系（Coordinate Reference Systems）
            'crs': {
                'type': 'name',
                'properties': {
                    'name': 'EPSG:3857'
                }
            },
            'features': [
                //画一个点
                {
                    'type': 'Feature',
                    'geometry': {
                        'type': 'Point',
                        //坐标系转换：
                        //EPSG:4326，直接把经纬度作为X、Y方向的坐标值，南纬、西经为负数
                        //EPSG:3857，球面墨卡托投影，以米为单位，以前叫EPSG:900931
                        'coordinates': ol.proj.transform([ 116.34430, 39.94225], 'EPSG:4326', 'EPSG:3857')
                    }
                },
                //画一个五边形
                {
                    'type': 'Feature',
                    'geometry': {
                        'type': 'Polygon',
                        'coordinates': [
                            [
                                ol.proj.transform([ 116.1007694, 40.2551712], 'EPSG:4326', 'EPSG:3857'),
                                ol.proj.transform([ 117.2687534, 40.3578032], 'EPSG:4326', 'EPSG:3857'),
                                ol.proj.transform([ 117.5886384, 39.2306078], 'EPSG:4326', 'EPSG:3857'),
                                ol.proj.transform([ 116.9843903, 38.42073], 'EPSG:4326', 'EPSG:3857'),
                                ol.proj.transform([ 115.5792222, 39.1692678], 'EPSG:4326', 'EPSG:3857')
                            ]
                        ]
                    }
                },
            ]
        }
    }));
 
    var styleFunction = function (feature, resolution) {
        return styles[feature.getGeometry().getType()];
    };
    //定义一个矢量图层
    var vectorLayer = new ol.layer.Vector({
        source: vectorSource,
        style: styleFunction//寻找样式定义的回调函数
    });
    //定义一个地图
    var map = new ol.Map({
        target: 'mapdiv', //渲染目标
        //图层列表，包含一个光栅图层，一个矢量图层
        layers: [
            new ol.layer.Tile({
                source: new ol.source.XYZ({
                    url: 'http://192.168.0.89:5539/osm/{z}/{x}/{y}.png'
                }),
            }),
            vectorLayer
        ],
        //视角：缩放级别7，以北二环为中心
        view: new ol.View({
            center: ol.proj.transform([116.34430, 39.94225], 'EPSG:4326', 'EPSG:3857'),
            zoom: 7
        })
    });
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<div class="blog_h2"><span class="graybg">使用Leaflet</span></div>
<p>Leaflet是一个近来迅速流行的JavaScript库，比起OpenLayers它更小小巧、简单，对于简单寻常的需求，Leaflet是个好的选择。</p>
<p>下面是一个简单的例子：</p>
<pre class="crayon-plain-tag">&lt;%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%&gt;
&lt;!DOCTYPE HTML&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Leaflet Example&lt;/title&gt;
    &lt;link rel="stylesheet" type="text/css" href="leaflet/leaflet.css" /&gt;
    &lt;script type="text/javascript" src="leaflet/leaflet-src.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript"&gt;
        var map;

        function init() {
            // 在一个DIV中创建地图对象
            map = new L.Map('mapdiv');
    
            // 创建瓦片图层
            var osmUrl='http://192.168.0.89:5539/osm/{z}/{x}/{y}.png';
            var osmAttrib='Kingsmart Tech';
            var osm = new L.TileLayer(osmUrl, {minZoom: 3, maxZoom: 18, attribution: osmAttrib});       
    
            // 地图中心设置为西北二环附近
            map.setView(new L.LatLng( 39.94225, 116.34430 ),12);
            map.addLayer(osm);//添加图层
            
            //在地图上添加标记
            var plot = {
                "name":"金名科技",
                "lon":"116.34430",
                "lat":"39.94225",
                "details":"金名科技是座落于海淀区高粱桥斜街59号院的高新技术企业"
            };
            var plotll = new L.LatLng( plot.lat, plot.lon, true );//标记的坐标
            var mark = new L.Marker(plotll);
            mark.data = plot;
            map.addLayer(mark);//添加标记到地图
            mark.bindPopup("&lt;h4&gt;" + plot.name + "&lt;/h4&gt;" + plot.details);//绑定提示框
            
            //在地图上添加一个多边形
            var latlngs = [
                new L.LatLng( 39.931064087073835, 116.3481330871582),    
                new L.LatLng( 39.9600172003783, 116.32684707641602),   
                new L.LatLng( 39.99264056247673, 116.37628555297852 ),   
                new L.LatLng( 39.97922477476731, 116.46417617797852 ),   
                new L.LatLng( 39.90657598772841, 116.45936965942383),   
                new L.LatLng( 39.87338459498892, 116.36838912963867),   
                new L.LatLng( 39.931064087073835, 116.3481330871582)
            ];
            var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
        }
    &lt;/script&gt;

    &lt;style&gt;
    html, body{ margin:0; height:100%; }
    #mapdiv { width:100%; height:100%; }
    div.olControlAttribution { bottom:3px; }
    &lt;/style&gt;

&lt;/head&gt;

&lt;body onload="init();"&gt;
    &lt;div id="mapdiv"&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/setup-openstreetmap-server">基于OpenStreetMap的地图服务器的搭建</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/setup-openstreetmap-server/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
	</channel>
</rss>
