?? shpfile.cpp
字號:
#include "stdafx.h"
//#include <d3dtypes.h>
#include "shpFile.h"
#include "MapPoint.h"
#include "MapPoints.h"
#include "MapLine.h"
#include "MapPolygon.h"
#include "MapFields.h"
CShpFile::CShpFile()
{
int i;
bShpOpen = FALSE;
bShxOpen = FALSE;
m_shpType = NULLSHP;
/* -------------------------------------------------------------------- */
/* Establish the byte order on this machine. */
/* -------------------------------------------------------------------- */
i = 1;
if( *((uchar *) &i) == 1 )
m_bBigEndian = FALSE;
else
m_bBigEndian = TRUE;
}
CShpFile::~CShpFile()
{
CMapPoint* pPt;
CMapPoints* pPts;
CMapLine* pLine;
CMapPolygon* pPolygon;
while(!m_ObList.IsEmpty())
{
switch ( m_shpType )
{
case POINT:
pPt =(CMapPoint*)m_ObList.RemoveTail();
delete pPt;
break;
case MULTIPOINT:
pPts =(CMapPoints*)m_ObList.RemoveTail();
delete pPts;
break;
case POLYLINE:
pLine =(CMapLine*)m_ObList.RemoveTail();
delete pLine;
break;
case POLYGON:
pPolygon =(CMapPolygon*)m_ObList.RemoveTail();
delete pPolygon;
break;
default:
m_ObList.RemoveTail();
break;
}
}
if ( bShpOpen )
fShp.Close();
if (bShxOpen)
fShx.Close();
if ( pRecordSet )
delete pRecordSet;
}
/*************************************************
描述: 讀入Shp、shx文件 格式 參閱ESRI技術白皮書
輸入: 文件名(全路徑)
輸出: 成功返回TRUE 失敗返回FALSE
*************************************************/
BOOL CShpFile::ReadShp(CString& csFileName)
{
int iTemp;
CString csShxName;
CFileException fe;
SHPHEADER varHeader;
//打開主文件
if ( !fShp.Open(csFileName, CFile::modeRead|CFile::shareDenyWrite,&fe))
return FALSE;
bShpOpen = TRUE;
//打開索引文件
csShxName = csFileName.Left(csFileName.GetLength() - 3);
csShxName = csShxName + "shx";
if ( !fShx.Open(csShxName, CFile::modeRead|CFile::shareDenyWrite,&fe))
return FALSE;
bShxOpen = TRUE;
TRY
{
//讀主文件頭 長100字節
if ( fShp.Read(&varHeader , sizeof(SHPHEADER))!= sizeof(SHPHEADER))
return FILE_READERR;
iTemp = varHeader.iFileCode;
if ( !m_bBigEndian )
SwapWord(sizeof(int),&iTemp);
if ( iTemp != 9994 ) //是否是shp文件
return FILE_CODEERR;
if ( varHeader.iVersion != FILE_VERSION ) //文件版本是否正確
return FILE_VERSIONERR;
//shp 類型
m_shpType = varHeader.iShpType;
m_shpFileLength = varHeader.iFileLength;
if ( !m_bBigEndian )
SwapWord(sizeof(int),&m_shpFileLength);
//保存數據最大矩形范圍
m_Extent.SetLeft(varHeader.dbXMin);
m_Extent.SetRight(varHeader.dbXMax);
m_Extent.SetTop(varHeader.dbYMin);
m_Extent.SetBottom(varHeader.dbYMax);
//讀索引文件頭 長100字節
if ( fShx.Read(&varHeader , sizeof(SHPHEADER))!= sizeof(SHPHEADER))
return FILE_READERR;
iTemp = varHeader.iFileCode;
if ( !m_bBigEndian )
SwapWord(sizeof(int),&iTemp);
if ( iTemp != 9994 ) //是否是shx文件
return FILE_CODEERR;
if ( varHeader.iVersion != FILE_VERSION ) //文件版本是否正確
return FILE_VERSIONERR;
m_shxFileLength = varHeader.iFileLength;
if ( !m_bBigEndian )
SwapWord(sizeof(int),&m_shxFileLength);
//通過索引文件計算主文件記錄個數 文件長度數值以16位計
m_iRecordCount = ((m_shxFileLength - 50 )*2)/sizeof(SHXRECORD);
if ( !ReadRecord() )
return FILE_READERR;
if ( !ReadDBF(csFileName))
return FALSE;
}
CATCH(CFileException ,eload)
{
fShp.Abort();
return FALSE;
}
END_CATCH
return TRUE;
}
/*************************************************
描述: 讀入DBF文件格式
輸入: 文件名(全路徑)
輸出: 成功返回TRUE 失敗返回FALSE
*************************************************/
BOOL CShpFile::ReadDBF(CString& csFileName)
{
CString csDbfName;
BOOL bResult;
//創建記錄集對象
pRecordSet = new CMapRecordSet;
ASSERT ( pRecordSet != NULL );
csDbfName = csFileName.Left(csFileName.GetLength() - 3);
csDbfName = csDbfName + "dbf";
//打開DBF文件
bResult = pRecordSet->openDBF(csDbfName);
if ( !bResult )
delete pRecordSet;
return bResult;
}
/*************************************************
描述: 獲得當前地圖文件最大矩形范圍
輸入: 無
輸出: 地圖矩形范圍
*************************************************/
CMapRectangle CShpFile::GetExtent()
{
return m_Extent;
}
/*************************************************
描述: 設置地圖文件最大矩形范圍
輸入: 地圖矩形范圍
輸出: 無
*************************************************/
void CShpFile::SetExtent(CMapRectangle& extent )
{
m_Extent.SetLeft(extent.GetLeft());
m_Extent.SetRight(extent.GetRight());
m_Extent.SetTop(extent.GetTop());
m_Extent.SetBottom(extent.GetBottom());
}
/*************************************************
描述: 設置Shp對象類型
輸入: shp 類型
輸出: 無
*************************************************/
void CShpFile::SetShpType(int& iShpType)
{
m_shpType = iShpType;
}
/*************************************************
描述: 讀入Shp對象坐標
輸入: 無
輸出: 成功返回TRUE 失敗返回FALSE
*************************************************/
BOOL CShpFile::ReadRecord()
{
int i,j,k,m;
int iDataLen,iLength,iIndex;
int *pIParts;
double dbTmp;
char *pszBuffer,*lpVer;
BOOL bEof;
SHPINFO shpIn;
SHPRECORDHEADER RecordHeader;
CMapRectangle objRectangle;
CMapPoint *pPoint;
CMapPoints *pPoints;
CMapParts *pParts;
CMapLine *pLine;
CMapPolygon *pPolygon;
bEof = FALSE;
switch ( m_shpType )
{
case NULLSHP:
return FALSE;
break;
case POINT:
{
SHPPTCONTENT point;
//讀入點記錄
for ( i = 1 ; i <= m_iRecordCount ; i++ )
{
iLength = SetRecordPos(i);
if ( iLength <= 0 )
return FALSE;
//獲得記錄頭信息
if (!GetRecordHeader(RecordHeader))
return FALSE;
//記錄內容長度是否與shp實體大小一致,索引記錄長度是否與記錄內容長度一致
if ( RecordHeader.iContentLength*2 != sizeof(point)||
RecordHeader.iContentLength*2 != iLength)
return FALSE;
if(fShp.Read(&point,sizeof(point))!= sizeof(point))
return FALSE;
pPoint = new CMapPoint;
iIndex = i - 1;
pPoint->SetIndex(iIndex);
if ( pPoint == NULL )
return FALSE;
//類型是否匹配
if ( point.iShpType != m_shpType)
return FALSE;
pPoint->SetX(point.dbX );
pPoint->SetY(point.dbY );
m_ObList.AddTail(pPoint);
}
}
break;
case POLYLINE:
pszBuffer = new char [MAX_BUFFER_SIZE]; //分配緩沖區
if ( pszBuffer == NULL )
return FALSE;
memset(pszBuffer , 0 , MAX_BUFFER_SIZE);
//讀入線記錄
for ( i = 1 ; i <= m_iRecordCount ; i++ ) //m_iRecordCount
{
iLength = SetRecordPos(i);
if ( iLength <= 0 )
return FALSE;
pLine = new CMapLine();
iIndex = i - 1;
pLine->SetIndex(iIndex);
if ( pLine == NULL )
return FALSE;
//獲得記錄頭信息
if (!GetRecordHeader(RecordHeader))
return FALSE;
if ( !GetShpInfo(shpIn))
return FALSE;
if (shpIn.ishpType != POLYLINE )//類型不匹配
{
delete pLine;
continue;
}
if ( shpIn.iNumParts*sizeof(int) > MAX_BUFFER_SIZE )
{
//多義線段數大于最大緩沖區長度,忽略該對象
delete pLine;
continue;
}
//計算對象內容實際長度
j = sizeof(SHPINFO) + shpIn.iNumParts*sizeof(int) ;
j += shpIn.iNumPoints*sizeof(SHPPOINT);
//判斷實際長度是否與索引文件中記錄的一致
if ( RecordHeader.iContentLength*2 != j )
{
delete pLine;
continue;
}
//設置shp矩形范圍
objRectangle.SetLeft(shpIn.Box[0].dbX);
objRectangle.SetTop(shpIn.Box[0].dbY);
objRectangle.SetRight(shpIn.Box[1].dbX);
objRectangle.SetBottom(shpIn.Box[1].dbY);
pLine->SetExtent(objRectangle);
pIParts = new int[shpIn.iNumParts];
if ( pIParts == NULL )
{
delete pLine;
return FALSE;
}
//讀入多義線段索引
if ( fShp.Read(pIParts,shpIn.iNumParts*4) != (uint)(shpIn.iNumParts*4))
{
delete pLine;
return FALSE;
}
//點坐標存儲所占字節數
iLength = shpIn.iNumPoints*sizeof(SHPPOINT);
//初始化緩沖區數據
iDataLen = ReadPoint(pszBuffer,iLength,bEof);
if ( iDataLen < 0 )
{
delete pLine;
delete pIParts;
return FALSE;
}
lpVer = pszBuffer;
for ( j = 0 ; j < shpIn.iNumParts ; j++ )
{
pParts = new CMapParts();
pPoints = new CMapPoints();
if ( pParts == NULL || pPoints == NULL)
return FALSE;
if ( j == shpIn.iNumParts - 1 )
{
k = pIParts[j]; //本段第一個頂點索引
m = shpIn.iNumPoints ; //下一個段第一個頂點索引
}
else
{
k = pIParts[j];
m = pIParts[j+1];
}
//處理第i段的頂點
for ( ; k < m ; k++)
{
pPoint = new CMapPoint();
if ( pPoint == NULL )
return FALSE;
//需要讀入數據更新緩沖區
if ( lpVer == pszBuffer + iDataLen && !bEof)
{
iDataLen = ReadPoint(pszBuffer,iLength,bEof);
if ( iDataLen < 0 )
{
delete pPoint;
delete pPoints;
delete pLine;
delete pIParts;
return FALSE;
}
lpVer = pszBuffer;
}
dbTmp = *(double*)lpVer;
pPoint->SetX(dbTmp);
lpVer += 8;
//需要讀入數據更新緩沖區
if ( lpVer == pszBuffer + iDataLen && !bEof)
{
iDataLen = ReadPoint(pszBuffer,iLength,bEof);
if ( iDataLen < 0 )
{
delete pPoint;
delete pPoints;
delete pLine;
delete pIParts;
return FALSE;
}
lpVer = pszBuffer;
}
dbTmp = *(double*)(lpVer);
lpVer += 8;
pPoint->SetY(dbTmp);
pPoints->Add(pPoint);
}
pParts->Add(pPoints);
pLine->Add(pParts);
}
m_ObList.AddTail( pLine);
delete []pIParts;
}
delete []pszBuffer;
break;
case POLYGON:
pszBuffer = new char [MAX_BUFFER_SIZE]; //分配緩沖區
if ( pszBuffer == NULL )
return FALSE;
memset(pszBuffer , 0 , MAX_BUFFER_SIZE);
//讀入多邊形記錄
for ( i = 1 ; i <= m_iRecordCount ; i++ ) //m_iRecordCount
{
iLength = SetRecordPos(i);
if ( iLength <= 0 )
return FALSE;
pPolygon = new CMapPolygon();
iIndex = i - 1;
pPolygon->SetIndex(iIndex);
if (pPolygon == NULL )
return FALSE;
//獲得記錄頭信息
if (!GetRecordHeader(RecordHeader))
return FALSE;
if ( !GetShpInfo(shpIn))
return FALSE;
if (shpIn.ishpType != POLYGON )//類型不匹配
{
delete pPolygon;
continue;
}
if ( shpIn.iNumParts*sizeof(int) > MAX_BUFFER_SIZE )
{
//復合多邊型中的多邊形個數大于最大緩沖區長度,忽略該對象
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -