AE开发可以定制化实现ArcGIS的地理处理功能,并实际运用于其他方面的工作,有时候我们还希望将AE开发的功能发布为网络地理信息处理服务(WPS),从而能在Web端更自由便利地调用所需要的地学处理算法。本文记录的就是这一过程,大体思路为:用C#类库封装专题图制作的方法并生成为Dll,再用C++调用这一Dll并生成C++的Dll,然后在Java中用jna来调用C++的Dll,实现Java调用AE开发的专题图制作的算法,最后用Tomcat将这一地学算法发布为服务。该服务只需要传递Shp文件的路径和专题图输出路径两个参数,便可以自动化执行,输入Shp矢量文件,输出Jpg专题图文件。

具体实现过程分为以下三方面来进行介绍:

一、将AE开发的功能封装为C#的Dll

在实验阶段,我其实先写了一个C#的Windows窗体应用程序,用以实现专题图制作功能,其界面如下所示:

这个程序可以实现简单的专题图制作功能,以天地图图层为背景,加载Shp文件到PageLayoutControl控件,通过点击按钮来添加标题、指北针、比例尺、图例等专题图要素,这些要素依据Shp文件并调用AE的相关接口来生成,生成后加载到PageLayoutControl窗口的固定位置,最后通过点击按钮来将其导出为Jpg图片,并保存在本地目录。

但是由于Windows窗体应用程序无法生成可以被C++调用的Dll,并且最后的服务不允许有窗口的出现,于是就需要将这一方法封装为C#的类库,过程及代码如下:

1.1以管理员方式启动VS(涉及到注册COM组件,必须以管理员方式启动),新建C#项目,选择类库。

1.2设置SThematicMap的属性,右键新建的项目,点击属性。

继续设置项目属性,由于引用的ESRI.ArcGIS.Version为32位,本项目必须生成为32位(与后面过程相对应,后续过程中C++、JDK和Tomcat都必须保持相同位数)。

记得保存属性设置。

1.3添加代码。

这一块需要说明一下,本项目最终不允许有窗体界面的出现,但是专题图制作中图例、比例尺等要素的添加都需要PageLayoutControl控件窗体的存在,就像是要在没有水的公路上开一艘船,很矛盾的一件事,想要开这艘船,就必须引水进来。换言之,就是在类库中引入Windows窗体文件,在窗体中加入需要的控件,并且设置窗体为不显示,仅仅让窗体控件作为一个搭载数据的载体。右键项目,添加新建项,添加C#的Windows窗体。

由于在类库中调用窗体会实例化Active X控件,而该控件需要应用程序的线程为单线程单元,因此在类库文件中需要添加一个额外的函数来设置线程,这一点很重要,否则后面会报错!因此,Class1下面的代码就如下所示:

using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Generic;namespace SThematicMap
{public class Class1{private string InputPath, OutputPath;public Thread newThread;//设置程序为单线程单元public void ThMap(string inputPath, string outPath) {InputPath = inputPath;OutputPath = outPath;newThread = new Thread(new ThreadStart(threadMap));newThread.SetApartmentState(ApartmentState.STA);newThread.Start();}//实际执行模块public void threadMap(){ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Desktop);Form1 form = new Form1();form.thMap(InputPath, OutputPath);}}
}

  其中form.thMap(InputPath, OutputPath)这句函数将两个参数传入Form1,核心的专题图生成算法在Form1.cs中实现,其代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Output;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.GISClient;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesFile;namespace SThematicMap
{public partial class Form1 : Form{public Form1(){InitializeComponent();}public void thMap(string InputPath, string OutputPath){//在MapControl中导入shp文件string filePath = System.IO.Path.GetDirectoryName(InputPath);string fileName = System.IO.Path.GetFileNameWithoutExtension(InputPath);axMapControl1.AddShapeFile(filePath, fileName);//加载天地图IPropertySet pPropertyset = new PropertySetClass();pPropertyset.SetProperty("url", "http://t0.tianditu.com/vec_c/wmts");//全球矢量地图服务//pPropertyset.SetProperty("url", "http://t0.tianditu.com/ter_c/wmts");//全球地形晕渲地图服务IWMTSConnectionFactory pWMTSConnectionfactory = new WMTSConnectionFactory();IWMTSConnection pWMTSConnection = pWMTSConnectionfactory.Open(pPropertyset, 0, null);IWMTSLayer pWMTSLayer = new WMTSLayer();IName pName = pWMTSConnection.FullName;pWMTSLayer.Connect(pName);axMapControl1.AddLayer(pWMTSLayer as ILayer);//加载中文注记IPropertySet pPropertyset1 = new PropertySetClass();pPropertyset1.SetProperty("url", "http://t0.tianditu.com/cva_c/wmts");//全球矢量中文注记服务IWMTSConnectionFactory pWMTSConnectionfactory1 = new WMTSConnectionFactory();IWMTSConnection pWMTSConnection1 = pWMTSConnectionfactory1.Open(pPropertyset1, 0, null);IWMTSLayer pWMTSLayer1 = new WMTSLayer();IName pName1 = pWMTSConnection1.FullName;pWMTSLayer1.Connect(pName1);axMapControl1.AddLayer(pWMTSLayer1 as ILayer);//将矢量文件显示在最上面axMapControl1.MoveLayerTo(axMapControl1.LayerCount - 1, 0);axMapControl1.Refresh();//将MapControl中shp文件转为地图布局视图IObjectCopy objectCopy = new ObjectCopyClass();object toCopyMap = axMapControl1.Map;object copiedMap = objectCopy.Copy(toCopyMap);object toOverwriteMap = axPageLayoutControl1.ActiveView.FocusMap;objectCopy.Overwrite(copiedMap, ref toOverwriteMap);//获取Layout视图内容IGraphicsContainer container = axPageLayoutControl1.GraphicsContainer;IActiveView activeView = axPageLayoutControl1.ActiveView;// 获得MapFrame  IFrameElement frameElement = container.FindFrame(activeView.FocusMap);IMapFrame mapFrame = frameElement as IMapFrame;//根据MapSurround的uid,创建相应的MapSurroundFrame和MapSurround  UID uid = new UIDClass();//*****************************添加指北针***************************uid.Value = "esriCarto.MarkerNorthArrow";IMapSurroundFrame mapSurroundFrame = mapFrame.CreateSurroundFrame(uid, null);//设置MapSurroundFrame中指北针的点符号  IMapSurround mapSurround = mapSurroundFrame.MapSurround;IMarkerNorthArrow markerNorthArrow = mapSurround as IMarkerNorthArrow;IMarkerSymbol markerSymbol = markerNorthArrow.MarkerSymbol;markerSymbol.Size = 130;markerNorthArrow.MarkerSymbol = markerSymbol;//QI,确定mapSurroundFrame的位置  IElement element = mapSurroundFrame as IElement;IEnvelope envelope = new EnvelopeClass();envelope.PutCoords(16, 21, 19, 23);element.Geometry = envelope;//使用IGraphicsContainer接口添加显示  container.AddElement(element, 0);activeView.Refresh();//*****************************添加比例尺***************************ITrackCancel trackCancel = new CancelTracker();//根据MapSurround的uid,创建相应的MapSurroundFrame和MapSurround  uid = new UIDClass();uid.Value = "esriCarto.AlternatingScaleBar";mapSurroundFrame = mapFrame.CreateSurroundFrame(uid, null);//设置MapSurroundFrame中比例尺的样式  mapSurround = mapSurroundFrame.MapSurround;//QI,确定mapSurroundFrame的位置  element = mapSurroundFrame as IElement;envelope = new EnvelopeClass();envelope.PutCoords(2, 2, 4, 4);envelope.Width = 6;element.Geometry = envelope;element.Activate(axPageLayoutControl1.ActiveView.ScreenDisplay);element.Draw(axPageLayoutControl1.ActiveView.ScreenDisplay, trackCancel);//使用IGraphicsContainer接口添加显示  container.AddElement(element, 0);axPageLayoutControl1.Refresh();//*****************************添加图例***************************// 获得MapFrame  //根据MapSurround的uid,创建相应的MapSurroundFrame和MapSurround  uid = new UIDClass();uid.Value = "esriCarto.Legend";mapSurroundFrame = mapFrame.CreateSurroundFrame(uid, null);//设置图例的属性  ILegend2 legend = mapSurroundFrame.MapSurround as ILegend2;legend.Title = "图例";element = mapSurroundFrame as IElement;envelope = new EnvelopeClass();envelope.PutCoords(2, 22, 6, 24);element.Geometry = envelope;//使用IGraphicsContainer接口添加显示  container.AddElement(element, 0);activeView.Refresh();//*****************************添加标题***************************//创建元素ITextElement pTextElement = new TextElementClass();pTextElement.Text = "北京烈度图";ITextSymbol pTextSymbol = new TextSymbolClass();pTextSymbol.Size = 50;pTextElement.Symbol = pTextSymbol;//设置位置                        IElement pElement = pTextElement as IElement;//pElement.Geometry = axPageLayoutControl1.TrackRectangle();envelope = new EnvelopeClass();envelope.PutCoords(10, 23, 12, 28);pElement.Geometry = envelope;//将元素添加到容器中container.AddElement(pElement, 0);//刷新axPageLayoutControl1.Refresh();//*****************************导出图片***************************double iScreenDispalyResolution = axPageLayoutControl1.ActiveView.ScreenDisplay.DisplayTransformation.Resolution;// 设置输出文件名string JpgfileName = OutputPath;ESRI.ArcGIS.Output.IExport pExport = new ESRI.ArcGIS.Output.ExportJPEGClass();pExport.ExportFileName = JpgfileName;// 设置输出分辨率pExport.Resolution = (short)iScreenDispalyResolution;// 获取输出范围,获取视图框架对象,进而得到视图范围tagRECT deviceRect = axPageLayoutControl1.ActiveView.ScreenDisplay.DisplayTransformation.get_DeviceFrame();IEnvelope pDeviceEnvelop = new EnvelopeClass();// 设置一个边框范围pDeviceEnvelop.PutCoords(deviceRect.left, deviceRect.bottom, deviceRect.right, deviceRect.top);// 将打印像素范围设置给输出对象pExport.PixelBounds = pDeviceEnvelop;// 设置跟踪取消对象ITrackCancel pCancle = new CancelTrackerClass();// 进行视图控件的视图输出操作,设置对应参数axPageLayoutControl1.ActiveView.Output(pExport.StartExporting(), (int)pExport.Resolution, ref deviceRect, axPageLayoutControl1.ActiveView.Extent, pCancle);Application.DoEvents();pExport.FinishExporting();pExport.Cleanup();}}
}

  在Form.cs中新建了public void thMap(string InputPath, string OutputPath)方法,其内容包括矢量文件的加载、布局视图的切换、天地图的加载、比例尺等要素的加载和图片文件的导出。至此,C#相关的所有代码都已完成。

1.4生成C#的Dll。

右键SThematicMap项目,点击生成。

第一步到此完成!

二、调用C#的Dll并生成C++的Dll

2.1右键解决方案,添加新建项目,新建C++的Win32项目,并选择Dll和空项目。

2.2设置项目属性,右键CThMapDll项目,点击属性。

2.3添加cpp文件并书写代码。右键源文件,添加新建项,添加C++文件(main.cpp)。

main.cpp代码如下:

/**********************************
声明需要被java调用的方法,该方法和java接口内部方法保持一致
预处理语句目的是暴露函数供外部调用。
************************/
#ifdef MYLIBAPI
#else
#define  MYLIBAPI  extern "C" __declspec(dllimport)
#endif MYLIBAPI void ThMap(char* inputPath, char* outputPath); //添加函数声明 using namespace System;
using namespace SThematicMap;void ThMap(char* inputPath, char* outputPath)
{String ^inStr = gcnew String(inputPath);String ^outStr = gcnew String(outputPath);Class1 ^method = gcnew Class1();method->ThMap(inStr,outStr);
}

2.4生成C++的Dll,右键CThMapDll项目,点击生成。

至此,第二步也已经完成!

三、用Java调用并将其发布为服务

3.1先下载两个jna的Jar包,用于调用C++的Dll,下载地址:Jna下载。

新建Lib文件夹,将两个Jna包导入并添加进项目。

3.2新建Package并添加ThematicMap.java。

其代码如下:

package whu.thematic.map;import com.sun.jna.Library;
import com.sun.jna.Native;public class ThematicMap {public static void main(String input,String output) throws Exception {System.out.println(System.getProperty("java.version"));//输出当前jdk版本号System.out.println(System.getProperty("sun.arch.data.model"));//输出当前jdk所用平台CLibrary1 clib = CLibrary1.INSTANCE;clib.ThMap(input,output);     }
}interface CLibrary1 extends Library {CLibrary1 INSTANCE = (CLibrary1) Native.loadLibrary("E:\\Learning\\SThematicMap\\Debug\\CThMapDll",CLibrary1.class);/*需要调用的方法,方法与C++方法名相同 */void ThMap(String inputPath, String outputPath);
}

  需要在服务发布文件中添加如下引用,并声明相关函数:

import whu.thematic.map.*;String input =new String(request.getParameter("district"));
String output = new String(request.getParameter("anglePath"));try {ThematicMap.main(input, output);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();
}

  在显示服务的网页中进行相应设置,其html文件代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>专题图制作</title>
<script src="login/js/jquery-1.4.2.min.js"></script>
</head>
<body>
<h1>专题图制作</h1><form name="DZLD" method="get" action="DZLDServlet" id="form"><p><table border="1"><tr><td>Input</td><td><input name="district"  value="E:\\Learning\\ShpData\\BeijingShp.shp" type="text" size="50"/></td></tr><tr><td>Output</td><td><input name="anglePath" value="E:\\Learning\\ShpData\\Beijing.jpg" type="text" size="50"/></td></tr></table></p> <tr><td><input type="submit" value="发送" size="50"/></td><td><input type="button" value="重置" size="50" οnclick="formReset()"/></td></tr></form><script type="text/javascript">function formReset() {$("input[name='district']").val("").focus(); // 清空并获得焦点}</script>
</body>
</html>

  3.3将该工程导入到Tomcat服务中,注意此处Tomcat必须是32位。

还要注意一点,此方法程序只是读到了C++的Dll,还需要将C#的Dll复制粘贴到所用Jre的bin目录下。然后发布并启动服务,在浏览器中输入:http://localhost:8080/image/

可以看到,WPS服务已经发布成功,点击发送,可在本地文件夹中看到Beijing.jpg

至此,全部工作都已经完成!其他带窗体或不带窗体的AE程序都可以按此种方法发布为服务。

将AE开发的专题图制作功能发布为WPS相关推荐

  1. 「干货」12.5米数字高程DEM专题图制作教程

    [干货]12.5米数字高程DEM专题图制作教程 概述 数字高程模型(Digital Elevation Model),简称DEM,是表达地面高程起伏形态的实体地面模型. 可用于绘制等高线.坡度图.坡向 ...

  2. 【ArcGIS教程】专题图制作之人口地图——湖北省人口密度分析

    成图展示: 人口密度分布状况统计--以湖北省为例 :这里所使用的为湖北省的省.市.县三个级别的行政区划矢量数据,以及居民点数据(OSM获取), 进而进行密度分析. 注:以下为比较简单的基础操作过程,如 ...

  3. 12米数字高程DEM现已上线!附DEM专题图制作教程

    概述: 数字高程模型(Digital Elevation Model),简称DEM,是表达地面高程起伏形态的实体地面模型.可用于绘制等高线.坡度图.坡向图.立体透视图.立体景观图,并应用于制作正射影像 ...

  4. 一次性搞定ArcGIS专题图制作流程

    专题图 何为专题图? 专题图是用于分析和表现数据的一种强有力的方式,用户可以通过使用专题图的方式将数据图形化,使数据以更直观的形式在地图上体现出来. 事实上,大家在日常生活中见过的很多地图都属于专题图 ...

  5. Android带三角形的弹窗,andriod开发 利用.9图制作带三角形指示的popwindow弹窗

    利用.9图做背景,配合使用popwindow和listview可以实现这个需求,也可以自定义popwindow的布局,画边框加阴影,自定义三角形的view,然后...然后我就放弃了这个思路,老老实实直 ...

  6. 专题图制作(点密度图、分层设色图/等级图、单值图、柱状图、饼状图)

    ArcEngine 专题图制作(C#) 点密度图.分层设色图/等级图.单值图.柱状图.饼状图的实现代码 C# private void 点密度图ToolStripMenuItem_Click(obje ...

  7. 【ArcGIS教程】专题图制作-人口密度分布图——人口密度分析

     本篇以湖北省为例,制作人口密度分布图:这里所使用的为湖北省的省.市.县三个级别的行政区划矢量数据,以及居民点数据,进而进行密度分析. 示例数据来源于地理遥感生态网,该网站更新了很多有关地理的数据,3 ...

  8. 基于arcgis的专题图制作教程

    文章目录 1. 准备好图层 2. 切换视图 3. 插入标题 4. 插入指北针 5. 插入图例 6. 插入比例尺 7. 插入经纬度格网 相关数据 1. 准备好图层 2. 切换视图 3. 插入标题

  9. ProcessOn - 高大上的免费中文在线作图工具/思维导图制作软件

    点此进入:https://www.processon.com/i/5518b08ae4b0a52a9843e123 ProcessOn 网页版在线作图工具!你只需要有一个浏览器即可制作思维导图.流程图 ...

最新文章

  1. 【原创】推荐广告入门:DeepCTR-Torch,基于深度学习的CTR预测算法库
  2. 深入V8引擎-Time模块介绍
  3. 产生线程安全的原因(2)(操作系统)
  4. 【CodeForces - 892C 】Pride (数学,思维构造,gcd)
  5. mmdetection多类目标训练查看单类准确率(AP)以及使用模型测试看结果(show)
  6. 【声传播】——角谱理论、模式理论及三维傅里叶变换
  7. Windows下mysql的基础操作
  8. linux管理进程的数据结构,Linux 进程运行的各项指标的监测和一些管理命令的应用...
  9. ACDSee 15/ACDSee Pro 6简体中文版破解注册机
  10. matlab 误差椭圆,第十章 误差椭圆.doc
  11. 如何用Airtest脚本切换手机的输入法
  12. 文件管理服务器搭建教程,文件服务器搭建教程
  13. CString 和 LPCTSTR 之间的转换 及 LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR的区分与转化
  14. 产品经理1.1_如何高效的开展产品需求评审会
  15. JS中VAR的用处(局部变量要用var来声明,全局变量不加var)
  16. 清理localstorage_localstorage文件夹可以删除吗
  17. AE使用函数集10:获取图层组中的所有图层
  18. 熊掌号php推送一次最多提交2000条,利害了我的熊掌号-熊掌号历史数据提交效果明显...
  19. 【向生活低头】将flv格式文件转为mp4
  20. 【bsauce读论文】2022-CCS-DirtyCred: Escalating Privilege in Linux Kernel

热门文章

  1. linux 下安装mysql相关笔记
  2. 机器学习之——什么是Onehot编码?
  3. java使用jsoup爬虫入门
  4. 初次爬虫:读取PDF转成图片,再提取图片里的文字信息
  5. 结果集没有当前行的解决方法
  6. matlab实现图像DCT变换
  7. Transactional(事务)
  8. 计算机一级重点知识,计算机一级考试重点
  9. 企业微信app中退出某个企业 最新版 图文
  10. 展示一下用thinker做小软件的UI