diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index b1354f2..47853a4 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -117,27 +117,6 @@ return SaveKeyValues.getValue(this, "") as String } -fun String.hexToString(): String { - val sb = StringBuilder() - val temp: StringBuilder = StringBuilder() - run { - var i = 0 - while (i < this.length - 1) { - // 每两个Hex为一组 - val output = this.substring(i, i + 2) - val decimal = output.toInt(16) - sb.append(decimal.toChar()) - temp.append(decimal) - i += 2 - } - } - return sb.toString() -} - -fun String.isNumeric(): Boolean { - return this.matches("-?\\d+".toRegex()) -} - fun String.calculateCheckDigit(): String { var checksum = 0 for (i in 1 until this.length - 3) { diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index b1354f2..47853a4 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -117,27 +117,6 @@ return SaveKeyValues.getValue(this, "") as String } -fun String.hexToString(): String { - val sb = StringBuilder() - val temp: StringBuilder = StringBuilder() - run { - var i = 0 - while (i < this.length - 1) { - // 每两个Hex为一组 - val output = this.substring(i, i + 2) - val decimal = output.toInt(16) - sb.append(decimal.toChar()) - temp.append(decimal) - i += 2 - } - } - return sb.toString() -} - -fun String.isNumeric(): Boolean { - return this.matches("-?\\d+".toRegex()) -} - fun String.calculateCheckDigit(): String { var checksum = 0 for (i in 1 until this.length - 3) { diff --git a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt index 3511a01..99dfdc5 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt @@ -20,6 +20,7 @@ private val kTag = "SerialPortService" private val gpioManager by lazy { GpioManager() } private val serialPorts = BaseApplication.get().getSerialPorts() + private val sendExecutor = Executors.newFixedThreadPool(5) private var executor = Executors.newScheduledThreadPool(2) private var outStream: OutputStream? = null private var inStreamFirst: InputStream? = null @@ -42,10 +43,19 @@ try { outStream = serialPorts.first().outputStream - commandArray.forEach { - outStream?.write(it.code) - outStream?.flush() - Thread.sleep(500) + // 使用线程池发送数据 + commandArray.forEach { command -> + sendExecutor.submit { + try { + outStream?.write(command.code) + outStream?.flush() + Thread.sleep(1000) + } catch (e: IOException) { + Log.e(kTag, "Error writing to output stream", e) + } catch (e: InterruptedException) { + Log.e(kTag, "Thread interrupted", e) + } + } } inStreamFirst = serialPorts.first().inputStream diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index b1354f2..47853a4 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -117,27 +117,6 @@ return SaveKeyValues.getValue(this, "") as String } -fun String.hexToString(): String { - val sb = StringBuilder() - val temp: StringBuilder = StringBuilder() - run { - var i = 0 - while (i < this.length - 1) { - // 每两个Hex为一组 - val output = this.substring(i, i + 2) - val decimal = output.toInt(16) - sb.append(decimal.toChar()) - temp.append(decimal) - i += 2 - } - } - return sb.toString() -} - -fun String.isNumeric(): Boolean { - return this.matches("-?\\d+".toRegex()) -} - fun String.calculateCheckDigit(): String { var checksum = 0 for (i in 1 until this.length - 3) { diff --git a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt index 3511a01..99dfdc5 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt @@ -20,6 +20,7 @@ private val kTag = "SerialPortService" private val gpioManager by lazy { GpioManager() } private val serialPorts = BaseApplication.get().getSerialPorts() + private val sendExecutor = Executors.newFixedThreadPool(5) private var executor = Executors.newScheduledThreadPool(2) private var outStream: OutputStream? = null private var inStreamFirst: InputStream? = null @@ -42,10 +43,19 @@ try { outStream = serialPorts.first().outputStream - commandArray.forEach { - outStream?.write(it.code) - outStream?.flush() - Thread.sleep(500) + // 使用线程池发送数据 + commandArray.forEach { command -> + sendExecutor.submit { + try { + outStream?.write(command.code) + outStream?.flush() + Thread.sleep(1000) + } catch (e: IOException) { + Log.e(kTag, "Error writing to output stream", e) + } catch (e: InterruptedException) { + Log.e(kTag, "Thread interrupted", e) + } + } } inStreamFirst = serialPorts.first().inputStream diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt new file mode 100644 index 0000000..200fac7 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt @@ -0,0 +1,53 @@ +package com.casic.common.detector.gd.utils + +import com.casic.common.detector.gd.bean.MarkerLocalBean +import jxl.Workbook +import jxl.read.biff.BiffException +import java.io.File + +object ExcelKit { + fun read(filePath: String): ArrayList { + val result = ArrayList() + try { + val workbook = Workbook.getWorkbook(File(filePath)) + val sheet = workbook.getSheet(0) + + for (i in 1 until sheet.rows) { + val marker = MarkerLocalBean() + marker.pipelineType = sheet.getCell(0, i).contents + marker.pipelineDiameter = sheet.getCell(1, i).contents + marker.pipelineMaterial = sheet.getCell(2, i).contents + marker.buryMethod = sheet.getCell(3, i).contents + marker.buryDepth = sheet.getCell(4, i).contents + marker.area = sheet.getCell(5, i).contents + marker.line = sheet.getCell(6, i).contents + marker.road = sheet.getCell(7, i).contents + marker.constructTime = sheet.getCell(8, i).contents + marker.owner = sheet.getCell(9, i).contents + marker.objectId = sheet.getCell(10, i).contents + marker.markerId = sheet.getCell(11, i).contents + marker.markerType = sheet.getCell(12, i).contents + marker.markerDepth = sheet.getCell(13, i).contents + marker.installationDept = sheet.getCell(14, i).contents + marker.lng = sheet.getCell(15, i).contents + marker.lat = sheet.getCell(16, i).contents + marker.updateTime = sheet.getCell(17, i).contents + marker.remark = sheet.getCell(18, i).contents + marker.underlyingPipelineType = sheet.getCell(19, i).contents + marker.underlyingPipelineDepth = sheet.getCell(20, i).contents + marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents + marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents + marker.objectType = sheet.getCell(23, i).contents + marker.color = sheet.getCell(24, i).contents + marker.imagePath = sheet.getCell(25, i).contents + + result.add(marker) + DataBaseManager.get.saveMarkerInLocale(marker) + } + workbook.close() + } catch (e: BiffException) { + e.printStackTrace() + } + return result + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index b1354f2..47853a4 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -117,27 +117,6 @@ return SaveKeyValues.getValue(this, "") as String } -fun String.hexToString(): String { - val sb = StringBuilder() - val temp: StringBuilder = StringBuilder() - run { - var i = 0 - while (i < this.length - 1) { - // 每两个Hex为一组 - val output = this.substring(i, i + 2) - val decimal = output.toInt(16) - sb.append(decimal.toChar()) - temp.append(decimal) - i += 2 - } - } - return sb.toString() -} - -fun String.isNumeric(): Boolean { - return this.matches("-?\\d+".toRegex()) -} - fun String.calculateCheckDigit(): String { var checksum = 0 for (i in 1 until this.length - 3) { diff --git a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt index 3511a01..99dfdc5 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt @@ -20,6 +20,7 @@ private val kTag = "SerialPortService" private val gpioManager by lazy { GpioManager() } private val serialPorts = BaseApplication.get().getSerialPorts() + private val sendExecutor = Executors.newFixedThreadPool(5) private var executor = Executors.newScheduledThreadPool(2) private var outStream: OutputStream? = null private var inStreamFirst: InputStream? = null @@ -42,10 +43,19 @@ try { outStream = serialPorts.first().outputStream - commandArray.forEach { - outStream?.write(it.code) - outStream?.flush() - Thread.sleep(500) + // 使用线程池发送数据 + commandArray.forEach { command -> + sendExecutor.submit { + try { + outStream?.write(command.code) + outStream?.flush() + Thread.sleep(1000) + } catch (e: IOException) { + Log.e(kTag, "Error writing to output stream", e) + } catch (e: InterruptedException) { + Log.e(kTag, "Thread interrupted", e) + } + } } inStreamFirst = serialPorts.first().inputStream diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt new file mode 100644 index 0000000..200fac7 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt @@ -0,0 +1,53 @@ +package com.casic.common.detector.gd.utils + +import com.casic.common.detector.gd.bean.MarkerLocalBean +import jxl.Workbook +import jxl.read.biff.BiffException +import java.io.File + +object ExcelKit { + fun read(filePath: String): ArrayList { + val result = ArrayList() + try { + val workbook = Workbook.getWorkbook(File(filePath)) + val sheet = workbook.getSheet(0) + + for (i in 1 until sheet.rows) { + val marker = MarkerLocalBean() + marker.pipelineType = sheet.getCell(0, i).contents + marker.pipelineDiameter = sheet.getCell(1, i).contents + marker.pipelineMaterial = sheet.getCell(2, i).contents + marker.buryMethod = sheet.getCell(3, i).contents + marker.buryDepth = sheet.getCell(4, i).contents + marker.area = sheet.getCell(5, i).contents + marker.line = sheet.getCell(6, i).contents + marker.road = sheet.getCell(7, i).contents + marker.constructTime = sheet.getCell(8, i).contents + marker.owner = sheet.getCell(9, i).contents + marker.objectId = sheet.getCell(10, i).contents + marker.markerId = sheet.getCell(11, i).contents + marker.markerType = sheet.getCell(12, i).contents + marker.markerDepth = sheet.getCell(13, i).contents + marker.installationDept = sheet.getCell(14, i).contents + marker.lng = sheet.getCell(15, i).contents + marker.lat = sheet.getCell(16, i).contents + marker.updateTime = sheet.getCell(17, i).contents + marker.remark = sheet.getCell(18, i).contents + marker.underlyingPipelineType = sheet.getCell(19, i).contents + marker.underlyingPipelineDepth = sheet.getCell(20, i).contents + marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents + marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents + marker.objectType = sheet.getCell(23, i).contents + marker.color = sheet.getCell(24, i).contents + marker.imagePath = sheet.getCell(25, i).contents + + result.add(marker) + DataBaseManager.get.saveMarkerInLocale(marker) + } + workbook.close() + } catch (e: BiffException) { + e.printStackTrace() + } + return result + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt deleted file mode 100644 index 3ff55df..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.common.detector.gd.utils - -import com.casic.common.detector.gd.bean.MarkerLocalBean -import jxl.Workbook -import jxl.read.biff.BiffException -import java.io.File - -object ExcelTool { - fun read(filePath: String): ArrayList { - val result = ArrayList() - try { - val workbook = Workbook.getWorkbook(File(filePath)) - val sheet = workbook.getSheet(0) - - for (i in 1 until sheet.rows) { - val marker = MarkerLocalBean() - marker.pipelineType = sheet.getCell(0, i).contents - marker.pipelineDiameter = sheet.getCell(1, i).contents - marker.pipelineMaterial = sheet.getCell(2, i).contents - marker.buryMethod = sheet.getCell(3, i).contents - marker.buryDepth = sheet.getCell(4, i).contents - marker.area = sheet.getCell(5, i).contents - marker.line = sheet.getCell(6, i).contents - marker.road = sheet.getCell(7, i).contents - marker.constructTime = sheet.getCell(8, i).contents - marker.owner = sheet.getCell(9, i).contents - marker.objectId = sheet.getCell(10, i).contents - marker.markerId = sheet.getCell(11, i).contents - marker.markerType = sheet.getCell(12, i).contents - marker.markerDepth = sheet.getCell(13, i).contents - marker.installationDept = sheet.getCell(14, i).contents - marker.lng = sheet.getCell(15, i).contents - marker.lat = sheet.getCell(16, i).contents - marker.updateTime = sheet.getCell(17, i).contents - marker.remark = sheet.getCell(18, i).contents - marker.underlyingPipelineType = sheet.getCell(19, i).contents - marker.underlyingPipelineDepth = sheet.getCell(20, i).contents - marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents - marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents - marker.objectType = sheet.getCell(23, i).contents - marker.color = sheet.getCell(24, i).contents - marker.imagePath = sheet.getCell(25, i).contents - - result.add(marker) - } - workbook.close() - } catch (e: BiffException) { - e.printStackTrace() - } - return result - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index b1354f2..47853a4 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -117,27 +117,6 @@ return SaveKeyValues.getValue(this, "") as String } -fun String.hexToString(): String { - val sb = StringBuilder() - val temp: StringBuilder = StringBuilder() - run { - var i = 0 - while (i < this.length - 1) { - // 每两个Hex为一组 - val output = this.substring(i, i + 2) - val decimal = output.toInt(16) - sb.append(decimal.toChar()) - temp.append(decimal) - i += 2 - } - } - return sb.toString() -} - -fun String.isNumeric(): Boolean { - return this.matches("-?\\d+".toRegex()) -} - fun String.calculateCheckDigit(): String { var checksum = 0 for (i in 1 until this.length - 3) { diff --git a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt index 3511a01..99dfdc5 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt @@ -20,6 +20,7 @@ private val kTag = "SerialPortService" private val gpioManager by lazy { GpioManager() } private val serialPorts = BaseApplication.get().getSerialPorts() + private val sendExecutor = Executors.newFixedThreadPool(5) private var executor = Executors.newScheduledThreadPool(2) private var outStream: OutputStream? = null private var inStreamFirst: InputStream? = null @@ -42,10 +43,19 @@ try { outStream = serialPorts.first().outputStream - commandArray.forEach { - outStream?.write(it.code) - outStream?.flush() - Thread.sleep(500) + // 使用线程池发送数据 + commandArray.forEach { command -> + sendExecutor.submit { + try { + outStream?.write(command.code) + outStream?.flush() + Thread.sleep(1000) + } catch (e: IOException) { + Log.e(kTag, "Error writing to output stream", e) + } catch (e: InterruptedException) { + Log.e(kTag, "Thread interrupted", e) + } + } } inStreamFirst = serialPorts.first().inputStream diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt new file mode 100644 index 0000000..200fac7 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt @@ -0,0 +1,53 @@ +package com.casic.common.detector.gd.utils + +import com.casic.common.detector.gd.bean.MarkerLocalBean +import jxl.Workbook +import jxl.read.biff.BiffException +import java.io.File + +object ExcelKit { + fun read(filePath: String): ArrayList { + val result = ArrayList() + try { + val workbook = Workbook.getWorkbook(File(filePath)) + val sheet = workbook.getSheet(0) + + for (i in 1 until sheet.rows) { + val marker = MarkerLocalBean() + marker.pipelineType = sheet.getCell(0, i).contents + marker.pipelineDiameter = sheet.getCell(1, i).contents + marker.pipelineMaterial = sheet.getCell(2, i).contents + marker.buryMethod = sheet.getCell(3, i).contents + marker.buryDepth = sheet.getCell(4, i).contents + marker.area = sheet.getCell(5, i).contents + marker.line = sheet.getCell(6, i).contents + marker.road = sheet.getCell(7, i).contents + marker.constructTime = sheet.getCell(8, i).contents + marker.owner = sheet.getCell(9, i).contents + marker.objectId = sheet.getCell(10, i).contents + marker.markerId = sheet.getCell(11, i).contents + marker.markerType = sheet.getCell(12, i).contents + marker.markerDepth = sheet.getCell(13, i).contents + marker.installationDept = sheet.getCell(14, i).contents + marker.lng = sheet.getCell(15, i).contents + marker.lat = sheet.getCell(16, i).contents + marker.updateTime = sheet.getCell(17, i).contents + marker.remark = sheet.getCell(18, i).contents + marker.underlyingPipelineType = sheet.getCell(19, i).contents + marker.underlyingPipelineDepth = sheet.getCell(20, i).contents + marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents + marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents + marker.objectType = sheet.getCell(23, i).contents + marker.color = sheet.getCell(24, i).contents + marker.imagePath = sheet.getCell(25, i).contents + + result.add(marker) + DataBaseManager.get.saveMarkerInLocale(marker) + } + workbook.close() + } catch (e: BiffException) { + e.printStackTrace() + } + return result + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt deleted file mode 100644 index 3ff55df..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.common.detector.gd.utils - -import com.casic.common.detector.gd.bean.MarkerLocalBean -import jxl.Workbook -import jxl.read.biff.BiffException -import java.io.File - -object ExcelTool { - fun read(filePath: String): ArrayList { - val result = ArrayList() - try { - val workbook = Workbook.getWorkbook(File(filePath)) - val sheet = workbook.getSheet(0) - - for (i in 1 until sheet.rows) { - val marker = MarkerLocalBean() - marker.pipelineType = sheet.getCell(0, i).contents - marker.pipelineDiameter = sheet.getCell(1, i).contents - marker.pipelineMaterial = sheet.getCell(2, i).contents - marker.buryMethod = sheet.getCell(3, i).contents - marker.buryDepth = sheet.getCell(4, i).contents - marker.area = sheet.getCell(5, i).contents - marker.line = sheet.getCell(6, i).contents - marker.road = sheet.getCell(7, i).contents - marker.constructTime = sheet.getCell(8, i).contents - marker.owner = sheet.getCell(9, i).contents - marker.objectId = sheet.getCell(10, i).contents - marker.markerId = sheet.getCell(11, i).contents - marker.markerType = sheet.getCell(12, i).contents - marker.markerDepth = sheet.getCell(13, i).contents - marker.installationDept = sheet.getCell(14, i).contents - marker.lng = sheet.getCell(15, i).contents - marker.lat = sheet.getCell(16, i).contents - marker.updateTime = sheet.getCell(17, i).contents - marker.remark = sheet.getCell(18, i).contents - marker.underlyingPipelineType = sheet.getCell(19, i).contents - marker.underlyingPipelineDepth = sheet.getCell(20, i).contents - marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents - marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents - marker.objectType = sheet.getCell(23, i).contents - marker.color = sheet.getCell(24, i).contents - marker.imagePath = sheet.getCell(25, i).contents - - result.add(marker) - } - workbook.close() - } catch (e: BiffException) { - e.printStackTrace() - } - return result - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt index 03976a6..cb02061 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt @@ -261,6 +261,7 @@ override fun onDataReceived(buffer: ByteArray) { + if (buffer.isEmpty()) return if ((buffer.first().toInt() and 0xFF).toString(16).uppercase() == "30") { val markerId = buffer.toMarkerId() runOnUiThread { diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index b1354f2..47853a4 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -117,27 +117,6 @@ return SaveKeyValues.getValue(this, "") as String } -fun String.hexToString(): String { - val sb = StringBuilder() - val temp: StringBuilder = StringBuilder() - run { - var i = 0 - while (i < this.length - 1) { - // 每两个Hex为一组 - val output = this.substring(i, i + 2) - val decimal = output.toInt(16) - sb.append(decimal.toChar()) - temp.append(decimal) - i += 2 - } - } - return sb.toString() -} - -fun String.isNumeric(): Boolean { - return this.matches("-?\\d+".toRegex()) -} - fun String.calculateCheckDigit(): String { var checksum = 0 for (i in 1 until this.length - 3) { diff --git a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt index 3511a01..99dfdc5 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt @@ -20,6 +20,7 @@ private val kTag = "SerialPortService" private val gpioManager by lazy { GpioManager() } private val serialPorts = BaseApplication.get().getSerialPorts() + private val sendExecutor = Executors.newFixedThreadPool(5) private var executor = Executors.newScheduledThreadPool(2) private var outStream: OutputStream? = null private var inStreamFirst: InputStream? = null @@ -42,10 +43,19 @@ try { outStream = serialPorts.first().outputStream - commandArray.forEach { - outStream?.write(it.code) - outStream?.flush() - Thread.sleep(500) + // 使用线程池发送数据 + commandArray.forEach { command -> + sendExecutor.submit { + try { + outStream?.write(command.code) + outStream?.flush() + Thread.sleep(1000) + } catch (e: IOException) { + Log.e(kTag, "Error writing to output stream", e) + } catch (e: InterruptedException) { + Log.e(kTag, "Thread interrupted", e) + } + } } inStreamFirst = serialPorts.first().inputStream diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt new file mode 100644 index 0000000..200fac7 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt @@ -0,0 +1,53 @@ +package com.casic.common.detector.gd.utils + +import com.casic.common.detector.gd.bean.MarkerLocalBean +import jxl.Workbook +import jxl.read.biff.BiffException +import java.io.File + +object ExcelKit { + fun read(filePath: String): ArrayList { + val result = ArrayList() + try { + val workbook = Workbook.getWorkbook(File(filePath)) + val sheet = workbook.getSheet(0) + + for (i in 1 until sheet.rows) { + val marker = MarkerLocalBean() + marker.pipelineType = sheet.getCell(0, i).contents + marker.pipelineDiameter = sheet.getCell(1, i).contents + marker.pipelineMaterial = sheet.getCell(2, i).contents + marker.buryMethod = sheet.getCell(3, i).contents + marker.buryDepth = sheet.getCell(4, i).contents + marker.area = sheet.getCell(5, i).contents + marker.line = sheet.getCell(6, i).contents + marker.road = sheet.getCell(7, i).contents + marker.constructTime = sheet.getCell(8, i).contents + marker.owner = sheet.getCell(9, i).contents + marker.objectId = sheet.getCell(10, i).contents + marker.markerId = sheet.getCell(11, i).contents + marker.markerType = sheet.getCell(12, i).contents + marker.markerDepth = sheet.getCell(13, i).contents + marker.installationDept = sheet.getCell(14, i).contents + marker.lng = sheet.getCell(15, i).contents + marker.lat = sheet.getCell(16, i).contents + marker.updateTime = sheet.getCell(17, i).contents + marker.remark = sheet.getCell(18, i).contents + marker.underlyingPipelineType = sheet.getCell(19, i).contents + marker.underlyingPipelineDepth = sheet.getCell(20, i).contents + marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents + marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents + marker.objectType = sheet.getCell(23, i).contents + marker.color = sheet.getCell(24, i).contents + marker.imagePath = sheet.getCell(25, i).contents + + result.add(marker) + DataBaseManager.get.saveMarkerInLocale(marker) + } + workbook.close() + } catch (e: BiffException) { + e.printStackTrace() + } + return result + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt deleted file mode 100644 index 3ff55df..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.common.detector.gd.utils - -import com.casic.common.detector.gd.bean.MarkerLocalBean -import jxl.Workbook -import jxl.read.biff.BiffException -import java.io.File - -object ExcelTool { - fun read(filePath: String): ArrayList { - val result = ArrayList() - try { - val workbook = Workbook.getWorkbook(File(filePath)) - val sheet = workbook.getSheet(0) - - for (i in 1 until sheet.rows) { - val marker = MarkerLocalBean() - marker.pipelineType = sheet.getCell(0, i).contents - marker.pipelineDiameter = sheet.getCell(1, i).contents - marker.pipelineMaterial = sheet.getCell(2, i).contents - marker.buryMethod = sheet.getCell(3, i).contents - marker.buryDepth = sheet.getCell(4, i).contents - marker.area = sheet.getCell(5, i).contents - marker.line = sheet.getCell(6, i).contents - marker.road = sheet.getCell(7, i).contents - marker.constructTime = sheet.getCell(8, i).contents - marker.owner = sheet.getCell(9, i).contents - marker.objectId = sheet.getCell(10, i).contents - marker.markerId = sheet.getCell(11, i).contents - marker.markerType = sheet.getCell(12, i).contents - marker.markerDepth = sheet.getCell(13, i).contents - marker.installationDept = sheet.getCell(14, i).contents - marker.lng = sheet.getCell(15, i).contents - marker.lat = sheet.getCell(16, i).contents - marker.updateTime = sheet.getCell(17, i).contents - marker.remark = sheet.getCell(18, i).contents - marker.underlyingPipelineType = sheet.getCell(19, i).contents - marker.underlyingPipelineDepth = sheet.getCell(20, i).contents - marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents - marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents - marker.objectType = sheet.getCell(23, i).contents - marker.color = sheet.getCell(24, i).contents - marker.imagePath = sheet.getCell(25, i).contents - - result.add(marker) - } - workbook.close() - } catch (e: BiffException) { - e.printStackTrace() - } - return result - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt index 03976a6..cb02061 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt @@ -261,6 +261,7 @@ override fun onDataReceived(buffer: ByteArray) { + if (buffer.isEmpty()) return if ((buffer.first().toInt() and 0xFF).toString(16).uppercase() == "30") { val markerId = buffer.toMarkerId() runOnUiThread { diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 881eb33..b4afad3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -7,8 +7,6 @@ import android.content.ServiceConnection import android.graphics.BitmapFactory import android.graphics.Color -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.Drawable import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle @@ -21,10 +19,12 @@ import androidx.lifecycle.lifecycleScope import com.amap.api.location.AMapLocation import com.amap.api.maps.AMap +import com.amap.api.maps.AMap.OnMapLongClickListener import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter import com.amap.api.maps.model.BitmapDescriptorFactory +import com.amap.api.maps.model.CameraPosition import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds import com.amap.api.maps.model.Marker @@ -37,15 +37,9 @@ import com.casic.common.detector.gd.callback.OnGetAddressListener import com.casic.common.detector.gd.callback.OnGetLocationListener import com.casic.common.detector.gd.callback.OnSerialPortListener -import com.casic.common.detector.gd.cluster.ClusterItem -import com.casic.common.detector.gd.cluster.ClusterOverlay -import com.casic.common.detector.gd.cluster.ClusterRender -import com.casic.common.detector.gd.cluster.OnClickClusterListener -import com.casic.common.detector.gd.cluster.RegionItem import com.casic.common.detector.gd.databinding.ActivityMainBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.createTaskCode -import com.casic.common.detector.gd.extensions.drawCircle import com.casic.common.detector.gd.extensions.initImmersionBar import com.casic.common.detector.gd.extensions.toMarkerId import com.casic.common.detector.gd.extensions.toSignalStrength @@ -54,7 +48,7 @@ import com.casic.common.detector.gd.service.NtripConnectService import com.casic.common.detector.gd.service.SerialPortService import com.casic.common.detector.gd.utils.DataBaseManager -import com.casic.common.detector.gd.utils.ExcelTool +import com.casic.common.detector.gd.utils.ExcelKit import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.utils.LocationKit @@ -64,7 +58,6 @@ import com.casic.common.detector.gd.widgets.QueryMarkerDialog import com.casic.common.detector.gd.widgets.SamplePopupWindow import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertDrawable import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.isNetworkConnected @@ -85,16 +78,14 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -import java.util.concurrent.CopyOnWriteArrayList -class MainActivity : KotlinBaseActivity(), ClusterRender, - OnClickClusterListener, OnSerialPortListener { +class MainActivity : KotlinBaseActivity(), AMap.OnMarkerClickListener, + OnMapLongClickListener, OnSerialPortListener { private val kTag = "MainActivity" private val context = this private val samplePopupWindow by lazy { SamplePopupWindow(this) } - private val backDrawables by lazy { HashMap() } private val detailDialog by lazy { MarkerDetailDialog(this) } private val locationKit by lazy { LocationKit(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } @@ -102,7 +93,6 @@ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build() private var clickTime: Long = 0 - private var markers = ArrayList() private var isFreeTask = false private var freeTaskTitle = "" private var ids = HashSet() @@ -140,16 +130,18 @@ } override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMapConfig(savedInstanceState) + //绑定串口通信服务 Intent(this, SerialPortService::class.java).also { bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) } - Intent(this, NtripConnectService::class.java).also { - startService(it) - } +// Intent(this, NtripConnectService::class.java).also { +// startService(it) +// } soundResourceId = soundPool.load(this, R.raw.ring3, 1) - //地图初始化 - initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -167,16 +159,9 @@ .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { - lifecycleScope.launch(Dispatchers.Main) { - withContext(Dispatchers.IO) { - markers = ExcelTool.read(file.absolutePath) - markers.forEach { marker -> - DataBaseManager.get.saveMarkerInLocale(marker) - } - } - LoadingDialog.dismiss() - showLabelsOnMap() - } + lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } + LoadingDialog.dismiss() + showMarkersOnMap() } override fun onFailure(throwable: Throwable) { @@ -224,12 +209,12 @@ ids.clear() //清空自由巡检添加的Marker aMap.clear() - showLabelsOnMap() + showMarkersOnMap() } taskViewModel.executeTaskResult.observe(this) { "工单任务已完成".show(this) aMap.clear() - showLabelsOnMap() + showMarkersOnMap() } } @@ -313,11 +298,9 @@ override fun onConfirmClick(selectedItem: String, value: String) { //查询数据库 lifecycleScope.launch(Dispatchers.Main) { - markers = withContext(Dispatchers.IO) { - DataBaseManager.get.loadMarkersByCondition( - selectedItem, value - ) as ArrayList - } + val markers = DataBaseManager.get.loadMarkersByCondition( + selectedItem, value + ) as ArrayList if (markers.isEmpty()) { "无法查到相关数据信息,请检查您的查询条件".show(context) @@ -344,8 +327,6 @@ //移动到指定经纬度 aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(center, 16f)) } - - showLabelsOnMap() } } } @@ -509,6 +490,7 @@ } override fun onDataReceived(buffer: ByteArray) { + if (buffer.isEmpty()) return //只响一次,因为探测频率高,所以依旧是连续的报警声 soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) when ((buffer.first().toInt() and 0xFF).toString(16).uppercase()) { @@ -567,14 +549,18 @@ private fun initMapConfig(savedInstanceState: Bundle?) { binding.mapView.onCreate(savedInstanceState) aMap = binding.mapView.map - + aMap.mapType = AMap.MAP_TYPE_NORMAL val uiSettings = aMap.uiSettings uiSettings.isCompassEnabled = true - uiSettings.isMyLocationButtonEnabled = false//不显示默认定位按钮 - uiSettings.isScaleControlsEnabled = true uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度 - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + //地图长按事件 + aMap.setOnMapLongClickListener(this) + //显示定位小蓝点 val locationStyle = MyLocationStyle() locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) @@ -594,15 +580,8 @@ //首次移动到定位点 moveToCurrentLocation() - aMap.setOnMapLongClickListener { - //协程异步显示默认数据 - lifecycleScope.launch(Dispatchers.Main) { - markers = withContext(Dispatchers.IO) { - DataBaseManager.get.loadMarkers() as ArrayList - } - showLabelsOnMap() - } - } + //渲染标识器位置 + showMarkersOnMap() //自定义定位按钮 binding.aimButton.setOnClickListener { moveToCurrentLocation() } @@ -638,97 +617,44 @@ "工单下载成功!".show(this) } - private var clusterOverlay: ClusterOverlay? = null + private fun showMarkersOnMap() { + lifecycleScope.launch(Dispatchers.IO) { + //取缓存 + val markers = DataBaseManager.get.loadMarkers() + if (markers.isEmpty()) { + return@launch + } + val first = markers.first() + val defaultLatLng = LatLng(first.lat.toDouble(), first.lng.toDouble()) + //移动到指定经纬度 + val cameraPosition = CameraPosition(defaultLatLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + withContext(Dispatchers.Main) { + aMap.animateCamera(cameraUpdate, 1500, null) + LoadingDialog.dismiss() + } - private fun showLabelsOnMap() { - val clusterItems = CopyOnWriteArrayList() - if (clusterOverlay == null) { - clusterOverlay = ClusterOverlay( - this, aMap, clusterItems, LocaleConstant.RADIUS_SIZE.dp2px(this) - ) - } - clusterOverlay?.apply { - setClusterRender(this@MainActivity) - setOnClickClusterListener(this@MainActivity) - } - markers.forEach { - if (it.lat.isNotEmpty() && it.lng.isNotEmpty()) { - val latitude = it.lat.toDouble() - val longitude = it.lng.toDouble() - - val latLng = LatLng(latitude, longitude, false) - //用标识器的ID当作地图Marker的Title - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + markers.forEach { marker -> + val latitude = marker.lat.toString().toDouble() + val longitude = marker.lng.toString().toDouble() + //将所有设备信息转化缓存为Marker点 + val options = MarkerOptions() + .position(LatLng(latitude, longitude)) + .title(marker.markerId) + aMap.addMarker(options) } } } - override fun getDrawableByCount(clusterNum: Int): Drawable { - //聚合点圆形半径 - val radius = 80.dp2px(this) - if (clusterNum == 1) { - var bitmapDrawable = backDrawables[1] - if (bitmapDrawable == null) { - bitmapDrawable = R.mipmap.label.convertDrawable(this)!! - backDrawables[1] = bitmapDrawable - } - return bitmapDrawable - } else if (clusterNum < 5) { - var bitmapDrawable = backDrawables[2] - if (bitmapDrawable == null) { - bitmapDrawable = BitmapDrawable( - null, radius.drawCircle(Color.argb(159, 100, 149, 237)) - ) - backDrawables[2] = bitmapDrawable - } - return bitmapDrawable - } else if (clusterNum < 10) { - var bitmapDrawable = backDrawables[3] - if (bitmapDrawable == null) { - bitmapDrawable = BitmapDrawable( - null, radius.drawCircle(Color.argb(199, 30, 144, 255)) - ) - backDrawables[3] = bitmapDrawable - } - return bitmapDrawable - } else { - var bitmapDrawable = backDrawables[4] - if (bitmapDrawable == null) { - bitmapDrawable = BitmapDrawable( - null, radius.drawCircle(Color.argb(235, 65, 105, 225)) - ) - backDrawables[4] = bitmapDrawable - } - return bitmapDrawable + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + showNavigationOption(title, position) } + return true } - override fun onClick(marker: Marker, clusterItems: MutableList) { - if (clusterItems.size == 1) { - val clusterItem = clusterItems[0] - showNavigationOption(clusterItem.title, clusterItem.position) - } else { - //聚合点,显示聚合点列表 - val idArray = ArrayList() - for (clusterItem in clusterItems) { - idArray.add(clusterItem.title) - } - BottomActionSheet.Builder() - .setContext(this) - .setItemTextColor(Color.BLUE) - .setActionItemTitle(idArray) - .setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener { - override fun onActionItemClick(position: Int) { - val markerId = idArray[position] - //根据markerId找到标识器 - val bean = markers.find { x -> x.markerId == markerId }!! - showNavigationOption( - bean.markerId, LatLng(bean.lat.toDouble(), bean.lng.toDouble()) - ) - } - }).build().show() - } + override fun onMapLongClick(p0: LatLng?) { + showMarkersOnMap() } private fun showNavigationOption(title: String, latLng: LatLng) { @@ -778,7 +704,6 @@ } aMap.addMarker(markerOptions) } - showLabelsOnMap() } //更新标识器数据 @@ -891,13 +816,6 @@ override fun onResume() { super.onResume() binding.mapView.onResume() - //协程异步显示默认数据 - lifecycleScope.launch(Dispatchers.Main) { - markers = withContext(Dispatchers.IO) { - DataBaseManager.get.loadMarkers() as ArrayList - } - showLabelsOnMap() - } } override fun onPause() { @@ -912,7 +830,6 @@ override fun onDestroy() { super.onDestroy() - clusterOverlay?.onDestroy() binding.mapView.onDestroy() soundPool.autoPause() locationKit.stopLocation() diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java b/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java deleted file mode 100644 index 85f50d4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/Cluster.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.Marker; - -import java.util.ArrayList; -import java.util.List; - -public class Cluster { - private final LatLng latLng; - private final String title; - private final List clusterItems; - private Marker marker; - - - public Cluster(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - clusterItems = new ArrayList<>(); - } - - public void addClusterItem(ClusterItem clusterItem) { - clusterItems.add(clusterItem); - } - - public int getClusterCount() { - return clusterItems.size(); - } - - public LatLng getCenterLatLng() { - return latLng; - } - - public String getTitle() { - return title; - } - - public void setMarker(Marker marker) { - this.marker = marker; - } - - public Marker getMarker() { - return marker; - } - - public List getClusterItems() { - return clusterItems; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java deleted file mode 100644 index 92916a4..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterItem.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public interface ClusterItem { - /** - * 返回聚合元素的地理位置 - */ - LatLng getPosition(); - - /** - * 返回聚合点标题(ID代替) - */ - String getTitle(); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java deleted file mode 100644 index b3e9a09..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterOverlay.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.TypedValue; -import android.view.Gravity; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.collection.LruCache; - -import com.amap.api.maps.AMap; -import com.amap.api.maps.AMapUtils; -import com.amap.api.maps.model.BitmapDescriptor; -import com.amap.api.maps.model.BitmapDescriptorFactory; -import com.amap.api.maps.model.CameraPosition; -import com.amap.api.maps.model.LatLng; -import com.amap.api.maps.model.LatLngBounds; -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.MarkerOptions; -import com.amap.api.maps.model.animation.AlphaAnimation; -import com.casic.common.detector.gd.R; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * 整体设计采用了两个线程,一个线程用于计算组织聚合数据,一个线程负责处理Marker相关操作 - */ -public class ClusterOverlay implements AMap.OnCameraChangeListener, AMap.OnMarkerClickListener { - private final AMap amap; - private final Context context; - private final CopyOnWriteArrayList clusterItems; - private final List clusters; - private final int clusterSize; - private OnClickClusterListener clickClusterListener; - private ClusterRender clusterRender; - private final CopyOnWriteArrayList addMarkers = new CopyOnWriteArrayList<>(); - private double clusterDistance; - private final LruCache lruCache; - private final HandlerThread markerHandlerThread = new HandlerThread("addMarker"); - private final HandlerThread signClusterThread = new HandlerThread("calculateCluster"); - private Handler markerHandler; - private Handler signClusterHandler; - private float pxInMeters; - private boolean isCanceled = false; - private final AlphaAnimation addAnimation = new AlphaAnimation(0, 1); - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, int clusterSize) { - this(context, amap, null, clusterSize); - } - - /** - * 构造函数,批量添加聚合元素时,调用此构造函数 - */ - public ClusterOverlay(Context context, AMap amap, CopyOnWriteArrayList clusterItems, int clusterSize) { - //默认最多会缓存80张图片作为聚合显示元素图片,根据自己显示需求和app使用内存情况,可以修改数量 - this.lruCache = new LruCache(80) { - protected void entryRemoved(boolean evicted, @NonNull Integer key, @NonNull BitmapDescriptor oldValue, BitmapDescriptor newValue) { - recycleBitmap(oldValue.getBitmap()); - } - }; - - if (clusterItems != null) { - this.clusterItems = clusterItems; - } else { - this.clusterItems = new CopyOnWriteArrayList<>(); - } - - this.context = context; - this.clusters = new ArrayList<>(); - this.amap = amap; - this.clusterSize = clusterSize; - this.pxInMeters = amap.getScalePerPixel(); - this.clusterDistance = pxInMeters * clusterSize; - amap.setOnCameraChangeListener(this); - amap.setOnMarkerClickListener(this); - initThreadHandler(); - assignClusters(); - } - - private void recycleBitmap(Bitmap bitmap) { - if (bitmap == null) { - return; - } - if (!bitmap.isRecycled()) { - bitmap.recycle(); - } - } - - /** - * 设置聚合点的点击事件 - */ - public void setOnClickClusterListener(OnClickClusterListener clickClusterListener) { - this.clickClusterListener = clickClusterListener; - } - - /** - * 添加一个聚合点 - */ - public void addClusterItem(ClusterItem item) { - Message message = Message.obtain(); - message.what = SignClusterHandler.CALCULATE_SINGLE_CLUSTER; - message.obj = item; - signClusterHandler.sendMessage(message); - } - - /** - * 设置聚合元素的渲染样式,不设置则默认为气泡加数字形式进行渲染 - */ - public void setClusterRender(ClusterRender render) { - this.clusterRender = render; - } - - public void onDestroy() { - isCanceled = true; - signClusterHandler.removeCallbacksAndMessages(null); - markerHandler.removeCallbacksAndMessages(null); - signClusterThread.quit(); - markerHandlerThread.quit(); - for (Marker marker : addMarkers) { - marker.remove(); - } - addMarkers.clear(); - lruCache.evictAll(); - } - - //初始化Handler - private void initThreadHandler() { - markerHandlerThread.start(); - signClusterThread.start(); - markerHandler = new MarkerHandler(markerHandlerThread.getLooper()); - signClusterHandler = new SignClusterHandler(signClusterThread.getLooper()); - } - - @Override - public void onCameraChange(CameraPosition arg0) { - - } - - @Override - public void onCameraChangeFinish(CameraPosition arg0) { - pxInMeters = amap.getScalePerPixel(); - clusterDistance = pxInMeters * clusterSize; - assignClusters(); - } - - @Override - public boolean onMarkerClick(Marker arg0) { - if (clickClusterListener == null) { - return true; - } - Cluster cluster = (Cluster) arg0.getObject(); - if (cluster != null) { - clickClusterListener.onClick(arg0, cluster.getClusterItems()); - return true; - } - return false; - } - - - /** - * 将聚合元素添加至地图上 - */ - private void addClusterToMap(List clusters) { - CopyOnWriteArrayList removeMarkers = new CopyOnWriteArrayList<>(addMarkers); - removeMarkers.addAll(addMarkers); - AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); - RemoveAnimationListener removeAnimationListener = new RemoveAnimationListener(removeMarkers); - for (Marker marker : removeMarkers) { - marker.setAnimation(alphaAnimation); - marker.setAnimationListener(removeAnimationListener); - marker.startAnimation(); - } - - for (Cluster cluster : clusters) { - addSingleClusterToMap(cluster); - } - } - - /** - * 将单个聚合元素添加至地图显示 - */ - private void addSingleClusterToMap(Cluster cluster) { - LatLng latlng = cluster.getCenterLatLng(); - MarkerOptions markerOptions = new MarkerOptions(); - markerOptions.icon(getBitmapDescriptor(cluster.getClusterCount())).position(latlng); - Marker marker = amap.addMarker(markerOptions); - marker.setAnimation(addAnimation); - marker.setObject(cluster); - marker.startAnimation(); - cluster.setMarker(marker); - addMarkers.add(marker); - } - - private void calculateClusters() { - isCanceled = false; - clusters.clear(); - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - for (ClusterItem clusterItem : clusterItems) { - if (isCanceled) { - return; - } - LatLng latlng = clusterItem.getPosition(); - if (visibleBounds.contains(latlng)) { - Cluster cluster = getCluster(latlng, clusters); - if (cluster == null) { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - } - cluster.addClusterItem(clusterItem); - } - } - - //复制一份数据,规避同步 - List tempClusters = new ArrayList<>(); - tempClusters.addAll(clusters); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_CLUSTER_LIST; - message.obj = tempClusters; - if (isCanceled) { - return; - } - markerHandler.sendMessage(message); - } - - /** - * 对点进行聚合 - */ - private void assignClusters() { - isCanceled = true; - signClusterHandler.removeMessages(SignClusterHandler.CALCULATE_CLUSTER); - signClusterHandler.sendEmptyMessage(SignClusterHandler.CALCULATE_CLUSTER); - } - - /** - * 在已有的聚合基础上,对添加的单个元素进行聚合 - */ - private void calculateSingleCluster(ClusterItem clusterItem) { - LatLngBounds visibleBounds = amap.getProjection().getVisibleRegion().latLngBounds; - LatLng latlng = clusterItem.getPosition(); - if (!visibleBounds.contains(latlng)) { - return; - } - Cluster cluster = getCluster(latlng, clusters); - if (cluster != null) { - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.UPDATE_SINGLE_CLUSTER; - - message.obj = cluster; - markerHandler.removeMessages(MarkerHandler.UPDATE_SINGLE_CLUSTER); - markerHandler.sendMessageDelayed(message, 5); - } else { - cluster = new Cluster(latlng, clusterItem.getTitle()); - clusters.add(cluster); - cluster.addClusterItem(clusterItem); - Message message = Message.obtain(); - message.what = MarkerHandler.ADD_SINGLE_CLUSTER; - message.obj = cluster; - markerHandler.sendMessage(message); - } - } - - /** - * 根据一个点获取是否可以依附的聚合点,没有则返回null - */ - private Cluster getCluster(LatLng latLng, List clusters) { - for (Cluster cluster : clusters) { - LatLng clusterCenterPoint = cluster.getCenterLatLng(); - double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint); - if (distance < clusterDistance && amap.getCameraPosition().zoom < 19) { - return cluster; - } - } - return null; - } - - - /** - * 获取每个聚合点的绘制样式 - */ - private BitmapDescriptor getBitmapDescriptor(int num) { - BitmapDescriptor bitmapDescriptor = lruCache.get(num); - if (bitmapDescriptor == null) { - TextView textView = new TextView(context); - if (num > 1) { - String tile = String.valueOf(num); - textView.setText(tile); - } - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.WHITE); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); - if (clusterRender != null && clusterRender.getDrawableByCount(num) != null) { - textView.setBackground(clusterRender.getDrawableByCount(num)); - } else { - textView.setBackgroundResource(R.mipmap.defaultcluster); - } - bitmapDescriptor = BitmapDescriptorFactory.fromView(textView); - lruCache.put(num, bitmapDescriptor); - - } - return bitmapDescriptor; - } - - /** - * 更新已加入地图聚合点的样式 - */ - private void updateCluster(Cluster cluster) { - Marker marker = cluster.getMarker(); - marker.setIcon(getBitmapDescriptor(cluster.getClusterCount())); - } - - /** - * 处理market添加,更新等操作 - */ - class MarkerHandler extends Handler { - - static final int ADD_CLUSTER_LIST = 0; - - static final int ADD_SINGLE_CLUSTER = 1; - - static final int UPDATE_SINGLE_CLUSTER = 2; - - public MarkerHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case ADD_CLUSTER_LIST: - List clusters = (List) message.obj; - addClusterToMap(clusters); - break; - case ADD_SINGLE_CLUSTER: - Cluster cluster = (Cluster) message.obj; - addSingleClusterToMap(cluster); - break; - case UPDATE_SINGLE_CLUSTER: - Cluster updateCluster = (Cluster) message.obj; - updateCluster(updateCluster); - break; - } - } - } - - /** - * 处理聚合点算法线程 - */ - class SignClusterHandler extends Handler { - static final int CALCULATE_CLUSTER = 0; - static final int CALCULATE_SINGLE_CLUSTER = 1; - - public SignClusterHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message message) { - switch (message.what) { - case CALCULATE_CLUSTER: - calculateClusters(); - break; - case CALCULATE_SINGLE_CLUSTER: - ClusterItem item = (ClusterItem) message.obj; - clusterItems.add(item); - calculateSingleCluster(item); - break; - } - } - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java b/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java deleted file mode 100644 index 01428c7..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/ClusterRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import android.graphics.drawable.Drawable; - -public interface ClusterRender { - /** - * 根据聚合点的元素数目返回渲染背景样式 - */ - Drawable getDrawableByCount(int clusterNum); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java deleted file mode 100644 index ac5adae..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/OnClickClusterListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; - -import java.util.List; - -public interface OnClickClusterListener { - /** - * 点击聚合点的回调处理函数 - * - * @param marker 点击的聚合点 - * @param clusterItems 聚合点所包含的元素 - */ - void onClick(Marker marker, List clusterItems); -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java deleted file mode 100644 index dbd9b26..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RegionItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.LatLng; - -public class RegionItem implements ClusterItem { - private final LatLng latLng; - private final String title; - - public RegionItem(LatLng latLng, String title) { - this.latLng = latLng; - this.title = title; - } - - @Override - public LatLng getPosition() { - return latLng; - } - - @Override - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java b/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java deleted file mode 100644 index 89c4945..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/cluster/RemoveAnimationListener.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.casic.common.detector.gd.cluster; - -import com.amap.api.maps.model.Marker; -import com.amap.api.maps.model.animation.Animation; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * marker渐变动画,动画结束后将Marker删除 - */ -public class RemoveAnimationListener implements Animation.AnimationListener { - private final CopyOnWriteArrayList removeMarkers; - - public RemoveAnimationListener(CopyOnWriteArrayList removeMarkers) { - this.removeMarkers = removeMarkers; - } - - @Override - public void onAnimationStart() { - - } - - @Override - public void onAnimationEnd() { - for (Marker marker : removeMarkers) { - marker.remove(); - } - removeMarkers.clear(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt index 97823b8..442189e 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/ByteArray.kt @@ -3,20 +3,6 @@ import android.util.Log /** - * ByteArray转Hex - * */ -fun ByteArray.toHex(): String { - val hexArray = "0123456789ABCDEF".toCharArray() - val hexChars = CharArray(this.size * 2) - for (j in this.indices) { - val v: Int = this[j].toInt() and 0xFF - hexChars[j * 2] = hexArray[v ushr 4] - hexChars[j * 2 + 1] = hexArray[v and 0x0F] - } - return String(hexChars) -} - -/** * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 * * [78, 53, 49, 55, 51] @@ -84,4 +70,38 @@ } } return list.last() +} + +/** + * 因为数据频率很高,而且每一帧数据至少有一个信号值,如果有多个信号强度值,取平均值 + * + * [83, 48, 48, 48, 57] + * + * [83, 48, 48, 48, 57, 83, 48, 48, 48, 57] + * */ +fun ByteArray.toBuryDepth(): Int { + //判断数据合理性 + val validBytes = if (this.size % 5 == 0) { + this + } else { + // 计算最大能取到的5的倍数的数据长度 + val maxMultipleOfFour = (this.size / 5) * 5 + // 获取最大能取到的5的倍数的数据 + this.sliceArray(0 until maxMultipleOfFour) + } + + val list = ArrayList() + for (i in validBytes.indices step 5) { + // 每5个字节取一次数据 + val tempBytes = validBytes.sliceArray(i until minOf(i + 5, validBytes.size)) + // [78, 53, 49, 55, 51] + // 第一个字节是标志位,丢弃,将后面的数据转为十进制 + val dataBytes = tempBytes.sliceArray(1 until tempBytes.size) + var decimalValue = 0 + for (byte in dataBytes) { + decimalValue = decimalValue * 10 + (byte - '0'.code.toByte()) + } + list.add(decimalValue) + } + return list.average().toInt() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt index b1354f2..47853a4 100644 --- a/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt +++ b/app/src/main/java/com/casic/common/detector/gd/extensions/String.kt @@ -117,27 +117,6 @@ return SaveKeyValues.getValue(this, "") as String } -fun String.hexToString(): String { - val sb = StringBuilder() - val temp: StringBuilder = StringBuilder() - run { - var i = 0 - while (i < this.length - 1) { - // 每两个Hex为一组 - val output = this.substring(i, i + 2) - val decimal = output.toInt(16) - sb.append(decimal.toChar()) - temp.append(decimal) - i += 2 - } - } - return sb.toString() -} - -fun String.isNumeric(): Boolean { - return this.matches("-?\\d+".toRegex()) -} - fun String.calculateCheckDigit(): String { var checksum = 0 for (i in 1 until this.length - 3) { diff --git a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt index 3511a01..99dfdc5 100644 --- a/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt +++ b/app/src/main/java/com/casic/common/detector/gd/service/SerialPortService.kt @@ -20,6 +20,7 @@ private val kTag = "SerialPortService" private val gpioManager by lazy { GpioManager() } private val serialPorts = BaseApplication.get().getSerialPorts() + private val sendExecutor = Executors.newFixedThreadPool(5) private var executor = Executors.newScheduledThreadPool(2) private var outStream: OutputStream? = null private var inStreamFirst: InputStream? = null @@ -42,10 +43,19 @@ try { outStream = serialPorts.first().outputStream - commandArray.forEach { - outStream?.write(it.code) - outStream?.flush() - Thread.sleep(500) + // 使用线程池发送数据 + commandArray.forEach { command -> + sendExecutor.submit { + try { + outStream?.write(command.code) + outStream?.flush() + Thread.sleep(1000) + } catch (e: IOException) { + Log.e(kTag, "Error writing to output stream", e) + } catch (e: InterruptedException) { + Log.e(kTag, "Thread interrupted", e) + } + } } inStreamFirst = serialPorts.first().inputStream diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt new file mode 100644 index 0000000..200fac7 --- /dev/null +++ b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelKit.kt @@ -0,0 +1,53 @@ +package com.casic.common.detector.gd.utils + +import com.casic.common.detector.gd.bean.MarkerLocalBean +import jxl.Workbook +import jxl.read.biff.BiffException +import java.io.File + +object ExcelKit { + fun read(filePath: String): ArrayList { + val result = ArrayList() + try { + val workbook = Workbook.getWorkbook(File(filePath)) + val sheet = workbook.getSheet(0) + + for (i in 1 until sheet.rows) { + val marker = MarkerLocalBean() + marker.pipelineType = sheet.getCell(0, i).contents + marker.pipelineDiameter = sheet.getCell(1, i).contents + marker.pipelineMaterial = sheet.getCell(2, i).contents + marker.buryMethod = sheet.getCell(3, i).contents + marker.buryDepth = sheet.getCell(4, i).contents + marker.area = sheet.getCell(5, i).contents + marker.line = sheet.getCell(6, i).contents + marker.road = sheet.getCell(7, i).contents + marker.constructTime = sheet.getCell(8, i).contents + marker.owner = sheet.getCell(9, i).contents + marker.objectId = sheet.getCell(10, i).contents + marker.markerId = sheet.getCell(11, i).contents + marker.markerType = sheet.getCell(12, i).contents + marker.markerDepth = sheet.getCell(13, i).contents + marker.installationDept = sheet.getCell(14, i).contents + marker.lng = sheet.getCell(15, i).contents + marker.lat = sheet.getCell(16, i).contents + marker.updateTime = sheet.getCell(17, i).contents + marker.remark = sheet.getCell(18, i).contents + marker.underlyingPipelineType = sheet.getCell(19, i).contents + marker.underlyingPipelineDepth = sheet.getCell(20, i).contents + marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents + marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents + marker.objectType = sheet.getCell(23, i).contents + marker.color = sheet.getCell(24, i).contents + marker.imagePath = sheet.getCell(25, i).contents + + result.add(marker) + DataBaseManager.get.saveMarkerInLocale(marker) + } + workbook.close() + } catch (e: BiffException) { + e.printStackTrace() + } + return result + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt b/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt deleted file mode 100644 index 3ff55df..0000000 --- a/app/src/main/java/com/casic/common/detector/gd/utils/ExcelTool.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.casic.common.detector.gd.utils - -import com.casic.common.detector.gd.bean.MarkerLocalBean -import jxl.Workbook -import jxl.read.biff.BiffException -import java.io.File - -object ExcelTool { - fun read(filePath: String): ArrayList { - val result = ArrayList() - try { - val workbook = Workbook.getWorkbook(File(filePath)) - val sheet = workbook.getSheet(0) - - for (i in 1 until sheet.rows) { - val marker = MarkerLocalBean() - marker.pipelineType = sheet.getCell(0, i).contents - marker.pipelineDiameter = sheet.getCell(1, i).contents - marker.pipelineMaterial = sheet.getCell(2, i).contents - marker.buryMethod = sheet.getCell(3, i).contents - marker.buryDepth = sheet.getCell(4, i).contents - marker.area = sheet.getCell(5, i).contents - marker.line = sheet.getCell(6, i).contents - marker.road = sheet.getCell(7, i).contents - marker.constructTime = sheet.getCell(8, i).contents - marker.owner = sheet.getCell(9, i).contents - marker.objectId = sheet.getCell(10, i).contents - marker.markerId = sheet.getCell(11, i).contents - marker.markerType = sheet.getCell(12, i).contents - marker.markerDepth = sheet.getCell(13, i).contents - marker.installationDept = sheet.getCell(14, i).contents - marker.lng = sheet.getCell(15, i).contents - marker.lat = sheet.getCell(16, i).contents - marker.updateTime = sheet.getCell(17, i).contents - marker.remark = sheet.getCell(18, i).contents - marker.underlyingPipelineType = sheet.getCell(19, i).contents - marker.underlyingPipelineDepth = sheet.getCell(20, i).contents - marker.underlyingPipelineDiameter = sheet.getCell(21, i).contents - marker.underlyingPipelineMaterial = sheet.getCell(22, i).contents - marker.objectType = sheet.getCell(23, i).contents - marker.color = sheet.getCell(24, i).contents - marker.imagePath = sheet.getCell(25, i).contents - - result.add(marker) - } - workbook.close() - } catch (e: BiffException) { - e.printStackTrace() - } - return result - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt index 03976a6..cb02061 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/InstallMarkerActivity.kt @@ -261,6 +261,7 @@ override fun onDataReceived(buffer: ByteArray) { + if (buffer.isEmpty()) return if ((buffer.first().toInt() and 0xFF).toString(16).uppercase() == "30") { val markerId = buffer.toMarkerId() runOnUiThread { diff --git a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt index 881eb33..b4afad3 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/MainActivity.kt @@ -7,8 +7,6 @@ import android.content.ServiceConnection import android.graphics.BitmapFactory import android.graphics.Color -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.Drawable import android.media.AudioAttributes import android.media.SoundPool import android.os.Bundle @@ -21,10 +19,12 @@ import androidx.lifecycle.lifecycleScope import com.amap.api.location.AMapLocation import com.amap.api.maps.AMap +import com.amap.api.maps.AMap.OnMapLongClickListener import com.amap.api.maps.AMapOptions import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CoordinateConverter import com.amap.api.maps.model.BitmapDescriptorFactory +import com.amap.api.maps.model.CameraPosition import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLngBounds import com.amap.api.maps.model.Marker @@ -37,15 +37,9 @@ import com.casic.common.detector.gd.callback.OnGetAddressListener import com.casic.common.detector.gd.callback.OnGetLocationListener import com.casic.common.detector.gd.callback.OnSerialPortListener -import com.casic.common.detector.gd.cluster.ClusterItem -import com.casic.common.detector.gd.cluster.ClusterOverlay -import com.casic.common.detector.gd.cluster.ClusterRender -import com.casic.common.detector.gd.cluster.OnClickClusterListener -import com.casic.common.detector.gd.cluster.RegionItem import com.casic.common.detector.gd.databinding.ActivityMainBinding import com.casic.common.detector.gd.extensions.appendDownloadUrl import com.casic.common.detector.gd.extensions.createTaskCode -import com.casic.common.detector.gd.extensions.drawCircle import com.casic.common.detector.gd.extensions.initImmersionBar import com.casic.common.detector.gd.extensions.toMarkerId import com.casic.common.detector.gd.extensions.toSignalStrength @@ -54,7 +48,7 @@ import com.casic.common.detector.gd.service.NtripConnectService import com.casic.common.detector.gd.service.SerialPortService import com.casic.common.detector.gd.utils.DataBaseManager -import com.casic.common.detector.gd.utils.ExcelTool +import com.casic.common.detector.gd.utils.ExcelKit import com.casic.common.detector.gd.utils.FileType import com.casic.common.detector.gd.utils.LocaleConstant import com.casic.common.detector.gd.utils.LocationKit @@ -64,7 +58,6 @@ import com.casic.common.detector.gd.widgets.QueryMarkerDialog import com.casic.common.detector.gd.widgets.SamplePopupWindow import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertDrawable import com.pengxh.kt.lite.extensions.createDownloadFileDir import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.isNetworkConnected @@ -85,16 +78,14 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -import java.util.concurrent.CopyOnWriteArrayList -class MainActivity : KotlinBaseActivity(), ClusterRender, - OnClickClusterListener, OnSerialPortListener { +class MainActivity : KotlinBaseActivity(), AMap.OnMarkerClickListener, + OnMapLongClickListener, OnSerialPortListener { private val kTag = "MainActivity" private val context = this private val samplePopupWindow by lazy { SamplePopupWindow(this) } - private val backDrawables by lazy { HashMap() } private val detailDialog by lazy { MarkerDetailDialog(this) } private val locationKit by lazy { LocationKit(this) } private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] } @@ -102,7 +93,6 @@ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build() private var clickTime: Long = 0 - private var markers = ArrayList() private var isFreeTask = false private var freeTaskTitle = "" private var ids = HashSet() @@ -140,16 +130,18 @@ } override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMapConfig(savedInstanceState) + //绑定串口通信服务 Intent(this, SerialPortService::class.java).also { bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) } - Intent(this, NtripConnectService::class.java).also { - startService(it) - } +// Intent(this, NtripConnectService::class.java).also { +// startService(it) +// } soundResourceId = soundPool.load(this, R.raw.ring3, 1) - //地图初始化 - initMapConfig(savedInstanceState) + //右上角菜单 samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES) samplePopupWindow.setBackgroundDrawable(null) @@ -167,16 +159,9 @@ .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir()) .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener { override fun onDownloadEnd(file: File) { - lifecycleScope.launch(Dispatchers.Main) { - withContext(Dispatchers.IO) { - markers = ExcelTool.read(file.absolutePath) - markers.forEach { marker -> - DataBaseManager.get.saveMarkerInLocale(marker) - } - } - LoadingDialog.dismiss() - showLabelsOnMap() - } + lifecycleScope.launch(Dispatchers.IO) { ExcelKit.read(file.absolutePath) } + LoadingDialog.dismiss() + showMarkersOnMap() } override fun onFailure(throwable: Throwable) { @@ -224,12 +209,12 @@ ids.clear() //清空自由巡检添加的Marker aMap.clear() - showLabelsOnMap() + showMarkersOnMap() } taskViewModel.executeTaskResult.observe(this) { "工单任务已完成".show(this) aMap.clear() - showLabelsOnMap() + showMarkersOnMap() } } @@ -313,11 +298,9 @@ override fun onConfirmClick(selectedItem: String, value: String) { //查询数据库 lifecycleScope.launch(Dispatchers.Main) { - markers = withContext(Dispatchers.IO) { - DataBaseManager.get.loadMarkersByCondition( - selectedItem, value - ) as ArrayList - } + val markers = DataBaseManager.get.loadMarkersByCondition( + selectedItem, value + ) as ArrayList if (markers.isEmpty()) { "无法查到相关数据信息,请检查您的查询条件".show(context) @@ -344,8 +327,6 @@ //移动到指定经纬度 aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(center, 16f)) } - - showLabelsOnMap() } } } @@ -509,6 +490,7 @@ } override fun onDataReceived(buffer: ByteArray) { + if (buffer.isEmpty()) return //只响一次,因为探测频率高,所以依旧是连续的报警声 soundPool.play(soundResourceId, 1f, 1f, 0, 0, 1f) when ((buffer.first().toInt() and 0xFF).toString(16).uppercase()) { @@ -567,14 +549,18 @@ private fun initMapConfig(savedInstanceState: Bundle?) { binding.mapView.onCreate(savedInstanceState) aMap = binding.mapView.map - + aMap.mapType = AMap.MAP_TYPE_NORMAL val uiSettings = aMap.uiSettings uiSettings.isCompassEnabled = true - uiSettings.isMyLocationButtonEnabled = false//不显示默认定位按钮 - uiSettings.isScaleControlsEnabled = true uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度 - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜 + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + //地图长按事件 + aMap.setOnMapLongClickListener(this) + //显示定位小蓝点 val locationStyle = MyLocationStyle() locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0)) @@ -594,15 +580,8 @@ //首次移动到定位点 moveToCurrentLocation() - aMap.setOnMapLongClickListener { - //协程异步显示默认数据 - lifecycleScope.launch(Dispatchers.Main) { - markers = withContext(Dispatchers.IO) { - DataBaseManager.get.loadMarkers() as ArrayList - } - showLabelsOnMap() - } - } + //渲染标识器位置 + showMarkersOnMap() //自定义定位按钮 binding.aimButton.setOnClickListener { moveToCurrentLocation() } @@ -638,97 +617,44 @@ "工单下载成功!".show(this) } - private var clusterOverlay: ClusterOverlay? = null + private fun showMarkersOnMap() { + lifecycleScope.launch(Dispatchers.IO) { + //取缓存 + val markers = DataBaseManager.get.loadMarkers() + if (markers.isEmpty()) { + return@launch + } + val first = markers.first() + val defaultLatLng = LatLng(first.lat.toDouble(), first.lng.toDouble()) + //移动到指定经纬度 + val cameraPosition = CameraPosition(defaultLatLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + withContext(Dispatchers.Main) { + aMap.animateCamera(cameraUpdate, 1500, null) + LoadingDialog.dismiss() + } - private fun showLabelsOnMap() { - val clusterItems = CopyOnWriteArrayList() - if (clusterOverlay == null) { - clusterOverlay = ClusterOverlay( - this, aMap, clusterItems, LocaleConstant.RADIUS_SIZE.dp2px(this) - ) - } - clusterOverlay?.apply { - setClusterRender(this@MainActivity) - setOnClickClusterListener(this@MainActivity) - } - markers.forEach { - if (it.lat.isNotEmpty() && it.lng.isNotEmpty()) { - val latitude = it.lat.toDouble() - val longitude = it.lng.toDouble() - - val latLng = LatLng(latitude, longitude, false) - //用标识器的ID当作地图Marker的Title - val regionItem = RegionItem(latLng, it.markerId.toString()) - clusterItems.add(regionItem) + markers.forEach { marker -> + val latitude = marker.lat.toString().toDouble() + val longitude = marker.lng.toString().toDouble() + //将所有设备信息转化缓存为Marker点 + val options = MarkerOptions() + .position(LatLng(latitude, longitude)) + .title(marker.markerId) + aMap.addMarker(options) } } } - override fun getDrawableByCount(clusterNum: Int): Drawable { - //聚合点圆形半径 - val radius = 80.dp2px(this) - if (clusterNum == 1) { - var bitmapDrawable = backDrawables[1] - if (bitmapDrawable == null) { - bitmapDrawable = R.mipmap.label.convertDrawable(this)!! - backDrawables[1] = bitmapDrawable - } - return bitmapDrawable - } else if (clusterNum < 5) { - var bitmapDrawable = backDrawables[2] - if (bitmapDrawable == null) { - bitmapDrawable = BitmapDrawable( - null, radius.drawCircle(Color.argb(159, 100, 149, 237)) - ) - backDrawables[2] = bitmapDrawable - } - return bitmapDrawable - } else if (clusterNum < 10) { - var bitmapDrawable = backDrawables[3] - if (bitmapDrawable == null) { - bitmapDrawable = BitmapDrawable( - null, radius.drawCircle(Color.argb(199, 30, 144, 255)) - ) - backDrawables[3] = bitmapDrawable - } - return bitmapDrawable - } else { - var bitmapDrawable = backDrawables[4] - if (bitmapDrawable == null) { - bitmapDrawable = BitmapDrawable( - null, radius.drawCircle(Color.argb(235, 65, 105, 225)) - ) - backDrawables[4] = bitmapDrawable - } - return bitmapDrawable + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + showNavigationOption(title, position) } + return true } - override fun onClick(marker: Marker, clusterItems: MutableList) { - if (clusterItems.size == 1) { - val clusterItem = clusterItems[0] - showNavigationOption(clusterItem.title, clusterItem.position) - } else { - //聚合点,显示聚合点列表 - val idArray = ArrayList() - for (clusterItem in clusterItems) { - idArray.add(clusterItem.title) - } - BottomActionSheet.Builder() - .setContext(this) - .setItemTextColor(Color.BLUE) - .setActionItemTitle(idArray) - .setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener { - override fun onActionItemClick(position: Int) { - val markerId = idArray[position] - //根据markerId找到标识器 - val bean = markers.find { x -> x.markerId == markerId }!! - showNavigationOption( - bean.markerId, LatLng(bean.lat.toDouble(), bean.lng.toDouble()) - ) - } - }).build().show() - } + override fun onMapLongClick(p0: LatLng?) { + showMarkersOnMap() } private fun showNavigationOption(title: String, latLng: LatLng) { @@ -778,7 +704,6 @@ } aMap.addMarker(markerOptions) } - showLabelsOnMap() } //更新标识器数据 @@ -891,13 +816,6 @@ override fun onResume() { super.onResume() binding.mapView.onResume() - //协程异步显示默认数据 - lifecycleScope.launch(Dispatchers.Main) { - markers = withContext(Dispatchers.IO) { - DataBaseManager.get.loadMarkers() as ArrayList - } - showLabelsOnMap() - } } override fun onPause() { @@ -912,7 +830,6 @@ override fun onDestroy() { super.onDestroy() - clusterOverlay?.onDestroy() binding.mapView.onDestroy() soundPool.autoPause() locationKit.stopLocation() diff --git a/app/src/main/java/com/casic/common/detector/gd/view/SearchMarkerActivity.kt b/app/src/main/java/com/casic/common/detector/gd/view/SearchMarkerActivity.kt index 1186df0..7fc6532 100644 --- a/app/src/main/java/com/casic/common/detector/gd/view/SearchMarkerActivity.kt +++ b/app/src/main/java/com/casic/common/detector/gd/view/SearchMarkerActivity.kt @@ -26,8 +26,7 @@ import com.casic.common.detector.gd.callback.OnGetLocationListener import com.casic.common.detector.gd.callback.OnSerialPortListener import com.casic.common.detector.gd.databinding.ActivitySearchMarkerBinding -import com.casic.common.detector.gd.extensions.hexToString -import com.casic.common.detector.gd.extensions.toHex +import com.casic.common.detector.gd.extensions.toBuryDepth import com.casic.common.detector.gd.extensions.toMarkerId import com.casic.common.detector.gd.extensions.toSignalStrength import com.casic.common.detector.gd.model.MarkerDistanceData @@ -69,8 +68,7 @@ private val valueArray = FloatArray(3)//方位角数值 private var slowSoundResourceId = 0 private var fastSoundResourceId = 0 - private var markerId = ""//实际探测出来的标识器ID - private var nearestMarkerId = ""//探测不到标识器的时候计算出来的最近的标识器ID + private var markerId = ""//标识器ID private var isExecuteTask = false private var signalEnergy = 0 //标识器信号强度 private var gravity: FloatArray? = null @@ -167,9 +165,8 @@ temp.addAll(markerPoints) temp.sortBy(MarkerDistanceData::distance) val nearestPoint = temp.first() - nearestMarkerId = nearestPoint.markerId runOnUiThread { - handleMarker(nearestMarkerId) + handleMarker(nearestPoint.markerId) } markerPoints.clear() } catch (e: NullPointerException) { @@ -193,7 +190,7 @@ override fun onFinish() { LoadingDialog.dismiss() - serialPortService?.closeSerialPort() +// serialPortService?.closeSerialPort() "标识器深度探测超时,请移动位置重试".show(context) lifecycleScope.launch(Dispatchers.Main) { delay(300) @@ -204,7 +201,8 @@ override fun initEvent() { binding.depthButton.setOnClickListener { - stopSearchMarker() + soundPool.autoPause() +// serialPortService?.closeSerialPort() val result = DataBaseManager.get.queryMarkerById(markerId) if (result.isNotEmpty()) { val tag = when (result.first().markerType) { @@ -226,13 +224,11 @@ serialPortService?.openSerialPort( arrayListOf(tag), object : OnSerialPortListener { override fun onDataReceived(buffer: ByteArray) { - val hex = buffer.toHex() - if (hex.startsWith("53")) { - runOnUiThread { - LoadingDialog.dismiss() - countDownTimer.cancel() - showDepthDialog(hex) - } + if (buffer.isEmpty()) return + val tag = (buffer.first().toInt() and 0xFF).toString(16).uppercase() + if (tag == "53") { +// serialPortService?.closeSerialPort() + showDepthDialog(buffer.toBuryDepth()) } } }) @@ -248,46 +244,41 @@ } binding.markerInfoButton.setOnClickListener { - val id = if (markerId == "") { - nearestMarkerId - } else { - markerId - } //查库 - val result = DataBaseManager.get.queryMarkerById(id) + val result = DataBaseManager.get.queryMarkerById(markerId) if (result.isNotEmpty()) { - navigatePageTo(id) + navigatePageTo(markerId) } else { - navigatePageTo(id) + navigatePageTo(markerId) } //查看完就把ID置空,便于下次查看最新的ID markerId = "" } } - private fun showDepthDialog(hex: String) { - try { - val depthResponse = hex.take(10).hexToString() - Log.d(kTag, "showDepthDialog: $depthResponse") - val depth = depthResponse.drop(2).toInt() - AlertMessageDialog.Builder().setContext(context) - .setTitle("温馨提示") - .setMessage("标识器埋深:${depth}厘米") - .setPositiveButton("知道了") - .setOnDialogButtonClickListener(object : - AlertMessageDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - serialPortService?.closeSerialPort() - lifecycleScope.launch(Dispatchers.Main) { - delay(300) - searchMarker() + private fun showDepthDialog(depth: Int) { + countDownTimer.cancel() + runOnUiThread { + LoadingDialog.dismiss() + try { + AlertMessageDialog.Builder().setContext(context) + .setTitle("温馨提示") + .setMessage("标识器埋深:${depth}厘米") + .setPositiveButton("知道了") + .setOnDialogButtonClickListener(object : + AlertMessageDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + lifecycleScope.launch(Dispatchers.Main) { + delay(300) + searchMarker() + } } - } - }).build().show() - } catch (e: WindowManager.BadTokenException) { - e.printStackTrace() - } catch (e: NumberFormatException) { - e.printStackTrace() + }).build().show() + } catch (e: WindowManager.BadTokenException) { + e.printStackTrace() + } catch (e: NumberFormatException) { + e.printStackTrace() + } } } @@ -316,8 +307,7 @@ } "30" -> { - markerId = buffer.toMarkerId() - handleMarker(markerId) + handleMarker(buffer.toMarkerId()) } else -> { @@ -390,13 +380,6 @@ binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_disable) } - private fun stopSearchMarker() { - soundPool.autoPause() - serialPortService?.closeSerialPort() - - Thread.sleep(100) - } - /** * 计算并渲染数据点。点太多采用协程计算,不然会有点卡顿。默认2s计算一次 * @param location 定位点(RTK获取) @@ -460,6 +443,8 @@ } private fun handleMarker(id: String) { + this.markerId = id + binding.depthButton.isEnabled = true binding.depthButton.setTextColor(Color.WHITE) binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable) @@ -529,7 +514,8 @@ override fun onDestroy() { super.onDestroy() - stopSearchMarker() + soundPool.autoPause() + serialPortService?.closeSerialPort() locationKit.stopLocation() unbindService(serviceConnection) }