惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
S
Securelist
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
云风的 BLOG
云风的 BLOG
N
News and Events Feed by Topic
AI
AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Schneier on Security
Schneier on Security
Attack and Defense Labs
Attack and Defense Labs
Vercel News
Vercel News
腾讯CDC
Google DeepMind News
Google DeepMind News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
Netflix TechBlog - Medium
量子位
S
Schneier on Security
Hacker News: Ask HN
Hacker News: Ask HN
Cyberwarzone
Cyberwarzone
S
Security Affairs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
N
News and Events Feed by Topic
T
Tenable Blog
PCI Perspectives
PCI Perspectives
MyScale Blog
MyScale Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
W
WeLiveSecurity
N
News | PayPal Newsroom
P
Proofpoint News Feed
O
OpenAI News
C
CERT Recently Published Vulnerability Notes
B
Blog
Cisco Talos Blog
Cisco Talos Blog
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
MongoDB | Blog
MongoDB | Blog
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
Y
Y Combinator Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Spread Privacy
Spread Privacy

博客园 - Flyingis

微博开通 ESRI UC 2010开幕视频 & Jack出场 地图缓存技术的标准 2010 新年招聘信息--学生实习版 2010 新年招聘信息--正式员工版 WGS 1984 Web Mercator 对于在线地图服务的意义 Geoprocessing scripts 利用多核进行计算 浅尝辄止 Parallel Python 将地震空间数据转变为专题地图 解析USGS网站页面中的地震空间数据 空间数据与内容的共享 ESRI UC 2009 见闻和感触 ArcGIS 9.3/9.3.1 客户端 API 更新信息--2009年5月 如何改善软件的用户体验 之 颜色与UI RIA+REST,琴瑟合鸣 ESRI中国(北京)招聘技术工程师 ArcGIS 9.3.1 关键更新 解决 File GDB 文件锁定的问题 ArcGIS Flex API 中的 Flex 技术(五)--技术列表
ArcGIS Server 开发系列(七)--物流配送
Flyingis · 2008-12-31 · via 博客园 - Flyingis

    作者:Flyingis

    本文严禁用于商业目的,如需转载请注明作者及原文链接,其他疑问请联系:dev.vip#gmail.com

    ArcGIS Server开发系列的文章至今已经一年多了,虽然文章只有短短六篇,也比较基础,但值得高兴的是帮助了不少第一次接触ArcGIS Server的开发者,现在不少都已经完成一两个项目了,相信收获不小,有时间可以和大家一起分享经验。今天开始,我们将继续这个系列教程,争取覆盖ADF开发常用功能,以帮助更多的人轻松入门ADF开发。

    目标:
    实现简易的物流配送(VRP)

    准备工作:
    1.重新复习《ArcGIS Server 开发系列(六)--自定义 Tasks》
    2.准备数据"%ArcGISInstallDir%\DeveloperKit\SamplesNET\Server\data\SanFranciscoNetwork"
    3.发布NATasks.mxd地图服务,添加Network Analyst功能服务
    4.MapResourceManager中添加一个ArcGIS Server Local类型服务

    在这个应用中,多车配送的功能封装为一个自定义的Task,然后生成一个dll添加到ASP.Net工具箱中,由Web Mapping Application的Task Manager调用,更改自定义Task的Task Results Container为模板应用中的TaskResults1控件。

    Web Mapping Application大家已经非常熟悉,现在的重点就在如何利用ArcGIS Server实现VRP功能。VRP全称vehicle routing problem,属于NP难问题,基本没有统一的方法来解决所有的VRP问题,只能根据具体的情况采用最合适的算法,咱们下面就利用ArcGIS Server模拟一个简单的应用场景,实现多车物流的配送计算。

    自定义Task,需要构建Task的UI和业务逻辑,UI构建通过重写方法CreateChildControls完成,咱们最终实现的效果:

    相应的代码比较容易看懂,结合上面实现的UI效果图和代码注释就能明白每部分代码所完成的功能,实现代码:

protected override void CreateChildControls()
{
 Controls.Clear();

 
base.CreateChildControls();

 
Create top level table

 
Orders Label

 
Create and populate orders Listbox

 
OrdersPanel

 
Get Directions Button

 
OnClick Event for executing task

 
// Access the graphics layer so it is created and shown in the TOC
 ElementGraphicsLayer pointsGraphicsLayer = PointsGraphicsLayer;
}


    CreateChildControls用于构建VRPTask UI,除了界面要素之外,还需要从源数据中读取商店信息,如读取商店名称显示在界面上,当VRPTask中的商店被勾选上时,车辆将为该商店送货。商店供货信息存储在数据源中单独的一个图层中stores.shp,包含商店所需的货物数量和预计提供服务的时间。 

    VRPTask UI完成之后,接下来要设计VRP的业务逻辑,ArcGIS 9.3 Network Extension提供了一个基本的VRP解决方案,因此我们在发布NATasks服务的时候需要勾选Network Analyst功能,通过ServerContext去远程调用AO方法。

    第一步,获取VRP分析图层。

IServerContext serverContext = MapResourceLocal.ServerContextInfo.ServerContext;
IMap vrpMap 
= Utility.GetCartoIMap(MapInstance, "NA_MapResourceItem");
IGPMessages gpMessages 
= serverContext.CreateObject("esriGeodatabase.GPMessages"as IGPMessages;

INALayer2 vrpNALayer 
= Utility.GetNALayer("Vehicle Routing Problem", vrpMap);
INAContext vrpNAContext 
= vrpNALayer.CopyContext();
INAContextEdit vrpNAContextEdit 
= vrpNAContext as INAContextEdit;
vrpNAContextEdit.Bind(vrpNALayer.Context.NetworkDataset, gpMessages);


    第二步,获取配送中心信息、商店信息、车辆信息和司机午餐时间。

IFeatureLayer depotsInputFLayer = Utility.GetFeatureLayer("DistributionCenters", vrpMap);
IFeatureClass depotsInputFClass 
= depotsInputFLayer.FeatureClass;
IFeatureCursor depotsInputFCursor 
= depotsInputFClass.Search(nullfalse);
LoadAnalysisClass(serverContext, vrpNAContext, 
"Depots", depotsInputFCursor as ICursor);

// Load Orders
IFeatureLayer ordersInputFLayer = Utility.GetFeatureLayer("Stores", vrpMap);
IFeatureClass ordersInputFClass 
= ordersInputFLayer.FeatureClass;
IFeatureCursor ordersInputFCursor 
= ordersInputFClass.GetFeatures(oids, true);
LoadAnalysisClass(serverContext, vrpNAContext, 
"Orders", ordersInputFCursor as ICursor);

// Load the Routes
ITable routesInputTable = Utility.GetStandaloneTable("Vehicles", vrpMap).Table;
ICursor routesInputCursor 
= routesInputTable.Search(nulltrue);
LoadAnalysisClass(serverContext, vrpNAContext, 
"Routes", routesInputCursor as ICursor);

// Load the Breaks
ITable breaksInputTable = Utility.GetStandaloneTable("LunchBreaks", vrpMap).Table;
ICursor breaksInputCursor 
= breaksInputTable.Search(nulltrue);
LoadAnalysisClass(serverContext, vrpNAContext, 
"Breaks", breaksInputCursor as ICursor);

// Message all of the network analysis agents that the analysis context has changed
vrpNAContextEdit.ContextChanged();

    配送中心、商店信息均存储在物理图层中,分别对应DistributionCenters.shp、Stores.shp,车辆信息和司机午餐时间存储于Table表中。车辆Table包含物流配送过程中和车辆相关的一切信息,如起止配送中心、承载量、最多订单数、发车时间、最长驾驶时间、最长行驶距离等,司机午餐Table包含允许的午餐持续时间、允许的午餐时间范围等,这些都将用于ArcGIS VRP模型的计算中。

    第三步,路径计算,做过ArcEngine Network Analyst开发的工程师对INASolver、INAVRPSolver一定非常熟悉了,调用过程比较简单,路径计算的同时处理系统反馈的消息信息。

gpMessages.Clear();
INASolver naSolver 
= vrpNAContext.Solver;
INAVRPSolver vrpSolver 
= naSolver as INAVRPSolver;
vrpSolver.GenerateInternalRouteContext 
= true// Required for true-shape and directions
vrpSolver.DefaultDate = DateTime.Today;        // Set the default date to be today

bool partialResults = naSolver.Solve(vrpNAContext, gpMessages, null);

// report errors
if (partialResults || gpMessages.Count > 0)
{
 StringBuilder sErrors 
= new StringBuilder();
 
for (int i = 0; i < gpMessages.Count; i++)
 sErrors.AppendLine(gpMessages.GetMessage(i).Description);

 Results 
= sErrors.ToString();
 
return;
}


    第四步,处理结果,VRP计算后最重要的结果就是生成的车辆分配情况、配送顺序和车辆配送路径,将车辆行驶的详细信息以图文并茂的方式展示出来。

// Get Map's Spatial Reference (to project output geometries
ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality mf = (ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality)MapInstance.GetFunctionality("NA_MapResourceItem");
SpatialReference mapSpatialReference 
= mf.MapDescription.SpatialReference;

// Output result Routes and Stops
Utility.OutputRoutesAsGraphics(serverContext, vrpNAContext, RoutesGraphicsLayer, mapSpatialReference);
Utility.OutputOrdersAsGraphics(serverContext, vrpNAContext, PointsGraphicsLayer, mapSpatialReference);

// Create results node
TaskResultNode parentTaskResultNode = Utility.CreateTaskResultNode("VRP Results");
parentTaskResultNode.Expanded 
= true;

// Get the Route Context from the results to use for directions
INAVRPResult vrpResult = vrpNAContext.Result as INAVRPResult;
INAContext routeNAContext 
= vrpResult.InternalRouteContext;

// Loop through the resulting routes and add items for each route (vehicle)
ISet routeSet = serverContext.CreateObject("esriSystem.Set"as ISet;
IFeatureClass routeRoutesFClass 
= routeNAContext.NAClasses.get_ItemByName("Routes"as IFeatureClass;
int routeNameIndex = routeRoutesFClass.FindField("Name");
IFeatureCursor routesRouteFCursor 
= routeRoutesFClass.Search(nullfalse);
int routeNumber = 0;
IFeature routeFeature 
= routesRouteFCursor.NextFeature();
while (routeFeature != null)
{
 
string routeName = routeFeature.get_Value(routeNameIndex).ToString();

 
Choose color for each route

 routeTaskResultNode.Expanded 
= true;
 parentTaskResultNode.Nodes.Add(routeTaskResultNode);

 
// Add Statistics
 TaskResultNode vrpRouteStatisticsNode = Utility.GetVRPRouteStatisticsNode(serverContext, vrpNAContext, routeName);
 vrpRouteStatisticsNode.TextCellStyleAttributes.Add(
"font-weight""bold");
 routeTaskResultNode.Nodes.Add(vrpRouteStatisticsNode);

 
// Add Directions

 
// Get the directions for the specified route
 routeSet.RemoveAll();
 routeSet.Add(routeFeature);
// Get Directions

 
// Generate the directions
 TaskResultNode directionsTaskResultNode = Utility.GetDirectionsNode(false, routeNAContext, routeSet);
 directionsTaskResultNode.TextCellStyleAttributes.Add(
"font-weight""bold");

 
// Add the directions to the results node
 routeTaskResultNode.Nodes.Add(directionsTaskResultNode);

 routeNumber
++;
 routeFeature 
= routesRouteFCursor.NextFeature();
}

    通过上述过程,完成了VRPTask的UI设计和业务逻辑程序,之后需要将应用重新生成为dll,添加到ASP.Net工具箱中,方便WebGIS应用调用该Task控件,我们在Web Mapping Application模板应用程序基础上添加VRPTask,运行后效果:
    数据源vehicles table中包含三辆汽车的记录,在应用中勾选需要进行配送的商店,

    例如选择15家商店,点击"Get Directions"执行VRP计算,生成结果如下所示:

    我们可以发现,很多路径配送需要考虑的问题ArcGIS VRP模型都提供了一套非常简便的解决方案,能够解决一般情况下的VRP问题,但是就如文章前面所说,VRP没有统一的解决方法,但是至少我们可以选择基于ArcGIS Server进行扩展,请思考:
    1.地图数据结构。
    2.配送分区怎么考虑。
    3.配送效率测试。
    4.结对订单。