Commit 237eeaf1 by huangjinxin

Merge remote-tracking branch 'origin/develop' into develop

2 parents 99031334 c5885899
...@@ -11,6 +11,8 @@ import org.gavaghan.geodesy.GlobalCoordinates; ...@@ -11,6 +11,8 @@ import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -59,13 +61,13 @@ public class GeoDistanceCalculator { ...@@ -59,13 +61,13 @@ public class GeoDistanceCalculator {
} }
} }
private Map<Location, Map<Location, Pair>> calculateBulkDistanceDuration(Collection<Location> fromLocations, Collection<Location> toLocations) { private Map<Location, Map<Location, Pair>> calculateBulkDistanceDuration(Collection<Location> fromLocations, Collection<Location> toLocations, Integer vehicleType) {
return fromLocations.stream().collect(Collectors.toMap( return fromLocations.stream().collect(Collectors.toMap(
Function.identity(), Function.identity(),
from -> toLocations.stream().collect(Collectors.toMap( from -> toLocations.stream().collect(Collectors.toMap(
Function.identity(), Function.identity(),
to -> { to -> {
Distance distance = RoadDistanceUtils.getDistance(from, to); Distance distance = RoadDistanceUtils.getDistance(from, to, vehicleType);
long path = (long) distance.getDis(); long path = (long) distance.getDis();
long time = distance.getTime(); long time = distance.getTime();
return new Pair(path, time); return new Pair(path, time);
...@@ -74,18 +76,17 @@ public class GeoDistanceCalculator { ...@@ -74,18 +76,17 @@ public class GeoDistanceCalculator {
)); ));
} }
public void initDistanceMaps(Collection<Location> locationList) { public void initDistanceMaps(Collection<Location> locationList, List<Integer> vehicleTypes) {
Map<Location, Map<Location, Pair>> distanceMatrix = calculateBulkDistanceDuration(locationList, locationList); for (Integer vehicleType: vehicleTypes) {
locationList.forEach(location -> { Map<Location, Map<Location, Pair>> distanceMatrix = calculateBulkDistanceDuration(locationList, locationList, vehicleType);
Map<Location, Pair> mapPair = distanceMatrix.get(location); locationList.forEach(location -> {
mapPair.forEach((loc2, pair) -> { Map<Location, Pair> mapPair = distanceMatrix.get(location);
location.getDistanceMap().put(loc2, pair.Distance); mapPair.forEach((loc2, pair) -> {
location.getDistanceTimeMap().put(loc2, pair.Duration); location.getDistanceMap(vehicleType).put(loc2, pair.Distance);
location.getDistanceTimeMap(vehicleType).put(loc2, pair.Duration);
});
}); });
}
});
} }
} }
......
...@@ -51,6 +51,9 @@ public class DispatchEngineer implements Serializable { ...@@ -51,6 +51,9 @@ public class DispatchEngineer implements Serializable {
@Column(name = "max_distance") @Column(name = "max_distance")
private Integer maxDistance; private Integer maxDistance;
@Column(name = "vehicle_type")
private Integer vehicleType;
private String ext = ""; private String ext = "";
......
...@@ -131,9 +131,9 @@ public class Customer { ...@@ -131,9 +131,9 @@ public class Customer {
// throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet."); // throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet.");
} }
if (previousCustomer == null) { if (previousCustomer == null) {
return technician.getDepot().getLocation().getDistanceTo(location); return technician.getDepot().getLocation().getDistanceTo(technician.getVehicleType(),location);
} }
return previousCustomer.getLocation().getDistanceTo(location); return previousCustomer.getLocation().getDistanceTo(technician.getVehicleType(),location);
} }
/** /**
...@@ -147,9 +147,9 @@ public class Customer { ...@@ -147,9 +147,9 @@ public class Customer {
// throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet."); // throw new IllegalStateException("This method must not be called when the shadow variables are not initialized yet.");
} }
if (previousCustomer == null) { if (previousCustomer == null) {
return technician.getDepot().getLocation().getPathTimeTo(location); return technician.getDepot().getLocation().getPathTimeTo(technician.getVehicleType(),location);
} }
return previousCustomer.getLocation().getPathTimeTo(location); return previousCustomer.getLocation().getPathTimeTo(technician.getVehicleType(),location);
} }
@Override @Override
......
...@@ -24,10 +24,26 @@ public class Location { ...@@ -24,10 +24,26 @@ public class Location {
private double latitude; private double latitude;
private double longitude; private double longitude;
// 汽车路网矩阵
@JsonIgnore @JsonIgnore
private Map<Location, Long> distanceMap = new HashMap<Location, Long>();// 路网距离矩阵 private Map<Location, Long> carDistanceMap = new HashMap<Location, Long>();// 路网距离矩阵
@JsonIgnore @JsonIgnore
private Map<Location, Long> distanceTimeMap = new HashMap<Location, Long>();// 路网时间矩阵 private Map<Location, Long> carDistanceTimeMap = new HashMap<Location, Long>();// 路网时间矩阵
// 电动车路网矩阵
@JsonIgnore
private Map<Location, Long> electricBicycleDistanceMap = new HashMap<Location, Long>();// 路网距离矩阵
@JsonIgnore
private Map<Location, Long> electricBicycleDistanceTimeMap = new HashMap<Location, Long>();// 路网时间矩阵
// 自行车路网矩阵
@JsonIgnore
private Map<Location, Long> bicycleDistanceMap = new HashMap<Location, Long>();// 路网距离矩阵
@JsonIgnore
private Map<Location, Long> bicycleDistanceTimeMap = new HashMap<Location, Long>();// 路网时间矩阵
// 步行路网矩阵
@JsonIgnore
private Map<Location, Long> walkDistanceMap = new HashMap<Location, Long>();// 路网距离矩阵
@JsonIgnore
private Map<Location, Long> walkDistanceTimeMap = new HashMap<Location, Long>();// 路网时间矩阵
public Location(long id) { public Location(long id) {
this.id = id; this.id = id;
...@@ -47,36 +63,101 @@ public class Location { ...@@ -47,36 +63,101 @@ public class Location {
this.latitude = latitude; this.latitude = latitude;
} }
/**
* Set the distance map. Distances are in meters.
*
* @param distanceMap a map containing distances from here to other locations
*/
public void setDistanceMap(Map<Location, Long> distanceMap) {
this.distanceMap = distanceMap;
}
/** /**
* Distance to the given location in meters. * 根据不同交通方式返回不同距离
* *
* @param location other location * @param vehicleType
* @return distance in meters * @param location
* @return
*/ */
public long getDistanceTo(Location location) { public long getDistanceTo(Integer vehicleType, Location location) {
return distanceMap.get(location); if (null == vehicleType) {
} return carDistanceMap.get(location);
}
switch (vehicleType) {
case 1:
return carDistanceMap.get(location);
case 2:
return electricBicycleDistanceMap.get(location);
case 3:
return bicycleDistanceMap.get(location);
case 4:
return walkDistanceMap.get(location);
}
return carDistanceMap.get(location);
}
public Map<Location, Long> getDistanceMap(Integer vehicleType) {
if (null == vehicleType) {
return carDistanceMap;
}
switch (vehicleType) {
case 1:
return carDistanceMap;
case 2:
return electricBicycleDistanceMap;
case 3:
return bicycleDistanceMap;
case 4:
return walkDistanceMap;
}
return carDistanceMap;
}
public Map<Location, Long> getDistanceTimeMap(Integer vehicleType) {
if (null == vehicleType) {
return carDistanceTimeMap;
}
switch (vehicleType) {
case 1:
return carDistanceTimeMap;
case 2:
return electricBicycleDistanceTimeMap;
case 3:
return bicycleDistanceTimeMap;
case 4:
return walkDistanceTimeMap;
}
return carDistanceTimeMap;
}
public int getPathTimeTo(Integer vehicleType, Location location) {
if (null == vehicleType) {
return carDistanceTimeMap.get(location).intValue() / 60;
}
switch (vehicleType) {
case 1:
return carDistanceTimeMap.get(location).intValue() / 60;
case 2:
return electricBicycleDistanceTimeMap.get(location).intValue() / 60;
case 3:
return bicycleDistanceTimeMap.get(location).intValue() / 60;
case 4:
return walkDistanceTimeMap.get(location).intValue() / 60;
}
return carDistanceTimeMap.get(location).intValue() / 60;
}
/** /**
* time to the given location in minutes. * time to the given location in minutes.
* *
* @param location other location * @param location other location
* @return time in minutes * @return time in minutes
*/ */
public int getPathTimeTo(Location location) { public int getCarPathTimeTo(Location location) {
return distanceTimeMap.get(location).intValue()/60; return carDistanceTimeMap.get(location).intValue() / 60;
}
public int getElectricBicyclePathTimeTo(Location location) {
return electricBicycleDistanceTimeMap.get(location).intValue() / 60;
}
public int getBicyclePathTimeTo(Location location) {
return bicycleDistanceTimeMap.get(location).intValue() / 60;
}
public int getWalkDathTimeTo(Location location) {
return walkDistanceTimeMap.get(location).intValue() / 60;
} }
// ************************************************************************ // ************************************************************************
...@@ -110,5 +191,4 @@ public class Location { ...@@ -110,5 +191,4 @@ public class Location {
'}'; '}';
} }
} }
...@@ -44,6 +44,9 @@ public class Technician { ...@@ -44,6 +44,9 @@ public class Technician {
// 单位是米,这里要注意 // 单位是米,这里要注意
private int maxDistanceMeter; private int maxDistanceMeter;
// 交通方式 1汽车;2电动车;3自行车;4步行 默认是汽车
private Integer vehicleType;
@PlanningListVariable @PlanningListVariable
private List<Customer> customerList = new ArrayList<>(); private List<Customer> customerList = new ArrayList<>();
...@@ -76,6 +79,20 @@ public class Technician { ...@@ -76,6 +79,20 @@ public class Technician {
this.maxDistanceMeter = maxDistanceMeter; this.maxDistanceMeter = maxDistanceMeter;
this.preferredlocationDistanceMap = preferredlocationDistanceMap; this.preferredlocationDistanceMap = preferredlocationDistanceMap;
} }
public Technician(long id, String code, int maxCount, int maxMinute, int maxDistanceMeter, Integer vehicleType, Depot depot,
int startTime, int endTime, Set<String> skills, Map<String, Long> preferredlocationDistanceMap) {
this.id = id;
this.code = code;
this.depot = depot;
this.startTime = startTime;
this.endTime = endTime;
this.skills = skills;
this.maxCount = maxCount;
this.maxMinute = maxMinute;
this.maxDistanceMeter = maxDistanceMeter;
this.preferredlocationDistanceMap = preferredlocationDistanceMap;
}
// ************************************************************************ // ************************************************************************
// Complex methods // Complex methods
...@@ -114,10 +131,10 @@ public class Technician { ...@@ -114,10 +131,10 @@ public class Technician {
Location previousLocation = depot.getLocation(); Location previousLocation = depot.getLocation();
for (Customer customer : customerList) { for (Customer customer : customerList) {
totalDistance += previousLocation.getDistanceTo(customer.getLocation()); totalDistance += previousLocation.getDistanceTo(this.getVehicleType(),customer.getLocation());
previousLocation = customer.getLocation(); previousLocation = customer.getLocation();
} }
totalDistance += previousLocation.getDistanceTo(depot.getLocation()); totalDistance += previousLocation.getDistanceTo(this.getVehicleType(), depot.getLocation());
return totalDistance; return totalDistance;
} }
......
...@@ -210,8 +210,8 @@ public class BatchServiceImpl implements BatchService { ...@@ -210,8 +210,8 @@ public class BatchServiceImpl implements BatchService {
jdbcTemplate.update("delete from dispatch_order where team_id=? and batch_no=?", teamId, batchNo); jdbcTemplate.update("delete from dispatch_order where team_id=? and batch_no=?", teamId, batchNo);
log.info("写入新批次技术员、工单数据, teamId:{}, day:{}, batchNo:{}", teamId, batchDay, batchNo); log.info("写入新批次技术员、工单数据, teamId:{}, day:{}, batchNo:{}", teamId, batchDay, batchNo);
String sqlEngineer = "INSERT INTO dispatch_engineer (team_id, batch_no, engineer_code, engineer_name, x, y, max_num, max_minute, max_distance)\n" String sqlEngineer = "INSERT INTO dispatch_engineer (team_id, batch_no, engineer_code, engineer_name, x, y, max_num, max_minute, max_distance, vehicle_type)\n"
+ "SELECT o.team_id,?,o.engineer_code, a.name , b.x, b.y , max_num, max_minute, max_distance FROM `org_team_engineer` o,engineer_info a,engineer_business b \r\n" + "SELECT o.team_id,?,o.engineer_code, a.name , b.x, b.y , max_num, max_minute, max_distance, b.vehicle FROM `org_team_engineer` o,engineer_info a,engineer_business b \r\n"
+ " WHERE o.team_id=? AND `status`=1\r\n" + " WHERE o.team_id=? AND `status`=1\r\n"
+ " AND o.engineer_code=a.engineer_code AND a.engineer_code = b.engineer_code \r\n" + " AND o.engineer_code=a.engineer_code AND a.engineer_code = b.engineer_code \r\n"
+ " AND b.x IS NOT NULL AND b.x !=''" + " order by a.engineer_code asc"; + " AND b.x IS NOT NULL AND b.x !=''" + " order by a.engineer_code asc";
......
...@@ -85,107 +85,108 @@ public class SolveServiceImpl implements SolveService { ...@@ -85,107 +85,108 @@ public class SolveServiceImpl implements SolveService {
// 按小组、批次号组装问题对象 // 按小组、批次号组装问题对象
@Override @Override
public DispatchSolution prepareSolution(String groupId, String batchNo) { public DispatchSolution prepareSolution(String groupId, String batchNo) {
log.info("组织问题对象, groupId:{}, batchNo:{}", groupId, batchNo); return null;
// log.info("组织问题对象, groupId:{}, batchNo:{}", groupId, batchNo);
entityManager.clear(); //
// entityManager.clear();
// 统一出发地 //
Depot oneDepot; // // 统一出发地
Optional<OrgGroup> optional = groupRepository.findByGroupId(groupId); // Depot oneDepot;
if (optional.isEmpty()) { // Optional<OrgGroup> optional = groupRepository.findByGroupId(groupId);
log.error("组织问题对象, 未查询到组织信息 ,groupId:{}, batchNo:{}", groupId, batchNo); // if (optional.isEmpty()) {
throw new RuntimeException(String.format("组织问题对象, 未查询到组织信息 ,groupId:%s, batchNo:%s", groupId, batchNo)); // log.error("组织问题对象, 未查询到组织信息 ,groupId:{}, batchNo:{}", groupId, batchNo);
} // throw new RuntimeException(String.format("组织问题对象, 未查询到组织信息 ,groupId:%s, batchNo:%s", groupId, batchNo));
// }
OrgGroup oneGroup = optional.get(); //
Location deptLocation = new Location(oneGroup.getId(), oneGroup.getGroupId(), "起点", Double.parseDouble(oneGroup.getX()), Double.parseDouble(oneGroup.getY())); // OrgGroup oneGroup = optional.get();
oneDepot = new Depot(oneGroup.getId(), oneGroup.getGroupId(), deptLocation, 60 * 8, 60 * 18); // Location deptLocation = new Location(oneGroup.getId(), oneGroup.getGroupId(), "起点", Double.parseDouble(oneGroup.getX()), Double.parseDouble(oneGroup.getY()));
// oneDepot = new Depot(oneGroup.getId(), oneGroup.getGroupId(), deptLocation, 60 * 8, 60 * 18);
//
// customerlist //
ArrayList<Customer> customerList = new ArrayList<>(); // // customerlist
// 已分配和未分配一起排班,因为已分配会影响整体排班结果 // ArrayList<Customer> customerList = new ArrayList<>();
List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAll(groupId, batchNo); // // 已分配和未分配一起排班,因为已分配会影响整体排班结果
// List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findNotAssigned(groupId, batchNo); // List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAll(groupId, batchNo);
// // List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findNotAssigned(groupId, batchNo);
log.info("组织问题对象, dispatchorder-list, groupId:{}, batchNo:{}, dispatchorder-size:{}", groupId, batchNo, dispatchOrderList.size()); //
// log.info("组织问题对象, dispatchorder-list, groupId:{}, batchNo:{}, dispatchorder-size:{}", groupId, batchNo, dispatchOrderList.size());
if (dispatchOrderList.isEmpty()) { //
log.error("组织问题对象, 未查询到工单信息 ,groupId:{}, batchNo:{}", groupId, batchNo); // if (dispatchOrderList.isEmpty()) {
} // log.error("组织问题对象, 未查询到工单信息 ,groupId:{}, batchNo:{}", groupId, batchNo);
// }
dispatchOrderList.forEach(order -> { //
Location location = new Location(order.getId(), order.getOrderId(), "工单", Double.parseDouble(order.getX()), Double.parseDouble(order.getY())); // dispatchOrderList.forEach(order -> {
// Location location = new Location(order.getId(), order.getOrderId(), "工单", Double.parseDouble(order.getX()), Double.parseDouble(order.getY()));
LocalDateTime ldt1 = dateToLocalDateTime(order.getExpectTimeBegin()); //
LocalDateTime ldt2 = dateToLocalDateTime(order.getExpectTimeEnd()); // LocalDateTime ldt1 = dateToLocalDateTime(order.getExpectTimeBegin());
int start = 60 * 8; // LocalDateTime ldt2 = dateToLocalDateTime(order.getExpectTimeEnd());
int end = 60 * 18; // int start = 60 * 8;
if (ldt1 != null) { // int end = 60 * 18;
start = ldt1.getHour() * 60 + ldt1.getMinute(); // if (ldt1 != null) {
} // start = ldt1.getHour() * 60 + ldt1.getMinute();
if (ldt2 != null) { // }
end = ldt2.getHour() * 60 + ldt2.getMinute(); // if (ldt2 != null) {
} // end = ldt2.getHour() * 60 + ldt2.getMinute();
// }
//
// 40分钟兜低(技能未能正确匹配原因) FIXME 需要跟客户沟通 //
if (null == order.getTakeTime()) { // // 40分钟兜低(技能未能正确匹配原因) FIXME 需要跟客户沟通
order.setTakeTime(40); // if (null == order.getTakeTime()) {
} // order.setTakeTime(40);
if (null == order.getTags()) { // }
order.setTags(""); // if (null == order.getTags()) {
} // order.setTags("");
if (null == order.getPriority()) { // }
order.setPriority(0); // if (null == order.getPriority()) {
} // order.setPriority(0);
// }
Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime()); //
// Customer customer = new Customer(order.getId(), order.getOrderId(), order.getDt(), location, start, end, order.getSkills(), order.getTakeTime());
customerList.add(customer); //
}); // customerList.add(customer);
// });
log.info("组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}", groupId, batchNo, customerList.size()); //
// log.info("组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}", groupId, batchNo, customerList.size());
// technicianList //
ArrayList<Technician> technicianList = new ArrayList<>(); // // technicianList
dispatchEngineerRepo.findByGroupIdAndBatchNo(groupId, batchNo).forEach(engineer -> { // ArrayList<Technician> technicianList = new ArrayList<>();
Location location = new Location(engineer.getId(), engineer.getEngineerCode(), "中心点", Double.parseDouble(engineer.getX()), Double.parseDouble(engineer.getY())); // dispatchEngineerRepo.findByGroupIdAndBatchNo(groupId, batchNo).forEach(engineer -> {
// Depot depot = new Depot(engineer.getId(), engineer.getEngineerCode(), location, 60 * 8, 60 * 18); // Location location = new Location(engineer.getId(), engineer.getEngineerCode(), "中心点", Double.parseDouble(engineer.getX()), Double.parseDouble(engineer.getY()));
// depotList.add(depot); //// Depot depot = new Depot(engineer.getId(), engineer.getEngineerCode(), location, 60 * 8, 60 * 18);
//// depotList.add(depot);
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode()); //
List<String> skillList = queryEngineerSkills(engineer.getEngineerCode()); //// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode());
// List<String> skillList = queryEngineerSkills(engineer.getEngineerCode());
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{} , skills:{}", groupId, batchNo, engineer.getEngineerCode(), String.join(";", skillList)); //
//// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{} , skills:{}", groupId, batchNo, engineer.getEngineerCode(), String.join(";", skillList));
// 距离偏好map //
Map<String, Long> preferedLoctionDistanceMap = new HashMap<String, Long>(); // // 距离偏好map
customerList.forEach(customer -> { // Map<String, Long> preferedLoctionDistanceMap = new HashMap<String, Long>();
long distance = distanceCalculator.calculateDistance(location, customer.getLocation()); // customerList.forEach(customer -> {
preferedLoctionDistanceMap.put(customer.getCode(), distance); // long distance = distanceCalculator.calculateDistance(location, customer.getLocation());
}); // preferedLoctionDistanceMap.put(customer.getCode(), distance);
// });
Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), engineer.getMaxMinute(), engineer.getMaxDistance() * 1000, oneDepot, 60 * 8, 60 * 18, Set.copyOf(skillList), preferedLoctionDistanceMap); //
technicianList.add(vehicle); // Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), engineer.getMaxMinute(), engineer.getMaxDistance() * 1000, oneDepot, 60 * 8, 60 * 18, Set.copyOf(skillList), preferedLoctionDistanceMap);
}); // technicianList.add(vehicle);
// });
log.info("组织问题对象, depotList-list, groupId:{}, batchNo:{}", groupId, batchNo); //
log.info("组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}", groupId, batchNo, technicianList.size()); // log.info("组织问题对象, depotList-list, groupId:{}, batchNo:{}", groupId, batchNo);
// log.info("组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}", groupId, batchNo, technicianList.size());
// locationlist 起点+订单地点 //
List<Location> locationList = Stream.concat(Lists.newArrayList(oneDepot).stream().map(Depot::getLocation), customerList.stream().map(Customer::getLocation)).collect(Collectors.toList()); // // locationlist 起点+订单地点
// List<Location> locationList = Stream.concat(Lists.newArrayList(oneDepot).stream().map(Depot::getLocation), customerList.stream().map(Customer::getLocation)).collect(Collectors.toList());
DispatchSolution solution = new DispatchSolution(groupId, batchNo, locationList, oneDepot, technicianList, customerList); //
// DispatchSolution solution = new DispatchSolution(groupId, batchNo, locationList, oneDepot, technicianList, customerList);
// path 路网数据初始化,FIXME 需要专门路网数据缓存库 //
long time1 = System.currentTimeMillis(); // // path 路网数据初始化,FIXME 需要专门路网数据缓存库
distanceCalculator.initDistanceMaps(locationList); // long time1 = System.currentTimeMillis();
long time2 = System.currentTimeMillis(); // distanceCalculator.initDistanceMaps(locationList);
// long time2 = System.currentTimeMillis();
log.info("组织问题对象 done, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}, 路网耗时path:{}ms", groupId, batchNo, technicianList.size(), customerList.size(), locationList.size(), time2-time1); //
// log.info("组织问题对象 done, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}, 路网耗时path:{}ms", groupId, batchNo, technicianList.size(), customerList.size(), locationList.size(), time2-time1);
return solution; //
// return solution;
} }
...@@ -275,9 +276,12 @@ public class SolveServiceImpl implements SolveService { ...@@ -275,9 +276,12 @@ public class SolveServiceImpl implements SolveService {
preferedLoctionDistanceMap.put(customer.getCode(), distance); preferedLoctionDistanceMap.put(customer.getCode(), distance);
}); });
// FIXME 硬约束:电动车固定40km上限,其他无限制 // 硬约束:电动车固定40km上限,其他无限制
int maxDistance = engineer.getMaxDistance() * 1000;
Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), engineer.getMaxMinute(), engineer.getMaxDistance() * 1000, oneDepot, 60 * 8, 60 * 18, Set.copyOf(skillList), preferedLoctionDistanceMap); if (engineer.getVehicleType() != null && engineer.getVehicleType() == 2) {
maxDistance = 40 * 1000;
}
Technician vehicle = new Technician(engineer.getId(), engineer.getEngineerCode(), engineer.getMaxNum(), engineer.getMaxMinute(), maxDistance, engineer.getVehicleType() , oneDepot, 60 * 8, 60 * 18, Set.copyOf(skillList), preferedLoctionDistanceMap);
technicianList.add(vehicle); technicianList.add(vehicle);
}); });
...@@ -291,8 +295,12 @@ public class SolveServiceImpl implements SolveService { ...@@ -291,8 +295,12 @@ public class SolveServiceImpl implements SolveService {
// path 路网数据初始化,FIXME 需要专门路网数据缓存库 // path 路网数据初始化,FIXME 需要专门路网数据缓存库
long time1 = System.currentTimeMillis(); long time1 = System.currentTimeMillis();
distanceCalculator.initDistanceMaps(locationList); // 根据不同的交通工具,初始化不同的路网数据
long time2 = System.currentTimeMillis(); List<Integer> vehicleTypes = technicianList.stream()
.map(tec -> tec.getVehicleType() == null ? 1 : tec.getVehicleType()).distinct()
.collect(Collectors.toList());
distanceCalculator.initDistanceMaps(locationList, vehicleTypes);
long time2 = System.currentTimeMillis();
log.info("组织问题对象 done, teamId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}, 路网耗时path:{}ms", teamId, batchNo, technicianList.size(), customerList.size(), locationList.size(), time2-time1); log.info("组织问题对象 done, teamId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}, 路网耗时path:{}ms", teamId, batchNo, technicianList.size(), customerList.size(), locationList.size(), time2-time1);
......
...@@ -240,7 +240,7 @@ public class DataUtils { ...@@ -240,7 +240,7 @@ public class DataUtils {
Location locationi = locationIndex.get(i + 1); Location locationi = locationIndex.get(i + 1);
for (int j = 0; j < pathMatrix[i].length; j++) { for (int j = 0; j < pathMatrix[i].length; j++) {
Location locationj = locationIndex.get(j + 1); Location locationj = locationIndex.get(j + 1);
locationi.getDistanceMap().put(locationj, pathMatrix[i][j]); locationi.getDistanceMap(1).put(locationj, pathMatrix[i][j]);
} }
} }
...@@ -259,7 +259,7 @@ public class DataUtils { ...@@ -259,7 +259,7 @@ public class DataUtils {
Location locationi = locationIndex.get(i + 1); Location locationi = locationIndex.get(i + 1);
for (int j = 0; j < pathTimeMatrix[i].length; j++) { for (int j = 0; j < pathTimeMatrix[i].length; j++) {
Location locationj = locationIndex.get(j + 1); Location locationj = locationIndex.get(j + 1);
locationi.getDistanceTimeMap().put(locationj, pathTimeMatrix[i][j]); locationi.getDistanceTimeMap(1).put(locationj, pathTimeMatrix[i][j]);
} }
} }
......
...@@ -72,12 +72,12 @@ public class DispatchSolutionUtils { ...@@ -72,12 +72,12 @@ public class DispatchSolutionUtils {
startPath = technician.getDepot().getStartTime(); startPath = technician.getDepot().getStartTime();
// endPath = startPath + // endPath = startPath +
// customer.getLocation().getPathTimeTo(technician.getDepot().getLocation()); // customer.getLocation().getPathTimeTo(technician.getDepot().getLocation());
endPath = startPath + technician.getDepot().getLocation().getPathTimeTo(customer.getLocation()); endPath = startPath + technician.getDepot().getLocation().getPathTimeTo(technician.getVehicleType(),customer.getLocation());
} else { } else {
startPath = previousCustomer.getDepartureTime(); startPath = previousCustomer.getDepartureTime();
// endPath = startPath + // endPath = startPath +
// customer.getLocation().getPathTimeTo(previousCustomer.getLocation()); // customer.getLocation().getPathTimeTo(previousCustomer.getLocation());
endPath = startPath + previousCustomer.getLocation().getPathTimeTo(customer.getLocation()); endPath = startPath + previousCustomer.getLocation().getPathTimeTo(technician.getVehicleType(),customer.getLocation());
} }
if (customer.getArrivalTime() > customer.getEndTime()) { if (customer.getArrivalTime() > customer.getEndTime()) {
......
...@@ -26,7 +26,7 @@ import lombok.Data; ...@@ -26,7 +26,7 @@ import lombok.Data;
*/ */
public class RoadDistanceUtils { public class RoadDistanceUtils {
public static String URL = "https://api.map.baidu.com/routematrix/v2/riding?"; public static String URL = "https://api.map.baidu.com/routematrix/v2/";
public static String AK = "doR30pE7R0I7ivGLwMpkpsTT4bos9Akg"; public static String AK = "doR30pE7R0I7ivGLwMpkpsTT4bos9Akg";
/** /**
...@@ -42,20 +42,21 @@ public class RoadDistanceUtils { ...@@ -42,20 +42,21 @@ public class RoadDistanceUtils {
* *
* @param from * @param from
* @param to * @param to
* @param vehicleType 不能为空
* @return * @return
*/ */
public static Distance getDistance(Location from, Location to) { public static Distance getDistance(Location from, Location to, int vehicleType) {
try { try {
String key = from.getLongitude() + "," + from.getLatitude() + ";" + to.getLongitude() + "," String key = from.getLongitude() + "," + from.getLatitude() + ";" + to.getLongitude() + ","
+ to.getLatitude(); + to.getLatitude() + "|" + vehicleType;
Distance distance = distanceCache.get(key); Distance distance = distanceCache.get(key);
if (null == distance) { if (null == distance) {
distance = getDistance(from.getLatitude() + "," + from.getLongitude(), distance = getDistance(from.getLatitude() + "," + from.getLongitude(),
to.getLatitude() + "," + to.getLongitude()); to.getLatitude() + "," + to.getLongitude(), vehicleType);
if(null == distance) { if (null == distance) {
Distance dis = new Distance(); Distance dis = new Distance();
return dis; return dis;
}else { } else {
distanceCache.put(key, distance); distanceCache.put(key, distance);
} }
return distance; return distance;
...@@ -68,14 +69,34 @@ public class RoadDistanceUtils { ...@@ -68,14 +69,34 @@ public class RoadDistanceUtils {
} }
} }
private static Distance getDistance(String yx1, String yx2) throws Exception { private static Distance getDistance(String yx1, String yx2, int vehicleType) throws Exception {
Map<String, String> params = new HashMap<String, String>(); Map<String, String> params = new HashMap<String, String>();
params.put("origins", yx1); params.put("origins", yx1);
params.put("destinations", yx2); params.put("destinations", yx2);
params.put("ak", AK); params.put("ak", AK);
params.put("riding_type", "1");// 电动自行车
params.put("coord_type", "gcj02"); params.put("coord_type", "gcj02");
String text = requestGetAK(URL, params);
String url = "";
switch (vehicleType) {
case 1:
url = URL + "driving?";
break;
case 2:
params.put("riding_type", "1");// 电动自行车
url = URL + "riding?";
break;
case 3:
params.put("riding_type", "0");// 普通自行车
url = URL + "riding?";
break;
case 4:
url = URL + "walking?";
break;
}
String text = requestGetAK(url, params);
BDResult webResult = gson.fromJson(text, BDResult.class); BDResult webResult = gson.fromJson(text, BDResult.class);
float dis = webResult.getResult().get(0).getDistance().getValue() / 1000F; float dis = webResult.getResult().get(0).getDistance().getValue() / 1000F;
int time = webResult.getResult().get(0).getDuration().getValue(); int time = webResult.getResult().get(0).getDuration().getValue();
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!