基于activiti和bpmn.js的wps服务链研究(毕设研究笔记)

381 阅读15分钟

毕设生态适宜性分析的几个步骤:

1.数据的预处理,得到标准化的环境因子数据产品

2.熵权法计算生态适宜性指数(评估点)/或者采用多种方法解决

3.随机森林模型和主成分分析模型的拟合效果(暂定)

1.IDEA导入geoserver源码项目

Intellij Idea启动GeoServer源码工程项目搭建_geoserver 源码部署-CSDN博客

IDEA导入geoserver项目_geoserver org.geoserver.wcs.kvp.rangesubset 文件不存在-CSDN博客

2.邻近分析

【QGIS】在Pycharm中使用pyqgis中的processing工具箱功能_qgis processing.core.processing_西米2231的博客-CSDN博客

【QGIS】在Pycharm中通过独立程序方式使用pyqgis里processing的工具箱功能 - 知乎 (zhihu.com)

栅格的邻近分析可计算一个栅格要素类中各点与另一要素类中最近的栅格像素值之间的距离

研究目的:利用Distance工具中的Euclidean Distance模型,计算菜子湖区每个栅格分别与湖泊、农田、草本沼泽、泥滩、圩堤、道路的距离。

方法实现:使用java封装wps模型调用python的QGIS库api实现邻近分析

Image.png

具体做法:

1.PyCharm QGIS环境配置

设置解释器方式

新建一个项目,选择Python解释器为:D:\QGIS\bin\python-qgis.bat,这个批处理会自动设置环境变量,然后启动python解释器。

PyCharm可以读取到qgis相关的包,包括qgis.core、qgis.gui

注:此时的PyCharm无法使用processing工具包

解决办法:

在环境变量中创建 PYTHONPATH 字段,将以下地址引入环境变量中

Image.webp

将Processing进行初始化

from processing.core.Processing import Processing
qgs = QgsApplication([], False)
qgs.initQgis()
# qgs.initQgis()之后再进行Processing的初始化
Processing.initialize()

里遇到问题即我不能成功索引到sys.path.append(r'D:\Program Files\QGIS\apps\qgis\python\plugins')来成功引入这个Processing包中的py文件,因此我选择直接将processing文件复制到项目文件夹

Image.png

发现通过以上方法设置后大部分工具箱的功能可以用,但是GDAL中的功能和部分插件不可用。如本次需要使用的gdal:proximity方法

解决方法:创建对 QgsApplication 的引用,以独立脚本的方式启动,并注册算法。

核心代码:

params = {
    'INPUT': input_file,
    'BAND': 1,
    'VALUES': source_pixel_value,
    'UNITS': 1,
    'MAX_DISTANCE': 0,
    'REPLACE': 0,
    'NODATA': 0,
    'OPTIONS': '',
    'EXTRA': '',
    'DATA_TYPE': 5,
    'OUTPUT': output_file
}

result = processing.run("gdal:proximity", params)
  • 'INPUT': 'E:/Edge_download/outputGridCoverage (5).tiff':输入栅格数据集的路径。

  • 'BAND': 1:要计算距离的波段索引。

  • 'VALUES': '2':指定要计算距离的栅格像元值。(这个也是模型封装需要是输入参数,这样才能确定土地利用类型各个代表栅格点到其他土地利用类型的距离)

  • 'UNITS': 1:距离单位,1表示像素单位、0代表配置后的实际坐标。

  • 'MAX_DISTANCE': 0:最大距离,这里设置为0,表示只计算与指定像元值相邻的像元的距离。

2.geoserver对gdal的处理进行WPS封装

重点:Java进程ProcessBuilder类的使用,ProcessBuilder调用外部程序执行python命令

// 构造 ProcessBuilder 对象
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "D:\\Program Files\\QGIS\\bin\\python-qgis.bat", "./src/main/webapp/data/python/euclidean_Distance.py");
// 启动进程
process = pb.start();
//获取进程的输出流
OutputStreamWriter streamWriter = new OutputStreamWriter(process.getOutputStream());
BufferedWriter bufferedWriter = new BufferedWriter(streamWriter);
// 将 sourcePixelValue 发送给 Python
bufferedWriter.write(Integer.toString(sourcePixelValue));
bufferedWriter.newLine();
bufferedWriter.flush();
// 读取进程输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
    System.out.println(line);
}
// 读取进程错误输出
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String errorLine;
while ((errorLine = errorReader.readLine()) != null) {
    System.err.println(errorLine);
}
// 等待进程结束
int exitCode = process.waitFor();
if (exitCode == 0) {
    System.out.println("Python 脚本运行成功!");
} else {
    System.err.println("Python 脚本运行失败,错误码:" + exitCode);
}

ProcessBuilder 是一个用于创建和启动子进程的工具类。它允许你以 Java 代码的方式执行外部命令。 下面是对 ProcessBuilder 构造函数参数的解释:

1. "cmd.exe":指定要执行的命令解释器,这里使用 Windows 的 cmd.exe 命令提示符。

2. "/c":传递给 cmd.exe 的参数,表示在执行完命令后关闭 cmd.exe。

3. "python-qgis.bat":要执行的可执行脚本或命令,这里是 python-qgis.bat 脚本。

4. "your_script.py":要传递给 python-qgis.bat 的参数,这里是你的 Python 脚本的文件名。

传参到进程中

1.java进程里使用bufferedWriter.write(Integer.toString(sourcePixelValue));将传输传给python进程 2.python进程使用source_pixel_value = str(sys.stdin.readline())获取该传值 这样实现了source_pixel_value参数在两个进程之间的传递

3.数据的预处理(wps服务)

需要的数据

WCS服务:reclass、landsat8_band4、landsat8_band5、DEM

WFS服务:bird_point

reclass.tif的分类

0:未定义

1:林地

2:灌木

3:草地

4.耕地

5.建筑用地

6.水域

7.泥滩

1701421591020.png

需要的服务模型

预处理部分:NDVI计算,坡度分析,坡向分析,邻近分析,掩膜(按范围)提取,重投影

需要解决的问题

1.每一条并行网关的执行的变量都独立,不能变量名相同,但在不同的执行路径上还能访问到

解决办法(暂时):在流程定义中,为每个并行网关的输出路径设置不同的变量名。例如,假设有一个并行网关,有两个输出路径:A和B。在路径A上,你可以设置变量名为variableA;在路径B上,你可以设置变量名为variableB。

2.activiti 要做几个并行的流程,然后等待所有并行流程结束后在将所有流程得到的变量汇聚起来做出来,需要哪些节点,怎么做等待实现

解决办法: 在Activiti中实现等待所有并行流程结束后将结果汇聚起来的功能,通常可以使用以下节点和技术:

并行网关(Parallel Gateway):用于创建并行执行的分支。在并行网关之后,会有多个并行执行路径。

服务任务(Service Task):在每一个并行执行路径中,你可以包含需要执行的服务任务,用于完成具体的业务逻辑或操作。

接收任务(Receive Task):用于等待所有并行执行路径的完成。可以在每个并行执行路径的末尾都放置一个接收任务,表示该路径已完成。

汇聚网关(Exclusive Gateway):用于等待所有并行执行路径完成后进行汇聚。在这里你可以使用排他网关来判断所有并行执行路径是否都已经完成。

下面是一个简单的示例流程设计:

<process id="parallelProcess" name="Parallel Process">
  <startEvent id="start" />
  
  <!-- 创建并行执行分支 -->
  <parallelGateway id="fork" />
  
  <!-- 并行执行路径1 -->
  <sequenceFlow id="toServiceTask1" sourceRef="fork" targetRef="serviceTask1" />
  <serviceTask id="serviceTask1" name="Service Task 1" />
  <sequenceFlow id="toReceiveTask1" sourceRef="serviceTask1" targetRef="receiveTask" />

  <!-- 并行执行路径2 -->
  <sequenceFlow id="toServiceTask2" sourceRef="fork" targetRef="serviceTask2" />
  <serviceTask id="serviceTask2" name="Service Task 2" />
  <sequenceFlow id="toReceiveTask2" sourceRef="serviceTask2" targetRef="receiveTask" />
  
  <!-- 等待接收任务 -->
  <receiveTask id="receiveTask" name="Receive Task" />
  
  <!-- 汇聚并行执行路径 -->
  <exclusiveGateway id="join" />
  <sequenceFlow id="toJoin" sourceRef="receiveTask" targetRef="join" />
  
  <!-- 结束 -->
  <endEvent id="end" />
  <sequenceFlow id="toEnd" sourceRef="join" targetRef="end" />
</process>

1702645996569.png

服务链为:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="http://www.activiti.org/processdef">
  <process id="process" isExecutable="true">
    <startEvent id="Event_0nhlqsi" name="开始">
      <outgoing>Flow_0arlac2</outgoing>
    </startEvent>
    <parallelGateway id="Gateway_0p0odbn">
      <incoming>Flow_0arlac2</incoming>
      <outgoing>Flow_17pywlx</outgoing>
      <outgoing>Flow_0201p21</outgoing>
      <outgoing>Flow_18lhvu8</outgoing>
    </parallelGateway>
    <serviceTask id="Activity_0p0rqtn" name="按范围裁剪栅格" activiti:class="com.demo.activiti.service.model.RangeCoverageClip">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputRangeCoverageClipGridCoverage">
          <activiti:string>http://localhost:8082/geoserver/dll/wms?service=WMS&amp;version=1.1.0&amp;request=GetMap&amp;layers=dll%3ANDVI_2018_10&amp;bbox=115.71722836%2C29.239625188%2C118.133489587%2C31.357427681&amp;width=768&amp;height=673&amp;srs=EPSG%3A4326&amp;styles=&amp;format=application/openlayers</activiti:string>
        </activiti:field>
        <activiti:field name="clipBoundary">
          <activiti:string>http://localhost:8082/geoserver/dll/ows?service=WFS&amp;version=1.0.0&amp;request=GetFeature&amp;typeName=dll%3Acaizi_lake_boundary&amp;outputFormat=application%2Fjson</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>NDVI裁剪</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_17pywlx</incoming>
      <outgoing>Flow_1lpllw5</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_17pywlx" sourceRef="Gateway_0p0odbn" targetRef="Activity_0p0rqtn" />
    <serviceTask id="Activity_1r2euy8" name="重投影" activiti:class="com.demo.activiti.service.model.Reprojection">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputReprojectionGridCoverage">
          <activiti:string>NDVI裁剪</activiti:string>
        </activiti:field>
        <activiti:field name="targetCRS">
          <activiti:string>EPSG:32650</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>NDVI预处理结果</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_1lpllw5</incoming>
      <outgoing>Flow_1nksb3r</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_1lpllw5" sourceRef="Activity_0p0rqtn" targetRef="Activity_1r2euy8" />
    <endEvent id="Event_0emaqy3" name="结束">
      <incoming>Flow_1ar3om7</incoming>
    </endEvent>
    <sequenceFlow id="Flow_0arlac2" sourceRef="Event_0nhlqsi" targetRef="Gateway_0p0odbn" />
    <serviceTask id="Activity_06zevtj" name="按范围裁剪栅格" activiti:class="com.demo.activiti.service.model.RangeCoverageClip">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputRangeCoverageClipGridCoverage">
          <activiti:string>http://localhost:8082/geoserver/dll/wms?service=WMS&amp;version=1.1.0&amp;request=GetMap&amp;layers=dll%3Areclassify&amp;bbox=116.794965106%2C30.618212105%2C117.299238775%2C31.269572503&amp;width=594&amp;height=768&amp;srs=EPSG%3A4326&amp;styles=&amp;format=application/openlayers</activiti:string>
        </activiti:field>
        <activiti:field name="clipBoundary">
          <activiti:string>http://localhost:8082/geoserver/dll/ows?service=WFS&amp;version=1.0.0&amp;request=GetFeature&amp;typeName=dll%3Acaizi_lake_boundary&amp;outputFormat=application%2Fjson</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>土地利用裁剪</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_0201p21</incoming>
      <outgoing>Flow_1w5a3yr</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_0201p21" sourceRef="Gateway_0p0odbn" targetRef="Activity_06zevtj" />
    <serviceTask id="Activity_0hlrnhy" name="按范围裁剪栅格" activiti:class="com.demo.activiti.service.model.RangeCoverageClip">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputRangeCoverageClipGridCoverage">
          <activiti:string>http://localhost:8082/geoserver/dll/wms?service=WMS&amp;version=1.1.0&amp;request=GetMap&amp;layers=dll%3Adem&amp;bbox=115.999861111%2C29.999861111%2C118.000138889%2C31.000138889&amp;width=768&amp;height=384&amp;srs=EPSG%3A4326&amp;styles=&amp;format=application/openlayers</activiti:string>
        </activiti:field>
        <activiti:field name="clipBoundary">
          <activiti:string>http://localhost:8082/geoserver/dll/ows?service=WFS&amp;version=1.0.0&amp;request=GetFeature&amp;typeName=dll%3Acaizi_lake_boundary&amp;outputFormat=application%2Fjson</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>DEM裁剪</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_18lhvu8</incoming>
      <outgoing>Flow_1rwkh09</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_18lhvu8" sourceRef="Gateway_0p0odbn" targetRef="Activity_0hlrnhy" />
    <serviceTask id="Activity_0h2a5m2" name="重投影" activiti:class="com.demo.activiti.service.model.Reprojection">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputReprojectionGridCoverage">
          <activiti:string>DEM裁剪</activiti:string>
        </activiti:field>
        <activiti:field name="targetCRS">
          <activiti:string>EPSG:32650</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>DEM预处理结果</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_1rwkh09</incoming>
      <outgoing>Flow_0t4odop</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_1rwkh09" sourceRef="Activity_0hlrnhy" targetRef="Activity_0h2a5m2" />
    <parallelGateway id="Gateway_193ryzg">
      <incoming>Flow_0t4odop</incoming>
      <outgoing>Flow_09josl1</outgoing>
      <outgoing>Flow_0n5ywr3</outgoing>
    </parallelGateway>
    <sequenceFlow id="Flow_0t4odop" sourceRef="Activity_0h2a5m2" targetRef="Gateway_193ryzg" />
    <parallelGateway id="Gateway_0ithekw">
      <incoming>Flow_1nksb3r</incoming>
      <incoming>Flow_09josl1</incoming>
      <incoming>Flow_09s0bow</incoming>
      <incoming>Flow_1liu47z</incoming>
      <outgoing>Flow_1ar3om7</outgoing>
    </parallelGateway>
    <sequenceFlow id="Flow_1nksb3r" sourceRef="Activity_1r2euy8" targetRef="Gateway_0ithekw" />
    <sequenceFlow id="Flow_09josl1" sourceRef="Gateway_193ryzg" targetRef="Gateway_0ithekw" />
    <serviceTask id="Activity_087e8qd" name="坡度分析" activiti:class="com.demo.activiti.service.model.CalcSlope">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputCalcSlopeGridCoverage">
          <activiti:string>DEM预处理结果</activiti:string>
        </activiti:field>
        <activiti:field name="zFactor">
          <activiti:string>1</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>坡度分析结果</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_0n5ywr3</incoming>
      <outgoing>Flow_09s0bow</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_0n5ywr3" sourceRef="Gateway_193ryzg" targetRef="Activity_087e8qd" />
    <sequenceFlow id="Flow_09s0bow" sourceRef="Activity_087e8qd" targetRef="Gateway_0ithekw" />
    <serviceTask id="Activity_0rbhr5h" name="重投影" activiti:class="com.demo.activiti.service.model.Reprojection">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputReprojectionGridCoverage">
          <activiti:string>土地利用裁剪</activiti:string>
        </activiti:field>
        <activiti:field name="targetCRS">
          <activiti:string>EPSG:32650</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>土地利用重投影</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_1w5a3yr</incoming>
      <outgoing>Flow_0j4109t</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_1w5a3yr" sourceRef="Activity_06zevtj" targetRef="Activity_0rbhr5h" />
    <serviceTask id="Activity_1jugvhh" name="邻近分析" activiti:class="com.demo.activiti.service.model.EuclideanDistance">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputEuclideanDistanceGridCoverage">
          <activiti:string>土地利用重投影</activiti:string>
        </activiti:field>
        <activiti:field name="sourcePixelValue">
          <activiti:string>6</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>水体邻近分析</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_0bspp1k</incoming>
      <outgoing>Flow_1dm4x52</outgoing>
    </serviceTask>
    <parallelGateway id="Gateway_1229jow">
      <incoming>Flow_0j4109t</incoming>
      <outgoing>Flow_0bspp1k</outgoing>
      <outgoing>Flow_0l5v4rw</outgoing>
    </parallelGateway>
    <sequenceFlow id="Flow_0j4109t" sourceRef="Activity_0rbhr5h" targetRef="Gateway_1229jow" />
    <sequenceFlow id="Flow_0bspp1k" sourceRef="Gateway_1229jow" targetRef="Activity_1jugvhh" />
    <serviceTask id="Activity_1jawm7r" name="邻近分析" activiti:class="com.demo.activiti.service.model.EuclideanDistance">
      <extensionElements>
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="start" />
        <activiti:executionListener class="com.demo.activiti.service.listener.MyExecutionListener" event="end" />
        <activiti:field name="inputEuclideanDistanceGridCoverage">
          <activiti:string>土地利用重投影</activiti:string>
        </activiti:field>
        <activiti:field name="sourcePixelValue">
          <activiti:string>7</activiti:string>
        </activiti:field>
        <activiti:field name="outputValueName">
          <activiti:string>湿地邻近分析</activiti:string>
        </activiti:field>
      </extensionElements>
      <incoming>Flow_0l5v4rw</incoming>
      <outgoing>Flow_09sjhqn</outgoing>
    </serviceTask>
    <sequenceFlow id="Flow_0l5v4rw" sourceRef="Gateway_1229jow" targetRef="Activity_1jawm7r" />
    <parallelGateway id="Gateway_1nir51n">
      <incoming>Flow_09sjhqn</incoming>
      <incoming>Flow_1dm4x52</incoming>
      <outgoing>Flow_1liu47z</outgoing>
    </parallelGateway>
    <sequenceFlow id="Flow_09sjhqn" sourceRef="Activity_1jawm7r" targetRef="Gateway_1nir51n" />
    <sequenceFlow id="Flow_1dm4x52" sourceRef="Activity_1jugvhh" targetRef="Gateway_1nir51n" />
    <sequenceFlow id="Flow_1ar3om7" sourceRef="Gateway_0ithekw" targetRef="Event_0emaqy3" />
    <sequenceFlow id="Flow_1liu47z" sourceRef="Gateway_1nir51n" targetRef="Gateway_0ithekw" />
  </process>
</definitions>

4.毕设过程中的问题汇总

响应式布局,height占满剩余空间,不要有滚动条

675918c31e941825c3ea448d34237e6.png

如图所示,前端界面右侧有滚动条,显得非常不美观

为什么设置了 height : 100%,会有纵向滚动条的出现?

页面中,#div1 是 高度100%,也就是body的高度,而在 #div1 之前还有一个div,也就是将浏览器窗口整体下降了那一个div的高度。

解决方法:

在app.vue界面设置style

给body设置overflow:auto; 设置 #app height: calc(100% - 1px);

html,body{
  height:100%;
	margin:0;
	overflow: auto;
}
#app {
  height:calc(100% - 1px);
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

工具栏和属性栏位置固定,画布扩展大小后滑动到下方不影响位置

设置position:fixed

.custom-properties-panel {
  position: fixed;
  right: 2.5rem;
  top: 8.125rem;
  width: 21.8rem;
  background-color: white;
  border-color: rgba(0, 0, 0, 0.09);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
  padding: 20px;
}

634329740f223c6945e14fd3609b333.png

Python之WinError 32:报错另一个程序在使用,文件操作不了

使用了 os.remove(output_file) 来删除文件,但是可能出现 [WinError 32] 另一个程序正在使用此文件,进程无法访问 的错误。这通常是因为在尝试删除文件时,另一个程序正在使用该文件。

解决方法:

延迟删除:在删除文件之前,添加一个适当的延迟时间,以确保其他程序已经释放对文件的控制。你可以使用 time.sleep() 来添加延迟时间,例如 time.sleep(1) 表示延迟 1 秒。

output_file='./src/main/webapp/data/python/outputGridCoverage.tif'
# 检查输出文件是否存在
if os.path.exists(output_file):
    time.sleep(0.5)  # 延迟 1os.remove(output_file)

后续:

移植到新电脑过程中仍然出现报错:Python之WinError 32:报错另一个程序在使用,文件操作不了

最终解决办法:

使用 contextlib 模块中的 suppress 函数来忽略 PermissionError 异常,这样即使文件被占用也能够删除

if os.path.exists(output_file):
    # 延迟 0.5time.sleep(0.5)

    # 删除文件
    with suppress(PermissionError):
        os.remove(output_file)
    print('删除成功')
else:
    print('文件不存在')

with suppress(PermissionError) 是 Python 中的上下文管理器,它用于临时忽略指定类型的异常。在这种情况下,suppress(PermissionError) 表示临时忽略 PermissionError 异常。

当代码块位于 with suppress(PermissionError): 内部时,如果发生 PermissionError 异常,该异常会被捕获并忽略,代码会继续执行而不会抛出异常

opeanlayer加载EPSG:32650的影像(涉及投影变换)

//定义EPSG:32650
      proj4.defs("EPSG:32650", "+proj=utm +zone=50 +datum=WGS84 +units=m +no_defs");
      register(proj4);
      var epsg32650 = new Proj.Projection({
        code: "EPSG:32650",
        extent: [-2500000, 0, 3045984, 9329000],
        units: "m"
      });
      Proj.addProjection(epsg32650);

首先使用proj4.defs()函数定义了"EPSG:32650"投影的参数。这里使用了UTM投影,并指定了50号带以及WGS84椭球体和米作为单位。

接下来通过ol.proj.proj4.register()函数将proj4中定义的投影注册到OpenLayers中。

然后,使用ol.proj.Projection()构造函数创建了一个名为"epsg32650"的Projection实例,该实例使用"EPSG:32650"作为其代码(EPSG编码),并指定了该投影的范围(extent)和单位(units)。这里范围被设置为[-2500000, 0, 3045984, 9329000],表示投影坐标系的范围。单位被设置为"m",表示单位是米。

最后,使用ol.proj.addProjection()函数将"epsg32650"投影添加到OpenLayers中,使得OpenLayers能够在地图中使用该投影进行坐标转换和显示

注意 在OpenLayers 6中,Proj 不是一个独立的模块,而是包含在 ol/proj 模块中的命名空间。因此,在导入时应该使用以下方式: import * as olProj from 'ol/proj';

根据图像的边界框信息计算中心点,并根据西经度的范围选择不同的投影方式

let [west, south, east, north] = image.getBoundingBox();
        // 计算中心点
        let centerX = (east + west) / 2;
        let centerY = (north + south) / 2;
        if (west >= -180 && west <= 180) {
          // 经度范围,使用4326投影
          this.WMSExtent=[west, south, east, north];
          this.WMSCenter=[centerX, centerY];
        } else {
          // 非经度范围,假设单位为米,使用32650投影
          // 转换EPSG:32650投影的四至范围到EPSG:4326投影
          this.WMSExtent = Proj.transformExtent([west, south, east, north], 'EPSG:32650', 'EPSG:4326');
          // 计算EPSG:32650投影的中心点
          this.WMSCenter = Proj.transform([centerX, centerY], 'EPSG:32650', 'EPSG:4326');
        }

使用 Proj.transformExtent([west, south, east, north], 'EPSG:32650', 'EPSG:4326') 将投影坐标的边界框转换为经纬度坐标

5.论文研究方向小记

1.分布式构建

空间数据需要被广泛共享、交换与使用 使空间数据存储与处理环境从传统集中式向分布式发展。

所谓分布式就是指数据和程序分散在多个服务器,以网络上分散分布的空间数据及受其影响的数据处理为研究对象的一种理论计算模型。

分布式有利于空间数据处理任务在整个计算机系统上进行分配与优化,克服了传统集中式系统会导致中心主机资源紧张与响应瓶颈的缺陷。很明显传统的集中环境很难满足分工明确的现代社会的需求分布式环境已成为空间数据管理与处理的主要发展趋势

问题:

开发的基于bpmn和wps服务链的地理处理工作流系统,我将封装好wps扩展模块的geoserver(包括待处理的服务数据)部署到一台服务器上,然后另一台服务器驱动bpmn工作流系统完成对wps服务xml的拼接,这是否属于分布式开发,是否可以提高效率

解答:

将封装好的WPS扩展模块的GeoServer和BPMN工作流系统部署在不同的服务器上,然后通过驱动BPMN工作流系统来完成对WPS服务XML的拼接。这种架构可以被认为是一种分布式开发方式。

分布式开发是指将一个应用程序或系统的不同组件或模块分布在多个独立的计算机或服务器上进行开发。每个服务器可以具有不同的功能和角色,并相互协作以实现整体的功能需求。将GeoServer和BPMN工作流系统部署在不同的服务器上,通过驱动工作流系统实现对WPS服务的拼接,可以充分利用不同服务器的资源和能力,提高系统的效率和可扩展性。

这种分布式架构的优势包括:

模块化设计:将不同的功能模块分离到不同的服务器上,使得系统的各个组件更易于维护和管理。 资源优化:不同服务器可以独立运行,充分利用各自的硬件资源,提高整体的处理能力和性能。 可扩展性:通过添加更多的服务器节点,可以灵活地扩展系统的处理能力,适应不断增长的用户需求。

2.BPMN.2.0与BPEL

BPEL 的发布是早于 BPMN 的,最早发布的 BPMN1.x 版本只是一些建模符号,不支持元模型,不支持存储和交换,也不支持执行。因此最初 BPEL 常用于服务组合的流程建模,而且由于 BPMN1.x 的缺陷问题,出现了一些从 BPMN 到BPEL 的转化算法,也可以使用 BPMN 语言来描述 BPEL 的流程。

但是随着BPMN2.0 规范的出现,解决了存储、执行的问题,由于 BPMN2.0 是支持图像化 的业务建模语言,开始被广泛应用于服务组合的建模方面。

BPMN 建模语言的优点体现在使用可视化的建模方式,用户使用起来更加的方便和直观,即使你不是了解完整的流程,也可以对自己负责的这一环节进行流程的构建。另外,使用者不一定必须具备编程能力,只要对流程的各个环节都很熟悉,就可以使用 BPMN 语言来构建流程图。和 BEPL 相比,BPMN 更注重业 务流程的完整周期的阶段,BPEL 则更注重业务实现的细节方面;并且 BPMN 是基于有向图的开发,适用于业务分析人员,对编程能力和技术没有太大的要求,但是 BPEL 则主要适用于技术分析人员和流程开发者,要求使用者对语法有一定的了解。因此,BPMN 建模语言使用起来相对简单,适合对较为完整的流程进行 定义,适合用于对时空大数据分析应用的流程建模.