Commit c6411612 authored by p x's avatar p x
Browse files

在线小车

parent b484b0d0
...@@ -12,6 +12,14 @@ ...@@ -12,6 +12,14 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.MapMultiEngine" android:theme="@style/Theme.MapMultiEngine"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name=".ui.ShowCarOnlineActivity"
android:exported="false" />
<activity
android:name=".ui.AMapWmsActivity"
android:exported="false" />
<activity <activity
android:name=".ui.CalculateDistanceActivity" android:name=".ui.CalculateDistanceActivity"
android:exported="false" /> android:exported="false" />
...@@ -52,8 +60,6 @@ ...@@ -52,8 +60,6 @@
android:name=".ui.ShowMyLocLandian" android:name=".ui.ShowMyLocLandian"
android:exported="false" android:exported="false"
android:theme="@style/Theme.MapMultiEngine" /> android:theme="@style/Theme.MapMultiEngine" />
<activity <activity
android:name=".ui.TBaseActivity" android:name=".ui.TBaseActivity"
android:exported="false" /> android:exported="false" />
......
package com.sd.mapmultiengine;
import android.content.Context;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.model.TileOverlay;
import com.amap.api.maps.model.TileOverlayOptions;
import com.amap.api.maps.model.TileProvider;
import com.amap.api.maps.model.UrlTileProvider;
import com.amap.api.maps.model.LatLng;
import java.net.MalformedURLException;
import java.net.URL;
/**
* 图层管理
*
* @author Hu
* @date 2024/5/23
*/
public class LayerManage {
private static final String TAG = "LayerManage";
private Context mContext;
private AMap aMap;
private int titleSize = 256;
private double initialResolution = 156543.03392804062;//2*Math.PI*6378137/titleSize;//
private double originShift = 20037508.342789244;//2*Math.PI*6378137/2.0;//
private TileOverlay tileOverlay;
/**
* 构造函数
*/
public LayerManage(Context context, AMap aMap) {
mContext = context.getApplicationContext();
this.aMap = aMap;
}
/**
* 设置地图模式,aMap是地图控制器对象
*
* @param type 地图模式
* MAP_TYPE_NORMAL:普通地图,值为1;
* MAP_TYPE_SATELLITE:卫星地图,值为2;
* MAP_TYPE_NIGHT 黑夜地图,夜间模式,值为3;
* MAP_TYPE_NAVI 导航模式,值为4;
* MAP_TYPE_BUS 公交模式,值为5。
*/
public void setMapType(int type) {
aMap.setMapType(type);
}
/**
* 添加图层
*
* @param url 构建WMS图层URL
*/
public TileOverlay addTileOverlay(String url) {
// 实例化自定义TileProvider
TileProvider tileProvider = new UrlTileProvider(256, 256) {
@Override
public URL getTileUrl(int x, int y, int zoom) {
// 构建WMS图层URL
try {
System.out.println(x + "/" + y + "/" + zoom + "=====>" + url + TitleBounds(x, y, zoom));
return new URL(url + TitleBounds(x, y, zoom));
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
};
TileOverlayOptions tileOverlayOptions = new TileOverlayOptions().tileProvider(tileProvider);
// 添加TileOverlay
tileOverlay = aMap.addTileOverlay(tileOverlayOptions);
LatLng latLng = new LatLng(39.80870258484975, 116.5011886304098);
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18.0f));
return tileOverlay;
}
/**
* 移除图层
*/
public void removeLayer() {
tileOverlay.remove();
}
/**
* 设置图层可见性
*
* @param visibility - true: 表示显示,为默认值; false: 不显示
*/
public void setLayerVisibility(boolean visibility) {
if (tileOverlay != null) {
tileOverlay.setVisible(visibility);
}
}
/**
* 根据像素、等级算出坐标
*
* @param p
* @param zoom
* @return
*/
private double Pixels2Meters(int p, int zoom) {
return p * Resolution(zoom) - originShift;
}
/**
* 根据瓦片的x/y等级返回瓦片范围
*
* @param tx
* @param ty
* @param zoom
* @return
*/
private String TitleBounds(int tx, int ty, int zoom) {
double minX = Pixels2Meters(tx * titleSize, zoom);
double maxY = -Pixels2Meters(ty * titleSize, zoom);
double maxX = Pixels2Meters((tx + 1) * titleSize, zoom);
double minY = -Pixels2Meters((ty + 1) * titleSize, zoom);
//转换成经纬度
// minX = Meters2Lon(minX);
// minY = Meters2Lat(minY);
// maxX = Meters2Lon(maxX);
// maxY = Meters2Lat(maxY);
//经纬度转换米
// minX = Lon2Meter(minX);
// minY = Lat2Meter(minY);
// maxX = Lon2Meter(maxX);
// maxY = Lat2Meter(maxY);
//坐标转换工具类构造方法 GPS( WGS-84) 转 为高德地图需要的坐标
// CoordinateConverter converter = new CoordinateConverter(context);
// converter.from(CoordinateConverter.CoordType.GPS);
// converter.coord(new LatLng(minY, minX));
// LatLng min = converter.convert();
// converter.coord(new LatLng(maxY, maxX));
// LatLng max = converter.convert();
// minX = Lon2Meter(-min.longitude + 2 * minX);
// minY = Lat2Meter(-min.latitude + 2 * minY);
// maxX = Lon2Meter(-max.longitude + 2 * maxX);
// maxY = Lat2Meter(-max.latitude + 2 * maxY);
return minX + "," + minY + "," + maxX + "," + maxY + "&WIDTH=256&HEIGHT=256";
}
/**
* 计算分辨率
*
* @param zoom
* @return
*/
private double Resolution(int zoom) {
return initialResolution / (Math.pow(2, zoom));
}
/**
* X米转经纬度
*/
private double Meters2Lon(double mx) {
double lon = (mx / originShift) * 180.0;
return lon;
}
/**
* Y米转经纬度
*/
private double Meters2Lat(double my) {
double lat = (my / originShift) * 180.0;
lat = 180.0 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180.0)) - Math.PI / 2.0);
return lat;
}
/**
* X经纬度转米
*/
private double Lon2Meter(double lon) {
double mx = lon * originShift / 180.0;
return mx;
}
/**
* Y经纬度转米
*/
private double Lat2Meter(double lat) {
double my = Math.log(Math.tan((90 + lat) * Math.PI / 360.0)) / (Math.PI / 180.0
);
my = my * originShift / 180.0;
return my;
}
}
...@@ -14,10 +14,12 @@ import com.sd.maplibrary.MSDKInitializer ...@@ -14,10 +14,12 @@ import com.sd.maplibrary.MSDKInitializer
import com.sd.maplibrary.OnSdkInitCb import com.sd.maplibrary.OnSdkInitCb
import com.sd.mapmultiengine.adapter.DemoListAdapter import com.sd.mapmultiengine.adapter.DemoListAdapter
import com.sd.mapmultiengine.databinding.ActivityMainBinding import com.sd.mapmultiengine.databinding.ActivityMainBinding
import com.sd.mapmultiengine.ui.AMapWmsActivity
import com.sd.mapmultiengine.ui.CalculateDistanceActivity import com.sd.mapmultiengine.ui.CalculateDistanceActivity
import com.sd.mapmultiengine.ui.ChangeMapCenterAct import com.sd.mapmultiengine.ui.ChangeMapCenterAct
import com.sd.mapmultiengine.ui.DisplayMapActivity import com.sd.mapmultiengine.ui.DisplayMapActivity
import com.sd.mapmultiengine.ui.GestureDemo import com.sd.mapmultiengine.ui.GestureDemo
import com.sd.mapmultiengine.ui.ShowCarOnlineActivity
import com.sd.mapmultiengine.ui.ShowMyLocLandian import com.sd.mapmultiengine.ui.ShowMyLocLandian
import com.sd.mapmultiengine.ui.TCircelActivity import com.sd.mapmultiengine.ui.TCircelActivity
import com.sd.mapmultiengine.ui.TDriveRouteActivity import com.sd.mapmultiengine.ui.TDriveRouteActivity
...@@ -57,8 +59,14 @@ class MainActivity : AppCompatActivity() { ...@@ -57,8 +59,14 @@ class MainActivity : AppCompatActivity() {
DemoDetails("两点间距离计算", CalculateDistanceActivity::class.java), DemoDetails("两点间距离计算", CalculateDistanceActivity::class.java),
DemoDetails("定位,获取我的位置", TGpsActivity::class.java), DemoDetails("定位,获取我的位置", TGpsActivity::class.java),
DemoDetails("在线地图显示小车", ShowCarOnlineActivity::class.java),
DemoDetails("驾车路线规划", TDriveRouteActivity::class.java), DemoDetails("驾车路线规划", TDriveRouteActivity::class.java),
DemoDetails("测试高德加载WMS", AMapWmsActivity::class.java),
) )
...@@ -108,7 +116,7 @@ class MainActivity : AppCompatActivity() { ...@@ -108,7 +116,7 @@ class MainActivity : AppCompatActivity() {
} }
fun initMap(type: MAP_TYPE = MAP_TYPE.AMAP) { fun initMap(type: MAP_TYPE = MAP_TYPE.MINE) {
MSDKInitializer.initializeMap(this, type, object : OnSdkInitCb { MSDKInitializer.initializeMap(this, type, object : OnSdkInitCb {
override fun onInitSuccess() { override fun onInitSuccess() {
println("--------onMapInitSuccess") println("--------onMapInitSuccess")
......
package com.sd.mapmultiengine.ui
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.amap.api.maps.AMap
import com.sd.mapmultiengine.LayerManage
import com.sd.mapmultiengine.R
import com.sd.mapmultiengine.databinding.ActivityAmapWmsBinding
class AMapWmsActivity : AppCompatActivity() {
lateinit var binding: ActivityAmapWmsBinding
private var layerManage: LayerManage? = null
private var aMap: AMap? = null
// var url =
// "https://faw.cuscavp.cn:8443/geoserver/changchun/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=true"
var url: String =
"http://10.166.15.10:8080/geoserver/cusc/wms?LAYERS=cusc%3AHMI_GJDT&FORMAT=image%2Fpng&TRANSPARENT=TRUE&SERVICE=" +
"WMS&VERSION=1.1.0&REQUEST=GetMap&STYLES=&SRS=EPSG:3857&BBOX="
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityAmapWmsBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.mapView.onCreate(savedInstanceState)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
aMap = binding.mapView.map
layerManage = LayerManage(this, aMap)
layerManage?.addTileOverlay(url)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
//在activity执行onSaveInstanceState时执行mapView.onSaveInstanceState (outState),保存地图当前的状态
binding.mapView.onSaveInstanceState(outState)
}
override fun onResume() {
super.onResume()
//在activity执行onResume时执行mapView.onResume (),重新绘制加载地图
binding.mapView.onResume()
}
override fun onPause() {
super.onPause()
//在activity执行onPause时执行mapView.onPause (),暂停地图的绘制
binding.mapView.onPause()
}
override fun onDestroy() {
super.onDestroy()
//在activity执行onDestroy时执行mapView.onDestroy(),销毁地图
binding.mapView.onDestroy()
}
}
\ No newline at end of file
package com.sd.mapmultiengine.ui
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.minedata.minenavi.mapdal.LatLng
import com.minedata.minenavi.util.Tools
import com.sd.maplibrary.bean.MSLatLng
import com.sd.maplibrary.bean.MSLocBean
import com.sd.maplibrary.core.MSGpsLocation
import com.sd.maplibrary.core.MSMethodAdv
import com.sd.maplibrary.core.MShowMainCarModel
import com.sd.maplibrary.core.MapReadyView
import com.sd.maplibrary.ui.MapMultiView.OnMapReadyLis
import com.sd.mapmultiengine.R
import com.sd.mapmultiengine.databinding.ActivityShowCarOnlineBinding
import com.sd.mapmultiengine.databinding.ActivityTgpsBinding
import com.sd.mapmultiengine.ui.TGpsActivity
/***在线地推显示小车***/
class ShowCarOnlineActivity : AppCompatActivity() {
private lateinit var binding: ActivityShowCarOnlineBinding
var mapReadView: MapReadyView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityShowCarOnlineBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.mapMultiView.addMapRenderCallback(object : OnMapReadyLis {
override fun onMapReady(mapReadyView: MapReadyView) {
this@ShowCarOnlineActivity.mapReadView = mapReadyView
//添加小车
var center = MSLatLng(39.787678,116.518766)
MSMethodAdv.setMapCenter(mapReadView,center.lat, center.lng)
MShowMainCarModel.addMyLocCarModel(mapReadView,this@ShowCarOnlineActivity,center.lat, center.lng, 0f)
}
})
//显示小车
binding.bt1.setOnClickListener {
}
//隐藏小车
binding.bt2.setOnClickListener {
}
//初始化定位
MSGpsLocation.initLoc(this)
//设置回调
MSGpsLocation.setOnMsGpsLoc(object : MSGpsLocation.OnMsGpsLoc {
override fun onMsGpsLoc(mSLocBean: MSLocBean) {
}
})
//开启定位
MSGpsLocation.starLoc()
}
}
\ No newline at end of file
...@@ -39,7 +39,7 @@ class TGpsActivity : AppCompatActivity() { ...@@ -39,7 +39,7 @@ class TGpsActivity : AppCompatActivity() {
} }
}) })
//初始化 //初始化定位
MSGpsLocation.initLoc(this) MSGpsLocation.initLoc(this)
//设置回调 //设置回调
MSGpsLocation.setOnMsGpsLoc(object : MSGpsLocation.OnMsGpsLoc { MSGpsLocation.setOnMsGpsLoc(object : MSGpsLocation.OnMsGpsLoc {
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.AMapWmsActivity">
<com.amap.api.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/bt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示小车" />
<Button
android:id="@+id/bt2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删掉小车" />
<com.sd.maplibrary.ui.MapMultiView
android:id="@+id/mapMultiView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
\ No newline at end of file
# exported by gszh.xyz
newmtl 99ce393e_fd5e_44cc_9c31_49c4bb9ceed6
Kd 1.0431372549019609 1.0431372549019609 1.0431372549019609
d 1
Ka 0 0 0
Ks 0 0 0
Ns 0
map_Kd Binary_0.jpeg
This diff is collapsed.
package com.sd.maplibrary.core package com.sd.maplibrary.core
import android.graphics.Rect
import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.model.CameraPosition import com.amap.api.maps.model.CameraPosition
import com.minedata.minenavi.mapdal.LatLng import com.minedata.minenavi.mapdal.LatLng
...@@ -54,6 +53,20 @@ object MSMethodAdv { ...@@ -54,6 +53,20 @@ object MSMethodAdv {
} }
} }
/***获取地图缩放级别**/
fun getMapZoom(mapReadView: MapReadyView?): Float {
when (MSDKInitializer.getMapType()) {
MAP_TYPE.MINE -> {
return mapReadView?.mMineMap?.zoomLevel?:0f
}
MAP_TYPE.AMAP -> {
return mapReadView?.aMap?.cameraPosition?.zoom?:0f
}
}
}
/***设置地图显示区域**/ /***设置地图显示区域**/
// fun setMapBoundArea(mapReadView: MapReadyView?) { // fun setMapBoundArea(mapReadView: MapReadyView?) {
......
...@@ -101,7 +101,7 @@ object MSRoutePlans { ...@@ -101,7 +101,7 @@ object MSRoutePlans {
} }
} }
/***驾车路径规划 /***驾车路径规划,直接跳转到 导航页面
*@param starPoint 起点坐标 *@param starPoint 起点坐标
* @param endPoint 终点坐标 * @param endPoint 终点坐标
* @param endName 终点名称(高德可不传) * @param endName 终点名称(高德可不传)
......
package com.sd.maplibrary.core
import android.content.Context
import android.util.Log
import androidx.lifecycle.viewModelScope
import com.amap.api.maps.AMapUtils
import com.amap.api.maps.model.LatLng as ALatLng
import com.minedata.minenavi.map.Model
import com.minedata.minenavi.map.ModelOptions
import com.minedata.minenavi.map.Overlay
import com.minedata.minenavi.mapdal.LatLng
import com.sd.maplibrary.MAP_TYPE
import com.sd.maplibrary.MSDKInitializer
import com.sd.shupathwebview.utils.FileIoUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.IOException
/***在线地图上绘制小车**/
object MShowMainCarModel {
//四维主车obj模型
private var objPath = ""
//四维在线地图用户当前位置模型
private var mainCarMo: Model? = null
/****加载主车特斯拉模型***/
private suspend fun loadMainCar(context: Context) {
withContext(Dispatchers.IO) {
try {
var parentFileDir = File(context.filesDir, "models/car_model")
if (!parentFileDir.exists())
parentFileDir.mkdirs()
objPath =
FileIoUtils.assetFilePath(context, "models/car_model/gszh_xyz.obj")
Log.d("-----", "✅ OBJ文件复制成功: " + objPath)
var path =
FileIoUtils.assetFilePath(context, "models/car_model/Binary_0.jpeg")
Log.d("-----", "✅ 纹理文件复制成功: " + path)
path =
FileIoUtils.assetFilePath(context, "models/car_model/gszh_xyz.mtl")
Log.d("-----", "✅ 材质文件复制成功: " + path)
} catch (e: IOException) {
e.printStackTrace()
}
}
}
/****添加我的定位小车模型
* 这小车模型航向角0是冲下的
* ***/
fun addMyLocCarModel(
mapReadView: MapReadyView?,
context: Context,
lat: Double,
lng: Double,
heading: Float
) {
// mMineMap?.removeOverlay(mainCarMo)
// deleteMyLocMarker()
when (MSDKInitializer.getMapType()) {
MAP_TYPE.MINE -> {
CoroutineScope(Dispatchers.IO).launch {
loadMainCar(context)
if (objPath.isEmpty() || lat == 0.0)
return@launch
// 模型文件相对路径
var modelOptions = ModelOptions()
.objFile(objPath)
.position(LatLng(lat, lng))
.layer(Overlay.Layer.aboveMarker)
.heading(heading)
.keepScaleSize(8f) // 保持尺寸的比例尺
.scaleFactor(0.01f) // 缩放因子
.visible(true)
if (mainCarMo != null) {
mapReadView?.mMineMap?.removeOverlay(mainCarMo)
}
mainCarMo = mapReadView?.mMineMap?.addModel(modelOptions)
}
}
MAP_TYPE.AMAP -> {
}
}
}
/****更新模型**/
fun upMyLocCarModel(
lat: Double,
lng: Double,
heading: Float
) {
when (MSDKInitializer.getMapType()) {
MAP_TYPE.MINE -> {
if (mainCarMo == null)
return
var temp = 0f - 180f - heading
mainCarMo?.setPosition(LatLng(lat, lng))
mainCarMo?.setHeading(temp)
}
MAP_TYPE.AMAP -> {
}
}
}
/****更新模型**/
fun upMyLocCarModelSmooth(
lat: Double,
lng: Double,
heading: Float
) {
when (MSDKInitializer.getMapType()) {
MAP_TYPE.MINE -> {
}
MAP_TYPE.AMAP -> {
}
}
}
}
\ No newline at end of file
package com.sd.shupathwebview.utils
import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.*
import java.math.BigDecimal
object FileIoUtils {
/**
* 读取asset 文件
*/
fun getAssetContent(context: Context, fileName: String): String {
val assetManager = context.assets
var stringBuilder = StringBuilder()
var bf: BufferedReader? = null
try {
val inputReader = InputStreamReader(assetManager.open(fileName))
bf = BufferedReader(inputReader)
var line = ""
while (!bf.run {
line = readLine()
return@run line
}.isNullOrEmpty()) {
stringBuilder.append(line)
}
bf?.close()
assetManager.close()
return stringBuilder.toString()
} catch (e: IOException) {
e.printStackTrace()
return ""
} finally {
bf?.close()
assetManager.close()
}
}
/**
* 复制assets 到手机内存里
* @param prePath 为路径前缀
* @param assetName 为文件名
* **/
suspend fun assetFilePath(context: Context, assetName: String): String {
return withContext(Dispatchers.IO) {
val file = File(context.filesDir, assetName)
if (file.exists() && file.length() > 0) {
return@withContext file.absolutePath
}
try {
var inputs = context.assets.open(assetName)
var os: OutputStream = FileOutputStream(file)
val buffer = ByteArray(4 * 1024)
var read: Int
while ((inputs.read(buffer).also { read = it }) != -1) {
os.write(buffer, 0, read)
}
os.flush()
return@withContext file.absolutePath
} catch (e: IOException) {
e.printStackTrace()
return@withContext ""
}
}
}
suspend fun getAssetMock(context: Context, fileName: String, dst: MutableList<String>) :Int{
val assetManager = context.assets
var bf: BufferedReader? = null
try {
val inputReader = InputStreamReader(assetManager.open(fileName))
bf = BufferedReader(inputReader)
var line = ""
while (!bf.run {
line = readLine()
return@run line
}.isNullOrEmpty()) {
dst.add(line)
}
bf?.close()
return 1
} catch (e: IOException) {
e.printStackTrace()
} finally {
bf?.close()
}
return 0
}
/**
* 读取asset 文件
*/
fun getAsset(context: Context, fileName: String): String {
val assetManager = context.assets
var inputStream: InputStream? = null
var str = ""
try {
inputStream = assetManager.open(fileName)
val size = inputStream.available()
val bytes = ByteArray(size)
inputStream.read(bytes)
str = String(bytes)
} catch (e: IOException) {
e.printStackTrace()
} finally {
inputStream?.close()
// assetManager.close()
}
return str
}
//Uri获取真实路径转换成File的方法
fun getAbsoluteImagePath(contentUri: Uri, context: Context): String { // can post image
var res = ""
val proj = arrayOf(MediaStore.Images.Media.DATA)
val cursor = context.contentResolver.query(contentUri, proj, null, null, null)
if (cursor!!.moveToFirst()) {
val column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
res = cursor.getString(column_index)
}
cursor.close()
return res
}
/**
* 把图片复制到应用缓存里
*/
fun copyHeImgFileToPath(
context: Context,
fileName: String,
source: File,
isRemove: Boolean = true
): File? {
try {
var dir = File(context.externalCacheDir, "xunhepic")
if (!dir.exists()) {
dir.mkdirs()
}
var imgFile = File(dir, fileName)
if (!dir.exists()) {
imgFile.createNewFile()
}
var fosfrom = FileInputStream(source)
var fosto = FileOutputStream(imgFile)
var bt = ByteArray(1024)
var c = 0
while (fosfrom.run {
c = read(bt)
return@run c
} > 0) {
fosto.write(bt, 0, c) //将内容写到新文件当
}
if (isRemove) {
// source.deleteOnExit()
}
fosfrom.close()
fosto.close()
return imgFile
} catch (e: IOException) {
return null
}
}
//file文件读取成byte[]
fun readFileToByte(file: File?): ByteArray? {
val byte_size = 1024
val b = ByteArray(byte_size)
try {
val fileInputStream = FileInputStream(file)
val outputStream = ByteArrayOutputStream(
byte_size
)
var length: Int
while (fileInputStream.read(b).also { length = it } != -1) {
outputStream.write(b, 0, length)
}
fileInputStream.close()
outputStream.close()
return outputStream.toByteArray()
} catch (e: IOException) {
e.printStackTrace()
}
return null
}
/**
* 获取总共的缓存
*/
fun getTotalCacheSize(context: Context): Long {
var size: Long = 0
return try {
size = getFolderSize(context.cacheDir)
size += getFolderSize(context.filesDir)
// size += getFolderSize(context.externalCacheDir)
size
} catch (e: Exception) {
e.printStackTrace()
0
}
}
/**
* 获取文件夹大小
*/
private fun getFolderSize(file: File?): Long {
if (file == null) {
return 0
}
var size: Long = 0
try {
val fileList = file!!.listFiles()
for (i in fileList.indices) {
// 如果下面还有文件
size = if (fileList[i].isDirectory) {
size + getFolderSize(fileList[i])
} else {
size + fileList[i].length()
}
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return size
}
/**
* 删除总共的缓存
*/
fun deleteTotalCacheSize(context: Context) {
runBlocking {
coroutineScope {
withContext(Dispatchers.IO) {
context.cacheDir.deleteRecursively()
context.filesDir.deleteRecursively()
// if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// context.externalCacheDir?.deleteRecursively()
// }
}
}
}
}
/**
* 格式化单位
*/
fun getFormatSize(size: Double): String? {
val kiloByte = size / 1024
if (kiloByte < 1) {
return size.toString() + "Byte"
}
val megaByte = kiloByte / 1024
if (megaByte < 1) {
val result1 = BigDecimal(kiloByte.toString())
return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
.toPlainString().toString() + "KB"
}
val gigaByte = megaByte / 1024
if (gigaByte < 1) {
val result2 = BigDecimal(megaByte.toString())
return result2.setScale(1, BigDecimal.ROUND_HALF_UP)
.toPlainString().toString() + "MB"
}
val teraBytes = gigaByte / 1024
if (teraBytes < 1) {
val result3 = BigDecimal(gigaByte.toString())
return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
.toPlainString().toString() + "GB"
}
val result4 = BigDecimal(teraBytes)
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
.toString() + "TB"
}
/**
* 保存图片到本地相册
*/
fun saveBitmapToGalley(context: Context, bitmap: Bitmap) {
try {
var parentDir: File
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
parentDir = context.getExternalFilesDir(Environment.DIRECTORY_DCIM)!!
} else {
return
}
} else {
parentDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
}
var fileName = "firend.jpg"
var file = File(parentDir, fileName)
val contentValues = ContentValues()
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/JPEG")
//兼容Android Q和以下版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//android Q中不再使用DATA字段,而用RELATIVE_PATH代替
//RELATIVE_PATH是相对路径不是绝对路径
//DCIM是系统文件夹,关于系统文件夹可以到系统自带的文件管理器中查看,不可以写没存在的名字
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
var uri = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
// LogUtil.v("-------uri= " + uri)
if (uri != null) {
//若生成了uri,则表示该文件添加成功
//使用流将内容写入该uri中即可
val outputStream = context.contentResolver.openOutputStream(uri)
if (outputStream != null) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
outputStream.flush()
outputStream.close()
}
}
} else {
contentValues.put(MediaStore.Images.Media.DATA, Environment.DIRECTORY_DCIM)
MediaStore.Images.Media.insertImage(
context.contentResolver,
bitmap,
fileName,
null
)
var outputStream = FileOutputStream(file)
if (file.exists()) {
file.delete()
} else {
file.createNewFile()
}
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
outputStream.flush()
outputStream.close()
}
// LogUtil.e("------ " + file?.toUri())
// context.sendBroadcast(
// Intent(
// Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
// file?.toUri()
// )
// )
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
}
\ No newline at end of file
package com.sd.maplibrary.utils;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.view.animation.LinearInterpolator;
import com.minedata.minenavi.mapdal.LatLng;
public class SmoothMoveUtils {
public interface OnPositionUpdateListener {
/**
* 每帧回调:插值点 + 朝向角度 bearing
*/
void onUpdate(LatLng interpolatedLatLng, float bearing);
/**
* 动画结束
*/
void onFinish();
}
public static void startSmoothMove(
LatLng from,
LatLng to,
long durationMillis,
OnPositionUpdateListener listener
) {
if (from == null || to == null || listener == null || durationMillis <= 0) {
return;
}
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(durationMillis);
animator.setInterpolator(new LinearInterpolator());
float bearing = calculateBearing(from, to);
animator.addUpdateListener(animation -> {
float fraction = (float) animation.getAnimatedValue();
double lat = from.latitude + (to.latitude - from.latitude) * fraction;
double lng = from.longitude + (to.longitude - from.longitude) * fraction;
LatLng interpolated = new LatLng(lat, lng);
listener.onUpdate(interpolated, bearing); // 实时位置 + 朝向角
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
listener.onFinish();
}
});
animator.start();
}
/**
* 计算从起点 to 终点的方位角(bearing),单位为度(0~360°)
*/
private static float calculateBearing(LatLng from, LatLng to) {
double lat1 = Math.toRadians(from.latitude);
double lon1 = Math.toRadians(from.longitude);
double lat2 = Math.toRadians(to.latitude);
double lon2 = Math.toRadians(to.longitude);
double dLon = lon2 - lon1;
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
double bearingRad = Math.atan2(y, x);
return (float) ((Math.toDegrees(bearingRad) + 360) % 360);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment