⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shapefile.cpp

📁 一个英国人写的GIS查看/编辑工具。支持标准的shapefile地图文件格式和coverage地图文件格式。同时可以编辑相应的dbf文件。
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//////////////////////////////////////////////////////
//
// 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 + -