package com.moral.api.service.impl;
import com.moral.api.entity.RadarHourlySummary;
import com.moral.api.mapper.RadarHourlySummaryMapper;
import com.moral.api.service.HistorySecondRadarService;
import com.moral.api.service.RadarHourlySummaryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
*
* 雷达小时汇总表 服务实现类
*
*
* @author moral
* @since 2026-09-08
*/
@Service
public class RadarHourlySummaryServiceImpl extends ServiceImpl implements RadarHourlySummaryService {
@Autowired
private HistorySecondRadarService radarService;
private static final double HEIGHT_STEP = 7.5;
private static final int PEAK_SEARCH_LIMIT = 200;
private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00");
@Override
public void processLastHour() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime prev = now.minusHours(1).withMinute(0).withSecond(0).withNano(0);
processHour(prev.format(FMT));
}
@Override
public void processHour(String hourStart) {
String hourEnd = nextHour(hourStart);
List rawList = radarService.queryRawDataByHour(hourStart, hourEnd);
if (rawList.isEmpty()) {
return ;
}
// 提取 a34004 / a34002
List a34004List = new ArrayList<>();
List a34002List = new ArrayList<>();
for (String json : rawList) {
a34004List.add(extractJsonField(json, "a34004-Avg"));
a34002List.add(extractJsonField(json, "a34002-Avg"));
}
double[] avg04 = averageByHeight(a34004List);
double[] avg02 = averageByHeight(a34002List);
R r04 = analyze(avg04);
R r02 = analyze(avg02);
RadarHourlySummary entity = new RadarHourlySummary();
entity.setTime(LocalDateTime.parse(hourStart, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
entity.setRadarData(buildRadarJson(avg04, avg02));
entity.setA34004PeakHeight(BigDecimal.valueOf(r04.peak));
entity.setA34004DropHeight(BigDecimal.valueOf(r04.drop));
entity.setA34002PeakHeight(BigDecimal.valueOf(r02.peak));
entity.setA34002DropHeight(BigDecimal.valueOf(r02.drop));
this.baseMapper.insert(entity);
}
// ======================== 算法 ========================
private double[] averageByHeight(List rawList) {
List rows = new ArrayList<>();
int minLen = Integer.MAX_VALUE;
for (String s : rawList) {
double[] arr = parseToArray(s);
rows.add(arr);
if (arr.length < minLen) minLen = arr.length;
}
double[] avg = new double[minLen];
int n = rows.size();
for (int i = 0; i < minLen; i++) {
double sum = 0;
for (double[] row : rows) sum += row[i];
BigDecimal bd = new BigDecimal(String.valueOf(sum / n));
BigDecimal resultBd = bd.setScale(2, RoundingMode.HALF_UP);
avg[i] =resultBd.doubleValue();
}
return avg;
}
private R analyze(double[] values) {
int searchEnd = Math.min(PEAK_SEARCH_LIMIT, values.length);
int peakIdx = 0;
double peakVal = values[0];
for (int i = 1; i < searchEnd; i++) {
if (values[i] > peakVal) { peakVal = values[i]; peakIdx = i; }
}
double peakHeight = peakIdx * HEIGHT_STEP;
System.out.println("最大值 》》》》》》》"+values[peakIdx]+" 》》》》最大高度>>>>>"+peakHeight+" 》》》》最大高度位置>>>>>"+peakIdx);
int dropIdx = -1;
if(PEAK_SEARCH_LIMIT-peakIdx == 1){
searchEnd = searchEnd+60;
}
double base = findBaseValue(values, peakIdx, searchEnd);
for (int i = peakIdx + 1; i < searchEnd; i++) {
if (values[i] <= base * 1.05) { dropIdx = i; break; }
}
double dropHeight = dropIdx > 0 ? dropIdx * HEIGHT_STEP : 0;
System.out.println("最小值 》》》》》》》"+values[dropIdx]+" 》》》》最小高度>>>>>"+dropHeight+" 米 》》》》最小高度位置>>>>>"+dropIdx);
return new R(peakHeight, dropHeight);
}
private double findBaseValue(double[] values, int peakIdx, int end) {
List tail = new ArrayList<>();
for (int i = peakIdx + 1; i < end; i++) tail.add(values[i]);
if (tail.isEmpty()) return 0;
Collections.sort(tail);
if (tail.size() >= 2) {
double a = tail.get(0), b = tail.get(1);
if (b - a > 2.0 || (a > 0 && b / a > 1.5)) return b;
}
return tail.get(0);
}
// ======================== 工具 ========================
private String extractJsonField(String json, String field) {
String key = "\"" + field + "\"";
int s = json.indexOf(key);
if (s == -1) return "";
s = json.indexOf(":", s) + 1;
while (s < json.length() && (json.charAt(s) == ' ' || json.charAt(s) == '"')) s++;
int e = json.indexOf("\"", s);
if (e == -1) e = json.indexOf(",", s);
if (e == -1) e = json.indexOf("}", s);
if (e == -1) return "";
while (e > s && json.charAt(e - 1) == '"') e--;
return json.substring(s, e);
}
private double[] parseToArray(String raw) {
if (raw == null || raw.isEmpty()) return new double[0];
String[] parts = raw.split("\\*");
double[] arr = new double[parts.length];
for (int i = 0; i < parts.length; i++) {
try { arr[i] = Double.parseDouble(parts[i]); }
catch (NumberFormatException e) { arr[i] = 0; }
}
return arr;
}
private String buildRadarJson(double[] a04, double[] a02) {
StringBuilder sb = new StringBuilder("{\"a34004-Avg\":[");
for (int i = 0; i < a04.length; i++) {
if (i > 0) sb.append(",");
sb.append(String.format("%.6f", a04[i]));
}
sb.append("],\"a34002-Avg\":[");
for (int i = 0; i < a02.length; i++) {
if (i > 0) sb.append(",");
sb.append(String.format("%.6f", a02[i]));
}
sb.append("]}");
return sb.toString();
}
private String nextHour(String timeStr) {
LocalDateTime time = LocalDateTime.parse(timeStr, FMT);
LocalDateTime nextTime = time.plusHours(1);
return nextTime.format(FMT);
}
static class R {
double peak, drop;
R(double peak, double drop) { this.peak = peak; this.drop = drop; }
}
}