shp地图解析(不用AE)

shp地图解析(不用AE)

AE太重型,还收费,如果只是加载地图作为底图,可以用纯C#实现。线类型用得最多,以下是线类型的数据结构:

总体架构

文件头

记录头

记录内容

记录头

记录内容

。。。。。。。。。。。。

记录头

记录内容

文件头

位置 类型 字段 说明
Byte 0 int File Code 文件代码
Byte 4 int 无用  
Byte 8 int 无用  
Byte 12 int 无用  
Byte 16 int 无用  
Byte 20 int 无用  
Byte 24 int File Length 文件长度
Byte 28 int Version 版本
Byte 32 int Shape Type

图形类型

1:Point,点类型

3:PolyLine,线类型

5:Polygon,面类型

Byte 36 double Xmin 整图的X轴坐标最小值
Byte 44 double Ymin 整图的Y轴坐标最小值
Byte 52 double Xmax 整图的X轴坐标最大值
Byte 60 double Ymax 整图的Y轴坐标最大值
Byte 68* double Zmin  
Byte 76* double Zmax  
Byte 84* double Mmin  
Byte 92* double Mmax  

记录头

位置 类型 字段 说明
Byte 0 int Record Number 记录号,从1开始
Byte 4 int Content Length 内容长度,内容的16位字数,不包括记录号。

记录内容

点类型:

位置 类型 字段 说明
Byte 0 int ShapeType Shape类型=1
Byte 4 double X 点的X坐标
Byte 12 double Y 点的Y坐标

线类型:

位置 类型 字段 说明
Byte 0 int ShapeType Shape类型=3
Byte 4 double [4] Box 该线条的边界盒,以Xmin,Ymin,Xmax,Ymax的顺序存储
Byte 36 int NumParts 是PolyLine中部分的数目
Byte 40 int NumPoints 是PolyLine中的数目
Byte 44 int [NumParts] Parts 每条PolyLine存储它在点数列中的第一个点的索引。数列索引是从0开始的。Parts[NumParts]数组是Points[NumPoints]数组的目录
X Point[NumPoints] Points 本条记录的所有点。Struct Point {Double  X;Double  Y;}

PartsPoints之间的关系:

如果Parts [0]=0Parts [1]=3Parts [2]=11Parts [3]=15那么

第0条线:(Points[0], Points[1] , Points[2])三个点依次连结

第1条线:(Points[3], Points[4] , Points[5] , Points[6] , Points[7] , Points[8] , Points[9] , Points[10])这几个点依次连结

第3条线:(Points[11], Points[12] , Points[13] , Points[14])四个点依次连结

ClassShp类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;

namespace SDD
{
  
struct StructShapePoint { public double X; public double Y; } struct StructShapePolyline { public int RecordNumber;//记录号 public int ContentLength;//内容长度 public int ShapeType; public double[] Box;//长度为4 public int PartsCount; public int PointsCount; public List<int> Parts;//在部分中第一个点的索引 public List<StructShapePoint> Points;//所有部分的点 public List<StructShapePoint[]> Lines;//把点按线组织好 } class ClassShp { public string FileName; public int FileLength; public int FileVersion; public int ShapeType;//绘图类型:1-点,3-线,5-面 public double Xmin, Ymin, Xmax, Ymax;//地图边界尺寸 public double RawWidth, RawHeight;//地图大小,原始值 public double RawCenterX, RawCenterY;//shp原始坐标系的中心点 public List<StructShapePoint> ListPoints = new List<StructShapePoint>();//点集合 public List<StructShapePolyline> ListPolylines = new List<StructShapePolyline>();//线集合 public double Scale = 0;//放大倍数,原始数据中1表示的像素数 public double CenterX, CenterY;//地图缩放后的中心点在控件坐标系中的位置 public double WindowWidth;//显示控件大小 public double WindowHeight; public Bitmap Bmp = null;//用于显示的画布,大小等于显示控件 public Pen ThePen = new Pen(Color.White, 1); public ClassShp() { } public ClassShp(string pmtShpPathName, double pmtVisibleWidth, double pmtVisibleHeight) { if (File.Exists(pmtShpPathName) == false) return; if (Init(pmtShpPathName, pmtVisibleWidth, pmtVisibleHeight)) { SaveAsTxt(); //把数据保存成文本文档 } } //################################################################################ // 由Xmin等四个值计算出基本成员参数 //################################################################################ public void SetBaseParameter(double pmtXmin,double pmtYmin,double pmtXmax,double pmtYmax) { Xmin = pmtXmin; Ymin = pmtYmin; Xmax = pmtXmax; Ymax = pmtYmax; RawWidth = Xmax - Xmin; RawHeight = Ymax - Ymin; RawCenterX = (Xmin + Xmax) / 2; RawCenterY = (Ymin + Ymax) / 2; CenterX = WindowWidth / 2; CenterY = WindowHeight / 2; SetRelativityScale(1, WindowWidth, WindowHeight); Console.WriteLine("绘图类型:{0}", ShapeType); Console.WriteLine("地图边界:({0}, {1}), ({2}, {3})", Xmin, Ymin, Xmax, Ymax); Console.WriteLine("地图大小:{0} * {1}", RawWidth, RawHeight); Console.WriteLine("地图中心:({0}, {1})", RawCenterX, RawCenterY); } //################################################################################ // 初始化 //################################################################################ public bool Init(string pmtShpPathName, double pmtVisibleWidth, double pmtVisibleHeight) { if (File.Exists(pmtShpPathName) == false) return false; int nameIndex = pmtShpPathName.LastIndexOf("\")+1; int nameLenght = pmtShpPathName.Length-5-pmtShpPathName.LastIndexOf("\"); FileName = pmtShpPathName.Substring(nameIndex, nameLenght); WindowWidth = pmtVisibleWidth; WindowHeight = pmtVisibleHeight; try { FileStream fs = new FileStream(pmtShpPathName, FileMode.Open); BinaryReader br = new BinaryReader(fs, Encoding.Default); br.ReadBytes(24); FileLength = br.ReadInt32(); FileVersion = br.ReadInt32(); ShapeType = br.ReadInt32(); Xmin = br.ReadDouble(); Ymin = br.ReadDouble(); Xmax = br.ReadDouble(); Ymax = br.ReadDouble(); br.ReadBytes(32); if (ShapeType == 1) { ListPoints.Clear(); while (br.PeekChar() != -1) { StructShapePoint shapePoint = new StructShapePoint(); uint recordNum = br.ReadUInt32(); int dataLength = br.ReadInt32(); br.ReadInt32(); shapePoint.X = br.ReadDouble(); shapePoint.Y = br.ReadDouble(); ListPoints.Add(shapePoint); } }//end of : if (ShpType==1) else if (ShapeType == 3 || ShapeType == 5) { ListPolylines.Clear(); while (br.PeekChar() != -1) { StructShapePolyline shapePolyline = new StructShapePolyline(); shapePolyline.Box = new double[4]; shapePolyline.Parts = new List<int>(); shapePolyline.Points = new List<StructShapePoint>(); shapePolyline.Lines = new List<StructShapePoint[]>(); shapePolyline.RecordNumber = br.ReadInt32(); shapePolyline.ContentLength = br.ReadInt32(); shapePolyline.ShapeType = br.ReadInt32(); shapePolyline.Box[0] = br.ReadDouble(); shapePolyline.Box[1] = br.ReadDouble(); shapePolyline.Box[2] = br.ReadDouble(); shapePolyline.Box[3] = br.ReadDouble(); shapePolyline.PartsCount = br.ReadInt32(); shapePolyline.PointsCount = br.ReadInt32(); //把每一段线的开始点偏移读进Parts队列 for (int i = 0; i < shapePolyline.PartsCount; i++) { int tmpPart = br.ReadInt32(); shapePolyline.Parts.Add(tmpPart); } //把所有点读进Points队列 for (int i = 0; i < shapePolyline.PointsCount; i++) { StructShapePoint tmpPoint = new StructShapePoint(); tmpPoint.X = br.ReadDouble(); tmpPoint.Y = br.ReadDouble(); shapePolyline.Points.Add(tmpPoint); } //把该线的点读进Lines队列 for (int i = 0; i < shapePolyline.PartsCount; i++) { int startpoint; int endpoint; if (i == shapePolyline.PartsCount - 1) { startpoint = (int)shapePolyline.Parts[i]; endpoint = shapePolyline.PointsCount; } else { startpoint = (int)shapePolyline.Parts[i]; endpoint = (int)shapePolyline.Parts[i + 1]; } StructShapePoint[] shpPointArray = new StructShapePoint[endpoint - startpoint]; for (int j = 0, k = startpoint; k < endpoint; j++, k++) { shpPointArray[j].X = shapePolyline.Points[k].X; shpPointArray[j].Y = shapePolyline.Points[k].Y; } shapePolyline.Lines.Add(shpPointArray); } //把该线条加进m_polylines队列 ListPolylines.Add(shapePolyline); } }//end of : else if (ShpType == 3) SetBaseParameter(Xmin, Ymin, Xmax, Ymax); return true; } catch (System.Exception ex) { Console.WriteLine("异常:ClassShp.Init()" + ex.ToString()); return false; } } //################################################################################ // 把数据写成txt文本 //################################################################################ public void SaveAsTxt() { StreamWriter swLine = new StreamWriter(FileName+".txt"); swLine.WriteLine("绘图类型:{0}", ShapeType); swLine.WriteLine("地图边界:({0}, {1}), ({2}, {3})", Xmin, Ymin, Xmax, Ymax); swLine.WriteLine("地图大小:{0} * {1}", RawWidth, RawHeight); swLine.WriteLine("地图中心:({0}, {1})", RawCenterX, RawCenterY); int recordCount = 0; if (ShapeType==1) { foreach (StructShapePoint p in ListPoints) { swLine.WriteLine("点{0}: ({1}, {2})", recordCount, p.X, p.Y); recordCount++; } } else if (ShapeType==3 || ShapeType==5) { foreach (StructShapePolyline p in ListPolylines) { for (int i = 0; i < p.Lines.Count; i++) { swLine.WriteLine("记录内容{0}:########################################################", recordCount, i); for (int j = 0; j < p.Lines[i].Length; j++) { StructShapePoint ps = p.Lines[i][j]; swLine.WriteLine("线{0}: ({1}, {2})", j, ps.X, ps.Y); } } recordCount++; }//end of :foreach } swLine.Close(); } //################################################################################ // 把图绘进Bmp中 //################################################################################ public bool DrawBmp(int pmtWidth, int pmtHeight) { double screenWidth = RawWidth * Scale; double screenHeight = RawHeight * Scale; try { Bmp = new Bitmap(pmtWidth, pmtHeight);//创建画布 Graphics g = Graphics.FromImage(Bmp); g.TranslateTransform((float)0, (float)pmtHeight);//变换坐标系,把左下角置为原点 g.ScaleTransform((float)1, (float)-1); if (ShapeType == 1) //点类型 { foreach (StructShapePoint p in ListPoints) { PointF pf = new PointF(); double offsetX = CenterX - screenWidth / 2.0; double offsetY = CenterY - screenHeight / 2.0; pf.X = (float)((p.X - Xmin) * Scale + offsetX); pf.Y = (float)((p.Y - Ymin) * Scale + offsetY); float r = 3; //g.DrawEllipse(ThePen, pf.X - r / 2, pf.Y + r / 2, r * 2, r * 2);//画点 Brush bs = new SolidBrush(Color.Green);//填充的颜色 g.FillEllipse(bs, pf.X - r / 2, pf.Y + r / 2, r * 2, r * 2); } } else if (ShapeType == 3 || ShapeType == 5) //线类型和面类型是一样的 { //Console.WriteLine("线类型"); foreach (StructShapePolyline p in ListPolylines) { for (int i = 0; i < p.Lines.Count; i++) { PointF[] pfArray = new PointF[p.Lines[i].Length]; for (int j = 0; j < p.Lines[i].Length; j++) { StructShapePoint ps = p.Lines[i][j]; double offsetX = CenterX - screenWidth / 2.0; double offsetY = CenterY - screenHeight / 2.0; pfArray[j].X = (float)((ps.X - Xmin) * Scale + offsetX); pfArray[j].Y = (float)((ps.Y - Ymin) * Scale + offsetY); } g.DrawLines(ThePen, pfArray); } } } return true; } catch (System.Exception ex) { Console.WriteLine("异常:ClassShp.drawBmp" + ex.ToString()); return false; } } } }

在主窗口放置一个pictureBox控件,名为pictureBoxMap.

主函数:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace SDD
{
    public partial class FormMain : Form
    {
        ClassShp ShapeChina;

        public FormMain()
        {
            InitializeComponent();

            string mapChinaPathName = new ClassShp(@"D:map地图国界.shp", pictureBoxMap.Width, pictureBoxMap.Height);
            pictureBoxMap.Refresh();
        }
        private void pictureBoxMap_Paint(object sender, PaintEventArgs e)
        {
            Bitmap bmp = new Bitmap(pictureBoxMap.Width, pictureBoxMap.Height);//创建画布
            ShapeChina.DrawBmp(pictureBoxMap.Width, pictureBoxMap.Height);
            e.Graphics.DrawImage(ShapeChina.Bmp, 0, 0);
        }
    }
}