ArcGIS API for JavaScript 4.16 局部场景添加自定义坐标系的场景图层(已修改)

1
分享 2020-07-20
替换这个文件中的._transformNode方法,以及注释掉一个检验坐标系的地方即可
\library\4.16\esri\views的SceneView.js
 方法修改前:
g.prototype._transformNode = function (a, b, d) {
for (var e = b.geometryData.geometries, f = Array(e.length), g = 0; g < e.length; ++g) f[g] = this._getVertexBufferLayout(e[g], b.geometryDescriptor);
var e = a.mbs,
h = this.elevationOffset,
k = this._controller.crsIndex,
l = this._controller.crsVertex,
m = this.view.renderSpatialReference,
g = V.getLocalOrigin(e, h, k),
h = V.computeGlobalTransformation(e, h, k, m),
k = ka.getProjectorName(k, l),
l = ka.getProjectorName(l, m);
return c.isNone(k) || c.isNone(l) ? null : this._worker.invoke({
context: this.layer.uid,
geometryBuffer: b.geometryBuffer,
geometryData: b.geometryData,
geometryDescriptor: b.geometryDescriptor,
layouts: f,
localOrigin: g,
globalTrafo: h,
mbs: e,
obb: a.obb,
elevationOffset: this.elevationOffset,
needNormals: !this._isIntegratedMesh && this._controller.isMeshPyramid,
normalReferenceFrame: this.layer.normalReferenceFrame || "none",
indexToVertexProjector: k,
vertexToRenderProjector: l
}, d)
};
有两种修改方式,按需使用,推荐使用第一种方式。但第二种方式也给了扩展的可行性。
 
第一种方式,不支持动态投影,需保证当前场景的坐标系和场景图层的坐标系完全一致。效果很好。
g.prototype._transformNode = function (a, b, d) {
for (var e = b.geometryData.geometries, f = Array(e.length), g = 0; g < e.length; ++g) f[g] = this._getVertexBufferLayout(e[g], b.geometryDescriptor);
console.log(this._controller);
this._controller.crsIndex.wkt = this.view.renderSpatialReference.wkt;
this._controller.crsVertex.wkt = this.view.renderSpatialReference.wkt;
console.log(this._controller.crsIndex);
console.log(this._controller.crsVertex);
console.log(this.view.renderSpatialReference);
var e = a.mbs,
h = this.elevationOffset,
k = this._controller.crsIndex,
l = this._controller.crsVertex,
m = this.view.renderSpatialReference,
g = V.getLocalOrigin(e, h, k),
h = V.computeGlobalTransformation(e, h, k, m),
k = ka.getProjectorName(k, l),
l = ka.getProjectorName(l, m);
console.log(k);
console.log(l);
return c.isNone(k) || c.isNone(l) ? null : this._worker.invoke({
context: this.layer.uid,
geometryBuffer: b.geometryBuffer,
geometryData: b.geometryData,
geometryDescriptor: b.geometryDescriptor,
layouts: f,
localOrigin: g,
globalTrafo: h,
mbs: e,
obb: a.obb,
elevationOffset: this.elevationOffset,
needNormals: !this._isIntegratedMesh && this._controller.isMeshPyramid,
normalReferenceFrame: this.layer.normalReferenceFrame || "none",
indexToVertexProjector: k,
vertexToRenderProjector: l
}, d)
};

第二种方式,支持动态投影,兼容不同坐标系信息的同坐标叠加。以SceneView坐标系为准。
g.prototype._transformNode = function(a, b, d) {
for (var e = b.geometryData.geometries,
f = Array(e.length), g = 0; g < e.length; ++g) f[g] = this._getVertexBufferLayout(e[g], b.geometryDescriptor);
this._controller.crsIndex.wkt = this.view.renderSpatialReference.wkt;
this._controller.crsVertex.wkt = this.view.renderSpatialReference.wkt;
if (this._controller.crsIndex.wkid !== null || this._controller.crsIndex.wkid !== undefined || this._controller.crsIndex.wkid !== '') {
this._controller.crsIndex.wkid = this.view.renderSpatialReference.wkid;
this._controller.crsVertex.wkid = this.view.renderSpatialReference.wkid;
var e = a.mbs,
h = this.elevationOffset,
k = this._controller.crsIndex,
l = this._controller.crsVertex,
m = this.view.renderSpatialReference,
g = V.getLocalOrigin(e, h, k),
h = V.computeGlobalTransformation(e, h, k, m),
k = ka.getProjectorName(k, l),
l = ka.getProjectorName(l, m);
} else {
var e = a.mbs,
h = this.elevationOffset,
k = this._controller.crsIndex,
l = this._controller.crsVertex,
m = this.view.renderSpatialReference,
g = V.getLocalOrigin(e, h, k),
h = V.computeGlobalTransformation(e, h, k, m),
k = ka.getProjectorName(k, l),
l = ka.getProjectorName(l, m);
}
return c.isNone(k) || c.isNone(l) ? this._worker.invoke({
context: this.layer.uid,
geometryBuffer: b.geometryBuffer,
geometryData: b.geometryData,
geometryDescriptor: b.geometryDescriptor,
layouts: f,
localOrigin: g,
globalTrafo: h,
mbs: e,
obb: a.obb,
elevationOffset: this.elevationOffset,
needNormals: !this._isIntegratedMesh && this._controller.isMeshPyramid,
normalReferenceFrame: this.layer.normalReferenceFrame || "none",
indexToVertexProjector: "copy3",
vertexToRenderProjector: "copy3"
},
d) : this._worker.invoke({
context: this.layer.uid,
geometryBuffer: b.geometryBuffer,
geometryData: b.geometryData,
geometryDescriptor: b.geometryDescriptor,
layouts: f,
localOrigin: g,
globalTrafo: h,
mbs: e,
obb: a.obb,
elevationOffset: this.elevationOffset,
needNormals: !this._isIntegratedMesh && this._controller.isMeshPyramid,
normalReferenceFrame: this.layer.normalReferenceFrame || "none",
indexToVertexProjector: k,
vertexToRenderProjector: l
},
d)
};

 
无论以上采用那一种方式,始终都需要修改坐标系检查部分的代码。坐标系检查代码修改前:
function P(a,b,c){if(!w.canProject(a,b))throw new h("layerview:spatial-reference-incompatible","The spatial reference of this scene layer is incompatible with the spatial reference of the view",{});if("local"===c&&a.isGeographic)throw new h("layerview:local-gcs-not-supported","Geographic coordinate systems are not supported in local scenes",{});}

坐标系检查代码修改后:
function P(a,b,c){/*if(!w.canProject(a,b))throw new h("layerview:spatial-reference-incompatible","The spatial reference of this scene layer is incompatible with the spatial reference of the view",{});*/if("local"===c&&a.isGeographic)throw new h("layerview:local-gcs-not-supported","Geographic coordinate systems are not supported in local scenes",{});}

--------------------------------2020年11月5日更新----------------------------------------------
根据用户反馈,自定义坐标系的场景图层在进行SceneLayerView的filter空间过滤时失败,并且控制台看到警告:
控制台警告.png
针对此问题,应修改\library\4.16\esri\views的SceneView.js的5463行添加一句
this._controller.crsIndex.wkt = this.view.renderSpatialReference.wkt;

即可解决。
修改后的代码为:
function(a, b, c, d) {
    var e = c[0].spatialReference || this.view.spatialReference;
    console.log(E);
    console.log(b.node.mbs);
    this._controller.crsIndex.wkt = this.view.renderSpatialReference.wkt;
    console.log(this._controller.crsIndex);
    console.log(W);
    console.log(e);
    if (E.mbsToMbs(b.node.mbs, this._controller.crsIndex, W, e)) for (var f = y.acquireMaskFilterContext(d, this.view, e, this._collection, b.objectHandle), g = y.computeMaskNodeMBS(W, f), e = function(c) {
        if (0 === a.length) return {
            value: void 0
        };
        switch (y.testMaskWithGeometry(c, g, d)) {
        case 1:
            return a.length = 0,
            {
                value: void 0
            };
        case 0:
            return "continue"
        }
        F.filterInPlace(a, b.featureIds,
        function(a) {
            return y.filterWithMask(c, a, f)
        })
    },
    h = 0; h < c.length; h++) {
        var k = e(c[h]);
        if ("object" === typeof k) return k.value
    } else Q.warnOnce("SceneLayerView.filter.geometry is using unsupported SpatialReference, skipping geometry filter")
};

这样,自定义空间参考的场景图层就可以进行空间过滤了。

geoscenelogo.png

 

4 个评论

有用户反馈使用了第二种以后,速度慢了20%-30%。还在研究如何优化。
已优化,目前两种方式有一样的效率和清晰程度。
请问有无办法可以实现arcgis js api不同坐标系二维地图叠加?
许丹石

许丹石 回复 OJB

动态地图服务、要素服务、影像服务、影像切片服务都可以支持不同坐标系二维叠加。

要回复文章请先登录注册