学习《Building Applications with FME Objects》 之九 高级要素处理
在本教程第三张介绍了FME要素对象FMEOFeature的属性、几何图形和坐标系统,第三章是本章的基础,本章将介绍更多更强大的要素处理功能。
介绍要素处理时,要区分基于要素的处理和基于集合的处理,基于要素的处理是指操作独立要素,基于集合的处理是指操作一批独立要素。
本章将学习:
- 创建拓扑面(基于集合)
- 融合多边形(基于集合)
- 缓冲要素(基于要素)
- 产生多边形内部点(基于要素)
- 在要素上执行任意函数(基于要素)
- 偏移、旋转和缩放几何要素(基于要素)
- 操作聚合要素(基于要素和集合)
- 操作环要素(基于要素和集合)
- 应用处理器管道(factory pipeline)(基于要素和集合)
创建拓扑面
一些GIS存储几何要素用来反映一个spaghetti(公路)数据模型,在公路模型中,任何几何要素依赖于集合中的其他要素。
通常空间数据处理从一个公路模型到拓扑模型转换到面要素,如果线有适当的节点FME可以解决这个问题:所有线的交汇节点的开始和结束位置(或节点),创建一个拓扑面就是一个典型的基于集合的要素处理。
下面有10根线要素a,是一个公路模型,拓扑模型结果为聚合要素b,注意F10没有包含在拓扑中,因为它没有形成面要素。
FMEOFeature的processFeatures方法提供了一个一个简单的方法为有正确节点的线创建拓扑面,该方法尝试从1个多边形、1个环、1个包含多边形和环的聚合体创建面要素,产生的面关联到一个要素。
例如,m_fmeFeatureVector包含一组相同feature type和要素属性的线要素,下面代码用processFeatures从m_fmeFeatureVector创建面,所有面要素属性从第一个线要素克隆而来:
Set fmeParams = m_fmeSession.createStringArray
Call fmeParams.append("fme_convert_to_area")
Call fmeParams.append("fme_drop_line")
Set fmeFeature = m_fmeSession.createFeature
Call m_fmeFeatureVector.element(0).cloneAttributes _
(fmeFeature)
Call fmeFeature.processFeatures(m_fmeFeatureVector, _
fmeParams)
注意:当调用processFeatures时,应用程序放弃了对要素矢量的所有控制,fmeFeature本身会被删除,如果程序后续还要用到femFeare,则在调用processFeatures前先对fmeFeature做深度拷贝(克隆)。
默认情况下,未用的线要素(例如图中F10)也会被返回到结果要素数组m_fmeFeatureVector中,如果你不想返回未用的要素可以给fmeParams参数列表中店家fme_drop_line。
注意:如果应用程序需要处理大型数据集,则用processFeaturesOnDisk代替processFeatures,该方法工作在基于磁盘的对象集合。关于FMEOFeatureVectorOnDisk参看本教程第10章。
融合多边形
通过消除相邻的多边形公共边来融合多边形,通过公共属性来融合相邻的多边形,合并多边形是非常实用的功能,例如,融合地区为一个销售区片。
FMEOFeature的processFeatures提供简单的方法来融合多边形,给定一些多边形,融合为一个面要素,可以是多边形,环,或聚合体(含岛),合并多边形是一个典型的基于集合的要素处理。
例如,图a的六个多边形融合,结果如图b
m_fmeFeatureVector包含了一组相同属性和要素类型的要素,下列代码演示如何使用processFeatures去融合它们,合并后的要素属性克隆m_fmeFeatureVector中的第一个要素,处理结果关联到一个fmeFeature。
Set fmeParams = m_fmeSession.createStringArray
Call fmeParams.append("fme_polygon_dissolve")
Call fmeParams.append("fme_drop_line")
Set fmeFeature = m_fmeSession.createFeature
Call m_fmeFeatureVector.element(0).cloneAttributes _
(fmeFeature)
Call fmeFeature.processFeatures(m_fmeFeatureVector, _
fmeParams)
提示:当processFeatures调用时,应用程序失去对要素的控制,fmeFeature被删除,如果后续还想使用features,则在处理前应对其克隆。
内部的线要素被返回到m_fmeFeatureVector,如果不想返回内部线要素,则给fmeParams参数添加fme_drop_line。
缓冲要素
一个缓冲区或简单缓冲是一个与点,线,多边形有一定距离的封闭的多边形,缓冲区对于临近分析非常有用,例如:查找距离小河300英尺范围内的森林面积,缓冲区是典型的基于要素的几何处理。
FMEOFeature的buffer方法提供简单的方法创建一个要素的缓冲,它用一个新的面要素来替换几何要素以表示缓冲。下面代码为m_fmeFeatureVector内的每一要素创建缓冲,并添加新要素到集合,结果m_fmeFeatureVector将包含原始要素和缓冲要素,每个要素距离原始要素0.1个单位,采样角度5,缓冲要素属性克隆自原始要素。
Dim fmeFeature As FMEOFeature
Dim i As Integer
Dim lCount As Integer
lCount = m_fmeFeatureVector.entries
For i = 0 To lCount – 1Set fmeFeature = m_fmeSession.createFeature
Call m_fmeFeatureVector.element(i).Clone(fmeFeature)
Call fmeFeature.buffer(0.1, 5)
fmeFeature.attribute("fme_type") = "fme_area"
Call m_fmeFeatureVector.append(fmeFeature)
Next i
FMEEOFeature的buffer函数使用@Buffer函数。
创建对变形的内部点
给一个多边形要素,你的应用程序产生这个多边形内部点,使用FMEOFeature的generatePointInPolygon方法,基于要素的几何处理。
下面创建m_fmeFeatureVector集合中的每个多边形要素的内部点并添加到m_fmeFeatureVector,结果m_fmeFeatureVector将包含原始多边形要素和新的点要素。点属性克隆自多边形。
Dim fmeFeature As FMEOFeature
Dim sFeatureType As String
Dim i As Integer
Dim lCount As Integer
Dim X As Double
Dim Y As Double
Dim z As Double
sFeatureType = m_fmeFeatureVector.element(0).featureType
lCount = m_fmeFeatureVector.entries
For i = 0 To lCount - 1
Set fmeFeature = m_fmeSession.createFeature
Call m_fmeFeatureVector.element(i). _
generatePointInPolygon(False, X, Y, z)
Call fmeFeature.addCoordinate(X, Y, z)
fmeFeature.featureType = sFeatureType
fmeFeature.attribute("fme_type") = "fme_point"
fmeFeature.GeometryType = foPoint
Call m_fmeFeatureVector.append(fmeFeature)
Next i
generatePointInPolygon的第一个参数是一个标志,如果为True,generatePointInPolygon将查找中心点,需要比较长的计算时间,如果是三维要素,则也要运算Z值。
执行任意函数
FME函数提供了灵活的功能来操作要素,有两类函数:属性函数用来计算属性值,要素函数用来操作要素。要素函数操作要素的几何要素属性,如果你的应用程序需要FME函数,你则需要阅读FME Foundation手册的FME Functions章节,FME Functions, Factories and Transformers手册页是非常有用的参考。
FMEOFeature对象的performFunction 方法可基于要素运行任何函数,例如,使用@Log要素函数去记录一个要素:
Call fmeFeature.performFunction("@Log(Data Feature:,-1)", _
sResult)
提示:如果调用函数时没有参数,performFunction将报告一个错误。
performFunction调用一个要素函数时,结果参数将返回一个空字符串。当属性函数被调用,结果参数返回函数的输出,例如,下面代码添加一个lot_area属性到要素:
Call fmeFeature.performFunction("@Area(1000)", sResult)
fmeFeature.real32Attribute("lot_area") = sResult
偏移、旋转、缩放要素
通过变换坐标到新的位置来偏移要素,偏移需要指定x,y还有z(可选),FMEOFeature对象的offset方法用于偏移。
另一个有用的几何变换是围绕一个中心点旋转要素,FMEOFeature对象用rotate2D来围绕中心逆时针旋转要素。
还可以缩放要素,使用FMEOFeature的scale方法。
偏移,旋转,缩放都是典型的基于要素的几何处理,例如:
Call m_fmeFeatureVector.element(i).offset(dXOffset, _
dYOffset, dZOffset)
Call m_fmeFeatureVector.element(i).rotate2D(dXCenter, _
dYCenter, dAngle)
Call m_fmeFeatureVector.element(i).scale(dXFactor, _
dYFactor, dZFactor)
操作聚合要素
聚合要素在第三章介绍过了,FMEOFeature的splitAggregate方法用来将要素分解成非聚合要素并返回包含这些非聚合要素的列表。
注意:该方法不清除输入的要素,仅添加结果。
有两个办法创建聚合要素:chopUp和buildAggregateFeature。
基于要素处理的chopUp方法用于将现有的非聚合面或线要素加入聚合,如果要素几何图形的矢量超过一定数量,则超过的部分将不被聚合,最小的聚合阀值是10,对于面要素,chopUp分解面为非面的片段,对于线要素根据矢量阀值打算为段,chopUp方法调用示例:
Call m_fmeFeatureVector.element(i).chopUp(20)
基于集合处理的buildAggregateFeature 方法用输入的几何要素创建聚合几何体,语法如下:
Call fmeFeature.BuildAggregateFeature(m_fmeFeatureVector)
操作环要素
环要素在第三章介绍过,FMEOFeature的getDonutParts方法返回组成环要素的多边形几何图形。
注意:该方法不清除输入要素,仅添加。
创建环要素可以十一偶那个makeDonuts方法。
makeDonuts方法从一些多边形要素中构造一个或多个环要素,返回的结果是聚合体,该方法调用如下:
Call fmeFeature.makeDonuts(m_fmeFeatureVector, False)
该方法第二个参数是keepHoles标志,如果为True,该方法返回作为要素岛的多边形。
outerShell方法获得环要素的外圈多边形,如果调用outerShell方法的要素不是环要素,则没有作用,方法调用如下:
Call fmeFeature.outerShell
如果你处理的格式对环的组成部分坐标有方向规则(左手或右手规则),则你可以使用getOrientation和setOrientation方法控制坐标存储顺序。
应用处理器管道(Factory Pipeline)
FME处理器是整合了要素和属性值的函数,并且被处理器管道所连接。处理器管道允许FME对象执行基于要素和基于集合的处理任务,实际上,所有本章介绍的要素处理都是用FMEOFeature方法,这些方法也都可以用要素处理器代替,用处理器管道代替内建方法需要一些设置,但它更强大,更易于修改和扩展。
如果想使用处理器管道,推荐你阅读FME Foundation 手册的FME Factories 章节,它提供了一些FME处理器的基础信息,FME Functions, Factories and Transformers 手册也很有参考价值。
FMEOPipelin对象提供了接口来构造和使用处理器管道,方法和属性如下图:
使用处理器管道需要以下步骤:
- 创建和定义管道
- 在管道中插入要素
- 从管道获取要素
创建和定义管道
创建新的处理器管道,你必须用FMEOSession对象的createFactoryPipeline方法,代码如下:
Set fmePipeline = m_fmeSession.createFactoryPipeline( _
"Test", fmeDirectives)
第一个参数是管道名,第二个参数允许你指定管道中的处理器和函数的参数,配置参数关键字必须有”__”前缀。
注意:FMEOPipeline的configureFunction方法为函数指定配置,例如@Lookup,@Relate和@Sql这些函数需要配置参数。
一旦管道被建立,有3个办法指定要素处理器:
- 放置所有的处理器到一个文本文件并调用addFactories方法。
- 每个独立的处理器放到一个字符串,并为每一个字符串调用addFactories方法。
- 放置每一个处理器到FME字符串数组并调用addFactoryFromStringArray。
你可以选择使用你觉得合适的方法来添加处理器,首先所有的处理器管道在一个文件中在开发和调试时较少发生错误,管道文件使用标准的FME映射文件语法(包括连接字符)你可以用FME Universal Viewer应用管道到现有数据集来测试处理器管道(在Display Control面板中的View节点上点右键,Apply Pipleline命令)。
注意:在FME Universal Viewer 进行测试时,如果视图中有多个数据集,则每个数据集将被一个对应的管道实例处理。
一旦管道功能被设计、实现和测试,addFactory和addFactoryFromStringArray方法可以将管道代码与程序代码一同编译,帮助保护你的知识产权,这两个方法也可以装在基于文件的管道,方法使用范例:
sFactory = "FACTORY_DEF * DonutHoleFactory "
sFactory = sFactory & "INPUT FEATURE_TYPE * "
sFactory = sFactory & "fme_geometry fme_donut "
sFactory = sFactory & "OUTPUT OUTERSHELL FEATURE_TYPE * "
sFactory = sFactory & "OUTPUT HOLE FEATURE_TYPE *"
Call fmePipeline.addFactory(sFactory, " ")
注意:当空格作为addFactory的分割符,函数调用则不能包含空格在参数列表中,如果处理器包含属性值包含空格,你将需要选择其他字符来代替空格作为分割幅(入”|” 或”;”)
下面的内容讲解addFactorys方法。
插入一些要素到管道
一旦处理器管道被创建和定义,它就准备开始接受要素,添加要素到处理器管道,你的应用程序必须使用FMEOPipeline的processFeature方法:
Call fmePipeline.processFeature( _
m_fmeFeatureVector.element(i))
processFeature方法处理传入的要素,返回空值,如果应用程序希望保留原始要素,在处理前需要用FMEOFeature的clone方法做拷贝。
从管道返回一些要素
你的应用程序通过管道返回和处理要素,输入的原始的要素并没有被管道改变。
如果你的管道仅包含一个基于要素处理的处理器,在processFeature返回控制权给应用程序后,结果将理解可用,获得返回的要素用getOutputFeature,例如:
Call fmePipeline.processFeature( _
m_fmeFeatureVector.element(i))
bEnd = fmePipeline.getOutputFeature(fmeFeature)
当最后一个要素被读取后,getOutputFeature返回True。
当管道包含一个或多个基于集合处理的处理器时,例如TopologyFactory,PolygonFactory或SortingFactory,你的应用程序在最后一个要素被插入后用FMEOPipeline的 allDone方法通知管道,在allDone方法返回控制权后,返回的要素立即变为可用。如果在allDone前调用getOutputfeature,则不能从输入读取要素,尽管有一些要素可能在管道中,但getOutputFeature将返回True。
注意:一个管道不能在调用allDone方法后重用,换句话说,调用allDone后,addFeature调用将失效。
综合练习
下面展示了本章所以学知识,用基于文件的处理器管道标记sPipelinefile来处理m_fmeFeatureVector中的要素。
Sub ApplyPipeline(sPipelineFile As String)
Dim i As Integer
Dim lCount As Integer
Dim bEnd As Boolean
Dim fmePipeline As FMEOPipeline
Dim fmeFeature As FMEOFeature
Dim fmeDirectives As FMEOStringArray
Set fmePipeline = m_fmeSession.createFactoryPipeline( _
"Test", fmeDirectives)
Call fmePipeline.addFactories(sPipelineFile)
lCount = m_fmeFeatureVector.entries
For i = 0 To lCount - 1
Call fmePipeline.processFeature( _
m_fmeFeatureVector.element(i))
Next i
Call fmePipeline.allDone
m_fmeFeatureVector.Clear
bEnd = False
Do While bEnd = False
Set fmeFeature = m_fmeSession.createFeature
bEnd = fmePipeline.getOutputFeature(fmeFeature)
If bEnd = False Then
Call m_fmeFeatureVector.append(fmeFeature)
End If
Loop
End Sub
如果你想创建一个拓扑面,你可以用上面的函数调用管道文件,管道文件内容如下:
FACTORY_DEF * PolygonFactory \
FACTORY_NAME POLYGONBUILDER \
INPUT FEATURE_TYPE * \
fme_geometry fme_line \
fType @FeatureType() \
GROUP_BY fType \
VERTEX_NODED \
OUTPUT POLYGON FEATURE_TYPE * \
@FeatureType(&fType) \
@RemoveAttributes(fType) \
fme_type fme_area
融合多边形,可以用下面的管道文件:
FACTORY_DEF * PolygonFactory \
FACTORY_NAME POLYGONBUILDER \
INPUT FEATURE_TYPE * \
fme_geometry fme_line \
fType @FeatureType() \
GROUP_BY fType \
VERTEX_NODED \
OUTPUT POLYGON FEATURE_TYPE * \
@FeatureType(&fType) \
@RemoveAttributes(fType) \
fme_type fme_area
至于缓冲区要素和产生多边形内部点的管道文件由读者自行练习。
参考资料:
《Building Applications with FME Objects》February 2005
转载请注明文章来源 http://www.cnblogs.com/booolee