package com.cr.pages import android.graphics.Bitmap import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.activityViewModels import com.cr.common.* import com.cr.cruav.CrApplication import com.cr.cruav.R import com.cr.data.CrUtil import com.cr.dialog.DialogInput import com.cr.dialog.DialogNormal import com.cr.event.EventMapCapture import com.cr.map.* import com.cr.models.CompletionModel import com.cr.models.ICompletion import com.cr.viewmodel.CrFlightControlVM import com.esri.arcgisruntime.arcgisservices.LabelDefinition import com.esri.arcgisruntime.data.* import com.esri.arcgisruntime.geometry.* import com.esri.arcgisruntime.layers.ArcGISMapImageLayer import com.esri.arcgisruntime.layers.ArcGISTiledLayer import com.esri.arcgisruntime.layers.FeatureLayer import com.esri.arcgisruntime.layers.Layer import com.esri.arcgisruntime.mapping.ArcGISMap import com.esri.arcgisruntime.mapping.view.* import com.esri.arcgisruntime.symbology.* import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.gson.JsonPrimitive import com.squareup.otto.Subscribe import kotlinx.android.synthetic.main.frag_map.* import kotlinx.coroutines.* import java.io.File import java.io.FileOutputStream import java.lang.Runnable import java.util.* import java.util.concurrent.ExecutionException import kotlin.math.abs /** * 操作系统:MAC系统 * 创建者:王成 * 创建日期:2023/3/14 09:51 * 描述:地图界面 */ class FragmentMap : CrAnimationFragment() { // todo: 2023/8/17 飞行器模型 private val flightControlVm:CrFlightControlVM by activityViewModels() /** * 事件监听接口 */ interface EventListener { // todo: 2023/6/15 案件上传监听 fun onCaseUpdate(selCase: CaseModel) } // define: 2023/3/14 地图容器 private var mapView: MapView? = null // define: 2023/3/14 地图 private var mMap: ArcGISMap? = null // todo: 2023/4/13 常量定义 val ONLINE_LAYER_NAME = "底图" val ONLINE_LABEL_LAYER_NAME = "标签" // todo: 2023/4/13 图层名称定义 val LAYER_NAME_ICO = "永久标志" val LAYER_NAME_DOODLE = "永久涂鸦" val LAYER_NAME_MEDIA = "案件点" val LAYER_NAME_CASE = "绘制案件图斑" val LAYER_NAME_YX = "影像图" val LAYER_NAME_GH = "规划图" val LAYER_NAME_XZ = "现状图" val LAYER_NAME_NET_CASE = "在线案件图斑" val LAYER_NAME_TEMP_ICO = "临时标志" val LAYER_NAME_TEMP_DOODLE = "临时涂鸦" val LAYER_NAME_CONFIG_VILLAGE = "行政区(村界)" val LAYER_NAME_CONFIG_TOWNS = "行政区(镇界)" val LAYER_NAME_AIR_LINE = "飞行航线" val LAYER_NAME_AIR_HISTORY_LINE = "历史航线" val LAYER_NAME_AIR_LOCATION = "飞行器" val LAYER_NAME_AIR_HOME = "返航点" // todo: 2023/4/14 符号相关常量 val SYMBOL_WIDTH = 25.0f // define: 2023/4/13 图片符号的宽度 val SYMBOL_HEIGHT = 25.0f // define: 2023/4/13 图片符号的高度 val R_LABEL_WJ_NO = "wj_no" // define: 2023/4/13 未上传违建标识 val R_LABEL_WJ_YES = "wj_yes" // define: 2023/4/13 已上传违建标识 val R_LABEL_REPEAT_NO = "repeat_no" // define: 2023/4/13 为上传复飞点标识 val R_LABEL_REPEAT_YES = "repeat_yes" // define: 2023/4/13 已上传复飞点标识 // todo: 2023/4/14 媒体点相关常量 val MEDIA_TYPE_WJ_NO = "0" // define: 2023/4/13 未上传的违建点 val MEDIA_TYPE_WJ_YES = "1" // define: 2023/4/13 已上传的违建点 val MEDIA_TYPE_REPEAT_NO = "4" // define: 2023/4/13 未上传的复飞案件 val MEDIA_TYPE_REPEAT_YES = "5" // define: 2023/4/13 已上传的复飞案件 // todo: 2023/4/14 字段相关常量 companion object { val FIELD_NET_CASE_POLYGON_AJH = "AJH" // define: 2023/4/13 网络案件的案件编号 val FIELD_CASE_POLYGON_ANJID = "ANJID" // define: 2023/4/13 案件ID val FIELD_CASE_POLYGON_MJ = "MJ" // define: 2023/4/13 面积 val FIELD_CASE_POLYGON_BZ = "BZ" // define: 2023/4/13 违建面的类型 0--代表未匹配 1--代表已匹配 val FIELD_CASE_POLYGON_BZ_VALUE_NO = "0" // define: 2023/4/13 未匹配 val FIELD_CASE_POLYGON_BZ_VALUE_YES = "1" // define: 2023/4/13 已匹配 val FIELD_CASE_NAME = "NAME" // define: 2023/4/13 名称字段 val FIELD_CASE_IMAGES = "IMAGES" // define: 2023/4/13 图片集合字段 val FIELD_CASE_RQ = "RQ" // define: 2023/4/13 日期字段 val FIELD_CASE_LAT = "LAT" // define: 2023/4/13 纬度字段 val FIELD_CASE_LNG = "LNG" // define: 2023/4/13 经度字段 val FIELD_CASE_ISUP = "ISUP" // define: 2023/4/13 是否上传 val FIELD_CASE_ALT = "ALT" // define: 2023/4/13 高度字段 val FIELD_CASE_ANG = "ANG" // define: 2023/4/13 角度字段 val FIELD_CASE_TYPE = "TYPE" // define: 2023/4/13 类型字段 val FIELD_CASE_ISDOWN = "ISDOWN" // define: 2023/4/13 是否下载 val MEDIA_TYPE_WJ_NO = "0" // define: 2023/6/12 未上传的案件点 val MEDIA_TYPE_WJ_YES = "1" // define: 2023/6/12 已上传的案件点 val MEDIA_TYPE_REPEAT_NO = "4" // define: 2023/6/12 未上传的复飞点 val MEDIA_TYPE_REPEAT_YES = "5" // define: 2023/6/12 已上传的复飞点 } // todo: 2023/4/13 标志相关 private var markChange: EventMarkChange? = null // todo: 2023/4/14 绘制图层 private var gLayerIco: GraphicsOverlay? = null // define: 2023/4/13 标志图层 private var gLayerAirplaneLocation: GraphicsOverlay? = null // define: 2023/4/13 飞行器位置图层 private var gLayerAirplaneHomeLocation: GraphicsOverlay? = null // define: 2023/4/13 飞行器返航点位置图层 private var gLayerAirplaneLine: GraphicsOverlay? = null // define: 2023/4/13 飞行航线图层 private var gLayerHistoryAirplaneLine: GraphicsOverlay? = null // define: 2023/4/13 历史航线图层 private var gLayerTemp: GraphicsOverlay? = null // define: 2023/6/5 临时展示内容图层 // todo: 2023/4/13 样式相关 private var symbolAirplaneLine: SimpleLineSymbol? = null // define: 2023/4/13 飞行航线样式 private var symbolAirplaneLink: SimpleLineSymbol? = null // define: 2023/4/13 飞行器与返航点连接线样式 private var symbolAirplaneLocation: PictureMarkerSymbol? = null // define: 2023/4/13 飞行器符号样式 // todo: 2023/4/13 要素相关 private var builderAirplaneLine: PolylineBuilder? = null // define: 2023/4/13 航线点集 private var builderAirplaneLink: PolylineBuilder? = null // define: 2023/4/13 飞行器与返航点连接线点集 private var builderAirplaneLocation: PointBuilder? = null // define: 2023/4/13 飞行器位置点 private var builderAirplaneHomeLocation: PointBuilder? = null // define: 2023/4/13 返航点位置 private var graAirplaneLine: Graphic? = null // define: 2023/4/13 航线图形 private var graAirplaneLink: Graphic? = null // define: 2023/4/13 飞行器与返航点连接线图形 private var graAirplaneLocation: Graphic? = null // define: 2023/4/13 飞行器位置图形 private var graAirplaneHomeLocation: Graphic? = null // define: 2023/4/13 返航点位置图形 // todo: 2023/4/17 草图编辑 private var sketchEditor: SketchEditor? = null // define: 2023/4/13 草图编辑器 private var feaSelectCase: Feature? = null // define: 2023/4/13 选中的案件点 // todo: 2023/4/14 编辑图层 private var fTableMark: FeatureTable? = null // define: 2023/4/14 永久标志表 private var fLayerMark: FeatureLayer? = null // define: 2023/4/14 永久标志图层 private var fTableMedia: FeatureTable? = null // define: 2023/4/14 媒体表 private var fLayerMedia: FeatureLayer? = null // define: 2023/4/14 媒体图层 private var fTableDoodle: FeatureTable? = null // define: 2023/4/14 永久涂鸦表 private var fLayerDoodle: FeatureLayer? = null // define: 2023/4/14 永久涂鸦图层 private var fTableCasePolygon: FeatureTable? = null // define: 2023/4/14 永久案件表 private var fLayerCasePolygon: FeatureLayer? = null // define: 2023/4/14 永久案件图层 private var fTableNetCasePolygon: ServiceFeatureTable? = null // define: 2023/4/14 网路案件表 private var fLayerNetCasePolygon: ArcGISMapImageLayer? = null // define: 2023/4/14 网络案件图层 // todo: 2023/4/18 地图Touch事件 private var mapTouch: MapTouch? = null // todo: 2023/6/15 内部监听 自行设置 private var eventListener: EventListener? = null // todo: 2023/8/8 截屏相关 private var mapStateList = mutableListOf() // define: 2023/8/14 地图状态 private var captureNames = mutableListOf() // define: 2023/8/14 截屏图片名称 // todo: 2023/8/17 投影 private val spatialReferenceWGS84 = SpatialReference.create(4326) private val spatialReferenceWebMTK = SpatialReference.create(3857) /** * 重写创建View方法 * @param inflater LayoutInflater * @param container ViewGroup? * @param savedInstanceState Bundle? * @return View? */ override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { mainView = inflater.inflate(R.layout.frag_map, container, false) // todo: 2023/4/17 注册订阅 CrApplication.getEventBus().register(this) return mainView } /** * 重写创建视图 * @param view View * @param savedInstanceState Bundle? */ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initUI() } /** * 初始化UI */ private fun initUI() { //ArcGISRuntimeEnvironment.setLicense("runtimelite,1000,rud4449636536,none,NKMFA0PL4S0DRJE15166"); // todo: 2023/3/14 初始化控件 mapView = mainView?.findViewById(R.id.map_mapView) mapView?.let { itView -> // todo: 2023/4/13 设置底部标识是否显示 itView.isAttributionTextVisible = false mMap = ArcGISMap() itView.map = mMap // todo: 2023/4/13 地图控件初始化 itView.backgroundGrid.color = Color.argb(255, 216, 216, 216) itView.backgroundGrid.gridLineColor = Color.argb(0, 255, 255, 255) // todo: 2023/4/17 设置草图编辑 sketchEditor = SketchEditor() setSketchEditor() itView.sketchEditor = sketchEditor // todo: 2023/4/18 Touch事件初始化 mapTouch = MapTouch(CrApplication.getContext(), itView) mapTouch?.setListener(touchListener) itView.onTouchListener = mapTouch } // todo: 2023/4/13 地图初始化 mapInit() } /** * 草图编辑工具监听 */ private var sketchGeometryChangeListener = SketchGeometryChangedListener { p0 -> if (p0!!.geometry.geometryType == GeometryType.POLYLINE) { // todo: 2023/6/5 清除已展示内容 gLayerTemp?.graphics?.clear() var polyline = p0.geometry as Polyline var pointCollection = PointCollection(SpatialReference.create(3857)) if (polyline.parts.size > 0) { for (point in polyline.parts[0].points) { pointCollection.add(point) if (pointCollection.size >= 2) { var polyline = Polyline(pointCollection) // todo: 2023/6/5 计算长度 var lineLength = GeometryEngine.length(polyline) // todo: 2023/6/5 添加标签 appendMeasureLabel(point, CrUnitManager.formatLength(lineLength)) } } } } else if (p0!!.geometry.geometryType == GeometryType.POLYGON) { // todo: 2023/6/6 清除临时标签 gLayerTemp?.graphics?.clear() var polygon = p0.geometry as Polygon if (polygon.parts.size > 0) { if (CrUnitManager.querySizeByIterable(polygon.parts[0].points) >= 3) { // todo: 2023/6/6 计算面积 var area = GeometryEngine.area(polygon) area = abs(area) // todo: 2023/6/6 添加标签 appendMeasureLabel( polygon.parts[0].startPoint, CrUnitManager.formatArea(area) ) } } } else if (p0!!.geometry.geometryType == GeometryType.POINT && mapTouch!!.getAction() == MapAction.MapTapStopMoveWaypoint) { caseMoveWaypointToEnd(p0!!.geometry as Point) } } /** * 添加一个测量标签 * @param location Point 位置 * @param label String 标签内容 */ private fun appendMeasureLabel(location: Point, label: String) { var tSymbol = TextSymbol(); tSymbol.color = Color.rgb(17, 46, 114) tSymbol.text = label tSymbol.size = 10f tSymbol.haloColor = Color.WHITE tSymbol.haloWidth = 2f tSymbol.fontWeight = TextSymbol.FontWeight.BOLD tSymbol.offsetY = 20f tSymbol.backgroundColor = Color.argb(200, 13, 49, 130) var graphic = Graphic(location, tSymbol) gLayerTemp?.graphics?.add(graphic) } /** * 设置草图编辑器 */ private fun setSketchEditor() { // todo: 2023/4/21 获取样式 var sketchStyle: SketchStyle = sketchEditor!!.sketchStyle // todo: 2023/4/21 设置点符号样式 var markerSymbol = SimpleMarkerSymbol() markerSymbol.size = 10f markerSymbol.color = Color.RED markerSymbol.style = SimpleMarkerSymbol.Style.CIRCLE // todo: 2023/4/21 设置样式 sketchStyle.vertexSymbol = markerSymbol // todo: 2023/4/21 启用 sketchEditor?.sketchStyle = sketchStyle } /** * Touch监听 */ private var touchListener = object : MapTouch.TouchListener { // todo: 2023/4/21 选择 override fun onSelect(feature: Feature?, layer: Layer) { if (layer is FeatureLayer) { if (feature != null) { // todo: 2023/4/18 高亮显示 focusFeature(layer!!, feature) } else { unfocusFeature(layer!!) } } } // todo: 2023/4/19 标志添加回调 override fun onMarkAppend(mapPoint: Point) { markAppend(mapPoint) } // todo: 2023/6/7 查询地理位置回调 override fun onQueryLocation(location: Point, longitude: String, latitude: String) { appendLocation(location, longitude, latitude) } // todo: 2023/6/12 添加案件点 override fun onAppendWaypoint(location: Point, longitude: String, latitude: String) { caseAppendWaypointToMap(location, longitude, latitude) } // todo: 2023/6/14 删除案件点 override fun onRemoveWaypoint(screenPoint: android.graphics.Point) { caseRemoveCaseWaypoing(screenPoint) } // todo: 2023/6/14 选择移动的案件点 override fun onMoveWaypointBySelect(location: Point) { caseMoveWaypointBySelect(location) } // todo: 2023/6/15 案件分享及上传选择回调 override fun onCaseUploadBySelect(screenPoint: android.graphics.Point) { caseUpload(screenPoint) } } /** * 地图初始化 */ private fun mapInit() { // todo: 2023/4/13 加载在线底图 addOnlineRasterLayer() // todo: 2023/4/13 添加切片图层 addTiledToMap() // todo: 2023/4/13 添加基础矢量地图 addBaseGeoDatabaseToMap() // todo: 2023/4/14 添加可编辑矢量数据 addEditGeoDatabaseToMap() // todo: 2023/4/19 添加动态图层 addGraphicOverlayToMap() // todo: 2023/8/17 添加飞行相关图层 addAirplaneLayerToMap() // todo: 2023/4/13 定位地图中心点 setMapCenter(118.709, 35.219, 5000.0); } /** * 添加在线地图 */ private fun addOnlineRasterLayer() { var url: String = "https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer"; var layer = ArcGISTiledLayer(url) layer.name = ONLINE_LAYER_NAME mMap?.operationalLayers?.add(layer) } /** * 添加切片图层 */ private fun addTiledToMap() { var tileLayers = DataManager.getTileLayerConfig() for (model in tileLayers) { var layer = ArcGISTiledLayer(model.url) layer.name = model.name layer.isVisible = model.isVisible mMap?.operationalLayers?.add(layer) // todo: 2023/4/13 添加到配置 LayerManager.getInstance().addLayer( LayerModel( model.name!!, model.isVisible, LayerType.LAYER_TYPE_TILED, layer ), LayerManager.LayerGroup.LAYER_NAME_DAILY ) } } /** * 添加基础矢量地图集合 */ private fun addBaseGeoDatabaseToMap() { if (!CrFileManager.isExists(CrUtil.MAP_PATH_BASE)) return var geoDatabase = Geodatabase(CrUtil.MAP_PATH_BASE) // todo: 2023/4/13 加载完成监听 geoDatabase.addDoneLoadingListener(Runnable { var vLayers = DataManager.getVectorLayerConfig() var tables = geoDatabase.geodatabaseFeatureTables for (vLayer in vLayers) { var table = tables[vLayer.lyrIdx] var layer = FeatureLayer(table) layer.name = vLayer.lyrName layer.isVisible = vLayer.isVisible mMap?.operationalLayers?.add(layer) // todo: 2023/4/13 添加到配置信息 LayerManager.getInstance().addLayer( LayerModel( vLayer.lyrName, vLayer.isVisible, LayerType.LAYER_TYPE_FEATURE, layer ), LayerManager.LayerGroup.LAYER_NAME_BASE ) } }) // todo: 2023/4/13 加载数据集 geoDatabase.loadAsync() } /** * 加载可编辑数据 */ private fun addEditGeoDatabaseToMap() { if (!CrFileManager.isExists(CrUtil.MAP_PATH_EDIT)) return var geoDatabase = Geodatabase(CrUtil.MAP_PATH_EDIT) // todo: 2023/4/14 数据加载完监听 geoDatabase.addDoneLoadingListener(Runnable { // todo: 2023/4/14 初始化标志图层 fTableMark = geoDatabase.getGeodatabaseFeatureTable("ico84") fLayerMark = FeatureLayer(fTableMark) fLayerMark!!.name = LAYER_NAME_ICO fLayerMark!!.isVisible = true mMap!!.operationalLayers.add(fLayerMark) LayerManager.getInstance().addLayer( LayerModel( fLayerMark!!.name, fLayerMark!!.isVisible, LayerType.LAYER_TYPE_FEATURE_EDIT, fLayerMark!! ), LayerManager.LayerGroup.LAYER_NAME_DAILY ) // todo: 2023/4/14 初始化涂鸦图层 fTableDoodle = geoDatabase.getGeodatabaseFeatureTable("ty84") fLayerDoodle = FeatureLayer(fTableDoodle) fLayerDoodle!!.name = LAYER_NAME_DOODLE fLayerDoodle!!.isVisible = true mMap!!.operationalLayers.add(fLayerDoodle) LayerManager.getInstance().addLayer( LayerModel( fLayerDoodle!!.name, fLayerDoodle!!.isVisible, LayerType.LAYER_TYPE_FEATURE_EDIT, fLayerDoodle!! ), LayerManager.LayerGroup.LAYER_NAME_DAILY ) // todo: 2023/4/14 初始化媒体点图层 fTableMedia = geoDatabase.getGeodatabaseFeatureTable("media84") fLayerMedia = FeatureLayer(fTableMedia) fLayerMedia!!.name = LAYER_NAME_MEDIA fLayerMedia!!.isVisible = true mMap!!.operationalLayers.add(fLayerMedia) LayerManager.getInstance().addLayer( LayerModel( fLayerMedia!!.name, fLayerMedia!!.isVisible, LayerType.LAYER_TYPE_FEATURE_EDIT, fLayerMedia!! ), LayerManager.LayerGroup.LAYER_NAME_DAILY ) // todo: 2023/4/14 初始化违建面图层 fTableCasePolygon = geoDatabase.getGeodatabaseFeatureTable("sbwj84") fLayerCasePolygon = FeatureLayer(fTableCasePolygon) fLayerCasePolygon!!.name = LAYER_NAME_CASE fLayerCasePolygon!!.isVisible = true // todo: 2023/4/14 给图层添加标注 val labelDefinition: LabelDefinition = createLabelDefinition(Color.BLUE, 12.0f, "round(\$feature.MJ,2) + '亩';") fLayerCasePolygon!!.labelDefinitions.add(labelDefinition) fLayerCasePolygon!!.isLabelsEnabled = true mMap!!.operationalLayers.add(fLayerCasePolygon) LayerManager.getInstance().addLayer( LayerModel( fLayerCasePolygon!!.name, fLayerCasePolygon!!.isVisible, LayerType.LAYER_TYPE_FEATURE_EDIT, fLayerCasePolygon!! ), LayerManager.LayerGroup.LAYER_NAME_DAILY ) // todo: 2023/4/14 可编辑数据符号化 editLayerRenderer() }) // todo: 2023/4/14 异步加载 geoDatabase.loadAsync() } /** * 添加动态图层到地图 */ private fun addGraphicOverlayToMap() { // todo: 2023/4/19 初始化动态标志图层 gLayerIco = GraphicsOverlay() appendGraphicOverlay(gLayerIco!!, LAYER_NAME_TEMP_ICO) // todo: 2023/6/5 初始化临时展示内容图层 gLayerTemp = GraphicsOverlay(); mapView?.graphicsOverlays?.add(gLayerTemp) } /** * 添加飞行相关图层到地图 */ private fun addAirplaneLayerToMap() { // todo: 2023/8/16 初始化航线图层 gLayerAirplaneLine = GraphicsOverlay() gLayerAirplaneLine?.let { overlaysAddToMap(it,LAYER_NAME_AIR_LINE,LayerManager.LayerGroup.LAYER_NAME_AIR) } // todo: 2023/8/16 初始化历史航线图层 gLayerHistoryAirplaneLine = GraphicsOverlay() gLayerHistoryAirplaneLine?.let { overlaysAddToMap(it,LAYER_NAME_AIR_HISTORY_LINE,LayerManager.LayerGroup.LAYER_NAME_AIR) } // todo: 2023/8/17 初始化返航点图层 gLayerAirplaneHomeLocation = GraphicsOverlay() gLayerAirplaneHomeLocation?.let { overlaysAddToMap(it,LAYER_NAME_AIR_HOME,LayerManager.LayerGroup.LAYER_NAME_AIR) } // todo: 2023/8/17 初始化飞行器图层 gLayerAirplaneLocation = GraphicsOverlay() gLayerAirplaneLocation?.let { overlaysAddToMap(it,LAYER_NAME_AIR_LOCATION,LayerManager.LayerGroup.LAYER_NAME_AIR) } // todo: 2023/8/17 符号化 initAirplaneSymbolInfo() } /** * 飞行相关符号化 */ private fun initAirplaneSymbolInfo(){ // todo: 2023/8/17 符号化航线 symbolAirplaneLine = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID,Color.WHITE,2.0f) symbolAirplaneLink = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID,Color.GREEN,2.0f) builderAirplaneLine = PolylineBuilder(spatialReferenceWGS84) builderAirplaneLink = PolylineBuilder(spatialReferenceWGS84) graAirplaneLine = Graphic(builderAirplaneLine!!.toGeometry(),symbolAirplaneLine) graAirplaneLink = Graphic(builderAirplaneLink!!.toGeometry(),symbolAirplaneLink) gLayerAirplaneLine?.graphics?.add(graAirplaneLine) gLayerAirplaneLine?.graphics?.add(graAirplaneLink) // todo: 2023/8/17 飞行器符号化 builderAirplaneLocation = PointBuilder(spatialReferenceWGS84) symbolAirplaneLocation = createPictureMarkerSymbol(R.drawable.ico_air,25f,40f) graAirplaneLocation = Graphic(builderAirplaneLocation!!.toGeometry(),symbolAirplaneLocation) gLayerAirplaneLocation?.graphics?.add(graAirplaneLocation) // todo: 2023/8/17 返航位置初始化 builderAirplaneHomeLocation = PointBuilder(spatialReferenceWGS84) var symbolAirplaneHomeLocation = createPictureMarkerSymbol(R.drawable.ico_home,30f,30f) graAirplaneHomeLocation = Graphic(builderAirplaneHomeLocation!!.toGeometry(),symbolAirplaneHomeLocation) gLayerAirplaneHomeLocation?.graphics?.add(graAirplaneHomeLocation) } /** * 添加绘制图层到地图中 * @param layer GraphicsOverlay 绘制图层 * @param layerName String 图层名称 * @param group LayerGroup 分组 */ private fun overlaysAddToMap(layer:GraphicsOverlay,layerName:String,group:LayerManager.LayerGroup){ // todo: 2023/8/17 设置可见 layer.isVisible = true // todo: 2023/8/17 加入到地图中 mapView?.graphicsOverlays!!.add(layer) // todo: 2023/8/17 加入到图层控制中 LayerManager.getInstance().addLayer( LayerModel( layerName, layer.isVisible, LayerType.LAYER_TYPE_GRAPHIC, layer ), group ) } /** * 编辑图层符号化 */ private fun editLayerRenderer() { // todo: 2023/4/14 永久涂鸦图层符号化 val doodleSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.BLUE, 2.5f) val doodleRenderer = SimpleRenderer(doodleSymbol) fLayerDoodle?.renderer = doodleRenderer // todo: 2023/4/14 永久标志图层符号化 val icoSymbol: PictureMarkerSymbol = createPictureMarkerSymbol(R.drawable.ico_ty1, 30f, 30f) val icoRenderer = SimpleRenderer(icoSymbol) fLayerMark?.renderer = icoRenderer // todo: 2023/4/14 违建符号化 val mediaRenderer = UniqueValueRenderer() val mediaSymbolYes: PictureMarkerSymbol = createPictureMarkerSymbol( R.drawable.ico_wj_upload_yes, SYMBOL_WIDTH, SYMBOL_HEIGHT ) val mediaSymbolNo: PictureMarkerSymbol = createPictureMarkerSymbol( R.drawable.ico_wj_no, SYMBOL_WIDTH, SYMBOL_HEIGHT ) val mediaSymbolRepeatYes: PictureMarkerSymbol = createPictureMarkerSymbol( R.drawable.ico_repeatflight_yes, SYMBOL_WIDTH, SYMBOL_HEIGHT ) val mediaSymbolRepeatNo: PictureMarkerSymbol = createPictureMarkerSymbol( R.drawable.ico_repeatflight_no, SYMBOL_WIDTH, SYMBOL_HEIGHT ) mediaRenderer.defaultSymbol = mediaSymbolNo mediaRenderer.defaultLabel = R_LABEL_WJ_NO mediaRenderer.fieldNames.add(FIELD_CASE_ISUP) val cValueNo: MutableList = ArrayList() cValueNo.add(MEDIA_TYPE_WJ_NO) mediaRenderer.uniqueValues.add( UniqueValueRenderer.UniqueValue( R_LABEL_WJ_NO, R_LABEL_WJ_NO, mediaSymbolNo, cValueNo ) ) val cValueYes: MutableList = ArrayList() cValueYes.add(MEDIA_TYPE_WJ_YES) mediaRenderer.uniqueValues.add( UniqueValueRenderer.UniqueValue( R_LABEL_WJ_YES, R_LABEL_WJ_YES, mediaSymbolYes, cValueYes ) ) val cValueRepeatNo: MutableList = ArrayList() cValueRepeatNo.add(MEDIA_TYPE_REPEAT_NO) mediaRenderer.uniqueValues.add( UniqueValueRenderer.UniqueValue( R_LABEL_REPEAT_NO, R_LABEL_REPEAT_NO, mediaSymbolRepeatNo, cValueRepeatNo ) ) val cValueRepeatYes: List = ArrayList() cValueNo.add(MEDIA_TYPE_REPEAT_YES) mediaRenderer.uniqueValues.add( UniqueValueRenderer.UniqueValue( R_LABEL_REPEAT_YES, R_LABEL_REPEAT_YES, mediaSymbolRepeatYes, cValueRepeatYes ) ) fLayerMedia?.renderer = mediaRenderer // todo: 2023/4/14 绘制违建面符号化 val colorClear = Color.argb(0, 255, 255, 255) val caseNoLineSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.DASH_DOT, Color.BLUE, 2.5f) val caseYesLineSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.DASH_DOT, Color.RED, 2.5f) val caseNoFillSymbol = SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, colorClear, caseNoLineSymbol) val caseYesFillSymbol = SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, colorClear, caseYesLineSymbol) val casePolygonRenderer = UniqueValueRenderer() casePolygonRenderer.fieldNames.add(FIELD_CASE_POLYGON_BZ) casePolygonRenderer.defaultSymbol = caseNoFillSymbol casePolygonRenderer.defaultLabel = FIELD_CASE_POLYGON_BZ_VALUE_NO val cValueCaseNo: MutableList = ArrayList() cValueCaseNo.add(FIELD_CASE_POLYGON_BZ_VALUE_NO) casePolygonRenderer.uniqueValues.add( UniqueValueRenderer.UniqueValue( FIELD_CASE_POLYGON_BZ_VALUE_NO, FIELD_CASE_POLYGON_BZ_VALUE_NO, caseNoFillSymbol, cValueCaseNo ) ) val cValueCaseYes: MutableList = ArrayList() cValueCaseYes.add(FIELD_CASE_POLYGON_BZ_VALUE_YES) casePolygonRenderer.uniqueValues.add( UniqueValueRenderer.UniqueValue( FIELD_CASE_POLYGON_BZ_VALUE_YES, FIELD_CASE_POLYGON_BZ_VALUE_YES, caseYesFillSymbol, cValueCaseYes ) ) fLayerCasePolygon?.renderer = casePolygonRenderer } /** * 向地图中添加动态绘制图层 * @param layer GraphicsOverlay 动态绘制图层 * @param layerName String 图层名称 */ private fun appendGraphicOverlay(layer: GraphicsOverlay, layerName: String) { // todo: 2023/4/19 设置该图层显示 layer.isVisible = true mapView?.graphicsOverlays?.let { it.add(layer) LayerManager.getInstance().addLayer( LayerModel( layerName, layer.isVisible, LayerType.LAYER_TYPE_GRAPHIC, layer ), LayerManager.LayerGroup.LAYER_NAME_DRAW ) } } /** * 创建图片符号 * @param drawable Int 图片资源Id * @param width Float 宽度 * @param height Float 高度 * @return PictureMarkerSymbol? */ private fun createPictureMarkerSymbol( drawable: Int, width: Float, height: Float ): PictureMarkerSymbol { val tDrawable = CrApplication.getContext().resources.getDrawable(drawable) as BitmapDrawable val symbol = PictureMarkerSymbol(tDrawable) if (width > 0) symbol.width = width else symbol.width = CrUnitManager.px2dp(tDrawable.bitmap.width).toFloat() if (height > 0) symbol.height = height else symbol.height = CrUnitManager.px2dp(tDrawable.bitmap.height).toFloat() return symbol } /** * 创建标注 * @param txtColor Int 文字颜色 * @param txtSize Float 文字大小 * @param expression String 表达式 * @return LabelDefinition? 标注 */ private fun createLabelDefinition( txtColor: Int, txtSize: Float, expression: String ): LabelDefinition { val textSymbol = TextSymbol() textSymbol.color = txtColor textSymbol.fontWeight = TextSymbol.FontWeight.BOLD textSymbol.haloColor = Color.WHITE textSymbol.haloWidth = 2.0f textSymbol.fontFamily = "Arial" textSymbol.size = txtSize val label = JsonObject() val labelExpression = JsonObject() labelExpression.add("expression", JsonPrimitive(expression)) label.add("labelExpressionInfo", labelExpression) label.add("labelPlacement", JsonPrimitive("esriServerPolygonPlacementAlwaysHorizontal")) label.add("symbol", JsonParser().parse(textSymbol.toJson())) return LabelDefinition.fromJson(label.toString()) } /** * 定位地图中心 * @param longitude Double 中心经度 * @param latitude Double 中心纬度 * @param scale Double 缩放比例 */ private fun setMapCenter(longitude: Double, latitude: Double, scale: Double) { // todo: 2023/4/13 创建中心点 var centerPoint: Point = Point(longitude, latitude, MapTouch.wgs84SpatialReference) if (scale > 0) { mapView?.setViewpointCenterAsync(centerPoint, scale) } else { mapView?.setViewpointCenterAsync(centerPoint) } } /** * 高亮显示要素 * @param layer FeatureLayer 要素所在图层 * @param feature Feature 要素 */ private fun focusFeature(layer: FeatureLayer, feature: Feature) { layer.selectFeature(feature) } /** * 清除高亮显示 * @param layer FeatureLayer 图层 */ private fun unfocusFeature(layer: FeatureLayer) { layer.clearSelection() } /** * 清除全部选择 */ private fun unfocusAllFeature() { for (layer in mMap!!.operationalLayers) { if (layer is FeatureLayer) { layer.clearSelection() } } for (overLayer in mapView!!.graphicsOverlays) { overLayer.clearSelection() } } /** * 开始绘制涂鸦 */ private fun doodleStartDraw() { sketchEditor?.start(SketchCreationMode.FREEHAND_LINE) } /** * 清除草图 */ private fun clearSketch() { sketchEditor?.clearGeometry() } /** * 保存绘制的涂鸦 */ private fun doodleSave() { var geometry: Geometry? = sketchEditor?.geometry geometry?.let { var feature: Feature = fTableDoodle!!.createFeature() feature.geometry = it var addAsync = fTableDoodle!!.addFeatureAsync(feature) addAsync.addDoneListener(Runnable { try { addAsync.get() if (addAsync.isDone) { showInformation("涂鸦保存成功!") sketchEditor?.stop() CrApplication.getEventBus() .post(FragmentDoodle.EventDoodleAction(FragmentDoodle.EventDoodleAction.CLOSE_DRAW)) } } catch (e: InterruptedException) { showWarning(e.message!!) } catch (e: ExecutionException) { showWarning(e.message!!) } }) } } /** * 删除数据表中的全部数据 * @param delTable FeatureTable 数据表 */ private fun removeAllFeatureByTable(delTable: FeatureTable) { var dialog = DialogNormal(CrApplication.getContext(), "警告", "删除后无法恢复,是否删除?") dialog.setButtonsText("是", "否") dialog.setListener(object : DialogNormal.DialogNormalListener { // todo: 2023/4/17 删除 override fun completion() { var params = QueryParameters() params.whereClause = "1=1" var queryAsync = delTable?.queryFeaturesAsync(params) queryAsync?.addDoneListener(Runnable { try { if (queryAsync.isDone) { var deleteAsync = delTable?.deleteFeaturesAsync(queryAsync.get()) deleteAsync?.addDoneListener(Runnable { try { if (deleteAsync.isDone) { showInformation("删除成功!") } } catch (e: java.lang.IllegalArgumentException) { showError("删除错误!") } }) } } catch (e: java.lang.IllegalArgumentException) { showError("删除错误!") } }) } // todo: 2023/4/17 否 override fun close() { } }) dialog.show() } /** * 删除图层中选中的要素 * @param layer FeatureLayer 图层 */ private fun doodleSelectFeature(layer: FeatureLayer) { var dialog = DialogNormal(requireContext(), "警告", "删除后无法恢复,是否删除?") dialog.setButtonsText("是", "否") dialog.setListener(object : DialogNormal.DialogNormalListener { override fun completion() { var sAsync = layer!!.selectedFeaturesAsync sAsync.addDoneListener(Runnable { if (sAsync.isDone) { var result = sAsync.get() var dAsync = layer.featureTable.deleteFeaturesAsync(result) dAsync.addDoneListener(Runnable { try { if (dAsync.isDone) { showInformation("删除成功!") } } catch (e: java.lang.IllegalArgumentException) { showError("删除错误!") } }) } }) } override fun close() { } }) dialog.show() } /** * 添加标志 * @param mapPoint Point 地图点 */ private fun markAppend(mapPoint: Point) { if (markChange == null) return var markSymbol = createPictureMarkerSymbol(markChange!!.markDrawable, 0f, 0f) // todo: 2023/4/19 设置偏移 markSymbol.offsetX = -1 * markSymbol.width / 2 markSymbol.angle = markChange!!.markAngle.toFloat() // todo: 2023/4/19 创建要素 var markGraphic = Graphic(mapPoint, markSymbol) gLayerIco?.graphics?.add(markGraphic) CrUtil.showToast("标志添加成功!") } /** * 保存标志 */ private fun markSave() { gLayerIco?.let { var features: MutableList = mutableListOf() for (graphic in it.graphics) { var feature = fTableMark?.createFeature() feature?.geometry = graphic.geometry features.add(feature!!) } var addAsync = fTableMark?.addFeaturesAsync(features) addAsync?.addDoneListener(Runnable { try { if (addAsync.isDone) { showInformation("保存成功!") gLayerIco?.graphics?.clear() } } catch (e: java.lang.IllegalArgumentException) { showError("保存错误!") } }) } } /** * 添加展示获取经纬度位置 * @param location Point 地理位置 * @param longitude String 经度 * @param latitude String 纬度 */ private fun appendLocation(location: Point, longitude: String, latitude: String) { // todo: 2023/6/7 点符号样式 var markSymbol: SimpleMarkerSymbol = SimpleMarkerSymbol() markSymbol.color = Color.argb(255, 0, 0, 255) markSymbol.size = 14.0f markSymbol.style = SimpleMarkerSymbol.Style.CIRCLE markSymbol.outline = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.argb(255, 255, 255, 255), 1.0f) // todo: 2023/6/7 创建点符号 var graphic = Graphic(location, markSymbol) gLayerTemp?.graphics?.add(graphic) // todo: 2023/6/7 添加标注 appendMeasureLabel(location, String.format("经度:%s 纬度:%s", longitude, latitude)) } /** * 添加经纬度点到地图中 * @param longitude String 经度值 * @param latitude String 纬度值 */ private fun appendWGS84PointToMap(longitude: String, latitude: String) { var lng = longitude.toDouble() var lat = latitude.toDouble() var wgs84Point = Point(lng, lat, SpatialReference.create(4326)) var location = GeometryEngine.project(wgs84Point, mMap?.spatialReference) as Point appendLocation(location, longitude, latitude) } /** * 测量长度 */ private fun measureLength() { CrUtil.showToast("地图上点击开始测量!") sketchEditor?.let { it.stop() it.removeGeometryChangedListener(sketchGeometryChangeListener) // todo: 2023/4/21 设置编辑模式 var model = SketchEditConfiguration() model.isAllowPartSelection = false model.isContextMenuEnabled = false model.isRequireSelectionBeforeDrag = true it.start(SketchCreationMode.POLYLINE, model) it.opacity = 1.0f // todo: 2023/4/21 设置监听 it.addGeometryChangedListener(sketchGeometryChangeListener) } } /** * 面积测量 */ private fun measureArea() { CrUtil.showToast("地图上点击开始测量!") sketchEditor?.let { it.stop() it.removeGeometryChangedListener(sketchGeometryChangeListener) // todo: 2023/6/6 设置编辑模式 var model = SketchEditConfiguration() model.isAllowPartSelection = false model.isContextMenuEnabled = false model.isRequireSelectionBeforeDrag = true it.start(SketchCreationMode.POLYGON, model) it.opacity = 1.0f // todo: 2023/6/6 设置监听 it.addGeometryChangedListener(sketchGeometryChangeListener) } } /** * 输入坐标定位监听 */ private var inputLocationToMapListener: DialogInput.DialogInputListener = object : DialogInput.DialogInputListener { // todo: 2023/6/7 点击完成按钮回调 override fun completion(valueOne: String, valueTwo: String, self: DialogInput) { if (!CrUnitManager.checkLongitude(valueOne)) { CrUtil.showToast("输入的经度值不符合要求!") } else if (!CrUnitManager.checkLatitude(valueTwo)) { CrUtil.showToast("输入的纬度值不符合要求!") } else { self.dismiss() // todo: 2023/6/8 添加到地图中 appendWGS84PointToMap(valueOne, valueTwo) } } // todo: 2023/6/7 点击取消按钮回调 override fun close() { } } /** * 开始绘制案件图斑 */ private fun caseStartDraw() { CrUtil.showToast("地图上点击开始绘制!") sketchEditor?.let { it.stop() it.removeGeometryChangedListener(sketchGeometryChangeListener) // todo: 2023/6/6 设置编辑模式 var model = SketchEditConfiguration() model.isAllowPartSelection = true model.isContextMenuEnabled = false model.isRequireSelectionBeforeDrag = true it.start(SketchCreationMode.POLYGON, model) it.opacity = 1.0f } } /** * 保存编辑的案件图斑 */ private fun caseSave() { var geo = sketchEditor?.geometry if (geo != null && geo.geometryType == GeometryType.POLYGON) { var polygon = geo as Polygon if (CrUnitManager.querySizeByIterable(polygon.parts[0].points) < 4) { showWarning("提交保存的要素少于4个点,无法提交!") } else { // todo: 2023/6/12 查询关联的案件点 var queryParams = QueryParameters() queryParams.geometry = polygon queryParams.spatialRelationship = QueryParameters.SpatialRelationship.CONTAINS queryParams.whereClause = String.format( "%s='%s' or %s='%s'", FIELD_CASE_ISUP, MEDIA_TYPE_WJ_NO, FIELD_CASE_ISUP, MEDIA_TYPE_WJ_YES ) var queryAsync = fTableMedia?.queryFeaturesAsync(queryParams) queryAsync?.addDoneListener(Runnable { if (queryAsync.isDone) { // todo: 2023/6/12 获取查询结果 var featureResult = queryAsync.get().iterator() var features = ArrayList() while (featureResult.hasNext()) { features.add(featureResult.next()) } // todo: 2023/6/12 如果存在违建点 则赋值 否则为 空 var caseId = "" if (features.size > 0) { caseId = features[0].attributes[FIELD_CASE_NAME].toString() } // todo: 2023/6/12 计算面积 并添加要素到图层 var area = abs(GeometryEngine.area(polygon)) * 0.0015 var wjFeature = fTableCasePolygon?.createFeature() wjFeature!!.let { it.attributes[FIELD_CASE_POLYGON_ANJID] = caseId it.attributes[FIELD_CASE_POLYGON_MJ] = area if (caseId == "") { it.attributes[FIELD_CASE_POLYGON_BZ] = FIELD_CASE_POLYGON_BZ_VALUE_NO } else { it.attributes[FIELD_CASE_POLYGON_BZ] = FIELD_CASE_POLYGON_BZ_VALUE_YES } it.geometry = polygon var appendAsync = fTableCasePolygon?.addFeatureAsync(it) appendAsync?.addDoneListener(Runnable { try { if (appendAsync.isDone) { showInformation("案件保存成功!") sketchEditor?.stop() } } catch (ex: java.lang.IllegalArgumentException) { showError("案件保存失败!") } }) } } }) } } else { showWarning("提交保存的要素不符合要求!") } } /** * 删除保存的案件图斑 */ private fun caseDelete() { var queryParameters = QueryParameters() queryParameters.whereClause = "1=1" var queryAsync = fTableCasePolygon?.queryFeaturesAsync(queryParameters) queryAsync?.addDoneListener(Runnable { try { if (queryAsync.isDone) { var deleteAsync = fTableCasePolygon?.deleteFeaturesAsync(queryAsync.get()) deleteAsync?.addDoneListener(Runnable { try { if (deleteAsync.isDone) { showInformation("删除成功!") } } catch (ex: java.lang.IllegalArgumentException) { showError("删除失败!") } }) } } catch (ex: java.lang.IllegalArgumentException) { showError("删除失败!") } }) } /** * 添加案件点到地图 * @param location Point 点位置 * @param longitude String 经度 * @param latitude String 纬度 */ private fun caseAppendWaypointToMap(location: Point, longitude: String, latitude: String) { // todo: 2023/6/13 创建案件点模型 var caseModel = CaseModel(longitude.toDouble(), latitude.toDouble(), 0.0, 0.0, CaseType.MediaTypeWjNo) // todo: 2023/6/13 创建案件点图元 var caseFeature = fTableMedia?.createFeature() // todo: 2023/6/13 添加属性 caseModel.setAttributes(caseFeature!!.attributes) // todo: 2023/6/13 设置要素空间图元 caseFeature.geometry = location // todo: 2023/6/13 添加到地图中 var appendAsync = fTableMedia?.addFeatureAsync(caseFeature) appendAsync?.addDoneListener(Runnable { try { if (appendAsync.isDone) { fLayerMedia?.clearSelection() fLayerMedia?.selectFeature(caseFeature) caseUpdatePolygonByFeature(caseFeature, object : ICompletion { override fun onCompletion(completion: CompletionModel) { if (completion.isSuccess == true) { CrUtil.showToast( String.format( "案件点追加成功 %s", caseFeature.attributes[FIELD_CASE_NAME] ) ) } else { showError(completion.result!!) } } }) } } catch (ex: java.lang.IllegalArgumentException) { showError("案件点添加错误!") } }) } /** * 根据案件点要素图元的案件编号查询到与之关联的案件面,并进行初始化 * @param geom Feature 案件点要素 * @param callback iCompletion 完成回调 */ private fun caseClearPolygonByFeature(geom: Feature, callback: ICompletion) { // todo: 2023/6/13 获取案件ID val caseId = geom.attributes[FIELD_CASE_NAME] // todo: 2023/6/15 先判断是否存在与该案件点名称相同的案件图斑 将其标志清除 var queryParameters = QueryParameters() queryParameters.whereClause = String.format("%s = '%s'", FIELD_CASE_POLYGON_ANJID, caseId) var asyncQuery = fTableCasePolygon?.queryFeaturesAsync(queryParameters) asyncQuery?.addDoneListener(Runnable { try { if (asyncQuery.isDone) { var features = mutableListOf() for (fea in asyncQuery.get()) { fea.attributes[FIELD_CASE_POLYGON_ANJID] = "" fea.attributes[FIELD_CASE_POLYGON_BZ] = FIELD_CASE_POLYGON_BZ_VALUE_NO features.add(fea) } var asyncUpdate = fTableCasePolygon?.updateFeaturesAsync(features) asyncUpdate?.addDoneListener(Runnable { try { if (asyncUpdate.isDone) { if (callback != null) callback.onCompletion( CompletionModel( true, "" ) ) } } catch (ex: java.lang.IllegalArgumentException) { if (callback != null) callback.onCompletion( CompletionModel( false, "案件面初始化错误!" ) ) } }) } } catch (ex: java.lang.IllegalArgumentException) { if (callback != null) callback.onCompletion(CompletionModel(false, "案件面初始化错误!")) } }) } /** * 更新案件点对应的案件对象 * @param geom Feature 案件点 * @param callback iCompletion 回调 */ private fun caseUpdatePolygonByFeature(geom: Feature, callback: ICompletion) { // todo: 2023/6/15 先进行初始化 caseClearPolygonByFeature(geom, object : ICompletion { override fun onCompletion(completion: CompletionModel) { if (completion.isSuccess == false) { if (callback != null) callback.onCompletion(completion) } else { // todo: 2023/6/13 获取案件ID val caseId = geom.attributes[FIELD_CASE_NAME] // todo: 2023/6/15 先判断是否存在与该案件点名称相同的案件图斑 将其标志清除 var queryParameters = QueryParameters() // todo: 2023/6/13 先进行空间查询 查询案件点对应的案件面 queryParameters.geometry = geom.geometry queryParameters.spatialRelationship = QueryParameters.SpatialRelationship.INTERSECTS queryParameters.whereClause = "1=1" var queryAsync = fTableCasePolygon!!.queryFeaturesAsync(queryParameters) queryAsync?.addDoneListener(Runnable { try { if (queryAsync.isDone) { var features = mutableListOf() for (fea in queryAsync.get()) { fea.attributes[FIELD_CASE_POLYGON_ANJID] = caseId fea.attributes[FIELD_CASE_POLYGON_BZ] = FIELD_CASE_POLYGON_BZ_VALUE_YES features.add(fea) } // todo: 2023/6/13 更新 var updateAsync = fTableCasePolygon!!.updateFeaturesAsync(features) updateAsync?.addDoneListener(Runnable { try { if (updateAsync.isDone) { // todo: 2023/6/13 更新完成 if (callback != null) callback.onCompletion( CompletionModel( true, "成功!" ) ) } } catch (ex: java.lang.IllegalArgumentException) { if (callback != null) callback.onCompletion( CompletionModel( false, "案件对象更新失败!" ) ) } }) } } catch (ex: java.lang.IllegalArgumentException) { if (callback != null) callback.onCompletion( CompletionModel( false, "案件对象查询失败!" ) ) } }) } } }) } /** * 删除案件点 * @param screenPoint android.graphics.Point 查询产靠位置 */ private fun caseRemoveCaseWaypoing(screenPoint: android.graphics.Point) { // todo: 2023/6/14 开始查询 var identifyAsync = map_mapView?.identifyLayerAsync(fLayerMedia, screenPoint, 6.0, false) identifyAsync?.addDoneListener(Runnable { try { if (identifyAsync.isDone) { var features = mutableListOf() for (element in identifyAsync.get().elements) { features.add(element as Feature) } if (features.size > 0) { var dig = DialogNormal(CrApplication.getContext()) dig.setTitle("提示") dig.setMessage("删除后将无法恢复,确定删除吗?") dig.setButtonsText("删除", "取消") dig.setListener(object : DialogNormal.DialogNormalListener { // todo: 2023/6/14 确认删除 override fun completion() { caseRemoveWaypointAndUpdateCasePolygon(features, object : ICompletion { override fun onCompletion(completion: CompletionModel) { if (completion.isSuccess == true) { CrUtil.showToast("删除成功!") } else { showError(completion.result!!) } } }) } // todo: 2023/6/14 关闭 override fun close() { } }) dig.show() } else { showWarning("未查询到任何案件点!") } } } catch (ex: java.lang.IllegalArgumentException) { showError("查询错误,无法删除!") } }) } /** * 删除案件点并更新与之相对应的案件面 * @param features List 案件点集合 * @param callback iCompletion 完成回调 */ private fun caseRemoveWaypointAndUpdateCasePolygon( features: List, callback: ICompletion ) { var deleteAsync = fTableMedia?.deleteFeaturesAsync(features) deleteAsync?.addDoneListener(Runnable { try { if (deleteAsync.isDone) { // todo: 2023/6/16 更新 var wheres = mutableListOf() for (fea in features) { wheres.add(fea.attributes[FIELD_CASE_NAME].toString()) } caseUpdateCasePolygonByWhere(wheres, callback) } } catch (ex: java.lang.IllegalArgumentException) { if (callback != null) callback.onCompletion(CompletionModel(false, "案件点删除失败!")) } }) } /** * 根据更新条件更新案件点关联的案件面为 未关联案件点状态 * @param wheres List 案件Id的集合 * @param callback iCompletion 完成回调 */ private fun caseUpdateCasePolygonByWhere(wheres: List, callback: ICompletion) { var updateWhere = "" // todo: 2023/6/16 组合条件 for (where in wheres) { updateWhere += if (updateWhere == "") { String.format("'%s'", where) } else { String.format(",'%s'", where) } } // todo: 2023/6/16 开始查询 var queryParameters = QueryParameters() queryParameters.whereClause = updateWhere var asyncQuery = fTableCasePolygon?.queryFeaturesAsync(queryParameters) asyncQuery?.addDoneListener(Runnable { try { if (asyncQuery.isDone) { var features = mutableListOf() for (fea in asyncQuery.get()) { fea.attributes[FIELD_CASE_POLYGON_ANJID] = "" fea.attributes[FIELD_CASE_POLYGON_BZ] = FIELD_CASE_POLYGON_BZ_VALUE_NO features.add(fea) } // todo: 2023/6/16 开始更新 var asyncUpdate = fTableCasePolygon?.updateFeaturesAsync(features) asyncUpdate?.addDoneListener(Runnable { try { if (asyncUpdate.isDone) { if (callback != null) callback.onCompletion( CompletionModel( true, "" ) ) } } catch (ex: java.lang.IllegalArgumentException) { if (callback != null) callback.onCompletion( CompletionModel( false, "关联案件更新失败!" ) ) } }) } } catch (ex: java.lang.IllegalArgumentException) { if (callback != null) callback.onCompletion(CompletionModel(false, "关联案件查询失败!")) } }) } /** * 移动案件点 */ private fun caseMoveWaypoint() { CrUtil.showToast("选择需要移动的案件点!") mapTouch?.setAction(MapAction.MapTapStartMoveWaypoing) } /** * 选择移动的案件点 * @param location Point 点击位置 */ private fun caseMoveWaypointBySelect(location: Point) { // todo: 2023/6/14 设置查询区域 var queryGeometry = GeometryEngine.buffer(location, 10.0) // todo: 2023/6/14 设置查询条件 var queryParameters = QueryParameters() queryParameters.geometry = queryGeometry queryParameters.spatialRelationship = QueryParameters.SpatialRelationship.CONTAINS queryParameters.whereClause = "1=1" // todo: 2023/6/14 开始查询 var queryAsync = fTableMedia?.queryFeaturesAsync(queryParameters) queryAsync?.addDoneListener(Runnable { try { if (queryAsync.isDone) { var features = mutableListOf() for (fea in queryAsync.get()) { features.add(fea) } if (features.size == 0) { CrUtil.showToast("未查询到任何违建点!") } else { fLayerMedia?.clearSelection() fLayerMedia?.selectFeature(features[0]) CrUtil.showToast("地图点击确定移动位置!") mapTouch?.setAction(MapAction.MapTapStopMoveWaypoint) // todo: 2023/6/15 利用编辑工具 sketchEditor?.start(location) sketchEditor?.addGeometryChangedListener(sketchGeometryChangeListener) } } } catch (ex: java.lang.IllegalArgumentException) { showError("案件点查询错误!") } }) } /** * 案件点移动结束 * @param location Point 移动后位置 */ private fun caseMoveWaypointToEnd(location: Point) { var asyncSelected = fLayerMedia?.selectedFeaturesAsync asyncSelected?.addDoneListener(Runnable { try { if (asyncSelected.isDone) { var features = mutableListOf() for (fea in asyncSelected.get()) { features.add(fea) } if (features.size == 0) { showError("未获取到可移动违建点,无法完成移动操作!") } else { features[0].geometry = location var asyncUpdate = fTableMedia?.updateFeatureAsync(features[0]) asyncUpdate?.addDoneListener(Runnable { try { if (asyncUpdate.isDone) { caseUpdatePolygonByFeature( features[0], object : ICompletion { override fun onCompletion(completion: CompletionModel) { if (completion.isSuccess == true) { CrUtil.showToast("移动完成!") sketchEditor?.removeGeometryChangedListener( sketchGeometryChangeListener ) sketchEditor?.stop() fLayerMedia?.clearSelection() } else { showError(completion.result!!) } } }) } } catch (ex: java.lang.IllegalArgumentException) { showError("移动错误,无法完成移动操作!") } }) } } } catch (ex: java.lang.IllegalArgumentException) { showError("获取可移动违建点错误,无法完成移动操作!") } }) } /** * 案件分享及上传选择执行 * @param screenPoint Point 屏幕点 */ private fun caseUpload(screenPoint: android.graphics.Point) { // todo: 2023/6/15 查询 var asyncQuery = map_mapView?.identifyLayerAsync(fLayerMedia, screenPoint, 6.0, false) asyncQuery?.addDoneListener(Runnable { try { if (asyncQuery.isDone) { var elements = asyncQuery.get().elements if (elements.size <= 0) { CrUtil.showToast("未选择上传案件!") } else { fLayerMedia?.selectFeature(elements.last() as Feature) if (eventListener != null) eventListener?.onCaseUpdate(CaseModel(elements.last().attributes)) } } } catch (ex: java.lang.IllegalArgumentException) { showError("案件查询错误!") } }) } /** * 保存截图 * @param joinCaseName String 关联的案件名称 */ private fun captures(joinCaseName: String) { // todo: 2023/8/14 显示等待框 showLoading("初始化...") // todo: 2023/8/14 初始化图片信息 captureNames.clear() captureNames.add("${joinCaseName}_yx.jpg") captureNames.add("${joinCaseName}_xz.jpg") captureNames.add("${joinCaseName}_gh.jpg") // todo: 2023/8/14 初始化信息 var opNameList = mutableListOf>() var ovLayerList = mutableListOf>() // todo: 2023/8/14 截图-影像图 val opNamesYX = mutableListOf( LAYER_NAME_YX, LAYER_NAME_CONFIG_VILLAGE, LAYER_NAME_CONFIG_TOWNS, LAYER_NAME_CASE ) val ovLayersYX = mutableListOf(gLayerIco!!) opNameList.add(opNamesYX) ovLayerList.add(ovLayersYX) // todo: 2023/8/14 截图-现状图 var opNamesXZ = mutableListOf( LAYER_NAME_XZ, LAYER_NAME_CONFIG_VILLAGE, LAYER_NAME_CONFIG_TOWNS, LAYER_NAME_CASE ) var ovLayersXZ = mutableListOf(gLayerIco!!) opNameList.add(opNamesXZ) ovLayerList.add(ovLayersXZ) // todo: 2023/8/14 截图-规划图 var opNamesGH = mutableListOf( LAYER_NAME_GH, LAYER_NAME_CONFIG_VILLAGE, LAYER_NAME_CONFIG_TOWNS, LAYER_NAME_CASE ) var ovLayersGH = mutableListOf(gLayerIco!!) opNameList.add(opNamesGH) ovLayerList.add(ovLayersGH) // todo: 2023/8/14 执行协程 GlobalScope.launch { withContext(Dispatchers.IO) { updateLoading("保存地图状态...") saveMapLayerState() updateLoading("截取影像图...") capturesByName(opNameList[0], ovLayerList[0], captureNames[0]) updateLoading("截取现状图...") capturesByName(opNameList[1], ovLayerList[1], captureNames[1]) updateLoading("截取规划图...") capturesByName(opNameList[2], ovLayerList[2], captureNames[2]) updateLoading("恢复地图状态...") restoreMapLayerState() // todo: 2023/8/14 发送截图完成事件 CrApplication.getEventBus().post( EventMapCapture( EventMapCapture.CaptureAction.CAPTURE_ACTION_COMPLETE, null, captureNames ) ) // todo: 2023/8/14 关闭等待框 closeLoading() } } } /** * 协程函数 可挂起 * 保存地图图层当前可视状态 */ private suspend fun saveMapLayerState() { // todo: 2023/8/8 清除数据 mapStateList.clear() // todo: 2023/8/8 循环操作类型图层 for (i in 0 until mMap?.operationalLayers!!.size) { var visible = mMap?.operationalLayers!![i].isVisible mapStateList.add(MapStateModel(i, visible, MapType.MAP_TYPE_O_LAYER)) } // todo: 2023/8/8 循环绘制类型图层 for (i in 0 until map_mapView.graphicsOverlays.size) { var visible = map_mapView.graphicsOverlays[i].isVisible mapStateList.add(MapStateModel(i, visible, MapType.MAP_TYPE_D_LAYER)) } delay(1000) } /** * 协程函数 可挂起 * 恢复地图图层状态 */ private suspend fun restoreMapLayerState() { for (model in mapStateList) { if (model.mapType == MapType.MAP_TYPE_O_LAYER) { mMap?.operationalLayers!![model.index].isVisible = model.visible } else if (model.mapType == MapType.MAP_TYPE_D_LAYER) { map_mapView.graphicsOverlays[model.index].isVisible = model.visible } } delay(1000) } /** * 地图截图 * @param opLayerNames List 显示的操作图层名称 * @param ovLayerNames List 显示的绘制图层名称 * @param saveName String 保存截图名称 */ private suspend fun capturesByName( opLayerNames: List, ovLayerNames: List, saveName: String ) { // todo: 2023/8/14 控制操作图层 for (layer in mMap?.operationalLayers!!) { layer.isVisible = opLayerNames.indexOf(layer.name) != -1 } // todo: 2023/8/14 操作绘制图层 for (overlay in map_mapView.graphicsOverlays) { overlay.isVisible = ovLayerNames.indexOf(overlay) != -1 } // todo: 2023/8/14 延迟1.5秒 为了图层能正确加载 delay(1500) toBitmapAndSave("${CrUtil.IMAGE_PATH}${saveName}") } /** * 保存地图截图到指定路径文件 * @param filePath String 文件全路径 */ private suspend fun toBitmapAndSave(filePath: String) { map_mapView.clearFocus() map_mapView.isPressed = false // todo: 2023/8/14 能绘制缓存就返回false var willNotCache = map_mapView.willNotCacheDrawing() map_mapView.setWillNotCacheDrawing(false) var color: Int = map_mapView.drawingCacheBackgroundColor map_mapView.drawingCacheBackgroundColor = 0 if (color != 0) { map_mapView.destroyDrawingCache() } map_mapView.buildDrawingCache() var cacheBitmap: Bitmap? = null while (cacheBitmap == null) { var export = map_mapView.exportImageAsync() try { cacheBitmap = export.get() } catch (e: InterruptedException) { e.message?.let { CrUtil.showToast(it) } } catch (e: ExecutionException) { e.message?.let { CrUtil.showToast(it) } } } // todo: 2023/8/14 创建位图 var bitmap = Bitmap.createBitmap(cacheBitmap) // todo: 2023/8/14 重置地图 map_mapView.destroyDrawingCache() map_mapView.setWillNotCacheDrawing(willNotCache) map_mapView.drawingCacheBackgroundColor = color // todo: 2023/8/14 保存截图 var saveFile = File(filePath) var stream = FileOutputStream(saveFile) bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream) } /** * 飞行器位置超边界剧中 * @param longitude Double 经度 * @param latitude Double 纬度 */ private fun aircraftCenter(longitude:Double,latitude:Double){ var visiblePolygon = mapView?.visibleArea var airPoint = Point(longitude,latitude,spatialReferenceWGS84) var targetPoint = GeometryEngine.project(airPoint,mapView?.spatialReference) as Point if(!GeometryEngine.within(targetPoint,visiblePolygon)){ setMapCenter(longitude,latitude,0.0) } } /** * 初始化订阅 */ private fun initObserver(){ flightControlVm.flightControlInfo.observe(requireActivity()){ it?.let { if(it.longitude > 10 && it.latitude > 10){ // todo: 2023/8/17 更新位置 updateAirplaneLocation(it) // todo: 2023/8/17 更新返航点 updateAirplaneHomeLocation(it) // todo: 2023/8/17 更新连接线 updateAirplaneLinkLine(it) } } } } /** * 更新飞行器位置 * @param obj CrFlightControlInfo 飞行器信息 */ private fun updateAirplaneLocation(obj:CrFlightControlInfo){ // todo: 2023/8/17 更新飞行器位置 builderAirplaneLocation?.setXY(obj.longitude,obj.latitude) graAirplaneLocation?.geometry = builderAirplaneLocation!!.toGeometry() // todo: 2023/8/17 更新角度 symbolAirplaneLocation?.angle = obj.yaw.toFloat() // todo: 2023/8/17 超边界更新 aircraftCenter(obj.longitude,obj.latitude) // todo: 2023/8/17 更新航线 builderAirplaneLine?.addPoint(Point(obj.longitude,obj.latitude)) graAirplaneLine?.geometry = builderAirplaneLine!!.toGeometry() } /** * 更新返航位置 * @param obj CrFlightControlInfo 飞行器信息 */ private fun updateAirplaneHomeLocation(obj:CrFlightControlInfo){ if(obj.isUpdateHomeLocation){ CrUtil.print("返航点已刷新,请留意返航位置!") CrAudioUtil.getInstance().play("返航点已刷新,请留意返航位置!") builderAirplaneHomeLocation?.setXY(obj.homeLongitude,obj.homeLatitude) graAirplaneHomeLocation?.geometry = builderAirplaneHomeLocation!!.toGeometry() // todo: 2023/8/17 如果返航点已刷新 则认为是更换了起飞位置 则重新初始化航线 builderAirplaneLine = PolylineBuilder(spatialReferenceWGS84) builderAirplaneLine?.addPoint(Point(obj.homeLongitude,obj.homeLatitude)) graAirplaneLine?.geometry = builderAirplaneLine!!.toGeometry() // todo: 2023/8/17 设置更新标志 否则一直更新 obj.isUpdateHomeLocation = false } } /** * 更新连接线 * @param obj CrFlightControlInfo 飞行器信息 */ private fun updateAirplaneLinkLine(obj:CrFlightControlInfo){ if(obj.isHomeLocationValid && obj.isLocationValid){ builderAirplaneLink = PolylineBuilder(spatialReferenceWGS84) builderAirplaneLink?.addPoint(Point(obj.longitude,obj.latitude)) builderAirplaneLink?.addPoint(Point(obj.homeLongitude,obj.homeLatitude)) graAirplaneLink?.geometry = builderAirplaneLink!!.toGeometry() } } /** * 订阅地图事件执行动作 * @param event EventMap 事件 */ @Subscribe fun onAction(event: EventMap) { when (event.action) { // todo: 2023/4/17 绘制涂鸦 MapAction.MapTapDrawDoodle -> { CrUtil.showToast("地图接收绘制命令") doodleStartDraw() } // todo: 2023/4/17 清除涂鸦 MapAction.EventDoodleClear -> { clearSketch() } // todo: 2023/4/17 保存涂鸦 MapAction.EventDoodleSave -> { doodleSave() } // todo: 2023/4/17 停止草图编辑 MapAction.EventStopSketch -> { sketchEditor?.stop() } // todo: 2023/4/17 全部删除保存的涂鸦 MapAction.EventDoodleRemove -> { removeAllFeatureByTable(fTableDoodle!!) } // todo: 2023/4/18 删除选择涂鸦 MapAction.EventDoodleDelete -> { doodleSelectFeature(fLayerDoodle!!) } // todo: 2023/4/18 选择涂鸦 MapAction.MapTapSelectDoodle -> { CrUtil.showToast("地图上点击需要选择的涂鸦") mapTouch?.setQueryLayer(fLayerDoodle!!, MapAction.MapTapSelectDoodle) } // todo: 2023/4/18 停止Touch MapAction.EventStopTouch -> { mapTouch?.setQueryLayer(null, null) unfocusAllFeature() } // todo: 2023/4/19 绘制标志 MapAction.MapTapAppendMark -> { CrUtil.showToast("地图上单击创建标志!") if (event.owner is FragmentMark) { markChange = (event.owner as FragmentMark).getMark() mapTouch?.setAction(MapAction.MapTapAppendMark) } } // todo: 2023/4/19 清除标志 MapAction.EventMarkClear -> { gLayerIco?.let { it.graphics?.clear() CrUtil.showToast("标志清除完成!") } } // todo: 2023/4/19 标志保存 MapAction.EventMarkSave -> { markSave() } // todo: 2023/4/19 删除保存的全部标志 MapAction.EventMarkRemove -> { removeAllFeatureByTable(fTableMark!!) } // todo: 2023/4/21 选择标志 MapAction.MapTapSelectMark -> { CrUtil.showToast("地图上点击需要选择的标志") mapTouch?.setQueryLayer(fLayerMark!!, MapAction.MapTapSelectMark) } // todo: 2023/4/21 删除选择的标志 MapAction.EventMarkDelete -> { doodleSelectFeature(fLayerMark!!) } // todo: 2023/4/21 长度测量 MapAction.EventSurveyLength -> { measureLength() } // todo: 2023/6/6 面积测量 MapAction.EventSurveyArea -> { measureArea() } // todo: 2023/6/7 初始化测量 MapAction.EventSurveyClear -> { // todo: 2023/6/7 清理临时标注 gLayerTemp?.graphics?.clear() // todo: 2023/6/7 结束编辑 sketchEditor?.let { it.stop() it.removeGeometryChangedListener(sketchGeometryChangeListener) } } // todo: 2023/6/7 获取地图位置 MapAction.MapTapGetLocation -> { CrUtil.showToast("地图上点击查询地理位置") mapTouch?.setAction(MapAction.MapTapGetLocation) } // todo: 2023/6/7 输入坐标定位 MapAction.EventInputLocationToMap -> { var dialogInput: DialogInput = DialogInput(requireContext(), "输入位置信息") dialogInput.setButtonsText("确定", "关闭") dialogInput.setHints("输入经度,例118.70687", "输入纬度,例35.218991") dialogInput.setFonts( getString(R.string.ico_location), getString(R.string.ico_location) ) dialogInput.setListener(inputLocationToMapListener) dialogInput.show() } // todo: 2023/6/9 开始绘制案件图斑 MapAction.EventCaseDrawPolygon -> { caseStartDraw() } // todo: 2023/6/9 重置绘制 MapAction.EventCaseDrawReset -> { caseStartDraw() } // todo: 2023/6/9 回退 MapAction.EventCaseDrawUndo -> { sketchEditor?.undo() } // todo: 2023/6/12 保存绘制的图斑 MapAction.EventCaseSavePolygon -> { caseSave() } // todo: 2023/6/12 删除保存的图斑 MapAction.EventCaseRemovePolygon -> { caseDelete() } // todo: 2023/6/12 地图点击添加违建点 MapAction.MapTapAddWaypoint -> { CrUtil.showToast("地图上点击添加案件点!") mapTouch?.setAction(MapAction.MapTapAddWaypoint) } // todo: 2023/6/13 删除案件点 MapAction.MapTapDeleteWaypoint -> { CrUtil.showToast("地图上选择需要删除的违建点后删除!") mapTouch?.setAction(MapAction.MapTapDeleteWaypoint) } // todo: 2023/6/14 移动案件点 MapAction.MapTapStartMoveWaypoing -> { caseMoveWaypoint() } // todo: 2023/6/15 案件分享及上传 MapAction.MapTapCaseWxAndUpload -> { CrUtil.showToast("地图上选择需要上传或分享的案件!") mapTouch?.setAction(MapAction.MapTapCaseWxAndUpload) } } } /** * 订阅截屏事件 */ @Subscribe fun onCapture(event: EventMapCapture) { event?.let { if (it.action == EventMapCapture.CaptureAction.CAPTURE_ACTION_START) { captures(it.joinCaseName!!) } } } /** * 设置事件监听 * @param listener EventListener 事件监听 */ fun crSetEventListener(listener: EventListener) { this.eventListener = listener } // todo: 2023/4/17 生命周期 override fun onDestroy() { // todo: 2023/4/17 移除订阅监听 CrApplication.getEventBus().unregister(this) super.onDestroy() } /** * 生命周期 * 后台转前台 */ override fun onResume() { super.onResume() // todo: 2023/8/17 初始化订阅 initObserver() } }