/// <summary>
        /// Creates a Polygon or MultiPolygon from this Polygon shape.
        /// </summary>
        /// <param name="shape">The shape to convert</param>
        /// <param name="factory">The geometry factory to use.</param>
        /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
        /// <returns>The geometry representing the converted shape.</returns>
        private static GeoAPIGeometry FromPolygonShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
        {
            var shells = new List<GeoAPILinearRing>();
            var holes = new List<GeoAPILinearRing>();
            foreach (var part in shape.Range.Parts)
            {
                var coords = new List<GeoAPICoordinate>();
                var i = part.StartIndex;
                foreach (var d in part)
                {
                    var c = new GeoAPICoordinate(d.X, d.Y);
                    //if (shape.HasM()) c.M = M[i];
                    if (shape.HasZ()) c.Z = shape.Z[i];
                    i++;
                    coords.Add(c);
                }
                var ring = factory.CreateLinearRing(coords.ToArray());
                if (shape.Range.Parts.Count == 1)
                {
                    shells.Add(ring);
                }
                else
                {
                    if (NetTopologySuite.Algorithm.CGAlgorithms.IsCCW(ring.Coordinates))
                    {
                        holes.Add(ring);
                    }
                    else
                    {
                        shells.Add(ring);
                    }
                }
            }
            //// Now we have a list of all shells and all holes
            var holesForShells = new List<GeoAPILinearRing>[shells.Count];
            for (var i = 0; i < shells.Count; i++)
            {
                holesForShells[i] = new List<GeoAPILinearRing>();
            }

            // Find holes
            foreach (var testRing in holes)
            {
                GeoAPILinearRing minShell = null;
                GeoAPIEnvelope minEnv = null;
                var testEnv = testRing.EnvelopeInternal;
                var testPt = testRing.Coordinates[0];
                for (int j = 0; j < shells.Count; j++)
                {
                    var tryRing = shells[j];
                    var tryEnv = tryRing.EnvelopeInternal;
                    if (minShell != null)
                        minEnv = minShell.EnvelopeInternal;
                    var isContained = tryEnv.Contains(testEnv)
                                      && (NetTopologySuite.Algorithm.CGAlgorithms.IsPointInRing(testPt, tryRing.Coordinates)
                                           || (PointInList(testPt, tryRing.Coordinates)));

                    // Check if this new containing ring is smaller than the current minimum ring
                    if (isContained)
                    {
                        if (minShell == null || minEnv.Contains(tryEnv))
                        {
                            minShell = tryRing;
                        }
                        holesForShells[j].Add(testRing);
                    }
                }
            }

            var polygons = new GeoAPIPolygon[shells.Count];
            for (var i = 0; i < shells.Count; i++)
            {
                polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray());
            }

            if (polygons.Length == 1)
            {
                if (copyAttributes)
                    polygons[0].UserData = shape.Attributes;
                return polygons[0];
            }
            // It's a multi part
            var ret = factory.CreateMultiPolygon(polygons);
            if (copyAttributes)
                ret.UserData = shape.Attributes;
            return ret;
        }
 /// <summary>
 /// Creates a new MultiPoint geometry from a MultiPoint shape
 /// </summary>
 /// <param name="shape">The shape to convert</param>
 /// <param name="factory">The geometry factory to use.</param>
 /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
 /// <returns>The geometry representing the converted shape.</returns>
 /// <returns></returns>
 private static GeoAPIGeometry FromMultiPointShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
 {
     var coords = new List<GeoAPICoordinate>();
     foreach (var part in shape.Range.Parts)
     {
         var i = part.StartIndex;
         foreach (var vertex in part)
         {
             var c = new GeoAPICoordinate(vertex.X, vertex.Y);
             coords.Add(c);
             //if (shape.HasM()) c.M = shape.M[i];
             if (shape.HasZ()) c.Z = shape.Z[i];
             i++;
         }
     }
     var ret = factory.CreateMultiPoint(coords.ToArray());
     if (copyAttributes)
         ret.UserData = shape.Attributes;
     return ret;
 }
        /// <summary>
        /// Gets the line for the specified index
        /// </summary>
        /// <param name="shape">The shape to convert</param>
        /// <param name="factory">The geometry factory to use.</param>
        /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
        /// <returns>The geometry representing the converted shape.</returns>
        private static GeoAPIGeometry FromLineShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
        {
            var lines = new List<GeoAPILineString>();
            foreach (var part in shape.Range.Parts)
            {
                var i = part.StartIndex;
                var coords = new List<GeoAPICoordinate>();
                foreach (var d in part)
                {
                    var c = new GeoAPICoordinate(d.X, d.Y);
                    coords.Add(c);
                    //if (shape.HasM()) c.M = M[i];
                    if (shape.HasZ()) c.Z = shape.Z[i];
                    i++;
                }
                lines.Add(factory.CreateLineString(coords.ToArray()));
            }
            if (lines.Count == 1)
            {
                if (copyAttributes)
                    lines[0].UserData = shape.Attributes;
                return lines[0];
            }

            var ret = factory.CreateMultiLineString(lines.ToArray());
            if (copyAttributes)
                ret.UserData = shape.Attributes;
            return ret;
        }
        /// <summary>
        /// Get the point for this shape if this is a point shape.
        /// </summary>
        /// <param name="shape">The shape to convert</param>
        /// <param name="factory">The geometry factory to use.</param>
        /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
        /// <returns>The geometry representing the converted shape.</returns>
        private static GeoAPIGeometry FromPointShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
        {
            var part = shape.Range.Parts[0];
            var i = part.StartIndex;

            var c = new GeoAPICoordinate(part.Vertices[0], part.Vertices[1]);
            //if (shape.HasM()) c.M = shape.M[i]
            if (shape.HasZ()) c.Z = shape.Z[i];
            var ret = factory.CreatePoint(c);
            if (copyAttributes)
                ret.UserData = shape.Attributes;
            return ret;
        }