Example #1
0
        /// <summary>
        /// Load media from stream.
        /// </summary>
        /// <param name="stream">
        /// A <see cref="Stream"/> where the media data is stored.
        /// </param>
        /// <param name="criteria">
        /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream.
        /// </param>
        /// <returns>
        /// An <see cref="Image"/> holding the media data.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="stream"/> or <paramref name="criteria"/> is null.
        /// </exception>
        public Image Load(Stream stream, ImageCodecCriteria criteria)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (criteria == null)
            {
                throw new ArgumentNullException("criteria");
            }

            const int BufferBlockSize = 4096;

            byte[] buffer = new byte[stream.Length];
            int    bufferOffset = 0, bytesRed;

            // Read the stream content
            while ((bytesRed = stream.Read(buffer, bufferOffset, BufferBlockSize)) > 0)
            {
                bufferOffset += bytesRed;
            }

            GCHandle bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);

            try {
                Gdal.FileFromMemBuffer("/vsimem/GdalLoad", buffer.Length, bufferHandle.AddrOfPinnedObject());
                using (Dataset dataset = Gdal.Open("/vsimem/GdalLoad", Access.GA_ReadOnly)) {
                    return(Load(dataset, criteria));
                }
            } finally {
                // Release virtual path
                Gdal.Unlink("/vsimem/GdalLoad");
                bufferHandle.Free();
            }
        }
Example #2
0
    public static void Main(string[] args)
    {
        if (args.Length != 1)
        {
            usage();
        }

        byte[] imageBuffer;

        using (FileStream fs = new FileStream(args[0], FileMode.Open, FileAccess.Read))
        {
            using (BinaryReader br = new BinaryReader(fs))
            {
                long numBytes = new FileInfo(args[0]).Length;
                imageBuffer = br.ReadBytes((int)numBytes);
                br.Close();
                fs.Close();
            }
        }

        Gdal.AllRegister();

        string memFilename = "/vsimem/inmemfile";

        try
        {
            Gdal.FileFromMemBuffer(memFilename, imageBuffer);
            Dataset ds = Gdal.Open(memFilename, Access.GA_ReadOnly);

            Console.WriteLine("Raster dataset parameters:");
            Console.WriteLine("  RasterCount: " + ds.RasterCount);
            Console.WriteLine("  RasterSize (" + ds.RasterXSize + "," + ds.RasterYSize + ")");

            Driver drv = Gdal.GetDriverByName("GTiff");

            if (drv == null)
            {
                Console.WriteLine("Can't get driver.");
                System.Environment.Exit(-1);
            }

            drv.CreateCopy("sample.tif", ds, 0, null, null, null);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally
        {
            Gdal.Unlink(memFilename);
        }
    }
Example #3
0
        /// <summary>
        /// Create a raster.
        /// </summary>
        /// <param name="leaveopen"></param>
        public override void Create(bool leaveopen = false)
        {
            if (GISFileInfo.Exists)
            {
                Gdal.Unlink(GISFileInfo.FullName);
            }

            CreateDS(driver, GISFileInfo, Extent, Proj, Datatype);
            RefreshFileInfo();
            if (!leaveopen)
            {
                UnloadDS();
            }
        }
Example #4
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            List <Curve> boundary = new List <Curve>();

            DA.GetDataList <Curve>(0, boundary);

            string IMG_file = string.Empty;

            DA.GetData <string>(1, ref IMG_file);

            RESTful.GdalConfiguration.ConfigureGdal();
            OSGeo.GDAL.Gdal.AllRegister();

            Dataset datasource = Gdal.Open(IMG_file, Access.GA_ReadOnly);

            OSGeo.GDAL.Driver drv = datasource.GetDriver();


            if (datasource == null)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "The vector datasource was unreadable by this component. It may not a valid file type for this component or otherwise null/empty.");
                return;
            }

            ///Get info about image
            string        srcInfo     = string.Empty;
            List <string> infoOptions = new List <string> {
                "-stats"
            };

            srcInfo = Gdal.GDALInfo(datasource, new GDALInfoOptions(infoOptions.ToArray()));


            ///Get the spatial reference of the input raster file and set to WGS84 if not known
            ///Set up transform from source to WGS84
            OSGeo.OSR.SpatialReference sr = new SpatialReference(Osr.SRS_WKT_WGS84);
            if (datasource.GetProjection() == null)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Coordinate Reference System (CRS) is missing.  CRS set automatically set to WGS84.");
            }

            else
            {
                sr = new SpatialReference(datasource.GetProjection());

                if (sr.Validate() != 0)
                {
                    ///Check if SRS needs to be converted from ESRI format to WKT to avoid error:
                    ///"No translation for Lambert_Conformal_Conic to PROJ.4 format is known."
                    ///https://gis.stackexchange.com/questions/128266/qgis-error-6-no-translation-for-lambert-conformal-conic-to-proj-4-format-is-kn
                    SpatialReference srEsri = sr;
                    srEsri.MorphFromESRI();
                    string projEsri = string.Empty;
                    srEsri.ExportToWkt(out projEsri);

                    ///If no SRS exists, check Ground Control Points SRS
                    SpatialReference srGCP   = new SpatialReference(datasource.GetGCPProjection());
                    string           projGCP = string.Empty;
                    srGCP.ExportToWkt(out projGCP);

                    if (!string.IsNullOrEmpty(projEsri))
                    {
                        datasource.SetProjection(projEsri);
                        sr = srEsri;
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Spatial Reference System (SRS) morphed form ESRI format.");
                    }
                    else if (!string.IsNullOrEmpty(projGCP))
                    {
                        datasource.SetProjection(projGCP);
                        sr = srGCP;
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Spatial Reference System (SRS) set from Ground Control Points (GCPs).");
                    }
                    else
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Spatial Reference System (SRS) is unknown or unsupported.  SRS assumed to be WGS84." +
                                          "Try setting the SRS with the GdalWarp component using -t_srs EPSG:4326 for the option input.");
                        sr.SetWellKnownGeogCS("WGS84");
                    }
                }

                else
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Data source SRS: EPSG:" + sr.GetAttrValue("AUTHORITY", 1));
                }
            }

            //OSGeo.OSR.SpatialReference sr = new SpatialReference(ds.GetProjection());
            OSGeo.OSR.SpatialReference dst = new OSGeo.OSR.SpatialReference("");
            dst.SetWellKnownGeogCS("WGS84");
            OSGeo.OSR.CoordinateTransformation coordTransform = new OSGeo.OSR.CoordinateTransformation(sr, dst);
            OSGeo.OSR.CoordinateTransformation revTransform   = new OSGeo.OSR.CoordinateTransformation(dst, sr);

            double[] adfGeoTransform = new double[6];
            double[] invTransform    = new double[6];
            datasource.GetGeoTransform(adfGeoTransform);
            Gdal.InvGeoTransform(adfGeoTransform, invTransform);

            int width  = datasource.RasterXSize;
            int height = datasource.RasterYSize;

            ///Dataset bounding box
            double oX = adfGeoTransform[0] + adfGeoTransform[1] * 0 + adfGeoTransform[2] * 0;
            double oY = adfGeoTransform[3] + adfGeoTransform[4] * 0 + adfGeoTransform[5] * 0;
            double eX = adfGeoTransform[0] + adfGeoTransform[1] * width + adfGeoTransform[2] * height;
            double eY = adfGeoTransform[3] + adfGeoTransform[4] * width + adfGeoTransform[5] * height;

            ///Transform to WGS84
            double[] extMinPT = new double[3] {
                oX, eY, 0
            };
            double[] extMaxPT = new double[3] {
                eX, oY, 0
            };
            coordTransform.TransformPoint(extMinPT);
            coordTransform.TransformPoint(extMaxPT);
            Point3d dsMin = new Point3d(extMinPT[0], extMinPT[1], extMinPT[2]);
            Point3d dsMax = new Point3d(extMaxPT[0], extMaxPT[1], extMaxPT[2]);

            Rectangle3d dsbox = new Rectangle3d(Plane.WorldXY, Heron.Convert.WGSToXYZ(dsMin), Heron.Convert.WGSToXYZ(dsMax));

            double pixelWidth  = dsbox.Width / width;
            double pixelHeight = dsbox.Height / height;

            ///Declare trees
            GH_Structure <GH_Point>   pointcloud = new GH_Structure <GH_Point>();
            GH_Structure <GH_Integer> rCount     = new GH_Structure <GH_Integer>();
            GH_Structure <GH_Integer> cCount     = new GH_Structure <GH_Integer>();
            GH_Structure <GH_Mesh>    tMesh      = new GH_Structure <GH_Mesh>();

            for (int i = 0; i < boundary.Count; i++)
            {
                GH_Path path = new GH_Path(i);

                Curve clippingBoundary = boundary[i];

                if (!clip)
                {
                    clippingBoundary = dsbox.ToNurbsCurve();
                }

                string clippedTopoFile = "/vsimem/topoclipped.tif";

                if (!(dsbox.BoundingBox.Contains(clippingBoundary.GetBoundingBox(true).Min) && (dsbox.BoundingBox.Contains(clippingBoundary.GetBoundingBox(true).Max))) && clip)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "One or more boundaries may be outside the bounds of the topo dataset.");
                }

                ///Offsets to mesh/boundary based on pixel size
                Point3d clipperMinPreAdd  = clippingBoundary.GetBoundingBox(true).Corner(true, false, true);
                Point3d clipperMinPostAdd = new Point3d(clipperMinPreAdd.X, clipperMinPreAdd.Y, clipperMinPreAdd.Z);
                Point3d clipperMin        = Heron.Convert.XYZToWGS(clipperMinPostAdd);

                Point3d clipperMaxPreAdd = clippingBoundary.GetBoundingBox(true).Corner(false, true, true);
                ///add/subtract pixel width if desired to get closer to boundary
                Point3d clipperMaxPostAdd = new Point3d();
                Point3d clipperMax        = new Point3d();
                if (clip)
                {
                    clipperMaxPostAdd = new Point3d(clipperMaxPreAdd.X + pixelWidth, clipperMaxPreAdd.Y - pixelHeight, clipperMaxPreAdd.Z);
                    clipperMax        = Heron.Convert.XYZToWGS(clipperMaxPostAdd);
                }
                else
                {
                    clipperMaxPostAdd = new Point3d(clipperMaxPreAdd.X, clipperMaxPreAdd.Y, clipperMaxPreAdd.Z);
                    clipperMax        = Heron.Convert.XYZToWGS(clipperMaxPostAdd);
                }


                double lonWest  = clipperMin.X;
                double lonEast  = clipperMax.X;
                double latNorth = clipperMin.Y;
                double latSouth = clipperMax.Y;

                var translateOptions = new[]
                {
                    "-of", "GTiff",
                    "-a_nodata", "0",
                    "-projwin_srs", "WGS84",
                    "-projwin", $"{lonWest}", $"{latNorth}", $"{lonEast}", $"{latSouth}"
                };

                using (Dataset clippedDataset = Gdal.wrapper_GDALTranslate(clippedTopoFile, datasource, new GDALTranslateOptions(translateOptions), null, null))
                {
                    Band band = clippedDataset.GetRasterBand(1);
                    width  = clippedDataset.RasterXSize;
                    height = clippedDataset.RasterYSize;
                    clippedDataset.GetGeoTransform(adfGeoTransform);
                    Gdal.InvGeoTransform(adfGeoTransform, invTransform);

                    rCount.Append(new GH_Integer(height), path);
                    cCount.Append(new GH_Integer(width), path);
                    Mesh           mesh  = new Mesh();
                    List <Point3d> verts = new List <Point3d>();
                    //var vertsParallel = new System.Collections.Concurrent.ConcurrentDictionary<double[][], Point3d>(Environment.ProcessorCount, ((Urow - 1) * (Lrow - 1)));

                    double[] bits = new double[width * height];
                    band.ReadRaster(0, 0, width, height, bits, width, height, 0, 0);

                    for (int col = 0; col < width; col++)
                    {
                        for (int row = 0; row < height; row++)
                        {
                            // equivalent to bits[col][row] if bits is 2-dimension array
                            double pixel = bits[col + row * width];
                            if (pixel < -10000)
                            {
                                pixel = 0;
                            }

                            double gcol = adfGeoTransform[0] + adfGeoTransform[1] * col + adfGeoTransform[2] * row;
                            double grow = adfGeoTransform[3] + adfGeoTransform[4] * col + adfGeoTransform[5] * row;

                            ///convert to WGS84
                            double[] wgsPT = new double[3] {
                                gcol, grow, pixel
                            };
                            coordTransform.TransformPoint(wgsPT);
                            Point3d pt = new Point3d(wgsPT[0], wgsPT[1], wgsPT[2]);

                            verts.Add(Heron.Convert.WGSToXYZ(pt));
                        }

                        /*Parallel.For(Urow, Lrow - 1, rowP =>
                         *  {
                         *      // equivalent to bits[col][row] if bits is 2-dimension array
                         *      double pixel = bits[col + rowP * width];
                         *      if (pixel < -10000)
                         *      {
                         *          pixel = 0;
                         *      }
                         *
                         *      double gcol = adfGeoTransform[0] + adfGeoTransform[1] * col + adfGeoTransform[2] * rowP;
                         *      double grow = adfGeoTransform[3] + adfGeoTransform[4] * col + adfGeoTransform[5] * rowP;
                         *
                         *      Point3d pt = new Point3d(gcol, grow, pixel);
                         *      vertsParallel[] = Heron.Convert.ToXYZ(pt);
                         *  });
                         * */
                    }

                    //Create meshes
                    //non Parallel
                    mesh.Vertices.AddVertices(verts);
                    //Parallel
                    //mesh.Vertices.AddVertices(vertsParallel.Values);

                    for (int u = 1; u < cCount[path][0].Value; u++)
                    {
                        for (int v = 1; v < rCount[path][0].Value; v++)
                        {
                            mesh.Faces.AddFace(v - 1 + (u - 1) * (height), v - 1 + u * (height), v - 1 + u * (height) + 1, v - 1 + (u - 1) * (height) + 1);
                            //(k - 1 + (j - 1) * num2, k - 1 + j * num2, k - 1 + j * num2 + 1, k - 1 + (j - 1) * num2 + 1)
                        }
                    }

                    //mesh.Flip(true, true, true);
                    tMesh.Append(new GH_Mesh(mesh), path);

                    band.Dispose();
                }
                Gdal.Unlink("/vsimem/topoclipped.tif");
            }

            datasource.Dispose();

            DA.SetDataTree(0, tMesh);
            DA.SetData(1, dsbox);
            DA.SetData(2, srcInfo);
        }
Example #5
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            ///TODO:    fix crash with "multi" types in a branch for shapefiles, can't create lines in a points layer
            ///         fix mesh/polygon face creation issue on sphere, dropping faces or flipped faces
            ///         fix swtich case for shapfiles so that points and multipoints (eg) are written to the same file. don't use switch anymore, us ifs
            ///         fix sql statements, they don't seem to have an effect.  Need these to work for pulling apart geometry collections.

            ///Gather GHA inputs
            string filename = string.Empty;

            DA.GetData <string>("Vector Data Filename", ref filename);

            string folder = string.Empty;

            DA.GetData <string>("Vector Data Folder", ref folder);
            folder = Path.GetFullPath(folder);
            if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                folder += Path.DirectorySeparatorChar;
            }

            string shpPath = folder + filename + drvExtension;
            ///for more than one geometry type, a list of files for shapefile output needs to be established
            List <string> shpPathList = new List <string>();
            List <string> shpTypeList = new List <string>();

            List <string> fields = new List <string>();

            DA.GetDataList <string>("Fields", fields);

            GH_Structure <GH_String> values = new GH_Structure <GH_String>();

            DA.GetDataTree <GH_String>("Values", out values);

            GH_Structure <IGH_GeometricGoo> gGoo = new GH_Structure <IGH_GeometricGoo>();

            DA.GetDataTree <IGH_GeometricGoo>("Feature Geometry", out gGoo);

            bool export = false;

            DA.GetData <bool>("Export", ref export);

            ///GDAL setup
            RESTful.GdalConfiguration.ConfigureOgr();
            OSGeo.GDAL.Gdal.SetConfigOption("OGR_SKIP", "KML");

            string driverType = drvType;

            //OSGeo.OGR.Driver drv = Ogr.GetDriverByName("LIBKML");// driverType);
            OSGeo.OGR.Driver drv = Ogr.GetDriverByName("GeoJSON");



            if (export == true)
            {
                ///File setup for save
                FileInfo file = new FileInfo(folder);
                file.Directory.Create();

                if (File.Exists(shpPath))
                {
                    drv.DeleteDataSource(shpPath);
                }

                ///Create virtual datasource to be converted later
                ///Using geojson as a flexiblle base file type which can be converted later with ogr2ogr
                DataSource ds = drv.CreateDataSource("/vsimem/out.geojson", null);

                ///Use WGS84 spatial reference
                OSGeo.OSR.SpatialReference dst = new OSGeo.OSR.SpatialReference("");
                dst.SetWellKnownGeogCS("WGS84");
                Transform transform = Heron.Convert.XYZToWGSTransform();

                ///Use OGR catch-all for geometry types
                var gtype = wkbGeometryType.wkbGeometryCollection;

                ///Create layer
                //string[] layerOptions = new string[] { "LIBKML_USE_SCHEMADATA=NO", "LIBKML_USE_SIMPLEFIELD=NO", "LIBKML_ALTITUDEMODE_FIELD=relativeToGround" };
                //string[] layerOptions = new string[] { "LIBKML_STRICT_COMPLIANCE=FALSE" };
                OSGeo.OGR.Layer layer = ds.CreateLayer(filename, dst, gtype, null);
                FeatureDefn     def   = layer.GetLayerDefn();

                ///Add fields to layer
                for (int f = 0; f < fields.Count; f++)
                {
                    OSGeo.OGR.FieldDefn fname = new OSGeo.OGR.FieldDefn(fields[f], OSGeo.OGR.FieldType.OFTString);
                    layer.CreateField(fname, f);
                }

                ///Specific fields for LIBKML for use in Google Earth
                ///See LIBMKL driver for more info https://gdal.org/drivers/vector/libkml.html
                if (drvType == "LIBKML")
                {
                    OSGeo.OGR.FieldDefn kmlFieldAltitudeMode = new OSGeo.OGR.FieldDefn("altitudeMode", OSGeo.OGR.FieldType.OFTString);
                    layer.CreateField(kmlFieldAltitudeMode, fields.Count());
                    //OSGeo.OGR.FieldDefn kmlFieldExtrude = new OSGeo.OGR.FieldDefn("tessellate", OSGeo.OGR.FieldType.OFTInteger);
                    //layer.CreateField(kmlFieldExtrude, fields.Count()+1);
                }


                for (int a = 0; a < gGoo.Branches.Count; a++)
                {
                    ///create feature
                    OSGeo.OGR.Feature feature = new OSGeo.OGR.Feature(def);

                    ///Set LIBKML specific fields for use in Google Earth, defaulting to 'relativeToGround'.  Consider setting to 'absolute'.
                    if (drvType == "LIBKML")
                    {
                        feature.SetField("altitudeMode", "relativeToGround");
                        //feature.SetField("altitudeMode", "absolute");
                        //feature.SetField("tessellate", 0);
                    }

                    ///TODO: Build style table
                    OSGeo.OGR.StyleTable styleTable = new StyleTable();
                    //feature.SetStyleString("BRUSH(fc:#0000FF);PEN(c:#000000)");

                    ///Get geometry type(s) in branch
                    var           geomList     = gGoo.Branches[a];
                    string        geomType     = string.Empty;
                    List <string> geomTypeList = geomList.Select(o => o.TypeName).ToList();
                    ///Test if geometry in the branch is of the same type.
                    ///If there is more than one element of a type, tag as multi, if there is more than one type, tag as mixed
                    if (geomTypeList.Count == 1)
                    {
                        geomType = geomTypeList.First();
                    }
                    else if (geomTypeList.Count > 1 && geomTypeList.All(gt => gt == geomTypeList.First()))
                    {
                        geomType = "Multi" + geomTypeList.First();
                    }

                    else
                    {
                        geomType = "Mixed";
                    }

                    ///For testing
                    //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, geomType);

                    ///Add geomtery to feature
                    ///Create containers for translating from GH Goo
                    Point3d        pt  = new Point3d();
                    List <Point3d> pts = new List <Point3d>();

                    Curve        crv  = null;
                    List <Curve> crvs = new List <Curve>();

                    Mesh mesh      = new Mesh();
                    Mesh multiMesh = new Mesh();

                    switch (geomType)
                    {
                    case "Point":
                        geomList.First().CastTo <Point3d>(out pt);
                        feature.SetGeometry(Heron.Convert.Point3dToOgrPoint(pt, transform));
                        if (!shpTypeList.Contains("POINT"))
                        {
                            shpTypeList.Add("POINT");
                        }
                        break;

                    case "MultiPoint":
                        foreach (var point in geomList)
                        {
                            point.CastTo <Point3d>(out pt);
                            pts.Add(pt);
                        }
                        feature.SetGeometry(Heron.Convert.Point3dsToOgrMultiPoint(pts, transform));
                        if (!shpTypeList.Contains("MULTIPOINT"))
                        {
                            shpTypeList.Add("MULTIPOINT");
                        }
                        break;

                    case "Curve":
                        geomList.First().CastTo <Curve>(out crv);
                        feature.SetGeometry(Heron.Convert.CurveToOgrLinestring(crv, transform));
                        if (!shpTypeList.Contains("LINESTRING"))
                        {
                            shpTypeList.Add("LINESTRING");
                        }
                        break;

                    case "MultiCurve":
                        foreach (var curve in geomList)
                        {
                            curve.CastTo <Curve>(out crv);
                            crvs.Add(crv);
                        }
                        feature.SetGeometry(Heron.Convert.CurvesToOgrMultiLinestring(crvs, transform));
                        if (!shpTypeList.Contains("MULTILINESTRING"))
                        {
                            shpTypeList.Add("MULTILINESTRING");
                        }
                        break;

                    case "Mesh":
                        geomList.First().CastTo <Mesh>(out mesh);
                        feature.SetGeometry(Heron.Convert.MeshToMultiPolygon(mesh, transform));
                        if (!shpTypeList.Contains("MULTIPOLYGON"))
                        {
                            shpTypeList.Add("MULTIPOLYGON");
                        }
                        break;

                    case "MultiMesh":
                        foreach (var m in geomList)
                        {
                            Mesh meshPart = new Mesh();
                            m.CastTo <Mesh>(out meshPart);
                            multiMesh.Append(meshPart);
                        }
                        feature.SetGeometry(Heron.Convert.MeshToMultiPolygon(multiMesh, transform));
                        if (!shpTypeList.Contains("MULTIPOLYGON"))
                        {
                            shpTypeList.Add("MULTIPOLYGON");
                        }
                        break;

                    case "Mixed":
                        OSGeo.OGR.Geometry geoCollection = new OSGeo.OGR.Geometry(wkbGeometryType.wkbGeometryCollection);
                        for (int gInt = 0; gInt < geomList.Count; gInt++)
                        {
                            string geomTypeMixed = geomTypeList[gInt];
                            switch (geomTypeMixed)
                            {
                            case "Point":
                                geomList[gInt].CastTo <Point3d>(out pt);
                                geoCollection.AddGeometry(Heron.Convert.Point3dToOgrPoint(pt, transform));
                                break;

                            case "Curve":
                                geomList[gInt].CastTo <Curve>(out crv);
                                geoCollection.AddGeometry(Heron.Convert.CurveToOgrLinestring(crv, transform));
                                break;

                            case "Mesh":
                                geomList[gInt].CastTo <Mesh>(out mesh);
                                geoCollection.AddGeometry(Ogr.ForceToMultiPolygon(Heron.Convert.MeshToMultiPolygon(mesh, transform)));
                                break;

                            default:
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Not able to export " + geomType + " geometry at branch " + gGoo.get_Path(a).ToString() +
                                                  ". Geometry must be a Point, Curve or Mesh.");
                                break;
                            }
                        }
                        feature.SetGeometry(geoCollection);
                        if (!shpTypeList.Contains("GEOMETRYCOLLECTION"))
                        {
                            shpTypeList.Add("GEOMETRYCOLLECTION");
                        }
                        break;

                    default:
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Not able to export " + geomType + " geometry at branch " + gGoo.get_Path(a).ToString() +
                                          ". Geometry must be a Point, Curve or Mesh.");
                        break;
                    }



                    ///Give the feature a unique ID
                    feature.SetFID(a);

                    ///Add values to fields
                    GH_Path path = gGoo.get_Path(a);

                    for (int vInt = 0; vInt < fields.Count; vInt++)
                    {
                        string val = string.Empty;
                        if (values.get_Branch(path) != null)
                        {
                            val = values.get_DataItem(path, vInt).ToString();
                        }
                        feature.SetField(fields[vInt], val);
                    }

                    ///Save feature to layer
                    layer.CreateFeature(feature);

                    ///Cleanup
                    feature.Dispose();
                }

                layer.Dispose();
                ds.Dispose();
                drv.Dispose();

                ///Convert in memory dataset to file using ogr2ogr
                ///For KML set 'altitudeMode' to 'relativeToGround' or 'absolute'

                ///Set base options for all export types
                if (drvType == "KML")
                {
                    drvType = "LIBKML";
                }
                List <string> ogr2ogrOptions = new List <string> {
                    "-overwrite",
                    "-f", drvType,
                    "-dim", "XYZ",
                    "-skipfailures",

                    //"-lco", "LIBKML_STRICT_COMPLIANCE=FALSE",
                    //"-lco", "AltitudeMode=absolute",

                    //"-dsco", "SHAPE_REWIND_ON_WRITE=YES"
                };

                Dataset src = Gdal.OpenEx("/vsimem/out.geojson", 0, null, null, null);

                if (drvType != "ESRI Shapefile")
                {
                    Dataset destDataset = Gdal.wrapper_GDALVectorTranslateDestName(shpPath, src, new GDALVectorTranslateOptions(ogr2ogrOptions.ToArray()), null, null);
                    destDataset.Dispose();
                    shpPathList.Add(shpPath);
                }

                ///Export multiple layers for shapefile
                ///https://trac.osgeo.org/gdal/wiki/FAQVector#HowdoItranslateamixedgeometryfiletoshapefileformat
                else
                {
                    ///
                    if (shpTypeList.Count <= 1 && shpTypeList.First() != "GEOMETRYCOLLECTION")
                    {
                        if (shpTypeList.First() == "POLYGON" || shpTypeList.First() == "MULTIPOLYGON")
                        {
                            ogr2ogrOptions.AddRange(new List <string> {
                                "-lco", "SHPT=MULTIPATCH"
                            });
                        }
                        Dataset destDataset = Gdal.wrapper_GDALVectorTranslateDestName(shpPath, src, new GDALVectorTranslateOptions(ogr2ogrOptions.ToArray()), null, null);
                        destDataset.Dispose();
                        shpPathList.Add(shpPath);
                    }

                    else
                    {
                        ///Add -explodecollections for mixed geometries in a branch
                        ///"-where" statement is not necessary, but could speed up big datasets

                        string        shpFileName       = string.Empty;
                        List <string> ogr2ogrShpOptions = new List <string>();

                        if (shpTypeList.Contains("POINT") || shpTypeList.Contains("MULTIPOINT"))
                        {
                            shpFileName = folder + filename + "_points.shp";
                            shpPathList.Add(shpFileName);
                            List <string> ogr2ogrShpOptionsPts = new List <string> {
                                "-overwrite",
                                "-f", drvType,
                                "-dim", "XYZ",
                                "-skipfailures"
                            };
                            //ogr2ogrShpOptionsPts.AddRange(new List<string> { "-where", "ogr_geometry=POINT", "-where", "ogr_geometry=MULTIPOINT", "-lco", "SHPT=MULTIPOINTZ", "-nlt", "PROMOTE_TO_MULTI"});
                            ogr2ogrShpOptionsPts.AddRange(new List <string> {
                                "-sql", "SELECT * FROM " + filename + " WHERE OGR_GEOMETRY='MULTIPOINT' OR OGR_GEOMETRY='POINT'", "-lco", "SHPT=MULTIPOINTZ", "-nlt", "PROMOTE_TO_MULTI"
                            });
                            //ogr2ogrShpOptionsPts.AddRange(new List<string> { "-dialect", "sqlite", "-sql", "select * from " + filename + " where GeometryType(geometry) in ('POINT','MULTIPOINT')", "-lco", "SHPT=MULTIPOINTZ", "-nlt", "PROMOTE_TO_MULTI" });

                            Dataset destDatasetPoint = Gdal.wrapper_GDALVectorTranslateDestName(shpFileName, src, new GDALVectorTranslateOptions(ogr2ogrShpOptionsPts.ToArray()), null, null);
                            destDatasetPoint.Dispose();
                        }

                        if (shpTypeList.Contains("LINESTRING") || shpTypeList.Contains("MULTILINESTRING"))
                        {
                            shpFileName = folder + filename + "_lines.shp";
                            shpPathList.Add(shpFileName);
                            List <string> ogr2ogrShpOptionsLines = new List <string> {
                                "-overwrite",
                                "-f", drvType,
                                "-dim", "XYZ",
                                "-skipfailures"
                            };
                            //ogr2ogrShpOptionsLines.AddRange(new List<string> { "-where", "ogr_geometry=LINESTRING25D", "-where", "ogr_geometry=MULTILINESTRING25D", "-lco", "SHPT=ARCZ", "-nlt", "PROMOTE_TO_MULTI" });
                            ogr2ogrShpOptionsLines.AddRange(new List <string> {
                                "-sql", "SELECT * FROM " + filename + " WHERE OGR_GEOMETRY='LINESTRING' OR OGR_GEOMETRY='MULTILINESTRING'", "-lco", "SHPT=ARCZ", "-nlt", "PROMOTE_TO_MULTI"
                            });
                            //ogr2ogrShpOptionsLines.AddRange(new List<string> { "-dialect", "sqlite", "-sql", "select * from " + filename + " where GeometryType(geometry) in ('LINESTRING','MULTILINESTRING')", "-lco", "SHPT=ARCZ", "-nlt", "PROMOTE_TO_MULTI" });

                            Dataset destDatasetLinestring = Gdal.wrapper_GDALVectorTranslateDestName(shpFileName, src, new GDALVectorTranslateOptions(ogr2ogrShpOptionsLines.ToArray()), null, null);
                            destDatasetLinestring.Dispose();
                        }

                        if (shpTypeList.Contains("POLYGON") || shpTypeList.Contains("MULTIPOLYGON"))
                        {
                            shpFileName = folder + filename + "_polygons.shp";
                            shpPathList.Add(shpFileName);
                            List <string> ogr2ogrShpOptionsPolygons = new List <string> {
                                "-overwrite",
                                "-f", drvType,
                                "-dim", "XYZ",
                                "-skipfailures",
                                "-dsco", "SHAPE_REWIND_ON_WRITE=NO"
                            };
                            //ogr2ogrShpOptionsPolygons.AddRange(new List<string> { "-where", "ogr_geometry=POLYGON", "-where", "ogr_geometry=MULTIPOLYGON", "-lco", "SHPT=POLYGONZ", "-nlt", "PROMOTE_TO_MULTI" });
                            ogr2ogrShpOptionsPolygons.AddRange(new List <string> {
                                "-sql", "SELECT * FROM " + filename + " WHERE OGR_GEOMETRY='MULTIPOLYGON25D' OR OGR_GEOMETRY='POLYGON25D'", "-lco", "SHPT=POLYGONZ", "-nlt", "PROMOTE_TO_MULTI"
                            });
                            Dataset destDatasetPolygon = Gdal.wrapper_GDALVectorTranslateDestName(shpFileName, src, new GDALVectorTranslateOptions(ogr2ogrShpOptionsPolygons.ToArray()), null, null);
                            destDatasetPolygon.Dispose();
                        }

                        ///Not working properly when multiple geometry types are part of the same branch for SHP export.
                        if (shpTypeList.Contains("GEOMETRYCOLLECTION"))
                        {
                            AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "One or more branches contain a mix of geometry types.");
                            ///export points
                            shpFileName = folder + filename + "_gc-points.shp";
                            shpPathList.Add(shpFileName);
                            List <string> ogr2ogrShpOptionsGCPts = new List <string> {
                                "-overwrite",
                                "-f", drvType,
                                "-dim", "XYZ",
                                "-skipfailures"
                            };
                            ogr2ogrShpOptionsGCPts.AddRange(new List <string> {
                                "-explodecollections", "-where", "ogr_geometry=GEOMETRYCOLLECTION", "-lco", "SHPT=MULTIPOINTZ", "-nlt", "PROMOTE_TO_MULTI"
                            });
                            //ogr2ogrShpOptionsGCPts.AddRange(new List<string> { "-explodecollections", "-sql", "SELECT * FROM " + filename + " WHERE OGR_GEOMETRY='MULTIPOINT' OR OGR_GEOMETRY='POINT'", "-lco", "SHPT=MULTIPOINTZ", "-nlt", "PROMOTE_TO_MULTI" });

                            Dataset destDatasetGCPoints = Gdal.wrapper_GDALVectorTranslateDestName(shpFileName, src, new GDALVectorTranslateOptions(ogr2ogrShpOptionsGCPts.ToArray()), null, null);
                            destDatasetGCPoints.Dispose();

                            ///export lines
                            shpFileName = folder + filename + "_gc-lines.shp";
                            shpPathList.Add(shpFileName);
                            List <string> ogr2ogrShpOptionsGCLines = new List <string> {
                                "-overwrite",
                                "-f", drvType,
                                "-dim", "XYZ",
                                "-skipfailures"
                            };
                            ogr2ogrShpOptionsGCLines.AddRange(new List <string> {
                                "-explodecollections", "-where", "ogr_geometry=GEOMETRYCOLLECTION", "-lco", "SHPT=ARCZ", "-nlt", "PROMOTE_TO_MULTI"
                            });
                            //ogr2ogrShpOptionsGCLines.AddRange(new List<string> { "-explodecollections", "-sql", "SELECT * FROM " + filename + " WHERE OGR_GEOMETRY='MULTILINESTRING25D' OR OGR_GEOMETRY='LINESTRING25D'", "-lco", "SHPT=ARCZ", "-nlt", "PROMOTE_TO_MULTI" });
                            Dataset destDatasetGCLines = Gdal.wrapper_GDALVectorTranslateDestName(shpFileName, src, new GDALVectorTranslateOptions(ogr2ogrShpOptionsGCLines.ToArray()), null, null);
                            destDatasetGCLines.Dispose();

                            ///export meshes
                            shpFileName = folder + filename + "_gc-polygons.shp";
                            shpPathList.Add(shpFileName);
                            List <string> ogr2ogrShpOptionsGCPolygons = new List <string> {
                                "-overwrite",
                                "-f", drvType,
                                "-dim", "XYZ",
                                "-skipfailures",
                                "-dsco", "SHAPE_REWIND_ON_WRITE=NO"
                            };
                            ogr2ogrShpOptionsGCPolygons.AddRange(new List <string> {
                                "-explodecollections", "-where", "ogr_geometry=GEOMETRYCOLLECTION", "-lco", "SHPT=POLYGONZ", "-nlt", "PROMOTE_TO_MULTI"
                            });
                            //ogr2ogrShpOptionsGCPolygons.AddRange(new List<string> { "-explodecollections", "-sql", "SELECT * FROM " + filename + " WHERE OGR_GEOMETRY='MULTIPOLYGON' OR OGR_GEOMETRY='POLYGON'", "-lco", "SHPT=POLYGONZ", "-nlt", "PROMOTE_TO_MULTI" });
                            Dataset destDatasetGCPolygons = Gdal.wrapper_GDALVectorTranslateDestName(shpFileName, src, new GDALVectorTranslateOptions(ogr2ogrShpOptionsGCPolygons.ToArray()), null, null);
                            destDatasetGCPolygons.Dispose();
                        }
                    }
                }

                ///Clean up
                Gdal.Unlink("/vsimem/out.geojson");
            }

            DA.SetDataList(0, shpPathList);
        }