本篇来说下ArcGIS API for JavaScript中的GeometryEngine,它包含了很多种方法,主要用于测量,叠加及测试Web应用程序中各几何之间的空间关系。类似于GeometryService中提供的方法,那么GeometryService和GeometryEngine有什么不同之处呢,在前端通过GeometryEngine是在客户端进行所有工作,使用任何GeometryEngine的方法时,不会发出网络请求。GeometryService是调用服务器端几何服务来实现,这意味着使用支持GeometryService的GeometryEngine可以显著提高web应用程序的性能,特别是当它们频繁地使用GeometryService请求或处理大量几何图形时。详见https://www.esri.com/arcgis-blog/products/js-api-arcgis/uncategorized/geometryengine-part-1-testing-spatial-relationships-and-editing/?rmedium=redirect&rsource=blogs.esri.com/esri/arcgis/2015/09/09/geometryengine-part-1-testing-spatial-relationships-and-editing
下面主要来介绍下geometryEngine中部分方法的使用及示例。
1、geometryEngine中的difference(inputGeometry, subtractor)构造两个几何的差异。
geometryEngine中的difference(inputGeometry, subtractor)将返回一个几何体,最终的几何体是inputGeometry不在subtractor中的部分。
情形一:两个几何体a和b, b完全包含a,如下图
geometryEngine中的difference后的结果:
情形二:两个几何体a和b, a与b有相交部分
geometryEngine中的difference后的结果::
示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>Intro to graphics - 4.14</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/themes/light/main.css"/>
<script src="https://js.arcgis.com/4.14/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require(["esri/Map", "esri/views/MapView","esri/geometry/Polygon","esri/Graphic",
"esri/geometry/geometryEngine","esri/geometry/geometryEngineAsync"], function(
Map,
MapView,Polygon,
Graphic,geometryEngine,geometryEngineAsync
) {
var map = new Map({
basemap: "osm"
});
var view = new MapView({
container: "viewDiv",
map: map,
center:[116.40, 39.90],
zoom:10
});
var rings1 = [
[
116.31151839225571,
39.943673736657132
],
[
116.35335002431609,
39.934926457303497
],
[
116.37236440252542,
39.927636203716013
],
[
116.37806871598811,
39.907219363120021
],
[
116.35430074322652,
39.882419302690636
],
[
116.31246911116614,
39.874393832515196
],
[
116.24116519288133,
39.913053367254633
],
[
116.31151839225571,
39.943673736657132
]
];
var polygon1 = new Polygon({
rings: rings1,
spatialReference: { wkid: 4326 }
});
var rings2 = [
[
116.28870113840455,
39.980108697240922
],
[
116.39232949964514,
39.976466074890702
],
[
116.44937263427295,
39.880960196153566
],
[
116.4075410022126,
39.851771545601245
],
[
116.27444035474754,
39.845202387911023
],
[
116.20503787428369,
39.90721936312007
],
[
116.28870113840455,
39.980108697240922
]
];
var polygon2 = new Polygon({
rings: rings2,
spatialReference: { wkid: 4326 }
});
var fillSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [227, 139, 79, 0.8],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 1
}
};
var fillSymbol2 = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [0, 255, 0, 0.5],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 0],
width: 1
}
};
var polygonGraphic1 = new Graphic({
geometry: polygon1
});
var polygonGraphic2 = new Graphic({
geometry: polygon2,
symbol: fillSymbol
});
var difference = geometryEngine.difference(polygon2, polygon1);
console.log(difference);
var polygonGraphic3 = new Graphic({
geometry: difference,
symbol: fillSymbol2
});
console.log(polygonGraphic3);
view.graphics.addMany([polygonGraphic3]);
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
2、geometryEngine 中的union(geometries)计算几何集合的并集
其中union(geometries)中的geometries输入参数必须具有相同的几何类型共享一个空间参考。下面举一个具体示例:a和b两个面进行合并,如下图所示
union后的结果:
示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>Intro to graphics - 4.14</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/themes/light/main.css"/>
<script src="https://js.arcgis.com/4.14/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require(["esri/Map", "esri/views/MapView","esri/geometry/Polygon","esri/Graphic","esri/geometry/geometryEngine"], function(
Map,
MapView,Polygon,
Graphic,geometryEngine
) {
var map = new Map({
basemap: "osm"
});
var view = new MapView({
container: "viewDiv",
map: map,
center:[116.40, 39.90],
zoom:10
});
var rings1 = [
[
116.31151839225571,
39.943673736657132
],
[
116.35335002431609,
39.934926457303497
],
[
116.37236440252542,
39.927636203716013
],
[
116.37806871598811,
39.907219363120021
],
[
116.35430074322652,
39.882419302690636
],
[
116.31246911116614,
39.874393832515196
],
[
116.24116519288133,
39.913053367254633
],
[
116.31151839225571,
39.943673736657132
]
];
var polygon1 = new Polygon({
rings: rings1,
spatialReference: { wkid: 4326 }
});
var rings2 = [
[
116.28870113840455,
39.980108697240922
],
[
116.39232949964514,
39.976466074890702
],
[
116.44937263427295,
39.880960196153566
],
[
116.4075410022126,
39.851771545601245
],
[
116.27444035474754,
39.845202387911023
],
[
116.20503787428369,
39.90721936312007
],
[
116.28870113840455,
39.980108697240922
]
];
var polygon2 = new Polygon({
rings: rings2,
spatialReference: { wkid: 4326 }
});
var fillSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [227, 139, 79, 0.8],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 1
}
};
var fillSymbol2 = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [0, 255, 0, 0.5],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 0],
width: 1
}
};
// Add the geometry and symbol to a new graphic
var polygonGraphic1 = new Graphic({
geometry: polygon1
});
var polygonGraphic2 = new Graphic({
geometry: polygon2,
symbol: fillSymbol
});
var union = geometryEngine.union([polygon1, polygon2]);
var polygonGraphic3 = new Graphic({
geometry: union,
symbol: fillSymbol2
});
//view.graphics.addMany([polygonGraphic1,polygonGraphic2]);
view.graphics.addMany([polygonGraphic1,polygonGraphic2,polygonGraphic3]);
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
3、geometryEngine.geodesicArea(geometry, unit)
计算输入几何的面积。geodesicArea在执行此计算时会考虑地球的曲率。因此,当使用空间参考为WGS84(wkid:4326)或Web Mercator的输入几何时,最佳实践是使用geodesicArea()计算面积。如果输入的几何图形具有Web Mercator以外的投影坐标系,请改用planeArea()。此方法仅适用于WGS84(wkid:4326)和Web Mercator空间参考。
4、geometryEngine.planarArea(geometry, unit)
计算输入几何的面积。使用投影坐标执行该计算,并且不考虑地球的曲率。如果输入的几何图形具有Web Mercator以外的投影坐标系,需要使用planeArea()
5、geometryEngine.geodesicLength(geometry, unit)
计算输入几何的长度。在执行此计算时会考虑地球的曲率。因此,当使用空间参考为WGS84(wkid:4326)或Web Mercator的输入几何时,最好的做法是使用geodesicLength()计算长度。如果输入的几何图形具有Web Mercator以外的投影坐标系,请改用planeLength()。此方法仅适用于WGS84(wkid:4326)和Web Mercator空间参考。
6、geometryEngine.planarLength(geometry, unit)
计算输入几何的长度。使用投影坐标以及执行该计算时,不会考虑地球的曲率。如果输入的几何图形具有Web Mercator以外的投影坐标系,需要用planeLength()
具体示例:下面是利用geodesicArea和geodesicLength方法的一个具体示例,用到了esri/views/2d/draw/Draw,具体代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>Measure</title>
<style>
html,
body,
#viewDiv {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font-family: verdana;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/css/main.css" />
<script src="https://js.arcgis.com/4.14/init.js"></script>
<script>
require([
"esri/views/2d/draw/Draw","esri/Map",
"esri/views/MapView",
"esri/Graphic", "esri/geometry/Polygon",
"esri/geometry/geometryEngine"
], function(Draw, Map, MapView, Graphic,Polygon,geometryEngine) {
var map = new Map({
basemap: "osm"});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-77.02, 38.89],
zoom: 15
});
view.ui.add("draw-polyline", "top-left");
view.ui.add("draw-polygon", "top-left");
var draw = new Draw({
view: view
});
// 画线按钮
document.getElementById("draw-polyline").addEventListener("click", function() {
view.graphics.removeAll();
// create() will return a reference to an instance of polylineDrawAction
var action = draw.create("polyline"); // focus the view to activate keyboard shortcuts for drawing polylines
view.focus();
// listen polylineDrawAction events to give immediate visual feedback
// to users as the polyline is being drawn on the view.
action.on("vertex-add", drawPolyline);
action.on("cursor-update", drawPolyline);
action.on("vertex-remove", drawPolyline);
action.on("redo", drawPolyline);
action.on("undo", drawPolyline);
action.on("draw-complete", drawPolyline);
});
// this function is called from the polyline draw action events
// to provide a visual feedback to users as they are drawing a polyline
function drawPolyline(event) {
var vertices = event.vertices;
//remove existing graphic
view.graphics.removeAll();
// create a new polyline
var polyline = {
type: "polyline", // autocasts as Polyline
paths: vertices,
spatialReference: view.spatialReference
};
// create a new graphic representing the polyline, add it to the view
var graphic = new Graphic({
geometry: polyline,
symbol: {
type: "simple-line", // autocasts as SimpleLineSymbol
color: "blue",
width: 4,
cap: "round",
join: "round"
}
}
view.graphics.add(graphic);
// calculate the area of the polyline
var area = geometryEngine.geodesicLength( graphic.geometry, "kilometers");
var lastSeg = vertices[vertices.length - 1];
var graphic = new Graphic({
geometry: {
type: "point",
x: lastSeg[0],
y: lastSeg[1],
spatialReference: view.spatialReference
},
symbol: {
type: "text",
color: "green",
haloColor: "black",
haloSize: "1px",
text: area.toFixed(2) + "km",
xoffset: 3,
yoffset: 3,
font: {
size: 14, // autocast as Font
family: "sans-serif"
}
}
});
view.graphics.add(graphic);
}
// 画面按钮
document.getElementById("draw-polygon").addEventListener("click",
function() {
view.graphics.removeAll();
// create() will return a reference to an instance of PolygonDrawAction
var action = draw.create("polygon");
// focus the view to activate keyboard shortcuts for drawing polygons
view.focus();
// listen polygonDrawAction events to give immediate visual feedback
// to users as the polygon is being drawn on the view.
action.on("vertex-add", drawPolygon);
action.on("cursor-update", drawPolygon);
action.on("vertex-remove", drawPolygon);
action.on("redo", drawPolygon);
action.on("undo", drawPolygon);
action.on("draw-complete", drawPolygon);
});
function drawPolygon(event) {
var vertices = event.vertices;
//remove existing graphic
view.graphics.removeAll();
// create a new polygon
var polygon = new Polygon({
rings: vertices,
spatialReference: view.spatialReference
});
// create a new graphic representing the polygon, add it to the view
var graphic = new Graphic({
geometry: polygon,
symbol: {
type: "simple-fill", // autocasts as SimpleFillSymbol
color: [218, 102, 144, 0.8],
style: "solid",
outline: { // autocasts as SimpleLineSymbol
color: [255, 255, 255],
width: 2
}
}
});
view.graphics.add(graphic);
// calculate the area of the polygon
var area = geometryEngine.geodesicArea(polygon, "acres");
if (area < 0) {
// simplify the polygon if needed and calculate the area again
var simplifiedPolygon = geometryEngine.simplify(polygon);
if (simplifiedPolygon) {
area = geometryEngine.geodesicArea(simplifiedPolygon, "acres");
}
}
// start displaying the area of the polygon
labelAreas(polygon, area);
}
//Label polyon with its area
function labelAreas(geom, area) {
var graphic = new Graphic({
geometry: geom.centroid,
symbol: {
type: "text",
color: "white",
haloColor: "black",
haloSize: "1px",
text: area.toFixed(2) + " acres",
xoffset: 1,
yoffset: 1,
font: { // autocast as Font
size: 14,
family: "sans-serif"
}
}
});
view.graphics.add(graphic);
}
});
</script>
</head>
<body>
<div id="viewDiv">
<div id="draw-polyline" class="esri-widget--button esri-widget esri-interactive" title="Draw and measure polyline">
<span class="esri-icon-polyline"></span>
</div>
<div id="draw-polygon" class="esri-widget--button esri-widget esri-interactive"
title="Draw and measure polygon">
<span class="esri-icon-polygon"></span>
</div>
</div>
</body>
</html>
测面效果图:
测距效果图
7、geometryEngine.buffer(geometry, distance, unit, unionResults)
GeometryEngine有两种方法来缓冲几何图形客户端:buffer和geodesicBuffer。如果输入几何是WGS84的空间参考(WKID:4326)或web墨卡托,可使用geodesicBuffer()。若尝试使用Web Mercator以外的投影坐标系来缓冲几何时,仅使用geometryEngine.buffer()。如果需要使用WGS84(wkid:4326)外的地理坐标系来缓冲几何,需要使用GeometryService.buffer()。
8、geometryEngine.geodesicBuffer(geometry, distance, unit, unionResults)
在输入的几何体周围指定距离处创建测地线缓冲区多边形。在计算距离时,该方法考虑了地球的曲率,当处理在全球范围内空间变化的非常大的几何图形和/或几何图形时,如果一个投影坐标系不能精确地绘制坐标和测量所有几何图形的距离,则该方法可提供高精度的结果。此方法仅适用于WGS84(wkid:4326)和Web Mercator空间参考。