OpenLayers移动屏幕和重复地图与矢量图层

时间:2014-07-22 14:39:40

标签: android openlayers openstreetmap

我正在使用Openlayers.mobile.js库在Android应用程序中嵌入OSM。

屏幕尺寸问题

我遇到的第一个问题是,当我缩放到0级时,例如在纵向中,而不是显示整个行星地图并在屏幕的额外顶部和底部填充黑色,它看起来像是相反的:垂直缩放到最大范围并剪切地图的额外水平边。

如果我设置了maxExtent(-180,-90,180,90),地图与屏幕的相对位置相同,并且不允许我移动地图,因此无法访问两个额外的边。

如果它正在考虑屏幕尺寸是相反的,但是如果我在风景中这样做,我只会在屏幕上看到地图的中心部分。

我理想的愿望是将所有地图都放在屏幕上,并在所有额外的屏幕上填充黑色。在这两种情况下,风景和肖像。

重复问题

由于我无法正确修复地图的maxExtent,因此在水平平移时会自动重复。我使用动态绘制多边形的矢量图层。当用户移动地图时,有时会将多边形的某些点移动到x +360º,因此,当关闭多边形时,它会显示奇怪的形状。 (它通过混合x点和x + 360点来关闭多边形。

有没有办法告诉矢量图层我希望所有点都是最接近的点,然后他可以决定整个多边形应该是x​​还是x + 360? 有没有办法阻止地图重复或重复矢量图层的方式与地图重复的方式相同(允许在地图的两个位置显示相同的国家/多边形(x和x +360º)?

注意:当多边形位于两个贴图之间时,只移动点,否则移动的是整个多边形。我需要告诉构造函数Polygon多边形是通过接近而不是单个地图中的点来关闭的。因此,点p1 =( - 179,0)和p2 =(179,0)应该在不经过点(0,0)但是经过点(180,0)=( - 180,0)的情况下关闭。

一些代码

Mobile.js:

// initialize map when page ready
var map;

// Get rid of address bar on iphone/ipod
var fixSize = function() {
    window.scrollTo(0,0);
    document.body.style.height = '100%';
    if (!(/(iphone|ipod)/.test(navigator.userAgent.toLowerCase()))) {
        if (document.body.parentNode) {
            document.body.parentNode.style.height = '100%';
        }
    }
};
setTimeout(fixSize, 700);
setTimeout(fixSize, 1500);

    var init = function () {
    // create map
    map = new OpenLayers.Map({
        div: "map",
        theme: null,
        numZoomLevels: 18,
        controls: [
            new OpenLayers.Control.TouchNavigation({
                dragPanOptions: {
                    enableKinetic: true
                }
            })
        ],
        layers: [
            new OpenLayers.Layer.OSM("OpenStreetMap", null, {
                transitionEffect: 'resize'
            })
        ],
        center: new OpenLayers.LonLat(0, 0),
        zoom: 0
    });
};

index.html->周期性绘图功能:

    //Stations      
    if(Math.abs(sc_altitude-sc_altitude_tmp)>sc_altitude_step){
        stations_area_layer.removeAllFeatures();
        for (var arrayIndex in station_areas){
            /*
            var radius = Rt*Math.sin(Math.acos(Rt/(Rt+sc_altitude-stations[arrayIndex].ellipsoid_elevation)));

            var circle = OpenLayers.Geometry.Polygon.createRegularPolygon(
                new OpenLayers.Geometry.Point(stations[arrayIndex].longitude, stations[arrayIndex].latitude).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()),
                radius,
                30 
            );

            //circle.transform(new OpenLayers.Projection("EPSG:4258"), map.getProjectionObject());
            var station_feature = new OpenLayers.Feature.Vector(circle, null, station_area_style);
            stations_area_layer.addFeatures([station_feature]);
            */
            var areaPoints = [];
            for (var i in station_areas[arrayIndex].points) {
                var coord = station_areas[arrayIndex].points[i];
                var point = new OpenLayers.Geometry.Point(coord.longitude, coord.latitude);
                // transform from WGS 1984 to Spherical Mercator
                point.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
                areaPoints.push(point);
            }               
            areaPoints.push(areaPoints[0]);

            var linearRing = new OpenLayers.Geometry.LinearRing(areaPoints);
            var geometry = new OpenLayers.Geometry.Polygon([linearRing]);
            var polygonFeature = new OpenLayers.Feature.Vector(geometry, null, station_area_style);
            stations_area_layer.addFeatures([polygonFeature]);
        }

        sc_altitude_tmp = sc_altitude;
    }

index.html->头:

<head>
    <title>OpenLayers Mobile</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="stylesheet" href="theme/default/style.css" type="text/css">
    <link rel="stylesheet" href="theme/default/style.mobile.css" type="text/css">
<script type='text/javascript' src="interface.js"></script>
<!--<script src="http://www.openlayers.org/api/OpenLayers.js"></script>-->
<script src="OpenLayers.mobile.js"></script>
    <script src="mobile.js"></script>

<script type="text/javascript" src="proj4js/proj4.js"></script>
<script type="text/javascript" src="greatCircle.js"></script>
<script type="text/javascript" src="greatcirclemod.js"></script>
<SCRIPT type="text/javascript" src="proj4js/data/tmerc.js"></SCRIPT>
<SCRIPT type="text/javascript" src="proj4js/data/merc.js"></SCRIPT>
<SCRIPT type="text/javascript" src="proj4js/data/EPSG31466.js"></SCRIPT>
<SCRIPT type="text/javascript" src="proj4js/data/EPSG31467.js"></SCRIPT>
<SCRIPT type="text/javascript" src="proj4js/data/EPSG900913.js"></SCRIPT>
<!--<script type="text/javascript" src="javascript/counter_orthodrome.js"></script>-->
<style>
        html, body {
            margin  : 0;
            padding : 0;
            height  : 100%;
            width   : 100%;
        }
        @media only screen and (max-width: 600px) {
            html, body {
                height  : 117%;
            }
        }
        #map {
            width    : 100%;
            position : absolute;
            height   : 100%;
        }
        .olControlAttribution {
            position      : absolute;
            font-size     : 10px;
            bottom        : 0 !important;
            right         : 0 !important;
            background    : rgba(0,0,0,0.1);
            font-family   : Arial;
            padding       : 2px 4px;
            border-radius : 5px 0 0 0;
        }
        #title, #tags, #shortdesc {
            display: none;
        }
    </style>
</head>

2 个答案:

答案 0 :(得分:1)

由于没有答案,我将解释我发现的内容以及我所做的解决方法:

对于屏幕尺寸:

当不使用map wrappingDateLine时,地图有不同的扩展名。 地图具有固定的最大缩放级别(来自切片提供者)。此缩放级别未考虑屏幕边界和像素密度,因为智能手机中的缩放级别1与平板电脑中的缩放1完全不同。没有简单的方法可以使地图始终适合任何设备。

可以使用setMaxResolution和MinResolution来改善这种行为。

重复层次:

现在我没有包装日期行,但我认为我的解决方法适用于所有情况:

我需要一种方法来区分多边形是否包含一些极点和哪一个。幸运的是,我有一种方法可以使用生成多边形点的相同库来区分它。

通过这种区分,我可以创建两种不同的函数,这些函数将以不同的方式运行:

对于封闭多边形:

这个想法是检测经度符号的变化,丢弃地图中间的符号变化(0º),并在检测到跳跃时交替填充两个点阵列。此外,在检测到的每次跳跃时,我们将通过选择经度-180/180和两个纬度之间的平均值(点之前和之后)来添加部分多边形的极限点。

我们最终得到了两个可用于构建多边形的数组。在下面的函数中,arrayIndex对应于“station”数组的索引,每个站包含一组用于创建多边形的点。

function paintClosedArea(arrayIndex){
var areaFirst = [];
var areaSecond = [];
var area_tmp_long = 0, area_tmp_lat = 0;
var first = true;
for (var i in station_areas[arrayIndex].points) {
    var coord = station_areas[arrayIndex].points[i];
    var point = new OpenLayers.Geometry.Point(
                        coord.longitude, 
                        coord.latitude
        ).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());

    if((i!=0) && ((coord.longitude*area_tmp_long)<0) && (Math.abs(coord.longitude)>90.0) && (area_tmp_long+coord.longitude<90.0)){
        var avg_lat = (coord.latitude+area_tmp_lat)/2;
        if(coord.longitude > 0)
            var new_lon = -179.999999;
        else
            var new_lon = 179.999999;
        if(first){
            areaFirst.push(new OpenLayers.Geometry.Point(new_lon, avg_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
            areaSecond.push(new OpenLayers.Geometry.Point(-new_lon, avg_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
            first=false;
        }else{
            areaFirst.push(new OpenLayers.Geometry.Point(-new_lon, avg_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
            areaSecond.push(new OpenLayers.Geometry.Point(+new_lon, avg_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
            first=true;
        }
    }
    area_tmp_lat = coord.latitude;
    area_tmp_long = coord.longitude;

    if(first){
        areaFirst.push(point);
    }else{
        areaSecond.push(point);
    }                   
}               
if(areaFirst.length>0){
    //areaFirst.push(areaFirst[0]);
    var linearRing = new OpenLayers.Geometry.LinearRing(areaFirst);
    var geometry = new OpenLayers.Geometry.Polygon([linearRing]);
    var polygonFeature = new OpenLayers.Feature.Vector(geometry, null, station_area_style);
    stations_area_layer.addFeatures([polygonFeature]);
}
if(areaSecond.length>0){
    //areaSecond.push(areaSecond[0]);
    var linearRing = new OpenLayers.Geometry.LinearRing(areaSecond);
    var geometry = new OpenLayers.Geometry.Polygon([linearRing]);
    var polygonFeature = new OpenLayers.Feature.Vector(geometry, null, station_area_style);
    stations_area_layer.addFeatures([polygonFeature]);
}
}

对于开放多边形,即包含内部极点的多边形,我们将生成一个点数组(一个多边形),但在这种情况下,当我们检测到日期行中的跳转时,我们添加4分:两个极限-180,180但是在包含北极的情况下,两个角-180,90 180,90,-180,-90 180,-90如果它包含南极。

通过给出这些额外的4个点,多边形将被填充,填充孔杆,如果不是,结果不会包围杆,多边形会自行切割。

在下面的函数中,arrayIndex与之前相同,如果多边形包含北极,则type为1;如果是北极,则type为2:

function paintOpenArea(arrayIndex,type){
var areaFirst = [];
var areaSecond = [];
var area_tmp_long = 0, area_tmp_lat = 0;
var first = true;
for (var i in station_areas[arrayIndex].points) {
    var coord = station_areas[arrayIndex].points[i];
    var point = new OpenLayers.Geometry.Point(
                        coord.longitude, 
                        coord.latitude
        ).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());

    if((i!=0) && ((coord.longitude*area_tmp_long)<0) && (Math.abs(coord.longitude)>90.0) && (area_tmp_long+coord.longitude<90.0)){
        var avg_lat = (coord.latitude+area_tmp_lat)/2;
        if(coord.longitude > 0)
            var new_lon = -179.999999;
        else
            var new_lon = 179.999999;
        if(type == 1)
            var new_lat = 90.0;
        else
            var new_lat = -90.0;

        areaFirst.push(new OpenLayers.Geometry.Point(new_lon, avg_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
        areaFirst.push(new OpenLayers.Geometry.Point(new_lon, new_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
        areaFirst.push(new OpenLayers.Geometry.Point(-new_lon, new_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
        areaFirst.push(new OpenLayers.Geometry.Point(-new_lon, avg_lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));

    }
    area_tmp_lat = coord.latitude;
    area_tmp_long = coord.longitude;

    areaFirst.push(point);                  
}               
if(areaFirst.length>0){
    //areaFirst.push(areaFirst[0]);
    var linearRing = new OpenLayers.Geometry.LinearRing(areaFirst);
    var geometry = new OpenLayers.Geometry.Polygon([linearRing]);
    var polygonFeature = new OpenLayers.Feature.Vector(geometry, null, station_area_style);
    stations_area_layer.addFeatures([polygonFeature]);
}
}

循环调用前两个函数的函数是:

function drawStationsAreas(){
if(Math.abs(sc_altitude-sc_altitude_tmp)>sc_altitude_step){
    stations_area_layer.removeAllFeatures();
    for (var arrayIndex in station_areas){
        if(station_areas[arrayIndex].type==0)
            paintClosedArea(arrayIndex);
        else
            paintOpenArea(arrayIndex,station_areas[arrayIndex].type);

    }

    sc_altitude_tmp = sc_altitude;
}
}

我们必须意识到这些函数并不完美,让输入的点集不是从一个极端开始是非常重要的(不会检测到日期行中的跳转)。

如果任何人不同意某些陈述,或者有关于这些功能的评论或建议,请不要犹豫,不要评论答案。

答案 1 :(得分:0)

谢谢你。在OL 5中,您可能不需要拆分封闭的多边形,只需将某些点的经度调整为> 180或<-180。这样,它可以绘制适当的多边形。但是,这种方法不适用于开放多边形,因此仍然需要额外的细分技巧。