未来索引
开启左侧

三维数字城市建设中的应用初探

[复制链接]
邢远 发表于 2015-3-7 23:48:13 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

题记

在实际工作中,笔者只是一个一线的数据加工者,所以本文所要讲述的内容主要以数据加工处理方面内容为主,至于理论性的东西,在文中不会存在也写不出来,主要是不擅长。

很长时间以来,感谢FME给我的数据加工工作带来的巨大帮助,一直想静下来把自己用FME的感受跟大家分享,苦于一直时间比较紧张,,这两天刚好工作告一段落,想想有什么关于FME的东西可以跟大家分享呢?现如今,三维数字城市建设处处都在说,我就想,有没有一种方法,可以批量的进行三维数字城市建筑物建模,于是我想到了强大的FME软件,结合以前一些项目,利用FME做了一个简单的测试,基于此,出现了这篇博文,希望文章的内容能为每一位FME爱好者提供点有趣的东西。好了,废话不说,进入正题。


一:任务描述

为了不浪费读者时间,用一句话来概括这次任务:从DGN地形图上提取建筑物边界和层数以及建筑结构信息,最后结合相应的建筑物材质纹理数据,将二维建筑物立起来,作为三维建筑物模型输出,同时找出不能建模的建筑物。


二:现有资料现状分析

现有数据资料分析如下:

数据格式:DGN

面积:几百平方公里,很大吧

数据现状问题描述:现有的DGN数据中,建筑物及建筑物注记主要是通过不同的层色和其他地物要素区分开来。但是数据中可能会存在某些建筑物本身不闭合,某些闭合的建筑物中没有建筑物注记或者注记层色错误等问题,这种情况就需要我们在处理的过程中将这类元素输出,作为结果参考依据。当然同样会存在建筑物边界线层色不对的情况,这不在我们考虑处理的范围。

另外,除了DGN格式的地形图之外,就只有已经处理好的建筑物材质纹理图片了,这些照片假设是直接可以使用的。说明一点,在本文中,原本是想通过利用建筑物不同的材质结构(砖、水泥、钢混等)对应不同的建筑物纹理照片,但由于本人专长PS水平实在太低,就把所有建筑物纹理设为一样的,采用同一张纹理照片。下面给出DGN图幅图面模拟截图。(说明,下图是为了模拟数据情况,自己画的一张不带坐标的地图截图,绝非真实数据)

1897141343031892504.jpg



图1 :DGN数据图面状况


三:任务分析与处理流程介绍

         初中时候,物理老师经常告诫我们,做考试题的时候,不能“得意忘形”,感谢老师。秉承“无图无真相”的原则,在下面的内容里面,我将多贴一些图,尽量做到图文并茂,一是可以减少文字输入,二是希望读者不要被我蹩脚拗口的文字描述给弄迷糊了。下面就该任务进行分析,并将其重点和难点列出来进行解说。我个人习惯,对于涉及内容稍微多一点的任务,都会先画一个流程图,用来说明任务执行过程。

3211348009293589051.jpg


图2:数据处理流程图


          结合流程图,将整个任务的的重点大致做一个梳理。

         节点1:DGN数据源准备。此节点好像没多少可说的,就是你把需要建模范围内的地形图拷贝出来待用。

         节点2与节点3:提取建筑物边界线和建筑物注记。这个过程也很简单,在fem workbench中读入DGN数据,读入选项按照几何类型(Geomety)进行分类读入,然后分别在用Tester转换器过滤出建筑物边界线与建筑物注记。

         节点4:建筑物构面。该节点算是有点工作量的内容,在流程图中实际上还隐藏了一点内容,就是把未构面成功的建筑物边界线输出,作为参考。

3888858278235073150.jpg



图3:建筑物边界线构面


针对构面操作,群里面很多大牛们说了很多遍了,同样可以用其他转换器来完成。不过既然把图贴出来了,我就捡着我觉得稍微需要注意的地方讲讲。

         建筑物构面,我们的思路不外乎下边这个流程:首先是准备了边界线,其次将所有的折线打断为线段,接下来就是创建线段之间的交点,再在交点处打断线段,然后就构面了。

         要想保证你最后的建筑物面正确,个人认为最起码有以下几点需要注意:

1.       针对本次任务的数据源DGN数据,建筑物可能是多边形,也可能是个椭圆,所以,要先把这些面状地物转换为线。在图3中,输入建筑物边界线之前实际上还有一个转换器GeometryCoercer,完成从面转为线的操作;

2.       对于弧段地物,是不能参与构面的,所以一般先用ArcStroker将弧段打散为线段。

3.       线段之间的交点一定要打断。这就是上图中MRFIntersector转化器的作用,在这个转换器中,Compute Fuzzy Intersections必须设置为Yes,该参数的意思就是说在可能虚交的地方创建真实交点。关于什么是虚交点,什么是真实交点,在MRFClean转换器帮助中有详细说明,另外,博客里也有一篇文章专门介绍MRFClean的,在此不再赘述。

关于图3中其他转换器,在图上已经注释的比较清楚了。

节点5:处理建筑物注记。在此节点中,要对建筑物注记做的处理其实很简单,就是把类似“砖5”或者”砖”,”5”之类的注记分离开来,形成建筑物的建筑结构和层数,例如:”砖5”分开为建筑结构”砖”与建筑层数”5”两部分。在这个节点中,处理思路为读取建筑物注记,将数字作为层数,非数字字符作为建筑结构属性。要保证数据拆分的准确性,需要对数据进行充分的调查,调查内容包括建筑物注记多长,有哪些结构,建筑物层数最多几层等。建筑物层数主要作为后期建筑物建模的高度使用。

1382042135650836855.jpg


图4:处理建筑物注记

在图4中,好像要说的内容已经在图上做了详细说明,PythyCaller中脚本的实现思路已在节点5的描述中进行说明,关于Fme中Python的使用,请参考www.fmepedia.com中对python的详细介绍,关于Python脚本的语法知识,我个人喜欢去w3cschool这个网站学习,简明扼要。如果要在这个节点再说点什么的话,那就把pythoncaller中的脚本片段贴出来吧。

import pyfme

from string import index

from string import atoi

from string import join

class MyPythonFactory(object):

    def __init__(self):

        self.count_features = 0

        self.logger = pyfme.FMELogfile()

        self.caizhi = ''

        self.layer = 0

        self.npos = -1

                   #_caizhi主要通过对建筑物注记的调查,记录了有多少种建筑物材质

        self._caizhi = '砖混水砼钢铁土玻璃简混砖砼破建'

                   #数字,用于和建筑物层数做比较

                   #关于提取建筑层数和建筑结构这点上,这是很原始的方法,用正则表达式应该可以完成此项功能

        self._layer = '0123456789'

    def input(self,feature):

        self.count_features += 1

        # Initialize some Python lists

        strtemp1 = ''

        strtemp2 = ''

        strtemp3 = ''

        strtemp4 = ''

        # 从igds_text_string 中提取DGN注记信息。

# 记得需要encode('gbk'),否则只能看到乱码

        self.textstring = feature.getUnicodeString('igds_text_string').encode('gbk').replace(' ','')

        #将建筑物注记才分开来,分别存放到caizhi 和 layer属性中

                   #需要说明的一点是:我在fme2011中作的测试,一个中文字符的长度为2

        if len(self.textstring) == 1:  #如果建筑物注记长度为1

            self.npos = self._layer.find(self.textstring) #在单个字符注记中查找数字

            if npos > -1:   #如果找到数字,则说明建筑结构为空,将数字作为建筑物层数

                self.caizhi = ''

                self.layer = atoi(self.textstring)

        elif len(self.textstring) == 2: #如果建筑物注记长度为2,

            strtemp1 = self.textstring[0:2]

            #self.logger.log( self.textstring + ' caizhi:' + strtemp1 ,1) #日志输出语句非常有用,因为可以作为跟踪调试程序的一种手段

            if self._caizhi.find(strtemp1) > -1:

                self.caizhi = strtemp1

                self.layer = 1

            elif self._layer.find(self.textstring[0:1]) > 0 and self._layer.find(self.textstring[1:]) > 0:

                self.caizhi = ''

                self.layer = atoi(self.textstring)  

        elif len(self.textstring) == 3: #如果建筑物注记长度为3

            strtemp1 = self.textstring[0:2]

            if self._caizhi.find(strtemp1) >= 0:

                self.caizhi = strtemp1;

                if self._layer.find(self.textstring[2:]) > 0:

                    self.layer = atoi(self.textstring[2:])

                else:

                    self.layer = 1

        elif len(self.textstring) == 4:  #如果建筑物注记长度为4

            strtemp1 = self.textstring[0:2]

            strtemp2 = self.textstring[2:]

            #strtemp3 = self.textstring[2:1]

            #strtemp4 = self.textstring[3:1]

            if self._caizhi.find(strtemp1) >= 0:

                if self._caizhi.find(strtemp2) >= 0:

                    self.caizhi = self.textstring

                    self.layer = 1

                elif self._layer.find(self.textstring[2:3]) > 0:

                    if self._layer.find(self.textstring[3:]) >= 0:

                       self.layer = atoi(strtemp2)

                       self.caizhi = strtemp1

                    else:

                        self.layer = atoi(elf.textstring[2:3])

                        self.caizhi = strtemp1

        elif len(self.textstring) == 5: #如果建筑物注记长度为5

            strtemp1 = self.textstring[0,2]

            strtemp2 = self.textstring[2:4]

            if self._caizhi.find(strtemp1) >= 0:

                if self._caizhi.find(strtemp2) >= 0:

                    self.caizhi = self.textstring[0,4]

                    if self._layer.find(self.textstring[4:]) >= 0:

                        self.layer = atoi(self.textstring[4:])

                else:

                    if self._layer.find(self.textstring[2:3]) > 0 and self._layer.find(self.textstring[3:4]) > 0:

                        self.layer = atoi(self.textstring[2:4])

                        self.caizhi = strtemp1

        elif len(self.textstring) >= 6:  #如果建筑物注记长度大于5

            self.caizhi = self.textstring

            self.alyer = 1

        self.logger.log('current process feature is : ' + self.textstring + ' caizhi:' + self.caizhi + ' layer:' + str(self.layer) ,1)        


        # Sending processed attributes back to FME

        feature.sETStringAttribute('caizhi',self.caizhi)   # return attribute back to FME

        feature.setIntAttribute('layer',self.layer) # return attribute back to FME


        # Write processed attributes to logfile


        self.pyoutput(feature)


    def close(self):

        self.logger.log('Total number of features: ' + str(self.count_features),1)


节点6:建筑物属性赋值。该节点很简单,只需要一个转换器PointOnAreaOverlayer输出_overlaps大于0的建筑屋面即为提取到建筑结构和层数的。_overlaps为0的则表示该建筑物内没有提取到相应的建筑物注记。按照每层建筑物3米计算,利用ExpressionEvaluator转换器,将层数layer乘以3,即为建筑物高度。

至节点6结束,建模数据的准备已经完成,下一步的工作就是如何建模了。

节点7、8:纹理数据输入,略过。

节点9: 建筑物建模。在建筑物建模这个节点上,涉及了屋顶模型生成,建筑物模型建模等,设计的可自由发挥的东西较多,我将核心部分列出来,做个说明。


917326949100423119.jpg



图5:建筑物建模

         在此节点中,我简单描述下三个转换器:Extruder、Orientor以及ApperenceAdder。Extruder作用是将建筑物面挤压出高度。Orientor作用是将建筑物面反向,如果不进行反向操作,贴上纹理之后应该是看不到的,纹理贴到建筑物内部了(不知此理解是否有误,如有误望指出)。ApperenceAdder作用就是贴纹理操作了,不做过多描述。

节点10:输出建筑物模型。在此节点,可以自行设置输出格式。为了做测试,笔者输出了两种格式,一是ESRI 的Geodatabase格式,便于在ArcScene中查看效果,另外一种格式为3ds格式,便于导入其他建模软件中进行深加工。

              最后,将我此次测试的结果截图展示一下,再次感受一下FME的强大。

1618762591064597060.jpg


图6:建筑物建模结果展示

四:总结

       在开始写这篇文章的时候,目标是能参与抽个奖,可越写思路越清晰,越觉得要写的东西太过简单,渐渐的没信心了,现在的目标改为:希望能耐心看完这篇文章的人能从中得到一点帮助,算是学习使用FME这么长时间来跟大家分享的一点东西吧。开个玩笑,下面来做个总结。

1.        FME是强大的。废话,地球人都知道。

2.        在开始每一项任务之前,仔细分析任务需求,画个流程图之类的物件,对工作的流程控制应该是比较有帮助的,同时可以帮助你把握项目的大致方向。个人习惯而已,不必当真。

3.        文中应该涉及了三个方面的内容。一是FME对传统数据的处理,例如构面;其次是在FME中嵌入python脚本的应用;最后就是个人认为相对涉及得较少一点的对三维数据的处理。


正如图6所示,测试生成的场景包括普通建筑物模型以及影像背景,如果仔细看的话,还能发现建筑物模型顶端还有屋顶。关于屋顶和影像背景部分的处理未能在文中做出表述。由于本人对建筑物建模方面的知识匮乏,很多相关概念不明白,对某些三维转换器的参数左右就不是很明白,例如ApperenceAdder纹理输入的front和back,我就不明白它们的区别在哪儿。在批量建筑物建模中,女儿墙的生成也可以直接在fme中完成。真期待FME的新版本增加更多对三维方面的支持。

         应该说,中国人对美的认可是比较苛刻的,例如对三维数字城市的模型精度要求就很高,所以本文所描述的内容实用意义不大,权作为FME在三维数据处理使用方面的一点探索吧。在文中笔者试图把一件事情说得清楚明白,期望能表述清楚一种思路,可发现越说越不清楚,所以赶紧打住,到此为止吧。

         最后,感谢FME群里面的乱马,跑等一系列高人在我学习FME过的帮助,另外非常欢迎各位战斗在数据生产一线的同志们来一起交流,把大家使用FME的更多经验分享出来,共同学习。


该会员没有填写今日想说内容.
高级模式
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注2973

粉丝3237

帖子9937

发布主题
阅读排行 更多
广告位
!jz_fbzt! !jz_sgzt! !jz_xgzt! 快速回复 !jz_sctz! !jz_fhlb! 搜索

智能技术共享平台 - 未来论

关注服务号

进入小程序

全国服务中心:

运维中心:天津

未来之家:天津 青岛 济南 郑州 石家庄

                商务邮箱:xy@mywll.com

Copyright © 2012-2021 未来派 未来论 (津ICP备16000236号-5)