1. 셰이프 파일 형식
1.1 먼저 셰이프 파일보기
ESRI Shapefile Technical Description에 따르면 전체 Shapefile에 가장 중요한 세 파일은 ***. shp, **. shx 및 .dbf입니다. 세 가지의 의미는 MainFile (메인 파일), IndexFile (인덱스 파일), dBaseFile (속성 파일)입니다. MainFile (.shp)은 점, 선 및 표면의 세 가지 기본 기하학적 유형을 저장하는 데 사용됩니다. IndexFile (.shx) 인덱스 파일은 해당 기본 파일에 각 레코드의 시작점 위치를 저장합니다. dBaseFile (.dbf) 속성 파일은 각 포인트의 속성을 저장합니다.
모든 파일은 바이너리 모드 로 저장되므로 C ++를 사용하여 파일을 읽을 때 ifstream 객체가 초기화 될 때 ios :: binary 를 추가해야 합니다. 이는 파일이 바이너리 모드로 열렸 음을 나타냅니다. 여는 방법은 다음과 같습니다.
ifstream inFile("C:\\Users\\Administrator\\Desktop\\test.shp", ios::binary | ios::in )
1.2 .shp 파일
각 .shp 파일은 두 부분으로 나뉩니다.100 바이트파일의 헤더와 다른 부분은 사용해야하는 데이터 콘텐츠이며 데이터 레코드라고합니다.
1.2.1 .shp 파일 헤더
파일의 첫 번째 바이트부터 100 바이트까지 파일 헤더의 내용이며 데이터를 읽을 때 0-99, 총 100 바이트입니다. 0부터 시작하는 배열의 인덱스와 마찬가지로 아래에 언급 된 파일 포인터는 모두 배열 인덱스를 기반으로합니다.
100 바이트부터 파일 끝까지 데이터 레코드의 내용입니다.
파일 헤더에 대한 설명은 아래 그림을 참조하십시오.
위 그림에서 가장 오른쪽 열은 컴퓨터 바이트 순서 모드입니다. 정보를 검색 한 후 저자는 다른 컴퓨터 시스템이 다른 엔디안을 사용할 수 있음을 알게되었습니다. Big은 big endian이고 Little은 little endian입니다. 빅 엔디안과 리틀 엔디안에 관해서는 여기서 많이 설명하지 않고 직접 사용할 수있는 바이트 순서 변환 코드를 게시하면됩니다.
template<class T>
T ByteTrans(T m)
{
//联合体内所有的数据公用一个内存
union n_
{
T n;
char mem[sizeof(T)];
};
n_ big, small;
big.n = m;
for (int i = 0; i < sizeof(T); i++)
{
small.mem[i] = big.mem[sizeof(T) - i - 1];
}
return small.n;
}
파일 헤더에서 가장 중요한 데이터는 ShapeType과 Box입니다. 여기서 ShapeType은 점, 선 및 표면의 세 가지 기하학적 요소에 해당하는 맵 유형입니다. 상자는 X의 최대 값과 최소값, Y의 최대 값과 최소값 (Z와 M이있는 경우, 최대 값과 최소값)을 포함하여 현재 .shp 파일에 기록 된 모든 포인트의 범위입니다. Z와 M,하지만 지금까지 저자는 M이 포함 된 .shp 파일을 보지 못했습니다).
파일 헤더의 ShapeType과 관련하여 다음 그림을 볼 수 있습니다.
그런 다음 파일의 데이터 레코드가 있습니다.
1.2.2 .shp 파일의 데이터 기록
.shp 파일의 101 번째 바이트, 즉 파일 포인터가 100 인 곳에서 시작하여 파일의 끝까지 계속되면 .shp 파일의 데이터 레코드입니다.
각 데이터 레코드에는 두 부분도 포함됩니다. 첫 번째 부분은 레코드 헤더라고하는 두 개의 빅 엔디안 정수를 포함하는 내용으로, 고정 길이이며 8 바이트에 불과하며 레코드 헤더는 빅 엔디안 순서로 저장됩니다. 다른 부분은 가변 길이, 즉 가변 길이 레코드 내용으로 모든 데이터는 리틀 엔디안 순서로 저장됩니다.
레코드 헤더의 첫 번째 빅 엔디안 정수는 1부터 시작하는 현재 레코드의 번호입니다. 두 번째 빅 엔디안 정수는 레코드 길이 (RecordLength)입니다. 고정 길이 기록 헤드는 일반적으로 쓸모가 없습니다.
가변 길이 레코드 내용은 먼저 맵 유형 (ShapeType)이고 그 다음에는 실제 포인트 레코드입니다. 점, 선 및 표면의 세 가지 기하학적 요소의 경우 다음 표에 표시된 것처럼 .shp 파일의 저장 방법이 다릅니다.
ShapeType | 저장 형식 |
---|---|
1시) | X (더블) , Y (더블) |
2 (라인) | double Box [4] , int NumParts , int NumPoints , int Parts [NumParts] , double [NumPoints [X , Y]] |
3 (얼굴) | double Box [4] , int NumParts , int NumPoints , int Parts [NumParts] , double [NumPoints [X , Y]] |
포인트의 경우 레코드 내용에 ShapeType (값 = 1)과 두 개의 이중 값 (X 및 Y 좌표) 만 있습니다.
선과 표면의 경우 ShapeType 외에 첫 번째 이중 상자 [4]는 현재 레코드의 모든 포인트 범위를 나타내며 저장 모드는 Xmin, Ymin, Xmax, Ymax입니다.
NumParts는 현재 레코드에있는 선의 세그먼트 수 (또는 표면의 링 수)입니다.
NumPoints는 현재 레코드의 포인트 수입니다.
int Parts [NumParts]는 라인 (또는 링)의 각 세그먼트의 시작점을 저장하는 파일 포인터의 인덱스입니다.
double [NumPoints [X, Y]]는 현재 레코드가 끝날 때까지 X1, Y1, X2, Y2, X3, Y3 ...과 같이 순서대로 저장된 점의 X 및 Y 좌표입니다.
1.2.3 요약
.shp 파일을 소개했습니다.
1.3 .shx 파일
.shx 파일은 100 바이트 파일 헤더와 고정 길이 레코드를 포함하는 색인 파일입니다.
파일 헤더는 .shp 파일과 동일합니다. 고정 길이 레코드는 8 바이트, 2 개의 int 유형 데이터입니다. 아래 그림과 같이:
1.4 .dbf 파일
당분간 형식이 어떤지 모르겠습니다. 나중에 사용할 때 업데이트하겠습니다.
2. C ++ 클래스 디자인
2.1 아이디어
shapefile은지도 유형 파일입니다.지도에는 여러 레이어가 포함되고 각 레이어에는 점, 선 및 다각형이 포함됩니다. 점, 선 및 평면에서 시작하여 점이 선을 구성하고 선이 표면을 구성한다는 것을 알 수 있습니다. 동시에 포인트는 레이어로 구성 할 수 있으며 선과 영역도 사용할 수 있습니다. 그림과 같이
점, 선 및 영역은 모두 개체이고 레이어도 개체이며 여러 레이어로 구성된지도도 개체입니다.
따라서 클래스 간의 관계가 나옵니다.
2.2 코드 구현
세 가지 유형의 점, 선 및 표면에는 한 가지 공통점이 있기 때문에 점의 좌표를 저장하고 파일에 저장하고 NumParts, NumPoints 및 Box와 같은 공통 속성을 갖습니다. 따라서 점, 선 및 표면 클래스를 디자인하기 전에 Shape 클래스를 추상화해야합니다.
* [ HTML ] :이 기사의 모든 코드는 QT에서 성공적으로 실행 된 코드로, 내 프로젝트에서 직접 복사하여 붙여 넣기 때문에 문제없이 실행되어야합니다.
2.2.1 모양 类
코드 쇼 :
#include <vector>
struct strXY
{
double dX;
double dY;
};
class Shape
{
public:
int _vParts[1000];
int _iNumParts;
int _iShapeType;
double _dBox[4];
std::vector<strXY> _vPoints;
virtual void toShape(double, double) = 0;
};
2.2.2 포인트 등급
코드 쇼 :
class Point :public Shape
{
public:
~Point();
void toShape(double, double);
}
2.2.3 LinePolygon 클래스
Polyline 및 Polygon에는 특정 공통 속성이 있으므로 이러한 공통 속성은 각 레코드의 수와 범위입니다.
코드 쇼 :
#include "shape.h"
class LinePolygon :public Shape
{
public:
int _iNumPnts;
double _dBox[4];
virtual void toShape(double, double) = 0;
};
2.2.4 폴리 라인 클래스
코드 쇼 :
#include "linepolygon.h"
class Polyline :public LinePolygon
{
public:
void toShape(double, double);
};
2.2.5 다각형 클래스
코드 쇼 :
#include "linepolygon.h"
class Polygon :public LinePolygon
{
public:
void toShape(double, double);
};
2.2.6 레이어 클래스
각 파일은 하나의 레이어이고 각 레이어에는 특정 기하학적 요소가 포함되어 있습니다. 여러 레이어를 합치면 다음과 같은 몇 가지 추상 속성이 있습니다.
int _iShpTyp; // 地图类型
double _dBox[4]; // 边界
int _iRecnt; // 记录数
string _sfilename; // 文件名
vector<Shape*> _vShape; // 记录的集合
그리고 레이어는 파일을 처리해야하므로 파일을 읽는 작업, 즉 파일을 읽는 일련의 기능도 있어야합니다. 다음과 같이 :
bool loadFile(string);
void readFilehead(ifstream&);
void toPoint(ifstream& inFile,int iIndex);
void toPolyline(ifstream& inFile,int iIndex);
void toPolygon(ifstream& inFile,int iIndex);
void toPointZ(ifstream& inFile,int iIndex);
void readRecContent(string);
int getReCnt(string);
따라서 전체 레이어 헤더 파일은 다음과 같습니다.
#include <fstream>
#include <vector>
#include "shape.h"
#include "point.h"
#include "polyline.h"
#include "polygon.h"
using namespace std;
class Layer
{
protected:
void readFilehead(ifstream&);
void toPoint(ifstream& inFile, int iIndex);
void toPolyline(ifstream& inFile, int iIndex);
void toPolygon(ifstream& inFile, int iIndex);
void toPointZ(ifstream& inFile, int iIndex);
void readRecContent(string);
int getReCnt(string);
public:
Layer();
~Layer();
bool loadFile(string);
Point* _pPoint;
Polyline* _pLine;
Polygon* _pPolygon;
int _iShpTyp; // 地图类型
double _dBox[4]; // 边界
int _iRecnt; // 记录数
string _sfilename; // 文件名
vector<Shape*> _vShape; // 记录的集合
double _dRecordBox[50000][4];
};
2.2.7지도 클래스
Map 객체에는 많은 Layer가 포함되어 있으므로 Layer에 많은 Shape가 포함 된 것처럼 Map 클래스의 디자인은 다음과 같이 비교할 수 있습니다.
#include <vector>
#include "layer.h"
#include "box.h"
#include <QPoint>
#include <QPolygon>
class Map
{
public:
Map();
Map(string);
// 自定义函数部分
void addFile(string); // 向地图里添加图层
void addFile(string*, int); // 重载addFile函数
// 属性
double _dBox[4]; // 整个地图里面的Box,是所有的Box求并之后的结果
std::vector<Layer*> _vMap; // 用来存储所有的图层
protected:
Box _box;
void setBox();
};
2.2.8 요약
클래스 구문은 매우 간단하지만 추상 개념을 실제 객체에 도입하고 공통점을 추상적으로 설명하는 방법은 매우 어렵습니다.
교사가 말했듯이 수업을 디자인 할 때 한 가지 포인트, 즉 간단하고 직접적입니다.
갈 길이 멀고 C ++는 프로그래머의 두뇌를 망칩니다.
3. 전체 코드
여기서 말할 것도없이 코드가 직접적으로 길어질 것이므로 소스 코드를보고 싶다면 바로 다운로드 할 수 있습니다 .
소스 코드 제공이 필요한 이유는 혼자서 먹을 수없는 좋은 것들이 있는데 오픈 소스는 좋지 않다!