代码之家  ›  专栏  ›  技术社区  ›  Carson

没有<Document>标签的KML/OpenLayers GroundOverlay元素没有加载到地图上?

  •  -1
  • Carson  · 技术社区  · 6 年前

    我有一个KML元素,没有文档标记,只是像…(用…)这样的标记删除了一些不相关的元素)

    <?xml version="1.0" encoding="UTF-8"?>
    <kml xmlns="http://www.opengis.net/kml/2.2">
    <GroundOverlay>
        <name>...</name>
        <description>...</description>
        <Icon><href>...</href></Icon>
        <LatLonBox>
           ...
        </LatLonBox>
    </GroundOverlay>
    </kml>
    

    在OpenLayers中,如果groundoverlayer周围没有文档标签,我就无法加载它。但是,我可以得到一个位置标记,它是根节点,没有要加载的文档标记。

    2 回复  |  直到 6 年前
        1
  •  0
  •   Carson    6 年前
        2
  •  0
  •   Mike    5 年前

    可以使用地面覆盖瓷砖作为OpenLayers层的源。到目前为止,我只做了硬编码的坐标,瓷砖大小,瓷砖路径等手动读取KML和让OpenLayers计算正确的投影,虽然proj4允许旋转投影,我还没有整理出需要处理旋转的数学。我有一个演示基于样本数据从 https://www.dwgwalking.co.uk/garminTryB4Buy.htm http://mikenunn.16mb.com/demo/dwg-aracena-demo.htm 使用顶行的东/西坐标和左列的北/南坐标,并忽略非常小的旋转。

    attributions crossOrigin .

    var tileLayer = new ol.layer.Tile({
        source: new ol.source.XYZ({
            attributions: [
                'Powered by Esri',
                'Source: Esri, DigitalGlobe, GeoEye, Earthstar Geographics, CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS User Community'
            ],
            attributionsCollapsible: false,
            url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
            maxZoom: 23
        })
    });
    
    var map = new ol.Map({
        layers: [tileLayer],
        target: 'map',
        logo: false,
        view: new ol.View({
            center:[0, 0],
            zoom: 2
        })
    });
    
    var extent = ol.extent.createEmpty();
    
    var group = kmlOverlay.loadUrl(
        'https://www.mikenunn.net/data/dwg/aracena/doc.kml',
        { attributions: 'Copyright David Brawn <a href="https://www.dwgwalking.co.uk" target="_blank">www.dwgwalking.co.uk</a>' }
    );
    
    group.getLayers().on('add', function(evt) {
        evt.element.once('change:source', function() {
            if (evt.element.getSource && evt.element.getSource().getProjection) {
                var imageProj = evt.element.getSource().getProjection();
                ol.extent.extend(extent, ol.proj.transformExtent(imageProj.getExtent(), imageProj, map.getView().getProjection()));
                map.getView().fit(extent);
            }
        });
    });
    
    group.setOpacity(0.7);
    map.addLayer(group);
    html, body {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
    }
    .map {
        width: 100%;
        height: 100%;
    }
    <link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
    <script>
    
    kmlOverlay = function() {
    
    function loadUrl ( url,
                       opt_options  // attributions (defaults to undefined), crossOrigin (defaults to 'anonymous')
    ) {
    
        var options = opt_options || {};
        var crossOrigin = options.crossOrigin === undefined ? 'anonymous' : options.crossOrigin;
    
        var group = new ol.layer.Group();
    
        function addLayer(name, extent, url, rotation) {  // function to maintain context during async img load
    
            var imageLayer = new ol.layer.Image({
                title: name
            });
            group.getLayers().push(imageLayer);
    
            var imageSize = [];
            var img = document.createElement('img');
            img.onload = function() {
                imageSize[0] = img.width;
                imageSize[1] = img.height;
                imageLayer.setSource(
                    source (
                        extent,
                        url,
                        rotation,
                        imageSize,
                        { attributions: options.attributions, crossOrigin: crossOrigin }
                    )
                );
            };
            img.crossOrigin = crossOrigin;
            img.src = url;
    
        }
    
        var last = url.lastIndexOf('/') + 1;
        path = url.slice(0, last);
    
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.onload = function() {
    
            var parser = new DOMParser();
            var xmlDoc = parser.parseFromString(xhr.responseText,'text/xml');
    
            var elements = xmlDoc.getElementsByTagName('GroundOverlay');
    
            for (var i=0; i<elements.length; i++) {
    
                var name;
                if (elements[i].getElementsByTagName('rotation').length > 0) {
                    name = elements[i].getElementsByTagName('name')[0].childNodes[0].nodeValue;
                }
                var href = elements[i].getElementsByTagName('href')[0].childNodes[0].nodeValue;
                if (href.indexOf('http:') != 0 && href.indexOf('https:') != 0) {
                    href = path + href;
                }
                var north = Number(elements[i].getElementsByTagName('north')[0].childNodes[0].nodeValue);
                var south = Number(elements[i].getElementsByTagName('south')[0].childNodes[0].nodeValue);
                var east = Number(elements[i].getElementsByTagName('east')[0].childNodes[0].nodeValue);
                var west = Number(elements[i].getElementsByTagName('west')[0].childNodes[0].nodeValue);
                var rotation = 0;
                if (elements[i].getElementsByTagName('rotation').length > 0) {
                    rotation = Number(elements[i].getElementsByTagName('rotation')[0].childNodes[0].nodeValue);
                }
    
                addLayer(name, [west, south, east, north], href, rotation);
    
            }
    
        }
        xhr.send();
        return group;
    
    }
    
    function source ( kmlExtent, // KMLs specify the extent the unrotated image would occupy
                      url,
                      rotation,
                      imageSize,
                      opt_options  // attributions, crossOrigin (default to undefined)
    ) {
    
        var options = opt_options || {};
    
        // calculate latitude of true scale of equidistant cylindrical projection based on pixels per degree on each axis
    
        proj4.defs('EPSG:' + url, '+proj=eqc +lat_ts=' +
                                  (Math.acos((ol.extent.getHeight(kmlExtent)/imageSize[1])
                                            /(ol.extent.getWidth(kmlExtent)/imageSize[0]))*180/Math.PI) +
                                  ' +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');
    
        if (ol.proj.proj4 && ol.proj.proj4.register) { ol.proj.proj4.register(proj4); } // if OL5 register proj4
    
        // convert the extents to source projection coordinates
    
        var projection = ol.proj.get('EPSG:' + url);
        var projExtent = ol.proj.transformExtent(kmlExtent, 'EPSG:4326', projection);
    
        var angle = -rotation * Math.PI/180;
    
        function rotateTransform(coordinate) {
            var point = new ol.geom.Point(coordinate);
            point.rotate(angle, ol.extent.getCenter(projExtent));
            return point.getCoordinates();
        }
    
        function normalTransform(coordinate) {
            var point = new ol.geom.Point(coordinate);
            point.rotate(-angle, ol.extent.getCenter(projExtent));
            return point.getCoordinates();
        }
    
        var rotatedProjection = new ol.proj.Projection({
            code: 'EPSG:' + url + ':rotation:' + rotation,
            units: 'm',
            extent: projExtent
        });
        ol.proj.addProjection(rotatedProjection);
    
        ol.proj.addCoordinateTransforms('EPSG:4326', rotatedProjection,
            function(coordinate) {
                return rotateTransform(ol.proj.transform(coordinate, 'EPSG:4326', projection));
            },
            function(coordinate) {
                return ol.proj.transform(normalTransform(coordinate), projection, 'EPSG:4326');
            }
        );
    
        ol.proj.addCoordinateTransforms('EPSG:3857', rotatedProjection,
            function(coordinate) {
                return rotateTransform(ol.proj.transform(coordinate, 'EPSG:3857', projection));
            },
            function(coordinate) {
                return ol.proj.transform(normalTransform(coordinate), projection, 'EPSG:3857');
            }
        );
    
        return new ol.source.ImageStatic({
            projection: rotatedProjection,
            url: url,
            imageExtent: projExtent,
            attributions: options.attributions,
            crossOrigin: options.crossOrigin
        });
    
    }
    
    return {
       "loadUrl" : loadUrl,
       "source"  : source
    }
    
    } ();
    
    </script>
    <div id="map" class="map"></div>

    这里是一个单一的覆盖演示非常明显的旋转采取从 https://renenyffenegger.ch/notes/tools/Google-Earth/kml/index

    var tileLayer = new ol.layer.Tile({
        source: new ol.source.XYZ({
            attributions: [
                'Powered by Esri',
                'Source: Esri, DigitalGlobe, GeoEye, Earthstar Geographics, CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS User Community'
            ],
            //attributionsCollapsible: false,
            url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
            maxZoom: 23
        })
    });
    
    var map = new ol.Map({
        layers: [tileLayer],
        target: 'map',
        logo: false,
        view: new ol.View({
            center:[0, 0],
            zoom: 2
        })
    });
    
    var extent = ol.extent.createEmpty();
    
    var group = kmlOverlay.loadUrl(
        'https://raw.githubusercontent.com/ReneNyffenegger/about-GoogleEarth/master/kml/GroundOverlay.kml'
    );
    
    group.getLayers().once('add', function(evt) {
        evt.element.once('change:source', function() {
            if (evt.element.getSource && evt.element.getSource().getProjection) {
                var imageProj = evt.element.getSource().getProjection();
                ol.extent.extend(extent, ol.proj.transformExtent(imageProj.getExtent(), imageProj, map.getView().getProjection()));
                map.getView().fit(extent, { constrainResolution: false });
            }
        });
    });
    
    group.setOpacity(0.8);
    map.addLayer(group);
    html,正文{
    边距:0;
    填充:0;
    宽度:100%;
    }
    .地图{
    高度:100%;
    }
    <链接href=“https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css“rel=”样式表“/>
    <脚本src=“https://cdn.polyfill.io/v2/polyfill.min.js?功能=requestAnimationFrame,元素.prototype.classList,URL“></script>
    <脚本src=“https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js“></script>
    <脚本src=“https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js“></script>
    
    
    函数loadUrl(url,
    ) {
    
    变量交叉原点=选项.crossOrigin===未定义?'匿名':选项.crossOrigin;
    
    var group=新建ol.layer.Group组();
    
    函数addLayer(name,extent,url,rotation){//用于在异步img加载期间维护上下文的函数
    
    var imageLayer=新建ol.layer.Image公司({
    });
    
    var imageSize=[];
    变量img=文档.createElement(‘img’);
    图像大小[1]=仪表高度;
    来源(
    范围,
    网址,
    图像大小,
    {属性:选项.属性,交叉原点:交叉原点}
    )
    图像交叉原点=交叉原点;
    img.src公司=网址;
    
    }
    
    路径=url.slice文件(0,最后一个);
    
    var xhr=new XMLHttpRequest();
    xhr打开('GET',网址);
    
    var parser=new DOMParser();
    
    变量元素=xmlDoc.getElementsByTagName(‘地面覆盖’);
    
    
    变量名称;
    if(elements[i].getElementsByTagName('旋转').length>0){
    var href=elements[i].getElementsByTagName('href')[0].childNodes[0].nodeValue;
    如果(href.indexOf索引('http:')!=0&href.indexOf索引('https:')!= 0) {
    href=路径+href;
    }
    var north=Number(元素[i].getElementsByTagName('north')[0].childNodes[0].nodeValue);
    var south=Number(元素[i].getElementsByTagName('south')[0].childNodes[0].nodeValue);
    var east=Number(元素[i].getElementsByTagName('east')[0].childNodes[0].nodeValue);
    var west=Number(元素[i].getElementsByTagName('west')[0].childNodes[0].nodeValue);
    rotation=Number(元素[i].getElementsByTagName('rotation')[0].childNodes[0].nodeValue);
    }
    
    
    }
    
    }
    返回组;
    
    }
    
    网址,
    旋转,
    图像大小,
    opt\u options//属性,交叉原点(默认为未定义)
    
    var options=opt| |{};
    
    
    proj4.defs('EPSG:'+url,'+proj=eqc+lat\ts='+
    (数学.acos((起点高度(kmlExtent)/图像大小[1])
    '+纬度0=0+经度0=0+经度0=0+经度0=0+经度0=0+基准面=WGS84+单位=m+无定义';
    
    
    //将范围转换为源投影坐标
    
    var投影=ol.proj.get公司('EPSG:'+url);
    
    可变角度=-旋转*数学.PI/180;
    
    函数旋转变换(坐标){
    var点=新ol.geom.点(坐标);
    返回点.getCoordinates();
    
    函数法线变换(坐标){
    var点=新ol.geom.点(坐标);
    点.旋转(-角度,ol.extent.getCenter公司(项目范围);
    返回点.getCoordinates();
    }
    
    var rotatedProjection=新建ol.proj.投影({
    代码:“EPSG:”+url+“:旋转:”+rotation,
    范围:projExtent
    });
    
    ol.proj.addCoordinateTransforms项目('EPSG:4326'旋转投影,
    功能(坐标){
    },
    功能(坐标){
    返回ol.proj.转换(法线变换(坐标),投影,'EPSG:4326');
    }
    );
    
    ol.proj.addCoordinateTransforms项目('EPSG:3857'旋转投影,
    功能(坐标){
    功能(坐标){
    返回ol.proj.转换(法线变换(坐标),投影,'EPSG:3857');
    }
    );
    
    返回新的ol.source.ImageStatic文件({
    投影:旋转投影,
    imageExtent:项目范围,
    属性:选项.属性,
    交叉原点:选项.crossOrigin
    });
    
    }
    
    返回{
    “来源”:来源
    
    } ();
    
    </script>