|
|
|
|
@ -0,0 +1,255 @@
|
|
|
|
|
package com.zhehekeji.web.service.algorithm;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
|
|
import java.awt.*;
|
|
|
|
|
import java.awt.image.BufferedImage;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.nio.file.Files;
|
|
|
|
|
import java.nio.file.Path;
|
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
|
|
|
|
|
|
|
import static com.zhehekeji.web.service.algorithm.PointCloudProcessor.clipPoints;
|
|
|
|
|
public class PointToImageMapper {
|
|
|
|
|
|
|
|
|
|
public static class PointColorMapping {
|
|
|
|
|
public double[] point;
|
|
|
|
|
public Color color;
|
|
|
|
|
|
|
|
|
|
public PointColorMapping(double[] point, Color color) {
|
|
|
|
|
this.point = point;
|
|
|
|
|
this.color = color;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getLongitudinalType(List<double[]> points, PcdPojo pojo, int l, int w, int height,String type){
|
|
|
|
|
//pojo里面的floorHeight为地板的值,以后所有的height都将根据地板值进行计算地板值减去当前点的z轴值,为高度,且当为height的倍数的时候,认为是有效的点,其中1倍的冗余在50mm,每高一层,冗余增加20mm
|
|
|
|
|
// 计算
|
|
|
|
|
System.out.println("新方法调用");
|
|
|
|
|
double baseTolerance = 50; // 初始冗余 50mm
|
|
|
|
|
double additionalTolerancePerLevel = 20; // 每层增加 20mm 冗余
|
|
|
|
|
Map<Integer, List<double[]>> map = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
points = points.stream()
|
|
|
|
|
.filter(point -> clipPoints(point, pojo.getMinBounds(), pojo.getMaxBounds()))
|
|
|
|
|
.filter(point -> {
|
|
|
|
|
// 计算当前点的高度(地板值减去 z 轴值)
|
|
|
|
|
double currentHeight = pojo.getFloorHeight() - point[2];
|
|
|
|
|
|
|
|
|
|
// 确保高度为正值
|
|
|
|
|
if (currentHeight < 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算当前高度是 height 的几倍
|
|
|
|
|
int level = (int) Math.round(currentHeight / height);
|
|
|
|
|
|
|
|
|
|
// 计算允许的冗余范围
|
|
|
|
|
double tolerance = baseTolerance + level * additionalTolerancePerLevel;
|
|
|
|
|
|
|
|
|
|
// 判断当前高度是否在允许的范围内
|
|
|
|
|
if (Math.abs(currentHeight - level * height) <= tolerance) {
|
|
|
|
|
if (!map.containsKey(level)) {
|
|
|
|
|
map.put(level, new ArrayList<>());
|
|
|
|
|
}
|
|
|
|
|
map.get(level).add(point);
|
|
|
|
|
return true;
|
|
|
|
|
}else return false;
|
|
|
|
|
})
|
|
|
|
|
.peek(point -> point[2] = pojo.getFloorHeight() - point[2])
|
|
|
|
|
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
String[] types = type.split(" ");
|
|
|
|
|
|
|
|
|
|
int layersCount = 0;
|
|
|
|
|
//计算最大值
|
|
|
|
|
for (String s : types){
|
|
|
|
|
if (s.endsWith("w")){
|
|
|
|
|
int maxW= Integer.parseInt(s.substring(0,1));
|
|
|
|
|
layersCount +=maxW;
|
|
|
|
|
}else if (s.endsWith("h")){
|
|
|
|
|
int maxL= Integer.parseInt(s.substring(0,1));
|
|
|
|
|
layersCount +=maxL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int h =5; h>0; h--){
|
|
|
|
|
if (map.containsKey(h) && map.get(h).size()>1000){
|
|
|
|
|
double area = 0;
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
area = drawPointsAndCalculateArea(map.get(h), String.valueOf(h),pojo);
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
|
}
|
|
|
|
|
if (area>0){
|
|
|
|
|
System.out.println("面积:"+area);
|
|
|
|
|
System.out.println("个数:"+area/(double) (l*w));
|
|
|
|
|
int i =(layersCount*(h-1))+(int) Math.min(Math.round(area/(double) (l*w)),layersCount);
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据点集合生成图像,并计算不同颜色区域的面积
|
|
|
|
|
*/
|
|
|
|
|
public static Double drawPointsAndCalculateArea(
|
|
|
|
|
List<double[]> points,String taskId,PcdPojo pojo
|
|
|
|
|
) throws Exception {
|
|
|
|
|
int imageWidth = 600;
|
|
|
|
|
int imageHeight = 600;
|
|
|
|
|
String drawMode= "point";
|
|
|
|
|
|
|
|
|
|
if (points == null || points.isEmpty()) {
|
|
|
|
|
return 0d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 1: 找出 x 和 y 的最大最小值
|
|
|
|
|
double minX = pojo.getMinBounds()[0] -20;
|
|
|
|
|
double maxX = pojo.getMaxBounds()[0]+20;
|
|
|
|
|
|
|
|
|
|
double minY = pojo.getMinBounds()[1]-20;
|
|
|
|
|
double maxY = pojo.getMaxBounds()[1]+20;
|
|
|
|
|
|
|
|
|
|
for (double[] point : points) {
|
|
|
|
|
minX = Math.min(minX, point[0]);
|
|
|
|
|
maxX = Math.max(maxX, point[0]);
|
|
|
|
|
minY = Math.min(minY, point[1]);
|
|
|
|
|
maxY = Math.max(maxY, point[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 2: 计算偏移量,使得所有坐标非负
|
|
|
|
|
double xOffset = minX < 0 ? -minX : 0;
|
|
|
|
|
double yOffset = minY < 0 ? -minY : 0;
|
|
|
|
|
|
|
|
|
|
// Step 3: 缩放比例
|
|
|
|
|
double scaleX = imageWidth / (maxX - minX + 1e-9);
|
|
|
|
|
double scaleY = imageHeight / (maxY - minY + 1e-9);
|
|
|
|
|
|
|
|
|
|
// Step 4: 创建图像
|
|
|
|
|
BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
|
|
|
|
|
Graphics2D g = image.createGraphics();
|
|
|
|
|
g.setBackground(Color.WHITE);
|
|
|
|
|
g.clearRect(0, 0, imageWidth, imageHeight);
|
|
|
|
|
|
|
|
|
|
// Step 5: 绘制点或连线
|
|
|
|
|
List<PointColorMapping> mappedPoints = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
for (double[] point : points) {
|
|
|
|
|
Color color = Color.RED;
|
|
|
|
|
double x = point[0];
|
|
|
|
|
double y = point[1];
|
|
|
|
|
|
|
|
|
|
int px = (int) ((x + xOffset) * scaleX);
|
|
|
|
|
int py = (int) ((y + yOffset) * scaleY);
|
|
|
|
|
|
|
|
|
|
mappedPoints.add(new PointColorMapping(new double[]{x, y}, color));
|
|
|
|
|
|
|
|
|
|
if ("point".equalsIgnoreCase(drawMode)) {
|
|
|
|
|
g.setColor(color);
|
|
|
|
|
g.fillRect(px, py, 8, 8); // 点模式
|
|
|
|
|
} else if ("line".equalsIgnoreCase(drawMode)) {
|
|
|
|
|
// 只有在连线模式下才记录点用于后续连线
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果是连线模式,按 x 排序后连接相邻点
|
|
|
|
|
if ("line".equalsIgnoreCase(drawMode)) {
|
|
|
|
|
mappedPoints.sort(Comparator.comparingDouble(p -> p.point[0]));
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < mappedPoints.size() - 1; i++) {
|
|
|
|
|
PointColorMapping p1 = mappedPoints.get(i);
|
|
|
|
|
PointColorMapping p2 = mappedPoints.get(i + 1);
|
|
|
|
|
|
|
|
|
|
int x1 = (int) ((p1.point[0] + xOffset) * scaleX);
|
|
|
|
|
int y1 = (int) ((p1.point[1] + yOffset) * scaleY);
|
|
|
|
|
int x2 = (int) ((p2.point[0] + xOffset) * scaleX);
|
|
|
|
|
int y2 = (int) ((p2.point[1] + yOffset) * scaleY);
|
|
|
|
|
|
|
|
|
|
g.setColor(p1.color);
|
|
|
|
|
g.drawLine(x1, y1, x2, y2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g.dispose();
|
|
|
|
|
|
|
|
|
|
// Step 6: 统计每种颜色的像素数量
|
|
|
|
|
Map<Color, Integer> colorCount = new HashMap<>();
|
|
|
|
|
Integer totalPixels = 0;
|
|
|
|
|
for (int y = 0; y < imageHeight; y++) {
|
|
|
|
|
for (int x = 0; x < imageWidth; x++) {
|
|
|
|
|
int rgb = image.getRGB(x, y);
|
|
|
|
|
if (rgb == Color.WHITE.getRGB()) continue;
|
|
|
|
|
|
|
|
|
|
Color color = new Color(rgb);
|
|
|
|
|
totalPixels++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 7: 换算像素数为实际面积
|
|
|
|
|
double pixelToAreaRatio = (maxX - minX) * (maxY - minY) / (imageWidth * imageHeight);
|
|
|
|
|
double area = totalPixels * pixelToAreaRatio;
|
|
|
|
|
|
|
|
|
|
// 可选:保存图像
|
|
|
|
|
ImageIO.write(image, "PNG", generateImageFilePath().toFile());
|
|
|
|
|
|
|
|
|
|
return area;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 生成 E:/data/pcdImage/yyyy-MM-dd/HHmmssSSS.png 格式的路径
|
|
|
|
|
* 并创建父目录(如果不存在)
|
|
|
|
|
*/
|
|
|
|
|
public static Path generateImageFilePath() throws IOException {
|
|
|
|
|
// 定义基础路径
|
|
|
|
|
String basePath = "E:/data/pcdImage";
|
|
|
|
|
|
|
|
|
|
// 获取当前日期和时间
|
|
|
|
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
|
|
SimpleDateFormat timeFormat = new SimpleDateFormat("HH_mm_ss_SSS");
|
|
|
|
|
|
|
|
|
|
String dateFolder = dateFormat.format(new Date());
|
|
|
|
|
String fileName = timeFormat.format(new Date()) + ".png";
|
|
|
|
|
|
|
|
|
|
// 构建完整路径
|
|
|
|
|
Path fullPath = Paths.get(basePath, dateFolder, fileName);
|
|
|
|
|
|
|
|
|
|
// 创建父目录(如果不存在)
|
|
|
|
|
Path parentDir = fullPath.getParent();
|
|
|
|
|
if (parentDir != null && !Files.exists(parentDir)) {
|
|
|
|
|
Files.createDirectories(parentDir);
|
|
|
|
|
System.out.println("创建目录: " + parentDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fullPath;
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
// // 示例调用方法
|
|
|
|
|
// public static void main(String[] args) throws Exception {
|
|
|
|
|
// List<double[]> points = new ArrayList<>();
|
|
|
|
|
// // 示例数据
|
|
|
|
|
// for (int i = 0; i < 100; i++) {
|
|
|
|
|
// double x = Math.sin(i * 0.1) * 10;
|
|
|
|
|
// double y = Math.cos(i * 0.1) * 10;
|
|
|
|
|
// points.add(new double[]{x, y});
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// // 使用 lambda 设置颜色规则(示例:红色)
|
|
|
|
|
// Function<double[], Color> colorFunc = point -> Color.RED;
|
|
|
|
|
//
|
|
|
|
|
// Map<Color, Double> result = drawPointsAndCalculateArea(points,"" );
|
|
|
|
|
//
|
|
|
|
|
// for (Map.Entry<Color, Double> entry : result.entrySet()) {
|
|
|
|
|
// System.out.println("颜色: " + entry.getKey() + ", 面积: " + entry.getValue());
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|