public static Transform GetUserSRSToModelTransform(OSGeo.OSR.SpatialReference userSRS) { ///TODO: Check what units the userSRS is in and coordinate with the scaling function. Currently only accounts for a userSRS in meters. ///TODO: translate or scale GCS (decimal degrees) to something like a Projectected Coordinate System. Need to go dd to xy ///transform rhino EAP from rhinoSRS to userSRS double eapLat = EarthAnchorPoint.EarthBasepointLatitude; double eapLon = EarthAnchorPoint.EarthBasepointLongitude; double eapElev = EarthAnchorPoint.EarthBasepointElevation; Plane eapPlane = EarthAnchorPoint.GetEarthAnchorPlane(out Vector3d eapNorth); OSGeo.OSR.SpatialReference rhinoSRS = new OSGeo.OSR.SpatialReference(""); rhinoSRS.SetWellKnownGeogCS("WGS84"); OSGeo.OSR.CoordinateTransformation coordTransform = new OSGeo.OSR.CoordinateTransformation(rhinoSRS, userSRS); OSGeo.OGR.Geometry userAnchorPointDD = Heron.Convert.Point3dToOgrPoint(new Point3d(eapLon, eapLat, eapElev)); Transform t = new Transform(1.0); userAnchorPointDD.Transform(coordTransform); Point3d userAnchorPointPT = Heron.Convert.OgrPointToPoint3d(userAnchorPointDD, t); ///setup userAnchorPoint plane for move and rotation double eapLatNorth = EarthAnchorPoint.EarthBasepointLatitude + 0.5; double eapLonEast = EarthAnchorPoint.EarthBasepointLongitude + 0.5; OSGeo.OGR.Geometry userAnchorPointDDNorth = Heron.Convert.Point3dToOgrPoint(new Point3d(eapLon, eapLatNorth, eapElev)); OSGeo.OGR.Geometry userAnchorPointDDEast = Heron.Convert.Point3dToOgrPoint(new Point3d(eapLonEast, eapLat, eapElev)); userAnchorPointDDNorth.Transform(coordTransform); userAnchorPointDDEast.Transform(coordTransform); Point3d userAnchorPointPTNorth = Heron.Convert.OgrPointToPoint3d(userAnchorPointDDNorth, t); Point3d userAnchorPointPTEast = Heron.Convert.OgrPointToPoint3d(userAnchorPointDDEast, t); Vector3d userAnchorNorthVec = userAnchorPointPTNorth - userAnchorPointPT; Vector3d userAnchorEastVec = userAnchorPointPTEast - userAnchorPointPT; Plane userEapPlane = new Plane(userAnchorPointPT, userAnchorEastVec, userAnchorNorthVec); ///shift (move and rotate) from userSRS EAP to 0,0 based on SRS north direction Transform scale = Transform.Scale(new Point3d(0.0, 0.0, 0.0), (1 / Rhino.RhinoMath.UnitScale(Rhino.RhinoDoc.ActiveDoc.ModelUnitSystem, Rhino.UnitSystem.Meters))); if (userSRS.GetLinearUnitsName().ToUpper().Contains("FEET") || userSRS.GetLinearUnitsName().ToUpper().Contains("FOOT")) { scale = Transform.Scale(new Point3d(0.0, 0.0, 0.0), (1 / Rhino.RhinoMath.UnitScale(Rhino.RhinoDoc.ActiveDoc.ModelUnitSystem, Rhino.UnitSystem.Feet))); } ///if SRS is geographic (ie WGS84) use Rhino's internal projection ///this is still buggy as it doesn't work with other geographic systems like NAD27 if ((userSRS.IsProjected() == 0) && (userSRS.IsLocal() == 0)) { userEapPlane.Transform(WGSToXYZTransform()); scale = WGSToXYZTransform(); } Transform shift = Transform.ChangeBasis(eapPlane, userEapPlane); Transform shiftScale = Transform.Multiply(scale, shift); return(shiftScale); }
protected override void SolveInstance(IGH_DataAccess DA) { ///Gather GHA inputs List <Curve> boundary = new List <Curve>(); DA.GetDataList <Curve>("Boundary", boundary); string shpFilePath = string.Empty; DA.GetData <string>("Vector Data Location", ref shpFilePath); bool cropIt = true; DA.GetData <Boolean>("Crop file", ref cropIt); string userSRStext = "WGS84"; DA.GetData <string>(2, ref userSRStext); ///GDAL setup ///Some preliminary testing has been done to read SHP, GeoJSON, OSM, KML, MVT, GML and GDB ///It can be spotty with KML, MVT and GML and doesn't throw informative errors. Likely has to do with getting a valid CRS and ///TODO: resolve errors with reading KML, MVT, GML. DataSource dataSource = CreateDataSource(shpFilePath); List <Layer> layerSet = GetLayers(dataSource); ///Declare trees GH_Structure <GH_Rectangle> recs = new GH_Structure <GH_Rectangle>(); GH_Structure <GH_String> spatialReferences = new GH_Structure <GH_String>(); GH_Structure <GH_String> fnames = new GH_Structure <GH_String>(); GH_Structure <GH_String> fset = new GH_Structure <GH_String>(); GH_Structure <GH_Point> gset = new GH_Structure <GH_Point>(); GH_Structure <GH_Point> gsetUser = new GH_Structure <GH_Point>(); GH_Structure <GH_Rectangle> recsUser = new GH_Structure <GH_Rectangle>(); GH_Structure <GH_String> gtype = new GH_Structure <GH_String>(); GH_Structure <IGH_GeometricGoo> gGoo = new GH_Structure <IGH_GeometricGoo>(); ///Loop through each layer. Layers usually occur in Geodatabase GDB format. SHP usually has only one layer. for (int iLayer = 0; iLayer < dataSource.GetLayerCount(); iLayer++) { OSGeo.OGR.Layer layer = dataSource.GetLayerByIndex(iLayer); if (layer == null) { Console.WriteLine($"Couldn't fetch advertised layer {iLayer}"); System.Environment.Exit(-1); } long count = layer.GetFeatureCount(1); int featureCount = System.Convert.ToInt32(count); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, $"Layer #{iLayer} {layer.GetName()} has {featureCount} features"); ///Get the spatial reference of the input vector file and set to WGS84 if not known /// OSGeo.OSR.SpatialReference sourceSRS = new SpatialReference(Osr.SRS_WKT_WGS84); string spatialReference = GetSpatialReference(layer, iLayer, dataSource, sourceSRS); spatialReferences.Append(new GH_String(spatialReference), new GH_Path(iLayer)); ///Set transform from input spatial reference to Rhino spatial reference ///TODO: look into adding a step for transforming to CRS set in SetCRS OSGeo.OSR.SpatialReference rhinoSRS = new OSGeo.OSR.SpatialReference(""); rhinoSRS.SetWellKnownGeogCS("WGS84"); ///TODO: verify the userSRS is valid ///TODO: use this as override of global SetSRS OSGeo.OSR.SpatialReference userSRS = new OSGeo.OSR.SpatialReference(""); userSRS.SetFromUserInput(userSRStext); ///These transforms move and scale in order to go from userSRS to XYZ and vice versa Transform userSRSToModelTransform = Heron.Convert.GetUserSRSToModelTransform(userSRS); Transform modelToUserSRSTransform = Heron.Convert.GetModelToUserSRSTransform(userSRS); Transform sourceToModelSRSTransform = Heron.Convert.GetUserSRSToModelTransform(sourceSRS); Transform modelToSourceSRSTransform = Heron.Convert.GetModelToUserSRSTransform(sourceSRS); ///Get OGR envelope of the data in the layer in the sourceSRS OSGeo.OGR.Envelope ext = new OSGeo.OGR.Envelope(); layer.GetExtent(ext, 1); OSGeo.OGR.Geometry extMinSourceOgr = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPoint); extMinSourceOgr.AddPoint(ext.MinX, ext.MinY, 0.0); extMinSourceOgr.AssignSpatialReference(sourceSRS); OSGeo.OGR.Geometry extMaxSourceOgr = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPoint); extMaxSourceOgr.AddPoint(ext.MaxX, ext.MaxY, 0.0); extMaxSourceOgr.AssignSpatialReference(sourceSRS); ///Get extents in Rhino SRS Point3d extPTmin = Heron.Convert.OgrPointToPoint3d(extMinSourceOgr, sourceToModelSRSTransform); Point3d extPTmax = Heron.Convert.OgrPointToPoint3d(extMaxSourceOgr, sourceToModelSRSTransform); Rectangle3d rec = new Rectangle3d(Plane.WorldXY, extPTmin, extPTmax); recs.Append(new GH_Rectangle(rec), new GH_Path(iLayer)); ///Get extents in userSRS ///Can give odd results if crosses 180 longitude extMinSourceOgr.TransformTo(userSRS); extMaxSourceOgr.TransformTo(userSRS); Point3d extPTminUser = Heron.Convert.OgrPointToPoint3d(extMinSourceOgr, userSRSToModelTransform); Point3d extPTmaxUser = Heron.Convert.OgrPointToPoint3d(extMaxSourceOgr, userSRSToModelTransform); Rectangle3d recUser = new Rectangle3d(Plane.WorldXY, extPTminUser, extPTmaxUser); recsUser.Append(new GH_Rectangle(recUser), new GH_Path(iLayer)); if (boundary.Count == 0 && cropIt == true) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Define a boundary or set cropIt to False"); } else if (boundary.Count == 0 && cropIt == false) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Clipping boundary has not been defined. File extents will be used instead"); boundary.Add(rec.ToNurbsCurve()); } ///Loop through input boundaries for (int i = 0; i < boundary.Count; i++) { OSGeo.OGR.FeatureDefn def = layer.GetLayerDefn(); ///Get the field names List <string> fieldnames = new List <string>(); for (int iAttr = 0; iAttr < def.GetFieldCount(); iAttr++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iAttr); fnames.Append(new GH_String(fdef.GetNameRef()), new GH_Path(i, iLayer)); } ///Check if boundary is contained in extent if (!rec.IsValid || ((rec.Height == 0) && (rec.Width == 0))) { ///Get field data if even if no geometry is present in the layer AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "One or more vector datasource bounds are not valid."); OSGeo.OGR.Feature feat; int m = 0; while ((feat = layer.GetNextFeature()) != null) { ///Loop through field values for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, iLayer, m)); fdef.Dispose(); } m++; feat.Dispose(); } } else if (boundary[i] == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Clipping boundary " + i + " not set."); } else if (!boundary[i].IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Clipping boundary " + i + " is not valid."); } else if (rec.IsValid && Curve.PlanarClosedCurveRelationship(rec.ToNurbsCurve(), boundary[i], Plane.WorldXY, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance) == RegionContainment.Disjoint) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "One or more clipping boundaries may be outside the bounds of the vector datasource."); } else { ///Create bounding box for clipping geometry Point3d min = boundary[i].GetBoundingBox(true).Min; Point3d max = boundary[i].GetBoundingBox(true).Max; min.Transform(modelToSourceSRSTransform); max.Transform(modelToSourceSRSTransform); double[] minpT = new double[3]; double[] maxpT = new double[3]; minpT[0] = min.X; minpT[1] = min.Y; minpT[2] = min.Z; maxpT[0] = max.X; maxpT[1] = max.Y; maxpT[2] = max.Z; OSGeo.OGR.Geometry ebbox = OSGeo.OGR.Geometry.CreateFromWkt("POLYGON((" + minpT[0] + " " + minpT[1] + ", " + minpT[0] + " " + maxpT[1] + ", " + maxpT[0] + " " + maxpT[1] + ", " + maxpT[0] + " " + minpT[1] + ", " + minpT[0] + " " + minpT[1] + "))"); ///Create bounding box for clipping geometry ///Not working on MVT type files //boundary[i].Transform(modelToSourceSRSTransform); //OSGeo.OGR.Geometry ebbox = Heron.Convert.CurveToOgrPolygon(boundary[i]); ///Clip Shapefile ///http://pcjericks.github.io/py-gdalogr-cookbook/vector_layers.html OSGeo.OGR.Layer clipped_layer = layer; if (cropIt) { clipped_layer.SetSpatialFilter(ebbox); } ///Loop through geometry OSGeo.OGR.Feature feat; def = clipped_layer.GetLayerDefn(); int m = 0; while ((feat = clipped_layer.GetNextFeature()) != null) { OSGeo.OGR.Geometry geom = feat.GetGeometryRef(); OSGeo.OGR.Geometry sub_geom; OSGeo.OGR.Geometry geomUser = feat.GetGeometryRef().Clone(); OSGeo.OGR.Geometry sub_geomUser; ///reproject geometry to WGS84 and userSRS ///TODO: look into using the SetCRS global variable here if (geom.GetSpatialReference() == null) { geom.AssignSpatialReference(sourceSRS); } if (geomUser.GetSpatialReference() == null) { geomUser.AssignSpatialReference(sourceSRS); } geom.TransformTo(rhinoSRS); geomUser.TransformTo(userSRS); gtype.Append(new GH_String(geom.GetGeometryName()), new GH_Path(i, iLayer, m)); if (feat.GetGeometryRef() != null) { ///Convert GDAL geometries to IGH_GeometricGoo gGoo.AppendRange(Heron.Convert.OgrGeomToGHGoo(geomUser, userSRSToModelTransform), new GH_Path(i, iLayer, m)); /// Get Feature Values if (fset.PathExists(new GH_Path(i, iLayer, m))) { fset.get_Branch(new GH_Path(i, iLayer, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, iLayer, m)); } else { fset.Append(new GH_String("null"), new GH_Path(i, iLayer, m)); } } ///End get Feature Values ///Start get points if open polylines and points for (int gpc = 0; gpc < geom.GetPointCount(); gpc++) { ///Loop through geometry points for Rhino SRS double[] ogrPt = new double[3]; geom.GetPoint(gpc, ogrPt); Point3d pt3D = new Point3d(ogrPt[0], ogrPt[1], ogrPt[2]); pt3D.Transform(Heron.Convert.WGSToXYZTransform()); gset.Append(new GH_Point(pt3D), new GH_Path(i, iLayer, m)); ///Loop through geometry points for User SRS double[] ogrPtUser = new double[3]; geomUser.GetPoint(gpc, ogrPtUser); Point3d pt3DUser = new Point3d(ogrPtUser[0], ogrPtUser[1], ogrPtUser[2]); pt3DUser.Transform(userSRSToModelTransform); gsetUser.Append(new GH_Point(pt3DUser), new GH_Path(i, iLayer, m)); ///End loop through geometry points /// Get Feature Values if (fset.PathExists(new GH_Path(i, iLayer, m))) { fset.get_Branch(new GH_Path(i, iLayer, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, iLayer, m)); } else { fset.Append(new GH_String("null"), new GH_Path(i, iLayer, m)); } } ///End Get Feature Values } ///End getting points if open polylines or points ///Start getting points if closed polylines and multipolygons for (int gi = 0; gi < geom.GetGeometryCount(); gi++) { sub_geom = geom.GetGeometryRef(gi); OSGeo.OGR.Geometry subsub_geom; sub_geomUser = geomUser.GetGeometryRef(gi); OSGeo.OGR.Geometry subsub_geomUser; if (sub_geom.GetGeometryCount() > 0) { for (int n = 0; n < sub_geom.GetGeometryCount(); n++) { subsub_geom = sub_geom.GetGeometryRef(n); subsub_geomUser = sub_geomUser.GetGeometryRef(n); for (int ptnum = 0; ptnum < subsub_geom.GetPointCount(); ptnum++) { ///Loop through geometry points double[] ogrPt = new double[3]; subsub_geom.GetPoint(ptnum, ogrPt); Point3d pt3D = new Point3d(ogrPt[0], ogrPt[1], ogrPt[2]); pt3D.Transform(Heron.Convert.WGSToXYZTransform()); gset.Append(new GH_Point(pt3D), new GH_Path(i, iLayer, m, gi, n)); ///Loop through geometry points for User SRS double[] ogrPtUser = new double[3]; subsub_geomUser.GetPoint(ptnum, ogrPtUser); Point3d pt3DUser = new Point3d(ogrPtUser[0], ogrPtUser[1], ogrPtUser[2]); pt3DUser.Transform(userSRSToModelTransform); gsetUser.Append(new GH_Point(pt3DUser), new GH_Path(i, iLayer, m, gi, n)); ///End loop through geometry points } subsub_geom.Dispose(); subsub_geomUser.Dispose(); } } else { for (int ptnum = 0; ptnum < sub_geom.GetPointCount(); ptnum++) { ///Loop through geometry points double[] ogrPt = new double[3]; sub_geom.GetPoint(ptnum, ogrPt); Point3d pt3D = new Point3d(ogrPt[0], ogrPt[1], ogrPt[2]); pt3D.Transform(Heron.Convert.WGSToXYZTransform()); gset.Append(new GH_Point(pt3D), new GH_Path(i, iLayer, m, gi)); ///Loop through geometry points for User SRS double[] ogrPtUser = new double[3]; sub_geomUser.GetPoint(ptnum, ogrPtUser); Point3d pt3DUser = new Point3d(ogrPtUser[0], ogrPtUser[1], ogrPtUser[2]); pt3DUser.Transform(userSRSToModelTransform); gsetUser.Append(new GH_Point(pt3DUser), new GH_Path(i, iLayer, m, gi)); ///End loop through geometry points } } sub_geom.Dispose(); sub_geomUser.Dispose(); /// Get Feature Values if (fset.PathExists(new GH_Path(i, iLayer, m))) { fset.get_Branch(new GH_Path(i, iLayer, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, iLayer, m)); } else { fset.Append(new GH_String("null"), new GH_Path(i, iLayer, m)); } } ///End Get Feature Values } //m++; } m++; geom.Dispose(); geomUser.Dispose(); feat.Dispose(); } ///end while loop through features } ///end clipped layer else statement } ///end loop through boundaries layer.Dispose(); }///end loop through layers dataSource.Dispose(); DA.SetDataTree(0, recs); DA.SetDataTree(1, spatialReferences); DA.SetDataTree(2, fnames); DA.SetDataTree(3, fset); DA.SetDataTree(4, gset); DA.SetDataTree(5, gsetUser); DA.SetDataTree(6, recsUser); DA.SetDataTree(7, gGoo); DA.SetDataTree(8, gtype); }
protected override void SolveInstance(IGH_DataAccess DA) { List <Curve> boundary = new List <Curve>(); DA.GetDataList <Curve>(0, boundary); string shpFileLoc = ""; DA.GetData <string>("Shapefile Location", ref shpFileLoc); ////int SRef = 3857; GdalConfiguration.ConfigureOgr(); GdalConfiguration.ConfigureGdal(); OSGeo.OGR.Driver drv = OSGeo.OGR.Ogr.GetDriverByName("ESRI Shapefile"); OSGeo.OGR.DataSource ds = OSGeo.OGR.Ogr.Open(shpFileLoc, 0); List <OSGeo.OGR.Layer> layerset = new List <OSGeo.OGR.Layer>(); List <int> fc = new List <int>(); for (int iLayer = 0; iLayer < ds.GetLayerCount(); iLayer++) { OSGeo.OGR.Layer layer = ds.GetLayerByIndex(iLayer); if (layer == null) { Console.WriteLine("FAILURE: Couldn't fetch advertised layer " + iLayer); System.Environment.Exit(-1); } long count = layer.GetFeatureCount(1); int featureCount = System.Convert.ToInt32(count); fc.Add(featureCount); layerset.Add(layer); } //Get OGR envelope of Shapefile OSGeo.OGR.Envelope ext = new OSGeo.OGR.Envelope(); layerset[0].GetExtent(ext, 1); Point3d extMin = new Point3d(); Point3d extMax = new Point3d(); extMin.X = ext.MinX; extMin.Y = ext.MinY; extMax.X = ext.MaxX; extMax.Y = ext.MaxY; OSGeo.OSR.SpatialReference sr = layerset[0].GetSpatialRef(); OSGeo.OSR.SpatialReference dst = new OSGeo.OSR.SpatialReference(""); dst.SetWellKnownGeogCS("WGS84"); //Get the spatial refernce of the input Shapefile string sRef; sr.ExportToWkt(out sRef); OSGeo.OSR.CoordinateTransformation coordTransform = new OSGeo.OSR.CoordinateTransformation(sr, dst); OSGeo.OSR.CoordinateTransformation revTransform = new OSGeo.OSR.CoordinateTransformation(dst, sr); //Get bounding box of data in Shapefile double[] extMinPT = new double[3] { extMin.X, extMin.Y, extMin.Z }; double[] extMaxPT = new double[3] { extMax.X, extMax.Y, extMax.Z }; coordTransform.TransformPoint(extMinPT); coordTransform.TransformPoint(extMaxPT); Point3d extPTmin = new Point3d(extMinPT[0], extMinPT[1], extMinPT[2]); Point3d extPTmax = new Point3d(extMaxPT[0], extMaxPT[1], extMaxPT[2]); Rectangle3d rec = new Rectangle3d(Plane.WorldXY, Heron.Convert.ToXYZ(extPTmin), Heron.Convert.ToXYZ(extPTmax)); //Declare trees GH_Structure <GH_String> fset = new GH_Structure <GH_String>(); GH_Structure <GH_Point> gset = new GH_Structure <GH_Point>(); GH_Structure <GH_String> layname = new GH_Structure <GH_String>(); OSGeo.OGR.FeatureDefn def = layerset[0].GetLayerDefn(); //Loop through input boundaries for (int i = 0; i < boundary.Count; i++) { if (rec.BoundingBox.Contains(boundary[i].GetBoundingBox(true).Min) && (rec.BoundingBox.Contains(boundary[i].GetBoundingBox(true).Max))) { //Create bounding box for clipping geometry Point3d min = Heron.Convert.ToWGS(boundary[i].GetBoundingBox(true).Min); Point3d max = Heron.Convert.ToWGS(boundary[i].GetBoundingBox(true).Max); double[] minpT = new double[3]; double[] maxpT = new double[3]; minpT[0] = min.X; minpT[1] = min.Y; minpT[2] = min.Z; maxpT[0] = max.X; maxpT[1] = max.Y; maxpT[2] = max.Z; revTransform.TransformPoint(minpT); revTransform.TransformPoint(maxpT); OSGeo.OGR.Geometry bbox = OSGeo.OGR.Geometry.CreateFromWkt("POLYGON((" + min.X + " " + min.Y + ", " + min.X + " " + max.Y + ", " + max.X + " " + max.Y + ", " + max.X + " " + min.Y + ", " + min.X + " " + min.Y + "))"); OSGeo.OGR.Geometry ebbox = OSGeo.OGR.Geometry.CreateFromWkt("POLYGON((" + minpT[0] + " " + minpT[1] + ", " + minpT[0] + " " + maxpT[1] + ", " + maxpT[0] + " " + maxpT[1] + ", " + maxpT[0] + " " + minpT[1] + ", " + minpT[0] + " " + minpT[1] + "))"); //Clip Shapefile //http://pcjericks.github.io/py-gdalogr-cookbook/vector_layers.html OSGeo.OGR.Layer clipped_layer = layerset[0]; clipped_layer.SetSpatialFilter(ebbox); //Loop through geometry OSGeo.OGR.Feature feat; def = clipped_layer.GetLayerDefn(); int m = 0; while ((feat = layerset[0].GetNextFeature()) != null) { if (feat.GetGeometryRef() != null) { //Get geometry points and field values OSGeo.OGR.Geometry geom = feat.GetGeometryRef(); OSGeo.OGR.Geometry sub_geom; //Start get points if open polylines and points for (int gpc = 0; gpc < geom.GetPointCount(); gpc++) { //Loop through geometry points double[] pT = new double[3]; pT[0] = geom.GetX(gpc); pT[1] = geom.GetY(gpc); pT[2] = geom.GetZ(gpc); if (Double.IsNaN(geom.GetZ(gpc))) { pT[2] = 0; } coordTransform.TransformPoint(pT); Point3d pt3D = new Point3d(); pt3D.X = pT[0]; pt3D.Y = pT[1]; pt3D.Z = pT[2]; gset.Append(new GH_Point(Heron.Convert.ToXYZ(pt3D)), new GH_Path(i, m)); //End loop through geometry points // Get Feature Values if (fset.PathExists(new GH_Path(i, m))) { fset.get_Branch(new GH_Path(i, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, m)); } else { fset.Append(new GH_String("null"), new GH_Path(i, m)); } } //End Get Feature Values } //End getting points if open polylines or points //Start getting points if closed polylines and multipolygons for (int gi = 0; gi < geom.GetGeometryCount(); gi++) { sub_geom = geom.GetGeometryRef(gi); List <Point3d> geom_list = new List <Point3d>(); for (int ptnum = 0; ptnum < sub_geom.GetPointCount(); ptnum++) { //Loop through geometry points double[] pT = new double[3]; pT[0] = sub_geom.GetX(ptnum); pT[1] = sub_geom.GetY(ptnum); pT[2] = sub_geom.GetZ(ptnum); coordTransform.TransformPoint(pT); Point3d pt3D = new Point3d(); pt3D.X = pT[0]; pt3D.Y = pT[1]; pt3D.Z = pT[2]; gset.Append(new GH_Point(Heron.Convert.ToXYZ(pt3D)), new GH_Path(i, m, gi)); //End loop through geometry points // Get Feature Values if (fset.PathExists(new GH_Path(i, m))) { fset.get_Branch(new GH_Path(i, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, m)); } else { fset.Append(new GH_String("null"), new GH_Path(i, m)); } } //End Get Feature Values } //End getting points from closed polylines } m++; } feat.Dispose(); } } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "One or more boundaries may be outside the bounds of the Shapefile dataset."); //return; } } //Get the field names List <string> fieldnames = new List <string>(); for (int iAttr = 0; iAttr < def.GetFieldCount(); iAttr++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iAttr); fieldnames.Add(fdef.GetNameRef()); } DA.SetData(0, def.GetName()); DA.SetDataList(1, fc); DA.SetData(2, rec); DA.SetData(3, sRef); DA.SetDataList(4, fieldnames); DA.SetDataTree(5, fset); DA.SetDataTree(6, gset); }
/// <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) { Curve boundary = null; DA.GetData <Curve>(0, ref boundary); int zoom = -1; DA.GetData <int>(1, ref zoom); string filePath = string.Empty; DA.GetData <string>(2, ref filePath); if (!filePath.EndsWith(@"\")) { filePath = filePath + @"\"; } string prefix = string.Empty; DA.GetData <string>(3, ref prefix); if (prefix == "") { prefix = mbSource; } string URL = mbURL; string mbToken = string.Empty; DA.GetData <string>(4, ref mbToken); if (mbToken == "") { string hmbToken = System.Environment.GetEnvironmentVariable("HERONMAPBOXTOKEN"); if (hmbToken != null) { mbToken = hmbToken; AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using Mapbox token stored in Environment Variable HERONMAPBOXTOKEN."); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "No Mapbox token is specified. Please get a valid token from mapbox.com"); return; } } bool run = false; DA.GetData <bool>("Run", ref run); ///GDAL setup RESTful.GdalConfiguration.ConfigureOgr(); OSGeo.OGR.Ogr.RegisterAll(); RESTful.GdalConfiguration.ConfigureGdal(); GH_Curve imgFrame; GH_String tCount; GH_Structure <GH_String> fnames = new GH_Structure <GH_String>(); GH_Structure <GH_String> fvalues = new GH_Structure <GH_String>(); GH_Structure <IGH_GeometricGoo> gGoo = new GH_Structure <IGH_GeometricGoo>(); GH_Structure <GH_String> gtype = new GH_Structure <GH_String>(); GH_Structure <IGH_GeometricGoo> gGooBuildings = new GH_Structure <IGH_GeometricGoo>(); int tileTotalCount = 0; int tileDownloadedCount = 0; ///Get image frame for given boundary if (!boundary.GetBoundingBox(true).IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Boundary is not valid."); return; } BoundingBox boundaryBox = boundary.GetBoundingBox(true); //create cache folder for vector tiles string cacheLoc = filePath + @"HeronCache\"; List <string> cachefilePaths = new List <string>(); if (!Directory.Exists(cacheLoc)) { Directory.CreateDirectory(cacheLoc); } //tile bounding box array List <Point3d> boxPtList = new List <Point3d>(); //get the tile coordinates for all tiles within boundary var ranges = Convert.GetTileRange(boundaryBox, zoom); var x_range = ranges.XRange; var y_range = ranges.YRange; if (x_range.Length > 100 || y_range.Length > 100) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "This tile range is too big (more than 100 tiles in the x or y direction). Check your units."); return; } ///cycle through tiles to get bounding box List <Polyline> tileExtents = new List <Polyline>(); List <double> tileHeight = new List <double>(); List <double> tileWidth = new List <double>(); for (int y = (int)y_range.Min; y <= y_range.Max; y++) { for (int x = (int)x_range.Min; x <= x_range.Max; x++) { //add bounding box of tile to list for translation Polyline tileExtent = Heron.Convert.GetTileAsPolygon(zoom, y, x); tileExtents.Add(tileExtent); tileWidth.Add(tileExtent[0].DistanceTo(tileExtent[1])); tileHeight.Add(tileExtent[1].DistanceTo(tileExtent[2])); boxPtList.AddRange(tileExtent.ToList()); cachefilePaths.Add(cacheLoc + mbSource.Replace(" ", "") + zoom + "-" + x + "-" + y + ".mvt"); tileTotalCount = tileTotalCount + 1; } } tCount = new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"); ///bounding box of tile boundaries BoundingBox bboxPts = new BoundingBox(boxPtList); ///convert bounding box to polyline List <Point3d> imageCorners = bboxPts.GetCorners().ToList(); imageCorners.Add(imageCorners[0]); imgFrame = new GH_Curve(new Rhino.Geometry.Polyline(imageCorners).ToNurbsCurve()); ///tile range as string for (de)serialization of TileCacheMeta string tileRangeString = "Tile range for zoom " + zoom.ToString() + ": " + x_range[0].ToString() + "-" + y_range[0].ToString() + " to " + x_range[1].ToString() + "-" + y_range[1].ToString(); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, tileRangeString); ///Query Mapbox URL ///download all tiles within boundary ///API to query string mbURLauth = mbURL + mbToken; if (run == true) { for (int y = (int)y_range.Min; y <= (int)y_range.Max; y++) { for (int x = (int)x_range.Min; x <= (int)x_range.Max; x++) { //create tileCache name string tileCache = mbSource.Replace(" ", "") + zoom + "-" + x + "-" + y + ".mvt"; string tileCacheLoc = cacheLoc + tileCache; //check cache folder to see if tile image exists locally if (File.Exists(tileCacheLoc)) { } else { string urlAuth = Heron.Convert.GetZoomURL(x, y, zoom, mbURLauth); System.Net.WebClient client = new System.Net.WebClient(); client.DownloadFile(urlAuth, tileCacheLoc); client.Dispose(); ///https://gdal.org/development/rfc/rfc59.1_utilities_as_a_library.html ///http://osgeo-org.1560.x6.nabble.com/gdal-dev-How-to-convert-shapefile-to-geojson-using-c-bindings-td5390953.html#a5391028 ///ogr2ogr is slow //OSGeo.GDAL.Dataset httpDS = OSGeo.GDAL.Gdal.OpenEx("MVT:"+urlAuth,4,null,null,null); //var transOptions = new OSGeo.GDAL.GDALVectorTranslateOptions(new[] { "-s_srs","EPSG:3857", "-t_srs", "EPSG:4326","-skipfailures" }); //var transDS = OSGeo.GDAL.Gdal.wrapper_GDALVectorTranslateDestName(mvtLoc + zoom + "-" + x + "-" + y , httpDS, transOptions, null, null); //httpDS.Dispose(); //transDS.Dispose(); tileDownloadedCount = tileDownloadedCount + 1; } } } } //add to tile count total tCount = new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, tCount.ToString()); ///Build a VRT file ///https://stackoverflow.com/questions/55386597/gdal-c-sharp-wrapper-for-vrt-doesnt-write-a-vrt-file //string vrtFile = cacheLoc + "mapboxvector.vrt"; //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, vrtFile); //var vrtOptions = new OSGeo.GDAL.GDALBuildVRTOptions(new[] { "-overwrite" }); //var vrtDataset = OSGeo.GDAL.Gdal.wrapper_GDALBuildVRT_names(vrtFile, cachefilePaths.ToArray(), vrtOptions, null, null); //vrtDataset.Dispose(); ///Set transform from input spatial reference to Rhino spatial reference ///TODO: look into adding a step for transforming to CRS set in SetCRS OSGeo.OSR.SpatialReference rhinoSRS = new OSGeo.OSR.SpatialReference(""); rhinoSRS.SetWellKnownGeogCS("WGS84"); ///TODO: verify the userSRS is valid ///TODO: use this as override of global SetSRS OSGeo.OSR.SpatialReference userSRS = new OSGeo.OSR.SpatialReference(""); //userSRS.SetFromUserInput(userSRStext); userSRS.SetFromUserInput("WGS84"); OSGeo.OSR.SpatialReference sourceSRS = new SpatialReference(""); sourceSRS.SetFromUserInput("EPSG:3857"); ///These transforms move and scale in order to go from userSRS to XYZ and vice versa Transform userSRSToModelTransform = Heron.Convert.GetUserSRSToModelTransform(userSRS); Transform modelToUserSRSTransform = Heron.Convert.GetModelToUserSRSTransform(userSRS); Transform sourceToModelSRSTransform = Heron.Convert.GetUserSRSToModelTransform(sourceSRS); Transform modelToSourceSRSTransform = Heron.Convert.GetModelToUserSRSTransform(sourceSRS); //OSGeo.GDAL.Driver gdalOGR = OSGeo.GDAL.Gdal.GetDriverByName("VRT"); //var ds = OSGeo.GDAL.Gdal.OpenEx(vrtFile, 4, ["VRT","MVT"], null, null); int t = 0; foreach (string mvtTile in cachefilePaths)// cachefilePaths) { OSGeo.OGR.Driver drv = OSGeo.OGR.Ogr.GetDriverByName("MVT"); OSGeo.OGR.DataSource ds = OSGeo.OGR.Ogr.Open("MVT:" + mvtTile, 0); string[] mvtOptions = new[] { "CLIP", "NO" }; //OSGeo.OGR.DataSource ds = drv.Open(mvtTile, 0); if (ds == 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; } ///Morph raw mapbox tile points to geolocated tile Vector3d moveDir = tileExtents[t].ElementAt(0) - new Point3d(0, 0, 0); Transform move = Transform.Translation(moveDir); Transform scale = Transform.Scale(Plane.WorldXY, tileWidth[t] / 4096, tileHeight[t] / 4096, 1); Transform scaleMove = Transform.Multiply(move, scale); for (int iLayer = 0; iLayer < ds.GetLayerCount(); iLayer++) { OSGeo.OGR.Layer layer = ds.GetLayerByIndex(iLayer); long count = layer.GetFeatureCount(1); int featureCount = System.Convert.ToInt32(count); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Layer #" + iLayer + " " + layer.GetName() + " has " + featureCount + " features"); //if (layer.GetName() == "admin" || layer.GetName() == "building") //{ OSGeo.OGR.FeatureDefn def = layer.GetLayerDefn(); ///Get the field names List <string> fieldnames = new List <string>(); for (int iAttr = 0; iAttr < def.GetFieldCount(); iAttr++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iAttr); fnames.Append(new GH_String(fdef.GetNameRef()), new GH_Path(iLayer, t)); } ///Loop through geometry OSGeo.OGR.Feature feat; int m = 0; ///error "Self-intersection at or near point..." when zoom gets below 12 for water ///this is an issue with the way mvt simplifies geometries at lower zoom levels and is a known problem ///TODO: look into how to fix invalid geom and return to the typical while loop iterating method //while ((feat = layer.GetNextFeature()) != null) while (true) { try { feat = layer.GetNextFeature(); } catch { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Some features had invalid geometry and were skipped."); continue; } if (feat == null) { break; } OSGeo.OGR.Geometry geom = feat.GetGeometryRef(); ///reproject geometry to WGS84 and userSRS ///TODO: look into using the SetCRS global variable here gtype.Append(new GH_String(geom.GetGeometryName()), new GH_Path(iLayer, t, m)); Transform tr = scaleMove; // new Transform(1); if (feat.GetGeometryRef() != null) { ///Convert GDAL geometries to IGH_GeometricGoo foreach (IGH_GeometricGoo gMorphed in Heron.Convert.OgrGeomToGHGoo(geom, tr)) { //gMorphed.Morph(morph); gGoo.Append(gMorphed, new GH_Path(iLayer, t, m)); } if (layer.GetName() == "building") { if (feat.GetFieldAsString(def.GetFieldIndex("extrude")) == "true") { double unitsConversion = Rhino.RhinoMath.UnitScale(Rhino.RhinoDoc.ActiveDoc.ModelUnitSystem, Rhino.UnitSystem.Meters); double height = System.Convert.ToDouble(feat.GetFieldAsString(def.GetFieldIndex("height"))) / unitsConversion; double min_height = System.Convert.ToDouble(feat.GetFieldAsString(def.GetFieldIndex("min_height"))) / unitsConversion; bool underground = System.Convert.ToBoolean(feat.GetFieldAsString(def.GetFieldIndex("underground"))); if (geom.GetGeometryType() == wkbGeometryType.wkbPolygon) { Extrusion bldg = Heron.Convert.OgrPolygonToExtrusion(geom, tr, height, min_height, underground); IGH_GeometricGoo bldgGoo = GH_Convert.ToGeometricGoo(bldg); gGooBuildings.Append(bldgGoo, new GH_Path(iLayer, t, m)); } if (geom.GetGeometryType() == wkbGeometryType.wkbMultiPolygon) { List <Extrusion> bldgs = Heron.Convert.OgrMultiPolyToExtrusions(geom, tr, height, min_height, underground); foreach (Extrusion bldg in bldgs) { IGH_GeometricGoo bldgGoo = GH_Convert.ToGeometricGoo(bldg); gGooBuildings.Append(bldgGoo, new GH_Path(iLayer, t, m)); } } } } /// Get Feature Values if (fvalues.PathExists(new GH_Path(iLayer, t, m))) { //fvalues.get_Branch(new GH_Path(iLayer, t, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fvalues.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(iLayer, t, m)); } else { fvalues.Append(new GH_String("null"), new GH_Path(iLayer, t, m)); } } } m++; geom.Dispose(); feat.Dispose(); }///end while loop through features //}///end layer by name layer.Dispose(); }///end loop through layers ds.Dispose(); t++; }///end loop through mvt tiles //write out new tile range metadata for serialization TileCacheMeta = tileRangeString; DA.SetData(0, imgFrame); DA.SetDataTree(1, fnames); DA.SetDataTree(2, fvalues); DA.SetDataTree(3, gGoo); DA.SetDataList(4, "copyright Mapbox"); DA.SetDataTree(5, gtype); DA.SetDataTree(6, gGooBuildings); DA.SetDataList(7, tileExtents); }
protected override void SolveInstance(IGH_DataAccess DA) { List <Curve> boundary = new List <Curve>(); DA.GetDataList <Curve>(0, boundary); string IMG_file = ""; DA.GetData <string>("IMG Location", ref IMG_file); /* * //Does not work with HGT files * * byte[] imageBuffer; * * using (FileStream fs = new FileStream(IMG_file, FileMode.Open, FileAccess.Read)) * { * using (BinaryReader br = new BinaryReader(fs)) * { * long numBytes = new FileInfo(IMG_file).Length; * imageBuffer = br.ReadBytes((int)numBytes); * br.Close(); * fs.Close(); * } * } */ RESTful.GdalConfiguration.ConfigureGdal(); OSGeo.GDAL.Gdal.AllRegister(); //string memFilename = "/vsimem/inmemfile"; //Gdal.FileFromMemBuffer(memFilename, imageBuffer); Dataset ds = Gdal.Open(IMG_file, Access.GA_ReadOnly); OSGeo.GDAL.Driver drv = ds.GetDriver(); if (ds == 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 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 (ds.GetProjection() == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Coordinate Reference System (CRS) is missing. CRS set automatically set to WGS84."); } else { sr = new SpatialReference(ds.GetProjection()); if (sr.Validate() != 0) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Coordinate Reference System (CRS) is unknown or unsupported. CRS set automatically set to WGS84."); 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]; ds.GetGeoTransform(adfGeoTransform); Gdal.InvGeoTransform(adfGeoTransform, invTransform); Band band = ds.GetRasterBand(1); int width = ds.RasterXSize; int height = ds.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]); //Point3d dsMin = new Point3d(oX, eY, 0); //Point3d dsMax = new Point3d(eX, oY, 0); Rectangle3d dsbox = new Rectangle3d(Plane.WorldXY, Heron.Convert.WGSToXYZ(dsMin), Heron.Convert.WGSToXYZ(dsMax)); //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++) { if (dsbox.BoundingBox.Contains(boundary[i].GetBoundingBox(true).Min) && (dsbox.BoundingBox.Contains(boundary[i].GetBoundingBox(true).Max))) { Point3d min = Heron.Convert.XYZToWGS(boundary[i].GetBoundingBox(true).Corner(true, false, true)); Point3d max = Heron.Convert.XYZToWGS(boundary[i].GetBoundingBox(true).Corner(false, true, true)); ///Transform to source SRS double[] minR = new double[3] { min.X, min.Y, min.Z }; double[] maxR = new double[3] { max.X, max.Y, max.Z }; revTransform.TransformPoint(minR); revTransform.TransformPoint(maxR); GH_Path path = new GH_Path(i); // http://gis.stackexchange.com/questions/46893/how-do-i-get-the-pixel-value-of-a-gdal-raster-under-an-ogr-point-without-numpy double ur, uc, lr, lc; Gdal.ApplyGeoTransform(invTransform, minR[0], minR[1], out uc, out ur); Gdal.ApplyGeoTransform(invTransform, maxR[0], maxR[1], out lc, out lr); //Gdal.ApplyGeoTransform(invTransform, min.X, min.Y, out uc, out ur); //Gdal.ApplyGeoTransform(invTransform, max.X, max.Y, out lc, out lr); int Urow = System.Convert.ToInt32(ur); int Ucol = System.Convert.ToInt32(uc); int Lrow = System.Convert.ToInt32(lr) + 1; int Lcol = System.Convert.ToInt32(lc) + 1; rCount.Append(new GH_Integer(Lrow - Urow), path); cCount.Append(new GH_Integer(Lcol - Ucol), 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 = Ucol; col < Lcol; col++) { for (int row = Urow; row < Lrow; 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]); //Point3d pt = new Point3d(gcol, grow, pixel); 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) * (Lrow - Urow), v - 1 + u * (Lrow - Urow), v - 1 + u * (Lrow - Urow) + 1, v - 1 + (u - 1) * (Lrow - Urow) + 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); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "One or more boundaries may be outside the bounds of the topo dataset."); //return; } } DA.SetDataTree(0, tMesh); DA.SetData(1, dsbox); }
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); }
public override void DoWork(Action <string, double> ReportProgress, Action Done) { // Checking for cancellation if (CancellationToken.IsCancellationRequested) { return; } ///Make sure there's an API key string mbToken = ApiKey; if (mbToken == "") { string hmbToken = System.Environment.GetEnvironmentVariable("HERONMAPBOXTOKEN"); if (hmbToken != null) { mbToken = hmbToken; RuntimeMessages.Add((GH_RuntimeMessageLevel.Remark, "Using Mapbox token stored in Environment Variable HERONMAPBOXTOKEN.")); } else { RuntimeMessages.Add((GH_RuntimeMessageLevel.Error, "No Mapbox token is specified. Please get a valid token from mapbox.com")); return; } } ///GDAL setup RESTful.GdalConfiguration.ConfigureOgr(); OSGeo.OGR.Ogr.RegisterAll(); ///Set transform from input spatial reference to Rhino spatial reference ///TODO: look into adding a step for transforming to CRS set in SetCRS OSGeo.OSR.SpatialReference rhinoSRS = new OSGeo.OSR.SpatialReference(""); rhinoSRS.SetWellKnownGeogCS("WGS84"); ///TODO: verify the userSRS is valid ///TODO: use this as override of global SetSRS OSGeo.OSR.SpatialReference userSRS = new OSGeo.OSR.SpatialReference(""); //userSRS.SetFromUserInput(userSRStext); userSRS.SetFromUserInput("WGS84"); ///Mapbox uses EPSG:3857 OSGeo.OSR.SpatialReference sourceSRS = new SpatialReference(""); sourceSRS.SetFromUserInput("EPSG:3857"); ///These transforms move and scale in order to go from userSRS to XYZ and vice versa Transform userSRSToModelTransform = Heron.Convert.GetUserSRSToModelTransform(userSRS); Transform modelToUserSRSTransform = Heron.Convert.GetModelToUserSRSTransform(userSRS); Transform sourceToModelSRSTransform = Heron.Convert.GetUserSRSToModelTransform(sourceSRS); Transform modelToSourceSRSTransform = Heron.Convert.GetModelToUserSRSTransform(sourceSRS); double lat = Heron.Convert.XYZToWGS(Location).Y; double lon = Heron.Convert.XYZToWGS(Location).X; ///Setup contour style and unit type string contourType = String.Empty; double?contourNum = Contour; if (contourNum < 0.0) { contourNum = 0.0; } double unitConversion = Rhino.RhinoMath.UnitScale(Rhino.RhinoDoc.ActiveDoc.ModelUnitSystem, Rhino.UnitSystem.Meters); if (MapboxIsochroneSpeckle.MinutesOrMeters == "Distance") { contourType = "contours_meters="; contourNum = contourNum * unitConversion; } else { contourType = "contours_minutes="; if (contourNum > 60) { contourNum = 60; RuntimeMessages.Add((GH_RuntimeMessageLevel.Warning, "Maximum minute contour is 60. Contour value reduced to 60.")); } } ///Make sure Denoise is between 0..1 double?denoiseNum = Denoise; if (denoiseNum < 0.0) { denoiseNum = 0.0; } if (denoiseNum > 1.0) { denoiseNum = 1.0; } ///Make sure Generalize is > 0 double?generalizeNum = Generalize * unitConversion; if (generalizeNum < 0.0) { generalizeNum = 0.0; } ///Construct URL query string string url = @"https://api.mapbox.com/isochrone/v1/mapbox/"; if (!String.IsNullOrEmpty(MapboxIsochroneSpeckle.Profile)) { url = url + MapboxIsochroneSpeckle.Profile.ToLower() + "/"; } if (lon > -180.0 && lon <= 180.0) { url = url + lon + "%2C"; } if (lat > -90.0 && lat <= 90.0) { url = url + lat + "?"; } if (!String.IsNullOrEmpty(contourType)) { url = url + contourType.ToLower(); } if (contourNum != null) { url = url + contourNum; } url = url + "&polygons=true"; if (denoiseNum != null) { url = url + "&denoise=" + denoiseNum; } if (generalizeNum != null) { url = url + "&generalize=" + generalizeNum; } if (mbToken != "") { url = url + "&access_token=" + mbToken; } Url = url; if (CancellationToken.IsCancellationRequested) { return; } if (Run) { List <IGH_GeometricGoo> gGoo = new List <IGH_GeometricGoo>(); OSGeo.OGR.DataSource dataSource = OSGeo.OGR.Ogr.Open(url, 0); if (dataSource == null) { RuntimeMessages.Add((GH_RuntimeMessageLevel.Error, "Mapbox returned an invalid response.")); return; } ///Only interested in geometry, not fields or values OSGeo.OGR.Layer ogrLayer = dataSource.GetLayerByIndex(0); OSGeo.OGR.Feature feat; while ((feat = ogrLayer.GetNextFeature()) != null) { OSGeo.OGR.Geometry geomUser = feat.GetGeometryRef().Clone(); ///reproject geometry to WGS84 and userSRS ///TODO: look into using the SetCRS global variable here if (geomUser.GetSpatialReference() == null) { geomUser.AssignSpatialReference(userSRS); } geomUser.TransformTo(userSRS); if (feat.GetGeometryRef() != null) { gGoo.AddRange(Heron.Convert.OgrGeomToGHGoo(geomUser, userSRSToModelTransform)); } } Isochrones = gGoo; } Done(); }
protected override void SolveInstance(IGH_DataAccess DA) { Curve boundary = null; DA.GetData <Curve>(0, ref boundary); string sourceFileLocation = string.Empty; DA.GetData <string>(1, ref sourceFileLocation); string clippedLocation = string.Empty; DA.GetData <string>(2, ref clippedLocation); RESTful.GdalConfiguration.ConfigureGdal(); OSGeo.GDAL.Gdal.AllRegister(); ///Specific settings for getting WMS images OSGeo.GDAL.Gdal.SetConfigOption("GDAL_HTTP_UNSAFESSL", "YES"); OSGeo.GDAL.Gdal.SetConfigOption("GDAL_SKIP", "WMS"); ///Read in the raster data Dataset datasource = Gdal.Open(sourceFileLocation, Access.GA_ReadOnly); OSGeo.GDAL.Driver drv = datasource.GetDriver(); string srcInfo = string.Empty; if (datasource == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "The raster datasource was unreadable by this component. It may not a valid file type for this component or otherwise null/empty."); return; } ///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, "Spatial Reference System (SRS) is missing. SRS 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)); } } ///Get info about image List <string> infoOptions = new List <string> { "-stats" }; srcInfo = Gdal.GDALInfo(datasource, new GDALInfoOptions(infoOptions.ToArray())); //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); Band band = datasource.GetRasterBand(1); 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. ///TODO: Allow for UserSRS 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]); ///Get bounding box for entire raster data Rectangle3d datasourceBBox = new Rectangle3d(Plane.WorldXY, Heron.Convert.WGSToXYZ(dsMin), Heron.Convert.WGSToXYZ(dsMax)); ///https://gis.stackexchange.com/questions/312440/gdal-translate-bilinear-interpolation ///set output to georeferenced tiff as a catch-all string clippedRasterFile = clippedLocation + Path.GetFileNameWithoutExtension(sourceFileLocation) + "_clipped.tif"; string previewPNG = clippedLocation + Path.GetFileNameWithoutExtension(sourceFileLocation) + "_preview.png"; AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Original Resolution: " + datasource.RasterXSize.ToString() + "x" + datasource.RasterYSize.ToString()); if (boundary != null) { Point3d clipperMin = Heron.Convert.XYZToWGS(boundary.GetBoundingBox(true).Corner(true, false, true)); Point3d clipperMax = Heron.Convert.XYZToWGS(boundary.GetBoundingBox(true).Corner(false, true, true)); double lonWest = clipperMin.X; double lonEast = clipperMax.X; double latNorth = clipperMin.Y; double latSouth = clipperMax.Y; ///GDALTranslate should also be its own component with full control over options var translateOptions = new[] { "-of", "GTiff", //"-a_nodata", "0", "-projwin_srs", "WGS84", "-projwin", $"{lonWest}", $"{latNorth}", $"{lonEast}", $"{latSouth}" }; using (Dataset clippedDataset = Gdal.wrapper_GDALTranslate(clippedRasterFile, datasource, new GDALTranslateOptions(translateOptions), null, null)) { Dataset previewDataset = Gdal.wrapper_GDALTranslate(previewPNG, clippedDataset, null, null, null); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Clipped Resolution: " + clippedDataset.RasterXSize.ToString() + "x" + datasource.RasterYSize.ToString()); ///clean up clippedDataset.FlushCache(); clippedDataset.Dispose(); previewDataset.FlushCache(); previewDataset.Dispose(); AddPreviewItem(previewPNG, BBoxToRect(boundary.GetBoundingBox(true))); } } else { Dataset previewDataset = Gdal.wrapper_GDALTranslate(previewPNG, datasource, null, null, null); ///clean up previewDataset.FlushCache(); previewDataset.Dispose(); AddPreviewItem(previewPNG, datasourceBBox); } ///clean up datasource.FlushCache(); datasource.Dispose(); DA.SetData(0, srcInfo); DA.SetData(1, datasourceBBox); DA.SetData(2, clippedRasterFile); }
/// <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); }
protected override void SolveInstance(IGH_DataAccess DA) { List <Curve> boundary = new List <Curve>(); DA.GetDataList <Curve>(0, boundary); string shpFileLoc = ""; DA.GetData <string>("Vector Data Location", ref shpFileLoc); ///GDAL setup ///Some preliminary testing has been done to read SHP, GeoJSON, OSM, KML, MVT, GML and GDB ///It can be spotty with KML, MVT and GML and doesn't throw informative errors. Likely has to do with getting a valid CRS and ///TODO: resolve errors with reading KML, MVT, GML. RESTful.GdalConfiguration.ConfigureOgr(); OSGeo.OGR.Ogr.RegisterAll(); OSGeo.OGR.Driver drv = OSGeo.OGR.Ogr.GetDriverByName("ESRI Shapefile"); OSGeo.OGR.DataSource ds = OSGeo.OGR.Ogr.Open(shpFileLoc, 0); if (ds == 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; } List <OSGeo.OGR.Layer> layerset = new List <OSGeo.OGR.Layer>(); List <int> fc = new List <int>(); for (int iLayer = 0; iLayer < ds.GetLayerCount(); iLayer++) { OSGeo.OGR.Layer layer = ds.GetLayerByIndex(iLayer); if (layer == null) { Console.WriteLine("Couldn't fetch advertised layer " + iLayer); System.Environment.Exit(-1); } else { layerset.Add(layer); } } ///Declare trees GH_Structure <GH_String> layname = new GH_Structure <GH_String>(); GH_Structure <GH_Integer> fcs = new GH_Structure <GH_Integer>(); GH_Structure <GH_Rectangle> recs = new GH_Structure <GH_Rectangle>(); GH_Structure <GH_String> sRefs = new GH_Structure <GH_String>(); GH_Structure <GH_String> fnames = new GH_Structure <GH_String>(); GH_Structure <GH_String> fset = new GH_Structure <GH_String>(); GH_Structure <GH_Point> gset = new GH_Structure <GH_Point>(); ///Loop through each layer. Layers usually occur in Geodatabase GDB format. SHP usually has only one layer. for (int iLayer = 0; iLayer < ds.GetLayerCount(); iLayer++) { OSGeo.OGR.Layer layer = ds.GetLayerByIndex(iLayer); if (layer == null) { Console.WriteLine("Couldn't fetch advertised layer " + iLayer); System.Environment.Exit(-1); } long count = layer.GetFeatureCount(1); int featureCount = System.Convert.ToInt32(count); fcs.Append(new GH_Integer(featureCount), new GH_Path(iLayer)); layname.Append(new GH_String(layer.GetName()), new GH_Path(iLayer)); ///Get OGR envelope of the data in the layer OSGeo.OGR.Envelope ext = new OSGeo.OGR.Envelope(); layer.GetExtent(ext, 1); Point3d extMin = new Point3d(); Point3d extMax = new Point3d(); extMin.X = ext.MinX; extMin.Y = ext.MinY; extMax.X = ext.MaxX; extMax.Y = ext.MaxY; ///Get the spatial reference of the input vector file and set to WGS84 if not known OSGeo.OSR.SpatialReference sr = new SpatialReference(Osr.SRS_WKT_WGS84); string sRef = ""; if (layer.GetSpatialRef() == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Coordinate Reference System (CRS) is missing. CRS set automatically set to WGS84."); sr.ImportFromXML(shpFileLoc); string pretty = ""; sr.ExportToPrettyWkt(out pretty, 0); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, pretty); sr.SetWellKnownGeogCS("WGS84"); sRef = "Coordinate Reference System (CRS) is missing. CRS set automatically set to WGS84."; //sr.ImportFromEPSG(2263); } else { if (layer.GetSpatialRef().Validate() != 0) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Coordinate Reference System (CRS) is unknown or unsupported. CRS set automatically set to WGS84."); sr.SetWellKnownGeogCS("WGS84"); sRef = "Coordinate Reference System (CRS) is unknown or unsupported. SRS set automatically set to WGS84."; } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Coordinate Reference System (CRS) set from layer" + iLayer + "."); sr = layer.GetSpatialRef(); sr.ExportToWkt(out sRef); } } sRefs.Append(new GH_String(sRef), new GH_Path(iLayer)); ///Set transform from input spatial reference to Rhino spatial reference ///TODO: look into adding a step for transforming to CRS set in SetCRS 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); ///Get bounding box of data in layer double[] extMinPT = new double[3] { extMin.X, extMin.Y, extMin.Z }; double[] extMaxPT = new double[3] { extMax.X, extMax.Y, extMax.Z }; coordTransform.TransformPoint(extMinPT); coordTransform.TransformPoint(extMaxPT); Point3d extPTmin = new Point3d(extMinPT[0], extMinPT[1], extMinPT[2]); Point3d extPTmax = new Point3d(extMaxPT[0], extMaxPT[1], extMaxPT[2]); Rectangle3d rec = new Rectangle3d(Plane.WorldXY, Heron.Convert.ToXYZ(extPTmin), Heron.Convert.ToXYZ(extPTmax)); recs.Append(new GH_Rectangle(rec), new GH_Path(iLayer)); ///Loop through input boundaries for (int i = 0; i < boundary.Count; i++) { OSGeo.OGR.FeatureDefn def = layer.GetLayerDefn(); ///Get the field names List <string> fieldnames = new List <string>(); for (int iAttr = 0; iAttr < def.GetFieldCount(); iAttr++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iAttr); fnames.Append(new GH_String(fdef.GetNameRef()), new GH_Path(i, iLayer)); } ///Check if boundary is contained in extent if (!rec.IsValid || ((rec.Height == 0) && (rec.Width == 0))) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "One or more vector datasource bounds are not valid."); OSGeo.OGR.Feature feat; int m = 0; while ((feat = layer.GetNextFeature()) != null) { ///Loop through field values for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, iLayer, m)); fdef.Dispose(); } m++; feat.Dispose(); } } else if (boundary[i] == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Clipping boundary " + i + " not set."); } else if (!boundary[i].IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Clipping boundary " + i + " is not valid."); } else if (rec.IsValid && Curve.PlanarClosedCurveRelationship(rec.ToNurbsCurve(), boundary[i], Plane.WorldXY, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance) == RegionContainment.Disjoint) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "One or more boundaries may be outside the bounds of the vector datasource."); } else { ///Create bounding box for clipping geometry Point3d min = Heron.Convert.ToWGS(boundary[i].GetBoundingBox(true).Min); Point3d max = Heron.Convert.ToWGS(boundary[i].GetBoundingBox(true).Max); double[] minpT = new double[3]; double[] maxpT = new double[3]; minpT[0] = min.X; minpT[1] = min.Y; minpT[2] = min.Z; maxpT[0] = max.X; maxpT[1] = max.Y; maxpT[2] = max.Z; revTransform.TransformPoint(minpT); revTransform.TransformPoint(maxpT); ///Convert to OGR geometry ///TODO: add conversion from GH geometry to OGR to Convert class OSGeo.OGR.Geometry ebbox = OSGeo.OGR.Geometry.CreateFromWkt("POLYGON((" + minpT[0] + " " + minpT[1] + ", " + minpT[0] + " " + maxpT[1] + ", " + maxpT[0] + " " + maxpT[1] + ", " + maxpT[0] + " " + minpT[1] + ", " + minpT[0] + " " + minpT[1] + "))"); ///Clip Shapefile ///http://pcjericks.github.io/py-gdalogr-cookbook/vector_layers.html ///TODO: allow for polyline/curve as clipper, not just bounding box OSGeo.OGR.Layer clipped_layer = layer; clipped_layer.SetSpatialFilter(ebbox); ///Loop through geometry OSGeo.OGR.Feature feat; def = clipped_layer.GetLayerDefn(); int m = 0; while ((feat = clipped_layer.GetNextFeature()) != null) { OSGeo.OGR.Geometry geom = feat.GetGeometryRef(); OSGeo.OGR.Geometry sub_geom; ///reproject geometry to WGS84 ///TODO: look into using the SetCRS global variable here geom.Transform(coordTransform); if (feat.GetGeometryRef() != null) { ///Start get points if open polylines and points for (int gpc = 0; gpc < geom.GetPointCount(); gpc++) { ///Loop through geometry points double[] pT = new double[3]; pT[0] = geom.GetX(gpc); pT[1] = geom.GetY(gpc); pT[2] = geom.GetZ(gpc); if (Double.IsNaN(geom.GetZ(gpc))) { pT[2] = 0; } //coordTransform.TransformPoint(pT); Point3d pt3D = new Point3d(); pt3D.X = pT[0]; pt3D.Y = pT[1]; pt3D.Z = pT[2]; gset.Append(new GH_Point(Heron.Convert.ToXYZ(pt3D)), new GH_Path(i, iLayer, m)); ///End loop through geometry points /// Get Feature Values if (fset.PathExists(new GH_Path(i, iLayer, m))) { fset.get_Branch(new GH_Path(i, iLayer, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, iLayer, m)); } else { fset.Append(new GH_String("null"), new GH_Path(i, iLayer, m)); } } ///End Get Feature Values } ///End getting points if open polylines or points ///Start getting points if closed polylines and multipolygons for (int gi = 0; gi < geom.GetGeometryCount(); gi++) { sub_geom = geom.GetGeometryRef(gi); OSGeo.OGR.Geometry subsub_geom; List <Point3d> geom_list = new List <Point3d>(); ///trouble getting all points. this is a troubleshoot ///gset.Append(new GH_Point(new Point3d(0, 0, sub_geom.GetGeometryCount())), new GH_Path(i, iLayer, m, gi)); if (sub_geom.GetGeometryCount() > 0) { for (int n = 0; n < sub_geom.GetGeometryCount(); n++) { subsub_geom = sub_geom.GetGeometryRef(n); for (int ptnum = 0; ptnum < subsub_geom.GetPointCount(); ptnum++) { ///Loop through geometry points double[] pT = new double[3]; pT[0] = subsub_geom.GetX(ptnum); pT[1] = subsub_geom.GetY(ptnum); pT[2] = subsub_geom.GetZ(ptnum); Point3d pt3D = new Point3d(); pt3D.X = pT[0]; pt3D.Y = pT[1]; pt3D.Z = pT[2]; gset.Append(new GH_Point(Heron.Convert.ToXYZ(pt3D)), new GH_Path(i, iLayer, m, gi, n)); ///End loop through geometry points } subsub_geom.Dispose(); } } else { for (int ptnum = 0; ptnum < sub_geom.GetPointCount(); ptnum++) { ///Loop through geometry points double[] pT = new double[3]; pT[0] = sub_geom.GetX(ptnum); pT[1] = sub_geom.GetY(ptnum); pT[2] = sub_geom.GetZ(ptnum); Point3d pt3D = new Point3d(); pt3D.X = pT[0]; pt3D.Y = pT[1]; pt3D.Z = pT[2]; gset.Append(new GH_Point(Heron.Convert.ToXYZ(pt3D)), new GH_Path(i, iLayer, m, gi)); ///End loop through geometry points } } sub_geom.Dispose(); /// Get Feature Values if (fset.PathExists(new GH_Path(i, iLayer, m))) { fset.get_Branch(new GH_Path(i, iLayer, m)).Clear(); } for (int iField = 0; iField < feat.GetFieldCount(); iField++) { OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iField); if (feat.IsFieldSet(iField)) { fset.Append(new GH_String(feat.GetFieldAsString(iField)), new GH_Path(i, iLayer, m)); } else { fset.Append(new GH_String("null"), new GH_Path(i, iLayer, m)); } } ///End Get Feature Values } //m++; } m++; feat.Dispose(); } ///end while loop through features } } //end loop through boundaries layer.Dispose(); }///end loop through layers ds.Dispose(); DA.SetDataTree(0, layname); DA.SetDataTree(1, fcs); DA.SetDataTree(2, recs); DA.SetDataTree(3, sRefs); DA.SetDataTree(4, fnames); DA.SetDataTree(5, fset); DA.SetDataTree(6, gset); }