public static OSGeo.OGR.Geometry Point3dsToOgrMultiPoint(List <Point3d> points) { OSGeo.OGR.Geometry ogrPoints = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiPoint); foreach (Point3d point in points) { ogrPoints.AddGeometry(Heron.Convert.Point3dToOgrPoint(point)); } return(ogrPoints); }
public static OSGeo.OGR.Geometry CurveToOgrPolygon(Curve curve) { OSGeo.OGR.Geometry polygon = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPolygon); Polyline pL = new Polyline(); curve.TryGetPolyline(out pL); polygon.AddGeometry(Heron.Convert.CurveToOgrRing(curve)); return(polygon); }
public static OSGeo.OGR.Geometry ToOgrPolygon(this IEnumerable <ICoordinate> coordinates) { OSGeo.OGR.Geometry geometry = null; OSGeo.OGR.Geometry ring = GetOgrGeometry(wkbGeometryType.wkbLinearRing, coordinates); if (ring != null) { geometry = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPolygon); geometry.AddGeometry(ring); } return(geometry); }
public static OSGeo.OGR.Geometry CurvesToOgrPolygon(List <Curve> curves) { OSGeo.OGR.Geometry polygon = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPolygon); foreach (Curve curve in curves) { Polyline pL = new Polyline(); curve.TryGetPolyline(out pL); polygon.AddGeometry(Heron.Convert.CurveToOgrRing(curve)); } return(polygon); }
public static OSGeo.OGR.Geometry CurvesToOgrMultiLinestring(List <Curve> curves) { OSGeo.OGR.Geometry multilinestring = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiLineString); foreach (Curve curve in curves) { Polyline pL = new Polyline(); curve.TryGetPolyline(out pL); multilinestring.AddGeometry(Heron.Convert.CurveToOgrLinestring(curve)); } return(multilinestring); }
/// <summary> /// 三点夹角的判定条件,输出为满足条件的成员的ID所组成的ID数组 /// </summary> /// <param name="aFeat"></param> /// <returns></returns> private static OSGeo.OGR.Geometry JID(Point[] aFeat, double userSet, int seleTime) { List <Point[]> pjGroupL = new List <Point[]>(); List <Point[]> zjGroupL = new List <Point[]>(); List <Point> pjGroup = new List <Point>(); List <Point> zjGroup = new List <Point>(); for (int i = 0; i < aFeat.Length; i++) { int frontId, thisId, backId; bool[] yon = new bool[seleTime]; for (int t = 1; t <= seleTime; t++) { frontId = i < t ? aFeat.Length - 1 + i - t : i - t; thisId = i; backId = i > aFeat.Length - 1 - t ? i - (aFeat.Length - 1) + t : backId = i + t; double jiaodu = cosCalculator(aFeat[frontId], aFeat[thisId], aFeat[backId]); yon[t - 1] = jiaodu > userSet; } if (yon.Contains(true)) { pjGroup.Add(aFeat[i]); } else { zjGroup.Add(aFeat[i]); } } OSGeo.OGR.Geometry outGeom = new OSGeo.OGR.Geometry(OSGeo.OGR.wkbGeometryType.wkbPolygon); OSGeo.OGR.Geometry subGeom = new OSGeo.OGR.Geometry(OSGeo.OGR.wkbGeometryType.wkbLinearRing); for (int g = 0; g < zjGroup.Count(); g++) { Point a = zjGroup[g]; subGeom.AddPoint(a.X, a.Y, a.Z); } if (subGeom.GetPointCount() < 4) { return(null); } subGeom.CloseRings(); outGeom.AddGeometry(subGeom); return(outGeom); }
public static OSGeo.OGR.Geometry ToGeometry(this Envelope envelope) { var ring = new OSGeo.OGR.Geometry(wkbGeometryType.wkbLinearRing); ring.AddPoint_2D(envelope.MinX, envelope.MinY); ring.AddPoint_2D(envelope.MaxX, envelope.MinY); ring.AddPoint_2D(envelope.MaxX, envelope.MaxY); ring.AddPoint_2D(envelope.MinX, envelope.MaxY); ring.CloseRings(); var polygon = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPolygon); polygon.AddGeometry(ring); return(polygon); }
public static OSGeo.OGR.Geometry MeshesToMultiPolygon(List <Mesh> meshes, Transform transform) { //OSGeo.OGR.Geometry ogrMultiPolygon = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiPolygon25D); OSGeo.OGR.Geometry ogrMultiPolygon = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiSurfaceZ); Mesh m = new Mesh(); foreach (var mesh in meshes) { m.Append(mesh); //ogrMultiPolygon.AddGeometry(Heron.Convert.MeshToMultiPolygon(mesh, transform)); } ogrMultiPolygon.AddGeometry(Heron.Convert.MeshToMultiPolygon(m, transform)); return(ogrMultiPolygon); }
public static OSGeo.OGR.Geometry ToOgrPolygon(this IEnumerable <IEnumerable <ICoordinate> > ringList) { OSGeo.OGR.Geometry geometry = null; if (ringList?.Any() == true) { geometry = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPolygon); foreach (var ring in ringList) { var ogrRing = GetOgrGeometry(wkbGeometryType.wkbLinearRing, ring); if (ogrRing == null) { return(null); } geometry.AddGeometry(ogrRing); } } return(geometry); }
public static OSGeo.OGR.Geometry MeshToMultiPolygon(Mesh mesh, Transform transform) { //OSGeo.OGR.Geometry ogrMultiPolygon = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiPolygon25D); OSGeo.OGR.Geometry ogrMultiPolygon = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiSurfaceZ); foreach (var face in mesh.GetNgonAndFacesEnumerable()) { Polyline pL = new Polyline(); foreach (var index in face.BoundaryVertexIndexList()) { pL.Add(mesh.Vertices.Point3dAt(System.Convert.ToInt32(index))); } ogrMultiPolygon.AddGeometry(Heron.Convert.CurveToOgrPolygon(pL.ToNurbsCurve(), transform)); } return(ogrMultiPolygon); }
/// <summary> /// 转换是否纠偏,只使用与火星坐标纠偏 /// </summary> /// <param name="dataTable">数据表,如果是点表中含X,Y字段,如果是线和面,表中含有PATH字段</param> /// <param name="filePath">存储路径</param> /// <param name="geoType">数据类型,暂时支持简单的点线面</param> /// <param name="jiupian">是否纠偏[火星坐标转84坐标]</param> public static void SaveShpFile(DataTable dataTable, string filePath, wkbGeometryType geoType, ProjectConvert jiupian) { if (geoType == wkbGeometryType.wkbLineString || geoType == wkbGeometryType.wkbPolygon) { if (!dataTable.Columns.Contains("PATH")) { return; } } else if (geoType == wkbGeometryType.wkbPoint) { if (!dataTable.Columns.Contains("X") || !dataTable.Columns.Contains("Y")) { return; } } else { return; } // 为了支持中文路径,请添加下面这句代码 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); // 为了使属性表字段支持中文,请添加下面这句 OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", ""); string strVectorFile = filePath; // 注册所有的驱动 Ogr.RegisterAll(); //创建数据,这里以创建ESRI的shp文件为例 string strDriverName = "ESRI Shapefile"; int count = Ogr.GetDriverCount(); Driver oDriver = Ogr.GetDriverByName(strDriverName); if (oDriver == null) { log.ErrorFormat("{0}驱动不可用!\n", strVectorFile); Console.WriteLine("{0}驱动不可用!\n", strVectorFile); return; } // 创建数据源 DataSource oDS = oDriver.CreateDataSource(strVectorFile, null); if (oDS == null) { log.ErrorFormat("创建矢量文件{0}失败!\n", strVectorFile); Console.WriteLine("创建矢量文件【%s】失败!\n", strVectorFile); return; } string strwkt = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"; OSGeo.OSR.SpatialReference srs = new OSGeo.OSR.SpatialReference(strwkt); // 创建图层,创建一个多边形图层,这里没有指定空间参考,如果需要的话,需要在这里进行指定 Layer oLayer = oDS.CreateLayer("test", null, geoType, null); if (oLayer == null) { Console.WriteLine("图层创建失败!\n"); return; } for (int i = 0; i < dataTable.Columns.Count; i++) { if (dataTable.Columns[i].ColumnName == "PATH") { continue; } string columnName = dataTable.Columns[i].ColumnName; FieldDefn oFieldName = new FieldDefn(columnName, FieldType.OFTString); oFieldName.SetWidth(255); oLayer.CreateField(oFieldName, 1); } FeatureDefn oDefn = oLayer.GetLayerDefn(); foreach (DataRow row in dataTable.Rows) { if ((geoType == wkbGeometryType.wkbPolygon || geoType == wkbGeometryType.wkbLineString) && string.IsNullOrEmpty(row["PATH"].ToString())) { continue; } // 创建Multi要素 Feature oFeatureMulty = new Feature(oDefn); for (int i = 0; i < dataTable.Columns.Count; i++) { if (geoType == wkbGeometryType.wkbPolygon || geoType == wkbGeometryType.wkbLineString) { if (dataTable.Columns[i].ColumnName == "PATH") { continue; } } string name = row[i] != null ? row[i].ToString() : ""; if (!string.IsNullOrEmpty(name)) { try { //oFeatureMulty.SetField(dataTable.Columns[i].ColumnName,name); var value = name.Trim().Replace("'", "").Replace(",", ""); if (value.Length > 255) { value = value.Substring(0, 250); } oFeatureMulty.SetField(i, value); } catch (Exception ex) { Console.WriteLine(ex); } } } if (geoType == wkbGeometryType.wkbPolygon || geoType == wkbGeometryType.wkbLineString) { string path = row["PATH"] != null ? row["PATH"].ToString() : ""; if (string.IsNullOrEmpty(path)) { continue; } var geoCount = path.Split('|').Length; wkbGeometryType newGeometryType = geoType; OSGeo.OGR.Geometry geo1 = new OSGeo.OGR.Geometry(geoType); if (geoType == wkbGeometryType.wkbPolygon) { if (geoCount > 1) { geo1 = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiPolygon); for (int i = 0; i < geoCount; i++) { var temp = path.Split('|')[i]; var points = temp.Split(';'); OSGeo.OGR.Geometry innGeometry = new Geometry(wkbGeometryType.wkbLinearRing); for (int j = 0; j < points.Length; j++) { var c = ProjectChange(points[j], jiupian); innGeometry.AddPoint_2D(c.lon, c.lat); } var polygon = new Geometry(wkbGeometryType.wkbPolygon); polygon.AddGeometry(innGeometry); geo1.AddGeometry(polygon); } } else { geo1 = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPolygon); for (int i = 0; i < geoCount; i++) { var temp = path.Split('|')[i]; var points = temp.Split(';'); OSGeo.OGR.Geometry innGeometry = new Geometry(wkbGeometryType.wkbLinearRing); for (int j = 0; j < points.Length; j++) { var c = ProjectChange(points[j], jiupian); innGeometry.AddPoint_2D(c.lon, c.lat); } geo1.AddGeometry(innGeometry); } } } else { if (geoCount > 1) { geo1 = new OSGeo.OGR.Geometry(wkbGeometryType.wkbMultiLineString); for (int i = 0; i < geoCount; i++) { var temp = path.Split('|')[i]; var points = temp.Split(';'); OSGeo.OGR.Geometry innGeometry = new Geometry(wkbGeometryType.wkbLinearRing); for (int j = 0; j < points.Length; j++) { var c = ProjectChange(points[j], jiupian); innGeometry.AddPoint_2D(c.lon, c.lat); } geo1.AddGeometry(innGeometry); } } else { for (int i = 0; i < geoCount; i++) { var temp = path.Split('|')[i]; var points = temp.Split(';'); geo1 = new OSGeo.OGR.Geometry(wkbGeometryType.wkbLinearRing); for (int j = 0; j < points.Length; j++) { var c = ProjectChange(points[j], jiupian); geo1.AddPoint_2D(c.lon, c.lat); } } } } //if (geoType == wkbGeometryType.wkbLineString) //{ // for (int i = 0; i < ps.Length; i++) // { // var c = ProjectChange(ps[i], jiupian); // geo1.AddPoint_2D(c.lon, c.lat); // } //} //else if (geoType == wkbGeometryType.wkbPolygon) //{ // List<int> indexs = new List<int>(); // indexs.Add(0); // for (int i = 0; i < ps.Length; i++) // { // if (ps[i].Split('|', ',').Length > 2) // { // indexs.Add(i); // } // } // indexs.Add(ps.Length - 1); // if (indexs.Count == 2) // { // OSGeo.OGR.Geometry outGeo = new OSGeo.OGR.Geometry(OSGeo.OGR.wkbGeometryType.wkbLinearRing); // for (int i = 0; i < ps.Length; i++) // { // var c = ProjectChange(ps[i], jiupian); // outGeo.AddPoint_2D(c.lon, c.lat); // } // var c1 = ProjectChange(ps[0], jiupian); // outGeo.AddPoint_2D(c1.lon, c1.lat); // geo1.AddGeometryDirectly(outGeo); // } // else // { // for (int j = 0; j < indexs.Count - 1; j++) // { // OSGeo.OGR.Geometry outGeo = new OSGeo.OGR.Geometry(OSGeo.OGR.wkbGeometryType.wkbLinearRing); // Coord sc = new Coord(); // int first = indexs[j]; // int end = indexs[j + 1]; // for (int i = first; i < end + 1; i++) // { // if (i == first && first != 0) // { // var c = ProjectChange(ps[i], jiupian); // outGeo.AddPoint(c.lon, c.lat,0); // } // else // { // if (jiupian != ProjectConvert.NONE) // { // var c = ProjectChange(ps[i], jiupian); // outGeo.AddPoint(c.lon, c.lat,0); // } // else // { // double x = double.Parse(ps[i].Split('|', ',')[0]); // double y = double.Parse(ps[i].Split('|', ',')[1]); // if (i == first) // { // sc.lon = x; // sc.lat = y; // } // outGeo.AddPoint(x, y, 0); // } // } // } // outGeo.AddPoint(sc.lon, sc.lat, 0); // geo1.AddGeometryDirectly(outGeo); // } // } //} oFeatureMulty.SetGeometry(geo1); } else if (geoType == wkbGeometryType.wkbPoint) { OSGeo.OGR.Geometry geo1 = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPoint); string xstring = row["X"] != null ? row["X"].ToString() : ""; string ystring = row["Y"] != null ? row["Y"].ToString() : ""; double x = double.Parse(xstring); double y = double.Parse(ystring); Coord c = CoordHelper.Gcj2Wgs(x, y); geo1.AddPoint(c.lon, c.lat, 0); oFeatureMulty.SetGeometry(geo1); } oLayer.CreateFeature(oFeatureMulty); } oLayer.Dispose(); oDS.Dispose(); }
/// <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) { GH_Structure <IGH_GeometricGoo> gGoo = new GH_Structure <IGH_GeometricGoo>(); DA.GetDataTree <IGH_GeometricGoo>("Feature Geometry", out gGoo); GH_Structure <GH_Number> bufferInt = new GH_Structure <GH_Number>(); DA.GetDataTree <GH_Number>("Buffer Distance", out bufferInt); GH_Structure <IGH_GeometricGoo> gGooBuffered = new GH_Structure <IGH_GeometricGoo>(); ///GDAL setup RESTful.GdalConfiguration.ConfigureOgr(); ///Use WGS84 spatial reference OSGeo.OSR.SpatialReference dst = new OSGeo.OSR.SpatialReference(""); dst.SetWellKnownGeogCS("WGS84"); Transform transform = new Transform(1); // Heron.Convert.XYZToWGSTransform(); Transform revTransform = new Transform(1); //Heron.Convert.WGSToXYZTransform(); ///Create virtual datasource to be converted later ///Using geojson as a flexiblle base file type which can be converted later with ogr2ogr OSGeo.OGR.Driver drv = Ogr.GetDriverByName("GeoJSON"); DataSource ds = drv.CreateDataSource("/vsimem/out.geojson", null); ///Use OGR catch-all for geometry types var gtype = wkbGeometryType.wkbGeometryCollection; ///Create layer OSGeo.OGR.Layer layer = ds.CreateLayer("temp", dst, gtype, null); FeatureDefn def = layer.GetLayerDefn(); var branchPaths = gGoo.Paths; for (int a = 0; a < gGoo.Branches.Count; a++) { ///create feature OSGeo.OGR.Feature feature = new OSGeo.OGR.Feature(def); ///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"; } //var buffList = bufferInt.Branches[a]; var buffList = new List <GH_Number>(); //var path = new GH_Path(a); var path = branchPaths[a]; if (path.Valid) { buffList = (List <GH_Number>)bufferInt.get_Branch(path); } else { buffList = bufferInt.Branches[0]; } int buffIndex = 0; double buffDist = 0; GH_Convert.ToDouble(buffList[buffIndex], out buffDist, GH_Conversion.Primary); ///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(); int quadsecs = 10; switch (geomType) { case "Point": geomList.First().CastTo <Point3d>(out pt); var bufferPt = Heron.Convert.Point3dToOgrPoint(pt, transform).Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferPt, revTransform), new GH_Path(a)); break; case "MultiPoint": foreach (var point in geomList) { point.CastTo <Point3d>(out pt); pts.Add(pt); } var bufferPts = Heron.Convert.Point3dsToOgrMultiPoint(pts, transform).Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferPts, revTransform), new GH_Path(a)); break; case "Curve": geomList.First().CastTo <Curve>(out crv); var bufferCrv = Heron.Convert.CurveToOgrLinestring(crv, transform).Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferCrv, revTransform), new GH_Path(a)); break; case "MultiCurve": bool allClosed = true; foreach (var curve in geomList) { curve.CastTo <Curve>(out crv); if (!crv.IsClosed) { allClosed = false; } crvs.Add(crv); } if (allClosed) { var bufferCrvs = Heron.Convert.CurvesToOgrPolygon(crvs, transform).Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferCrvs, revTransform), new GH_Path(a)); } else { var bufferCrvs = Heron.Convert.CurvesToOgrMultiLinestring(crvs, transform).Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferCrvs, revTransform), new GH_Path(a)); } break; case "Mesh": geomList.First().CastTo <Mesh>(out mesh); mesh.Ngons.AddPlanarNgons(DocumentTolerance()); var bufferPoly = Ogr.ForceToMultiPolygon(Heron.Convert.MeshToMultiPolygon(mesh, transform)).Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferPoly, revTransform), new GH_Path(a)); break; case "MultiMesh": foreach (var m in geomList) { Mesh meshPart = new Mesh(); m.CastTo <Mesh>(out meshPart); meshPart.Ngons.AddPlanarNgons(DocumentTolerance()); multiMesh.Append(meshPart); } var bufferPolys = Ogr.ForceToMultiPolygon(Heron.Convert.MeshToMultiPolygon(multiMesh, transform)).Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferPolys, revTransform), new GH_Path(a)); 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; } } var bufferCol = geoCollection.Buffer(buffDist, quadsecs); gGooBuffered.AppendRange(Heron.Convert.OgrGeomToGHGoo(bufferCol, revTransform), new GH_Path(a)); 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; } } def.Dispose(); layer.Dispose(); ds.Dispose(); DA.SetDataTree(0, gGooBuffered); }
/// <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); }