Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
yangxiujun
/
paidan_demo
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 5eb60d24
authored
Sep 28, 2023
by
chamberone
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 算法添加路网支持
1 parent
27bcdacf
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
174 additions
and
13 deletions
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/GeoDistanceCalculator.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/RoadDistanceUtils.java
project-dispatch/src/main/java/com/dituhui/pea/dispatch/common/GeoDistanceCalculator.java
View file @
5eb60d2
package
com
.
dituhui
.
pea
.
dispatch
.
common
;
package
com
.
dituhui
.
pea
.
dispatch
.
common
;
import
com.dituhui.pea.dispatch.pojo.Location
;
import
com.dituhui.pea.dispatch.pojo.Location
;
import
com.dituhui.pea.dispatch.utils.RoadDistanceUtils
;
import
com.dituhui.pea.dispatch.utils.RoadDistanceUtils.Distance
;
import
org.gavaghan.geodesy.Ellipsoid
;
import
org.gavaghan.geodesy.Ellipsoid
;
import
org.gavaghan.geodesy.GeodeticCalculator
;
import
org.gavaghan.geodesy.GeodeticCalculator
;
import
org.gavaghan.geodesy.GeodeticCurve
;
import
org.gavaghan.geodesy.GeodeticCurve
;
...
@@ -62,9 +65,10 @@ public class GeoDistanceCalculator {
...
@@ -62,9 +65,10 @@ public class GeoDistanceCalculator {
from
->
toLocations
.
stream
().
collect
(
Collectors
.
toMap
(
from
->
toLocations
.
stream
().
collect
(
Collectors
.
toMap
(
Function
.
identity
(),
Function
.
identity
(),
to
->
{
to
->
{
long
distance
=
calculateDistance
(
from
,
to
);
Distance
distance
=
RoadDistanceUtils
.
getDistance
(
from
,
to
);
long
duration
=
Math
.
round
(
distance
/
avgRate
);
long
path
=
(
long
)
distance
.
getDis
();
return
new
Pair
(
distance
,
duration
);
long
time
=
distance
.
getTime
();
return
new
Pair
(
path
,
time
);
}
}
))
))
));
));
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/service/impl/SolveServiceImpl.java
View file @
5eb60d2
...
@@ -12,6 +12,8 @@ import com.dituhui.pea.dispatch.pojo.*;
...
@@ -12,6 +12,8 @@ import com.dituhui.pea.dispatch.pojo.*;
import
com.dituhui.pea.dispatch.service.ExtractService
;
import
com.dituhui.pea.dispatch.service.ExtractService
;
import
com.dituhui.pea.dispatch.service.SolveService
;
import
com.dituhui.pea.dispatch.service.SolveService
;
import
com.dituhui.pea.dispatch.utils.DispatchSolutionUtils
;
import
com.dituhui.pea.dispatch.utils.DispatchSolutionUtils
;
import
com.google.common.collect.Lists
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.optaplanner.core.api.solver.Solver
;
import
org.optaplanner.core.api.solver.Solver
;
import
org.optaplanner.core.api.solver.SolverFactory
;
import
org.optaplanner.core.api.solver.SolverFactory
;
...
@@ -123,7 +125,7 @@ public class SolveServiceImpl implements SolveService {
...
@@ -123,7 +125,7 @@ public class SolveServiceImpl implements SolveService {
}
}
// 40分钟兜低(技能未能正确匹配原因)
// 40分钟兜低(技能未能正确匹配原因)
FIXME 需要跟客户沟通
if
(
null
==
order
.
getTakeTime
())
{
if
(
null
==
order
.
getTakeTime
())
{
order
.
setTakeTime
(
40
);
order
.
setTakeTime
(
40
);
}
}
...
@@ -141,14 +143,12 @@ public class SolveServiceImpl implements SolveService {
...
@@ -141,14 +143,12 @@ public class SolveServiceImpl implements SolveService {
log
.
info
(
"组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}"
,
groupId
,
batchNo
,
customerList
.
size
());
log
.
info
(
"组织问题对象, customer-list, groupId:{}, batchNo:{}, customer-list:{}"
,
groupId
,
batchNo
,
customerList
.
size
());
// depotlist 技术员中收点列表
ArrayList
<
Depot
>
depotList
=
new
ArrayList
<
Depot
>();
// technicianList
// technicianList
ArrayList
<
Technician
>
technicianList
=
new
ArrayList
<>();
ArrayList
<
Technician
>
technicianList
=
new
ArrayList
<>();
dispatchEngineerRepo
.
findByGroupIdAndBatchNo
(
groupId
,
batchNo
).
forEach
(
engineer
->
{
dispatchEngineerRepo
.
findByGroupIdAndBatchNo
(
groupId
,
batchNo
).
forEach
(
engineer
->
{
Location
location
=
new
Location
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
"中心点"
,
Double
.
parseDouble
(
engineer
.
getX
()),
Double
.
parseDouble
(
engineer
.
getY
()));
Location
location
=
new
Location
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
"中心点"
,
Double
.
parseDouble
(
engineer
.
getX
()),
Double
.
parseDouble
(
engineer
.
getY
()));
Depot
depot
=
new
Depot
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
location
,
60
*
8
,
60
*
18
);
//
Depot depot = new Depot(engineer.getId(), engineer.getEngineerCode(), location, 60 * 8, 60 * 18);
depotList
.
add
(
depot
);
//
depotList.add(depot);
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode());
// log.debug("组织问题对象, technicianList groupId:{}, batchNo:{}, engineer-code:{}", groupId, batchNo, engineer.getEngineerCode());
List
<
String
>
skillList
=
queryEngineerSkills
(
engineer
.
getEngineerCode
());
List
<
String
>
skillList
=
queryEngineerSkills
(
engineer
.
getEngineerCode
());
...
@@ -162,20 +162,24 @@ public class SolveServiceImpl implements SolveService {
...
@@ -162,20 +162,24 @@ public class SolveServiceImpl implements SolveService {
preferedLoctionDistanceMap
.
put
(
customer
.
getCode
(),
distance
);
preferedLoctionDistanceMap
.
put
(
customer
.
getCode
(),
distance
);
});
});
Technician
vehicle
=
new
Technician
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
engineer
.
getMaxNum
(),
engineer
.
getMaxMinute
(),
engineer
.
getMaxDistance
()
*
1000
,
d
epot
,
60
*
8
,
60
*
18
,
Set
.
copyOf
(
skillList
),
preferedLoctionDistanceMap
);
Technician
vehicle
=
new
Technician
(
engineer
.
getId
(),
engineer
.
getEngineerCode
(),
engineer
.
getMaxNum
(),
engineer
.
getMaxMinute
(),
engineer
.
getMaxDistance
()
*
1000
,
oneD
epot
,
60
*
8
,
60
*
18
,
Set
.
copyOf
(
skillList
),
preferedLoctionDistanceMap
);
technicianList
.
add
(
vehicle
);
technicianList
.
add
(
vehicle
);
});
});
log
.
info
(
"组织问题对象, depotList-list, groupId:{}, batchNo:{}
, depotList-list:{}"
,
groupId
,
batchNo
,
depotList
.
size
()
);
log
.
info
(
"组织问题对象, depotList-list, groupId:{}, batchNo:{}
"
,
groupId
,
batchNo
);
log
.
info
(
"组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}"
,
groupId
,
batchNo
,
technicianList
.
size
());
log
.
info
(
"组织问题对象, technician-list, groupId:{}, batchNo:{}, technician-list:{}"
,
groupId
,
batchNo
,
technicianList
.
size
());
//
locationlist
//
locationlist 起点+订单地点
List
<
Location
>
locationList
=
Stream
.
concat
(
depotList
.
stream
().
map
(
Depot:
:
getLocation
),
customerList
.
stream
().
map
(
Customer:
:
getLocation
)).
collect
(
Collectors
.
toList
());
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
();
distanceCalculator
.
initDistanceMaps
(
locationList
);
distanceCalculator
.
initDistanceMaps
(
locationList
);
long
time2
=
System
.
currentTimeMillis
();
log
.
info
(
"组织问题对象 done, groupId:{}, batchNo:{}, technician-size:{}, customer-size:{}, location-size:{}
"
,
groupId
,
batchNo
,
technicianList
.
size
(),
customerList
.
size
(),
locationList
.
size
()
);
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
;
...
...
project-dispatch/src/main/java/com/dituhui/pea/dispatch/utils/RoadDistanceUtils.java
0 → 100644
View file @
5eb60d2
package
com
.
dituhui
.
pea
.
dispatch
.
utils
;
import
java.io.BufferedReader
;
import
java.io.InputStreamReader
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.net.URLConnection
;
import
java.net.URLEncoder
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
com.dituhui.pea.dispatch.pojo.Location
;
import
com.google.common.collect.Maps
;
import
com.google.gson.Gson
;
import
lombok.Data
;
/**
* 路网组件<br>
* TODO 需要做成分布式缓存模式,这里会造成内存问题<br>
* TODO 调用方式需要改成批量调用方式
*
* @author gpzhang
*
*/
public
class
RoadDistanceUtils
{
public
static
String
URL
=
"https://api.map.baidu.com/routematrix/v2/riding?"
;
public
static
String
AK
=
"doR30pE7R0I7ivGLwMpkpsTT4bos9Akg"
;
/**
* 格式 x1,y1;x2,y2
*/
private
static
Map
<
String
,
Distance
>
distanceCache
=
Maps
.
newHashMap
();
private
static
Gson
gson
=
new
Gson
();
/**
* 获取路网距离和时间<br>
* TODO 需要做成分布式缓存模式,这里会造成内存问题<br>
* TODO 调用方式需要改成批量调用方式
*
* @param from
* @param to
* @return
*/
public
static
Distance
getDistance
(
Location
from
,
Location
to
)
{
try
{
String
key
=
from
.
getLongitude
()
+
","
+
from
.
getLatitude
()
+
";"
+
to
.
getLongitude
()
+
","
+
to
.
getLatitude
();
Distance
distance
=
distanceCache
.
get
(
key
);
if
(
null
==
distance
)
{
distance
=
getDistance
(
from
.
getLatitude
()
+
","
+
from
.
getLongitude
(),
to
.
getLatitude
()
+
","
+
to
.
getLongitude
());
if
(
null
==
distance
)
{
Distance
dis
=
new
Distance
();
return
dis
;
}
else
{
distanceCache
.
put
(
key
,
distance
);
}
return
distance
;
}
else
{
return
distance
;
}
}
catch
(
Exception
e
)
{
Distance
dis
=
new
Distance
();
return
dis
;
}
}
private
static
Distance
getDistance
(
String
yx1
,
String
yx2
)
throws
Exception
{
Map
<
String
,
String
>
params
=
new
HashMap
<
String
,
String
>();
params
.
put
(
"origins"
,
yx1
);
params
.
put
(
"destinations"
,
yx2
);
params
.
put
(
"ak"
,
AK
);
params
.
put
(
"riding_type"
,
"1"
);
// 电动自行车
params
.
put
(
"coord_type"
,
"gcj02"
);
String
text
=
requestGetAK
(
URL
,
params
);
BDResult
webResult
=
gson
.
fromJson
(
text
,
BDResult
.
class
);
float
dis
=
webResult
.
getResult
().
get
(
0
).
getDistance
().
getValue
()
/
1000
F
;
int
time
=
webResult
.
getResult
().
get
(
0
).
getDuration
().
getValue
();
Distance
d
=
new
Distance
();
d
.
setDis
(
dis
);
d
.
setTime
(
time
);
return
d
;
}
/**
* 默认ak 选择了ak,使用IP白名单校验: 根据您选择的AK已为您生成调用代码 检测到您当前的ak设置了IP白名单校验
* 您的IP白名单中的IP非公网IP,请设置为公网IP,否则将请求失败 请在IP地址为xxxxxxx的计算发起请求,否则将请求失败
*/
public
static
String
requestGetAK
(
String
strUrl
,
Map
<
String
,
String
>
param
)
throws
Exception
{
if
(
strUrl
==
null
||
strUrl
.
length
()
<=
0
||
param
==
null
||
param
.
size
()
<=
0
)
{
return
""
;
}
StringBuffer
queryString
=
new
StringBuffer
();
queryString
.
append
(
strUrl
);
for
(
Map
.
Entry
<?,
?>
pair
:
param
.
entrySet
())
{
queryString
.
append
(
pair
.
getKey
()
+
"="
);
// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可
queryString
.
append
(
URLEncoder
.
encode
((
String
)
pair
.
getValue
(),
"UTF-8"
).
replace
(
"+"
,
"%20"
)
+
"&"
);
}
if
(
queryString
.
length
()
>
0
)
{
queryString
.
deleteCharAt
(
queryString
.
length
()
-
1
);
}
java
.
net
.
URL
url
=
new
URL
(
queryString
.
toString
());
URLConnection
httpConnection
=
(
HttpURLConnection
)
url
.
openConnection
();
httpConnection
.
connect
();
InputStreamReader
isr
=
new
InputStreamReader
(
httpConnection
.
getInputStream
());
BufferedReader
reader
=
new
BufferedReader
(
isr
);
StringBuffer
buffer
=
new
StringBuffer
();
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
buffer
.
append
(
line
);
}
reader
.
close
();
isr
.
close
();
return
(
buffer
.
toString
());
}
@Data
public
static
class
Distance
{
float
dis
;
int
time
;
}
@Data
static
class
BDResult
{
List
<
BDDistance
>
result
;
}
@Data
static
class
BDDistance
{
Dis
distance
;
Dur
duration
;
}
@Data
static
class
Dis
{
Float
value
;
}
@Data
static
class
Dur
{
Integer
value
;
}
}
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment