头文件
enum
{
SHPNullShape=0,
SHPPoint=1,
SHPPolyLine=3,
SHPPolygon=5,
SHPMultipoint=8,
SHPPointZ=11,
SHPPolyLineZ=13,
SHPPolygonZ=15,
SHPMultiPointZ=18,
SHPPointM=21,
SHPPolyLineM=23,
SHPPolygonM=25,
SHPMultipointM=28,
SHPMultiPatch=31
};
#pragma pack(1)
struct CMainHeader
{
int m_nFileCode;
// Big Endian
int m_nUnused1;
// ""
int m_nUnused2;
int m_nUnused3;
int m_nUnused4;
int m_nUnused5;
int m_nFileLength;
int m_nVersion;
// Little endian
int m_nShapeType;
// ""
do
uble m_dXMin;
do
uble m_dYMin;
do
uble m_dXMax;
do
uble m_dYMax;
do
uble m_dZMin;
do
uble m_dZMax;
do
uble m_dMMin;
do
uble m_dMMax;
};
struct CRecordHeader
{
int m_nRecordNumber;
// Big Endian
int m_nContentLength;
// ""
};
struct CIndexRecord
{
int m_nOffset;
int m_nContentLength;
};
struct CPolyLine
{
CPolyLine();
do
uble m_dBox[4];
// Little endian
DWORD m_nParts;
// ""
DWORD m_nPoints;
};
struct CShapePoint
{
do
uble m_dX;
// Little endian
do
uble m_dY;
};
struct CDBFHeader
{
BYTE m_nValid;
char m_aDate[3];
int m_nNumRecords;
short m_nHeaderBytes;
short m_nRecordBytes;
BYTE m_nReserved1[3];
BYTE m_nReserved2[13];
BYTE m_nReserved3[4];
};
struct CDBFDescriptor
{
char m_sName[11];
BYTE m_nType;
BYTE m_nAddress[4];
BYTE m_nFieldLength;
BYTE m_nFieldCount;
BYTE m_nReserved1[2];
BYTE m_nWorkArea;
BYTE m_nReserved2[2];
BYTE m_nSetFieldsFlag;
BYTE m_nReserved3[8];
};
struct CDBFRecordPoint
{
char m_sID[8];
char m_sName[32];
};
#define DBF_TEXT 256
#define DBF_NUMBER 16
#define DBF_BOOL 1
#define DBF_DATE 8
//////////////////////////////////////////////////////////////////////
class CShapeFile
{
public:
CShapeFile();
virtual ~CShapeFile();
BOOL ImportShapeFile(CMapLines* pMapLines, LPCSTR sFileName);
BOOL ExportShapeFile(CMapLines* pMapLines, LPCSTR sFileName, int nFlags);
BOOL ExportShapeFile(CMapLayer* pMapLayer, LPCSTR sFileName, int nFlags);
BOOL ImportShapeFile(CMapLayer* pMapLayer, LPCSTR sFileName);
void Convert();
enum {LatLon=1, Header=2, PolyLine=4, Points=8, Polygon=16};
protected:
BOOL ImportPolyLine(CMapLines* pMapLines, FILE* pFile, BOOL bLatLon, CRectDbl* pRect = NULL);
BOOL ImportPoints(CCoordArray* pPoints, FILE* pFile, BOOL bLatLon);
BOOL ExportPoints(CMapLayer* pMapLayer, FILE* pFile, BOOL bLatLon);
BOOL ImportDBase(CMapLayer* pMapLayer, LPCSTR sFileName);
BOOL ExportPolyLine(CMapLayer* pMapLayer, FILE* pFile, BOOL bLatLon, DWORD nShape);
BOOL ExportShapeFilePoint(CMapLayer* pMapLayer, LPCSTR sFileName, BOOL bLatLon);
BOOL ExportShapeFilePoly(CMapLayer* pMapLayer, LPCSTR sFileName, BOOL bLatLon);
BOOL ExportIndexFile(CPolyLine&
polyline, CMapLayer* pMapLayer, LPCSTR sFileName, CMainHeader&
mainheader);
BOOL ExportIndexFile(CMapLayer* pMapLayer, LPCSTR sFileName, CMainHeader&
mainheader);
BOOL ExportDBase(CMapLayer* pMapLayer, LPCSTR sFileName);
int ReverseBytes(int);
CPolyLine GetBoundingBoxPoly(CMapLines* pMapLines, BOOL bLatLon, int i1 = 0, int j2 = 0);
CPolyLine GetBoundingBox(CMapLayer* pMapLayer, BOOL bLatLon);
CPolyLine GetNumParts(CMapLines* pMapLines);
CString GetLineText(CMapLayer*, CMapLayerObj*);
void fwritex(void* p, size_t size, DWORD n, FILE* pFile);
BOOL ConvertShapeFile();
BOOL ConvertPolyLine();
BOOL ConvertPoints();
BOOL ConvertIndex();
BOOL ConvertDBaseFile();
BOOL PolylineToPolygon(CMapLayer*);
};
CPP:
//////////////////////////////////////////////////////////////////////
inline void Swap(double &A,do
uble&
B)
{
do
uble C = A;
A = B;
B = C;
}
inline void Swap(int &A, int&
B)
{
int C = A;
A = B;
B = C;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
CShapeFile::CShapeFile()
{
}
CShapeFile::~CShapeFile()
{
}
//////////////////////////////////////////////////////////////////////
CPolyLine::CPolyLine()
{
for (int i = 0;
i < 4;
i++ ) m_dBox
= 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();
}
}
///////////////////////////////////////////////////////////////////////////////
//
// 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;
// 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;
}
// Latitude/longitude not supported
if (iFlag &
LatLon)
{
AfxMessageBox("This shapefile appears to be in latitude/longitude. This version "
"of NRDB View only accepts data in metres.");
bOK = FALSE;
}
// Read the record header
while (bOK &&
fread(&recordheader, sizeof(CRecordHeader),1,pFile) == 1 &&
!(iFlag &
Header))
{
// Read the shape type
if (fread(&nShape,sizeof(nShape),1,pFile) == 1)
{
CMapLayerObj* pMapLayerObj = new CMapLayerObj;
// Import only polylines
if (nShape == SHPPolyLine || nShape == SHPPolygon)
{
CMapLines* pMapLines = new CMapLines;
pMapLayerObj->SetMapObject(pMapLines);
pMapLayerObj->SetDataType(BDMAPLINES);
CRectDbl rect;
bOK = ImportPolyLine(pMapLines, pFile, iFlag &
LatLon, &rect);
// Set the extent
pMapLayerObj->GetExtent() = rect;
}
else
if (nShape == SHPPoint)
{
CCoordArray aCoord;
bOK = ImportPoints(&aCoord, pFile, iFlag &
LatLon);
CCoord* pCoord = new CCoord(aCoord[0]);
pMapLayerObj->SetMapObject(pCoord);
pMapLayerObj->SetDataType(BDCOORD);
// Set the extent
pMapLayerObj->GetExtent().left = pCoord->x;
pMapLayerObj->GetExtent().top = pCoord->y;
pMapLayerObj->GetExtent().right = pCoord->x;
pMapLayerObj->GetExtent().bottom = pCoord->y;
}
// Skip the record
else
{
// Handles corrupt shapefile
if (nShape != 0)
{
bOK = FALSE;
} else
if (mainheader.m_nShapeType == SHPPolyLine || mainheader.m_nShapeType == SHPPolygon)
{
CMapLines* pMapLines = new CMapLines;
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;
}
}
}
nBytes += ReverseBytes(recordheader.m_nContentLength);
// Add to the array of map objects
pMapLayer->Add(pMapLayerObj);
} else
{
bOK = FALSE;
}
}
} else
{
bOK = FALSE;
}
}
if (pFile != NULL) fclose(pFile);
// Set the shape
if (bOK)
{
if (nShape == SHPPolygon) pMapLayer->GetMapProp().m_nShapeType = CViewMap:olygon;
else
if (nShape == SHPPolyLine) pMapLayer->GetMapProp().m_nShapeType = CViewMap:olyline;
else
if (nShape == SHPPoint) pMapLayer->GetMapProp().m_nShapeType = CViewMap:oints;
}
// Import the corresponding data
if (bOK)
{
bOK = ImportDBase(pMapLayer, sFileName);
}
// Report on error
if (!bOK)
{
AfxMessageBox("Invalid shapefile");
bOK = FALSE;
}
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Import polylines or the format
//
BOOL CShapeFile::ImportPolyLine(CMapLines* pMapLines, FILE* pFile, BOOL bLatLon, CRectDbl* pRect)
{
CPolyLine polyline;
BOOL bOK = TRUE;
CArray <DWORD,DWORD> anParts;
CArray <double,double> adPoints;
CCoord 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;
j < anParts[i+1];
j++)
{
do
uble dX = adPoints[j*2];
do
uble dY = adPoints[j*2+1];
coord.x = dX;
coord.y = dY;
// Convert the units to metres
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 (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))
{
do
uble dX = shapepoint.m_dX;
do
uble dY = shapepoint.m_dY;
coord.x = dX;
coord.y = dY;
pPoints->Add(coord);
} else
{
bOK = FALSE;
}
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Import the data from the DBase file corresponding to the shapefile into the
// CAttrArray part of the map layer
//
BOOL CShapeFile::ImportDBase(CMapLayer* pMapLayer, LPCSTR sFileName)
{
BOOL bOK = TRUE;
CDBFHeader header;
CDBFDescriptor descriptor;
BYTE nRecord;
BYTE nTerminator;
BYTE* pBuffer = NULL;
int nBufferLen = 0;
CAttrArray&
aAttr = pMapLayer->GetAttr();
// Determine the file name
CString sDBaseFile = sFileName;
sDBaseFile = sDBaseFile.Left(sDBaseFile.ReverseFind('.'));
sDBaseFile += ".dbf";
// Open the file
FILE* pFile = fopen(sDBaseFile, "rb");
if (pFile != NULL)
{
// Read header information
if (fread(&header, sizeof(header), 1, pFile) == 1 &&
header.m_nValid == 0x03)
{
// Read the field types
int nFields = (header.m_nHeaderBytes - sizeof(header) - sizeof(BYTE)) /
sizeof(descriptor);
aAttr.SetSize(nFields);
for (int i = 0;
i < nFields &&
bOK;
i++)
{
if (fread(&descriptor, sizeof(descriptor), 1, pFile) == 1)
{
// Determine the type
if (descriptor.m_nType == 'N') aAttr.SetDataType(BDNUMBER);
else
if (descriptor.m_nType == 'D') aAttr.SetDataType(BDDATE);
else
if (descriptor.m_nType == 'L') aAttr.SetDataType(BDBOOLEAN);
else
aAttr.SetDataType(BDTEXT);
// Determine the length
aAttr.SetLength(descriptor.m_nFieldLength);
// Set the title
CString sDesc;
strncpy(sDesc.GetBuffer(11), descriptor.m_sName, 11);
aAttr.SetDesc(sDesc);
};
}
// Skip the header terminator character
fread(&nTerminator,sizeof(BYTE),1,pFile);
// Set the number of rows
aAttr.SetNumRows(header.m_nNumRecords);
// Now read the data
for (i = 0;
i < header.m_nNumRecords;
i++)
{
// Read the record separator
fread(&nRecord,sizeof(BYTE),1,pFile);
for (int j = 0;
j < nFields;
j++)
{
// Allocate buffer to read data into
if (aAttr[j].GetLength() > nBufferLen)
{
nBufferLen = aAttr[j].GetLength();
if (pBuffer != NULL) delete [] pBuffer;
pBuffer = new BYTE[nBufferLen];
}
// Now read the record
fread(pBuffer, aAttr[j].GetLength(), 1, pFile);
// Now store the value
aAttr[j].SetValue(i, (LPCSTR)pBuffer);
};
}
} else
{
bOK = FALSE;
}
fclose(pFile);
} else
{
bOK = TRUE;
}
// Tidy
if (pBuffer != NULL) delete pBuffer;
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
BOOL CShapeFile::ExportShapeFile(CMapLines* 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("Shapefile exported");
} else
{
AfxMessageBox("Error exporting shapefile");
}
mapobj.SetMapObject(NULL);
maplayer.CArray <CMapLayerObj*, CMapLayerObj*>::RemoveAll();
// Prevents deletion of memory
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Exports map lines in the format of a shape file
//
BOOL CShapeFile::ExportShapeFilePoly(CMapLayer* pMapLayer, LPCSTR sFileName, int nFlags)
{
BOOL bOK = TRUE;
CMainHeader mainheader;
CPolyLine polyline;
DWORD nShape = SHPPolyLine;
FILE* pFile = NULL;
// Retrieve query data
BOOL bLatLon = nFlags &
LatLon;
if (nFlags &
Polygon) nShape = nShape = SHPPolygon;
// If polygon, make sure that the last point is closed
if (nShape == SHPPolygon)
{
PolylineToPolygon(pMapLayer);
};
// Determine the extend of the points
polyline = GetBoundingBox(pMapLayer, bLatLon);
memset(&mainheader,0,sizeof(mainheader));
mainheader.m_dXMin = polyline.m_dBox[0];
mainheader.m_dXMax = polyline.m_dBox[2];
mainheader.m_dYMin = polyline.m_dBox[1];
mainheader.m_dYMax = polyline.m_dBox[3];
// Initialise the polyline
polyline.m_nParts = 0;
polyline.m_nPoints = 0;
// First create the header
mainheader.m_nFileCode = ReverseBytes(9994);
mainheader.m_nVersion = 1000;
mainheader.m_nShapeType = nShape;
// Count the number of points, exclude repeating null values
for (int j = 0;
j < pMapLayer->GetSize();
j++)
{
CMapLayerObj* pMapObj = pMapLayer->GetAt(j);
if (pMapObj->GetDataType() == BDMAPLINES)
{
CMapLines* pMapLines = (CMapLines*)pMapObj->GetMapObject();
CPolyLine polylineP = GetNumParts(pMapLines);
polyline.m_nParts += polylineP.m_nParts;
polyline.m_nPoints += polylineP.m_nPoints;
}
};
// Determine the file length
// Support for multipart polylines
int nFileLength = sizeof(CMainHeader) + (sizeof(CRecordHeader) + sizeof(CPolyLine) + sizeof(int)) * pMapLayer->GetSize() +
sizeof(int) * polyline.m_nParts + sizeof(double)*2 * polyline.m_nPoints;
mainheader.m_nFileLength = ReverseBytes(nFileLength/2);
// Open the file as binary
TRY
{
pFile = fopen(sFileName, "wb");
if (pFile != NULL)
{
// Write the file header
if (fwrite(&mainheader, sizeof(CMainHeader),1,pFile) == 1)
{
bOK = ExportPolyLine(pMapLayer, pFile, bLatLon, nShape);
} else
{
bOK = FALSE;
}
}
} CATCH(CException, ex)
{
bOK = FALSE;
} END_CATCH
if (pFile != NULL) fclose(pFile);
// Export the index file
if (bOK)
{
bOK = ExportIndexFile(polyline, pMapLayer, sFileName, mainheader);
};
// Export DBASE format
if (bOK)
{
bOK = ExportDBase(pMapLayer, sFileName);
};
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
BOOL CShapeFile:olylineToPolygon(CMapLayer* pMapLayer)
{
CCoord coord1, coord2;
for (int j = 0;
j < pMapLayer->GetSize();
j++)
{
CMapLayerObj* pMapLayerObj = pMapLayer->GetAt(j);
CMapLines* pMapLines = (CMapLines*)pMapLayerObj->GetMapObject();
// For each map lines, close polygons
for (int i = 0;
i < pMapLines->GetSize();
i++)
{
// Determine the start of a line
if (!pMapLines->GetAt(i).IsNull() &&
(i == 0 || (i > 0 &&
pMapLines->GetAt(i-1).IsNull())))
{
coord1 = pMapLines->GetAt(i);
}
// Determine the end of a line
if (i + 1 < pMapLines->GetSize() &&
pMapLines->GetAt(i+1).IsNull() &&
!pMapLines->GetAt(i).IsNull())
{
coord2 = pMapLines->GetAt(i);
// If the two ends are not the same then
make them the same
if (coord1.x != coord2.x &&
coord1.y != coord2.y)
{
pMapLines->InsertAt(i+1, coord1);
i++;
}
}
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//
// Exports the polyline part of the shape file - retains multipart polylines
//
BOOL CShapeFile::ExportPolyLine(CMapLayer* pMapLayer, FILE* pFile, BOOL bLatLon, DWORD nShape)
{
BOOL bOK = TRUE;
CRecordHeader recordheader;
CPolyLine polyline;
// Determine parts
int nRecord = 1;
for (int j = 0;
j < pMapLayer->GetSize();
j++)
{
BOOL bStart = TRUE;
CMapLayerObj* pMapObj = pMapLayer->GetAt(j);
if (pMapObj->GetDataType() == BDMAPLINES)
{
CMapLines* pMapLines = (CMapLines*)pMapObj->GetMapObject();
// Determine bounding rectangle
polyline = GetBoundingBoxPoly(pMapLines, bLatLon);
// For each polyline determine its parts
CLongArray anParts;
anParts.Add(0);
polyline.m_nPoints = 0;
for (int k = 0;
k < pMapLines->GetSize();
k++)
{
CCoord coord = pMapLines->GetAt(k);
if (!coord.IsNull()) polyline.m_nPoints++;
else
if (k + 1 < pMapLines->GetSize()) anParts.Add(polyline.m_nPoints);
}
polyline.m_nParts = anParts.GetSize();
// Write record header
recordheader.m_nRecordNumber = ReverseBytes(nRecord++);
int nRecordLength = sizeof(int) + sizeof(CPolyLine) + sizeof(int)*polyline.m_nParts +
sizeof(double)*2 * polyline.m_nPoints;
recordheader.m_nContentLength = ReverseBytes(nRecordLength/2);
fwritex(&recordheader, sizeof(CRecordHeader),1,pFile);
// Write shape type
fwritex(&nShape,sizeof(nShape),1,pFile);
// Write polyline record contents
fwritex(&polyline, sizeof(CPolyLine),1,pFile);
// Write the parts data
fwritex(anParts.GetData(), sizeof(int),anParts.GetSize(),pFile);
// Write the points data
for (int i = 0;
i < pMapLines->GetSize() &&
bOK;
i++)
{
CCoord coord = pMapLines->GetAt(i);
if (!coord.IsNull())
{
// Output the data
do
uble dX = coord.x;
do
uble dY = coord.y;
fwritex(&dX, sizeof(double), 1, pFile);
fwritex(&dY, sizeof(double), 1, pFile);
}
}
}
}
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Export an entire layer to a shape file (as points)
//
BOOL CShapeFile::ExportPoints(CMapLayer* pMapLayer, FILE* pFile, BOOL bLatLon)
{
BOOL bOK = TRUE;
DWORD nShape = SHPPoint;
CRecordHeader recordheader;
CShapePoint point;
// Determine parts
int nRecord = 1;
for (int i = 0;
i < pMapLayer->GetSize() &&
bOK;
i++)
{
CCoord* pCoord = (CCoord*)pMapLayer->GetAt(i)->GetMapObject();
// Initialise the header
recordheader.m_nRecordNumber = ReverseBytes(nRecord++);
int nRecordLength = sizeof(CShapePoint) + sizeof(int);
recordheader.m_nContentLength = ReverseBytes(nRecordLength/2);
// Write the record header
fwritex(&recordheader, sizeof(CRecordHeader),1,pFile);
// Write the shape type
fwritex(&nShape,sizeof(nShape),1,pFile);
// Write the x,y data
point.m_dX = pCoord->x;
point.m_dY = pCoord->y;
fwritex(&point, sizeof(CShapePoint), 1, pFile);
}
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Export the index file (points)
//
BOOL CShapeFile::ExportIndexFile(CMapLayer* pMapLayer, LPCSTR sFileName, CMainHeader&
mainheader)
{
CIndexRecord indexrecord;
FILE* pFile = NULL;
BOOL bOK = TRUE;
CString sIndexFile = sFileName;
sIndexFile = sIndexFile.Left(sIndexFile.ReverseFind('.'));
sIndexFile += ".shx";
TRY
{
pFile = fopen(sIndexFile,"wb");
if (pFile != NULL)
{
// Write the header
int nFileLength = sizeof(CMainHeader)+sizeof(CIndexRecord)*pMapLayer->GetSize();
mainheader.m_nFileLength = ReverseBytes(nFileLength/2);
fwritex(&mainheader, sizeof(CMainHeader),1,pFile);
// Determine the indexes
indexrecord.m_nOffset = ReverseBytes((sizeof(CMainHeader)-sizeof(CRecordHeader))/2);
indexrecord.m_nContentLength = 0;
for (int i = 0;
i < pMapLayer->GetSize() &&
bOK;
i++)
{
CCoord* pCoord = (CCoord*)pMapLayer->GetAt(i)->GetMapObject();
// Write record header
indexrecord.m_nOffset = ReverseBytes(indexrecord.m_nContentLength)+
ReverseBytes(indexrecord.m_nOffset) +
sizeof(CRecordHeader)/2;
indexrecord.m_nOffset = ReverseBytes(indexrecord.m_nOffset);
int nRecordLength = sizeof(CShapePoint) + sizeof(int);
indexrecord.m_nContentLength = ReverseBytes(nRecordLength/2);
// Write the record header
fwritex(&indexrecord, sizeof(CIndexRecord),1,pFile);
}
} else
{
bOK = FALSE;
}
}
CATCH (CException, ex)
{
bOK = FALSE;
} END_CATCH
if (pFile != NULL) fclose(pFile);
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Export the index file multi-part polygons
//
BOOL CShapeFile::ExportIndexFile(CPolyLine&
polyline, CMapLayer* pMapLayer, LPCSTR sFileName, CMainHeader&
mainheader)
{
CIndexRecord indexrecord;
FILE* pFile = NULL;
BOOL bOK = TRUE;
CString sIndexFile = sFileName;
sIndexFile = sIndexFile.Left(sIndexFile.ReverseFind('.'));
sIndexFile += ".shx";
TRY
{
pFile = fopen(sIndexFile,"wb");
if (pFile != NULL)
{
// Write the header
int nFileLength = sizeof(CMainHeader)+sizeof(CIndexRecord)*pMapLayer->GetSize();
mainheader.m_nFileLength = ReverseBytes(nFileLength/2);
fwritex(&mainheader, sizeof(CMainHeader),1,pFile);
// Determine the indexes
indexrecord.m_nOffset = ReverseBytes(sizeof(CMainHeader)/2);
for (int j = 0;
j < pMapLayer->GetSize() &&
bOK;
j++)
{
CMapLayerObj* pMapObj = pMapLayer->GetAt(j);
if (pMapObj->GetDataType() == BDMAPLINES)
{
// For each polyline determine its parts
CMapLines* pMapLines = (CMapLines*)pMapObj->GetMapObject();
polyline.m_nPoints = 0;
polyline.m_nParts = 1;
for (int k = 0;
k < pMapLines->GetSize();
k++)
{
CCoord coord = pMapLines->GetAt(k);
if (!coord.IsNull()) polyline.m_nPoints++;
else
if (k + 1 < pMapLines->GetSize()) polyline.m_nParts++;
}
int nRecordLength = sizeof(int) + sizeof(CPolyLine) + sizeof(int)*polyline.m_nParts +
sizeof(double)*2 * polyline.m_nPoints;
// Write index
indexrecord.m_nContentLength = ReverseBytes(nRecordLength/2);
fwritex(&indexrecord, sizeof(CIndexRecord),1,pFile);
// Update the next index record
int nOffSet = ReverseBytes(indexrecord.m_nOffset)*2 + nRecordLength +
sizeof(CRecordHeader);
indexrecord.m_nOffset = ReverseBytes(nOffSet/2);
} else
{
bOK = FALSE;
}
}
} else
{
bOK = FALSE;
}
}
CATCH (CException, ex)
{
bOK = FALSE;
} END_CATCH
if (pFile != NULL) fclose(pFile);
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
BOOL CShapeFile::ExportShapeFile(CMapLayer* pMapLayer, LPCSTR sFileName, int nFlags)
{
BOOL bOK = TRUE;
if (pMapLayer->GetSize() == 0)
{
AfxMessageBox("No data in layer");
}
if (pMapLayer->GetAt(0)->GetDataType() == BDMAPLINES)
{
bOK = ExportShapeFilePoly(pMapLayer, sFileName, nFlags);
};
if (pMapLayer->GetAt(0)->GetDataType() == BDCOORD)
{
bOK = ExportShapeFilePoint(pMapLayer, sFileName, nFlags);
};
return bOK;
};
///////////////////////////////////////////////////////////////////////////////
//
// This exports an entire layer to a shape file
//
BOOL CShapeFile::ExportShapeFilePoint(CMapLayer* pMapLayer, LPCSTR sFileName, BOOL bLatLon)
{
BOOL bOK = TRUE;
CMainHeader mainheader;
DWORD nShape = SHPPoint;
FILE* pFile = NULL;
// Determine the extent of the points
CPolyLine polyline = GetBoundingBox(pMapLayer, bLatLon);
memset(&mainheader,0,sizeof(mainheader));
mainheader.m_dXMin = polyline.m_dBox[0];
mainheader.m_dXMax = polyline.m_dBox[2];
mainheader.m_dYMin = polyline.m_dBox[1];
mainheader.m_dYMax = polyline.m_dBox[3];
// Initialise the polyline
polyline.m_nParts = 0;
polyline.m_nPoints = 0;
// First create the header
mainheader.m_nFileCode = ReverseBytes(9994);
mainheader.m_nVersion = 1000;
mainheader.m_nShapeType = nShape;
// Determine the file length
int nFileLength = sizeof(CMainHeader)+(sizeof(CRecordHeader)+sizeof(CShapePoint) + sizeof(int)*2)*pMapLayer->GetSize();
mainheader.m_nFileLength = ReverseBytes(nFileLength/2);
// Open the file as binary
TRY
{
pFile = fopen(sFileName, "wb");
if (bOK &&
pFile != NULL)
{
// Write the file header
if (fwrite(&mainheader, sizeof(CMainHeader),1,pFile) == 1)
{
bOK = ExportPoints(pMapLayer, pFile, bLatLon);
} else
{
bOK = FALSE;
}
} else
{
bOK = FALSE;
}
} CATCH(CException, ex)
{
bOK = FALSE;
} END_CATCH
if (pFile != NULL) fclose(pFile);
// Export the index file
if (bOK)
{
bOK = ExportIndexFile(pMapLayer, sFileName, mainheader);
};
// Export DBASE format
if (bOK)
{
bOK = ExportDBase(pMapLayer, sFileName);
};
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Retrieves a bounding box for an entire layer
//
CPolyLine CShapeFile::GetBoundingBox(CMapLayer* pMapLayer, BOOL bLatLon)
{
// Initialise polyline
CPolyLine polyline;
polyline.m_dBox[0] = DBL_MAX;
polyline.m_dBox[1] = DBL_MAX;
polyline.m_dBox[2] = -DBL_MAX;
polyline.m_dBox[3] = -DBL_MAX;
for (int i = 0;
i < pMapLayer->GetSize();
i++)
{
// Map layer
CMapLayerObj* pMapLayerObj = pMapLayer->GetAt(i);
if (pMapLayerObj->GetDataType() == BDMAPLINES)
{
CMapLines* pMapLines = (CMapLines*)pMapLayerObj->GetMapObject();
CPolyLine polylineP = GetBoundingBoxPoly(pMapLines, bLatLon);
polyline.m_dBox[0] = min(polyline.m_dBox[0], polylineP.m_dBox[0]);
polyline.m_dBox[1] = min(polyline.m_dBox[1], polylineP.m_dBox[1]);
polyline.m_dBox[2] = max(polyline.m_dBox[2], polylineP.m_dBox[2]);
polyline.m_dBox[3] = max(polyline.m_dBox[3], polylineP.m_dBox[3]);
}
// Points
else
if (pMapLayerObj->GetDataType() == BDCOORD)
{
CCoord coord = *(CCoord*)pMapLayerObj->GetMapObject();
// Convert to lat/lon if necessary
do
uble dX, dY;
dX = coord.x;
dY = coord.y;
polyline.m_dBox[0] = min(polyline.m_dBox[0], dX);
polyline.m_dBox[1] = min(polyline.m_dBox[1], dY);
polyline.m_dBox[2] = max(polyline.m_dBox[2], dX);
polyline.m_dBox[3] = max(polyline.m_dBox[3], dY);
}
}
return polyline;
}
///////////////////////////////////////////////////////////////////////////////
//
// Retrieves the bounding box for a map line
//
CPolyLine CShapeFile::GetBoundingBoxPoly(CMapLines* pMapLines, BOOL bLatLon, int i1, int i2)
{
CPolyLine polyline;
if (i1 == i2) i2 = pMapLines->GetSize();
polyline.m_dBox[0] = DBL_MAX;
polyline.m_dBox[1] = DBL_MAX;
polyline.m_dBox[2] = -DBL_MAX;
polyline.m_dBox[3] = -DBL_MAX;
for (int i = i1;
i < i2;
i++)
{
CCoord coord = pMapLines->GetAt(i);
if (!coord.IsNull())
{
polyline.m_dBox[0] = min(polyline.m_dBox[0], coord.x);
polyline.m_dBox[1] = min(polyline.m_dBox[1], coord.y);
polyline.m_dBox[2] = max(polyline.m_dBox[2], coord.x);
polyline.m_dBox[3] = max(polyline.m_dBox[3], coord.y);
};
}
return polyline;
}
///////////////////////////////////////////////////////////////////////////////
CPolyLine CShapeFile::GetNumParts(CMapLines* pMapLines)
{
CPolyLine polyline;
BOOL bStart = TRUE;
for (int i = 0;
i < pMapLines->GetSize();
i++)
{
CCoord coord = pMapLines->GetAt(i);
if (coord.IsNull())
{
bStart = TRUE;
}
else
{
if (bStart) polyline.m_nParts++;
polyline.m_nPoints++;
bStart = FALSE;
}
}
return polyline;
}
///////////////////////////////////////////////////////////////////////////////
//
// Export the dbase data for shapefile. For NRDBPro, this includes ALL
// columns from the query
//
BOOL CShapeFile::ExportDBase(CMapLayer* pMapLayer, LPCSTR sFileName)
{
BOOL bOK = TRUE;
CDBFHeader header;
CDBFDescriptor descriptor;
// Create file name
CString sIndexFile = sFileName;
sIndexFile = sIndexFile.Left(sIndexFile.ReverseFind('.'));
sIndexFile += ".dbf";
FILE* pFile = fopen(sIndexFile,"wb");
TRY
{
if (bOK &&
pFile != NULL)
{
// Create header
time_t time_tDate;
// Current system time and date
struct tm *pTmDate;
// Current system time and date
time(&time_tDate);
pTmDate = localtime(&time_tDate);
memset(&header, 0, sizeof(header));
header.m_nValid = 0x03;
header.m_aDate[0] = (pTmDate->tm_year+1900)%100+100;
header.m_aDate[1] = pTmDate->tm_mon+1;
header.m_aDate[2] = pTmDate->tm_mday;
int nRecords = pMapLayer->GetAttr().GetNumRows();
header.m_nNumRecords = nRecords;
// Determine number of record bytes and fields
CAttrArray&
aAttr = pMapLayer->GetAttr();
int nRecordBytes = 0;
int nFields = 0;
for (int i = 0;
i < aAttr.GetSize();
i++)
{
switch (aAttr.GetDataType())
{
case BDTEXT :
nRecordBytes += aAttr.GetLength();
nFields++;
break;
case BDBOOLEAN : nRecordBytes += DBF_BOOL;
nFields++;
break;
case BDNUMBER : nRecordBytes += DBF_NUMBER;
nFields++;
break;
case BDDATE : nRecordBytes += DBF_DATE;
nFields++;
break;
}
}
// Set number of field descriptor bytes
header.m_nHeaderBytes = sizeof(header) + sizeof(CDBFDescriptor) *
nFields + sizeof(BYTE);
header.m_nRecordBytes = nRecordBytes + sizeof(BYTE);
header.m_nReserved3[1] = 0;
fwritex(&header,sizeof(header),1,pFile);
// Create the record descriptors
for (i = 0;
i < aAttr.GetSize();
i++)
{
memset(&descriptor,0,sizeof(descriptor));
strncpy(descriptor.m_sName, aAttr.GetDesc(), 10);
switch (aAttr.GetDataType())
{
case BDTEXT :
descriptor.m_nType = 'C';
descriptor.m_nFieldLength = aAttr.GetLength();
break;
case BDNUMBER :
descriptor.m_nType = 'N';
descriptor.m_nFieldLength = DBF_NUMBER;
break;
case BDDATE :
descriptor.m_nType = 'D';
descriptor.m_nFieldLength = DBF_DATE;
break;
case BDBOOLEAN :
descriptor.m_nType = 'L';
descriptor.m_nFieldLength = DBF_BOOL;
break;
}
if (descriptor.m_nType != 0)
{
fwritex(&descriptor,sizeof(descriptor),1,pFile);
}
}
BYTE nTerminator = 0x0D;
fwritex(&nTerminator,sizeof(BYTE),1,pFile);
// Write the data
for (i = 0;
i < nRecords;
i++)
{
// Write the record separator
BYTE nRecord = 0x20;
fwritex(&nRecord,sizeof(BYTE),1,pFile);
// Write the attribute data
for (int j = 0;
j < aAttr.GetSize();
j++)
{
CString s;
char record[DBF_TEXT];
memset(&record, 0x20, sizeof(record));
// Get pointer to attribute, not a copy
CAttribute* pAttr = aAttr.GetData()+j;
int nLength = 0;
switch(pAttr->GetDataType())
{
case BDTEXT :
s = pAttr->GetValue(i);
strncpy(record, s, min(pAttr->GetLength(), s.GetLength()));
nLength = pAttr->GetLength();
break;
case BDNUMBER :
s.Format("%8lf", pAttr->GetDouble(i));
strncpy(record, s, DBF_NUMBER);
nLength = DBF_NUMBER;
break;
case BDBOOLEAN :
if (pAttr->GetBoolean(i) == TRUE) record[0] = 'Y';
else
if (pAttr->GetBoolean(i) == FALSE) record[0] = 'N';
else
record[0] = '?';
nLength = DBF_BOOL;
break;
case BDDATE :
CDateX date = pAttr->GetDate(i);
CString s1,s2;
s.Format("%4d",date.m_nYear);
s1.Format("%02d",date.m_nMonth);
s2.Format("%02d",date.m_nDay);
s += s1 + s2;
strncpy(record, s, min(DBF_DATE, s.GetLength()));
nLength = DBF_DATE;
break;
}
ASSERT(nLength != 0);
if (nLength != 0) fwritex(&record, nLength, 1, pFile);
}
}
// Write the end of file marker
BYTE nEnd = 0x1a;
fwritex(&nEnd, sizeof(nEnd), 1, pFile);
} else
{
bOK = FALSE;
}
} CATCH(CException, ex)
{
bOK = FALSE;
} END_CATCH
if (pFile != NULL) fclose(pFile);
return bOK;
}
///////////////////////////////////////////////////////////////////////////////
//
// Converts big endian to little endian
//
int CShapeFile::ReverseBytes(int n)
{
union
{
BYTE a[4];
int n;
} u,v;
u.n = n;
v.a[0] = u.a[3];
v.a[1] = u.a[2];
v.a[2] = u.a[1];
v.a[3] = u.a[0];
return v.n;
}