mapbox中的旋转点是倾斜的

时间:2017-05-10 11:32:35

标签: javascript rotation mapbox

我有一个mapbox示例,其中我执行以下操作:
1)设置俯仰角为60度的视图
2)绘制画布角点以使观看截头体为梯形< 3)将轴承改变30度并再次得到梯​​形图4)缩小看梯形
5)手动旋转第一个梯形30度
6)绘制旋转的梯形
7)将音高改为零以向下看图像
当我这样做时,手动旋转的梯形(图像中的红色)与使用setBearing生成的梯形不匹配( )呼叫(图像中的紫色)。它似乎是不正确的倾斜,我一直在看手动旋转代码8小时,无法弄清楚原因。我处理地球曲率旋转坐标问题还是?有人可以解决这个问题吗?谢谢!

&#13;
&#13;
mapboxgl.accessToken = 'pk.eyJ1IjoiZm1hY2RlZSIsImEiOiJjajJlNWMxenowNXU2MzNudmkzMndwaGI3In0.ALOYWlvpYXnlcH6sCR9MJg';

var map;

function addLayerToMap(name, points, color, width) {
    map.addLayer({
        "id": name,
        "type": "line",
        "source": {
            "type": "geojson",
            "data": {
                "type": "Feature",
                "properties": {},
                "geometry": {
                    "type": "LineString",
                    "coordinates": points
                }
            }
        },
        "layout": {
            "line-join": "round",
            "line-cap": "round"
        },
        "paint": {
            "line-color": color,
            "line-width": width
        }
    });
}

function pointsRotate(points, cx, cy, angle){
    var radians = (Math.PI / 180) * angle;
    var cos = Math.cos(radians);
    var sin = Math.sin(radians);
    var newpoints = [];

    function rotate(x, y) {
        nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
        ny = (cos * (y - cy)) + (-sin * (x - cx)) + cy;
        return [nx, ny];
    }
    for(var i=0;i<points.length;i++) {
        newpoints[i] = rotate(points[i][0],points[i][1]);
    }
    return(newpoints);
}

function convertTrapezoidToPath(trap) {
    return([ 
        [trap.Tl.lng, trap.Tl.lat], [trap.Tr.lng, trap.Tr.lat], 
        [trap.Br.lng, trap.Br.lat], [trap.Bl.lng, trap.Bl.lat], 
        [trap.Tl.lng, trap.Tl.lat] ]);
}

function getViewTrapezoid() {
    var canvas = map.getCanvas();
    var trap = {};

    trap.Tl = map.unproject([0,0]);
    trap.Tr = map.unproject([canvas.offsetWidth,0]);
    trap.Br = map.unproject([canvas.offsetWidth,canvas.offsetHeight]);
    trap.Bl = map.unproject([0,canvas.offsetHeight]);

    return(trap);
}

map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v9',
    center: [-122.48610019683838, 37.82880236636284],
    zoom: 17,
    pitch: 60
});

map.on('load', function () {

  // get the center and trapezoid of the zoomed in view
  var center = map.getCenter();
  var trapezoid = getViewTrapezoid();
  
  // convert the view trapezoid to a path and add it to the view
  var trapezoid_path = convertTrapezoidToPath(trapezoid);
  addLayerToMap("viewTrapezoid",trapezoid_path,'#888',4);

  // now rotate the bearing by 30 degrees to get a second view trapezoid 
  map.setBearing(30);
  setTimeout(function() {
    var trapezoid2 = getViewTrapezoid();
    var trapezoid2_path = convertTrapezoidToPath(trapezoid2);
    addLayerToMap("viewTrapezoid2",trapezoid2_path,'#f0f',2);
    
    // return to a "top down" view and zoom out to show the trapezoids
    map.setBearing(0);
    map.setZoom(13.5);
      setTimeout(function() {
        map.flyTo({ pitch: 0 });
        
        // rotate the original view trapezoid by 30 degrees and add it to the map
        var newpath = pointsRotate(trapezoid_path,center.lng,center.lat,30);
        addLayerToMap("rotatedTrapezoid",newpath,'#f00',2);
    }, 500);
  }, 500);
  
  
 
});
&#13;
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
&#13;
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.css' rel='stylesheet' />

<div id='map'></div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

好吧,事实证明,当你接近极点时经度变得越来越薄,你首先需要将所有度坐标(纬度和长度)转换为考虑到非球面性质的墨卡托坐标地球的。我在这里添加了两个函数,它们从lat lon转换为mercator,反之亦然,并将它们放入代码中,结果是一个直接位于使用setBearing()方法提供的梯形顶部的梯形。问题解决了!

mapboxgl.accessToken = 'pk.eyJ1IjoiZm1hY2RlZSIsImEiOiJjajJlNWMxenowNXU2MzNudmkzMndwaGI3In0.ALOYWlvpYXnlcH6sCR9MJg';

var map;

function addLayerToMap(name, points, color, width) {
    map.addLayer({
        "id": name,
        "type": "line",
        "source": {
            "type": "geojson",
            "data": {
                "type": "Feature",
                "properties": {},
                "geometry": {
                    "type": "LineString",
                    "coordinates": points
                }
            }
        },
        "layout": {
            "line-join": "round",
            "line-cap": "round"
        },
        "paint": {
            "line-color": color,
            "line-width": width
        }
    });
}

function pointsRotate(points, cx, cy, angle){
    var radians = (Math.PI / 180) * angle;
    var cos = Math.cos(radians);
    var sin = Math.sin(radians);
    var newpoints = [];

    function rotate(x, y) {
        nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
        ny = (cos * (y - cy)) + (-sin * (x - cx)) + cy;
        return [nx, ny];
    }
    for(var i=0;i<points.length;i++) {
        newpoints[i] = rotate(points[i][0],points[i][1]);
    }
    return(newpoints);
}

function convertTrapezoidToPath(trap) {
    return([ 
        [trap.Tl.lng, trap.Tl.lat], [trap.Tr.lng, trap.Tr.lat], 
        [trap.Br.lng, trap.Br.lat], [trap.Bl.lng, trap.Bl.lat], 
        [trap.Tl.lng, trap.Tl.lat] ]);
}

function getViewTrapezoid() {
    var canvas = map.getCanvas();
    var trap = {};

    trap.Tl = map.unproject([0,0]);
    trap.Tr = map.unproject([canvas.offsetWidth,0]);
    trap.Br = map.unproject([canvas.offsetWidth,canvas.offsetHeight]);
    trap.Bl = map.unproject([0,canvas.offsetHeight]);

    return(trap);
}

function Mercator2ll(mercX, mercY) { 
    var rMajor = 6378137; //Equatorial Radius, WGS84
    var shift  = Math.PI * rMajor;
    var lon    = mercX / shift * 180.0;
    var lat    = mercY / shift * 180.0;
    lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180.0)) - Math.PI / 2.0);

    return [ lon, lat ];
}
function ll2Mercator(lon, lat) {
    var rMajor = 6378137; //Equatorial Radius, WGS84
    var shift  = Math.PI * rMajor;
    var x      = lon * shift / 180;
    var y      = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
    y = y * shift / 180;

    return [ x, y ];
}

function convertDegrees2Meters(points) {
    var newpoints = [];

    for(var i=0;i<points.length;i++) {
        newpoints[i] = ll2Mercator( points[i][0], points[i][1] );
    }
    return newpoints;
}
function convertMeters2Degrees(points) {
    var newpoints = [];

    for(var i=0;i<points.length;i++) {
        newpoints[i] = Mercator2ll( points[i][0], points[i][1] );;
    }
    return newpoints;
}

map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v9',
    center: [-122.48610019683838, 37.82880236636284],
    zoom: 17,
    pitch: 60
});

map.on('load', function () {

  // get the center and trapezoid of the zoomed in view
  var center = map.getCenter();
  var trapezoid = getViewTrapezoid();
  var center_meters = ll2Mercator(center.lng,center.lat);
  // convert the view trapezoid to a path and add it to the view
  var trapezoid_path = convertTrapezoidToPath(trapezoid);
  addLayerToMap("viewTrapezoid",trapezoid_path,'#888',4);

  // now rotate the bearing by 30 degrees to get a second view trapezoid 
  map.setBearing(30);
  setTimeout(function() {
    var trapezoid2 = getViewTrapezoid();
    var trapezoid2_path = convertTrapezoidToPath(trapezoid2);
    addLayerToMap("viewTrapezoid2",trapezoid2_path,'#f0f',2);
    
    // return to a "top down" view and zoom out to show the trapezoids
    map.setBearing(0);
    map.setZoom(13.5);
      setTimeout(function() {
        map.flyTo({ pitch: 0 });
        
        // rotate the original view trapezoid by 30 degrees and add it to the map
        var tpath_meters = convertDegrees2Meters(trapezoid_path);
        var newpath_meters = pointsRotate(tpath_meters,center_meters[0],center_meters[1],30);
        var newpath = convertMeters2Degrees(newpath_meters);
        addLayerToMap("rotatedTrapezoid",newpath,'#f00',2);
    }, 500);
  }, 500); 
});
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.css' rel='stylesheet' />

<div id='map'></div>