protected override void SolveInstance(IGH_DataAccess DA) { GH_Structure <GH_Brep> breps = null; GH_Structure <GH_Brep> cutters = null; //Brep brep = null; //List<Brep> cutters = new List<Brep>(); if (!DA.GetDataTree("Brep", out breps)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Invalid Brep input."); return; } if (!DA.GetDataTree("Cutters", out cutters)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Invalid cutter input."); return; } GH_Structure <GH_Brep> resTree = new GH_Structure <GH_Brep>(); foreach (var path in breps.Paths) { resTree.EnsurePath(path); } List <string> errors = new List <string>(); Parallel.For(0, breps.Paths.Count, index => { GH_Path path = breps.Paths[index]; if (cutters.PathExists(path) && breps[path].Count > 0) { resTree[path].Add(new GH_Brep(breps[path][0].Value.Cut( cutters[path].Select(x => x.Value)))); } else if (cutters.PathCount == 1 && breps[path].Count > 0) // Handle a single list of cutters { try { if (cutters[0].Count > 0 && breps[path][0] != null) { resTree[path].Add(new GH_Brep(breps[path][0].Value.Cut( cutters[cutters.Paths[0]].Select(x => x.Value)))); } } catch (Exception ex) { errors.Add(ex.Message); } } else { resTree[path].AddRange(breps[path]); } }); DA.SetDataTree(0, resTree); DA.SetDataList("Errors", errors); }
public override void DoWork(Action <string, double> ReportProgress, Action Done) { Parent.Message = "Extending..."; var path = new GH_Path(iteration); if (valueTree.PathExists(path)) { var values = valueTree.get_Branch(path) as List <IGH_Goo>; // Input is a list of values. Assign them directly if (keys.Count != values?.Count) { Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Key and Value lists are not the same length."); Done(); } AssignToObject(@base, keys, values); } else if (valueTree.Branches.Count == 1) { var values = valueTree.Branches[0]; if (keys.Count != values.Count) { Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Key and Value lists are not the same length."); Done(); } // Input is just one list, so use it. AssignToObject(@base, keys, values); } else { // Input is a tree, meaning it's values are either lists or trees. var subTree = Utilities.GetSubTree(valueTree, path); var index = 0; keys.ForEach(key => { var subPath = new GH_Path(index); if (subTree.PathExists(subPath)) { // Value is a list, convert and assign. var list = subTree.get_Branch(subPath) as List <IGH_Goo>; if (list?.Count > 0) { @base[key] = list.Select(goo => Utilities.TryConvertItemToSpeckle(goo, Converter)).ToList(); } ; } else { // TODO: Handle tree conversions Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Cannot handle trees yet"); } index++; }); } Done(); }
protected override void SolveInstance(IGH_DataAccess DA) { // Initialize local variables var valueTree = new GH_Structure <IGH_Goo>(); var keys = new List <string>(); // Get data from inputs if (!DA.GetDataList(0, keys)) { return; } if (!DA.GetDataTree(1, out valueTree)) { return; } // Create a path from the current iteration var searchPath = new GH_Path(DA.Iteration); // Grab the corresponding subtree from the value input tree. var subTree = Utilities.GetSubTree(valueTree, searchPath); Base speckleObj = new Base(); // Find the list or subtree belonging to that path if (valueTree.PathExists(searchPath) || valueTree.Paths.Count == 1) { var list = valueTree.Paths.Count == 1 ? valueTree.Branches[0] : valueTree.get_Branch(searchPath); // We got a list of values var ind = 0; keys.ForEach(key => { if (ind < list.Count) { speckleObj[key] = Utilities.TryConvertItemToSpeckle(list[ind], Converter); } ind++; }); } else { // We got a tree of values // Create the speckle object with the specified keys var index = 0; keys.ForEach(key => { var itemPath = new GH_Path(index); //TODO: Grab conversion methods and implement branch handling. var branch = subTree.get_Branch(itemPath); if (branch != null) { List <object> objs = new List <object>(); foreach (var goo in branch) { objs.Add(Utilities.TryConvertItemToSpeckle(goo, Converter)); } if (objs.Count > 0) { speckleObj[key] = objs; } } index++; }); } // Set output DA.SetData(0, new GH_SpeckleBase { Value = speckleObj }); }
public Base DoWork(Base @base, List <string> keys, GH_Structure <IGH_Goo> valueTree) { try { // 👉 Checking for cancellation! if (CancelToken.IsCancellationRequested) { return(null); } // Create a path from the current iteration var searchPath = new GH_Path(RunCount - 1); // Grab the corresponding subtree from the value input tree. var subTree = Utilities.GetSubTree(valueTree, searchPath); // Find the list or subtree belonging to that path if (valueTree.PathExists(searchPath) || valueTree.Paths.Count == 1) { var list = valueTree.Paths.Count == 1 ? valueTree.Branches[0] : valueTree.get_Branch(searchPath); // We got a list of values var ind = 0; var hasErrors = false; keys.ForEach(key => { if (ind < list.Count) { try { if (Converter != null) { @base[key] = Utilities.TryConvertItemToSpeckle(list[ind], Converter); } else { @base[key] = list[ind]; } } catch (Exception e) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message); hasErrors = true; } } ind++; }); if (hasErrors) { @base = null; } } else { // We got a tree of values // Create the speckle object with the specified keys var index = 0; var hasErrors = false; keys.ForEach(key => { var itemPath = new GH_Path(index); var branch = subTree.get_Branch(itemPath); if (branch != null) { var objs = new List <object>(); foreach (var goo in branch) { if (Converter != null) { objs.Add(Utilities.TryConvertItemToSpeckle(goo, Converter)); } else { objs.Add(goo); } } if (objs.Count > 0) { try { @base[key] = objs; } catch (Exception e) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message); hasErrors = true; } } } index++; }); if (hasErrors) { @base = null; } } return(@base); } catch (Exception e) { // If we reach this, something happened that we weren't expecting... Log.CaptureException(e); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Something went terribly wrong... " + e.Message); return(null); } }
protected override void SolveInstance(IGH_DataAccess DA) { List <Curve> boundary = new List <Curve>(); DA.GetDataList <Curve>(0, boundary); string URL = string.Empty; DA.GetData <string>("REST URL", ref URL); if (!URL.EndsWith("/")) { URL = URL + "/"; } string userSRStext = string.Empty; DA.GetData <string>("User Spatial Reference System", ref userSRStext); bool run = false; DA.GetData <bool>("run", ref run); ///GDAL setup RESTful.GdalConfiguration.ConfigureOgr(); ///TODO: implement SetCRS here. ///Option to set CRS here to user-defined. Needs a SetCRS global variable. OSGeo.OSR.SpatialReference userSRS = new OSGeo.OSR.SpatialReference(""); userSRS.SetFromUserInput(userSRStext); int userSRSInt = Int16.Parse(userSRS.GetAuthorityCode(null)); ///Set transform from input spatial reference to Rhino spatial reference OSGeo.OSR.SpatialReference rhinoSRS = new OSGeo.OSR.SpatialReference(""); rhinoSRS.SetWellKnownGeogCS("WGS84"); ///This transform moves and scales the points required in going from userSRS to XYZ and vice versa Transform userSRSToModelTransform = Heron.Convert.GetUserSRSToModelTransform(userSRS); Transform modelToUserSRSTransform = Heron.Convert.GetModelToUserSRSTransform(userSRS); GH_Structure <GH_String> mapquery = new GH_Structure <GH_String>(); GH_Structure <GH_Point> gsetUser = new GH_Structure <GH_Point>(); GH_Structure <IGH_GeometricGoo> gGoo = new GH_Structure <IGH_GeometricGoo>(); GH_Structure <GH_String> fset = new GH_Structure <GH_String>(); GH_Structure <GH_String> fieldnames = new GH_Structure <GH_String>(); for (int i = 0; i < boundary.Count; i++) { GH_Path cpath = new GH_Path(i); BoundingBox bbox = boundary[i].GetBoundingBox(false); bbox.Transform(modelToUserSRSTransform); string restquery = URL + "query?where=&text=&objectIds=&time=&geometry=" + bbox.Min.X + "%2C" + bbox.Min.Y + "%2C" + bbox.Max.X + "%2C" + bbox.Max.Y + "&geometryType=esriGeometryEnvelope&inSR=" + userSRSInt + "&spatialRel=esriSpatialRelIntersects" + "&relationParam=&outFields=*" + "&returnGeometry=true" + "&maxAllowableOffset=" + "&geometryPrecision=" + "&outSR=" + userSRSInt + "&returnIdsOnly=false" + "&returnCountOnly=false" + "&orderByFields=" + "&groupByFieldsForStatistics=&outStatistics=" + "&returnZ=true" + "&returnM=false" + "&gdbVersion=" + "&returnDistinctValues=false" + "&f=json"; mapquery.Append(new GH_String(restquery), cpath); if (run) { //string result = Heron.Convert.HttpToJson(restquery); OSGeo.OGR.DataSource dataSource = OSGeo.OGR.Ogr.Open("ESRIJSON:" + restquery, 0); 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."); } ///Loop through each layer. Likely not any layers in a REST service for (int iLayer = 0; iLayer < dataSource.GetLayerCount(); iLayer++) { OSGeo.OGR.Layer ogrLayer = dataSource.GetLayerByIndex(iLayer); if (ogrLayer == null) { Console.WriteLine($"Couldn't fetch advertised layer {iLayer}"); System.Environment.Exit(-1); } long count = ogrLayer.GetFeatureCount(1); int featureCount = System.Convert.ToInt32(count); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, $"Layer #{iLayer} {ogrLayer.GetName()} has {featureCount} features"); OSGeo.OGR.FeatureDefn def = ogrLayer.GetLayerDefn(); ///Get the field names for (int iAttr = 0; iAttr < def.GetFieldCount(); iAttr++) { ///TODO: Look into GetAlternativeNameRef() for field aliases (more readable) available in GDAL 3.2 OSGeo.OGR.FieldDefn fdef = def.GetFieldDefn(iAttr); fieldnames.Append(new GH_String(fdef.GetNameRef()), new GH_Path(i, iLayer)); } ///Loop through geometry OSGeo.OGR.Feature feat; def = ogrLayer.GetLayerDefn(); int m = 0; while ((feat = ogrLayer.GetNextFeature()) != null) { 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 (geomUser.GetSpatialReference() == null) { geomUser.AssignSpatialReference(userSRS); } geomUser.TransformTo(userSRS); if (feat.GetGeometryRef() != null) { if (!pointsOnly) { ///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 } else { ///Start get points if open polylines and points for (int gpc = 0; gpc < geomUser.GetPointCount(); gpc++) { ///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); gGoo.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 < geomUser.GetGeometryCount(); gi++) { sub_geomUser = geomUser.GetGeometryRef(gi); OSGeo.OGR.Geometry subsub_geomUser; if (sub_geomUser.GetGeometryCount() > 0) { for (int n = 0; n < sub_geomUser.GetGeometryCount(); n++) { subsub_geomUser = sub_geomUser.GetGeometryRef(n); for (int ptnum = 0; ptnum < subsub_geomUser.GetPointCount(); ptnum++) { ///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); gGoo.Append(new GH_Point(pt3DUser), new GH_Path(i, iLayer, m, gi, n)); ///End loop through geometry points } subsub_geomUser.Dispose(); } } else { for (int ptnum = 0; ptnum < sub_geomUser.GetPointCount(); ptnum++) { ///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); gGoo.Append(new GH_Point(pt3DUser), new GH_Path(i, iLayer, m, gi)); ///End loop through geometry points } } 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 } ///End closed polygons and multipolygons } ///End points only } m++; geomUser.Dispose(); feat.Dispose(); }///end while loop through features } dataSource.Dispose(); } } ///Not the most elegant way of setting outputs only on run if (run) { DA.SetDataList(0, fieldnames.get_Branch(0)); DA.SetDataTree(1, fset); DA.SetDataTree(2, gGoo); } DA.SetDataTree(3, mapquery); }
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); }
/// <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 <GH_Point> ptsTree = new GH_Structure <GH_Point>(); GH_Structure <GH_Vector> velTree = new GH_Structure <GH_Vector>(); GH_Structure <GH_Number> massTree = new GH_Structure <GH_Number>(); GH_Structure <GH_Boolean> scTree = new GH_Structure <GH_Boolean>(); GH_Structure <GH_Boolean> ifTree = new GH_Structure <GH_Boolean>(); GH_Structure <GH_Integer> giTree = new GH_Structure <GH_Integer>(); DA.GetDataTree(0, out ptsTree); DA.GetDataTree(1, out velTree); DA.GetDataTree(2, out massTree); DA.GetDataTree(3, out scTree); DA.GetDataTree(4, out ifTree); DA.GetDataTree(5, out giTree); #region clean up etc if (!ptsTree.IsEmpty) { ptsTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!velTree.IsEmpty) { ptsTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!massTree.IsEmpty) { ptsTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!scTree.IsEmpty) { ptsTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!ifTree.IsEmpty) { ptsTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!giTree.IsEmpty) { ptsTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (ptsTree.Branches.Count == 1) { GH_Structure <GH_Point> pT = new GH_Structure <GH_Point>(); pT.AppendRange(ptsTree.Branches[0], new GH_Path(0)); ptsTree = pT; } if (velTree.Branches.Count == 1) { GH_Structure <GH_Vector> pT = new GH_Structure <GH_Vector>(); pT.AppendRange(velTree.Branches[0], new GH_Path(0)); velTree = pT; } if (massTree.Branches.Count == 1) { GH_Structure <GH_Number> mT = new GH_Structure <GH_Number>(); mT.AppendRange(massTree.Branches[0], new GH_Path(0)); massTree = mT; } if (scTree.Branches.Count == 1) { GH_Structure <GH_Boolean> mT = new GH_Structure <GH_Boolean>(); mT.AppendRange(scTree.Branches[0], new GH_Path(0)); scTree = mT; } if (ifTree.Branches.Count == 1) { GH_Structure <GH_Boolean> mT = new GH_Structure <GH_Boolean>(); mT.AppendRange(ifTree.Branches[0], new GH_Path(0)); ifTree = mT; } if (giTree.Branches.Count == 1) { GH_Structure <GH_Integer> mT = new GH_Structure <GH_Integer>(); mT.AppendRange(giTree.Branches[0], new GH_Path(0)); giTree = mT; } #endregion List <FlexParticle> parts = new List <FlexParticle>(); for (int i = 0; i < ptsTree.PathCount; i++) { GH_Path path = new GH_Path(i); for (int j = 0; j < ptsTree.get_Branch(path).Count; j++) { float[] pos = new float[3] { (float)ptsTree.get_DataItem(path, j).Value.X, (float)ptsTree.get_DataItem(path, j).Value.Y, (float)ptsTree.get_DataItem(path, j).Value.Z }; float[] vel = new float[3] { 0.0f, 0.0f, 0.0f }; if (velTree.PathExists(path)) { if (velTree.get_Branch(path).Count > j) { vel = new float[3] { (float)velTree.get_DataItem(path, j).Value.X, (float)velTree.get_DataItem(path, j).Value.Y, (float)velTree.get_DataItem(path, j).Value.Z } } ; else { vel = new float[3] { (float)velTree.get_DataItem(path, 0).Value.X, (float)velTree.get_DataItem(path, 0).Value.Y, (float)velTree.get_DataItem(path, 0).Value.Z } }; } float iM = 1.0f; if (massTree.PathExists(path)) { if (massTree.get_Branch(path).Count > j) { iM = 1.0f / (float)massTree.get_DataItem(path, j).Value; } else { iM = 1.0f / (float)massTree.get_DataItem(path, 0).Value; } } bool sc = false; if (scTree.PathExists(path)) { if (scTree.get_Branch(path).Count > j) { sc = scTree.get_DataItem(path, j).Value; } else { sc = scTree.get_DataItem(path, 0).Value; } } bool isf = false; if (ifTree.PathExists(path)) { if (ifTree.get_Branch(path).Count > j) { isf = ifTree.get_DataItem(path, j).Value; } else { isf = ifTree.get_DataItem(path, 0).Value; } } int gi = i; if (giTree.PathExists(path)) { if (giTree.get_Branch(path).Count > j) { gi = giTree.get_DataItem(path, j).Value; } else { gi = giTree.get_DataItem(path, 0).Value; } } parts.Add(new FlexParticle(pos, vel, iM, sc, isf, gi, true)); } } DA.SetDataList(0, parts); }
public override void DoWork(Action <string, double> ReportProgress, Action Done) { try { Parent.Message = "Extending..."; var path = new GH_Path(iteration); if (valueTree.PathExists(path)) { var values = valueTree.get_Branch(path) as List <IGH_Goo>; // Input is a list of values. Assign them directly if (keys.Count != values?.Count) { Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Key and Value lists are not the same length."); Parent.Message = "Error"; return; } AssignToObject(@base, keys, values); } else if (valueTree.Branches.Count == 1) { var values = valueTree.Branches[0]; if (keys.Count != values.Count) { Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Key and Value lists are not the same length."); Parent.Message = "Error"; return; } // Input is just one list, so use it. AssignToObject(@base, keys, values); } else { // Input is a tree, meaning it's values are either lists or trees. var subTree = Utilities.GetSubTree(valueTree, path); var index = 0; var foundTree = false; keys.ForEach(key => { var subPath = new GH_Path(index); if (subTree.PathExists(subPath)) { // Value is a list, convert and assign. var list = subTree.get_Branch(subPath) as List <IGH_Goo>; if (list?.Count > 0) { try { @base[key] = list.Select(goo => Utilities.TryConvertItemToSpeckle(goo, Converter)).ToList(); } catch (Exception e) { Console.WriteLine(e); } } ; } else { foundTree = true; } index++; }); if (foundTree) { // TODO: Handle tree conversions Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Cannot handle trees yet"); Parent.Message = "Error"; } } Done(); } catch (Exception e) { // If we reach this, something happened that we weren't expecting... Log.CaptureException(e); Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Something went terribly wrong... " + e.Message); Parent.Message = "Error"; } }
/// <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) { double anchorThreshold = 0.01; List <Mesh> meshes = new List <Mesh>(); GH_Structure <GH_Vector> velTree = new GH_Structure <GH_Vector>(); GH_Structure <GH_Number> massTree = new GH_Structure <GH_Number>(); List <double> stretchStiffness = new List <double>(); List <double> bendStiffness = new List <double>(); List <double> preTension = new List <double>(); GH_Structure <IGH_Goo> anchorTree = new GH_Structure <IGH_Goo>(); List <int> groupIndexList = new List <int>(); List <Cloth> cloths = new List <Cloth>(); DA.GetDataList(0, meshes); DA.GetDataTree(1, out velTree); DA.GetDataTree(2, out massTree); DA.GetDataList(3, stretchStiffness); DA.GetDataList(4, bendStiffness); DA.GetDataList(5, preTension); DA.GetDataTree(6, out anchorTree); DA.GetDataList(7, groupIndexList); #region simplify trees and if(branch.Count == 1) make sure everything sits in path {0} if (!velTree.IsEmpty) { velTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!massTree.IsEmpty) { massTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!anchorTree.IsEmpty) { anchorTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (velTree.Branches.Count == 1) { GH_Structure <GH_Vector> vT = new GH_Structure <GH_Vector>(); vT.AppendRange(velTree.Branches[0], new GH_Path(0)); velTree = vT; } if (massTree.Branches.Count == 1) { GH_Structure <GH_Number> mT = new GH_Structure <GH_Number>(); mT.AppendRange(massTree.Branches[0], new GH_Path(0)); massTree = mT; } if (anchorTree.Branches.Count == 1) { GH_Structure <IGH_Goo> aT = new GH_Structure <IGH_Goo>(); aT.AppendRange(anchorTree.Branches[0], new GH_Path(0)); anchorTree = aT; } #endregion for (int i = 0; i < meshes.Count; i++) { Mesh mesh = new Mesh(); mesh.Vertices.AddVertices(meshes[i].Vertices); mesh.Faces.AddFaces(meshes[i].Faces); GH_Path path = new GH_Path(i); List <float> positions = new List <float>(); List <float> velocities = new List <float>(); List <float> invMasses = new List <float>(); for (int j = 0; j < mesh.Vertices.Count; j++) { positions.Add((float)mesh.Vertices[j].X); positions.Add((float)mesh.Vertices[j].Y); positions.Add((float)mesh.Vertices[j].Z); Vector3d vel = new Vector3d(0.0, 0.0, 0.0); if (velTree.PathExists(path)) { if (velTree.get_Branch(path).Count == 1) { vel = velTree.get_DataItem(path, 0).Value; } else if (velTree.get_Branch(path).Count > j) { vel = velTree.get_DataItem(path, j).Value; } } velocities.Add((float)vel.X); velocities.Add((float)vel.Y); velocities.Add((float)vel.Z); float invMass = 1.0f; if (massTree.PathExists(path)) { if (massTree.get_Branch(path).Count == 1) { invMass = 1.0f / (float)massTree.get_DataItem(path, 0).Value; } else if (massTree.get_Branch(path).Count > j) { invMass = 1.0f / (float)massTree.get_DataItem(path, j).Value; } } invMasses.Add(invMass); } int[] triangles = new int[mesh.Faces.Count * 3]; float[] triangleNormals = new float[mesh.Faces.Count * 3]; mesh.UnifyNormals(); mesh.FaceNormals.ComputeFaceNormals(); for (int j = 0; j < triangles.Length / 3; j++) { triangles[3 * j] = mesh.Faces[j].A; triangles[3 * j + 1] = mesh.Faces[j].B; triangles[3 * j + 2] = mesh.Faces[j].C; triangleNormals[3 * j] = mesh.FaceNormals[j].X; triangleNormals[3 * j + 1] = mesh.FaceNormals[j].Y; triangleNormals[3 * j + 2] = mesh.FaceNormals[j].Z; } List <int> anchorIndices = new List <int>(); if (anchorTree.PathExists(path)) { foreach (IGH_Goo ao in anchorTree.get_Branch(path)) { string aS = ""; int aI = -1; Point3d aP; if (ao.CastTo <Point3d>(out aP)) { for (int j = 0; j < positions.Count / 3; j++) { if (Util.SquareDistance(new Point3d(positions[3 * j], positions[3 * j + 1], positions[3 * j + 2]), aP) < anchorThreshold * anchorThreshold) { anchorIndices.Add(j); break; } } } else if (ao.CastTo <int>(out aI)) { anchorIndices.Add(aI); } else if (ao.CastTo <string>(out aS)) { anchorIndices.Add(int.Parse(aS)); } } } float preTens = (float)preTension[0];; if (preTension.Count > i) { preTens = (float)preTension[i]; } float sStiffness = (float)stretchStiffness[0]; if (stretchStiffness.Count > i) { sStiffness = (float)stretchStiffness[i]; } float bStiffness = (float)bendStiffness[0]; if (bendStiffness.Count > i) { bStiffness = (float)bendStiffness[i]; } Cloth cloth = new Cloth(positions.ToArray(), velocities.ToArray(), invMasses.ToArray(), triangles, triangleNormals, sStiffness, bStiffness, preTens, anchorIndices.ToArray(), groupIndexList[i]); cloth.Mesh = mesh; cloths.Add(cloth); } DA.SetDataList(0, cloths); }
public override void DoWork(Action <string, double> ReportProgress, Action Done) { // 👉 Checking for cancellation! if (CancellationToken.IsCancellationRequested) { return; } Parent.Message = "Creating..."; // Create a path from the current iteration var searchPath = new GH_Path(iteration); // Grab the corresponding subtree from the value input tree. var subTree = Utilities.GetSubTree(valueTree, searchPath); speckleObj = new Base(); // Find the list or subtree belonging to that path if (valueTree.PathExists(searchPath) || valueTree.Paths.Count == 1) { var list = valueTree.Paths.Count == 1 ? valueTree.Branches[0] : valueTree.get_Branch(searchPath); // We got a list of values var ind = 0; keys.ForEach(key => { if (ind < list.Count) { speckleObj[key] = Utilities.TryConvertItemToSpeckle(list[ind], Converter); } ind++; }); } else { // We got a tree of values // Create the speckle object with the specified keys var index = 0; keys.ForEach(key => { var itemPath = new GH_Path(index); var branch = subTree.get_Branch(itemPath); if (branch != null) { var objs = new List <object>(); foreach (var goo in branch) { objs.Add(Utilities.TryConvertItemToSpeckle(goo, Converter)); } if (objs.Count > 0) { speckleObj[key] = objs; } } index++; }); } // --> Report progress if necessary // ReportProgress(Id, percentage); // Call Done() to signal it's finished. Done(); }
/// <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 <GH_Curve> crvs = new GH_Structure <GH_Curve>(); DA.GetDataTree <GH_Curve>(0, out crvs); GH_Structure <GH_Number> height = new GH_Structure <GH_Number>(); DA.GetDataTree <GH_Number>(1, out height); double tol = DocumentTolerance(); //reserve one processor for GUI //create a dictionary that works in parallel var mPatchTree = new System.Collections.Concurrent.ConcurrentDictionary <GH_Path, GH_Mesh>(); //Multi-threading the loop System.Threading.Tasks.Parallel.ForEach(crvs.Paths, new System.Threading.Tasks.ParallelOptions { MaxDegreeOfParallelism = totalMaxConcurrancy }, pth => { List <Curve> branchCrvs = new List <Curve>(); double offset = 0; if (crvs.get_Branch(pth).Count > 0) { foreach (var ghCrv in crvs.get_Branch(pth)) { Curve c = null; GH_Convert.ToCurve(ghCrv, ref c, 0); if (extrudeDir == "Extrude Z") { ///Ensure boundary winds clockwise if (c.ClosedCurveOrientation(Vector3d.ZAxis) < 0) { c.Reverse(); } } branchCrvs.Add(c); } ///Convert first curve in branch to polyline ///Don't know why the boundary parameter can't be a Curve if the holes are allowed to be Curves Polyline pL = null; branchCrvs[0].TryGetPolyline(out pL); branchCrvs.RemoveAt(0); if (!pL.IsClosed) { pL.Add(pL[0]); } ///Check validity of pL if (!pL.IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Outer boundary curve could not be converted to polyline or is invalid"); } ///The magic found here: ///https://discourse.mcneel.com/t/mesh-with-holes-from-polylines-in-rhinowip-to-c/45589 Mesh mPatch = Mesh.CreatePatch(pL, tol, null, branchCrvs, null, null, true, 1); mPatch.Ngons.AddPlanarNgons(tol); //mPatch.UnifyNormals(); mPatch.FaceNormals.ComputeFaceNormals(); mPatch.Normals.ComputeNormals(); mPatch.Compact(); if (height.PathExists(pth)) { if (height.get_Branch(pth).Count > 0) { GH_Convert.ToDouble(height.get_Branch(pth)[0], out offset, 0); if (extrudeDir == "Extrude Z") { mPatch = mPatch.Offset(offset, true, Vector3d.ZAxis); } else { mPatch.Flip(true, true, true); mPatch = mPatch.Offset(offset, true); } } } else if (height.get_FirstItem(true) != null) { GH_Convert.ToDouble(height.get_FirstItem(true), out offset, 0); if (extrudeDir == "Extrude Z") { mPatch = mPatch.Offset(offset, true, Vector3d.ZAxis); } else { mPatch.Flip(true, true, true); mPatch = mPatch.Offset(offset, true); } } else { } if (mPatch != null) { if (mPatch.SolidOrientation() < 0) { mPatch.Flip(true, true, true); } } mPatchTree[pth] = new GH_Mesh(mPatch); } }); ///End of multi-threaded loop ///Convert dictionary to regular old data tree GH_Structure <GH_Mesh> mTree = new GH_Structure <GH_Mesh>(); foreach (KeyValuePair <GH_Path, GH_Mesh> m in mPatchTree) { mTree.Append(m.Value, m.Key); } DA.SetDataTree(0, mTree); }
public override void DoWork(Action <string, double> ReportProgress, Action Done) { try { // 👉 Checking for cancellation! if (CancellationToken.IsCancellationRequested) { return; } Parent.Message = "Creating..."; // Create a path from the current iteration var searchPath = new GH_Path(iteration); // Grab the corresponding subtree from the value input tree. var subTree = Utilities.GetSubTree(valueTree, searchPath); speckleObj = new Base(); // Find the list or subtree belonging to that path if (valueTree.PathExists(searchPath) || valueTree.Paths.Count == 1) { var list = valueTree.Paths.Count == 1 ? valueTree.Branches[0] : valueTree.get_Branch(searchPath); // We got a list of values var ind = 0; var hasErrors = false; keys.ForEach(key => { if (ind < list.Count) { try { speckleObj[key] = Utilities.TryConvertItemToSpeckle(list[ind], Converter); } catch (Exception e) { Console.WriteLine(e); Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message); Parent.Message = "Error"; hasErrors = true; } } ind++; }); if (hasErrors) { return; } } else { // We got a tree of values // Create the speckle object with the specified keys var index = 0; keys.ForEach(key => { var itemPath = new GH_Path(index); var branch = subTree.get_Branch(itemPath); if (branch != null) { var objs = new List <object>(); foreach (var goo in branch) { objs.Add(Utilities.TryConvertItemToSpeckle(goo, Converter)); } if (objs.Count > 0) { try { speckleObj[key] = objs; } catch (Exception e) { Console.WriteLine(e); Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message); return; } } } index++; }); } // --> Report progress if necessary // ReportProgress(Id, percentage); // Call Done() to signal it's finished. Done(); } catch (Exception e) { // If we reach this, something happened that we weren't expecting... Log.CaptureException(e); Parent.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Something went terribly wrong... " + e.Message); Parent.Message = "Error"; } }
/// <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) { double anchorThreshold = 0.01; double pointDuplicateThreshold = 0.01; bool isSheetMesh = false; GH_Structure <IGH_Goo> springTree = new GH_Structure <IGH_Goo>(); GH_Structure <GH_Vector> velTree = new GH_Structure <GH_Vector>(); GH_Structure <GH_Number> massTree = new GH_Structure <GH_Number>(); GH_Structure <GH_Number> lengthTree = new GH_Structure <GH_Number>(); GH_Structure <GH_Number> stiffnessTree = new GH_Structure <GH_Number>(); List <double> sheetStiffeningList = new List <double>(); GH_Structure <IGH_Goo> anchorTree = new GH_Structure <IGH_Goo>(); List <bool> selfCollisionList = new List <bool>(); List <int> groupIndexList = new List <int>(); List <SpringSystem> springSystems = new List <SpringSystem>(); DA.GetDataTree(0, out springTree); DA.GetDataTree(1, out velTree); DA.GetDataTree(2, out massTree); DA.GetDataTree(3, out lengthTree); DA.GetDataTree(4, out stiffnessTree); DA.GetDataList(5, sheetStiffeningList); DA.GetDataList(6, selfCollisionList); DA.GetDataTree(7, out anchorTree); DA.GetDataList(8, groupIndexList); #region simplify trees and if(branch.Count == 1) make sure everything sits in path {0} if (!springTree.IsEmpty) { springTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!velTree.IsEmpty) { velTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!massTree.IsEmpty) { massTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!lengthTree.IsEmpty) { lengthTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!stiffnessTree.IsEmpty) { stiffnessTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (!anchorTree.IsEmpty) { anchorTree.Simplify(GH_SimplificationMode.CollapseAllOverlaps); } if (springTree.Branches.Count != groupIndexList.Count || springTree.Branches.Count != selfCollisionList.Count) { throw new Exception("Line tree doesn't fit either groupIndices count or selfCollision count!"); } if (springTree.Branches.Count == 1) { GH_Structure <IGH_Goo> lT = new GH_Structure <IGH_Goo>(); lT.AppendRange(springTree.Branches[0], new GH_Path(0)); springTree = lT; } if (velTree.Branches.Count == 1) { GH_Structure <GH_Vector> vT = new GH_Structure <GH_Vector>(); vT.AppendRange(velTree.Branches[0], new GH_Path(0)); velTree = vT; } if (massTree.Branches.Count == 1) { GH_Structure <GH_Number> mT = new GH_Structure <GH_Number>(); mT.AppendRange(massTree.Branches[0], new GH_Path(0)); massTree = mT; } if (lengthTree.Branches.Count == 1) { GH_Structure <GH_Number> leT = new GH_Structure <GH_Number>(); leT.AppendRange(lengthTree.Branches[0], new GH_Path(0)); lengthTree = leT; } if (stiffnessTree.Branches.Count == 1) { GH_Structure <GH_Number> sT = new GH_Structure <GH_Number>(); sT.AppendRange(stiffnessTree.Branches[0], new GH_Path(0)); stiffnessTree = sT; } if (anchorTree.Branches.Count == 1) { GH_Structure <IGH_Goo> aT = new GH_Structure <IGH_Goo>(); aT.AppendRange(anchorTree.Branches[0], new GH_Path(0)); anchorTree = aT; } #endregion for (int branchIndex = 0; branchIndex < springTree.Branches.Count; branchIndex++) { List <float> positions = new List <float>(); List <float> velocities = new List <float>(); List <float> invMasses = new List <float>(); List <int> springPairIndices = new List <int>(); List <float> targetLengths = new List <float>(); List <float> stiffnesses = new List <float>(); List <int> anchorIndices = new List <int>(); List <float> initialLengths = new List <float>(); //just for info GH_Path path = new GH_Path(branchIndex); List <Line> lines = new List <Line>(); Curve c; Line l; Mesh mesh = new Mesh(); foreach (IGH_Goo springObject in springTree.get_Branch(path)) { if (springObject.CastTo <Mesh>(out mesh)) { break; } else if (springObject.CastTo <Curve>(out c)) { if (c.IsPolyline()) { Polyline pl; c.TryGetPolyline(out pl); for (int i = 0; i < pl.SegmentCount; i++) { lines.Add(pl.SegmentAt(i)); } AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Polyline in branch " + branchIndex + " was split into its segments!"); } else { lines.Add(new Line(c.PointAtStart, c.PointAtEnd)); } } else if (springObject.CastTo <Line>(out l)) { lines.Add(l); } } #region isMesh if (mesh != null && mesh.IsValid) { mesh.Vertices.CombineIdentical(true, true); mesh.Weld(Math.PI); mesh.UnifyNormals(); Rhino.Geometry.Collections.MeshTopologyVertexList mv = mesh.TopologyVertices; Rhino.Geometry.Collections.MeshTopologyEdgeList me = mesh.TopologyEdges; //Add everything related to particles for (int i = 0; i < mv.Count; i++) { //add position positions.Add(mv[i].X); positions.Add(mv[i].Y); positions.Add(mv[i].Z); //add velocity Vector3d vel = new Vector3d(0.0, 0.0, 0.0); if (velTree.PathExists(path)) { if (velTree.get_Branch(path).Count > i) { vel = velTree.get_DataItem(path, i).Value; } else { vel = velTree.get_DataItem(path, 0).Value; } } velocities.Add((float)vel.X); velocities.Add((float)vel.Y); velocities.Add((float)vel.Z); //add inverse mass float invMass = 1.0f; if (massTree.PathExists(path)) { if (massTree.get_Branch(path).Count > i) { invMass = 1.0f / (float)massTree.get_DataItem(path, i).Value; } else { invMass = 1.0f / (float)massTree.get_DataItem(path, 0).Value; } } invMasses.Add(invMass); } //Add everything related to spring lines for (int i = 0; i < me.Count; i++) { springPairIndices.Add(me.GetTopologyVertices(i).I); springPairIndices.Add(me.GetTopologyVertices(i).J); //add length float length = (float)me.EdgeLine(i).Length; initialLengths.Add(length); if (lengthTree.PathExists(path)) { float temp = 0.0f; if (lengthTree.get_Branch(path).Count > i) { temp = (float)lengthTree.get_DataItem(path, i).Value; } else { temp = (float)lengthTree.get_DataItem(path, 0).Value; } if (temp < 0.0) { length *= -temp; } else { length = temp; } } targetLengths.Add(length); //add stiffness float stiffness = 1.0f; if (stiffnessTree.PathExists(path)) { if (stiffnessTree.get_Branch(path).Count > i) { stiffness = (float)stiffnessTree.get_DataItem(path, i).Value; } else { stiffness = (float)stiffnessTree.get_DataItem(path, 0).Value; } } stiffnesses.Add(stiffness); List <Line> f = new List <Line>(); if (sheetStiffeningList.Count > branchIndex && sheetStiffeningList[branchIndex] > 0.0) { isSheetMesh = true; int[] adjFaceInd = me.GetConnectedFaces(i); if (adjFaceInd.Length == 2) { f.Add(me.EdgeLine(i)); MeshFace faceA = mesh.Faces[adjFaceInd[0]]; MeshFace faceB = mesh.Faces[adjFaceInd[1]]; if (faceA.IsTriangle && faceB.IsTriangle) { List <int> allInds = new List <int> { faceA.A, faceA.B, faceA.C, faceB.A, faceB.B, faceB.C }; int[] uniques = new int[6] { 0, 0, 0, 0, 0, 0 }; for (int h = 0; h < 6; h++) { for (int g = 0; g < 6; g++) { if (allInds[h] == allInds[g]) { uniques[h]++; } } } for (int h = 0; h < 6; h++) { if (uniques[h] == 1) { springPairIndices.Add(mv.TopologyVertexIndex(allInds[h])); stiffnesses.Add((float)(stiffness * sheetStiffeningList[branchIndex])); } } float le = (float)mv[springPairIndices[springPairIndices.Count - 2]].DistanceTo(mv[springPairIndices[springPairIndices.Count - 1]]); targetLengths.Add(le); initialLengths.Add(le); f.Add(new Line(mesh.Vertices[mv.TopologyVertexIndex(springPairIndices[springPairIndices.Count - 1])], mesh.Vertices[mv.TopologyVertexIndex(springPairIndices[springPairIndices.Count - 2])])); } } } } } #endregion #region isLines else if (lines.Count != 0) { List <Line> cleanLineList = new List <Line>(); double ptDuplThrSquared = pointDuplicateThreshold * pointDuplicateThreshold; #region clean up line list List <Line> lHist = new List <Line>(); for (int j = 0; j < lines.Count; j++) { //Clean list from duplicate lines Line lCand = lines[j]; Point3d ptCandA = lCand.From; Point3d ptCandB = lCand.To; bool lineExistsAlready = false; foreach (Line lh in lHist) { Line tempL = new Line(lCand.From, lCand.To); if ((Util.SquareDistance(tempL.From, lh.From) < ptDuplThrSquared && Util.SquareDistance(tempL.To, lh.To) < ptDuplThrSquared) || (Util.SquareDistance(tempL.From, lh.To) < ptDuplThrSquared && Util.SquareDistance(tempL.To, lh.From) < ptDuplThrSquared)) { lineExistsAlready = true; } } //Clean list from too short lines if (!(Util.SquareDistance(ptCandA, ptCandB) < ptDuplThrSquared || lineExistsAlready)) { lHist.Add(lCand); cleanLineList.Add(lCand); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Spring nr. " + j + " in branch " + branchIndex + " is either invalid (too short) or appeared for the second time. It is ignored."); } } #endregion //get velocity and mass for this branch (no mass / velo per particle allowed) List <float> branchDefaultVelocity = new List <float>() { 0.0f, 0.0f, 0.0f }; if (velTree.PathExists(path)) { branchDefaultVelocity = new List <float> { (float)velTree.get_DataItem(path, 0).Value.X, (float)velTree.get_DataItem(path, 0).Value.Y, (float)velTree.get_DataItem(path, 0).Value.Z } } ; float branchDefaultInvMass = 1.0f; if (massTree.PathExists(path)) { branchDefaultInvMass = 1.0f / (float)massTree.get_DataItem(path, 0).Value; } //find unique line start indices List <int> springStartIndices = new List <int>(); int advance = 0; for (int item = 0; item < cleanLineList.Count; item++) { Point3d ptCand = cleanLineList[item].From; int alreadyExistsAs = -1; for (int k = 0; k < positions.Count / 3; k++) { //simple squared distance if (Util.SquareDistance(new Point3d(positions[k * 3], positions[k * 3 + 1], positions[k * 3 + 2]), ptCand) < ptDuplThrSquared) { alreadyExistsAs = k; springStartIndices.Add(alreadyExistsAs); break; } } if (alreadyExistsAs == -1) { positions.Add((float)ptCand.X); positions.Add((float)ptCand.Y); positions.Add((float)ptCand.Z); velocities.AddRange(branchDefaultVelocity); invMasses.Add(branchDefaultInvMass); springStartIndices.Add(advance); advance++; } } //find unique line end indices List <int> springEndIndices = new List <int>(); for (int item = 0; item < cleanLineList.Count; item++) { Point3d ptCand = cleanLineList[item].To; int alreadyExistsAs = -1; for (int k = 0; k < positions.Count / 3; k++) { if (Util.SquareDistance(new Point3d(positions[3 * k], positions[3 * k + 1], positions[3 * k + 2]), ptCand) < ptDuplThrSquared) { alreadyExistsAs = k; springEndIndices.Add(alreadyExistsAs); break; } } if (alreadyExistsAs == -1) { positions.Add((float)ptCand.X); positions.Add((float)ptCand.Y); positions.Add((float)ptCand.Z); velocities.AddRange(branchDefaultVelocity); invMasses.Add(branchDefaultInvMass); springEndIndices.Add(advance); advance++; } } //weave spring start indices and spring end indices together for (int w = 0; w < springStartIndices.Count; w++) { springPairIndices.Add(springStartIndices[w]); springPairIndices.Add(springEndIndices[w]); } //Add everything spring line related... for (int i = 0; i < cleanLineList.Count; i++) { //add length float length = (float)cleanLineList[i].Length; initialLengths.Add(length); if (lengthTree.PathExists(path)) { float temp = 0.0f; if (lengthTree.get_Branch(path).Count > i) { temp = (float)lengthTree.get_DataItem(path, i).Value; } else { temp = (float)lengthTree.get_DataItem(path, 0).Value; } if (temp < 0.0) { length *= -temp; } else { length = temp; } } targetLengths.Add(length); //add stiffness float stiffness = 1.0f; if (stiffnessTree.PathExists(path)) { if (stiffnessTree.get_Branch(path).Count > i) { stiffness = (float)stiffnessTree.get_DataItem(path, i).Value; } else { stiffness = (float)stiffnessTree.get_DataItem(path, 0).Value; } } stiffnesses.Add(stiffness); } } #endregion else { throw new Exception("No valid spring input found in branch " + branchIndex); } //Add anchors if (anchorTree.PathExists(path)) { foreach (IGH_Goo anchorObj in anchorTree.get_Branch(path)) { string ass = ""; int ai = 0; Point3d ap = new Point3d(0.0, 0.0, 0.0); if (anchorObj.CastTo <string>(out ass)) { anchorIndices.Add(int.Parse(ass)); } else if (anchorObj.CastTo <int>(out ai)) { anchorIndices.Add(ai); } else if (anchorObj.CastTo <Point3d>(out ap)) { for (int i = 0; i < positions.Count / 3; i++) { if ((anchorThreshold * anchorThreshold) > Math.Pow((positions[3 * i] - ap.X), 2) + Math.Pow((positions[3 * i + 1] - ap.Y), 2) + Math.Pow((positions[3 * i + 2] - ap.Z), 2)) { anchorIndices.Add(i); } } } } } SpringSystem ss = new SpringSystem(positions.ToArray(), velocities.ToArray(), invMasses.ToArray(), springPairIndices.ToArray(), targetLengths.ToArray(), stiffnesses.ToArray(), selfCollisionList[branchIndex], anchorIndices.ToArray(), groupIndexList[branchIndex]); ss.Mesh = mesh; ss.IsSheetMesh = isSheetMesh; ss.InitialLengths = initialLengths.ToArray(); springSystems.Add(ss); } DA.SetDataList(0, springSystems); }
/// <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) { ///Gather GHA inputs Curve boundary = null; DA.GetData <Curve>(0, ref boundary); string osmFilePath = string.Empty; DA.GetData <string>("OSM Data Location", ref osmFilePath); //string userSRStext = "WGS84"; //DA.GetData<string>(2, ref userSRStext); List <string> filterWords = new List <string>(); DA.GetDataList <string>(2, filterWords); List <string> filterKeyValue = new List <string>(); DA.GetDataList <string>(3, filterKeyValue); Transform xformToMetric = new Transform(scaleToMetric); Transform xformFromMetric = new Transform(scaleFromMetric); ///Declare trees Rectangle3d recs = new Rectangle3d(); GH_Structure <GH_String> fieldNames = new GH_Structure <GH_String>(); GH_Structure <GH_String> fieldValues = new GH_Structure <GH_String>(); GH_Structure <IGH_GeometricGoo> geometryGoo = new GH_Structure <IGH_GeometricGoo>(); GH_Structure <IGH_GeometricGoo> buildingGoo = new GH_Structure <IGH_GeometricGoo>(); Point3d max = new Point3d(); Point3d min = new Point3d(); if (boundary != null) { Point3d maxM = boundary.GetBoundingBox(true).Corner(true, false, true); max = Heron.Convert.XYZToWGS(maxM); Point3d minM = boundary.GetBoundingBox(true).Corner(false, true, true); min = Heron.Convert.XYZToWGS(minM); } /// get extents (why is this not part of OsmSharp?) System.Xml.Linq.XDocument xdoc = System.Xml.Linq.XDocument.Load(osmFilePath); if (xdoc.Root.Element("bounds") != null) { double minlat = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("minlat").Value); double minlon = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("minlon").Value); double maxlat = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("maxlat").Value); double maxlon = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("maxlon").Value); Point3d boundsMin = Heron.Convert.WGSToXYZ(new Point3d(minlon, minlat, 0)); Point3d boundsMax = Heron.Convert.WGSToXYZ(new Point3d(maxlon, maxlat, 0)); recs = new Rectangle3d(Plane.WorldXY, boundsMin, boundsMax); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Cannot determine the extents of the OSM file. A 'bounds' element may not be present in the file. " + "Try turning off clipping in this component's menu."); } using (var fileStreamSource = File.OpenRead(osmFilePath)) { /// create a source. OsmSharp.Streams.XmlOsmStreamSource source = new OsmSharp.Streams.XmlOsmStreamSource(fileStreamSource); /// filter by bounding box OsmSharp.Streams.OsmStreamSource sourceClipped = source; if (clipped) { sourceClipped = source.FilterBox((float)max.X, (float)max.Y, (float)min.X, (float)min.Y, true); } /// create a dictionary of elements OsmSharp.Db.Impl.MemorySnapshotDb sourceMem = new OsmSharp.Db.Impl.MemorySnapshotDb(sourceClipped); /// filter the source var filtered = from osmGeos in sourceClipped where osmGeos.Tags != null select osmGeos; if (filterWords.Any()) { filtered = from osmGeos in filtered where osmGeos.Tags.ContainsAnyKey(filterWords) select osmGeos; } if (filterKeyValue.Any()) { List <Tag> tags = new List <Tag>(); foreach (string term in filterKeyValue) { string[] kv = term.Split(','); Tag tag = new Tag(kv[0], kv[1]); tags.Add(tag); } filtered = from osmGeos in filtered where osmGeos.Tags.Intersect(tags).Any() select osmGeos; } source.Dispose(); /// loop over all objects and count them. int nodes = 0, ways = 0, relations = 0; Dictionary <PolylineCurve, GH_Path> bldgOutlines = new Dictionary <PolylineCurve, GH_Path>(); List <BuildingPart> buildingParts = new List <BuildingPart>(); foreach (OsmSharp.OsmGeo osmGeo in filtered) { //NODES if (osmGeo.Type == OsmGeoType.Node) { OsmSharp.Node n = (OsmSharp.Node)osmGeo; GH_Path nodesPath = new GH_Path(0, nodes); //populate Fields and Values for each node fieldNames.AppendRange(GetKeys(osmGeo), nodesPath); fieldValues.AppendRange(GetValues(osmGeo), nodesPath); //get geometry for node Point3d nPoint = Heron.Convert.WGSToXYZ(new Point3d((double)n.Longitude, (double)n.Latitude, 0)); geometryGoo.Append(new GH_Point(nPoint), nodesPath); //increment nodes nodes++; } //////////////////////////////////////////////////////////// //WAYS if (osmGeo.Type == OsmGeoType.Way) { OsmSharp.Way w = (OsmSharp.Way)osmGeo; GH_Path waysPath = new GH_Path(1, ways); //populate Fields and Values for each way fieldNames.AppendRange(GetKeys(osmGeo), waysPath); fieldValues.AppendRange(GetValues(osmGeo), waysPath); //get polyline geometry for way List <Point3d> wayNodes = new List <Point3d>(); foreach (long j in w.Nodes) { OsmSharp.Node n = (OsmSharp.Node)sourceMem.Get(OsmGeoType.Node, j); wayNodes.Add(Heron.Convert.WGSToXYZ(new Point3d((double)n.Longitude, (double)n.Latitude, 0))); } PolylineCurve pL = new PolylineCurve(wayNodes); if (pL.IsClosed) { //create base surface Brep[] breps = Brep.CreatePlanarBreps(pL, DocumentTolerance()); geometryGoo.Append(new GH_Brep(breps[0]), waysPath); } else { geometryGoo.Append(new GH_Curve(pL), waysPath); } //building massing if ((w.Tags.ContainsKey("building") || w.Tags.ContainsKey("building:part")))// && !w.Tags.ContainsKey("construction")) { if (pL.IsClosed) { ///Populate dictionary for sorting building parts later if (w.Tags.ContainsKey("building")) { bldgOutlines.Add(pL, waysPath); } CurveOrientation orient = pL.ClosedCurveOrientation(Plane.WorldXY); if (orient != CurveOrientation.CounterClockwise) { pL.Reverse(); } ///Move polylines to min height double minHeightWay = GetMinBldgHeight(osmGeo); Vector3d minVec = new Vector3d(0, 0, minHeightWay); //minVec.Transform(xformFromMetric); if (minHeightWay > 0.0) { var minHeightTranslate = Transform.Translation(minVec); pL.Transform(minHeightTranslate); } Vector3d hVec = new Vector3d(0, 0, GetBldgHeight(osmGeo) - minHeightWay); //hVec.Transform(xformFromMetric); Extrusion ex = Extrusion.Create(pL, hVec.Z, true); IGH_GeometricGoo bldgGoo = GH_Convert.ToGeometricGoo(ex); ///Save building parts for sorting later and remove part from geometry goo tree if (w.Tags.ContainsKey("building:part")) { BuildingPart bldgPart = new BuildingPart(pL, bldgGoo, fieldNames[waysPath], fieldValues[waysPath], osmGeo); buildingParts.Add(bldgPart); fieldNames.RemovePath(waysPath); fieldValues.RemovePath(waysPath); geometryGoo.RemovePath(waysPath); ways = ways - 1; } else { buildingGoo.Append(bldgGoo, waysPath); } } } //increment ways ways++; } /////////////////////////////////////////////////////////// //RELATIONS if (osmGeo.Type == OsmGeoType.Relation) { OsmSharp.Relation r = (OsmSharp.Relation)osmGeo; GH_Path relationPath = new GH_Path(2, relations); //populate Fields and Values for each relation fieldNames.AppendRange(GetKeys(osmGeo), relationPath); fieldValues.AppendRange(GetValues(osmGeo), relationPath); List <Curve> pLines = new List <Curve>(); // start members loop for (int mem = 0; mem < r.Members.Length; mem++) { GH_Path memberPath = new GH_Path(2, relations, mem); OsmSharp.RelationMember rMem = r.Members[mem]; OsmSharp.OsmGeo rMemGeo = sourceMem.Get(rMem.Type, rMem.Id); if (rMemGeo != null) { //get geometry for node if (rMemGeo.Type == OsmGeoType.Node) { long memNodeId = rMem.Id; OsmSharp.Node memN = (OsmSharp.Node)sourceMem.Get(rMem.Type, rMem.Id); Point3d memPoint = Heron.Convert.WGSToXYZ(new Point3d((double)memN.Longitude, (double)memN.Latitude, 0)); geometryGoo.Append(new GH_Point(memPoint), memberPath); } //get geometry for way if (rMem.Type == OsmGeoType.Way) { long memWayId = rMem.Id; OsmSharp.Way memWay = (OsmSharp.Way)rMemGeo; //get polyline geometry for way List <Point3d> memNodes = new List <Point3d>(); foreach (long memNodeId in memWay.Nodes) { OsmSharp.Node memNode = (OsmSharp.Node)sourceMem.Get(OsmGeoType.Node, memNodeId); memNodes.Add(Heron.Convert.WGSToXYZ(new Point3d((double)memNode.Longitude, (double)memNode.Latitude, 0))); } PolylineCurve memPolyline = new PolylineCurve(memNodes); geometryGoo.Append(new GH_Curve(memPolyline.ToNurbsCurve()), memberPath); CurveOrientation orient = memPolyline.ClosedCurveOrientation(Plane.WorldXY); if (orient != CurveOrientation.CounterClockwise) { memPolyline.Reverse(); } pLines.Add(memPolyline.ToNurbsCurve()); } //get nested relations if (rMem.Type == OsmGeoType.Relation) { ///not sure if this is needed } } } //end members loop bool allClosed = true; foreach (Curve pc in pLines) { if (!pc.IsClosed) { allClosed = false; } } if (pLines.Count > 0 && allClosed) { ///Move polylines to min height double minHeight = GetMinBldgHeight(osmGeo); if (minHeight > 0.0) { Vector3d minVec = new Vector3d(0, 0, minHeight); //minVec.Transform(xformFromMetric); var minHeightTranslate = Transform.Translation(minVec); for (int i = 0; i < pLines.Count; i++) { pLines[i].Transform(minHeightTranslate); } } ///Create base surface Brep[] breps = Brep.CreatePlanarBreps(pLines, DocumentTolerance()); geometryGoo.RemovePath(relationPath); foreach (Brep b in breps) { geometryGoo.Append(new GH_Brep(b), relationPath); ///Building massing if (r.Tags.ContainsKey("building") || r.Tags.ContainsKey("building:part")) { Vector3d hVec = new Vector3d(0, 0, GetBldgHeight(osmGeo) - minHeight); //hVec.Transform(xformFromMetric); ///Create extrusion from base surface buildingGoo.Append(new GH_Brep(Brep.CreateFromOffsetFace(b.Faces[0], hVec.Z, DocumentTolerance(), false, true)), relationPath); } } } ///Increment relations relations++; } ///End relation loop } ///End filtered loop ///Add building parts to sub-branches under main building for (int partIndex = 0; partIndex < buildingParts.Count; partIndex++) { BuildingPart bldgPart = buildingParts[partIndex]; Point3d partPoint = bldgPart.PartFootprint.PointAtStart; partPoint.Z = 0; bool replaceBuidingMass = false; GH_Path mainBuildingMassPath = new GH_Path(); PolylineCurve massOutline = new PolylineCurve(); bool isRoof = bldgPart.PartOsmGeo.Tags.TryGetValue("roof:shape", out string isRoofString); if (isRoof) { bldgPart.PartGoo = BldgPartToRoof(bldgPart); } foreach (KeyValuePair <PolylineCurve, GH_Path> pair in bldgOutlines) { PointContainment pc = pair.Key.Contains(partPoint, Plane.WorldXY, DocumentTolerance()); if (pc != PointContainment.Outside) { ///Create new sub-branch int numSubBranches = 0; GH_Path partPath = pair.Value.AppendElement(numSubBranches); while (buildingGoo.PathExists(partPath)) { numSubBranches++; partPath = pair.Value.AppendElement(numSubBranches); } ///Add data to sub-branch fieldNames.AppendRange(bldgPart.PartFieldNames, partPath); fieldValues.AppendRange(bldgPart.PartFieldValues, partPath); buildingGoo.Append(bldgPart.PartGoo, partPath); ///Remove the main building mass replaceBuidingMass = true; mainBuildingMassPath = pair.Value; massOutline = pair.Key; } } ///Remove the main building mass if (replaceBuidingMass) { buildingGoo.RemovePath(mainBuildingMassPath); buildingGoo.Append(new GH_Curve(massOutline), mainBuildingMassPath); } else { GH_Path extrasPath = new GH_Path(3, partIndex); buildingGoo.Append(bldgPart.PartGoo, extrasPath); fieldNames.AppendRange(bldgPart.PartFieldNames, extrasPath); fieldValues.AppendRange(bldgPart.PartFieldValues, extrasPath); } } } ///end osm source loop if (recs.IsValid) { DA.SetData(0, recs); } DA.SetDataTree(1, fieldNames); DA.SetDataTree(2, fieldValues); DA.SetDataTree(3, geometryGoo); DA.SetDataTree(4, buildingGoo); } ///end SolveInstance
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>("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); }