阅读:1634回复:0
[原创]常见DEM格式分析与三维分层设色显示
在城市地质调查项目中需要读取<FONT face="Courier New">CNSDTF</FONT> DEM数据,这种格式与美国USGS DEM数据格式相比较,有些简单,不包含椭球体,投影方式等元数据,实际上就是投影后的平面格网数据,所以读取入系统不困难.以后将介绍ERDAS IMG格式的读取,这个就显得有些复杂了.<BR> std::locale::global(std::locale(""));
<P> ifstream _demfile; //DEM文件流<BR> _demfile.open(lpszPathName); //读取文件<BR> <BR> string sDataName,sCNDataName;<BR> string sVersion;float iVersion;<BR> string sAlpha;float fAlpha;<BR> string sUnit; string sUnitName;<BR> string sCompress; float dCompress;<BR> string sX0; double dX0;<BR> string sY0; double dY0;<BR> string sDX; double dDX;<BR> string sDY; double dDY;<BR> string sRow; int iRows;<BR> string sColumn; int iColumns;<BR> string sValueTypeName; string sValueType;<BR> string sHzoom; int iHzoom;<BR> string sMinV;<BR> string sMaxV;</P> <P> if(_demfile)<BR> {<BR> _demfile>>sDataName>>sCNDataName;<BR> _demfile>>sVersion>>iVersion;<BR> _demfile>>sAlpha>>fAlpha;<BR> _demfile>>sUnit>>sUnitName;<BR> _demfile>>sCompress>>dCompress;<BR> _demfile>>sX0>>dX0;<BR> _demfile>>sY0>>dY0;<BR> _demfile>>sDX>>dDX;<BR> _demfile>>sDY>>dDY;<BR> _demfile>>sRow>>iRows;<BR> _demfile>>sColumn>>iColumns;<BR> _demfile>>sValueTypeName>>sValueType;<BR> _demfile>>sHzoom>>iHzoom;<BR> _demfile>>sMinV;<BR> _demfile>>sMaxV;</P> <P> }<BR> else <BR> {<BR> AfxMessageBox("无法读取文件数据头!");<BR> return false;<BR> }<BR> dY0 = dY0 - dDY*iRows; //从文件中读取的dYO记录的是最大数值<BR> long index = 0,PointsTotalNumber = 0;<BR> int i,j;<BR> double tmpHeight = 0;<BR> <BR> POINT3d* p3dDEMGridPoint = new POINT3d[iRows*iColumns]; //准备读文件中数据<BR> <BR> double dNodata = -99999;<BR> double dZMin = 9999,dZMax = -9999;<BR> for(j=iRows-1;j>=0;j--) //由于此文件记录Y数值的方法与其他不同,需要翻转数据<BR> {<BR> for(i=0;i<iColumns;i++)<BR> {<BR> index = j*iColumns+i;<BR> _demfile>>tmpHeight;<BR> if(iHzoom != 0) tmpHeight = tmpHeight/iHzoom; //原始的缩放因子<BR> p3dDEMGridPoint[index][2] = tmpHeight;<BR> <BR> if( tmpHeight > -9999) //也就是不等于 dNodata<BR> {<BR> if(dZMin > tmpHeight) dZMin = tmpHeight; //记录高程上的最小数值<BR> if(dZMax < tmpHeight) dZMax = tmpHeight; //记录高程上的最大数值<BR> }<BR> <BR> }<BR>}</P> <P><BR> </P> <P><IMG src="http://www.cnblogs.com/images/cnblogs_com/wuhanhoutao/111912/r_layercoloring1.jpg" border=0></P> <P>美国USGS的DEM数据读取的程序代码已经提供,关键是对文件头的处理要注意每个字段的含义,到数据部分需要注意XY轴的最大和最小数值,Z轴的最大最小数值提取的时候,要防止NodataValue数据的干扰,因为部分数据是NodataValue,会非常小或大。<BR> </P> <P>读取美国USGS的DEM数据程序</P> <P>string quadName,processInfo;<BR> double seGeoCornerX,seGeoCornerY;<BR> long processCode;<BR> string sectionIndicator, mapCenterCode;<BR> long levelCode,elevPattern,groundRefSysCode,groundRefSysZone,groundRefSysUnits;<BR> long elevUnits, numPolySides;<BR> DEMPointVector demCorners;<BR> double counterclockAngle;<BR> long elevAccuracyCode;<BR> <BR> double spatialResX,spatialResY,spatialResZ;<BR> long profileRows,profileColumns;<BR> long largeContInt,maxSourceUnits,smallContInt,minSourceUnits;<BR> long sourceDate, inspRevDate;<BR> string inspFlag;<BR> long valFlag;<BR> long suspectVoidFlg;<BR> long vertDatum,horizDatum;<BR> long dataEdition;<BR> long perctVoid;<BR> long westEdgeFlag,northEdgeFlag,eastEdgeFlag,southEdgeFlag;<BR> double vertDatumShift; //通过文件流得到DEM文件头信息<BR> <BR> <BR> char bufstr[1024];<BR> char temp[1024];<BR> long i;</P> <P> DEMUtil::getRecord(dem,bufstr); //从文件流中获得信息</P> <P> strncpy(temp, bufstr, 40); //从获得信息中拷贝到临时变量<BR> temp[40] = '\0';<BR> quadName = temp;</P> <P> strncpy(temp,bufstr+40,40); //从获得信息中拷贝到临时变量<BR> temp[40] = '\0';<BR> processInfo = temp;<BR> <BR> DEMUtil::getDouble(bufstr, 109, 13, seGeoCornerX);<BR> DEMUtil::getDouble(bufstr, 122, 13, seGeoCornerY);<BR> processCode = DEMUtil::getLong(bufstr, 135, 1); //135 = 122 + 13</P> <P> strncpy(temp,bufstr+137,3);<BR> temp[3] = '\0';<BR> sectionIndicator = temp;</P> <P> strncpy(temp,bufstr+140,4);<BR> temp[4] = '\0';<BR> mapCenterCode = temp;<BR> <BR> levelCode = DEMUtil::getLong(bufstr, 144, 6); //level编码<BR> elevPattern = DEMUtil::getLong(bufstr, 150, 6);<BR> groundRefSysCode = DEMUtil::getLong(bufstr, 156, 6);<BR> groundRefSysZone = DEMUtil::getLong(bufstr, 162, 6);<BR> groundRefSysUnits = DEMUtil::getLong(bufstr, 528, 6); //得到平面上使用的度量单位<BR> elevUnits = DEMUtil::getLong(bufstr, 534, 6); //得到Z轴上的度量单位<BR> numPolySides = DEMUtil::getLong(bufstr, 540, 6);</P> <P> for (i = 0; i < 4; i++)<BR> {<BR> double x,y;<BR> long pos = 546 + (i * 48);<BR> DEMUtil::getDouble(bufstr, pos, 24, x);<BR> DEMUtil::getDouble(bufstr, pos + 24, 24, y);<BR> demCorners.push_back(DEMPoint(x,y)); //各角部顶点数据<BR> }</P> <P> DEMUtil::getDouble(bufstr, 738, 24, m_dminElevation); //得到最小高程数值<BR> DEMUtil::getDouble(bufstr, 762, 24, m_dmaxElevation); //得到最大高程数值 <BR> DEMUtil::getDouble(bufstr, 786, 24, counterclockAngle );<BR> elevAccuracyCode = DEMUtil::getLong(bufstr, 810, 6);<BR> DEMUtil::getDouble(bufstr, 816, 12, spatialResX); //X轴分辨率<BR> DEMUtil::getDouble(bufstr, 828, 12, spatialResY); //Y轴分辨率<BR> DEMUtil::getDouble(bufstr, 840, 12, spatialResZ); //Z轴分辨率<BR> profileRows = DEMUtil::getLong(bufstr, 852, 6); //得到行数<BR> profileColumns = DEMUtil::getLong(bufstr, 858, 6); //得到列数<BR> largeContInt = DEMUtil::getLong(bufstr, 864, 5);<BR> maxSourceUnits = DEMUtil::getLong(bufstr, 869, 1);<BR> smallContInt = DEMUtil::getLong(bufstr, 870, 5);<BR> minSourceUnits = DEMUtil::getLong(bufstr, 875, 1);<BR> sourceDate = DEMUtil::getLong(bufstr, 876, 4);<BR> inspRevDate = DEMUtil::getLong(bufstr, 880, 4);<BR> <BR> strncpy(temp, bufstr+884,1);<BR> temp[1]='\0';<BR> inspFlag = temp;</P> <P> valFlag = DEMUtil::getLong(bufstr, 885, 1);<BR> suspectVoidFlg = DEMUtil::getLong(bufstr, 886, 2);<BR> vertDatum = DEMUtil::getLong(bufstr, 888, 2); //垂直<BR> horizDatum = DEMUtil::getLong(bufstr, 890, 2); //水平<BR> dataEdition = DEMUtil::getLong(bufstr, 892, 4);<BR> perctVoid = DEMUtil::getLong(bufstr, 896, 4);<BR> westEdgeFlag = DEMUtil::getLong(bufstr, 900, 2); //西部<BR> northEdgeFlag = DEMUtil::getLong(bufstr, 902, 2); //北部<BR> eastEdgeFlag = DEMUtil::getLong(bufstr, 904, 2); //东部<BR> southEdgeFlag = DEMUtil::getLong(bufstr, 906, 2); //南部<BR> DEMUtil::getDouble(bufstr, 908, 7, vertDatumShift);</P> <P> m_p3dDEMGrid->SetXMin( demCorners[0].getX() );<BR> m_p3dDEMGrid->SetYMin( demCorners[0].getY() );<BR> m_p3dDEMGrid->SetXCellSize( spatialResX );<BR> m_p3dDEMGrid->SetYCellSize( spatialResY );<BR> m_p3dDEMGrid->SetColumns( profileColumns );<BR> <BR> long retval;</P> <P> retval = FillGeographic(dem,incrementalRead);</P> <P>long ImportDEMDataUSGS::FillGeographic(istream; dem,bool incrementalRead)<BR>{<BR>if (m_bReadingFileHeadOnlyOnce) <BR>{<BR> m_lCurProfile = 0;<BR>}</P> <P> while (m_lCurProfile < m_p3dDEMGrid->GetColumns()) //断面数据还没有读完<BR> {<BR> m_vecProfiles.push_back(DEMProfile());<BR> dem >> m_vecProfiles.back(); //存储断面数据<BR> m_lCurProfile++;<BR> if (incrementalRead) //倘若采用增量读法,则马上返回<BR> return m_p3dDEMGrid->GetColumns() - m_lCurProfile + 1;<BR> }<BR> <BR> int width = m_p3dDEMGrid->GetColumns();<BR> int height = m_vecProfiles[0].getNumberOfElevations(); //假设所有的断面和第一个断面有一样的一连串高程数值<BR> m_p3dDEMGrid->SetRows( height );</P> <P> m_ppt3dPoint = new POINT3d[width * height]; //added</P> <P> double dXMin = m_p3dDEMGrid->GetXMin();<BR> double dYMin = m_p3dDEMGrid->GetYMin();<BR> double dXCellSize = m_p3dDEMGrid->GetXCellSize();<BR> double dYCellSize = m_p3dDEMGrid->GetYCellSize();<BR> int i,j;<BR> long Index;<BR> for (i = 1; i < width; i++)<BR> {<BR> DEMElevationVector const; elev = m_vecProfiles.getElevations(); //得到这个断面的一连串高程数值<BR> for (j = 0; j < height; j++)<BR> {<BR> Index = width * j + i;<BR> m_ppt3dPoint[Index][0]=dXMin + i*dXCellSize; <BR> m_ppt3dPoint[Index][1]=dYMin + j*dYCellSize; <BR> m_ppt3dPoint[Index][2]=elev[j]/m_dPlaneHeightRadio; //保证三轴单位统一<BR> }<BR> }</P> <P>i=0; //为了填充数组第一列<BR>DEMElevationVector const; elev_1 = m_vecProfiles[1].getElevations();<BR>for(j = 0; j < elev_1.size();j++)<BR>{<BR> Index = width * j + i;<BR> m_ppt3dPoint[Index][0]=dXMin + i*dXCellSize; <BR> m_ppt3dPoint[Index][1]=dYMin + j*dYCellSize;<BR> m_ppt3dPoint[Index][2]=elev_1[j]/m_dPlaneHeightRadio; <BR> <BR>}<BR>m_vecProfiles.erase(m_vecProfiles.begin(), m_vecProfiles.end());<BR>return 0;<BR>}<BR></P> <P><IMG src="http://hiphotos.baidu.com/wuhanhoutao/pic/item/22cdc0ee53e9c0222cf534f8.jpg" border=0></P> <P><FONT face="Courier New"> SDTS(Spatial Data Transfer Standard ) DEM 读取也是颇费力的一件事情,首先这个体系并不是一个单一的数据文件,而是由一系列的相同后缀(.ddf)构成文件的组合.其中,*CATD.DDF是首要文件,相当于一个索引,告知其他文件的功能.剩下的文件中,*LDEF.DDF可以获得格网的长宽数值。*IREF.DDF文件可以得到XY轴的分辨率。*CELL.DDF是真正带有数据的文件。可以提取高程数值。另外还涉及到读取8211文件的问题,所以说,是件比较费力的事情.<BR> 在<a href="http://wuhanhoutao.cnblogs.com/" target="_blank" >http://wuhanhoutao.cnblogs.com/</A>提供程序框架和结果图供大家参考。愿与大家多多交流.<BR></FONT></P> |
|