no message
parent
2566ff544b
commit
f521e2cb73
|
|
@ -26,10 +26,8 @@ import org.cpte.modules.receive.mapper.AsnMapper;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 扫描托盘处理
|
||||
|
|
@ -204,14 +202,16 @@ public class ScanTrayProcessor {
|
|||
//2.获取所有可用库位
|
||||
availablePoints = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), areaCode);
|
||||
}
|
||||
//根据巷到分组,得到每个巷道有多个库位,<巷道编号,库位个数>
|
||||
Map<String, Long> colMap = getColMap(areaCode);
|
||||
|
||||
List<PointScore> scoredPoints = availablePoints.stream()
|
||||
.map(point -> clusterPointScore(point, station, itemKeys))
|
||||
.map(point -> clusterPointScore(point, station, itemKeys, colMap))
|
||||
.sorted(Comparator.comparing(PointScore::getScore).reversed())
|
||||
.limit(50)
|
||||
.toList();
|
||||
|
||||
if (!scoredPoints.isEmpty()) {
|
||||
log.info("最优【{}】库位评分结果:{}", scoredPoints.get(0).getPoint().getPointCode(), scoredPoints.get(0).getScore());
|
||||
return scoredPoints.get(0).getPoint();
|
||||
}
|
||||
|
||||
|
|
@ -221,17 +221,17 @@ public class ScanTrayProcessor {
|
|||
/**
|
||||
* 库位评分计算
|
||||
*/
|
||||
private PointScore clusterPointScore(Point point, Point station, List<ItemKey> itemKeys) {
|
||||
private PointScore clusterPointScore(Point point, Point station, List<ItemKey> itemKeys, Map<String, Long> colMap) {
|
||||
double totalScore;
|
||||
|
||||
// 1. 距离评分 - 考虑从入库口到库位的距离
|
||||
double distanceScore = calculateClusterDistanceCost(point, station) * 0.3;// 权重30%
|
||||
|
||||
// 2. 通道深度策略评分 - 新增核心策略
|
||||
double channelDepthScore = calculateChannelDepthScore(point) * 0.25; // 权重25%
|
||||
double channelDepthScore = calculateChannelDepthScore(point, colMap) * 0.25; // 权重25%
|
||||
|
||||
// 3. 通道类型评分 - 双通道优先
|
||||
double channelScore = calculateChannelScore(point) * 0.15; // 权重15%
|
||||
double channelScore = calculateChannelScore(point) * 0.2; // 权重20%
|
||||
|
||||
// 4. 均衡评分 - 避免热点区域
|
||||
// double balanceScore = calculateBalanceScore(point) * 0.1; // 权重10%
|
||||
|
|
@ -239,47 +239,64 @@ public class ScanTrayProcessor {
|
|||
// 5. 物料聚集潜力评分 - 新增
|
||||
// double clusterPotentialScore = calculateClusterPotentialScore(point, itemKeys) * 0.2; // 权重20%
|
||||
|
||||
totalScore = distanceScore + channelDepthScore + channelScore ;
|
||||
totalScore = distanceScore + channelDepthScore + channelScore;
|
||||
log.info("【{}】库位总分:{} - 距离评分: {} - 通道深度策略评分: {} - 通道类型评分: {} - 均衡评分: {} - 物料聚集评分: {}", point.getPointCode(), totalScore, distanceScore, channelDepthScore, channelScore, 0, 0);
|
||||
return new PointScore(point, totalScore);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通道深度策略评分 - 核心优化
|
||||
* 双通道:中间优先(04),向两端扩展
|
||||
* 单通道:深度优先(07),向前扩展
|
||||
* 通道深度策略评分 - 核心优化(动态深度)
|
||||
* 双通道:中间优先,向两端扩展
|
||||
* 单通道:深度优先,越靠里分数越高
|
||||
*/
|
||||
private double calculateChannelDepthScore(Point point) {
|
||||
private double calculateChannelDepthScore(Point point, Map<String, Long> colMap) {
|
||||
// 获取当前巷道的最大深度
|
||||
Long maxDepth = colMap.get(point.getColNum());
|
||||
if (point.getIzDoubleLane().equals(1)) {
|
||||
// 双通道策略:中间优先,得分 04 > 03=05 > 02=06 > 01=07
|
||||
return doubleChannelDepthScore(Integer.parseInt(point.getRowNum()));
|
||||
return doubleChannelDepthScore(Integer.parseInt(point.getRowNum()), maxDepth);
|
||||
} else {
|
||||
// 单通道策略:深度优先,得分 07 > 06 > 05 > 04 > 03 > 02 > 01
|
||||
return singleChannelDepthScore(Integer.parseInt(point.getRowNum()));
|
||||
return singleChannelDepthScore(Integer.parseInt(point.getRowNum()), maxDepth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 双通道深度评分
|
||||
* 理想顺序:04 > 03=05 > 02=06 > 01=07
|
||||
* 双通道深度评分(动态深度)
|
||||
* 策略:中间位置最优,向两端递减
|
||||
*/
|
||||
private double doubleChannelDepthScore(int depth) {
|
||||
return switch (depth) {
|
||||
case 4 -> 100; // 最优位置
|
||||
case 3, 5 -> 85; // 次优位置
|
||||
case 2, 6 -> 70; // 良好位置
|
||||
case 1, 7 -> 60; // 一般位置
|
||||
default -> 50;
|
||||
};
|
||||
private double doubleChannelDepthScore(int depth, long maxDepth) {
|
||||
// 计算中间位置
|
||||
long middle = (maxDepth + 1) / 2;
|
||||
|
||||
// 对于偶数深度,中间两个位置分数相同
|
||||
if (maxDepth % 2 == 0) {
|
||||
if (depth == middle || depth == middle + 1) {
|
||||
return 100; // 中间最优位置
|
||||
}
|
||||
} else {
|
||||
if (depth == middle) {
|
||||
return 100; // 中间最优位置
|
||||
}
|
||||
}
|
||||
|
||||
// 计算距离中心的偏离程度,偏离越大分数越低
|
||||
double center = (maxDepth + 1) / 2.0;
|
||||
double distanceFromCenter = Math.abs(depth - center);
|
||||
|
||||
// 根据巷道深度调整评分递减幅度,确保评分在合理范围内
|
||||
double maxDistance = Math.max(center - 1, maxDepth - center);
|
||||
if (maxDistance == 0) return 100; // 只有一个位置的情况
|
||||
|
||||
// 使用线性递减,确保边缘位置仍有合理分数
|
||||
return 100 - (distanceFromCenter / maxDistance) * 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单通道深度评分
|
||||
* 理想顺序:07 > 06 > 05 > 04 > 03 > 02 > 01
|
||||
* 单通道深度评分(动态深度)
|
||||
* 策略:深度越大(越靠里)分数越高
|
||||
*/
|
||||
private double singleChannelDepthScore(int depth) {
|
||||
// 深度越大分数越高,07得100分,01得14分
|
||||
return depth * 100.0 / 7;
|
||||
private double singleChannelDepthScore(int depth, long maxDepth) {
|
||||
// 深度越大分数越高,按比例计算
|
||||
return depth * 100.0 / maxDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -392,8 +409,21 @@ public class ScanTrayProcessor {
|
|||
private double calculateClusterDistanceCost(Point point, Point station) {
|
||||
// 计算曼哈顿距离
|
||||
double distance = Math.abs(point.getPositionX() - station.getPositionX()) + Math.abs(point.getPositionY() - station.getPositionY());
|
||||
|
||||
// 使用更大的标准化参数(根据实际坐标范围)
|
||||
double normalizationFactor = 250000.0; // 或使用动态计算的最大距离值
|
||||
// 距离越小分数越高
|
||||
return Math.max(0, 100 - (distance / 100.0));
|
||||
return Math.max(0, 100 - (distance / normalizationFactor) * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每个巷道的库位个数
|
||||
*
|
||||
* @param areaCode 库区
|
||||
* @return Map<巷道编码, 库位个数>
|
||||
*/
|
||||
private Map<String, Long> getColMap(String areaCode) {
|
||||
List<Point> pointList = pointMapper.queryPoints(null, null, areaCode);
|
||||
return pointList.stream().collect(Collectors.groupingBy(Point::getColNum, Collectors.counting()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,10 +76,10 @@ public class ReceiveBackProcessor {
|
|||
parameterValue1.setValue(List.of(task));
|
||||
|
||||
SMOMRequest.ParameterValue2 parameterValue2 = new SMOMRequest.ParameterValue2();
|
||||
parameterValue2.setValue(1);
|
||||
parameterValue2.setValue(2);
|
||||
|
||||
SMOMRequest.Context context = new SMOMRequest.Context();
|
||||
context.setInvOrgId(1);
|
||||
context.setInvOrgId(2);
|
||||
context.setTicket(ticket);
|
||||
|
||||
SMOMRequest saiWmsRequest = new SMOMRequest();
|
||||
|
|
|
|||
|
|
@ -84,10 +84,10 @@ public class PickBackProcessor {
|
|||
parameterValue1.setValue(List.of(taskReq));
|
||||
|
||||
SMOMRequest.ParameterValue2 parameterValue2 = new SMOMRequest.ParameterValue2();
|
||||
parameterValue2.setValue(1);
|
||||
parameterValue2.setValue(2);
|
||||
|
||||
SMOMRequest.Context context = new SMOMRequest.Context();
|
||||
context.setInvOrgId(1);
|
||||
context.setInvOrgId(2);
|
||||
context.setTicket(ticket);
|
||||
|
||||
SMOMRequest saiWmsRequest = new SMOMRequest();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class SwmsLoginUtil {
|
|||
private OpenApiMapper openApiMapper;
|
||||
|
||||
public String loginJson() {
|
||||
String userName = "LM";
|
||||
String userName = "LIKU";
|
||||
String password = "654321";
|
||||
|
||||
SMOMRequest.ParameterValue3 parameterValue1 = new SMOMRequest.ParameterValue3();
|
||||
|
|
|
|||
Loading…
Reference in New Issue