Commit 2dcc5362 by yangyang

轨迹相似度工具提交(标准)

parent 0e34e70e
package com.founder.commonutils.util.map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Coordinate {
private double x;
private double y;
}
package com.founder.commonutils.util.map;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
public class DTW {
//一维比较
//s1 = [1, 2, 3, 4, 5, 5, 5, 4]
//s2 = [3, 4, 5, 5, 5, 4]
public void DTW_1(int[] s1, int[] s2) {
int r = s1.length;
int c = s2.length;
//计算距离矩阵M
int[][] D0 = new int[r + 1][c + 1];
for (int i = 0; i < r + 1; i++) {
for (int j = 0; j < c + 1; j++) {
if (i == 0 && j == 0) {
D0[i][j] = 0;
} else if (i == 0) {
D0[i][j] = Integer.MAX_VALUE;
} else if (j == 0) {
D0[i][j] = Integer.MAX_VALUE;
} else {
D0[i][j] = Math.abs(s1[i - 1] - s2[j - 1]);
}
}
}
int[][] D = new int[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
D[i][j] = D0[i + 1][j + 1];
}
}
System.out.println("距离矩阵D:");
System.out.println(Arrays.deepToString(D).replaceAll("],", "]," + System.getProperty("line.separator")));
//计算损失矩阵M
int[][] MC = D0.clone();
for (int i = 1; i < r + 1; i++) {
for (int j = 1; j < c + 1; j++) {
MC[i][j] += Math.min(Math.min(MC[i - 1][j - 1], MC[i][j - 1]), MC[i - 1][j]);
}
}
int[][] M = new int[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
M[i][j] = MC[i + 1][j + 1];
}
}
System.out.println("损失矩阵M:");
System.out.println(Arrays.deepToString(M).replaceAll("],", "]," + System.getProperty("line.separator")));
System.out.println("序列距离:" + M[r - 1][c - 1]);
}
public static double getDistance(Coordinate p, Coordinate q) {
double dx = p.getX() - q.getX();
double dy = p.getY() - q.getY();
double distance = Math.sqrt(dx * dx + dy * dy);
return distance;
}
public void DTW_2(List<Coordinate> coords1, List<Coordinate> coords2) {
int r = coords1.size();
int c = coords2.size();
//计算距离矩阵M
double[][] D0 = new double[r + 1][c + 1];
for (int i = 0; i < r + 1; i++) {
for (int j = 0; j < c + 1; j++) {
if (i == 0 && j == 0) {
D0[i][j] = 0;
} else if (i == 0) {
D0[i][j] = Double.MAX_VALUE;
} else if (j == 0) {
D0[i][j] = Double.MAX_VALUE;
} else {
// D0[i][j] = coords1.get(i - 1).distance(coords2.get(j - 1));
D0[i][j] =getDistance(coords1.get(i - 1), coords2.get(j - 1));
}
}
}
DecimalFormat df = new DecimalFormat("#.00");
double[][] D = new double[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
D[i][j] = Double.parseDouble(df.format(D0[i + 1][j + 1]));
}
}
System.out.println("距离矩阵D:");
System.out.println(Arrays.deepToString(D).replaceAll("],", "]," + System.getProperty("line.separator")));
//计算损失矩阵M
double[][] MC = D0.clone();
for (int i = 1; i < r + 1; i++) {
for (int j = 1; j < c + 1; j++) {
MC[i][j] += Math.min(Math.min(MC[i - 1][j - 1], MC[i][j - 1]), MC[i - 1][j]);
}
}
double[][] M = new double[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
M[i][j] = MC[i + 1][j + 1];
}
}
System.out.println("损失矩阵M:");
System.out.println(Arrays.deepToString(M).replaceAll("],", "]," + System.getProperty("line.separator")));
System.out.println("序列距离:" + M[r - 1][c - 1]);
}
}
\ No newline at end of file
package com.founder.commonutils.util.map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LCSS {
private List<Coordinate> l1;
private List<Coordinate> l2;
private List<Coordinate> lcs = new ArrayList<>();
public static double getDistance(Coordinate p, Coordinate q) {
double dx = p.getX() - q.getX();
double dy = p.getY() - q.getY();
double distance = Math.sqrt(dx * dx + dy * dy);
return distance;
}
public boolean isNearby(Coordinate a, Coordinate b,int radius) {
if (getDistance(a, b) < radius) return true;
return false;
}
public void printLcs(int[][] flag, List<Coordinate> a, int i, int j) {
if (i == 0 || j == 0) return;
if (flag[i][j] == 1) {
printLcs(flag, a, i - 1, j - 1);
lcs.add(a.get(i - 1));
} else if (flag[i][j] == 2) {
printLcs(flag, a, i, j - 1);
} else {
printLcs(flag, a, i - 1, j);
}
}
public double lcs(List<Coordinate> l1, List<Coordinate> l2,int radius) {
int len1 = l1.size();
int len2 = l2.size();
int[][] c = new int[len1 + 1][len2 + 1];
int[][] flag = new int[len1 + 1][len2 + 1];
for (int i = 0; i < len1; i++) {
for (int j = 0; j < len2; j++) {
if (isNearby(l1.get(i), l2.get(j),radius)) {
c[i + 1][j + 1] = c[i][j] + 1;
flag[i + 1][j + 1] = 1;//1='ok' //1表示箭头为 左上
//for循环知道行数列数的情况
//System.out.print(flag[i + 1][j + 1] + " ");
} else if (c[i + 1][j] > c[i][j + 1]) {
c[i + 1][j + 1] = c[i + 1][j];
flag[i + 1][j + 1] = 2;//2='left' //2表示箭头向 上
//for循环知道行数列数的情况
//System.out.print(flag[i + 1][j + 1] + " ");
} else {
c[i + 1][j + 1] = c[i][j + 1];
flag[i + 1][j + 1] = 3;//3='up' //3表示箭头向 左
//for循环知道行数列数的情况
//System.out.print(flag[i + 1][j + 1] + " ");
}
}
}
printLcs(flag, l1, len1, len2);
//归一化处理
return (lcs.size() * 1.0 / Math.min(len1, len2));
}
public static void main(String[] args) {
List<Coordinate> l1 = new ArrayList<>();
l1.add(new Coordinate(114.300, 30.1));
l1.add(new Coordinate(114.302, 30.101));
/* l1.add(new Coordinate(114.3023, 30.1002));
l1.add(new Coordinate(114.30235, 30.1011));
l1.add(new Coordinate(114.304, 30.1003));*/
List<Coordinate> l2 = new ArrayList<>();
l2.add(new Coordinate(109.304, 30.1003));
l2.add(new Coordinate(109.302, 30.101));
LCSS lcss = new LCSS();
System.out.println(lcss.lcs(l1, l2,10));
}
}
\ No newline at end of file
package com.founder.commonutils.util.map;
/**
* 艮
* 2022/1/18
* 10:54
*/
import java.util.*;
/**
* _ooOoo_
* o8888888o
* 88" . "88
* (| -_- |)
* O\ = /O
* ___/`---'\____
* . ' \\| |// `.
* / \\||| : |||// \
* / _||||| -:- |||||- \
* | | \\\ - /// | |
* | \_| ''\---/'' | |
* \ .-\__ `-` ___/-. /
* ___`. .' /--.--\ `. . __
* ."" '< `.___\_<|>_/___.' >'"".
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
* \ \ `-. \_ __\ /__ _/ .-` / /
* ======`-.____`-.___\_____/___.-`____.-'======
* `=---='
*/
public class LocalPath {
public static void main(String[] args) {
Double[] s1 = {1.0, 1.0};
Double[] s2 = {1.0, 2.0};
Double[] s3 = {2.0, 3.0};
Double[] s4 = {2.0, 4.0};
Double[] s5 = {3.0, 4.5};
Double[] s6 = {3.0, 4.0};
Solution s = new Solution();
//System.out.println(s.onSegment(s1, s2, s3));
List<Double[]> l = new ArrayList<>();
List<Double[]> l2 = new ArrayList<>();
l.add(s1);
l.add(s2);
l.add(s3);
l.add(s4);
l.add(s5);
l.add(s6);
l2.add(new Double[]{1.0, 1.0});
l2.add(new Double[]{1.0, 2.0});
l2.add(new Double[]{2.0, 2.5});
l2.add(new Double[]{2.0, 3.5});
l2.add(new Double[]{3.0, 3.5});
l2.add(new Double[]{3.0, 4.0});
// List<Double[]> l3 = new ArrayList<>();
// List<Double[]> l4 = new ArrayList<>();
// l3.add(new Double[]{3.0, 3.5});
// l3.add(new Double[]{3.0, 4.0});
// l4.add(new Double[]{3.0, 4.5});
// l4.add(new Double[]{3.0, 4.0});
//// l2.add(new Double[]{3.0, 3.5});
//// l2.add(new Double[]{3.0, 4.0});
// Double[] i = s.intersection(l3.get(0), l3.get(1), l4.get(0), l4.get(1));
// for (Double aDouble : i) {
// System.out.println(aDouble);
// }
List<Double[]> doubles = s.intersectionAsList(l, l2);
System.out.println(s.area(doubles, l, l2));
}
}
class Solution {
//计算交点及上一个交点的面积
//得到一个集合里面存储全部的交点面积
public double area(List<Double[]> in, List<Double[]> path1, List<Double[]> path2) {
//得到交点的,路径
Double[] d1, d2;
double l1 = 0.0, l2 = 0.0;
double lip = 0.0;
List<Double[]> d3 = new ArrayList<>();
List<Double[]> d4 = new ArrayList<>();
List<Double[]> d5 = new ArrayList<>();
List<Double[]> d6 = new ArrayList<>();
List<Double[]> power = new ArrayList<>();
List<Double[]> power2 = new ArrayList<>();
for (int i = 1; i < path1.size(); i++) {
//路径1的长度
l1 = Math.sqrt(Math.pow(path1.get(i)[0] - path1.get(i - 1)[0], 2) + Math.pow(path1.get(i)[1] - path1.get(i - 1)[1], 2)) + l1;
}
System.out.println("路径s的长度为:" + l1);
for (int i = 1; i < path2.size(); ++i) {
//路径2的长度
l2 = Math.sqrt(Math.pow(path2.get(i)[0] - path2.get(i - 1)[0], 2) + Math.pow(path2.get(i)[1] - path2.get(i - 1)[1], 2)) + l2;
}
System.out.println("路径q的长度为:" + l2);
if (in.size() < 2) {
return 0.0;
}
for (int i = 1; i < in.size(); i++) {
System.out.println("=======================================");
//从二个交点的时候,可以得到面积
//i ,i-1
d1 = in.get(i);//第二个交点
d2 = in.get(i - 1);//第一个交点
//两个容器,一个用来判断,一个用来装载
d4.clear();
d6.clear();
// //找到路径12中在范围d1,d2的
int min = Math.min(path1.size(), path2.size());
//开始位置为上一个交点,
for (int i1 = d3.size(); i1 < path1.size(); i1++) {
//判断交点在哪条路径上,得到对应的点的范围
if (!Arrays.equals(path1.get(i1), d1)) {
d3.add(path1.get(i1));
d4.add(path1.get(i1));
}
if (Arrays.equals(path1.get(i1), d1)) {
break;
}
}
for (int i1 = d5.size(); i1 < path2.size(); ++i1) {
//判断交点在哪条路径上,得到对应的点的范围
if (!Arrays.equals(path2.get(i1), d1)) {
d5.add(path2.get(i1));
d6.add(path2.get(i1));
}
if (Arrays.equals(path2.get(i1), d1)) {
break;
}
}
d4.add(d1);
d6.add(d1);
System.out.println("交点范围坐标:[" + d2[0] + " " + d2[1] + "]" + "[" + d1[0] + " " + d1[1] + "]");
System.out.println("交点范围内路径d4的点:");
d4.forEach(a -> {
System.out.println("[" + a[0] + " " + a[1] + "]");
});
System.out.println("交点范围内路径d6的点:");
d6.forEach(a -> {
System.out.println("[" + a[0] + " " + a[1] + "]");
});
//这个时候我们有全部的点,带入公式得到对应范围的面积,进行存储
double aread4 = 0.0;
double aread6 = 0.0;
//计算此时d4,d6的面积,相加
for (int j = 0; j < d4.size(); j++) {
//多边形面积方程
if (j == d4.size() - 1) {
aread4 = 0.5 * (d4.get(j)[0] * d4.get(0)[1] - d4.get(0)[0] * d4.get(j)[1]) + aread4;
} else {
aread4 = 0.5 * (d4.get(j)[0] * d4.get(j + 1)[1] - d4.get(j + 1)[0] * d4.get(j)[1]) + aread4;
}
//System.out.println(area);
}
for (int j = 0; j < d6.size(); ++j) {
//多边形面积方程
if (j == d6.size() - 1) {
aread6 = 0.5 * (d6.get(j)[0] * d6.get(0)[1] - d6.get(0)[0] * d6.get(j)[1]) + aread6;
} else {
aread6 = 0.5 * (d6.get(j)[0] * d6.get(j + 1)[1] - d6.get(j + 1)[0] * d6.get(j)[1]) + aread6;
}
//System.out.println(area);
}
//area表示面积
double area = Math.abs(aread4) + Math.abs(aread6);
System.out.println("第" + i + "交点到" + (i + 1) + "交点范围面积:" + area);
//求交点权重
power.addAll(d4);
double ps = 0.0, pq = 0.0, p;
//路径s的路径
for (int j = 1; j < power.size(); j++) {
ps = Math.sqrt(Math.pow(power.get(j)[0] - power.get(j - 1)[0], 2) + Math.pow(power.get(j)[1] - power.get(j - 1)[1], 2)) + ps;
}
power2.addAll(d6);
for (int j = 1; j < power2.size(); ++j) {
pq = Math.sqrt(Math.pow(power2.get(j)[0] - power2.get(j - 1)[0], 2) + Math.pow(power2.get(j)[1] - power2.get(j - 1)[1], 2)) + pq;
}
//权重
p = (pq + ps) / (l1 + l2);
System.out.println("第" + i + "交点到" + (i + 1) + "交点范围的权重:" + p);
lip = lip + p * area;
power.clear();
power2.clear();
}
//返回所有面积和周长权重的map集合.
System.out.println("最后的dLIP为" + Math.abs(lip));
// System.out.println("轨迹相似度为:"+Math.abs(lip)*100+"%");
// System.out.println("轨迹相似度为:"+Math.abs(lip)/2.3*100+"%");
// System.out.println("轨迹相似度为:"+Math.abs(lip)*100+"%");
// System.out.println("轨迹相似度为:"+Math.abs(lip)/2*100+"%");
// System.out.println("轨迹相似度为:"+Math.abs(lip)/5*100+"%");
return lip;
}
//将所有的点存储在一个Set集合,下标0标识起点,后面的每一个的点的起点都是前面的终点
//因为我们不知道所有线段长度的情况,依次遍历每一条线段所有情况得到所有交点,
//以起点为目标,得到每个交点与之对应的上一个交点的情况
public List<Double[]> intersectionAsList(List<Double[]> path1, List<Double[]> path2) {
//交点集合
int h = 0;
Double[] intersection = new Double[0];
List<Double[]> list = new ArrayList<>();
int min = Math.min(path1.size(), path2.size());
int max = Math.max(path1.size(), path2.size());
for (int i = 1; i < min; i++) {
//如果与上一条相交,则不用考虑多余情况
for (int j = 1; j < max; j++) {
//判断第i与第j是否相交,相交的话,存入到list
// System.out.println(intersection[0] + " " + intersection[1]);
//在比较最后一个的时候,发生了数组越界
// System.out.println("进行比较的线段s[" + path1.get(i - 1)[0] + path1.get(i - 1)[1] + "][" + path1.get(i)[0] + path1.get(i)[1] + "]");
// System.out.println("进行比较的线段q[" + path2.get(j - 1)[0] + path2.get(j - 1)[1] + "][" + path2.get(j)[0] + path2.get(j)[1] + "]");
try {
intersection = intersection(path1.get(i - 1), path1.get(i), path2.get(j), path2.get(j - 1));
} catch (Exception e) {
//e.printStackTrace();
}
//System.out.println(intersection[0] + " " + intersection[1]);
if (intersection != null && !list.contains(intersection) && intersection.length > 0) {
//System.out.println(intersection);
list.add(intersection);
}
}
}
isEquality(list);
int si = 1;
int si2 = 1;
int size = path1.size();
for (int i = 1; i < path1.size(); i++) {
for (Double[] doubles : list) {
//将交点添加到路径,保证每次都是最新的路径
if (onSegment(path1.get(i - 1), path1.get(i), doubles)) {
i++;
path1.add(si, doubles);
}
si = i;
}
}
for (int i = 1; i < path2.size(); i++) {
for (Double[] doubles : list) {
//将交点添加到路径,保证每次都是最新的路径
if (onSegment(path2.get(i - 1), path2.get(i), doubles)) {
i++;
path2.add(si2, doubles);
//i--;
}
si2 = i;
}
}
for (Double[] doubles : list) {
System.out.println("交点坐标:[" + doubles[0] + " " + doubles[1] + "]");
}
isEquality(path1);
isEquality(path2);
return list;
}
//判断集合内数组是否相等,去重
public void isEquality(List<Double[]> list) {
boolean isArray = false;
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
boolean equals = Arrays.equals(list.get(i), list.get(j));
//相等情况下判断,但是下标remove以后,list会前进
if (equals) {
list.remove(j);
j--;
}
}
}
}
Double[] ans;
//判断点是否在线段上
//0,横坐标,1,纵坐标
public boolean onSegment(Double[] pi, Double[] pj, Double[] Q) {
return (Q[0] - pi[0]) * (pj[1] - pi[1]) == (pj[0] - pi[0]) * (Q[1] - pi[1]) && Math.min(pi[0], pj[0]) <= Q[0] && Q[0] <= Math.max(pi[0], pj[0]) && Math.min(pi[1], pj[1]) <= Q[1] && Q[1] <= Math.max(pi[1], pj[1]);
}
//每一次对比都有保证线段的更新,不能是上一次
public Double[] intersection(Double[] start1, Double[] end1, Double[] start2, Double[] end2) {
ans = new Double[0];
//线段1的开始,线段1的结尾
//线段2的开始,线段2的结尾
Double x1 = start1[0], y1 = start1[1];
Double x2 = end1[0], y2 = end1[1];
Double x3 = start2[0], y3 = start2[1];
Double x4 = end2[0], y4 = end2[1];
// 判断 (x1, y1)~(x2, y2) 和 (x3, y3)~(x4, y4) 是否平行
if ((y4 - y3) * (x2 - x1) == (y2 - y1) * (x4 - x3)) {
// 若平行,则判断 (x3, y3) 是否在「直线」(x1, y1)~(x2, y2) 上
if ((y2 - y1) * (x3 - x1) == (y3 - y1) * (x2 - x1)) {
// 判断 (x3, y3) 是否在「线段」(x1, y1)~(x2, y2) 上
if (inside(x1, y1, x2, y2, x3, y3)) {
update(x3, y3);
}
// 判断 (x4, y4) 是否在「线段」(x1, y1)~(x2, y2) 上
if (inside(x1, y1, x2, y2, x4, y4)) {
update(x4, y4);
}
// 判断 (x1, y1) 是否在「线段」(x3, y3)~(x4, y4) 上
if (inside(x3, y3, x4, y4, x1, y1)) {
update(x1, y1);
}
// 判断 (x2, y2) 是否在「线段」(x3, y3)~(x4, y4) 上
if (inside(x3, y3, x4, y4, x2, y2)) {
update(x2, y2);
}
}
// 在平行时,其余的所有情况都不会有交点
} else {
// 联立方程得到 t1 和 t2 的值
double t1 = (double) (x3 * (y4 - y3) + y1 * (x4 - x3) - y3 * (x4 - x3) - x1 * (y4 - y3)) / ((x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1));
double t2 = (double) (x1 * (y2 - y1) + y3 * (x2 - x1) - y1 * (x2 - x1) - x3 * (y2 - y1)) / ((x4 - x3) * (y2 - y1) - (x2 - x1) * (y4 - y3));
// 判断 t1 和 t2 是否均在 [0, 1] 之间
if (t1 >= 0.0 && t1 <= 1.0 && t2 >= 0.0 && t2 <= 1.0) {
ans = new Double[]{x1 + t1 * (x2 - x1), y1 + t1 * (y2 - y1)};
}
}
return ans;
}
// 判断 (xk, yk) 是否在「线段」(x1, y1)~(x2, y2) 上
// 这里的前提是 (xk, yk) 一定在「直线」(x1, y1)~(x2, y2) 上
public boolean inside(Double x1, Double y1, Double x2, Double y2, Double xk, Double yk) {
// 若与 x 轴平行,只需要判断 x 的部分
// 若与 y 轴平行,只需要判断 y 的部分
// 若为普通线段,则都要判断
return (x1 == x2 || (Math.min(x1, x2) <= xk && xk <= Math.max(x1, x2))) && (y1 == y2 || (Math.min(y1, y2) <= yk && yk <= Math.max(y1, y2)));
}
public void update(double xk, double yk) {
// 将一个交点与当前 ans 中的结果进行比较
// 若更优则替换
if (ans.length == 0 || xk < ans[0] || (xk == ans[0] && yk < ans[1])) {
ans = new Double[]{xk, yk};
}
}
}
\ No newline at end of file
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