Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
p x
mycomutils
Commits
5d52878c
Commit
5d52878c
authored
Jan 20, 2026
by
p x
Browse files
新增通过点移动计算是否通过
parent
745a80a3
Changes
5
Show whitespace changes
Inline
Side-by-side
build.gradle.kts
View file @
5d52878c
...
...
@@ -17,10 +17,11 @@ android {
buildTypes
{
release
{
isMinifyEnabled
=
false
proguardFiles
(
consumerProguardFiles
(
"proguard-rules.pro"
)
/* proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
)
*/
}
}
compileOptions
{
...
...
proguard-rules.pro
0 → 100644
View file @
5d52878c
# Add project specific ProGuard rules here.
#
You
can
control
the
set
of
applied
configuration
files
using
the
#
proguardFiles
setting
in
build
.
gradle
.
#
#
For
more
details
,
see
#
http
://
developer
.
android
.
com
/
guide
/
developing
/
tools
/
proguard
.
html
#
If
your
project
uses
WebView
with
JS
,
uncomment
the
following
#
and
specify
the
fully
qualified
class
name
to
the
JavaScript
interface
#
class
:
#-
keepclassmembers
class
fqcn
.
of
.
javascript
.
interface
.
for
.
webview
{
#
public
*
;
#
}
#
Uncomment
this
to
preserve
the
line
number
information
for
#
debugging
stack
traces
.
#-
keepattributes
SourceFile
,
LineNumberTable
#
If
you
keep
the
line
number
information
,
uncomment
this
to
#
hide
the
original
source
file
name
.
#-
renamesourcefileattribute
SourceFile
src/main/java/commons/gis/BasicTools.kt
View file @
5d52878c
package
commons.gis
import
android.location.Location
import
kotlin.math.atan2
import
kotlin.math.cos
import
kotlin.math.pow
...
...
@@ -11,9 +12,53 @@ object BasicTools {
/**
* 计算2点距离
* Android Location 类自带的计算方法
* @return 返回米
* **/
fun
calculateHaversineDistance
(
lng1
:
Double
,
lat1
:
Double
,
lng2
:
Double
,
lat2
:
Double
):
Double
{
*/
fun
calculateDistance
(
lat1
:
Double
,
lon1
:
Double
,
lat2
:
Double
,
lon2
:
Double
):
Float
{
val
results
=
FloatArray
(
1
)
Location
.
distanceBetween
(
lat1
,
lon1
,
lat2
,
lon2
,
results
)
return
results
[
0
]
// 单位:米
}
/**
* 计算2点距离
* Android Location 类自带的计算方法
* @return 返回结果为:Pair(距离, 初始方位角(起点到终点))
*/
fun
calculateDistancePair
(
lat1
:
Double
,
lon1
:
Double
,
lat2
:
Double
,
lon2
:
Double
):
Pair
<
Float
,
Float
>
{
val
results
=
FloatArray
(
2
)
Location
.
distanceBetween
(
lat1
,
lon1
,
lat2
,
lon2
,
results
)
return
Pair
(
results
[
0
],
(
results
[
1
]
+
360
)
%
360
)
// return Pair(results[0], results[1])
}
/**
* 标准化方位角,确保结果在 0.0° ~ 360.0° 范围内
* @param bearing 原始方位角(可能为负数)
* @return 标准化后的方位角
*/
private
fun
normalizeBearing
(
bearing
:
Float
):
Float
{
// 取模运算处理循环,再处理边界值
var
temp
=
bearing
%
360
if
(
temp
<
0
)
{
temp
+=
360f
}
return
temp
}
/**
* 计算2点距离
* 纯 Java 实现 Haversine 公式(近似计算)
* @return 返回米
*/
fun
calculateHaversineDistance
(
lng1
:
Double
,
lat1
:
Double
,
lng2
:
Double
,
lat2
:
Double
):
Double
{
val
earthRadius
=
6371000.0
// 地球半径,单位:米
val
lat1
=
Math
.
toRadians
(
lat1
)
...
...
src/main/java/commons/gis/CrsShiftUtils.java
0 → 100644
View file @
5d52878c
package
commons.gis
;
/**
* 星际旅行概论(坐标系偏移工具类)
* 支持GC02、BD09和WGS84坐标系之间互相转化
* @author marquis
*
*/
public
class
CrsShiftUtils
{
/**
* π
*/
private
final
static
double
PI
=
3.1415926535897931
;
/**
* 长半轴
*/
private
final
static
double
aa
=
6378245.0
;
/**
* 偏心率平方
*/
private
final
static
double
ee
=
0.00669342162296594323
;
private
final
static
double
ee1
=
0.0066934216229659433
;
/**
* 默认偏移中心点坐标
*/
private
final
static
double
centerLng
=
105.0
;
private
final
static
double
centerLat
=
35.0
;
private
final
static
double
centerLng1
=
100.0
;
private
final
static
double
centerLat1
=
30.0
;
/**
* 偏移/反偏移方向
* @author marquis
*
*/
public
enum
Method
{
WGS84_2_GCJ02
,
GCJ02_2_WGS84
,
WGS84_2_BD09
,
BD09_2_WGS84
,
GCJ02_2_BD09
,
BD09_2_GCJ02
}
/**
* 禁止实例化
*/
private
CrsShiftUtils
()
{
}
/**
* 二维点数据的坐标系转换
* @param lng
* @param lat
* @param method
* @return
*/
public
static
double
[]
convert
(
double
lng
,
double
lat
,
Method
method
)
{
double
ret
[];
switch
(
method
)
{
case
WGS84_2_GCJ02:
ret
=
shift2Mars
(
lng
,
lat
,
Math
.
PI
,
aa
,
ee
,
lng
,
lat
);
ret
[
0
]
=
lng
+
ret
[
0
];
ret
[
1
]
=
lat
+
ret
[
1
];
return
ret
;
case
GCJ02_2_WGS84:
ret
=
shift2Mars
(
lng
,
lat
,
Math
.
PI
,
aa
,
ee
,
centerLng
,
centerLat
);
ret
[
0
]
=
lng
-
ret
[
0
];
ret
[
1
]
=
lat
-
ret
[
1
];
return
ret
;
case
WGS84_2_BD09:
ret
=
shift2Mars
(
lng
,
lat
,
Math
.
PI
,
aa
,
ee
,
centerLng
,
centerLat
);
ret
[
0
]
=
lng
+
ret
[
0
];
ret
[
1
]
=
lat
+
ret
[
1
];
return
mars2Saturn
(
ret
[
0
],
ret
[
1
],
Math
.
PI
);
case
BD09_2_WGS84:
ret
=
saturn2Mars
(
lng
,
lat
,
Math
.
PI
);
ret
=
shift2Mars
(
ret
[
0
],
ret
[
1
],
Math
.
PI
,
aa
,
ee
,
centerLng
,
centerLat
);
ret
[
0
]
=
lng
-
ret
[
0
];
ret
[
1
]
=
lat
-
ret
[
1
];
return
ret
;
case
GCJ02_2_BD09:
return
mars2Saturn
(
lng
,
lat
,
Math
.
PI
);
case
BD09_2_GCJ02:
return
saturn2Mars
(
lng
,
lat
,
Math
.
PI
);
default
:
ret
=
new
double
[
2
];
ret
[
0
]
=
lng
;
ret
[
1
]
=
lat
;
return
ret
;
}
}
/**
* 计算火星坐标系的偏移量,正向偏移时坐标加偏移量,反向偏移时减偏移量
* @param lng
* @param lat
* @param pi
* @param a
* @param e
* @param cLng
* @param cLat
* @return
*/
private
static
double
[]
shift2Mars
(
double
lng
,
double
lat
,
double
pi
,
double
a
,
double
e
,
double
cLng
,
double
cLat
)
{
if
(
outOfChina
(
lng
,
lat
))
{
double
[]
ret
=
new
double
[
2
];
ret
[
0
]
=
lng
;
ret
[
1
]
=
lat
;
return
ret
;
}
double
dlat
=
transformlat
(
lng
-
cLng
,
lat
-
cLat
,
pi
);
double
dlng
=
transformlng
(
lng
-
cLng
,
lat
-
cLat
,
pi
);
double
radlat
=
lat
/
180.0
*
pi
;
double
magic
=
Math
.
sin
(
radlat
);
magic
=
1
-
e
*
magic
*
magic
;
double
sqrtmagic
=
Math
.
sqrt
(
magic
);
dlat
=
(
dlat
*
180.0
)
/
((
a
*
(
1
-
ee
))
/
(
magic
*
sqrtmagic
)
*
pi
);
dlng
=
(
dlng
*
180.0
)
/
(
a
/
sqrtmagic
*
Math
.
cos
(
radlat
)
*
pi
);
return
new
double
[]{
dlng
,
dlat
};
}
/**
* 计算火星坐标系到土星坐标系
* @param lng
* @param lat
* @param pi
* @return
*/
private
static
double
[]
mars2Saturn
(
double
lng
,
double
lat
,
double
pi
)
{
if
(
outOfChina
(
lng
,
lat
))
{
double
[]
ret
=
new
double
[
2
];
ret
[
0
]
=
lng
;
ret
[
1
]
=
lat
;
return
ret
;
}
double
magic
=
Math
.
sqrt
(
lng
*
lng
+
lat
*
lat
)
+
0.00002
*
Math
.
sin
(
lat
*
pi
);
double
theta
=
Math
.
atan2
(
lat
,
lng
)
+
0.000003
*
Math
.
cos
(
lng
*
pi
);
double
bdLng
=
magic
*
Math
.
cos
(
theta
)
+
0.0065
;
double
bdLat
=
magic
*
Math
.
sin
(
theta
)
+
0.006
;
return
new
double
[]
{
bdLng
,
bdLat
};
}
/**
* 计算土星坐标系到火星坐标系
* @param lng
* @param lat
* @param pi
* @return
*/
private
static
double
[]
saturn2Mars
(
double
lng
,
double
lat
,
double
pi
)
{
if
(
outOfChina
(
lng
,
lat
))
{
return
new
double
[]
{
lng
,
lat
};
}
double
bdLng
=
lng
-
0.0065
,
bdLat
=
lat
-
0.006
;
double
magic
=
Math
.
sqrt
(
bdLng
*
bdLng
+
bdLat
*
bdLat
)
-
0.00002
*
Math
.
sin
(
bdLat
*
pi
);
double
theta
=
Math
.
atan2
(
bdLat
,
bdLng
)
-
0.000003
*
Math
.
cos
(
bdLng
*
pi
);
double
gcjLng
=
magic
*
Math
.
cos
(
theta
);
double
gcjLat
=
magic
*
Math
.
sin
(
theta
);
return
new
double
[]
{
gcjLng
,
gcjLat
};
}
/**
* 转换经度
* @param lng
* @param lat
* @param pi
* @return
*/
private
static
double
transformlng
(
double
lng
,
double
lat
,
double
pi
)
{
double
ret
=
300.0
+
lng
+
2.0
*
lat
+
0.1
*
lng
*
lng
+
0.1
*
lng
*
lat
+
0.1
*
Math
.
sqrt
(
Math
.
abs
(
lng
));
ret
+=
(
20.0
*
Math
.
sin
(
6.0
*
lng
*
pi
)
+
20.0
*
Math
.
sin
(
2.0
*
lng
*
pi
))
*
2.0
/
3.0
;
ret
+=
(
20.0
*
Math
.
sin
(
lng
*
pi
)
+
40.0
*
Math
.
sin
(
lng
/
3.0
*
pi
))
*
2.0
/
3.0
;
ret
+=
(
150.0
*
Math
.
sin
(
lng
/
12.0
*
pi
)
+
300.0
*
Math
.
sin
(
lng
/
30.0
*
pi
))
*
2.0
/
3.0
;
return
ret
;
}
/**
* 转换维度
* @param lng
* @param lat
* @param pi
* @return
*/
private
static
double
transformlat
(
double
lng
,
double
lat
,
double
pi
)
{
double
ret
=
-
100.0
+
2.0
*
lng
+
3.0
*
lat
+
0.2
*
lat
*
lat
+
0.1
*
lng
*
lat
+
0.2
*
Math
.
sqrt
(
Math
.
abs
(
lng
));
ret
+=
(
20.0
*
Math
.
sin
(
6.0
*
lng
*
pi
)
+
20.0
*
Math
.
sin
(
2.0
*
lng
*
pi
))
*
2.0
/
3.0
;
ret
+=
(
20.0
*
Math
.
sin
(
lat
*
pi
)
+
40.0
*
Math
.
sin
(
lat
/
3.0
*
pi
))
*
2.0
/
3.0
;
ret
+=
(
160.0
*
Math
.
sin
(
lat
/
12.0
*
pi
)
+
320
*
Math
.
sin
(
lat
*
pi
/
30.0
))
*
2.0
/
3.0
;
return
ret
;
}
/**
* 简单粗暴的判断是否在国内,不在国内不做偏移
* @param lng
* @param lat
* @return
*/
private
static
boolean
outOfChina
(
double
lng
,
double
lat
)
{
//return false;
return
!(
lng
>
73.66
&&
lng
<
135.05
&&
lat
>
3.86
&&
lat
<
53.55
);
}
}
src/main/java/commons/gis/PassThroughDetector.kt
0 → 100644
View file @
5d52878c
package
commons.gis
/**
* 利用方位角+距离判断是否经过目标点位的工具类
*/
object
PassThroughDetector
{
// 距离阈值:可根据场景调整(步行50米,驾车200米)
private
val
distanceThresholdM
:
Float
=
100.0f
// 方位角变化阈值:允许的误差范围
private
val
bearingThresholdDeg
:
Float
=
15.0f
private
var
speedThresholdMps
:
Float
=
1.0f
// 速度阈值(米/秒),1m/s ≈ 3.6km/h
// 记录上一次的方位角(-1 表示首次调用)
private
var
lastBearingToTarget
:
Float
=
-
1f
// 记录是否曾接近目标点(距离≤阈值)
private
var
isApproached
:
Boolean
=
false
/**
* 判断是否经过目标点位
* @param currentLat 当前位置纬度
* @param currentLng 当前位置经度
* @param targetLat 目标点纬度
* @param targetLng 目标点经度
* @return true=已经过,false=未经过
*/
fun
isPassThroughTarget
(
currentLat
:
Double
,
currentLng
:
Double
,
targetLat
:
Double
,
targetLng
:
Double
):
Boolean
{
/*
* 速度过滤:低于阈值直接返回false,不更新任何状态
* 驾车 5.0 ~ 10.0 换算(km/h) 18 ~ 36 过滤停车 / 堵车状态
*
* */
/* if (currentSpeed < speedThresholdMps) {
return false
}*/
// 1. 计算当前位置到目标点的距离和方位角
var
(
distanceToTarget
,
currentBearingToTarget
)
=
BasicTools
.
calculateDistancePair
(
currentLat
,
currentLng
,
targetLat
,
targetLng
,
)
// currentBearingToTarget= normalizeBearing(currentBearingToTarget)
// 2. 判断是否接近目标点
if
(
distanceToTarget
<=
distanceThresholdM
)
{
isApproached
=
true
}
// 3. 首次调用:记录初始方位角,返回未经过
if
(
lastBearingToTarget
==
-
1f
)
{
lastBearingToTarget
=
currentBearingToTarget
return
false
}
// 4. 计算方位角变化(处理360°循环)
var
bearingDiff
=
Math
.
abs
(
currentBearingToTarget
-
lastBearingToTarget
)
// bearingDiff = Math.min(bearingDiff, 360 - bearingDiff)
// println("距离: ${distanceToTarget}米 初始方位角: ${currentBearingToTarget} 方位角变化${bearingDiff}")
// 核心判断:曾接近 + 方位角突变≈180° → 判定经过
val
isPassThrough
=
if
(
isApproached
&&
bearingDiff
>=
(
180
-
bearingThresholdDeg
)
// && bearingDiff <= (180 + bearingThresholdDeg)
)
{
reset
()
// 重置状态避免重复判定
true
}
else
{
false
}
// 5. 更新上一次的方位角
lastBearingToTarget
=
currentBearingToTarget
return
isPassThrough
}
/**
* 标准化方位角为 0~360°(处理负数)
*/
private
fun
normalizeBearing
(
bearing
:
Float
):
Float
{
var
normalizedBearing
=
bearing
%
360
if
(
normalizedBearing
<
0
)
{
normalizedBearing
+=
360
}
return
normalizedBearing
}
/**
* 重置检测器状态(开始新的判断时调用)
*/
fun
reset
()
{
lastBearingToTarget
=
-
1f
isApproached
=
false
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment