{{{ArcGISUtils.java
}}}
package com.hylab.websiteforgis.utils;
import com.esri.arcgisruntime.ArcGISRuntimeException;
import com.esri.arcgisruntime.arcgisservices.ArcGISFeatureServiceInfo;
import com.esri.arcgisruntime.arcgisservices.IdInfo;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.*;
import com.esri.arcgisruntime.geometry.*;
import com.esri.arcgisruntime.loadable.LoadStatus;
import com.esri.arcgisruntime.security.Credential;
import com.esri.arcgisruntime.security.UserCredential;
import com.esri.arcgisruntime.utilitynetworks.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hylab.websiteforgis.model.R;
import com.hylab.websiteforgis.utils.trace.ResultElement;
import com.hylab.websiteforgis.utils.trace.TraceLocation;
import com.hylab.websiteforgis.utils.trace.TraceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* ArcGIS工具类
*
* @author liteng
* @since 2022-11-01
*/
public class ArcGISUtils {
private final static SpatialReference spatialReference = SpatialReference.create(3857);
private final static ObjectMapper mapper = new ObjectMapper();
private final static Logger logger = LoggerFactory.getLogger(ArcGISUtils.class);
/**
* 获取Geodatabase
*
* @param serviceUrl 服务地址
* @param timeout 超时时间
* @return 加载结果
*/
public static R<ServiceGeodatabase> getGeodatabase(String serviceUrl, String username, String password, long timeout) {
ServiceGeodatabase db = new ServiceGeodatabase(serviceUrl);
Credential credential = new UserCredential(username, password);
db.setCredential(credential);
db.loadAsync();
CountDownLatch countDownLatch = new CountDownLatch(1);
R<ServiceGeodatabase> result = new R<>();
db.addDoneLoadingListener(() -> {
if (db.getLoadStatus() == LoadStatus.LOADED) {
result.setOk(db);
} else {
ArcGISRuntimeException exception = db.getLoadError();
exception.printStackTrace();
result.setFail(exception.getMessage());
}
countDownLatch.countDown();
});
try {
if (!countDownLatch.await(timeout, TimeUnit.SECONDS)) {
result.setFail("请求服务超时");
}
} catch (InterruptedException e) {
e.printStackTrace();
result.setFail(e.getMessage());
}
return R.ok(db);
}
/**
* 根据图层名称获取图层
*
* @param db 服务数据库
* @param names 图层名称
* @return 结果
*/
public static List<IdInfo> getLayerByNames(ServiceGeodatabase db, List<String> names) {
ArcGISFeatureServiceInfo info = db.getServiceInfo();
List<IdInfo> layers = info.getLayerInfos();
List<IdInfo> infos = new ArrayList<>();
names.forEach(name -> {
Optional<IdInfo> layerVal = layers.stream().filter(n -> n.getName().equals(name)).findFirst();
if (layerVal.isPresent()) {
infos.add(layerVal.get());
} else {
logger.warn("图层{}不存在", name);
}
});
return infos;
}
/**
* 获取图层数据表
*
* @param db 数据库
* @param layerId 图层id
* @param timeout 超时时间
* @return 结果
*/
public static R<FeatureTable> getFeatureTable(ServiceGeodatabase db, long layerId, long timeout) {
FeatureTable table = db.getTable(layerId);
table.loadAsync();
CountDownLatch countDownLatch = new CountDownLatch(1);
R<FeatureTable> result = new R<>();
table.addDoneLoadingListener(() -> {
if (table.getLoadStatus() == LoadStatus.LOADED) {
result.setOk(table);
} else {
ArcGISRuntimeException exception = table.getLoadError();
exception.printStackTrace();
result.setFail(exception.getMessage());
}
countDownLatch.countDown();
});
try {
if (!countDownLatch.await(timeout, TimeUnit.SECONDS)) {
result.setFail("请求服务超时");
}
} catch (InterruptedException e) {
e.printStackTrace();
result.setFail(e.getMessage());
}
return result;
}
/**
* 获取相交要素
*
* @param table 数据表
* @param geometry 几何
* @param timeout 超时时间
* @return 结果
*/
public static R<List<Feature>> getIntersectFeatures(FeatureTable table, Geometry geometry, long timeout) {
QueryParameters query = new QueryParameters();
query.setSpatialRelationship(QueryParameters.SpatialRelationship.INTERSECTS);
query.setGeometry(geometry);
query.setMaxFeatures(100000);
query.setOutSpatialReference(spatialReference);
query.setReturnGeometry(true);
R<List<Feature>> result = new R<>();
ListenableFuture<FeatureQueryResult> featuresAsync = ((ServiceFeatureTable) table).queryFeaturesAsync(query, ServiceFeatureTable.QueryFeatureFields.LOAD_ALL);
try {
List<Feature> features = new ArrayList<>();
featuresAsync.get(timeout, TimeUnit.SECONDS).forEach(feature -> {
features.add(feature);
});
result.setOk(features);
} catch (Exception e) {
e.printStackTrace();
result.setFail(e.getMessage());
}
return result;
}
/**
* 获取某个位置附近要素
*
* @param table 数据表
* @param x 横坐标
* @param y 纵坐标
* @param timeout 超时时间
* @return 附近要素
*/
public static R<List<Feature>> getNearFeatures(FeatureTable table, double x, double y, long timeout) {
double offset = 0.1;
Envelope envelope = new Envelope(x - offset, y - offset, x + offset, y + offset, spatialReference);
return getIntersectFeatures(table, envelope, timeout);
}
/**
* 获取某个表所有要素
*
* @param table 数据表
* @param timeout 超时时间
* @return 附近要素
*/
public static R<List<Feature>> getAllFeatures(FeatureTable table, long timeout) {
Envelope envelope = new Envelope(-180, -90, 180, 90, SpatialReference.create(4326));
return getIntersectFeatures(table, envelope, timeout);
}
/**
* 获取公共设施网络
*
* @param serviceUrl 服务地址
* @param timeout 超时时间
* @return 加载结果
*/
public static R<UtilityNetwork> getUtilityNetwork(String serviceUrl, long timeout) {
UtilityNetwork utilityNetwork = new UtilityNetwork(serviceUrl);
utilityNetwork.loadAsync();
CountDownLatch countDownLatch = new CountDownLatch(1);
R<UtilityNetwork> result = new R<>();
utilityNetwork.addDoneLoadingListener(() -> {
if (utilityNetwork.getLoadStatus() == LoadStatus.LOADED) {
result.setOk(utilityNetwork);
} else {
ArcGISRuntimeException exception = utilityNetwork.getLoadError();
exception.printStackTrace();
result.setFail(exception.getMessage());
}
countDownLatch.countDown();
});
try {
if (!countDownLatch.await(timeout, TimeUnit.SECONDS)) {
result.setFail("请求服务超时");
}
} catch (InterruptedException e) {
e.printStackTrace();
result.setFail(e.getMessage());
}
return result;
}
/**
* 获取路径分析结果
*
* @param utilityNetwork 公共设施网络
* @param timeout 超时时间
* @return 路径要素
*/
public static R<List<ArcGISFeature>> getTraceFeatures(UtilityNetwork utilityNetwork, long timeout) {
// get a trace configuration from a tier
UtilityNetworkDefinition networkDefinition = utilityNetwork.getDefinition();
UtilityDomainNetwork domainNetwork = networkDefinition.getDomainNetwork("Pipeline");
UtilityTier tier = domainNetwork.getTier("Pipe Distribution System");
UtilityTraceConfiguration traceConfiguration = tier.getTraceConfiguration();
// create a trace filter
traceConfiguration.setFilter(new UtilityTraceFilter());
// get a default starting location
UtilityNetworkSource networkSource = networkDefinition.getNetworkSource("Gas Device");
UtilityAssetGroup assetGroup = networkSource.getAssetGroup("Meter");
UtilityAssetType assetType = assetGroup.getAssetType("Customer");
UtilityElement startingLocation = utilityNetwork.createElement(assetType, UUID.fromString("98A06E95-70BE-43E7-91B7-E34C9D3CB9FF"));
// create new base trace parameters
UtilityTraceParameters utilityTraceParameters = new UtilityTraceParameters(UtilityTraceType.CONNECTED, Collections.singleton(startingLocation));
// get the first feature for the starting location, and get its geometry
ListenableFuture<List<ArcGISFeature>> elementFeaturesFuture = utilityNetwork.fetchFeaturesForElementsAsync(Collections.singletonList(startingLocation));
CountDownLatch countDownLatch = new CountDownLatch(1);
R<List<ArcGISFeature>> result = new R<>();
elementFeaturesFuture.addDoneListener(() -> {
try {
List<ArcGISFeature> startingLocationFeatures = elementFeaturesFuture.get();
List<ArcGISFeature> features = new ArrayList<>(elementFeaturesFuture.get());
result.setOk(features);
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
result.setFail(e.getMessage());
countDownLatch.countDown();
}
});
try {
if (!countDownLatch.await(timeout, TimeUnit.SECONDS)) {
result.setFail("请求服务超时");
}
} catch (InterruptedException e) {
e.printStackTrace();
result.setFail(e.getMessage());
}
return result;
}
/**
* 计算两点距离
*
* @param x1 第一个点横坐标
* @param y1 第一个点纵坐标
* @param x2 第二个点横坐标
* @param y2 第二个点纵坐标
* @param spatialReference 空间坐标系
* @return 距离
*/
public static double distance(double x1, double y1, double x2, double y2, SpatialReference spatialReference) {
Point point1 = new Point(x1, y1, spatialReference);
Point point2 = new Point(x2, y2, spatialReference);
PointCollection points = new PointCollection(spatialReference);
points.add(point1);
points.add(point2);
return GeometryEngine.length(new Polyline(points));
}
/**
* 追踪
*
* @param traceServer 追踪网络服务器
* @param traceType 追踪类型
* @param traceLocations 追踪位置
* @return 分析结果
*/
public static R<List<ResultElement>> trace(String traceServer, TraceType traceType, List<TraceLocation> traceLocations) {
String url = String.format("%s/trace", traceServer);
Map<String, Object> params = new HashMap<>();
params.put("gdbVersion", "");
params.put("sessionId", "");
params.put("moment", "");
params.put("traceType", traceType);
try {
params.put("traceLocations", mapper.writeValueAsString(traceLocations));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
params.put("traceConfigurationGlobalId", "");
params.put("traceConfiguration", "");
params.put("resultTypes", "[{\"type\":\"elements\"}]");
params.put("f", "json");
String resultVal = HttpUtils.post(url, params, 60000, 60000, "utf-8");
Map result = null;
try {
result = mapper.readValue(resultVal, Map.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
return R.fail(e.getMessage());
}
Boolean success = (Boolean) result.get("success");
if (!success) {
Map error = (Map) result.get("error");
return R.fail((String) error.get("message"));
}
Map traceResults = (Map) result.get("traceResults");
List elements = (List) traceResults.get("elements");
List<ResultElement> list = new ArrayList<>();
for (Object elementVal : elements) {
Map element = (Map) elementVal;
ResultElement item = new ResultElement();
item.setNetworkSourceId((Integer) element.get("networkSourceId"));
item.setGlobalId((String) element.get("globalId"));
item.setObjectId((Integer) element.get("objectId"));
list.add(item);
}
return R.ok(list);
}
/**
* 根据图层id获取所有数据globalId跟layerName对应关系
*
* @param db 数据库
* @param layers 图层
* @return globalId跟layerName对应关系
*/
public static Map<String, String> getGlobalIdLayerNames(ServiceGeodatabase db, List<IdInfo> layers, long timeout) {
Map<String, String> result = new HashMap<>();
for (IdInfo layer : layers) {
R<FeatureTable> tableVal = getFeatureTable(db, layer.getId(), timeout);
if (!tableVal.isOk()) {
logger.warn(tableVal.getMsg());
continue;
}
FeatureTable table = tableVal.getData();
R<List<Feature>> featuresVal = getAllFeatures(table, timeout);
if (!featuresVal.isOk()) {
logger.warn(featuresVal.getMsg());
continue;
}
List<Feature> features = featuresVal.getData();
for (Feature feature : features) {
Map<String, Object> attributes = feature.getAttributes();
String globalID = attributes.get("GlobalID").toString().toUpperCase();
if (!result.containsKey(globalID)) {
result.put(globalID, layer.getName());
}
}
}
return result;
}
}