📄 shapefile.cpp
字号:
//////////////////////////////////////////////////////
//
// NRDB Pro - Spatial database and mapping application
//
// Copyright (c) 1989-2004 Richard D. Alexander
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// NRDB Pro is part of the Natural Resources Database Project
//
// Homepage: http://www.nrdb.co.uk/
// Users' Forum: http://nrdb.mypalawan.info/
//
#include "stdafx.h"
#include "nrdb.h"
#include "ShapeFile.h"
#include "projctns.h"
#include "maplayer.h"
#include "dlgprogress.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
inline void Swap(double &A, double& B)
{
double C = A;
A = B;
B = C;
}
inline void Swap(int &A, int& B)
{
int C = A;
A = B;
B = C;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CShapeFile::CShapeFile()
{
m_pFileIn = NULL;
m_pFileOut = NULL;
m_bLatLon = FALSE;
}
CShapeFile::~CShapeFile()
{
}
//////////////////////////////////////////////////////////////////////
CPolyLine::CPolyLine()
{
for (int i = 0; i < 4; i++ ) m_dBox[i] = 0;
m_nParts = 0;
m_nPoints = 0;
}
///////////////////////////////////////////////////////////////////////////////
void CShapeFile::fwritex(void* p, size_t size, DWORD n, FILE* pFile)
{
if (fwrite(p, size, n, pFile) != n)
{
AfxThrowUserException();
}
}
///////////////////////////////////////////////////////////////////////////////
BOOL CShapeFile::ImportShapeFile(CLongLines* pMapLines, LPCSTR sFileName)
{
CMainHeader mainheader;
CCoordArray aCoord;
return ImportShapeFile(pMapLines, &aCoord, mainheader, sFileName, PolyLine);
}
///////////////////////////////////////////////////////////////////////////////
int CShapeFile::ImportShapeFileType(LPCSTR sFileName)
{
CMainHeader mainheader;
CLongLines maplines;
CCoordArray aCoord;
BOOL bOK = ImportShapeFile(&maplines, &aCoord, mainheader, sFileName, Header);
if (bOK) return mainheader.m_nShapeType;
else return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
//
// Import information from ESRI shapefile, Nb. that only polylines and
// polygons will be supported
//
BOOL CShapeFile::ImportShapeFile(CLongLines* pMapLines, CCoordArray* pCoords, CMainHeader& mainheader, LPCSTR sFileName, int iFlag)
{
BOOL bOK = TRUE;
CRecordHeader recordheader;
DWORD nShape;
BOOL bPolyLine = FALSE;
int nBytes = sizeof(CMainHeader);
// Open the file as binary
FILE* pFile = fopen(sFileName, "rb");
if (pFile != NULL)
{
// Read the file header
if (fread(&mainheader, sizeof(CMainHeader),1,pFile) == 1)
{
mainheader.m_nFileCode = ReverseBytes(mainheader.m_nFileCode);
mainheader.m_nFileLength = ReverseBytes(mainheader.m_nFileLength);
// Determine if lat/long or coordinates
if (mainheader.m_dXMin >= -180 && mainheader.m_dXMax <= 180 &&
mainheader.m_dYMax <= 90 && mainheader.m_dYMin >= -90)
{
iFlag |= LatLon;
}
// Read the record header
BDProgressRange(0, mainheader.m_nFileLength);
while (bOK && fread(&recordheader, sizeof(CRecordHeader),1,pFile) == 1 &&
!(iFlag & Header))
{
// Read the shape type
if (fread(&nShape,sizeof(nShape),1,pFile) == 1)
{
// Import only polylines
if (nShape == SHPPolyLine || nShape == SHPPolygon)
{
bPolyLine = TRUE;
bOK = ImportPolyLine(pMapLines, pFile, iFlag & LatLon);
}
else if (nShape == SHPPoint)
{
bOK = ImportPoints(pCoords, pFile, iFlag & LatLon);
}
// Skip the record
else
{
// Handles corrupt shapefiles
if (nShape != 0) bOK = FALSE;
ASSERT(nShape >= 0 && nShape <= 31);
int nContentLength = ReverseBytes(recordheader.m_nContentLength);
for (int i = 0; bOK && i < nContentLength-2; i++)
{
WORD word;
if (fread(&word,sizeof(word),1,pFile) != 1)
{
bOK = FALSE;
}
}
}
// Update progress bar
nBytes += ReverseBytes(recordheader.m_nContentLength);
BDProgressPos(nBytes);
} else
{
bOK = FALSE;
}
}
} else
{
bOK = FALSE;
}
}
if (pFile != NULL) fclose(pFile);
if (bOK && !bPolyLine && (iFlag & PolyLine) && !(iFlag & Points))
{
AfxMessageBox(BDString(IDS_SHAPEFILENOPOLYLINES));
bOK = FALSE;
}
BDProgressPos(0);
return bOK;
};
///////////////////////////////////////////////////////////////////////////////
//
// Import a shapefile with each record as a separate layer, this should overcome the
// problem of reallocating memory all the time for large files
//
BOOL CShapeFile::ImportShapeFile(CMapLayer* pMapLayer, LPCSTR sFileName)
{
BOOL bOK = TRUE;
CRecordHeader recordheader;
CMainHeader mainheader;
DWORD nShape;
int nBytes = sizeof(CMainHeader);
int iFlag = 0;
BOOL bCancel = FALSE;
// Open the file as binary
FILE* pFile = fopen(sFileName, "rb");
if (pFile != NULL)
{
// Read the file header
if (fread(&mainheader, sizeof(CMainHeader),1,pFile) == 1)
{
mainheader.m_nFileCode = ReverseBytes(mainheader.m_nFileCode);
mainheader.m_nFileLength = ReverseBytes(mainheader.m_nFileLength);
// Determine if lat/long or coordinates
if (mainheader.m_dXMin >= -180 && mainheader.m_dXMax <= 180 &&
mainheader.m_dYMax <= 90 && mainheader.m_dYMin >= -90)
{
iFlag |= LatLon;
}
// Read the record header
BDProgressRange(0, mainheader.m_nFileLength);
while (bOK && fread(&recordheader, sizeof(CRecordHeader),1,pFile) == 1 &&
!(iFlag & Header) && !bCancel)
{
// Read the shape type
if (fread(&nShape,sizeof(nShape),1,pFile) == 1)
{
CMapLayerObj* pMapLayerObj = new CMapLayerObj;
// Import only polylines
if (nShape == SHPPolyLine || nShape == SHPPolygon)
{
CLongLines* pMapLines = new CLongLines;
pMapLayerObj->SetMapObject(pMapLines);
pMapLayerObj->SetDataType(BDMAPLINES);
CRectDbl rect;
bOK = ImportPolyLine(pMapLines, pFile, iFlag & LatLon, &rect);
pMapLayerObj->GetExtent().left = (long)(rect.left + 0.5);
pMapLayerObj->GetExtent().top = (long)(rect.top + 0.5);
pMapLayerObj->GetExtent().right = (long)(rect.right + 0.5);
pMapLayerObj->GetExtent().bottom = (long)(rect.bottom + 0.5);
}
else if (nShape == SHPPoint)
{
CCoordArray aCoord;
bOK = ImportPoints(&aCoord, pFile, iFlag & LatLon);
CCoord* pCoord = new CCoord(aCoord[0]);
pMapLayerObj->SetMapObject(pCoord);
pMapLayerObj->SetDataType(BDCOORD);
}
// Skip the record
else
{
// Handles corrupt shapefile
if (nShape != 0)
{
bOK = FALSE;
} else if (mainheader.m_nShapeType == SHPPolyLine || mainheader.m_nShapeType == SHPPolygon)
{
CLongLines* pMapLines = new CLongLines;
pMapLayerObj->SetMapObject(pMapLines);
pMapLayerObj->SetDataType(BDMAPLINES);
} else if (mainheader.m_nShapeType == SHPPoint)
{
CCoord* pCoord = new CCoord;
pMapLayerObj->SetMapObject(pCoord);
pMapLayerObj->SetDataType(BDCOORD);
}
ASSERT(nShape >= 0 && nShape <= 31);
int nContentLength = ReverseBytes(recordheader.m_nContentLength);
for (int i = 0; bOK && i < nContentLength-2; i++)
{
WORD word;
if (fread(&word,sizeof(word),1,pFile) != 1)
{
bOK = FALSE;
}
}
}
// Update progress bar
nBytes += ReverseBytes(recordheader.m_nContentLength);
if (!BDProgressPos(nBytes))
{
bCancel = TRUE;
}
// Add to the array of map objects
pMapLayer->Add(pMapLayerObj);
} else
{
bOK = FALSE;
}
}
} else
{
bOK = FALSE;
}
}
if (pFile != NULL) fclose(pFile);
// If layer is a polygon then ensure that all polygons are closed
if (bOK)
{
if (mainheader.m_nShapeType == SHPPolygon)
{
PolylineToPolygon(pMapLayer);
}
}
// Display error message
if (!bOK && !bCancel)
{
AfxMessageBox(BDString(IDS_INVALIDSHAPEFILE));
bOK = FALSE;
}
BDProgressPos(0);
return bOK && !bCancel;
}
///////////////////////////////////////////////////////////////////////////////
//
// Import polylines or the format
//
BOOL CShapeFile::ImportPolyLine(CLongLines* pMapLines, FILE* pFile, BOOL bLatLon, CRectDbl* pRect)
{
CPolyLine polyline;
BOOL bOK = TRUE;
CArray <DWORD,DWORD> anParts;
CArray <double,double> adPoints;
CLongCoord coord;
// Read header
if (fread(&polyline, sizeof(CPolyLine), 1, pFile))
{
// Assign space for data
anParts.SetSize(polyline.m_nParts);
adPoints.SetSize(polyline.m_nPoints*2);
// Read data
if (fread(anParts.GetData(),sizeof(int),polyline.m_nParts, pFile) == polyline.m_nParts &&
fread(adPoints.GetData(), sizeof(double)*2,polyline.m_nPoints, pFile) == polyline.m_nPoints)
{
// Add a last point to the list of points showing the last array
anParts.Add(polyline.m_nPoints);
int k = pMapLines->GetSize();
pMapLines->SetSize(pMapLines->GetSize() + polyline.m_nPoints+polyline.m_nParts);
// Preallocate the size of the array
for (DWORD i = 0; i < polyline.m_nParts; i++)
{
for (DWORD j = anParts[i]; j < anParts[i+1]; j++)
{
double dX = adPoints[j*2];
double dY = adPoints[j*2+1];
if (bLatLon)
{
BDProjection()->LatLonToTransMercator(dY, dX, &coord.x, &coord.y);
} else
{
coord.x = (long)(dX + 0.5);
coord.y = (long)(dY + 0.5);
}
pMapLines->SetAt(k++, coord);
}
coord.SetNull();
if (i+1 == polyline.m_nParts) coord.SetEOL();
pMapLines->SetAt(k++, coord);
}
}
else
{
bOK = FALSE;
}
} else
{
bOK = FALSE;
}
// Optimization, store extent read from shapefile
if (bOK && pRect != NULL)
{
pRect->left = polyline.m_dBox[0];
pRect->right = polyline.m_dBox[2];
pRect->top = polyline.m_dBox[1];
pRect->bottom = polyline.m_dBox[3];
if (bLatLon)
{
BDProjection()->LatLonToTransMercator(pRect->top, pRect->left, &pRect->left, &pRect->top);
BDProjection()->LatLonToTransMercator(pRect->bottom, pRect->right, &pRect->right, &pRect->bottom);
}
if (pRect->top > pRect->bottom) Swap(pRect->top, pRect->bottom);
}
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Imports a single point into the array of points from a shapefile
//
BOOL CShapeFile::ImportPoints(CCoordArray* pPoints, FILE* pFile, BOOL bLatLon)
{
CShapePoint shapepoint;
BOOL bOK = TRUE;
CCoord coord;
// Read header
if (fread(&shapepoint, sizeof(shapepoint), 1, pFile))
{
double dX = shapepoint.m_dX;
double dY = shapepoint.m_dY;
if (bLatLon)
{
BDProjection()->LatLonToTransMercator(dY, dX, &coord.x, &coord.y);
} else
{
coord.x = (long)(dX + 0.5);
coord.y = (long)(dY + 0.5);
}
pPoints->Add(coord);
} else
{
bOK = FALSE;
}
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
BOOL CShapeFile::ExportShapeFile(CLongLines* pMapLines, LPCSTR sFileName, int nFlags)
{
BOOL bOK;
// Convert the maplines into a map object and export it
CMapLayer maplayer;
CMapLayerObj mapobj;
mapobj.SetMapObject(pMapLines);
mapobj.SetDataType(BDMAPLINES);
maplayer.Add(&mapobj);
bOK = ExportShapeFile(&maplayer, sFileName, nFlags);
if (bOK)
{
AfxMessageBox(BDString(IDS_SHAPEFILEEXPORTED));
} else
{
AfxMessageBox(BDString(IDS_ERROREXPORT));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -