C ++는 .shp 파일을 읽습니다.

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 바이트부터 파일 끝까지 데이터 레코드의 내용입니다. 그림에서 볼 수 있듯이 .shp 파일의 처음 100 바이트는 파일 헤더이고 다음 내용은 데이터 레코드입니다.
파일 헤더에 대한 설명은 아래 그림을 참조하십시오.
그림에서 가장 왼쪽 열은 바이트 번호입니다. 예를 들어 7 행에있는 파일 길이의 바이트 번호는 24입니다. 파일 길이의 내용을 읽으려면 파일 포인터를 24로 이동하기 만하면됩니다.
위 그림에서 가장 오른쪽 열은 컴퓨터 바이트 순서 모드입니다. 정보를 검색 한 후 저자는 다른 컴퓨터 시스템이 다른 엔디안을 사용할 수 있음을 알게되었습니다. 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과 관련하여 다음 그림을 볼 수 있습니다.
Point, Polyline 및 Polygon에 해당하는 ShapeType의 값은 각각 1, 3, 5입니다.

그런 다음 파일의 데이터 레코드가 있습니다.
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 유형 데이터입니다. 아래 그림과 같이:
오프셋은 파일에있는 현재 레코드의 첫 번째 바이트 위치 인 오프셋입니다. 뒤에 오는 ContentLength는 .shp 파일의 각 레코드에 해당하는 ContentLength와 동일합니다.
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. 전체 코드

여기서 말할 것도없이 코드가 직접적으로 길어질 것이므로 소스 코드를보고 싶다면 바로 다운로드 할 수 있습니다 .
소스 코드 제공이 필요한 이유는 혼자서 먹을 수없는 좋은 것들이 있는데 오픈 소스는 좋지 않다!

자신을 경멸하고 오픈 소스 세계를 포용하세요, Oye!

추천

출처blog.csdn.net/GeomasterYi/article/details/106434452