118 lines
4.7 KiB
Java
118 lines
4.7 KiB
Java
package com.xiang.common.utils;
|
|
|
|
import com.xiang.common.pojo.jntyzx.zlb.ZlbOrderInfo;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
|
/**
|
|
* 浙里办验证码轨迹生成工具。
|
|
*/
|
|
public class ZlbCaptchaTrackUtil {
|
|
|
|
private ZlbCaptchaTrackUtil() {
|
|
}
|
|
|
|
public static List<ZlbOrderInfo.ZlbData.TrackList> generateBezierTrackList(List<String> trackList) {
|
|
List<ZlbOrderInfo.ZlbData.TrackList> result = new ArrayList<>();
|
|
if (trackList == null || trackList.isEmpty()) {
|
|
return result;
|
|
}
|
|
|
|
for (int i = 0; i < trackList.size(); i++) {
|
|
int[] currentPoint = parseTrackCoordinate(trackList.get(i));
|
|
int clickTime = result.isEmpty()
|
|
? randomBetween(1800, 2200)
|
|
: result.get(result.size() - 1).getT() + randomBetween(25, 60);
|
|
result.add(buildTrackPoint(currentPoint[0], currentPoint[1], clickTime, "click"));
|
|
|
|
if (i < trackList.size() - 1) {
|
|
int[] nextPoint = parseTrackCoordinate(trackList.get(i + 1));
|
|
int moveStartTime = result.get(result.size() - 1).getT();
|
|
int moveDuration = randomBetween(800, 1200);
|
|
List<int[]> movePoints = buildBezierMovePoints(currentPoint[0], currentPoint[1], nextPoint[0], nextPoint[1]);
|
|
for (int moveIndex = 0; moveIndex < movePoints.size(); moveIndex++) {
|
|
int[] movePoint = movePoints.get(moveIndex);
|
|
int moveTime = moveStartTime + (int) Math.round((double) moveDuration * (moveIndex + 1) / (movePoints.size() + 1));
|
|
result.add(buildTrackPoint(movePoint[0], movePoint[1], moveTime, "move"));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static List<String> parseCoordinateText(String coordinateText) {
|
|
if (coordinateText == null || coordinateText.trim().isEmpty()) {
|
|
return Collections.emptyList();
|
|
}
|
|
String normalized = coordinateText.replace("\n", "|").replace(";", "|");
|
|
String[] parts = normalized.split("\\|");
|
|
List<String> result = new ArrayList<>();
|
|
for (String part : parts) {
|
|
if (part != null && !part.trim().isEmpty()) {
|
|
result.add(part.trim());
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static int[] parseTrackCoordinate(String track) {
|
|
String[] coordinateArr = track.split(",");
|
|
return new int[]{
|
|
Integer.parseInt(coordinateArr[0].trim()),
|
|
Integer.parseInt(coordinateArr[1].trim())
|
|
};
|
|
}
|
|
|
|
private static List<int[]> buildBezierMovePoints(int fromX, int fromY, int toX, int toY) {
|
|
int movePointCount = randomBetween(3, 5);
|
|
double dx = toX - fromX;
|
|
double dy = toY - fromY;
|
|
double distance = Math.max(1d, Math.hypot(dx, dy));
|
|
double normalX = -dy / distance;
|
|
double normalY = dx / distance;
|
|
double direction = ThreadLocalRandom.current().nextBoolean() ? 1d : -1d;
|
|
double offset = Math.min(28d, Math.max(6d, distance * ThreadLocalRandom.current().nextDouble(0.08d, 0.22d))) * direction;
|
|
double controlX = (fromX + toX) / 2d + normalX * offset;
|
|
double controlY = (fromY + toY) / 2d + normalY * offset;
|
|
|
|
List<int[]> movePoints = new ArrayList<>(movePointCount);
|
|
for (int i = 1; i <= movePointCount; i++) {
|
|
double progress = easeInOutCubic((double) i / (movePointCount + 1));
|
|
int x = (int) Math.round(
|
|
Math.pow(1 - progress, 2) * fromX
|
|
+ 2 * (1 - progress) * progress * controlX
|
|
+ Math.pow(progress, 2) * toX
|
|
);
|
|
int y = (int) Math.round(
|
|
Math.pow(1 - progress, 2) * fromY
|
|
+ 2 * (1 - progress) * progress * controlY
|
|
+ Math.pow(progress, 2) * toY
|
|
);
|
|
movePoints.add(new int[]{x, y});
|
|
}
|
|
return movePoints;
|
|
}
|
|
|
|
private static double easeInOutCubic(double value) {
|
|
return value < 0.5d
|
|
? 4d * value * value * value
|
|
: 1d - Math.pow(-2d * value + 2d, 3d) / 2d;
|
|
}
|
|
|
|
private static ZlbOrderInfo.ZlbData.TrackList buildTrackPoint(int x, int y, int t, String type) {
|
|
ZlbOrderInfo.ZlbData.TrackList data = new ZlbOrderInfo.ZlbData.TrackList();
|
|
data.setX(x);
|
|
data.setY(y);
|
|
data.setT(t);
|
|
data.setType(type);
|
|
return data;
|
|
}
|
|
|
|
private static int randomBetween(int minInclusive, int maxInclusive) {
|
|
return ThreadLocalRandom.current().nextInt(minInclusive, maxInclusive + 1);
|
|
}
|
|
}
|