Create a shapefile

Topics: Algorithms, SharpMap v2.0
Mar 2, 2012 at 2:05 PM

Hi all! I have to create a ShapeFile and browsing the discussion I found 2 solutions:

Using SharpMap V2 or using the EGIS.ShapeFileLib dll

 

Both mothods work quite ok, but when I try to save a multipolygon shapefile I get this error:

"Currently unsupported geometry type"

 

this error comes from ShapeFile.computeGeometryLengthInWords function.

It seems it can handle Point, MultiPoint, LineString, MultiLineString and Polygon only, but not MultiPolygon


What can I do?

Developer
Mar 3, 2012 at 12:55 AM

Quick Solution while waiting the support: Split MultiPolygon become 1,2,3... Polygon :)

Mar 5, 2012 at 8:33 AM

OK thank you I solved my problem :)

Aug 3, 2012 at 2:22 AM

Hi! 

Please can you show  me how to create a shapefile with SharMap 2.0 , I really need it

Sep 5, 2012 at 11:25 AM

I used http://www.easygisdotnet.com/api/output/html/N_EGIS_ShapeFileLib.htm time ago, but I had problems in converting polygons with holes

Sep 5, 2012 at 12:14 PM

Or you can check this: http://shapelib.maptools.org/dl/contrib/DotNetArchive.zip

this is very interesting....

Sep 6, 2012 at 7:23 AM
Edited Sep 6, 2012 at 7:25 AM

Hey! Look this piece of code! It converts a FeatureDataTable into a ShapeFile. Pay attention in the creation of the DBF file: the columns of the FeatureDataTable must have MaxSize property set

(the namespace MapTools is downloadable from http://shapelib.maptools.org/dl/contrib/DotNetArchive.zip)

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using MapTools;
using SharpMap.Data;
using SharpMap.Geometries;

namespace ShapeFileWriter
{
    public class ShapeFileWriter
    {
        public static void WriteFile(FeatureDataTable FDT, string FileName)
        {
            ShapeLib.ShapeType shpType = ShapeLib.ShapeType.Polygon;
            IntPtr hShp;
            int iRet;
            // create a new shapefile
            hShp = ShapeLib.SHPCreate(FileName, shpType);
            if (hShp.Equals(IntPtr.Zero))
                return;
            IntPtr pshpObj;
            foreach(FeatureDataRow FDR in FDT)
            {
                Polygon P= (Polygon)FDR.Geometry;

                // add shapes
                if (P.InteriorRings.Count> 0)
                {
                    int NVERTICES = 0;
                    List<int> apartStart = new List<int>();
                    List<ShapeLib.PartType> apartType = new List<ShapeLib.PartType>();
                    List<double> vX = new List<double>();
                    List<double> vY = new List<double>();
                    apartStart.Add(NVERTICES);
                    apartType.Add(ShapeLib.PartType.Ring);
                    NVERTICES += P.ExteriorRing.Vertices.Count;
                    for (int v = 0; v < P.ExteriorRing.Vertices.Count; v++)
                    {
                        vX.Add(P.ExteriorRing.Vertices[v].X);
                        vY.Add(P.ExteriorRing.Vertices[v].Y);
                    }
                    apartStart.Add(NVERTICES);

                    for (int j = 0; j < P.InteriorRings.Count; j++)
                    {
                        for (int v = 0; v < P.InteriorRings[j].Vertices.Count; v++)
                        {
                            vX.Add(P.InteriorRings[j].Vertices[v].X);
                            vY.Add(P.InteriorRings[j].Vertices[v].Y);
                        }
                        NVERTICES += P.InteriorRings[j].Vertices.Count;
                        if(j+1!=P.InteriorRings.Count)
                            apartStart.Add(NVERTICES);
                        apartType.Add(ShapeLib.PartType.Ring);
                    }
                    pshpObj = ShapeLib.SHPCreateObject(shpType, -1, apartStart.Count, apartStart.ToArray(), apartType.ToArray(), NVERTICES /*+ 4*/, vX.ToArray(), vY.ToArray(), null, null);
                }
                else
                {
                    List<double> vX = new List<double>();
                    List<double> vY = new List<double>();
                    for (int v = 0; v < P.ExteriorRing.Vertices.Count; v++)
                    {
                        vX.Add(P.ExteriorRing.Vertices[v].X);
                        vY.Add(P.ExteriorRing.Vertices[v].Y);
                    }
                    pshpObj = ShapeLib.SHPCreateSimpleObject(shpType, P.ExteriorRing.Vertices.Count, vX.ToArray(), vY.ToArray(), null);
                }
                iRet = ShapeLib.SHPWriteObject(hShp, -1, pshpObj);
                ShapeLib.SHPDestroyObject(pshpObj);
            }

            ShapeLib.SHPClose(hShp);


            // create dbase file
            IntPtr hDbf = ShapeLib.DBFCreate(FileName);
            if (hDbf.Equals(IntPtr.Zero))
            {
                //Console.WriteLine("Error:  Unable to create {0}.dbf!", FileName);
                return;
            }

            for(int i=0;i<FDT.Columns.Count;i++)
            {
                if (FDT.Columns[i].DataType == ((Int32)0).GetType() || FDT.Columns[i].GetType() == ((Int16)0).GetType())
                    iRet = ShapeLib.DBFAddField(hDbf, FDT.Columns[i].ColumnName, ShapeLib.DBFFieldType.FTInteger, 4, 0);
                else if (FDT.Columns[i].DataType == "".GetType())
                    iRet = ShapeLib.DBFAddField(hDbf, FDT.Columns[i].ColumnName, ShapeLib.DBFFieldType.FTString, FDT.Columns[i].MaxLength, 0);
                else if (FDT.Columns[i].DataType == (DateTime.Now).GetType())
                    iRet = ShapeLib.DBFAddField(hDbf, FDT.Columns[i].ColumnName, ShapeLib.DBFFieldType.FTDate, 10, 0);
                else if (FDT.Columns[i].DataType == ((double)0).GetType() || FDT.Columns[i].GetType() == ((float)0).GetType() || FDT.Columns[i].GetType() == ((decimal)0).GetType())
                    iRet = ShapeLib.DBFAddField(hDbf, FDT.Columns[i].ColumnName, ShapeLib.DBFFieldType.FTDouble, 32, 0);
                else if (FDT.Columns[i].DataType == (true).GetType())
                    iRet = ShapeLib.DBFAddField(hDbf, FDT.Columns[i].ColumnName, ShapeLib.DBFFieldType.FTLogical, 1, 0);
            }
            int iShape=0;
            foreach(FeatureDataRow FDR in FDT)
            {
                int iField = 0;
                for(int i=0;i<FDR.ItemArray.Length;i++)
                {
                    if (FDR.ItemArray[i] == null || FDR.ItemArray[i] == DBNull.Value)
                    {
                        iRet = ShapeLib.DBFWriteNULLAttribute(hDbf, iShape, iField++);
                    }
                    else
                    {
                        if (FDT.Columns[i].DataType == ((Int32)0).GetType() || FDT.Columns[i].GetType() == ((Int16)0).GetType())
                            iRet = ShapeLib.DBFWriteIntegerAttribute(hDbf, iShape, iField++, Convert.ToInt32(FDR.ItemArray[i]));
                        else if (FDT.Columns[i].DataType == "".GetType())
                            iRet = ShapeLib.DBFWriteStringAttribute(hDbf, iShape, iField++, FDR.ItemArray[i].ToString());
                        else if (FDT.Columns[i].DataType == (DateTime.Now).GetType())
                            iRet = ShapeLib.DBFWriteDateAttribute(hDbf, iShape, iField++, (DateTime)FDR.ItemArray[i]);
                        else if (FDT.Columns[i].DataType == ((double)0).GetType() || FDT.Columns[i].GetType() == ((float)0).GetType() || FDT.Columns[i].GetType() == ((decimal)0).GetType())
                            iRet = ShapeLib.DBFWriteDoubleAttribute(hDbf, iShape, iField++, (double)FDR.ItemArray[i]);
                        else if (FDT.Columns[i].DataType == (true).GetType())
                            iRet = ShapeLib.DBFWriteLogicalAttribute(hDbf, iShape, iField++, (bool)FDR.ItemArray[i]);
                    }
                }
                iShape++;
            }
            ShapeLib.DBFClose(hDbf);
        }
    }
}

 

Oct 17, 2012 at 1:57 AM
Edited Oct 17, 2012 at 6:57 AM

Hi, I need creating shp file function too.

But when I use maptools wrapper, error happened.

I downloaded the zip file you linked, I built it in the VS 2008 and .Net Framework 3.5. And I use the simple code below.

 

     ShapeLib.ShapeType shpType = ShapeLib.ShapeType.Polygon;
     Console.WriteLine("*****Creating {0}*****\n", ShapeLib.SHPTypeName(shpType));// error in this line

Do you know why error occurs?

And also I tried to use EGIS.ShapFileLib but in sample codes they use existing shape file to make new file. Could you give me an example that write new shape file?

Thanks in advance!

Oct 17, 2012 at 5:30 PM

Can you post me the full error message?

Oct 18, 2012 at 12:28 AM
Edited Oct 18, 2012 at 1:02 AM

ShapeLib Wrapper : 

There was an exception BadFormatException, and I found that I didn't make the environment same as x86.

When I made it same, there is an another error. The application just stopped and close. There is no error line on output and stack tab.

 

EGIS.ShapeFileLib :

When I made a shape file with polygon, it worked well.

When I made it with point type, the file was created well, but I can't see anything when I open it on the shp file viewer.

Anybody has the sample source creating new shape file with point type?

 

SharpMap :

I am new to SharpMap. Where can I find the sample source creating new shape file?

When I found in WinFormSamples for shapefile, there is SharpMap.Data.Providers.ShapeFile class. But I can't find the method that create shapefile.

 

Thanks to steelraiden and everybody!

Oct 18, 2012 at 7:34 AM

well, I think the environment has to be x86.

I used these libraries to create polygons only (no multipolygons, no points, no linestrings), so I can't understand the error by now. 

Can you post me the code to recreate the error?

Oct 19, 2012 at 1:00 AM

WOO....So sorry that I took some mistakes.

I should have made my environment x86.

And I added just some PointD arrays. In array, it has different coordinate. But each array has same value.

I thought that each point in PointD array would add to shape file. But it didn't work. Opening it, I can't find any point. Although there is attribute I added to dbf file.

When I tested with more PointD array with different coordinate, it works.

Thank you:)

Oct 20, 2012 at 7:07 AM

No problem! If you want, I have some nice code to create kml/kmz files too 

Developer
Nov 15, 2012 at 5:30 AM
steelraiden wrote:

No problem! If you want, I have some nice code to create kml/kmz files too 

Code for KML/KMZ would be much appreciated

Nov 23, 2012 at 1:45 PM

for KML/KMZ coding I started from this site: http://sharpkml.codeplex.com/

 

and for the SHP creation, I found this library (fully compatible with SharpMap): http://code.google.com/p/nettopologysuite/

look at ShapefileDataWriter class

May 27, 2013 at 9:40 PM
@steelraiden
I'm trying to add a new kml layer to Sharpmap.
Do you know how to do it?
Sharpmap seems which don't have a provider for kml.
May 29, 2013 at 4:39 PM
yes I know how to do it.
To starting you can look at http://sharpkml.codeplex.com/
If you want to know more, e-mail me

May 29, 2013 at 5:01 PM
SteelRaiden wrote:
yes I know how to do it. To starting you can look at http://sharpkml.codeplex.com/ If you want to know more, e-mail me
I have created KML's using SharpKml. It's working fine.
But add it to Sharpmap as a layer is the main problem.
Can you help me with this?
May 30, 2013 at 2:16 PM
You have to read the geometries and data of your KML file and create a memory provider like GeometryFeatureProvider or better NtsProvider.
Doing this, you have a layer. If you create a class, you can also read the style of your KML geometries and modify the style of your memory layer


Nov 12, 2013 at 5:15 AM
Edited Nov 12, 2013 at 5:16 AM
ni mei.You're welcome.
Developer
Nov 18, 2013 at 5:41 AM
steelraiden wrote:
for KML/KMZ coding I started from this site: http://sharpkml.codeplex.com/   and for the SHP creation, I found this library (fully compatible with SharpMap): http://code.google.com/p/nettopologysuite/ look at ShapefileDataWriter class
this is what I did, just in case it might help someone, improvements will be greatly appreciated

Firstly I made an extension to generate the Shp dbf headers (mainly because of an exception I got when using the stock feature of NTS on some data sets, the code is almost same)
using NetTopologySuite.Features;
using NetTopologySuite.IO;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

public static class ShapeFileHelper
    {
        private const int DoubleLength = 18;
        private const int DoubleDecimals = 8;
        private const int IntLength = 10;
        private const int IntDecimals = 0;
        private const int StringLength = 254;
        private const int StringDecimals = 0;
        private const int BoolLength = 1;
        private const int BoolDecimals = 0;
        private const int DateLength = 8;
        private const int DateDecimals = 0;


        public static DbaseFileHeader GetDBFHeader(this DataColumnCollection columns, int count)
        {

            var header = new DbaseFileHeader(Encoding.UTF8);
            header.NumRecords = count;
            foreach (DataColumn col in columns)
            {
                var name = col.ColumnName;
                Type type = col.DataType;
                if (type == typeof(double) || type == typeof(float))
                    header.AddColumn(name, 'N', DoubleLength, DoubleDecimals);
                else if (type == typeof(short) || type == typeof(ushort) ||
                         type == typeof(int) || type == typeof(uint) ||
                         type == typeof(long) || type == typeof(ulong))
                    header.AddColumn(name, 'N', IntLength, IntDecimals);
                else if (type == typeof(string))
                    header.AddColumn(name, 'C', StringLength, StringDecimals);
                else if (type == typeof(bool))
                    header.AddColumn(name, 'L', BoolLength, BoolDecimals);
                else if (type == typeof(DateTime))
                    header.AddColumn(name, 'D', DateLength, DateDecimals);
                else
                    header.AddColumn(name, 'C', StringLength, StringDecimals);
            }
            return header;
        }

    }
then did the export like this

public void ExportShapeFile(VectorLayer layer, string FileName)
{
    var sfw = new ShapefileDataWriter(FileName);
    var fds = GetFeatureDataSet(layer);
    var fc = new List<Feature>();
    var ft = fds.Tables[0];
    foreach (FeatureDataRow item in ft.Rows)
    {
        var attrs = new AttributesTable();
        foreach (DataColumn col in ft.Columns)
        {
            var attName = col.ColumnName;
            var attVal = item[col];
            attrs.AddAttribute(attName, attVal);
        }
        var feature = new Feature(item.Geometry, attrs);
        fc.Add(feature);
    }
    sfw.Header = ft.Columns.GetDBFHeader(fc.Count);
    sfw.Write(fc);
}

Jan 7, 2014 at 2:56 AM
Hi, the code is clear. But I can't find GetFeatureDataSet(vectorLayer) function, where does it belong to ?
Developer
Jan 7, 2014 at 3:37 PM
mileslee wrote:
Hi, the code is clear. But I can't find GetFeatureDataSet(vectorLayer) function, where does it belong to ?
The GetFeatureDataSet(vectorLayer) takes in a layer and returns the backing data of the layer. in the simplest case you can do something like
        public FeatureDataSet GetFeatureDataSet(VectorLayer vlay)
        {
            var fds = new FeatureDataSet();
            vlay.ExecuteIntersectionQuery(vlay.Envelope, fds);
            return fds;
        }
Jun 13, 2015 at 2:33 PM
the above code not working in sharpmap 1.1
GEOAPI 1.7.2 is required by sharpmap 1.1 while NTS 1.3.3 requires 1.7.3 and higher.
this is causing a conflict were as NTS ver 1.3.2 nettotpologysuite.IO.shapefile doesnot exist. hence shapefilewriter clas doesnot exist
suggest a remedy please
Coordinator
Jun 15, 2015 at 6:29 AM
you need to add a reference to this nuget package.