├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── Heron.sln ├── Heron ├── Components │ ├── Deprecated │ │ ├── ExportVector_DEPRECATED20240729.cs │ │ ├── ImportLAZ_DEPRECATED20250120.cs │ │ ├── ImportSHP_DEPRECATED.cs │ │ ├── ImportTopo_DEPRECATED.cs │ │ ├── ImportVectorSRS_DEPRECATED20230506.cs │ │ ├── ImportVector_DEPRECATED20220730.cs │ │ ├── MapboxRaster_DEPRECATED20211114.cs │ │ ├── MultiSDiff_DEPRECATED20230910.cs │ │ ├── RESTLayer_DEPRECATED.cs │ │ ├── RESTRaster_DEPRECATED20220730.cs │ │ ├── RESTTOSM_DEPRECATED20240128.cs │ │ ├── RESTTopo_DEPRECATED20250119.cs │ │ ├── RESTVector_DEPRECATED.cs │ │ ├── RESTVector_DEPRECATED20220730.cs │ │ ├── SetEAP_DEPRECATED20220416.cs │ │ ├── SetSRS_DEPRECATED20240811.cs │ │ └── SlippyRaster_DEPRECATED2021114.cs │ ├── GIS API │ │ ├── MapboxIsochrone.cs │ │ ├── MapboxIsochroneSpeckle.cs │ │ ├── MapboxRaster.cs │ │ ├── MapboxTopo.cs │ │ ├── MapboxVector.cs │ │ ├── SlippyRaster.cs │ │ ├── SlippyRasterCustom.cs │ │ ├── SlippyTiles.cs │ │ ├── SlippyViewport.cs │ │ └── Yelp.cs │ ├── GIS Import-Export │ │ ├── ExportVector.cs │ │ ├── ImportLAZ.cs │ │ ├── ImportOSM.cs │ │ ├── ImportOSMLite.cs │ │ ├── ImportRaster.cs │ │ ├── ImportTopo.cs │ │ ├── ImportTopoLite.cs │ │ ├── ImportVectorLite.cs │ │ └── ImportVectorSRS.cs │ ├── GIS REST │ │ ├── RESTGeocode.cs │ │ ├── RESTLayer.cs │ │ ├── RESTOSM.cs │ │ ├── RESTRasterSRS.cs │ │ ├── RESTRevGeo.cs │ │ ├── RESTTopo.cs │ │ └── RESTVectorSRS.cs │ ├── GIS Tools │ │ ├── CoordinateTransformation.cs │ │ ├── DDtoXY.cs │ │ ├── DMStoDD.cs │ │ ├── GdalBuffer.cs │ │ ├── GdalConcaveHull.cs │ │ ├── GdalConvexHull.cs │ │ ├── GdalFillNoData.cs │ │ ├── GdalInfo.cs │ │ ├── GdalOGR2OGR.cs │ │ ├── GdalPoligonize.cs │ │ ├── GdalTranslate.cs │ │ ├── GdalWarp.cs │ │ ├── OgrInfo.cs │ │ ├── SetEAP.cs │ │ ├── SetSRS.cs │ │ └── XYtoDD.cs │ └── Utilities │ │ ├── ColorToHex.cs │ │ ├── DecimateTopoFromPoint.cs │ │ ├── GdalDetails.cs │ │ ├── HexToColor.cs │ │ ├── ImageCubeMap.cs │ │ ├── ImageCubeMapPlus.cs │ │ ├── ImageCubeToEqui.cs │ │ ├── ImageFilterColors.cs │ │ ├── ImageFlip.cs │ │ ├── ImageRotate.cs │ │ ├── ImageTopColors.cs │ │ ├── MultiMeshPatch.cs │ │ ├── MultiMoveToTopo.cs │ │ ├── MultiSDiff.cs │ │ ├── TopiaryFlatten.cs │ │ └── VisualCenter.cs ├── Convert.cs ├── GdalConfiguration.cs ├── Heron.csproj ├── HeronBoxPreviewComponent.cs ├── HeronComponent.cs ├── HeronConfiguration.cs ├── HeronInfo.cs ├── HeronRasterPreviewComponent.cs ├── HeronSRS.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ ├── Demo.png │ ├── HeronServiceEndpoints.json │ ├── Icon.png │ ├── ddtoxy.png │ ├── eap.png │ ├── geocode.png │ ├── heron-favicon.png │ ├── heron-icon.png │ ├── img.png │ ├── layer-01.png │ ├── layer.png │ ├── raster.png │ ├── revgeocode.png │ ├── shp.png │ ├── vector.png │ └── xytodd.png ├── SpeckleAsync │ ├── GH_AsyncComponent.cs │ └── WorkerInstance.cs ├── app.config ├── appsettings.json └── packages.config ├── HeronServiceEndpoints.json ├── LICENSE ├── Packages.dgml └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: herongis 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /Heron.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31613.86 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Heron", "Heron\Heron.csproj", "{A3CC60C1-0145-4237-8E81-1E96326B62A2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {A3CC60C1-0145-4237-8E81-1E96326B62A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {A3CC60C1-0145-4237-8E81-1E96326B62A2}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {A3CC60C1-0145-4237-8E81-1E96326B62A2}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {A3CC60C1-0145-4237-8E81-1E96326B62A2}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {50125008-9BD8-47A9-9FC7-BC762A783683} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Heron/Components/Deprecated/MultiSDiff_DEPRECATED20230910.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Grasshopper.Kernel; 5 | using Grasshopper.Kernel.Data; 6 | using Grasshopper.Kernel.Types; 7 | using Rhino.Geometry; 8 | 9 | namespace Heron 10 | { 11 | public class MultiSDiff_DEPRECATED20230910_OBSOLETE : HeronComponent 12 | { 13 | /// 14 | /// Initializes a new instance of the MultiSDiff class. 15 | /// 16 | public MultiSDiff_DEPRECATED20230910_OBSOLETE() 17 | : base("Multi SDiff", "MSDiff", 18 | "This multithreaded boolean solid difference (SDiff) component spreads the branches of input over threads for the boolean operation. " + 19 | "Any failed difference breps will be discarded to the Bad Breps output. " + 20 | "An example use would be to differnce shapes from panels where each panel and the shapes to be cut are on the same relative branches in a tree. " + 21 | "Of the available threads, one thread is always reserved for the GUI.", 22 | "Utilities") 23 | { 24 | } 25 | 26 | ///Retiring this component to add faster boolean difference algo 27 | public override Grasshopper.Kernel.GH_Exposure Exposure 28 | { 29 | get { return GH_Exposure.hidden; } 30 | } 31 | 32 | /// 33 | /// Registers all the input parameters for this component. 34 | /// 35 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 36 | { 37 | pManager.AddBrepParameter("Solids", "S", "Solid breps from which to difference.", GH_ParamAccess.tree); 38 | pManager.AddBrepParameter("Diffs", "D", "Solid breps of which to remove.", GH_ParamAccess.tree); 39 | } 40 | 41 | /// 42 | /// Registers all the output parameters for this component. 43 | /// 44 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 45 | { 46 | pManager.AddBrepParameter("Results", "R", "Results of boolean difference operation.", GH_ParamAccess.tree); 47 | pManager.AddBrepParameter("Bad Breps", "BB", "Differnce breps that failed in the boolean operation", GH_ParamAccess.tree); 48 | } 49 | 50 | /// 51 | /// This is the method that actually does the work. 52 | /// 53 | /// The DA object is used to retrieve from inputs and store in outputs. 54 | protected override void SolveInstance(IGH_DataAccess DA) 55 | { 56 | GH_Structure sBreps = new GH_Structure(); 57 | DA.GetDataTree(0, out sBreps); 58 | 59 | GH_Structure dBreps = new GH_Structure(); 60 | DA.GetDataTree(1, out dBreps); 61 | 62 | double tol = DocumentTolerance(); 63 | 64 | ///Reserve one processor for GUI 65 | int totalMaxConcurrancy = System.Environment.ProcessorCount - 1; 66 | 67 | ///Tells us how many threads were using 68 | Message = totalMaxConcurrancy + " threads"; 69 | 70 | ///Declare dictionaries that work in parallel to hold the successful boolean results and 71 | ///the unsuccessful boolean cutters 72 | var mainBrepsMT = new System.Collections.Concurrent.ConcurrentDictionary(); 73 | var badBrepsMT = new System.Collections.Concurrent.ConcurrentDictionary>(); 74 | 75 | ///Start of the parallel engine 76 | ///Cast to GH_Brep to Brep and back in parallel engine to avoid speed hit when casting all at once later 77 | System.Threading.Tasks.Parallel.ForEach(sBreps.Paths, new System.Threading.Tasks.ParallelOptions 78 | { MaxDegreeOfParallelism = totalMaxConcurrancy }, 79 | pth => 80 | { 81 | 82 | List badBrep = new List(); 83 | 84 | Brep mainBrep = new Brep(); 85 | GH_Convert.ToBrep(sBreps.get_Branch(pth)[0], ref mainBrep, 0); 86 | List diffBreps = new List(); 87 | foreach (var d_GH in dBreps.get_Branch(pth)) 88 | { 89 | Brep d_Rhino = new Brep(); 90 | GH_Convert.ToBrep(d_GH, ref d_Rhino, 0); 91 | diffBreps.Add(d_Rhino); 92 | } 93 | 94 | ///Look into boolean first with lists, then if fails, revert to one-by-one 95 | ///https://discourse.mcneel.com/t/boolean-difference-in-gh-much-slower-than-in-rhino/97985/19 96 | 97 | ///Difference one cutter brep at a time from the main brep in the branch. 98 | ///This allows the boolean operation to continue without failing 99 | ///and bad cutter breps can be discarded to a list that can be used for troubleshooting 100 | ///haven't noticed a hit big hit on performance 101 | foreach (Brep b in diffBreps) 102 | { 103 | Brep[] breps = new Brep[] { }; 104 | breps = Brep.CreateBooleanDifference(mainBrep, b, tol); 105 | if ((breps == null) || (breps.Length < 1)) 106 | { 107 | badBrep.Add(new GH_Brep(b)); 108 | } 109 | else 110 | { 111 | mainBrep = breps[0]; 112 | } 113 | } 114 | mainBrepsMT[pth] = new GH_Brep(mainBrep); 115 | badBrepsMT[pth] = badBrep; 116 | }); 117 | ///End of the parallel engine 118 | /// 119 | 120 | //convert dictionaries to regular old data trees 121 | GH_Structure mainBreps = new GH_Structure(); 122 | GH_Structure badBreps = new GH_Structure(); 123 | 124 | foreach (KeyValuePair p in mainBrepsMT) 125 | { 126 | mainBreps.Append(p.Value, p.Key); 127 | } 128 | 129 | foreach (KeyValuePair> b in badBrepsMT) 130 | { 131 | badBreps.AppendRange(b.Value, b.Key); 132 | } 133 | 134 | DA.SetDataTree(0, mainBreps); 135 | DA.SetDataTree(1, badBreps); 136 | 137 | } 138 | 139 | /// 140 | /// Provides an Icon for the component. 141 | /// 142 | protected override System.Drawing.Bitmap Icon 143 | { 144 | get 145 | { 146 | //You can add image files to your project resources and access them like this: 147 | // return Resources.IconForThisComponent; 148 | return Properties.Resources.shp; 149 | } 150 | } 151 | 152 | /// 153 | /// Gets the unique ID for this component. Do not change this ID after release. 154 | /// 155 | public override Guid ComponentGuid 156 | { 157 | get { return new Guid("94a1165e-7fed-45a7-8c08-449bea06d503"); } 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /Heron/Components/Deprecated/RESTLayer_DEPRECATED.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Xml; 4 | using System.Xml.Linq; 5 | using System.Linq; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.Reflection; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Runtime.InteropServices; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using System.Windows.Forms; 15 | using Grasshopper; 16 | using Grasshopper.Kernel; 17 | using Grasshopper.Kernel.Data; 18 | using Grasshopper.Kernel.Types; 19 | using Grasshopper.Kernel.Special; 20 | using Rhino.Geometry; 21 | using GH_IO; 22 | using GH_IO.Serialization; 23 | 24 | using Newtonsoft.Json.Bson; 25 | using Newtonsoft.Json; 26 | using Newtonsoft.Json.Converters; 27 | using Newtonsoft.Json.Linq; 28 | using Newtonsoft.Json.Schema; 29 | using Newtonsoft.Json.Serialization; 30 | 31 | namespace Heron 32 | { 33 | public class RESTLayer_DEPRECATED_OBSOLETE : HeronComponent 34 | { 35 | //Class Constructor 36 | public RESTLayer_DEPRECATED_OBSOLETE() : base("Get REST Service Layers DEPRECATED", "RESTLayer_D", "Discover ArcGIS REST Service Layers", "GIS REST") 37 | { 38 | 39 | } 40 | 41 | ///Retiring this component in to update the outputs to include urls 42 | public override Grasshopper.Kernel.GH_Exposure Exposure 43 | { 44 | get { return GH_Exposure.hidden; } 45 | } 46 | 47 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 48 | { 49 | pManager.AddTextParameter("Service URL", "serviceURL", "Service URL string", GH_ParamAccess.item); 50 | 51 | } 52 | 53 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 54 | { 55 | pManager.AddTextParameter("Map Description", "mapDescription", "Description of the REST Service", GH_ParamAccess.item); 56 | pManager.AddTextParameter("Map Layer", "mapLayers", "Names of available Service Layers", GH_ParamAccess.list); 57 | pManager.AddIntegerParameter("Map Integer", "mapIndex", "Index of available Service Layers", GH_ParamAccess.list); 58 | 59 | } 60 | 61 | protected override void SolveInstance(IGH_DataAccess DA) 62 | { 63 | string URL = string.Empty; 64 | 65 | DA.GetData("Service URL", ref URL); 66 | 67 | //get json from rest service 68 | string restquery = URL + "?f=pjson"; 69 | 70 | System.Net.HttpWebRequest req = System.Net.WebRequest.Create(restquery) as System.Net.HttpWebRequest; 71 | string result = null; 72 | 73 | using (System.Net.HttpWebResponse resp = req.GetResponse() as System.Net.HttpWebResponse) 74 | { 75 | System.IO.StreamReader reader = new System.IO.StreamReader(resp.GetResponseStream()); 76 | result = reader.ReadToEnd(); 77 | reader.Close(); 78 | } 79 | 80 | //parse json into a description and list of layer values 81 | JObject j = JObject.Parse(result); 82 | List layerKey = new List(); 83 | List layerInt = new List(); 84 | 85 | Dictionary d = new Dictionary(); 86 | 87 | for (int i = 1; i < j["layers"].Children()["name"].Count(); i++) 88 | { 89 | d[(string)j["layers"][i]["name"]] = (int)j["layers"][i]["id"]; 90 | layerKey.Add((string)j["layers"][i]["name"]); 91 | layerInt.Add((int)j["layers"][i]["id"]); 92 | } 93 | 94 | DA.SetData("Map Description", (string)j["description"]); 95 | //mapDescription = (string) j["description"]; 96 | DA.SetDataList("Map Layer", layerKey); 97 | //mapLayer = layerKey; 98 | DA.SetDataList("Map Integer", layerInt); 99 | //mapInt = layerInt; 100 | 101 | } 102 | 103 | 104 | 105 | 106 | 107 | private JObject vectorJson = JObject.Parse(Heron.Convert.GetEnpoints()); 108 | 109 | /// 110 | /// Adds to the context menu an option to create a pre-populated list of common REST Vector sources 111 | /// 112 | /// 113 | /// https://discourse.mcneel.com/t/generated-valuelist-not-working/79406/6?u=hypar 114 | public override void AppendAdditionalMenuItems(ToolStripDropDown menu) 115 | { 116 | var rasterSourcesJson = vectorJson["REST Vector"].Select(x => x["source"]).Distinct(); 117 | List rasterSources = rasterSourcesJson.Values().ToList(); 118 | foreach (var src in rasterSourcesJson) 119 | { 120 | ToolStripMenuItem root = GH_DocumentObject.Menu_AppendItem(menu, "Create " + src.ToString() + " Source List", CreateRasterList); 121 | root.ToolTipText = "Click this to create a pre-populated list of some " + src.ToString() + " sources."; 122 | base.AppendAdditionalMenuItems(menu); 123 | } 124 | } 125 | 126 | /// 127 | /// Creates a value list pre-populated with possible accent colors and adds it to the Grasshopper Document, located near the component pivot. 128 | /// 129 | /// The sender. 130 | /// The instance containing the event data. 131 | private void CreateRasterList(object sender, System.EventArgs e) 132 | { 133 | string source = sender.ToString(); 134 | source = source.Replace("Create ", ""); 135 | source = source.Replace(" Source List", ""); 136 | 137 | GH_DocumentIO docIO = new GH_DocumentIO(); 138 | docIO.Document = new GH_Document(); 139 | 140 | ///Initialize object 141 | GH_ValueList vl = new GH_ValueList(); 142 | 143 | ///Clear default contents 144 | vl.ListItems.Clear(); 145 | 146 | foreach (var service in vectorJson["REST Vector"]) 147 | { 148 | if (service["source"].ToString() == source) 149 | { 150 | GH_ValueListItem vi = new GH_ValueListItem(service["service"].ToString(), String.Format("\"{0}\"", service["url"].ToString())); 151 | vl.ListItems.Add(vi); 152 | } 153 | } 154 | 155 | ///Set component nickname 156 | vl.NickName = source; 157 | 158 | ///Get active GH doc 159 | GH_Document doc = OnPingDocument(); 160 | if (docIO.Document == null) return; 161 | 162 | ///Place the object 163 | docIO.Document.AddObject(vl, false, 1); 164 | 165 | ///Get the pivot of the "URL" param 166 | PointF currPivot = Params.Input[0].Attributes.Pivot; 167 | 168 | ///Set the pivot of the new object 169 | vl.Attributes.Pivot = new PointF(currPivot.X - 400, currPivot.Y - 11); 170 | 171 | docIO.Document.SelectAll(); 172 | docIO.Document.ExpireSolution(); 173 | docIO.Document.MutateAllIds(); 174 | IEnumerable objs = docIO.Document.Objects; 175 | doc.DeselectAll(); 176 | doc.UndoUtil.RecordAddObjectEvent("Create REST Vector Source List", objs); 177 | doc.MergeDocument(docIO.Document); 178 | } 179 | 180 | protected override System.Drawing.Bitmap Icon 181 | { 182 | get 183 | { 184 | return Properties.Resources.layer; 185 | } 186 | } 187 | 188 | public override Guid ComponentGuid 189 | { 190 | get { return new Guid("{AD3A9FBB-AD30-4C95-BDD4-44D804895120}"); } 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /Heron/Components/Deprecated/SetEAP_DEPRECATED20220416.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Xml; 4 | using System.Xml.Linq; 5 | using System.Linq; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.Reflection; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Runtime.InteropServices; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using Grasshopper; 15 | using Grasshopper.Kernel; 16 | using Grasshopper.Kernel.Data; 17 | using Grasshopper.Kernel.Types; 18 | using Rhino; 19 | using Rhino.Geometry; 20 | using Rhino.DocObjects; 21 | using Rhino.Collections; 22 | using GH_IO; 23 | using GH_IO.Serialization; 24 | 25 | using Newtonsoft.Json.Bson; 26 | using Newtonsoft.Json; 27 | using Newtonsoft.Json.Converters; 28 | using Newtonsoft.Json.Linq; 29 | using Newtonsoft.Json.Schema; 30 | using Newtonsoft.Json.Serialization; 31 | 32 | namespace Heron 33 | { 34 | public class SetEAP_DEPRECATED20220416_OBSOLETE : HeronComponent 35 | { 36 | //Class Constructor 37 | public SetEAP_DEPRECATED20220416_OBSOLETE() : base("Set EarthAnchorPoint", "SetEAP", "Set the Rhino EarthAnchorPoint", "GIS Tools") 38 | { 39 | 40 | } 41 | 42 | ///Retiring this component to add point of interest and DMS formatted lat/lon as input 43 | public override Grasshopper.Kernel.GH_Exposure Exposure 44 | { 45 | get { return GH_Exposure.hidden; } 46 | } 47 | 48 | 49 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 50 | { 51 | pManager.AddBooleanParameter("Set EAP", "set", "Set the EarthAnchorPoint", GH_ParamAccess.item, false); 52 | pManager.AddNumberParameter("Latitude", "LAT", "Decimal Degree Latitude", GH_ParamAccess.item); 53 | pManager.AddNumberParameter("Longitude", "LON", "Decimal Degree Longitude", GH_ParamAccess.item); 54 | pManager[1].Optional = true; 55 | pManager[2].Optional = true; 56 | } 57 | 58 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 59 | { 60 | pManager.AddTextParameter("Earth Anchor Point", "EAP", "EarthAnchorPoint Longitude/Latitude", GH_ParamAccess.item); 61 | } 62 | 63 | protected override void SolveInstance(IGH_DataAccess DA) 64 | { 65 | double lat = -1; 66 | double lon = -1; 67 | bool EAP = false; 68 | string lonlatString = string.Empty; 69 | 70 | //check if EAP has been set and if so what is it 71 | if (!Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthLocationIsSet()) 72 | { 73 | lonlatString = "The Earth Anchor Point has not been set yet"; 74 | AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "EAP has not been set yet"); 75 | } 76 | 77 | else lonlatString = "Longitude: " + Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthBasepointLongitude.ToString() + 78 | " / Latitude: " + Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthBasepointLatitude.ToString(); 79 | 80 | DA.GetData("Set EAP", ref EAP); 81 | DA.GetData("Latitude", ref lat); 82 | DA.GetData("Longitude", ref lon); 83 | 84 | if (EAP == true) 85 | { 86 | EarthAnchorPoint ePt = new EarthAnchorPoint(); 87 | ePt.EarthBasepointLatitude = lat; 88 | ePt.EarthBasepointLongitude = lon; 89 | 90 | //set new EAP 91 | Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint = ePt; 92 | 93 | //new EAP to string for output 94 | lonlatString = "Longitude: " + Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthBasepointLongitude.ToString() + 95 | " / Latitude: " + Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthBasepointLatitude.ToString(); 96 | } 97 | 98 | 99 | DA.SetData("Earth Anchor Point", lonlatString); 100 | } 101 | 102 | protected override System.Drawing.Bitmap Icon 103 | { 104 | get 105 | { 106 | return Properties.Resources.eap; 107 | } 108 | } 109 | 110 | public override Guid ComponentGuid 111 | { 112 | get { return new Guid("{6577DC68-200C-4B3C-ADB4-78DE61D76870}"); } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Heron/Components/GIS API/SlippyTiles.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | 5 | using Grasshopper.Kernel; 6 | using Grasshopper.Kernel.Data; 7 | using Grasshopper.Kernel.Types; 8 | using Rhino.Geometry; 9 | 10 | namespace Heron 11 | { 12 | public class SlippyTiles : HeronComponent 13 | { 14 | /// 15 | /// Initializes a new instance of the SlippyTiles class. 16 | /// 17 | public SlippyTiles() 18 | : base("Slippy Tiles", "SlippyTiles", 19 | "Visualize boundaries of slippy map tiles within a given boundary at a given zoom level. See https://en.wikipedia.org/wiki/Tiled_web_map for more information about map tiles.", 20 | "GIS API") 21 | { 22 | } 23 | 24 | /// 25 | /// Registers all the input parameters for this component. 26 | /// 27 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 28 | { 29 | pManager.AddCurveParameter("Boundary", "boundary", "Boundary curve for map tiles", GH_ParamAccess.item); 30 | pManager.AddIntegerParameter("Zoom Level", "zoom", "Slippy map zoom level. Higher zoom level is higher resolution.", GH_ParamAccess.item); 31 | } 32 | 33 | /// 34 | /// Registers all the output parameters for this component. 35 | /// 36 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 37 | { 38 | pManager.AddCurveParameter("Tile Extents", "tiles", "Map tile boundaries for each tile", GH_ParamAccess.list); 39 | pManager.AddTextParameter("Tile ID", "id", "Map tile ID. The tile ID is formatted 'Z-X-Y' where Z is zoom level, X is the column and Y the row.", GH_ParamAccess.list); 40 | } 41 | 42 | /// 43 | /// This is the method that actually does the work. 44 | /// 45 | /// The DA object is used to retrieve from inputs and store in outputs. 46 | protected override void SolveInstance(IGH_DataAccess DA) 47 | { 48 | Curve boundary = null; 49 | DA.GetData(0, ref boundary); 50 | 51 | int zoom = -1; 52 | DA.GetData(1, ref zoom); 53 | 54 | ///Get image frame for given boundary 55 | if (!boundary.GetBoundingBox(true).IsValid) 56 | { 57 | AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Boundary is not valid."); 58 | return; 59 | } 60 | BoundingBox boundaryBox = boundary.GetBoundingBox(true); 61 | 62 | ///Tile bounding box array 63 | List boxPtList = new List(); 64 | 65 | ///Get the tile coordinates for all tiles within boundary 66 | var ranges = Convert.GetTileRange(boundaryBox, zoom); 67 | var x_range = ranges.XRange; 68 | var y_range = ranges.YRange; 69 | 70 | if (x_range.Length > 100 || y_range.Length > 100) 71 | { 72 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "This tile range is too big (more than 100 tiles in the x or y direction). Check your units."); 73 | return; 74 | } 75 | 76 | ///Cycle through tiles to get bounding box 77 | List tileExtents = new List(); 78 | List tileID = new List(); 79 | 80 | for (int y = (int)y_range.Min; y <= y_range.Max; y++) 81 | { 82 | for (int x = (int)x_range.Min; x <= x_range.Max; x++) 83 | { 84 | string tileString = zoom + "-" + x + "-" + y; 85 | tileID.Add(tileString); 86 | Polyline tileExtent = Heron.Convert.GetTileAsPolygon(zoom, y, x); 87 | tileExtents.Add(tileExtent); 88 | double tileHeight = tileExtent[1].DistanceTo(tileExtent[2]); 89 | 90 | if (!string.IsNullOrWhiteSpace(tileString)) 91 | { 92 | _text.Add(tileString); 93 | _point.Add(tileExtent.CenterPoint()); 94 | _size.Add(tileHeight / 20); 95 | _tile.Add(tileExtent); 96 | } 97 | } 98 | } 99 | 100 | DA.SetDataList(0, tileExtents); 101 | DA.SetDataList(1, tileID); 102 | } 103 | 104 | ///Preview text and tile polylines 105 | ///https://www.grasshopper3d.com/forum/topics/drawing-a-text-tag-from-a-c-component?commentId=2985220%3AComment%3A1024697 106 | 107 | private readonly List _text = new List(); 108 | private readonly List _point = new List(); 109 | private readonly List _size = new List(); 110 | private readonly List _tile = new List(); 111 | 112 | protected override void BeforeSolveInstance() 113 | { 114 | _text.Clear(); 115 | _point.Clear(); 116 | _size.Clear(); 117 | _tile.Clear(); 118 | } 119 | 120 | public override void DrawViewportWires(IGH_PreviewArgs args) 121 | { 122 | if (_text.Count == 0) 123 | return; 124 | 125 | //Plane plane; 126 | //args.Viewport.GetFrustumFarPlane(out plane); 127 | 128 | for (int i = 0; i < _text.Count; i++) 129 | { 130 | string text = _text[i]; 131 | Point3d point = _point[i]; 132 | double size = _size[i]; 133 | Polyline tile = _tile[i]; 134 | 135 | Plane plane; 136 | args.Viewport.GetFrustumFarPlane(out plane); 137 | plane.Origin = point; 138 | 139 | Rhino.Display.Text3d drawText = new Rhino.Display.Text3d(text, plane, size); 140 | args.Display.Draw3dText(text, Color.Black, plane, size, null, false, false, Rhino.DocObjects.TextHorizontalAlignment.Center, Rhino.DocObjects.TextVerticalAlignment.Middle); 141 | args.Display.DrawPolyline(tile, Color.Black, 2); 142 | drawText.Dispose(); 143 | } 144 | } 145 | 146 | 147 | /// 148 | /// Provides an Icon for the component. 149 | /// 150 | protected override System.Drawing.Bitmap Icon 151 | { 152 | get 153 | { 154 | //You can add image files to your project resources and access them like this: 155 | // return Resources.IconForThisComponent; 156 | return Properties.Resources.vector; 157 | } 158 | } 159 | 160 | /// 161 | /// Gets the unique ID for this component. Do not change this ID after release. 162 | /// 163 | public override Guid ComponentGuid 164 | { 165 | get { return new Guid("ae47ba29-49ae-4bbe-b76c-7335e725e91e"); } 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /Heron/Components/GIS API/SlippyViewport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Grasshopper.Kernel; 6 | using Rhino.Geometry; 7 | 8 | namespace Heron 9 | { 10 | public class SlippyViewport : HeronComponent 11 | { 12 | /// 13 | /// Initializes a new instance of the SlippyViewport class. 14 | /// 15 | public SlippyViewport() 16 | : base("Slippy Viewport", "SlippyVP", "Projects the boundary of a given Viewport to the World XY plane and calculates a good Zoom level for use with tile-based map components.", "GIS API") 17 | { 18 | } 19 | 20 | /// 21 | /// Registers all the input parameters for this component. 22 | /// 23 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 24 | { 25 | pManager.AddTextParameter("Named Viewport", "view", "Provide the name of the viewport to be used.", GH_ParamAccess.item, "Top"); 26 | } 27 | 28 | /// 29 | /// Registers all the output parameters for this component. 30 | /// 31 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 32 | { 33 | pManager.AddCurveParameter("Viewport Boundary", "boundary", "The boundary of the given viewport projected onto the World XY plane", GH_ParamAccess.item); 34 | pManager.AddNumberParameter("Zoom Level", "zoom", "A good zoom level to be used with a Raster API componenet given the extents of viewport boundary. Max zoom level is set to 21", GH_ParamAccess.item); 35 | } 36 | 37 | /// 38 | /// This is the method that actually does the work. 39 | /// 40 | /// The DA object is used to retrieve from inputs and store in outputs. 41 | protected override void SolveInstance(IGH_DataAccess DA) 42 | { 43 | List pProjected = new List(); 44 | 45 | string view = string.Empty; 46 | DA.GetData(0, ref view); 47 | viewportName = view; 48 | ///Get viewport boundary 49 | Rhino.Display.RhinoView[] rvList = Rhino.RhinoDoc.ActiveDoc.Views.GetViewList(true, false); 50 | Rhino.Display.RhinoView rv = Rhino.RhinoDoc.ActiveDoc.Views.Find(view, true); 51 | 52 | if (!rvList.Contains(rv)) 53 | { 54 | rv = Rhino.RhinoDoc.ActiveDoc.Views.ActiveView; 55 | AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Viewport name is not valid. Using active viewport " + rv.ActiveViewport.Name); 56 | } 57 | 58 | 59 | Rhino.Display.RhinoViewport vp = rv.MainViewport; 60 | Point3d[] pNear = rv.MainViewport.GetNearRect(); 61 | Point3d[] pFar = rv.MainViewport.GetFarRect(); 62 | 63 | ///Project viewport boundary to a plane 64 | for (int i = 0; i < pNear.Length; i++) 65 | { 66 | Vector3d tVec = pFar[i] - pNear[i]; 67 | Transform trans = Transform.ProjectAlong(Plane.WorldXY, tVec); 68 | pNear[i].Transform(trans); 69 | pProjected.Add(pNear[i]); 70 | } 71 | 72 | ///Create polyline from project viewport boundary 73 | Polyline pL = new Polyline(); 74 | pL.Add(pProjected[2]); 75 | pL.Add(pProjected[3]); 76 | pL.Add(pProjected[1]); 77 | pL.Add(pProjected[0]); 78 | pL.Add(pProjected[2]); 79 | 80 | 81 | ///Calculate recommended zoom level from viewport size 82 | BoundingBox bb = pL.BoundingBox; 83 | Vector3d dia = bb.Diagonal; 84 | Double maxDim = Math.Max(dia.X, dia.Y) * Rhino.RhinoMath.UnitScale(Rhino.RhinoDoc.ActiveDoc.ModelUnitSystem, Rhino.UnitSystem.Meters); 85 | Double maxPix = Math.Max(vp.Size.Height, vp.Size.Width); 86 | 87 | 88 | ///https://gis.stackexchange.com/questions/19632/how-to-calculate-the-optimal-zoom-level-to-display-two-or-more-points-on-a-map 89 | ///diameter of earth at equator is approx 40,000km 90 | ///resolution = (512px*distance)/40,075,000 meters * 2^zoom 91 | ///2^zoom = (resolution * 40,000,000) / (512px * distance) 92 | Double a = (maxPix * 40075000) / (512 * maxDim * 1.2); 93 | 94 | ///Solve for zoom 95 | ///https://stackoverflow.com/questions/4016213/whats-the-opposite-of-javascripts-math-pow 96 | Double z = Math.Log(a) / Math.Log(2); 97 | 98 | 99 | ///make sure zoom doesn't get too ridiculous levels 100 | DA.SetData(0, pL); 101 | DA.SetData(1, Math.Min(z, 21)); 102 | } 103 | 104 | public override bool IsPreviewCapable => true; 105 | 106 | private int updateFrequencyMS = 300; 107 | private Point3d lastCameraLocation = default(Point3d); 108 | private string viewportName = null; 109 | 110 | public override void DrawViewportWires(IGH_PreviewArgs args) 111 | { 112 | if (args.Display.Viewport.Name == viewportName) 113 | { 114 | var delta = args.Display.Viewport.CameraLocation.DistanceToSquared(lastCameraLocation); 115 | if (delta > 1) // if it's moved 116 | { 117 | lastCameraLocation = args.Display.Viewport.CameraLocation; 118 | OnPingDocument().ScheduleSolution(updateFrequencyMS, (doc) => 119 | { 120 | ExpireSolution(false); 121 | }); 122 | } 123 | } 124 | base.DrawViewportWires(args); 125 | } 126 | 127 | /// 128 | /// Provides an Icon for the component. 129 | /// 130 | protected override System.Drawing.Bitmap Icon 131 | { 132 | get 133 | { 134 | //You can add image files to your project resources and access them like this: 135 | // return Resources.IconForThisComponent; 136 | return Properties.Resources.vector; 137 | } 138 | } 139 | 140 | /// 141 | /// Gets the unique ID for this component. Do not change this ID after release. 142 | /// 143 | public override Guid ComponentGuid 144 | { 145 | get { return new Guid("76082489-C7F2-403A-9490-BC52374C4F2B"); } 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /Heron/Components/GIS REST/RESTGeocode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Xml; 4 | using System.Xml.Linq; 5 | using System.Linq; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.Reflection; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Runtime.InteropServices; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using Grasshopper; 15 | using Grasshopper.Kernel; 16 | using Grasshopper.Kernel.Data; 17 | using Grasshopper.Kernel.Types; 18 | using Rhino.Geometry; 19 | using GH_IO; 20 | using GH_IO.Serialization; 21 | 22 | using Newtonsoft.Json.Bson; 23 | using Newtonsoft.Json; 24 | using Newtonsoft.Json.Converters; 25 | using Newtonsoft.Json.Linq; 26 | using Newtonsoft.Json.Schema; 27 | using Newtonsoft.Json.Serialization; 28 | 29 | namespace Heron 30 | { 31 | public class RESTGeocode : HeronComponent 32 | { 33 | //Class Constructor 34 | public RESTGeocode() : base("ESRI REST Service Geocode", "RESTGeocode", "Get coordinates based on a Point-of-Interest or Address using the ESRI geocode service.", "GIS REST") 35 | { 36 | 37 | } 38 | 39 | 40 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 41 | { 42 | pManager.AddTextParameter("Addresses", "addresses", "POI or Address string(s) to geocode", GH_ParamAccess.tree); 43 | 44 | } 45 | 46 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 47 | { 48 | pManager.AddTextParameter("Candidates", "Candidates", "List of Candidate locations", GH_ParamAccess.tree); 49 | pManager.AddTextParameter("Latitude", "LAT", "Latitude of Candidate location", GH_ParamAccess.tree); 50 | pManager.AddTextParameter("Longitude", "LON", "Longitude of Candidate location", GH_ParamAccess.tree); 51 | 52 | } 53 | 54 | protected override void SolveInstance(IGH_DataAccess DA) 55 | { 56 | GH_Structure Addresses = new GH_Structure(); 57 | 58 | DA.GetDataTree("Addresses", out Addresses); 59 | 60 | GH_Structure addr = new GH_Structure(); 61 | GH_Structure latx = new GH_Structure(); 62 | GH_Structure lony = new GH_Structure(); 63 | 64 | for (int a = 0; a < Addresses.Branches.Count; a++) 65 | { 66 | IList branch = Addresses.Branches[a]; 67 | GH_Path path = Addresses.Paths[a]; 68 | int count = 0; 69 | foreach (GH_String addressString in branch) 70 | { 71 | string address = System.Net.WebUtility.UrlEncode(addressString.Value); 72 | string output = GetData("https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?Address=" + address + "&f=pjson"); 73 | JObject ja = JObject.Parse(output); 74 | 75 | if (ja["candidates"].Count() < 1) 76 | { 77 | addr.Append(new GH_String("No Cadidate location found for this address"), path); 78 | lony.Append(new GH_String(""), path); 79 | latx.Append(new GH_String(""), path); 80 | } 81 | else 82 | { 83 | for (int i = 0; i < ja["candidates"].Count(); i++) 84 | { 85 | if (ja["candidates"][i]["score"].Value() > 99) 86 | { 87 | addr.Append(new GH_String(ja["candidates"][i]["address"].ToString()), new GH_Path(path[count], i)); 88 | addr.Append(new GH_String("LON: " + ja["candidates"][i]["location"]["x"].ToString()), new GH_Path(path[count], i)); 89 | addr.Append(new GH_String("LAT: " + ja["candidates"][i]["location"]["y"].ToString()), new GH_Path(path[count], i)); 90 | lony.Append(new GH_String(ja["candidates"][i]["location"]["y"].ToString()), new GH_Path(path[count], i)); 91 | latx.Append(new GH_String(ja["candidates"][i]["location"]["x"].ToString()), new GH_Path(path[count], i)); 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | if (addr == null) 99 | { 100 | AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "No Candidate locations found"); 101 | return; 102 | } 103 | else 104 | { 105 | DA.SetDataTree(0, addr); 106 | DA.SetDataTree(1, lony); 107 | DA.SetDataTree(2, latx); 108 | } 109 | 110 | 111 | } 112 | 113 | public static string GetData(string qst) 114 | { 115 | System.Net.HttpWebRequest req = System.Net.WebRequest.Create(qst) as System.Net.HttpWebRequest; 116 | string result = null; 117 | try 118 | { 119 | using (System.Net.HttpWebResponse resp = req.GetResponse() as System.Net.HttpWebResponse) 120 | { 121 | System.IO.StreamReader reader = new System.IO.StreamReader(resp.GetResponseStream()); 122 | result = reader.ReadToEnd(); 123 | reader.Close(); 124 | } 125 | } 126 | catch 127 | { 128 | return "Something went wrong getting data from the Service"; 129 | } 130 | return result; 131 | } 132 | 133 | 134 | protected override System.Drawing.Bitmap Icon 135 | { 136 | get 137 | { 138 | return Properties.Resources.geocode; 139 | } 140 | } 141 | 142 | public override Guid ComponentGuid 143 | { 144 | get { return new Guid("{019FCF0D-08A1-4CB0-A0D7-EDD6F840378E}"); } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Heron/Components/GIS REST/RESTLayer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Xml; 4 | using System.Xml.Linq; 5 | using System.Linq; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.Reflection; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Runtime.InteropServices; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using System.Windows.Forms; 15 | using Grasshopper; 16 | using Grasshopper.Kernel; 17 | using Grasshopper.Kernel.Data; 18 | using Grasshopper.Kernel.Types; 19 | using Grasshopper.Kernel.Special; 20 | using Rhino.Geometry; 21 | using GH_IO; 22 | using GH_IO.Serialization; 23 | 24 | using Newtonsoft.Json.Bson; 25 | using Newtonsoft.Json; 26 | using Newtonsoft.Json.Converters; 27 | using Newtonsoft.Json.Linq; 28 | using Newtonsoft.Json.Schema; 29 | using Newtonsoft.Json.Serialization; 30 | 31 | namespace Heron 32 | { 33 | public class RESTLayer : HeronComponent 34 | { 35 | //Class Constructor 36 | public RESTLayer() : base("Get REST Service Layers", "RESTLayer", "Discover ArcGIS REST Service Layers", "GIS REST") 37 | { 38 | 39 | } 40 | 41 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 42 | { 43 | pManager.AddTextParameter("Service URL", "serviceURL", "Service URL string", GH_ParamAccess.item); 44 | 45 | } 46 | 47 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 48 | { 49 | pManager.AddTextParameter("Map Description", "mapDescription", "Description of the REST Service", GH_ParamAccess.item); 50 | pManager.AddTextParameter("Map Layers", "mapLayers", "Names of available Service Layers", GH_ParamAccess.list); 51 | pManager.AddIntegerParameter("Map Integers", "mapIndexes", "Indexes of available Service Layers", GH_ParamAccess.list); 52 | pManager.AddTextParameter("Map Layer URLs", "URLs", "URLs of available Service Layers", GH_ParamAccess.list); 53 | 54 | } 55 | 56 | protected override void SolveInstance(IGH_DataAccess DA) 57 | { 58 | string URL = string.Empty; 59 | 60 | DA.GetData("Service URL", ref URL); 61 | if (!URL.EndsWith(@"/")) { URL = URL + "/"; } 62 | 63 | //get json from rest service 64 | string restquery = URL + "?f=pjson"; 65 | 66 | System.Net.HttpWebRequest req = System.Net.WebRequest.Create(restquery) as System.Net.HttpWebRequest; 67 | string result = null; 68 | 69 | using (System.Net.HttpWebResponse resp = req.GetResponse() as System.Net.HttpWebResponse) 70 | { 71 | System.IO.StreamReader reader = new System.IO.StreamReader(resp.GetResponseStream()); 72 | result = reader.ReadToEnd(); 73 | reader.Close(); 74 | } 75 | 76 | //parse json into a description and list of layer values 77 | JObject j = JObject.Parse(result); 78 | List layerKey = new List(); 79 | List layerInt = new List(); 80 | List layerUrl = new List(); 81 | 82 | Dictionary d = new Dictionary(); 83 | 84 | for (int i = 1; i < j["layers"].Children()["name"].Count(); i++) 85 | { 86 | d[(string)j["layers"][i]["name"]] = (int)j["layers"][i]["id"]; 87 | layerKey.Add((string)j["layers"][i]["name"]); 88 | layerInt.Add((int)j["layers"][i]["id"]); 89 | layerUrl.Add(URL + j["layers"][i]["id"].ToString() + "/"); 90 | } 91 | 92 | DA.SetData(0, (string)j["description"]); 93 | //mapDescription = (string) j["description"]; 94 | DA.SetDataList(1, layerKey); 95 | //mapLayer = layerKey; 96 | DA.SetDataList(2, layerInt); 97 | //mapInt = layerInt; 98 | DA.SetDataList(3, layerUrl); 99 | 100 | } 101 | 102 | 103 | 104 | 105 | 106 | private JObject vectorJson = JObject.Parse(Heron.Convert.GetEnpoints()); 107 | 108 | /// 109 | /// Adds to the context menu an option to create a pre-populated list of common REST Vector sources 110 | /// 111 | /// 112 | /// https://discourse.mcneel.com/t/generated-valuelist-not-working/79406/6?u=hypar 113 | public override void AppendAdditionalMenuItems(ToolStripDropDown menu) 114 | { 115 | var rasterSourcesJson = vectorJson["REST Vector"].Select(x => x["source"]).Distinct(); 116 | List rasterSources = rasterSourcesJson.Values().ToList(); 117 | foreach (var src in rasterSourcesJson) 118 | { 119 | ToolStripMenuItem root = GH_DocumentObject.Menu_AppendItem(menu, "Create " + src.ToString() + " Source List", CreateRasterList); 120 | root.ToolTipText = "Click this to create a pre-populated list of some " + src.ToString() + " sources."; 121 | base.AppendAdditionalMenuItems(menu); 122 | } 123 | } 124 | 125 | /// 126 | /// Creates a value list pre-populated with possible accent colors and adds it to the Grasshopper Document, located near the component pivot. 127 | /// 128 | /// The sender. 129 | /// The instance containing the event data. 130 | private void CreateRasterList(object sender, System.EventArgs e) 131 | { 132 | string source = sender.ToString(); 133 | source = source.Replace("Create ", ""); 134 | source = source.Replace(" Source List", ""); 135 | 136 | GH_DocumentIO docIO = new GH_DocumentIO(); 137 | docIO.Document = new GH_Document(); 138 | 139 | ///Initialize object 140 | GH_ValueList vl = new GH_ValueList(); 141 | 142 | ///Clear default contents 143 | vl.ListItems.Clear(); 144 | 145 | foreach (var service in vectorJson["REST Vector"]) 146 | { 147 | if (service["source"].ToString() == source) 148 | { 149 | GH_ValueListItem vi = new GH_ValueListItem(service["service"].ToString(), String.Format("\"{0}\"", service["url"].ToString())); 150 | vl.ListItems.Add(vi); 151 | } 152 | } 153 | 154 | ///Set component nickname 155 | vl.NickName = source; 156 | 157 | ///Get active GH doc 158 | GH_Document doc = OnPingDocument(); 159 | if (docIO.Document == null) return; 160 | 161 | ///Place the object 162 | docIO.Document.AddObject(vl, false, 1); 163 | 164 | ///Get the pivot of the "URL" param 165 | PointF currPivot = Params.Input[0].Attributes.Pivot; 166 | 167 | ///Set the pivot of the new object 168 | vl.Attributes.Pivot = new PointF(currPivot.X - 400, currPivot.Y - 11); 169 | 170 | docIO.Document.SelectAll(); 171 | docIO.Document.ExpireSolution(); 172 | docIO.Document.MutateAllIds(); 173 | IEnumerable objs = docIO.Document.Objects; 174 | doc.DeselectAll(); 175 | doc.UndoUtil.RecordAddObjectEvent("Create REST Vector Source List", objs); 176 | doc.MergeDocument(docIO.Document); 177 | } 178 | 179 | protected override System.Drawing.Bitmap Icon 180 | { 181 | get 182 | { 183 | return Properties.Resources.layer; 184 | } 185 | } 186 | 187 | public override Guid ComponentGuid 188 | { 189 | get { return new Guid("{8F33D7B4-FF14-438A-B49B-7DF895890BDD}"); } 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/CoordinateTransformation.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Grasshopper.Kernel.Types; 3 | using Grasshopper.Kernel.Data; 4 | using Rhino.Geometry; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | using OSGeo.OGR; 9 | 10 | namespace Heron 11 | { 12 | public class CoordinateTransformation : HeronComponent 13 | { 14 | /// 15 | /// Initializes a new instance of the TranslateTo class. 16 | /// 17 | public CoordinateTransformation() 18 | : base("Coordinate Transformation", "CT", 19 | "Transform points from a source SRS to a destination SRS. The source points should be in the coordinate system of the source SRS.", 20 | "GIS Tools") 21 | { 22 | } 23 | 24 | /// 25 | /// Registers all the input parameters for this component. 26 | /// 27 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 28 | { 29 | pManager.AddPointParameter("Source Points", "sourcePoints", "Points to transform.", GH_ParamAccess.tree); 30 | pManager.AddTextParameter("Source SRS", "sourceSRS", "Source spatial reference system from which to translate the points. " + 31 | "This can be a simple EPSG code (ie 'EPSG:4326') or a full projection string (ie text from a prj file).", GH_ParamAccess.item, "WGS84"); 32 | pManager.AddTextParameter("Destination SRS", "destSRS", "Destination spatial reference system to which to translate the points. " + 33 | "This can be a simple EPSG code (ie 'EPSG:4326') or a full projection string (ie text from a prj file).", GH_ParamAccess.item, "WGS84"); 34 | } 35 | 36 | /// 37 | /// Registers all the output parameters for this component. 38 | /// 39 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 40 | { 41 | pManager.AddPointParameter("Translated Points", "destPoints", "Translated points", GH_ParamAccess.tree); 42 | } 43 | 44 | /// 45 | /// This is the method that actually does the work. 46 | /// 47 | /// The DA object is used to retrieve from inputs and store in outputs. 48 | protected override void SolveInstance(IGH_DataAccess DA) 49 | { 50 | ///GDAL setup 51 | Heron.GdalConfiguration.ConfigureOgr(); 52 | 53 | ///Working with data trees allows us to only call the osr coordinate transformation once, which seems to be expensive 54 | GH_Structure sourcePoints = new GH_Structure(); 55 | DA.GetDataTree(0, out sourcePoints); 56 | 57 | GH_Structure destPoints = new GH_Structure(); 58 | 59 | string sourceString = string.Empty; 60 | DA.GetData(1, ref sourceString); 61 | OSGeo.OSR.SpatialReference sourceSRS = new OSGeo.OSR.SpatialReference(""); 62 | sourceSRS.SetFromUserInput(sourceString); 63 | if (sourceSRS.Validate()==1) 64 | { 65 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid Source SRS."); 66 | return; 67 | } 68 | 69 | string destString = string.Empty; 70 | DA.GetData(2, ref destString); 71 | OSGeo.OSR.SpatialReference destSRS = new OSGeo.OSR.SpatialReference(""); 72 | destSRS.SetFromUserInput(destString); 73 | if (destSRS.Validate() == 1) 74 | { 75 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid Destination SRS."); 76 | return; 77 | } 78 | 79 | OSGeo.OSR.CoordinateTransformation trans = new OSGeo.OSR.CoordinateTransformation(sourceSRS, destSRS); 80 | 81 | foreach(var path in sourcePoints.Paths) 82 | { 83 | List branchPts = (List)sourcePoints.get_Branch(path); 84 | foreach (var sp in branchPts) 85 | { 86 | OSGeo.OGR.Geometry destOgrPoint = new OSGeo.OGR.Geometry(wkbGeometryType.wkbPoint); 87 | destOgrPoint.AddPoint(sp.Value.X, sp.Value.Y, sp.Value.Z); 88 | destOgrPoint.AssignSpatialReference(sourceSRS); 89 | 90 | destOgrPoint.Transform(trans); 91 | Point3d destPoint = new Point3d(destOgrPoint.GetX(0), destOgrPoint.GetY(0), destOgrPoint.GetZ(0)); 92 | 93 | destPoints.Append(new GH_Point(destPoint),path); 94 | destOgrPoint.Dispose(); 95 | } 96 | } 97 | 98 | DA.SetDataTree(0, destPoints); 99 | 100 | 101 | } 102 | 103 | /// 104 | /// Provides an Icon for the component. 105 | /// 106 | protected override System.Drawing.Bitmap Icon 107 | { 108 | get 109 | { 110 | //You can add image files to your project resources and access them like this: 111 | // return Resources.IconForThisComponent; 112 | return Properties.Resources.xytodd; 113 | } 114 | } 115 | 116 | /// 117 | /// Gets the unique ID for this component. Do not change this ID after release. 118 | /// 119 | public override Guid ComponentGuid 120 | { 121 | get { return new Guid("0c32eee6-1721-4a0b-bd68-a10b0a7b6ccb"); } 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/DDtoXY.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Rhino.Geometry; 3 | using System; 4 | 5 | namespace Heron 6 | { 7 | public class DDtoXY : HeronComponent 8 | { 9 | //Class Constructor 10 | public DDtoXY() : base("Decimal Degrees to XY", "DDtoXY", "Convert WGS84 Decimal Degrees Longitude/Latitude to X/Y", "GIS Tools") 11 | { 12 | 13 | } 14 | 15 | 16 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 17 | { 18 | pManager.AddNumberParameter("Latitude", "LAT", "Decimal Degree Latitude", GH_ParamAccess.item); 19 | pManager.AddNumberParameter("Longitude", "LON", "Decimal Degree Longitude", GH_ParamAccess.item); 20 | pManager[0].Optional = true; 21 | pManager[1].Optional = true; 22 | } 23 | 24 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 25 | { 26 | pManager.AddPointParameter("xyPoint", "xyPoint", "Longitude/Latitude translated to X/Y", GH_ParamAccess.item); 27 | pManager.AddTransformParameter("Transform", "xForm", "The transform from WGS to XYZ", GH_ParamAccess.item); 28 | 29 | } 30 | 31 | protected override void SolveInstance(IGH_DataAccess DA) 32 | { 33 | ///GDAL setup 34 | Heron.GdalConfiguration.ConfigureOgr(); 35 | 36 | ///Set transform from input spatial reference to Heron spatial reference 37 | OSGeo.OSR.SpatialReference heronSRS = new OSGeo.OSR.SpatialReference(""); 38 | heronSRS.SetFromUserInput(HeronSRS.Instance.SRS); 39 | OSGeo.OSR.SpatialReference wgsSRS = new OSGeo.OSR.SpatialReference(""); 40 | wgsSRS.SetFromUserInput("WGS84"); 41 | //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Heron's Spatial Spatial Reference System (SRS): " + HeronSRS.Instance.SRS); 42 | int heronSRSInt = Int16.Parse(heronSRS.GetAuthorityCode(null)); 43 | Message = "EPSG:" + heronSRSInt; 44 | 45 | ///Apply EAP to HeronSRS 46 | Transform userSRSToModelTransform = Heron.Convert.GetUserSRSToHeronSRSTransform(heronSRS); 47 | Transform wgsToHeronSRSTransform = Heron.Convert.GetUserSRSToHeronSRSTransform(wgsSRS); 48 | 49 | ///Set transforms between source and HeronSRS 50 | OSGeo.OSR.CoordinateTransformation coordTransform = new OSGeo.OSR.CoordinateTransformation(wgsSRS, heronSRS); 51 | 52 | ///Dump out the transform first 53 | DA.SetData("Transform", wgsToHeronSRSTransform); 54 | 55 | 56 | /// Then, we need to retrieve all data from the input parameters. 57 | /// We'll start by declaring variables and assigning them starting values. 58 | double lat = -1; 59 | double lon = -1; 60 | 61 | /// Then we need to access the input parameters individually. 62 | /// When data cannot be extracted from a parameter, we should abort this method. 63 | if (!DA.GetData("Latitude", ref lat)) return; 64 | if (!DA.GetData("Longitude", ref lon)) return; 65 | 66 | /// We should now validate the data and warn the user if invalid data is supplied. 67 | if (lat < -90.0 || lat > 90.0) 68 | { 69 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Latitude should be between -90.0 deg and 90.0 deg"); 70 | return; 71 | } 72 | if (lon < -180.0 || lon > 180.0) 73 | { 74 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Longitude should be between -180.0 deg and 180.0 deg"); 75 | return; 76 | } 77 | 78 | Point3d dd = Heron.Convert.OSRTransformPoint3dToPoint3d(new Point3d(lon, lat, 0), coordTransform); 79 | dd.Transform(userSRSToModelTransform); 80 | DA.SetData("xyPoint", dd); 81 | 82 | } 83 | 84 | protected override System.Drawing.Bitmap Icon 85 | { 86 | get 87 | { 88 | return Properties.Resources.ddtoxy; 89 | } 90 | } 91 | 92 | public override Guid ComponentGuid 93 | { 94 | get { return new Guid("{78543216-14B5-422C-85F8-BB575FBED3D2}"); } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/DMStoDD.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Rhino.Geometry; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Heron 7 | { 8 | public class DMStoDD : HeronComponent 9 | { 10 | /// 11 | /// Initializes a new instance of the DMStoDD class. 12 | /// 13 | public DMStoDD() 14 | : base("DMStoDD", "DMS to DD", 15 | "Convert Latitude and Longitude coordinates formatted in Degree Mintue Seconds (DMS) to Decimal Degree (DD) format." + 16 | "Valid Degree Minute Second formats are: 79°58′36″W | 079:56:55W | 079d 58′ 36″ W | 079 58 36.0 | 079 58 36.4 E", 17 | "GIS Tools") 18 | { 19 | } 20 | 21 | /// 22 | /// Registers all the input parameters for this component. 23 | /// 24 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 25 | { 26 | pManager.AddTextParameter("Latitude", "LAT", "Latitude in Degree Minute Second (DMS) format", GH_ParamAccess.item); 27 | pManager.AddTextParameter("Longitude", "LON", "Longitude in Degree Minute Second (DMS) format", GH_ParamAccess.item); 28 | } 29 | 30 | /// 31 | /// Registers all the output parameters for this component. 32 | /// 33 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 34 | { 35 | pManager.AddTextParameter("Latitude", "LAT", "Latitude in Decimal Degree (DD) format", GH_ParamAccess.item); 36 | pManager.AddTextParameter("Longitude", "LON", "Longitude in Decimal Degree (DD) format", GH_ParamAccess.item); 37 | } 38 | 39 | /// 40 | /// This is the method that actually does the work. 41 | /// 42 | /// The DA object is used to retrieve from inputs and store in outputs. 43 | protected override void SolveInstance(IGH_DataAccess DA) 44 | { 45 | string latString = string.Empty; 46 | string lonString = string.Empty; 47 | double lat = Double.NaN; 48 | double lon = Double.NaN; 49 | 50 | DA.GetData("Latitude", ref latString); 51 | DA.GetData("Longitude", ref lonString); 52 | 53 | lat = Heron.Convert.DMStoDDLat(latString); 54 | lon = Heron.Convert.DMStoDDLon(lonString); 55 | 56 | if (!Double.IsNaN(lat) && Double.IsNaN(lon)) 57 | { 58 | DA.SetData("Latitude", lat); 59 | return; 60 | } 61 | 62 | else if (Double.IsNaN(lat) && !Double.IsNaN(lon)) 63 | { 64 | DA.SetData("Longitude", lon); 65 | } 66 | 67 | else if (Double.IsNaN(lat) && Double.IsNaN(lon)) 68 | { 69 | return; 70 | } 71 | 72 | else 73 | { 74 | DA.SetData("Latitude", lat); 75 | DA.SetData("Longitude", lon); 76 | } 77 | } 78 | 79 | /// 80 | /// Provides an Icon for the component. 81 | /// 82 | protected override System.Drawing.Bitmap Icon 83 | { 84 | get 85 | { 86 | return Properties.Resources.ddtoxy; 87 | } 88 | } 89 | 90 | /// 91 | /// Gets the unique ID for this component. Do not change this ID after release. 92 | /// 93 | public override Guid ComponentGuid 94 | { 95 | get { return new Guid("570bd625-a7c6-4ec5-a6bc-a4b6ad70e528"); } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/GdalConcaveHull.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Grasshopper.Kernel.Data; 3 | using Grasshopper.Kernel.Types; 4 | using OSGeo.OGR; 5 | using Rhino.Geometry; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Heron.Components.GIS_Tools 11 | { 12 | public class GdalConcaveHull : HeronComponent 13 | { 14 | /// 15 | /// Initializes a new instance of the MyComponent1 class. 16 | /// 17 | public GdalConcaveHull() 18 | : base("Gdal Concave Hull", "GCCH", 19 | "Create a concave hull around geometry using Gdal's concave hull function. GDAL concave hull only works in 2D, so the results will be on the XY plane.", 20 | "GIS Tools") 21 | { 22 | } 23 | 24 | public override Grasshopper.Kernel.GH_Exposure Exposure 25 | { 26 | get { return GH_Exposure.tertiary; } 27 | } 28 | 29 | /// 30 | /// Registers all the input parameters for this component. 31 | /// 32 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 33 | { 34 | pManager.AddGeometryParameter("Feature Geometry", "FG", "Geometry contained in the feature. Geometry can be point(s), polyline(s), mesh(es) or a combination of these.", GH_ParamAccess.tree); 35 | pManager.AddNumberParameter("Ratio", "R", "Ratio of the area of the convex hull and the concave hull. A value of 1 will result in the convex hull.", GH_ParamAccess.tree); 36 | } 37 | 38 | /// 39 | /// Registers all the output parameters for this component. 40 | /// 41 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 42 | { 43 | pManager.AddGeometryParameter("Hull Geometry", "H", "Hull geometry.", GH_ParamAccess.tree); 44 | } 45 | 46 | /// 47 | /// This is the method that actually does the work. 48 | /// 49 | /// The DA object is used to retrieve from inputs and store in outputs. 50 | protected override void SolveInstance(IGH_DataAccess DA) 51 | { 52 | 53 | GH_Structure gGoo = new GH_Structure(); 54 | DA.GetDataTree("Feature Geometry", out gGoo); 55 | 56 | GH_Structure ratios = new GH_Structure(); 57 | DA.GetDataTree("Ratio", out ratios); 58 | 59 | GH_Structure gGooHull = new GH_Structure(); 60 | 61 | ///GDAL setup 62 | Heron.GdalConfiguration.ConfigureOgr(); 63 | 64 | ///Use WGS84 spatial reference 65 | OSGeo.OSR.SpatialReference dst = new OSGeo.OSR.SpatialReference(""); 66 | dst.SetWellKnownGeogCS("WGS84"); 67 | Transform transform = new Transform(1); 68 | Transform revTransform = new Transform(1); 69 | 70 | ///Create virtual datasource to be converted later 71 | ///Using geojson as a flexiblle base file type which can be converted later with ogr2ogr 72 | OSGeo.OGR.Driver drv = Ogr.GetDriverByName("GeoJSON"); 73 | DataSource ds = drv.CreateDataSource("/vsimem/out.geojson", null); 74 | 75 | ///Use OGR catch-all for geometry types 76 | var gtype = wkbGeometryType.wkbGeometryCollection; 77 | 78 | ///Create layer 79 | OSGeo.OGR.Layer layer = ds.CreateLayer("temp", dst, gtype, null); 80 | FeatureDefn def = layer.GetLayerDefn(); 81 | 82 | var branchPaths = gGoo.Paths; 83 | 84 | for (int a = 0; a < gGoo.Branches.Count; a++) 85 | { 86 | ///create feature 87 | OSGeo.OGR.Feature feature = new OSGeo.OGR.Feature(def); 88 | 89 | ///Get geometry type(s) in branch 90 | var geomList = gGoo.Branches[a]; 91 | List geomTypeList = geomList.Select(o => o.TypeName).ToList(); 92 | 93 | var ratioList = ratios.Branches[a]; 94 | GH_Convert.ToDouble(ratioList[0], out double ratio, GH_Conversion.Primary); 95 | 96 | ///Add geomtery to feature 97 | ///Create containers for translating from GH Goo 98 | Point3d pt = new Point3d(); 99 | List pts = new List(); 100 | 101 | Curve crv = null; 102 | List crvs = new List(); 103 | 104 | Mesh mesh = new Mesh(); 105 | Mesh multiMesh = new Mesh(); 106 | 107 | OSGeo.OGR.Geometry geoCollection = new OSGeo.OGR.Geometry(wkbGeometryType.wkbGeometryCollection); 108 | for (int gInt = 0; gInt < geomList.Count; gInt++) 109 | { 110 | string geomTypeMixed = geomTypeList[gInt]; 111 | switch (geomTypeMixed) 112 | { 113 | case "Point": 114 | geomList[gInt].CastTo(out pt); 115 | geoCollection.AddGeometry(Heron.Convert.Point3dToOgrPoint(pt, transform)); 116 | break; 117 | 118 | case "Curve": 119 | geomList[gInt].CastTo(out crv); 120 | geoCollection.AddGeometry(Heron.Convert.CurveToOgrLinestring(crv, transform)); 121 | break; 122 | 123 | case "Mesh": 124 | geomList[gInt].CastTo(out mesh); 125 | geoCollection.AddGeometry(Ogr.ForceToMultiPolygon(Heron.Convert.MeshToMultiPolygon(mesh, transform))); 126 | break; 127 | 128 | default: 129 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Not able to export " + geomTypeMixed + " geometry at branch " + gGoo.get_Path(a).ToString() + 130 | ". Geometry must be a Point, Curve or Mesh."); 131 | break; 132 | } 133 | 134 | } 135 | 136 | ///Need to wait until GEOS 3.11 is included with the GDAL nuget package 137 | var hullCol = geoCollection.ConcaveHull(ratio,true); 138 | gGooHull.AppendRange(Heron.Convert.OgrGeomToGHGoo(hullCol, revTransform), new GH_Path(a)); 139 | 140 | } 141 | 142 | def.Dispose(); 143 | layer.Dispose(); 144 | ds.Dispose(); 145 | 146 | DA.SetDataTree(0, gGooHull); 147 | } 148 | 149 | /// 150 | /// Provides an Icon for the component. 151 | /// 152 | protected override System.Drawing.Bitmap Icon 153 | { 154 | get 155 | { 156 | //You can add image files to your project resources and access them like this: 157 | // return Resources.IconForThisComponent; 158 | return Properties.Resources.shp; 159 | } 160 | } 161 | 162 | /// 163 | /// Gets the unique ID for this component. Do not change this ID after release. 164 | /// 165 | public override Guid ComponentGuid 166 | { 167 | get { return new Guid("C56FC98A-98DA-49F8-8621-8677E4520D90"); } 168 | } 169 | } 170 | } -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/GdalConvexHull.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Grasshopper.Kernel.Data; 3 | using Grasshopper.Kernel.Types; 4 | using OSGeo.OGR; 5 | using Rhino.Geometry; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Heron.Components.GIS_Tools 11 | { 12 | public class GdalConvexHull : HeronComponent 13 | { 14 | /// 15 | /// Initializes a new instance of the MyComponent1 class. 16 | /// 17 | public GdalConvexHull() 18 | : base("Gdal Convex Hull", "GCVH", 19 | "Create a convex hull around geometry using Gdal's convex hull function. GDAL convex hull only works in 2D, so the results will be on the XY plane.", 20 | "GIS Tools") 21 | { 22 | } 23 | 24 | public override Grasshopper.Kernel.GH_Exposure Exposure 25 | { 26 | get { return GH_Exposure.tertiary; } 27 | } 28 | 29 | /// 30 | /// Registers all the input parameters for this component. 31 | /// 32 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 33 | { 34 | pManager.AddGeometryParameter("Feature Geometry", "FG", "Geometry contained in the feature. Geometry can be point(s), polyline(s), mesh(es) or a combination of these.", GH_ParamAccess.tree); 35 | } 36 | 37 | /// 38 | /// Registers all the output parameters for this component. 39 | /// 40 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 41 | { 42 | pManager.AddGeometryParameter("Hull Geometry", "H", "Hull geometry.", GH_ParamAccess.tree); 43 | } 44 | 45 | /// 46 | /// This is the method that actually does the work. 47 | /// 48 | /// The DA object is used to retrieve from inputs and store in outputs. 49 | protected override void SolveInstance(IGH_DataAccess DA) 50 | { 51 | 52 | GH_Structure gGoo = new GH_Structure(); 53 | DA.GetDataTree("Feature Geometry", out gGoo); 54 | 55 | GH_Structure gGooHull = new GH_Structure(); 56 | 57 | ///GDAL setup 58 | Heron.GdalConfiguration.ConfigureOgr(); 59 | 60 | ///Use WGS84 spatial reference 61 | OSGeo.OSR.SpatialReference dst = new OSGeo.OSR.SpatialReference(""); 62 | dst.SetWellKnownGeogCS("WGS84"); 63 | Transform transform = new Transform(1); 64 | Transform revTransform = new Transform(1); 65 | 66 | ///Create virtual datasource to be converted later 67 | ///Using geojson as a flexiblle base file type which can be converted later with ogr2ogr 68 | OSGeo.OGR.Driver drv = Ogr.GetDriverByName("GeoJSON"); 69 | DataSource ds = drv.CreateDataSource("/vsimem/out.geojson", null); 70 | 71 | ///Use OGR catch-all for geometry types 72 | var gtype = wkbGeometryType.wkbGeometryCollection; 73 | 74 | ///Create layer 75 | OSGeo.OGR.Layer layer = ds.CreateLayer("temp", dst, gtype, null); 76 | FeatureDefn def = layer.GetLayerDefn(); 77 | 78 | var branchPaths = gGoo.Paths; 79 | 80 | for (int a = 0; a < gGoo.Branches.Count; a++) 81 | { 82 | ///create feature 83 | OSGeo.OGR.Feature feature = new OSGeo.OGR.Feature(def); 84 | 85 | ///Get geometry type(s) in branch 86 | var geomList = gGoo.Branches[a]; 87 | 88 | List geomTypeList = geomList.Select(o => o.TypeName).ToList(); 89 | 90 | ///Add geomtery to feature 91 | ///Create containers for translating from GH Goo 92 | Point3d pt = new Point3d(); 93 | List pts = new List(); 94 | 95 | Curve crv = null; 96 | List crvs = new List(); 97 | 98 | Mesh mesh = new Mesh(); 99 | Mesh multiMesh = new Mesh(); 100 | 101 | 102 | OSGeo.OGR.Geometry geoCollection = new OSGeo.OGR.Geometry(wkbGeometryType.wkbGeometryCollection); 103 | for (int gInt = 0; gInt < geomList.Count; gInt++) 104 | { 105 | string geomTypeMixed = geomTypeList[gInt]; 106 | switch (geomTypeMixed) 107 | { 108 | case "Point": 109 | geomList[gInt].CastTo(out pt); 110 | geoCollection.AddGeometry(Heron.Convert.Point3dToOgrPoint(pt, transform)); 111 | break; 112 | 113 | case "Curve": 114 | geomList[gInt].CastTo(out crv); 115 | geoCollection.AddGeometry(Heron.Convert.CurveToOgrLinestring(crv, transform)); 116 | break; 117 | 118 | case "Mesh": 119 | geomList[gInt].CastTo(out mesh); 120 | geoCollection.AddGeometry(Ogr.ForceToMultiPolygon(Heron.Convert.MeshToMultiPolygon(mesh, transform))); 121 | break; 122 | 123 | default: 124 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Not able to export " + geomTypeMixed + " geometry at branch " + gGoo.get_Path(a).ToString() + 125 | ". Geometry must be a Point, Curve or Mesh."); 126 | break; 127 | } 128 | 129 | } 130 | 131 | var hullCol = geoCollection.ConvexHull(); 132 | gGooHull.AppendRange(Heron.Convert.OgrGeomToGHGoo(hullCol, revTransform), new GH_Path(a)); 133 | 134 | } 135 | 136 | def.Dispose(); 137 | layer.Dispose(); 138 | ds.Dispose(); 139 | 140 | DA.SetDataTree(0, gGooHull); 141 | } 142 | 143 | /// 144 | /// Provides an Icon for the component. 145 | /// 146 | protected override System.Drawing.Bitmap Icon 147 | { 148 | get 149 | { 150 | //You can add image files to your project resources and access them like this: 151 | // return Resources.IconForThisComponent; 152 | return Properties.Resources.shp; 153 | } 154 | } 155 | 156 | /// 157 | /// Gets the unique ID for this component. Do not change this ID after release. 158 | /// 159 | public override Guid ComponentGuid 160 | { 161 | get { return new Guid("E09EE6ED-8126-4624-AE3B-B400C43DDDE0"); } 162 | } 163 | } 164 | } -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/GdalFillNoData.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using OSGeo.GDAL; 3 | using System; 4 | using System.IO; 5 | 6 | namespace Heron 7 | { 8 | public class GdalFillNoData : HeronComponent 9 | { 10 | /// 11 | /// Initializes a new instance of the GdalTranslate class. 12 | /// 13 | public GdalFillNoData() 14 | : base("Gdal Fill No Data", "GFND", 15 | "Fill raster regions that have no data by interpolation from edges with the GDAL FillNoData program. " + 16 | "More information can be found at https://gdal.org/programs/gdal_fillnodata.html.", 17 | "GIS Tools") 18 | { 19 | } 20 | 21 | public override Grasshopper.Kernel.GH_Exposure Exposure 22 | { 23 | get { return GH_Exposure.tertiary; } 24 | } 25 | 26 | /// 27 | /// Registers all the input parameters for this component. 28 | /// 29 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 30 | { 31 | pManager.AddTextParameter("Source dataset", "S", "File location for the source raster dataset.", GH_ParamAccess.item); 32 | pManager.AddTextParameter("Destination dataset", "D", "File location for the destination dataset.", GH_ParamAccess.item); 33 | pManager.AddIntegerParameter("Max Distance", "MD", "The maximum distance (in pixels) that the algorithm will search out for values to interpolate. " + 34 | "The default is 100 pixels.", GH_ParamAccess.item, 100); 35 | pManager.AddIntegerParameter("Smooth Iterations", "SI", "The number of 3x3 average filter smoothing iterations to run after the interpolation to dampen artifacts. " + 36 | "The default is zero smoothing iterations.", GH_ParamAccess.item, 0); 37 | pManager.AddIntegerParameter("Band", "B", "The band to operate on, by default the first band is operated on.", GH_ParamAccess.item, 1); 38 | pManager[2].Optional = true; 39 | pManager[3].Optional = true; 40 | pManager[4].Optional = true; 41 | } 42 | 43 | /// 44 | /// Registers all the output parameters for this component. 45 | /// 46 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 47 | { 48 | pManager.AddTextParameter("Destination File", "D", "File location of destination datasource.", GH_ParamAccess.item); 49 | } 50 | 51 | /// 52 | /// This is the method that actually does the work. 53 | /// 54 | /// The DA object is used to retrieve from inputs and store in outputs. 55 | protected override void SolveInstance(IGH_DataAccess DA) 56 | { 57 | string datasourceFileLocation = string.Empty; 58 | DA.GetData(0, ref datasourceFileLocation); 59 | 60 | string dstFileLocation = string.Empty; 61 | DA.GetData(1, ref dstFileLocation); 62 | 63 | int maxDistance = 100; 64 | DA.GetData(2, ref maxDistance); 65 | 66 | int smoothIterations = 0; 67 | DA.GetData(3, ref smoothIterations); 68 | 69 | int band = 1; 70 | DA.GetData(4, ref band); 71 | 72 | string dstOutput = string.Empty; 73 | 74 | 75 | Heron.GdalConfiguration.ConfigureGdal(); 76 | OSGeo.GDAL.Gdal.AllRegister(); 77 | 78 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Look for more information about options at:"); 79 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "https://gdal.org/programs/gdal_fillnodata.html"); 80 | 81 | if (!string.IsNullOrEmpty(datasourceFileLocation)) 82 | { 83 | using (Dataset datasource = Gdal.Open(datasourceFileLocation, Access.GA_ReadOnly)) 84 | { 85 | if (datasource == null) 86 | { 87 | throw new Exception("Can't open GDAL dataset: " + datasourceFileLocation); 88 | } 89 | 90 | if (!string.IsNullOrEmpty(dstFileLocation)) 91 | { 92 | if(File.Exists(dstFileLocation)) 93 | { 94 | File.Delete(dstFileLocation); 95 | } 96 | OSGeo.GDAL.Driver drv = datasource.GetDriver(); 97 | Dataset dst = drv.CreateCopy(dstFileLocation, datasource, 0, null, null, null); 98 | int filled = Gdal.FillNodata(dst.GetRasterBand(band), null, (double)maxDistance, smoothIterations, null, null, null); 99 | dst.Dispose(); 100 | dstOutput = dstFileLocation; 101 | } 102 | datasource.Dispose(); 103 | } 104 | } 105 | 106 | DA.SetData(0, dstOutput); 107 | 108 | } 109 | 110 | /// 111 | /// Provides an Icon for the component. 112 | /// 113 | protected override System.Drawing.Bitmap Icon 114 | { 115 | get 116 | { 117 | return Properties.Resources.raster; 118 | } 119 | } 120 | 121 | /// 122 | /// Gets the unique ID for this component. Do not change this ID after release. 123 | /// 124 | public override Guid ComponentGuid 125 | { 126 | get { return new Guid("0E773376-BB1B-42DA-8366-D6273BDF8755"); } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/GdalInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text.RegularExpressions; 7 | 8 | using Grasshopper.Kernel; 9 | using Rhino.Geometry; 10 | 11 | using OSGeo.GDAL; 12 | using OSGeo.OSR; 13 | using OSGeo.OGR; 14 | 15 | namespace Heron 16 | { 17 | public class GdalInfo : HeronComponent 18 | { 19 | /// 20 | /// Initializes a new instance of the GdalTranslate class. 21 | /// 22 | public GdalInfo() 23 | : base("Gdal Info", "GI", 24 | "Gdalinfo program lists various information about a GDAL supported raster dataset. " + 25 | "More information about Gdalinfo options can be found at https://gdal.org/programs/gdalinfo.html.", 26 | "GIS Tools") 27 | { 28 | } 29 | 30 | public override Grasshopper.Kernel.GH_Exposure Exposure 31 | { 32 | get { return GH_Exposure.tertiary; } 33 | } 34 | 35 | /// 36 | /// Registers all the input parameters for this component. 37 | /// 38 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 39 | { 40 | pManager.AddTextParameter("Source dataset", "S", "File location for the source raster dataset.", GH_ParamAccess.item); 41 | pManager.AddTextParameter("Options", "O", "String of options with a space separating each term. " + 42 | "For instance, to report histogram information for all bands, the options string would be '-hist'.", GH_ParamAccess.item); 43 | pManager[1].Optional = true; 44 | } 45 | 46 | /// 47 | /// Registers all the output parameters for this component. 48 | /// 49 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 50 | { 51 | pManager.AddTextParameter("Source Info", "I", "List of information about the source dataset.", GH_ParamAccess.item); 52 | } 53 | 54 | /// 55 | /// This is the method that actually does the work. 56 | /// 57 | /// The DA object is used to retrieve from inputs and store in outputs. 58 | protected override void SolveInstance(IGH_DataAccess DA) 59 | { 60 | string datasourceFileLocation = string.Empty; 61 | DA.GetData(0, ref datasourceFileLocation); 62 | 63 | string options = string.Empty; 64 | DA.GetData(1, ref options); 65 | 66 | var re = new System.Text.RegularExpressions.Regex("(?<=\")[^\"]*(?=\")|[^\" ]+"); 67 | string[] infoOptions = re.Matches(options).Cast().Select(m => m.Value).ToArray(); 68 | 69 | string datasourceInfo = string.Empty; 70 | string dstInfo = string.Empty; 71 | string dstOutput = string.Empty; 72 | 73 | Heron.GdalConfiguration.ConfigureGdal(); 74 | OSGeo.GDAL.Gdal.AllRegister(); 75 | ///Specific settings for getting WMS images 76 | OSGeo.GDAL.Gdal.SetConfigOption("GDAL_HTTP_UNSAFESSL", "YES"); 77 | OSGeo.GDAL.Gdal.SetConfigOption("GDAL_SKIP", "WMS"); 78 | 79 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Look for more information about options at:"); 80 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "https://gdal.org/programs/gdalinfo.html"); 81 | 82 | if (!string.IsNullOrEmpty(datasourceFileLocation)) 83 | { 84 | //using (Dataset datasource = Gdal.OpenEx(datasourceFileLocation,0, null,null,null)) 85 | using (Dataset datasource = Gdal.Open(datasourceFileLocation, Access.GA_ReadOnly)) 86 | { 87 | if (datasource == null) 88 | { 89 | throw new Exception("Can't open GDAL dataset: " + datasourceFileLocation); 90 | } 91 | 92 | datasourceInfo = Gdal.GDALInfo(datasource, new GDALInfoOptions(infoOptions.ToArray())); 93 | datasource.Dispose(); 94 | } 95 | } 96 | 97 | DA.SetData(0, datasourceInfo); 98 | } 99 | 100 | /// 101 | /// Provides an Icon for the component. 102 | /// 103 | protected override System.Drawing.Bitmap Icon 104 | { 105 | get 106 | { 107 | return Properties.Resources.raster; 108 | } 109 | } 110 | 111 | /// 112 | /// Gets the unique ID for this component. Do not change this ID after release. 113 | /// 114 | public override Guid ComponentGuid 115 | { 116 | get { return new Guid("35AF7648-AAAD-464F-8343-B7DA339788FB"); } 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/GdalTranslate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text.RegularExpressions; 7 | 8 | using Grasshopper.Kernel; 9 | using Rhino.Geometry; 10 | 11 | using OSGeo.GDAL; 12 | using OSGeo.OSR; 13 | using OSGeo.OGR; 14 | 15 | namespace Heron 16 | { 17 | public class GdalTranslate : HeronComponent 18 | { 19 | /// 20 | /// Initializes a new instance of the GdalTranslate class. 21 | /// 22 | public GdalTranslate() 23 | : base("GdalTranslate", "GdalTranslate", 24 | "Manipulate raster data with the GDAL Translate program given a source dataset, a destination dataset and a list of options. " + 25 | "Formatting for the list of options should be a single string of text with a space separating each term " + 26 | "where '-' should preceed the option parameter and the next item in the list should be that parameter's value. " + 27 | "For instance, to convert raster data to PNG format the options string would be '-of PNG'. To clip a large raster data set " + 28 | "to a boundary of upper left x (ulx), upper left y (uly), lower right x (lrx) and lower right y (lry), the options string " + 29 | "would be '-projwin ulx uly lrx lry' where ulx, uly, lrx and lry are substituted with coordinate values. " + 30 | "More information about translate options can be found at https://gdal.org/programs/gdal_translate.html.", 31 | "GIS Tools") 32 | { 33 | } 34 | 35 | public override Grasshopper.Kernel.GH_Exposure Exposure 36 | { 37 | get { return GH_Exposure.tertiary; } 38 | } 39 | 40 | /// 41 | /// Registers all the input parameters for this component. 42 | /// 43 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 44 | { 45 | pManager.AddTextParameter("Source dataset", "source", "File location for the source raster dataset.", GH_ParamAccess.item); 46 | pManager.AddTextParameter("Destination dataset", "dest", "File location for the destination dataset.", GH_ParamAccess.item); 47 | pManager.AddTextParameter("Options", "options", "String of options with a space separating each term. " + 48 | "For instance, to convert raster data to PNG format the options string would be '-of PNG'.", GH_ParamAccess.item); 49 | pManager[0].Optional = true; 50 | pManager[1].Optional = true; 51 | pManager[2].Optional = true; 52 | } 53 | 54 | /// 55 | /// Registers all the output parameters for this component. 56 | /// 57 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 58 | { 59 | pManager.AddTextParameter("Source Info", "sourceInfo", "List of information about the source dataset.", GH_ParamAccess.item); 60 | pManager.AddTextParameter("Destination Info", "destInfo", "List of information about the destination dataset.", GH_ParamAccess.item); 61 | pManager.AddTextParameter("Destination File", "destFile", "File location of destination datasource.", GH_ParamAccess.item); 62 | } 63 | 64 | /// 65 | /// This is the method that actually does the work. 66 | /// 67 | /// The DA object is used to retrieve from inputs and store in outputs. 68 | protected override void SolveInstance(IGH_DataAccess DA) 69 | { 70 | string datasourceFileLocation = string.Empty; 71 | DA.GetData(0, ref datasourceFileLocation); 72 | 73 | string dstFileLocation = string.Empty; 74 | DA.GetData(1, ref dstFileLocation); 75 | 76 | string options = string.Empty; 77 | DA.GetData(2, ref options); 78 | 79 | var re = new System.Text.RegularExpressions.Regex("(?<=\")[^\"]*(?=\")|[^\" ]+"); 80 | string[] translateOptions = re.Matches(options).Cast().Select(m => m.Value).ToArray(); 81 | 82 | string datasourceInfo = string.Empty; 83 | string dstInfo = string.Empty; 84 | string dstOutput = string.Empty; 85 | 86 | Heron.GdalConfiguration.ConfigureGdal(); 87 | OSGeo.GDAL.Gdal.AllRegister(); 88 | ///Specific settings for getting WMS images 89 | OSGeo.GDAL.Gdal.SetConfigOption("GDAL_HTTP_UNSAFESSL", "YES"); 90 | OSGeo.GDAL.Gdal.SetConfigOption("GDAL_SKIP", "WMS"); 91 | 92 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Look for more information about options at:"); 93 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "https://gdal.org/programs/gdal_translate.html"); 94 | 95 | if (!string.IsNullOrEmpty(datasourceFileLocation)) 96 | { 97 | using (Dataset datasource = Gdal.Open(datasourceFileLocation, Access.GA_ReadOnly)) 98 | { 99 | if (datasource == null) 100 | { 101 | throw new Exception("Can't open GDAL dataset: " + datasourceFileLocation); 102 | } 103 | 104 | SpatialReference sr = new SpatialReference(datasource.GetProjection()); 105 | 106 | ///Check if SRS needs to be converted from ESRI format to WKT to avoid error: 107 | ///"No translation for Lambert_Conformal_Conic to PROJ.4 format is known." 108 | ///https://gis.stackexchange.com/questions/128266/qgis-error-6-no-translation-for-lambert-conformal-conic-to-proj-4-format-is-kn 109 | SpatialReference srEsri = sr; 110 | srEsri.MorphFromESRI(); 111 | string projEsri = string.Empty; 112 | srEsri.ExportToWkt(out projEsri, null); 113 | 114 | ///If no SRS exists, check Ground Control Points SRS 115 | SpatialReference srGCP = new SpatialReference(datasource.GetGCPProjection()); 116 | string projGCP = string.Empty; 117 | srGCP.ExportToWkt(out projGCP, null); 118 | 119 | if (!string.IsNullOrEmpty(projEsri)) 120 | { 121 | datasource.SetProjection(projEsri); 122 | sr = srEsri; 123 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Spatial Reference System (SRS) morphed form ESRI format."); 124 | } 125 | else if (!string.IsNullOrEmpty(projGCP)) 126 | { 127 | datasource.SetProjection(projGCP); 128 | sr = srGCP; 129 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Spatial Reference System (SRS) set from Ground Control Points (GCPs)."); 130 | } 131 | else 132 | { 133 | AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Spatial Reference System (SRS) is unknown or unsupported. " + 134 | "Try setting the SRS with the GdalWarp component using -t_srs EPSG:4326 for the option input."); 135 | //sr.SetWellKnownGeogCS("WGS84"); 136 | } 137 | 138 | ///Get info about image 139 | List infoOptions = new List { 140 | "-stats" 141 | }; 142 | datasourceInfo = Gdal.GDALInfo(datasource, new GDALInfoOptions(infoOptions.ToArray())); 143 | 144 | if (!string.IsNullOrEmpty(dstFileLocation)) 145 | { 146 | if (string.IsNullOrEmpty(options) && File.Exists(dstFileLocation)) 147 | { 148 | Dataset dst = Gdal.Open(dstFileLocation, Access.GA_ReadOnly); 149 | dstInfo = Gdal.GDALInfo(dst, null); 150 | dst.Dispose(); 151 | dstOutput = dstFileLocation; 152 | } 153 | else 154 | { 155 | Dataset dst = Gdal.wrapper_GDALTranslate(dstFileLocation, datasource, new GDALTranslateOptions(translateOptions), null, null); 156 | dstInfo = Gdal.GDALInfo(dst, new GDALInfoOptions(infoOptions.ToArray())); 157 | dst.Dispose(); 158 | dstOutput = dstFileLocation; 159 | } 160 | } 161 | datasource.Dispose(); 162 | } 163 | } 164 | 165 | DA.SetData(0, datasourceInfo); 166 | DA.SetData(1, dstInfo); 167 | DA.SetData(2, dstOutput); 168 | } 169 | 170 | /// 171 | /// Provides an Icon for the component. 172 | /// 173 | protected override System.Drawing.Bitmap Icon 174 | { 175 | get 176 | { 177 | return Properties.Resources.raster; 178 | } 179 | } 180 | 181 | /// 182 | /// Gets the unique ID for this component. Do not change this ID after release. 183 | /// 184 | public override Guid ComponentGuid 185 | { 186 | get { return new Guid("c9056659-a5f8-4cc0-89f3-0e2f22b08afc"); } 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/SetEAP.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Newtonsoft.Json.Linq; 3 | using Rhino.DocObjects; 4 | using System; 5 | using System.Linq; 6 | 7 | namespace Heron 8 | { 9 | public class SetEAP : HeronComponent 10 | { 11 | //Class Constructor 12 | public SetEAP() : base("Set EarthAnchorPoint", "SetEAP", "Set the Rhino EarthAnchorPoint using either an address or Lat/Lon coordinates", "GIS Tools") 13 | { 14 | 15 | } 16 | 17 | 18 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 19 | { 20 | pManager.AddBooleanParameter("Set EAP", "set", "Set the EarthAnchorPoint", GH_ParamAccess.item, false); 21 | pManager.AddTextParameter("Point of Interest", "poi", "Point of interest or address with which to set the EarthAnchorPoint. " + 22 | "If a point of interest or address is supplied, this component will query the ESRI geolocation service and set the EAP to the first coordinates in the list of candidates.", GH_ParamAccess.item); 23 | pManager[1].Optional = true; 24 | pManager.AddTextParameter("Latitude", "LAT", "Latitude in either Decimal Degree (DD) or Degree Minute Second (DMS) format", GH_ParamAccess.item); 25 | pManager[2].Optional = true; 26 | pManager.AddTextParameter("Longitude", "LON", "Longitude in either Decimal Degree (DD) or Degree Minute Second (DMS) format", GH_ParamAccess.item); 27 | pManager[3].Optional = true; 28 | } 29 | 30 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 31 | { 32 | pManager.AddTextParameter("Earth Anchor Point", "EAP", "EarthAnchorPoint Longitude/Latitude", GH_ParamAccess.item); 33 | } 34 | 35 | protected override void SolveInstance(IGH_DataAccess DA) 36 | { 37 | string latString = string.Empty; 38 | string lonString = string.Empty; 39 | double lat = Double.NaN; 40 | double lon = Double.NaN; 41 | bool EAP = false; 42 | string address = string.Empty; 43 | string lonlatString = string.Empty; 44 | string addressString = string.Empty; 45 | 46 | DA.GetData("Set EAP", ref EAP); 47 | DA.GetData("Point of Interest", ref address); 48 | DA.GetData("Latitude", ref latString); 49 | DA.GetData("Longitude", ref lonString); 50 | 51 | 52 | 53 | if (EAP == true) 54 | { 55 | EarthAnchorPoint ePt = new EarthAnchorPoint(); 56 | 57 | lat = Heron.Convert.DMStoDDLat(latString); 58 | lon = Heron.Convert.DMStoDDLon(lonString); 59 | 60 | if (Double.IsNaN(lat) && !string.IsNullOrEmpty(latString)) 61 | { 62 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Latitude value is invalid. Please enter value in valid Decimal Degree format (-79.976666) " + 63 | "or valid Degree Minute Second format (79°58′36″W | 079:56:55W | 079d 58′ 36″ W | 079 58 36.0 | 079 58 36.4 E)"); 64 | return; 65 | } 66 | 67 | if (Double.IsNaN(lon) && !string.IsNullOrEmpty(lonString)) 68 | { 69 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Longitude value is invalid. Please enter value in valid Decimal Degree format (40.446388) " + 70 | "or valid Degree Minute Second format (40°26′47″N | 40:26:46N | 40d 26m 47s N | 40 26 47.1 | 40 26 47.4141 N)"); 71 | return; 72 | } 73 | 74 | if (!string.IsNullOrEmpty(address) && string.IsNullOrEmpty(latString) && string.IsNullOrEmpty(lonString)) 75 | { 76 | string output = Heron.Convert.HttpToJson("https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?Address=" + address + "&f=pjson"); 77 | JObject ja = JObject.Parse(output); 78 | 79 | if (ja["candidates"].Count() < 1) 80 | { 81 | AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "No Cadidate location found for this address"); 82 | DA.SetData("Earth Anchor Point", lonlatString); 83 | return; 84 | } 85 | else 86 | { 87 | if (ja["candidates"][0]["score"].Value() > 99) 88 | { 89 | addressString = "EAP set to the following address: " + ja["candidates"][0]["address"].ToString() + "\r\n"; 90 | ePt.EarthBasepointLatitude = (double)ja["candidates"][0]["location"]["y"]; 91 | ePt.EarthBasepointLongitude = (double)ja["candidates"][0]["location"]["x"]; 92 | } 93 | } 94 | } 95 | 96 | else 97 | { 98 | if (!Double.IsNaN(lat) && !Double.IsNaN(lon)) 99 | { 100 | ePt.EarthBasepointLatitude = lat; 101 | ePt.EarthBasepointLongitude = lon; 102 | } 103 | } 104 | 105 | if ((ePt.EarthBasepointLatitude > -90) && (ePt.EarthBasepointLatitude < 90) && (ePt.EarthBasepointLongitude > -180) && (ePt.EarthBasepointLongitude < 180)) 106 | { 107 | //set new EAP 108 | Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint = ePt; 109 | } 110 | 111 | } 112 | 113 | //check if EAP has been set and if so what is it 114 | if (!Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthLocationIsSet()) 115 | { 116 | lonlatString = "The Earth Anchor Point has not been set yet"; 117 | AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "EAP has not been set yet"); 118 | } 119 | 120 | else lonlatString = "Longitude: " + Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthBasepointLongitude.ToString() + 121 | " / Latitude: " + Rhino.RhinoDoc.ActiveDoc.EarthAnchorPoint.EarthBasepointLatitude.ToString(); 122 | 123 | DA.SetData("Earth Anchor Point", lonlatString); 124 | 125 | } 126 | 127 | protected override System.Drawing.Bitmap Icon 128 | { 129 | get 130 | { 131 | return Properties.Resources.eap; 132 | } 133 | } 134 | 135 | public override Guid ComponentGuid 136 | { 137 | get { return new Guid("3A9B1B9D-9DED-4B5B-9101-ED57F5239EC8"); } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Heron/Components/GIS Tools/XYtoDD.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Rhino.Geometry; 3 | using System; 4 | 5 | namespace Heron 6 | { 7 | public class XYtoDD : HeronComponent 8 | { 9 | //Class Constructor 10 | public XYtoDD() : base("XY to Decimal Degrees", "XYtoDD", "Convert X/Y to Decimal Degrees Longitude/Latitude in the WGS84 spatial reference system", "GIS Tools") 11 | { 12 | 13 | } 14 | 15 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 16 | { 17 | pManager.AddPointParameter("xyPoint", "xyPoint", "Point to translate to Longitude/Latitude", GH_ParamAccess.item); 18 | } 19 | 20 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 21 | { 22 | pManager.AddNumberParameter("Latitude", "LAT", "Decimal Degree Latitude", GH_ParamAccess.item); 23 | pManager.AddNumberParameter("Longitude", "LON", "Decimal Degree Longitude", GH_ParamAccess.item); 24 | pManager.AddTransformParameter("Transform", "xForm", "The transform from XYZ to WGS", GH_ParamAccess.item); 25 | } 26 | 27 | protected override void SolveInstance(IGH_DataAccess DA) 28 | { 29 | ///GDAL setup 30 | Heron.GdalConfiguration.ConfigureOgr(); 31 | 32 | ///Set transform from input spatial reference to Heron spatial reference 33 | OSGeo.OSR.SpatialReference heronSRS = new OSGeo.OSR.SpatialReference(""); 34 | heronSRS.SetFromUserInput(HeronSRS.Instance.SRS); 35 | OSGeo.OSR.SpatialReference wgsSRS = new OSGeo.OSR.SpatialReference(""); 36 | wgsSRS.SetFromUserInput("WGS84"); 37 | //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Heron's Spatial Spatial Reference System (SRS): " + HeronSRS.Instance.SRS); 38 | int heronSRSInt = Int16.Parse(heronSRS.GetAuthorityCode(null)); 39 | Message = "EPSG:" + heronSRSInt; 40 | 41 | ///Apply EAP to HeronSRS 42 | Transform heronToUserSRSTransform = Heron.Convert.GetHeronSRSToUserSRSTransform(heronSRS); 43 | Transform heronToWgsSRSTransform = Heron.Convert.GetHeronSRSToUserSRSTransform(wgsSRS); 44 | 45 | ///Set transforms between source and HeronSRS 46 | OSGeo.OSR.CoordinateTransformation revTransform = new OSGeo.OSR.CoordinateTransformation(heronSRS, wgsSRS); 47 | 48 | ///Dump out the transform first 49 | DA.SetData("Transform", heronToWgsSRSTransform); 50 | 51 | 52 | Point3d xyPt = new Point3d(); 53 | if (!DA.GetData("xyPoint", ref xyPt)) return; 54 | 55 | xyPt.Transform(heronToUserSRSTransform); 56 | Point3d dd = Heron.Convert.OSRTransformPoint3dToPoint3d(xyPt, revTransform); 57 | 58 | DA.SetData("Latitude", dd.Y); 59 | DA.SetData("Longitude", dd.X); 60 | } 61 | 62 | protected override System.Drawing.Bitmap Icon 63 | { 64 | get 65 | { 66 | return Properties.Resources.xytodd; 67 | } 68 | } 69 | 70 | public override Guid ComponentGuid 71 | { 72 | get { return new Guid("{0B461B47-632B-4145-AA06-157AAFAC1DDA}"); } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Heron/Components/Utilities/ColorToHex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using Grasshopper.Kernel; 5 | using Rhino.Geometry; 6 | 7 | namespace Heron 8 | { 9 | public class ColorToHex : HeronComponent 10 | { 11 | /// 12 | /// Initializes a new instance of the ColorToHex class. 13 | /// 14 | public ColorToHex() 15 | : base("Color to Hex", "C2H", "Convert an RGBA color to hexidecimal format.", "Utilities") 16 | { 17 | } 18 | public override Grasshopper.Kernel.GH_Exposure Exposure 19 | { 20 | get { return GH_Exposure.quarternary; } 21 | } 22 | 23 | 24 | /// 25 | /// Registers all the input parameters for this component. 26 | /// 27 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 28 | { 29 | pManager.AddColourParameter("colorRGBA", "colorRGBA", "RGBA color to convert to hexidecimal format", GH_ParamAccess.item); 30 | } 31 | 32 | /// 33 | /// Registers all the output parameters for this component. 34 | /// 35 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 36 | { 37 | pManager.AddTextParameter("colorHexidecmial", "colorHex", "Hexidecimal color converted from RGBA", GH_ParamAccess.item); 38 | } 39 | 40 | /// 41 | /// This is the method that actually does the work. 42 | /// 43 | /// The DA object is used to retrieve from inputs and store in outputs. 44 | protected override void SolveInstance(IGH_DataAccess DA) 45 | { 46 | Color color = Color.Empty; 47 | DA.GetData(0, ref color); 48 | string hex = String.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.R, color.G, color.B, color.A); 49 | DA.SetData(0, hex); 50 | } 51 | 52 | /// 53 | /// Provides an Icon for the component. 54 | /// 55 | protected override System.Drawing.Bitmap Icon 56 | { 57 | get 58 | { 59 | //You can add image files to your project resources and access them like this: 60 | // return Resources.IconForThisComponent; 61 | return Properties.Resources.raster; 62 | } 63 | } 64 | 65 | /// 66 | /// Gets the unique ID for this component. Do not change this ID after release. 67 | /// 68 | public override Guid ComponentGuid 69 | { 70 | get { return new Guid("5fd79e04-c146-4b3e-9e96-b1c0ec66310f"); } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Heron/Components/Utilities/DecimateTopoFromPoint.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Grasshopper.Kernel.Geometry; 3 | using Rhino.Geometry; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Runtime; 8 | 9 | namespace Heron.Components.Utilities 10 | { 11 | public class DecimateTopoFromPoint : HeronComponent 12 | { 13 | /// 14 | /// Initializes a new instance of the DecimateTopoFromPoint class. 15 | /// 16 | public DecimateTopoFromPoint() 17 | : base("Decimate Topography From Point", "DTP", 18 | "Reduce the number of vertexes of a topo mesh the farther they are from a given point.", 19 | "Utilities") 20 | { 21 | } 22 | 23 | public override Grasshopper.Kernel.GH_Exposure Exposure 24 | { 25 | get { return GH_Exposure.tertiary; } 26 | } 27 | 28 | /// 29 | /// Registers all the input parameters for this component. 30 | /// 31 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 32 | { 33 | pManager.AddPointParameter("View Point", "V", "The point from which to decimate the mesh. " + 34 | "The farther from this point a mesh vertex is, the more likely it will be eliminated from the mesh.", GH_ParamAccess.item); 35 | pManager.AddMeshParameter("Topography Mesh", "M", "The topographic (2.5D) mesh to be decimated.", GH_ParamAccess.item); 36 | pManager.AddNumberParameter("Distance Increments", "D", "List of distance increments for which to apply the corresponding percent reduction. " + 37 | "The number of distance and percent increments must match.", GH_ParamAccess.list); 38 | pManager[2].Optional = true; 39 | pManager.AddNumberParameter("Percent Increments", "P", "List of increments (from 0-1) by which to randomly reduce the mesh within each corresponding distance increment. " + 40 | "Numbers less than 0 and more than 1 will be clamped back to the 0-1 range. " + 41 | "The number of percent and distance increments must match.", GH_ParamAccess.list); 42 | pManager[3].Optional = true; 43 | pManager.AddIntegerParameter("Random Seed", "S", "Random seed used for randomly reducing the vertexes.", GH_ParamAccess.item, 1); 44 | } 45 | 46 | /// 47 | /// Registers all the output parameters for this component. 48 | /// 49 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 50 | { 51 | pManager.AddMeshParameter("Decimated Mesh", "M", "The decimated mesh, a 2.5D Delaunay triagulation of the decimated vertexes.", GH_ParamAccess.item); 52 | } 53 | 54 | /// 55 | /// This is the method that actually does the work. 56 | /// 57 | /// The DA object is used to retrieve from inputs and store in outputs. 58 | protected override void SolveInstance(IGH_DataAccess DA) 59 | { 60 | Point3d p = new Point3d(); 61 | DA.GetData("View Point", ref p); 62 | 63 | Mesh topoMesh = new Mesh(); 64 | DA.GetData("Topography Mesh", ref topoMesh); 65 | 66 | List distanceIncrements = new List(); 67 | DA.GetDataList("Distance Increments", distanceIncrements); 68 | 69 | List percentIncrements = new List(); 70 | DA.GetDataList("Percent Increments", percentIncrements); 71 | 72 | int seed = 1; 73 | DA.GetData("Random Seed", ref seed); 74 | 75 | BoundingBox bbox = topoMesh.GetBoundingBox(false); 76 | double diagonal = bbox.Diagonal.Length; 77 | 78 | ///Default ranges 79 | var distRanges = new List() { diagonal * 0.1 / 2, diagonal * 0.2 / 2, diagonal * 0.3 / 2, diagonal * 0.4 / 2 }; 80 | var pctRanges = new List() { 0.5, 0.8, 0.9, 0.99 }; 81 | 82 | ///Clamp values of user input 83 | if(distanceIncrements.Count != 0) { distRanges = distanceIncrements.Select(x => Math.Max(x,0.0)).ToList(); } 84 | if(percentIncrements.Count != 0) { pctRanges = percentIncrements.Select(x => Math.Min(Math.Max(x, 0.0), 1.0)).ToList(); } 85 | 86 | 87 | if (distRanges.Count != pctRanges.Count) 88 | { 89 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "The number of Distance Increments does not match the number of Percent Increments. The default is 4 increments."); 90 | return; 91 | } 92 | 93 | pctRanges.Insert(0, 0.0); 94 | 95 | 96 | List vertexPoints = topoMesh.Vertices.ToPoint3dArray().ToList(); 97 | List nakedVerts = new List(); 98 | List clothedVerts = new List(); 99 | 100 | ///Allow maintaining of naked vertexes 101 | bool keepNakedVerts = true; 102 | if (keepNakedVerts) 103 | { 104 | bool[] nakedArray = topoMesh.GetNakedEdgePointStatus(); 105 | for (int v = 0; v < nakedArray.Length; v++) 106 | { 107 | if (!nakedArray[v]) { clothedVerts.Add(vertexPoints[v]); } 108 | else { nakedVerts.Add(vertexPoints[v]); } 109 | } 110 | 111 | vertexPoints = clothedVerts; 112 | } 113 | 114 | 115 | ///Points grouped by distance 116 | var pointGroups = vertexPoints.GroupBy(x => distRanges.FirstOrDefault(r => r > Math.Sqrt(x.DistanceToSquared(p)))) 117 | .OrderBy(grp => grp.First().DistanceToSquared(p)) 118 | .Select(x => new List(x)) 119 | .ToList(); 120 | 121 | ///Randomly reduce points in a group based on user provided percentages 122 | var delPoints = new List(); 123 | for (int i=0; i rnd.Next()).Take(count)); 128 | } 129 | 130 | ///Create a Delaunay triangulated mesh 131 | delPoints.AddRange(nakedVerts); 132 | Mesh delMesh = DelaunayPoints(delPoints); 133 | delMesh.Faces.ConvertTrianglesToQuads(0, 0); 134 | 135 | DA.SetData(0, delMesh); 136 | } 137 | 138 | 139 | /// From https://discourse.mcneel.com/t/3d-delaunay/126194 140 | public Mesh DelaunayPoints(List pts) 141 | { 142 | //code from http://james-ramsden.com/create-2d-delaunay-triangulation-mesh-with-c-in-grasshopper/ 143 | 144 | //convert point3d to node2 145 | //grasshopper requres that nodes are saved within a Node2List for Delaunay 146 | var nodes = new Node2List(); 147 | for (int i = 0; i < pts.Count; i++) 148 | { 149 | //notice how we only read in the X and Y coordinates 150 | // this is why points should be mapped onto the XY plane 151 | nodes.Append(new Node2(pts[i].X, pts[i].Y)); 152 | } 153 | 154 | //solve Delaunay 155 | var delMesh = new Mesh(); 156 | var faces = new List(); 157 | 158 | faces = Grasshopper.Kernel.Geometry.Delaunay.Solver.Solve_Faces(nodes, DocumentTolerance()); 159 | 160 | //output 161 | delMesh = Grasshopper.Kernel.Geometry.Delaunay.Solver.Solve_Mesh(nodes, DocumentTolerance(), ref faces); 162 | for (int i = 0; i < pts.Count; i++) 163 | { 164 | delMesh.Vertices.SetVertex(i, pts[i]); 165 | } 166 | 167 | return delMesh; 168 | } 169 | 170 | /// 171 | /// Provides an Icon for the component. 172 | /// 173 | protected override System.Drawing.Bitmap Icon 174 | { 175 | get 176 | { 177 | //You can add image files to your project resources and access them like this: 178 | // return Resources.IconForThisComponent; 179 | return null; 180 | } 181 | } 182 | 183 | /// 184 | /// Gets the unique ID for this component. Do not change this ID after release. 185 | /// 186 | public override Guid ComponentGuid 187 | { 188 | get { return new Guid("0c6c5f78-9b7a-4e53-8d3c-4e8f6c1c2632"); } 189 | } 190 | } 191 | } -------------------------------------------------------------------------------- /Heron/Components/Utilities/GdalDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using Gdal = OSGeo.GDAL.Gdal; 8 | using Ogr = OSGeo.OGR.Ogr; 9 | using System.Linq; 10 | 11 | using Grasshopper; 12 | using Grasshopper.Kernel; 13 | using Rhino.Geometry; 14 | 15 | namespace Heron 16 | { 17 | public class GdalDetails : HeronComponent 18 | { 19 | /// 20 | /// Each implementation of GH_Component must provide a public 21 | /// constructor without any arguments. 22 | /// Category represents the Tab in which the component will appear, 23 | /// Subcategory the panel. If you use non-existing tab or panel names, 24 | /// new tabs/panels will automatically be created. 25 | /// 26 | public GdalDetails() 27 | : base("GDAL Details", "GD", 28 | "This component enumerates the current version of GDAL and it's available raster and vector drivers.", 29 | "Utilities") 30 | { 31 | } 32 | 33 | /// 34 | /// Registers all the input parameters for this component. 35 | /// 36 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 37 | { 38 | } 39 | 40 | /// 41 | /// Registers all the output parameters for this component. 42 | /// 43 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 44 | { 45 | pManager.AddTextParameter("D", "GDAL Details", "", GH_ParamAccess.list); 46 | } 47 | 48 | /// 49 | /// This is the method that actually does the work. 50 | /// 51 | /// The DA object can be used to retrieve data from input parameters and 52 | /// to store data in output parameters. 53 | protected override void SolveInstance(IGH_DataAccess DA) 54 | { 55 | var info = new List(); 56 | 57 | Heron.GdalConfiguration.ConfigureGdal(); 58 | Heron.GdalConfiguration.ConfigureOgr(); 59 | 60 | string gdalVersion = Gdal.VersionInfo(""); 61 | info.Add("Gdal Version: " + gdalVersion); 62 | 63 | //string heronVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 64 | info.Add("Heron Version: " + HeronVersion.AssemblyFileVer); 65 | //string executingAssemblyFileMac = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath; 66 | 67 | 68 | //string executingDirectory = Path.GetDirectoryName(executingAssemblyFileMac); 69 | string executingDirectory = HeronLocation.GetHeronFolder(); 70 | info.Add("Heron Location: " + executingDirectory); 71 | 72 | string osxPlatform = ""; 73 | var arch = RuntimeInformation.ProcessArchitecture; 74 | var isOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); 75 | if (arch == Architecture.X64 && isOSX == true) { osxPlatform = "osx-64"; } 76 | if (arch == Architecture.Arm64 && isOSX == true) { osxPlatform = "osx-Arm64"; } 77 | 78 | string gdalPath = Path.Combine(executingDirectory, "gdal"); 79 | string nativePath = Path.Combine(gdalPath, osxPlatform); 80 | 81 | //info.Add("Gdal Path: " + gdalPath); 82 | //info.Add(nativePath); 83 | 84 | string envGdalDriverPath = Environment.GetEnvironmentVariable("GDAL_DRIVER_PATH"); 85 | //info.Add("GDAL Driver Path: " + envGdalDriverPath); 86 | 87 | ///Add Gdal driver info 88 | Gdal.AllRegister(); 89 | var driverCount = Gdal.GetDriverCount(); 90 | List gdrivers = new List(); 91 | info.Add("----------"); 92 | info.Add("GDAL drivers (" + driverCount + "):"); 93 | 94 | for (int drv = 0; drv < Gdal.GetDriverCount(); drv++) 95 | { 96 | gdrivers.Add(Gdal.GetDriver(drv).ShortName + " (" + Gdal.GetDriver(drv).LongName + ")"); 97 | } 98 | gdrivers.Sort(); 99 | info.AddRange(gdrivers); 100 | 101 | ///Add Ogr driver info 102 | Ogr.RegisterAll(); 103 | var ogrDriverCount = Ogr.GetDriverCount(); 104 | List odrivers = new List(); 105 | info.Add("----------"); 106 | info.Add("OGR drivers (" + ogrDriverCount + ") :"); 107 | for (int odrv = 0; odrv < Ogr.GetDriverCount(); odrv++) 108 | { 109 | odrivers.Add(Ogr.GetDriver(odrv).GetName()); 110 | } 111 | odrivers.Sort(); 112 | info.AddRange(odrivers); 113 | 114 | ///Get Environment Variables for troublshooting 115 | var d = Environment.GetEnvironmentVariables(); 116 | List ks = Environment.GetEnvironmentVariables().Keys.OfType().ToList(); 117 | ks.Sort(); 118 | //info.Add("----------"); 119 | //info.Add("Environment Variables:"); 120 | foreach (var key in ks) 121 | { 122 | string k = key; 123 | string v = (string)d[key]; 124 | //info.Add(k + " : " + v); 125 | } 126 | 127 | 128 | DA.SetDataList(0, info); 129 | } 130 | 131 | /// 132 | /// Provides an Icon for every component that will be visible in the User Interface. 133 | /// Icons need to be 24x24 pixels. 134 | /// 135 | protected override System.Drawing.Bitmap Icon 136 | { 137 | get 138 | { 139 | // You can add image files to your project resources and access them like this: 140 | //return Resources.IconForThisComponent; 141 | return Properties.Resources.heron_favicon; 142 | } 143 | } 144 | 145 | /// 146 | /// Each component must have a unique Guid to identify it. 147 | /// It is vital this Guid doesn't change otherwise old ghx files 148 | /// that use the old ID will partially fail during loading. 149 | /// 150 | public override Guid ComponentGuid 151 | { 152 | get { return new Guid("bf25d013-6042-4b5d-a20f-8ba37c96a24c"); } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Heron/Components/Utilities/HexToColor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Text.RegularExpressions; 5 | using Grasshopper.Kernel; 6 | using Rhino.Geometry; 7 | 8 | namespace Heron 9 | { 10 | public class HexToColor : HeronComponent 11 | { 12 | /// 13 | /// Initializes a new instance of the ColorToHex class. 14 | /// 15 | public HexToColor() 16 | : base("Hex to Color", "H2C", "Convert a hexidecimal color to RGBA format.", "Utilities") 17 | { 18 | } 19 | public override Grasshopper.Kernel.GH_Exposure Exposure 20 | { 21 | get { return GH_Exposure.quarternary; } 22 | } 23 | 24 | 25 | /// 26 | /// Registers all the input parameters for this component. 27 | /// 28 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 29 | { 30 | pManager.AddTextParameter("colorHexidecmial", "colorHex", "Hexidecimal color converted from RGBA", GH_ParamAccess.item); 31 | } 32 | 33 | /// 34 | /// Registers all the output parameters for this component. 35 | /// 36 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 37 | { 38 | pManager.AddColourParameter("colorRGBA", "colorRGBA", "RGBA color to convert to hexidecimal format", GH_ParamAccess.item); 39 | 40 | } 41 | 42 | /// 43 | /// This is the method that actually does the work. 44 | /// 45 | /// The DA object is used to retrieve from inputs and store in outputs. 46 | protected override void SolveInstance(IGH_DataAccess DA) 47 | { 48 | //Color color = Color.Empty; 49 | string hex = string.Empty; 50 | DA.GetData(0, ref hex); 51 | //string hex = String.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.R, color.G, color.B, color.A); 52 | Regex reg = new Regex("^#(?:[0-9a-fA-F]{3,4}){1,2}$"); 53 | 54 | if (!reg.IsMatch(hex)) 55 | { 56 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "colorHex input string is not in a hexidecimal format."); 57 | return; 58 | } 59 | 60 | ///Parsing hex string from Stack Overflow 61 | ///https://stackoverflow.com/questions/2109756/how-do-i-get-the-color-from-a-hexadecimal-color-code-using-net?rq=1 62 | 63 | hex = hex.TrimStart('#'); 64 | 65 | Color color; 66 | if (hex.Length == 6) 67 | color = Color.FromArgb(255, // hardcoded opaque 68 | int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber), 69 | int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber), 70 | int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber)); 71 | else 72 | color = Color.FromArgb( 73 | int.Parse(hex.Substring(6, 2), System.Globalization.NumberStyles.HexNumber), 74 | int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber), 75 | int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber), 76 | int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber)); 77 | 78 | DA.SetData(0, color); 79 | } 80 | 81 | /// 82 | /// Provides an Icon for the component. 83 | /// 84 | protected override System.Drawing.Bitmap Icon 85 | { 86 | get 87 | { 88 | //You can add image files to your project resources and access them like this: 89 | // return Resources.IconForThisComponent; 90 | return Properties.Resources.raster; 91 | } 92 | } 93 | 94 | /// 95 | /// Gets the unique ID for this component. Do not change this ID after release. 96 | /// 97 | public override Guid ComponentGuid 98 | { 99 | get { return new Guid("190F4F13-49C0-41F9-88BA-B13D2317F4BD"); } 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /Heron/Components/Utilities/ImageFilterColors.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using System.Drawing; 5 | using System.Linq; 6 | 7 | using Grasshopper.Kernel; 8 | using Grasshopper.Kernel.Data; 9 | using Grasshopper.Kernel.Types; 10 | using GH_IO.Serialization; 11 | 12 | using Rhino; 13 | using Rhino.Geometry; 14 | 15 | namespace Heron 16 | { 17 | public class ImageFilterColors : GH_TaskCapableComponent 18 | { 19 | ///parallel processing based on code from https://github.com/mcneel/rhino-developer-samples/blob/6/grasshopper/cs/SampleGhTaskCapable/Components/SampleGhTaskCapableComponent.cs 20 | ///no need to worry about data trees, concurrent dictionaries or max concurrency, gh takes care of it! 21 | ///just think of what inputs you need per branch 22 | 23 | /// 24 | /// Initializes a new instance of the ImageColors class. 25 | /// 26 | public ImageFilterColors() 27 | : base("Image Filtered Colors", "ImageFC", 28 | "Get a filtered pixel count of colors contained in an image based on color list.", 29 | "Heron", "Utilities") 30 | { 31 | } 32 | 33 | /// 34 | /// Registers all the input parameters for this component. 35 | /// 36 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 37 | { 38 | pManager.AddTextParameter("Image File Location", "fileLoc", "File location(s) of the image(s).", GH_ParamAccess.item); 39 | pManager.AddColourParameter("Color Filter", "colors", "Filter the image for specific colors. If no filter colors are provided, all colors in the image will be included.", GH_ParamAccess.list); 40 | pManager[1].Optional = true; 41 | } 42 | 43 | /// 44 | /// Registers all the output parameters for this component. 45 | /// 46 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 47 | { 48 | pManager.AddIntegerParameter("Pixel Count", "PC", "Number of pixels in the image.", GH_ParamAccess.item); 49 | pManager.AddColourParameter("Top Colors", "TC", "Sorted list of colors in image.", GH_ParamAccess.list); 50 | pManager.AddPointParameter("Color Coordinates", "CC", "Coordinates of pixels in image of color.", GH_ParamAccess.tree); 51 | //pManager.AddPointParameter("Color Location", "CL", "Pixel locations grouped by color.", GH_ParamAccess.tree); 52 | } 53 | 54 | public class SolveResults 55 | { 56 | public GH_Integer PixCount { get; set; } 57 | public List TopColors { get; set; } 58 | public GH_Structure ColorLocation { get; set; } 59 | } 60 | 61 | SolveResults Compute (string fileLoc, List colors, int tskId) 62 | { 63 | var rc = new SolveResults(); 64 | bool filterColors = colors.Any(); 65 | 66 | List topCols = new List(); 67 | List colCount = new List(); 68 | GH_Structure colLocation = new GH_Structure(); 69 | 70 | 71 | try 72 | { 73 | using (Bitmap bitmap = new Bitmap(fileLoc)) 74 | { 75 | GH_Integer pixCount = new GH_Integer(); 76 | GH_Convert.ToGHInteger(bitmap.Height * bitmap.Width,0,ref pixCount); 77 | rc.PixCount = pixCount; 78 | 79 | ///https://www.grasshopper3d.com/forum/topics/unsafe?page=1&commentId=2985220%3AComment%3A808291&x=1#2985220Comment808291 80 | GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmap); 81 | 82 | Color col = Color.Transparent; 83 | for (int x = 0; x < bitmap.Width; x++) 84 | { 85 | for (int y = 0; y < bitmap.Height; y++) 86 | { 87 | ///GH_MemoryBitmap Sample is faster than GetPixel 88 | //col = bitmap.GetPixel(x, y); 89 | if (sampler.Sample(x,y,ref col)) 90 | { 91 | if (colors.Contains(col)) 92 | { 93 | GH_Path path = new GH_Path(tskId, colors.IndexOf(col)); 94 | colLocation.Append(new GH_Point(new Point3d(x,y,0)), path); 95 | } 96 | else if (!filterColors) 97 | { 98 | colors.Add(col); 99 | GH_Path path = new GH_Path(tskId, colors.IndexOf(col)); 100 | colLocation.Append(new GH_Point(new Point3d(x, y, 0)), path); 101 | } 102 | 103 | } 104 | 105 | } 106 | } 107 | 108 | sampler.Release(false); 109 | bitmap.Dispose(); 110 | } 111 | 112 | } 113 | 114 | catch 115 | { 116 | AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Could not load image from file path: "+fileLoc); 117 | } 118 | 119 | List ghColors = new List(); 120 | foreach (var c in colors) 121 | { 122 | ghColors.Add(new GH_Colour(c)); 123 | } 124 | 125 | rc.TopColors = ghColors; 126 | rc.ColorLocation = colLocation; 127 | 128 | return rc; 129 | 130 | } 131 | 132 | /// 133 | /// This is the method that actually does the work. 134 | /// 135 | /// The DA object is used to retrieve from inputs and store in outputs. 136 | protected override void SolveInstance(IGH_DataAccess DA) 137 | { 138 | if (InPreSolve) 139 | { 140 | ///First pass; collect data and construct tasks 141 | /// 142 | string fileLocList = ""; 143 | List colors = new List(); 144 | Task tsk = null; 145 | 146 | if(DA.GetData(0,ref fileLocList)) 147 | { 148 | DA.GetDataList(1, colors); 149 | tsk = Task.Run(() => Compute(fileLocList, colors, tsk.Id), CancelToken); 150 | } 151 | 152 | ///Add a null task even if data collection fails. This keeps the list size in sync with the iterations 153 | TaskList.Add(tsk); 154 | return; 155 | } 156 | 157 | if(!GetSolveResults(DA, out var results)) 158 | { 159 | ///Compute right here, right now. 160 | ///1. Collect 161 | /// 162 | string fileLocList = ""; 163 | List colors = new List(); 164 | int tskId = 0; 165 | 166 | if (!DA.GetData(0, ref fileLocList)) { return; } 167 | if(!DA.GetDataList(1, colors)) { return; } 168 | 169 | ///2. Compute 170 | /// 171 | results = Compute(fileLocList, colors, tskId); 172 | } 173 | 174 | ///3. Set 175 | /// 176 | if (results != null) 177 | { 178 | DA.SetData(0, results.PixCount); 179 | DA.SetDataList(1, results.TopColors); 180 | DA.SetDataTree(2, results.ColorLocation); 181 | //DA.SetDataTree(3, results.ColorLocation); 182 | } 183 | } 184 | 185 | /// 186 | /// Provides an Icon for the component. 187 | /// 188 | protected override System.Drawing.Bitmap Icon 189 | { 190 | get 191 | { 192 | //You can add image files to your project resources and access them like this: 193 | // return Resources.IconForThisComponent; 194 | return Properties.Resources.raster; 195 | } 196 | } 197 | 198 | /// 199 | /// Gets the unique ID for this component. Do not change this ID after release. 200 | /// 201 | public override Guid ComponentGuid 202 | { 203 | get { return new Guid("DB0FE3BC-2471-45C3-BAAC-4BC0C83CB654"); } 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /Heron/Components/Utilities/ImageFlip.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Imaging; 5 | using System.IO; 6 | using System.Windows.Forms; 7 | 8 | using Grasshopper.Kernel; 9 | using GH_IO.Serialization; 10 | using Rhino.Geometry; 11 | 12 | namespace Heron 13 | { 14 | public class ImageFlip : HeronComponent 15 | { 16 | /// 17 | /// Initializes a new instance of the FlipImage class. 18 | /// 19 | public ImageFlip() 20 | : base("Flip Image", "FlipImage", "Flip an image along its vertical, horizontal axis or both.", 21 | "Utilities") 22 | { 23 | } 24 | 25 | /// 26 | /// Registers all the input parameters for this component. 27 | /// 28 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 29 | { 30 | pManager.AddTextParameter("Original Image", "image", "File path for the image to be flipped.", GH_ParamAccess.item); 31 | pManager.AddTextParameter("Suffix", "suffix", "Suffix to add the end of the original image. If none is provided, a '_flipped' suffix will be added. " + 32 | "An existing flipped image path will be overwritten.", GH_ParamAccess.item, "_flipped"); 33 | pManager.AddBooleanParameter("Run", "run", "Flip the image. An existing flipped image path will be overwritten.", GH_ParamAccess.item, false); 34 | pManager[1].Optional = true; 35 | Message = flipStatus; 36 | 37 | } 38 | 39 | /// 40 | /// Registers all the output parameters for this component. 41 | /// 42 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 43 | { 44 | pManager.AddTextParameter("Flipped Image", "flipped", "File path for the flipped image.", GH_ParamAccess.item); 45 | } 46 | 47 | /// 48 | /// This is the method that actually does the work. 49 | /// 50 | /// The DA object is used to retrieve from inputs and store in outputs. 51 | protected override void SolveInstance(IGH_DataAccess DA) 52 | { 53 | string originalPath = string.Empty; 54 | DA.GetData(0, ref originalPath); 55 | if (!File.Exists(originalPath)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Cannot find the original image."); } 56 | string fDir = Path.GetDirectoryName(originalPath); 57 | string fName = Path.GetFileNameWithoutExtension(originalPath); 58 | string fExt = Path.GetExtension(originalPath); 59 | 60 | string suffix = string.Empty; 61 | DA.GetData(1, ref suffix); 62 | 63 | string fOut = Path.Combine(fDir, fName + suffix + fExt); 64 | if (!File.Exists(fOut)) { fOut = string.Empty; } 65 | 66 | bool run = false; 67 | DA.GetData("Run", ref run); 68 | 69 | Bitmap originalBitmap = new Bitmap(originalPath, true); 70 | ImageFormat imgFormat = originalBitmap.RawFormat; 71 | 72 | if (run) 73 | { 74 | Bitmap finalImage = new Bitmap(originalBitmap); 75 | originalBitmap.Dispose(); 76 | 77 | fOut = Path.Combine(fDir, fName + suffix + fExt); 78 | if (File.Exists(fOut)) { File.Delete(fOut); } 79 | 80 | switch (flipStatus) 81 | { 82 | case "None": 83 | break; 84 | case "Flip X": 85 | finalImage.RotateFlip(RotateFlipType.RotateNoneFlipX); 86 | break; 87 | case "Flip Y": 88 | finalImage.RotateFlip(RotateFlipType.RotateNoneFlipY); 89 | break; 90 | case "Flip X and Y": 91 | finalImage.RotateFlip(RotateFlipType.RotateNoneFlipXY); 92 | break; 93 | } 94 | 95 | finalImage.Save(fOut, imgFormat); 96 | finalImage.Dispose(); 97 | } 98 | 99 | DA.SetData(0, fOut); 100 | 101 | } 102 | 103 | 104 | //////////////////////////// 105 | //Menu Items 106 | 107 | private bool IsFlipSelected(string flipString) 108 | { 109 | return flipString.Equals(flipStatus); 110 | } 111 | protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown menu) 112 | { 113 | ToolStripMenuItem fN = new ToolStripMenuItem("No Flip"); 114 | fN.Tag = "No Flip"; 115 | fN.Checked = IsFlipSelected("No Flip"); 116 | fN.ToolTipText = "Do not flip the image"; 117 | fN.Click += FlipItemOnClick; 118 | menu.Items.Add(fN); 119 | 120 | ToolStripMenuItem fX = new ToolStripMenuItem("Flip X"); 121 | fX.Tag = "Flip X"; 122 | fX.Checked = IsFlipSelected("Flip X"); 123 | fX.ToolTipText = "Flip image along its vertical axis (left becomes right)."; 124 | fX.Click += FlipItemOnClick; 125 | menu.Items.Add(fX); 126 | 127 | ToolStripMenuItem fY = new ToolStripMenuItem("Flip Y"); 128 | fY.Tag = "Flip Y"; 129 | fY.Checked = IsFlipSelected("Flip Y"); 130 | fY.ToolTipText = "Flip image along its horizontal axis (top becomes bottom)."; 131 | fY.Click += FlipItemOnClick; 132 | menu.Items.Add(fY); 133 | 134 | ToolStripMenuItem fXY = new ToolStripMenuItem("Flip X and Y"); 135 | fXY.Tag = "Flip X and Y"; 136 | fXY.Checked = IsFlipSelected("Flip X and Y"); 137 | fXY.ToolTipText = "Flip image along both X and Y axises."; 138 | fXY.Click += FlipItemOnClick; 139 | menu.Items.Add(fXY); 140 | 141 | base.AppendAdditionalComponentMenuItems(menu); 142 | } 143 | 144 | private void FlipItemOnClick(object sender, EventArgs e) 145 | { 146 | ToolStripMenuItem item = sender as ToolStripMenuItem; 147 | if (item == null) 148 | return; 149 | 150 | string code = (string)item.Tag; 151 | if (IsFlipSelected(code)) 152 | return; 153 | 154 | RecordUndoEvent("FlipStatus"); 155 | 156 | flipStatus = code; 157 | Message = flipStatus; 158 | 159 | ExpireSolution(true); 160 | } 161 | 162 | //////////////////////////// 163 | //Sticky Parameters 164 | 165 | private string flipStatus = "Flip Y"; 166 | 167 | public string FlipStatus 168 | { 169 | get { return flipStatus; } 170 | set 171 | { 172 | flipStatus = value; 173 | Message = flipStatus; 174 | } 175 | } 176 | 177 | public override bool Write (GH_IWriter writer) 178 | { 179 | writer.SetString("FlipStatus", FlipStatus); 180 | return base.Write(writer); 181 | } 182 | 183 | public override bool Read(GH_IReader reader) 184 | { 185 | FlipStatus = reader.GetString("FlipStatus"); 186 | return base.Read(reader); 187 | } 188 | 189 | /// 190 | /// Provides an Icon for the component. 191 | /// 192 | protected override System.Drawing.Bitmap Icon 193 | { 194 | get 195 | { 196 | return Properties.Resources.raster; 197 | } 198 | } 199 | 200 | /// 201 | /// Gets the unique ID for this component. Do not change this ID after release. 202 | /// 203 | public override Guid ComponentGuid 204 | { 205 | get { return new Guid("f1e9c8ad-2500-48de-9692-54e7d6f6379d"); } 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /Heron/Components/Utilities/ImageRotate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Imaging; 5 | using System.IO; 6 | using System.Windows.Forms; 7 | 8 | using Grasshopper.Kernel; 9 | using GH_IO.Serialization; 10 | using Rhino.Geometry; 11 | 12 | namespace Heron 13 | { 14 | public class ImageRotate : HeronComponent 15 | { 16 | /// 17 | /// Initializes a new instance of the FlipImage class. 18 | /// 19 | public ImageRotate() 20 | : base("Rotate Image", "RotateImage", "Roate an image 90, 180 or 270 degrees.", 21 | "Utilities") 22 | { 23 | } 24 | 25 | /// 26 | /// Registers all the input parameters for this component. 27 | /// 28 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 29 | { 30 | pManager.AddTextParameter("Original Image", "image", "File path for the image to be rotated.", GH_ParamAccess.item); 31 | pManager.AddTextParameter("Suffix", "suffix", "Suffix to add the end of the original image. If none is provided, a '_rotated' suffix will be added. " + 32 | "An existing flipped image path will be overwritten.", GH_ParamAccess.item, "_rotated"); 33 | pManager.AddBooleanParameter("Run", "run", "Rotate the image. An existing rotated image path will be overwritten.", GH_ParamAccess.item, false); 34 | pManager[1].Optional = true; 35 | Message = rotateStatus; 36 | 37 | } 38 | 39 | /// 40 | /// Registers all the output parameters for this component. 41 | /// 42 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 43 | { 44 | pManager.AddTextParameter("Rotated Image", "rotated", "File path for the rotated image.", GH_ParamAccess.item); 45 | } 46 | 47 | /// 48 | /// This is the method that actually does the work. 49 | /// 50 | /// The DA object is used to retrieve from inputs and store in outputs. 51 | protected override void SolveInstance(IGH_DataAccess DA) 52 | { 53 | string originalPath = string.Empty; 54 | DA.GetData(0, ref originalPath); 55 | if (!File.Exists(originalPath)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Cannot find the original image."); } 56 | string fDir = Path.GetDirectoryName(originalPath); 57 | string fName = Path.GetFileNameWithoutExtension(originalPath); 58 | string fExt = Path.GetExtension(originalPath); 59 | 60 | string suffix = string.Empty; 61 | DA.GetData(1, ref suffix); 62 | 63 | string fOut = Path.Combine(fDir, fName + suffix + fExt); 64 | if (!File.Exists(fOut)) { fOut = string.Empty; } 65 | 66 | bool run = false; 67 | DA.GetData("Run", ref run); 68 | 69 | Bitmap originalBitmap = new Bitmap(originalPath, true); 70 | ImageFormat imgFormat = originalBitmap.RawFormat; 71 | 72 | if (run) 73 | { 74 | Bitmap finalImage = new Bitmap(originalBitmap); 75 | originalBitmap.Dispose(); 76 | 77 | fOut = Path.Combine(fDir, fName + suffix + fExt); 78 | if (File.Exists(fOut)) { File.Delete(fOut); } 79 | 80 | switch (rotateStatus) 81 | { 82 | case "None": 83 | break; 84 | case "Rotate 90": 85 | finalImage.RotateFlip(RotateFlipType.Rotate90FlipNone); 86 | break; 87 | case "Rotate 180": 88 | finalImage.RotateFlip(RotateFlipType.Rotate180FlipNone); 89 | break; 90 | case "Rotate 270": 91 | finalImage.RotateFlip(RotateFlipType.Rotate270FlipNone); 92 | break; 93 | } 94 | 95 | finalImage.Save(fOut, imgFormat); 96 | finalImage.Dispose(); 97 | } 98 | 99 | DA.SetData(0, fOut); 100 | 101 | } 102 | 103 | 104 | //////////////////////////// 105 | //Menu Items 106 | 107 | private bool IsFlipSelected(string rotateString) 108 | { 109 | return rotateString.Equals(rotateStatus); 110 | } 111 | protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown menu) 112 | { 113 | ToolStripMenuItem sN = new ToolStripMenuItem("No Rotation"); 114 | sN.Tag = "No Rotation"; 115 | sN.Checked = IsFlipSelected("No Rotation"); 116 | sN.ToolTipText = "Do not rotate the image"; 117 | sN.Click += FlipItemOnClick; 118 | menu.Items.Add(sN); 119 | 120 | ToolStripMenuItem s90 = new ToolStripMenuItem("Rotate 90"); 121 | s90.Tag = "Rotate 90"; 122 | s90.Checked = IsFlipSelected("Rotate 90"); 123 | s90.ToolTipText = "Rotate image 90 deg clockwise."; 124 | s90.Click += FlipItemOnClick; 125 | menu.Items.Add(s90); 126 | 127 | ToolStripMenuItem s180 = new ToolStripMenuItem("Rotate 180"); 128 | s180.Tag = "Rotate 180"; 129 | s180.Checked = IsFlipSelected("Rotate 180"); 130 | s180.ToolTipText = "Rotate image 180 deg clockwise."; 131 | s180.Click += FlipItemOnClick; 132 | menu.Items.Add(s180); 133 | 134 | ToolStripMenuItem s270 = new ToolStripMenuItem("Rotate 270"); 135 | s270.Tag = "Rotate 270"; 136 | s270.Checked = IsFlipSelected("Rotate 270"); 137 | s270.ToolTipText = "Rotate image 270 deg clockwise."; 138 | s270.Click += FlipItemOnClick; 139 | menu.Items.Add(s270); 140 | 141 | base.AppendAdditionalComponentMenuItems(menu); 142 | } 143 | 144 | private void FlipItemOnClick(object sender, EventArgs e) 145 | { 146 | ToolStripMenuItem item = sender as ToolStripMenuItem; 147 | if (item == null) 148 | return; 149 | 150 | string code = (string)item.Tag; 151 | if (IsFlipSelected(code)) 152 | return; 153 | 154 | RecordUndoEvent("rotateStatus"); 155 | 156 | rotateStatus = code; 157 | Message = rotateStatus; 158 | 159 | ExpireSolution(true); 160 | } 161 | 162 | //////////////////////////// 163 | //Sticky Parameters 164 | 165 | private string rotateStatus = "Rotate 270"; 166 | 167 | public string RotateStatus 168 | { 169 | get { return rotateStatus; } 170 | set 171 | { 172 | rotateStatus = value; 173 | Message = rotateStatus; 174 | } 175 | } 176 | 177 | public override bool Write (GH_IWriter writer) 178 | { 179 | writer.SetString("rotateStatus", rotateStatus); 180 | return base.Write(writer); 181 | } 182 | 183 | public override bool Read(GH_IReader reader) 184 | { 185 | rotateStatus = reader.GetString("rotateStatus"); 186 | return base.Read(reader); 187 | } 188 | 189 | /// 190 | /// Provides an Icon for the component. 191 | /// 192 | protected override System.Drawing.Bitmap Icon 193 | { 194 | get 195 | { 196 | return Properties.Resources.raster; 197 | } 198 | } 199 | 200 | /// 201 | /// Gets the unique ID for this component. Do not change this ID after release. 202 | /// 203 | public override Guid ComponentGuid 204 | { 205 | get { return new Guid("AA4281C3-74E4-46A8-A37D-F095F9EC1570"); } 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /Heron/Components/Utilities/TopiaryFlatten.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using Grasshopper.Kernel.Data; 3 | using Grasshopper.Kernel.Types; 4 | using Rhino.Geometry; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace Heron 10 | { 11 | public class TopiaryFlatten : HeronComponent 12 | { 13 | 14 | public TopiaryFlatten() 15 | : base("Topiary Flatten", "TF", "Flatten branches by a set depth from the deepest path in a data tree. " + 16 | "The resulting tree will look more like a topiary. This can be useful for data trees with uneven path depths.", "Utilities") 17 | { 18 | } 19 | 20 | /// 21 | /// Registers all the input parameters for this component. 22 | /// 23 | protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) 24 | { 25 | pManager.AddGenericParameter("Data Tree", "DT", "Data tree to flatten to a topiary.", GH_ParamAccess.tree); 26 | pManager.AddIntegerParameter("Number of Branches", "N", "The number of branches to merge from the deepest path branch count. " + 27 | "For instance, if N=2 and the path with the most branches is 4, any path in the tree with a depth greater than 2 will be flattened up into 2.", GH_ParamAccess.item); 28 | } 29 | 30 | /// 31 | /// Registers all the output parameters for this component. 32 | /// 33 | protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) 34 | { 35 | pManager.AddGenericParameter("Pruned Tree", "PT", "Pruned tree.", GH_ParamAccess.tree); 36 | } 37 | 38 | /// 39 | /// This is the method that actually does the work. 40 | /// 41 | /// The DA object is used to retrieve from inputs and store in outputs. 42 | protected override void SolveInstance(IGH_DataAccess DA) 43 | { 44 | GH_Structure treeIn = new GH_Structure(); 45 | DA.GetDataTree(0, out treeIn); 46 | 47 | int pruneDepth = 0; 48 | DA.GetData(1, ref pruneDepth); 49 | 50 | GH_Structure treeOut = new GH_Structure(); 51 | 52 | ///Create list of path strings 53 | var pathStrings = treeIn.Paths.Select(x => x.ToString()); 54 | ///Find the deepest path in the tree 55 | var maxDepthPath = pathStrings.Aggregate((max, cur) => max.Split(';').Length > cur.Split(';').Length ? max : cur); 56 | ///Get number of branches for deepest path 57 | var maxDepthInt = maxDepthPath.Split(';').Length; 58 | 59 | foreach (var path in treeIn.Paths) 60 | { 61 | ///Determine number of branches to prune if any 62 | GH_Path.SplitPathLikeString(path.ToString(), out string[] path_segments, out string index_segment); 63 | var numBranchesToRemove = path_segments.Length - (maxDepthInt - pruneDepth); 64 | 65 | var newPath = path; 66 | 67 | if (numBranchesToRemove > 0 && maxDepthInt - pruneDepth > 0) 68 | { 69 | ///Remove pruned branches from path string 70 | path_segments = path_segments.Take(path_segments.Count() - numBranchesToRemove).ToArray(); 71 | int[] path_args = path_segments.Select(int.Parse).ToArray(); 72 | 73 | newPath = new GH_Path(path_args); 74 | } 75 | 76 | treeOut.AppendRange(treeIn[path],newPath); 77 | } 78 | 79 | DA.SetDataTree(0, treeOut); 80 | } 81 | 82 | 83 | /// 84 | /// Provides an Icon for the component. 85 | /// 86 | protected override System.Drawing.Bitmap Icon 87 | { 88 | get 89 | { 90 | return Properties.Resources.shp; 91 | } 92 | } 93 | 94 | /// 95 | /// Gets the unique ID for this component. Do not change this ID after release. 96 | /// 97 | public override Guid ComponentGuid 98 | { 99 | get { return new Guid("a3499421-1bcb-4877-9c68-4afca606c3f7"); } 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /Heron/HeronBoxPreviewComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Grasshopper.Kernel; 8 | using Rhino.Display; 9 | using Rhino.DocObjects; 10 | using Rhino.Geometry; 11 | using Rhino.Render; 12 | 13 | namespace Heron 14 | { 15 | internal struct HeronBoxPreviewItem 16 | { 17 | public BoundingBox bbox; 18 | public PointCloud pointCloud; 19 | public double radius; 20 | } 21 | 22 | public abstract class HeronBoxPreviewComponent : HeronComponent 23 | { 24 | private List _previewItems; 25 | private BoundingBox _box; 26 | 27 | public HeronBoxPreviewComponent(string name, string nickName, string description, string subCategory) : base(name, nickName, description, subCategory) 28 | { 29 | _previewItems = new List(); 30 | } 31 | 32 | protected override void BeforeSolveInstance() 33 | { 34 | _previewItems.Clear(); 35 | } 36 | 37 | public override bool IsPreviewCapable => true; 38 | 39 | 40 | internal void AddPreviewItem(BoundingBox bbox) 41 | { 42 | _previewItems.Add(new HeronBoxPreviewItem() 43 | { 44 | bbox = bbox 45 | }); 46 | } 47 | 48 | internal void AddPreviewItem(PointCloud pointCloud, double radius) 49 | { 50 | _previewItems.Add(new HeronBoxPreviewItem() 51 | { 52 | pointCloud = pointCloud, 53 | radius = radius, 54 | }); 55 | } 56 | 57 | public override void DrawViewportWires(IGH_PreviewArgs args) 58 | { 59 | foreach (var item in _previewItems) 60 | { 61 | if (item.bbox.IsValid) args.Display.DrawBox(item.bbox, Color.Red); //args.Display.DrawLines(item.bbox.GetEdges(), Color.Red); 62 | if (item.pointCloud != null) args.Display.DrawPointCloud(item.pointCloud, (float) item.radius); 63 | } 64 | 65 | base.DrawViewportWires(args); 66 | } 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Heron/HeronComponent.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | 9 | namespace Heron 10 | { 11 | public abstract class HeronComponent : GH_Component 12 | { 13 | public HeronComponent(string name, string nickName, string description, string subCategory) : base(name, nickName, description, "Heron", subCategory) 14 | { 15 | 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Heron/HeronInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Grasshopper; 8 | using Grasshopper.Kernel; 9 | 10 | namespace Heron 11 | { 12 | public class HeronInfo : GH_AssemblyInfo 13 | { 14 | public override string Name 15 | { 16 | get 17 | { 18 | return "Heron"; 19 | } 20 | } 21 | public override string AuthorName 22 | { 23 | get 24 | { 25 | return "Brian Washburn"; 26 | } 27 | } 28 | 29 | public override string Version 30 | { 31 | get 32 | { 33 | return HeronVersion.AssemblyFileVer; 34 | } 35 | } 36 | 37 | public override string AuthorContact 38 | { 39 | get 40 | { 41 | return "blueheronGIS@gmail.com"; 42 | } 43 | } 44 | 45 | public override Guid Id 46 | { 47 | get 48 | { 49 | return new System.Guid("{94830583-1656-43FB-8415-6FD290548DD1}"); 50 | } 51 | } 52 | 53 | public override Bitmap Icon 54 | { 55 | get 56 | { 57 | return Properties.Resources.heron_favicon; 58 | } 59 | } 60 | } 61 | 62 | /// 63 | /// https://discourse.mcneel.com/t/add-a-custom-icon-image-to-grasshopper-plugin-tabs/61777/14 64 | /// 65 | public class HeronCategoryIcon : Grasshopper.Kernel.GH_AssemblyPriority 66 | { 67 | public override Grasshopper.Kernel.GH_LoadingInstruction PriorityLoad() 68 | { 69 | Grasshopper.Instances.ComponentServer.AddCategoryIcon("Heron", Properties.Resources.heron_favicon); 70 | Grasshopper.Instances.ComponentServer.AddCategorySymbolName("Heron", 'H'); 71 | return Grasshopper.Kernel.GH_LoadingInstruction.Proceed; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Heron/HeronRasterPreviewComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Grasshopper.Kernel; 7 | using Rhino.Display; 8 | using Rhino.DocObjects; 9 | using Rhino.Geometry; 10 | using Rhino.Render; 11 | 12 | namespace Heron 13 | { 14 | internal struct HeronRasterPreviewItem 15 | { 16 | public DisplayMaterial mat; 17 | public Mesh mesh; 18 | } 19 | 20 | public abstract class HeronRasterPreviewComponent : HeronComponent 21 | { 22 | private List _previewItems; 23 | private BoundingBox _boundingBox; 24 | public HeronRasterPreviewComponent(string name, string nickName, string description, string subCategory) : base(name, nickName, description, subCategory) 25 | { 26 | _previewItems = new List(); 27 | } 28 | 29 | protected override void BeforeSolveInstance() 30 | { 31 | _previewItems.Clear(); 32 | _boundingBox = BoundingBox.Empty; 33 | } 34 | 35 | internal static Rectangle3d BBoxToRect(BoundingBox imageBox) 36 | { 37 | var xInterval = new Interval(imageBox.Min.X, imageBox.Max.X); 38 | var yInterval = new Interval(imageBox.Min.Y, imageBox.Max.Y); 39 | var rect = new Rectangle3d(Plane.WorldXY, xInterval, yInterval); 40 | return rect; 41 | } 42 | 43 | public override bool IsPreviewCapable => true; 44 | 45 | internal void AddPreviewItem(string bitmap, Rectangle3d rect) 46 | { 47 | AddPreviewItem(bitmap, rect.ToNurbsCurve(), rect); 48 | } 49 | 50 | internal void AddPreviewItem(string bitmap, Curve c, Rectangle3d rect) 51 | { 52 | var mesh = Mesh.CreateFromPlanarBoundary(c, MeshingParameters.FastRenderMesh, 0.1); 53 | TextureMapping tm = TextureMapping.CreatePlaneMapping(rect.Plane, rect.X, rect.Y, new Interval(-1, 1)); 54 | mesh.SetTextureCoordinates(tm, Transform.Identity, true); 55 | var mat = new DisplayMaterial(System.Drawing.Color.White); 56 | 57 | ///Force bitmap to redraw 58 | //string docBitmapName = string.Empty; 59 | //var docBitmap = Rhino.RhinoDoc.ActiveDoc.Bitmaps.Find(bitmap, true, out docBitmapName); 60 | //mat.SetBitmapTexture(docBitmapName, true); 61 | 62 | mat.SetBitmapTexture(bitmap, true); 63 | 64 | _previewItems.Add(new HeronRasterPreviewItem() 65 | { 66 | mesh = mesh, 67 | mat = mat 68 | }); 69 | 70 | ///Use Wait to refresh images 71 | ///https://discourse.mcneel.com/t/wish-list-set-bitmap-texture-from-memory-stream/105158/5 72 | ///https://mcneel.myjetbrains.com/youtrack/issue/RH-59416 73 | Rhino.RhinoApp.Wait(); 74 | } 75 | 76 | public override void DrawViewportMeshes(IGH_PreviewArgs args) 77 | { 78 | foreach (var item in _previewItems) 79 | { 80 | args.Display.DrawMeshShaded(item.mesh, item.mat); 81 | } 82 | base.DrawViewportMeshes(args); 83 | } 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Heron/HeronSRS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Heron 8 | { 9 | /// 10 | /// https://discourse.mcneel.com/t/defining-plugin-wide-variables-for-grasshopper-plugin/67582/2 11 | /// 12 | public sealed class HeronSRS 13 | { 14 | private static HeronSRS _instance; 15 | private HeronSRS() { } // private constructor, should only access through Instance. Any necessary initialization here, too. 16 | public static HeronSRS Instance 17 | { 18 | get 19 | { 20 | if (_instance == null) 21 | _instance = new HeronSRS(); 22 | 23 | return _instance; 24 | } 25 | } 26 | 27 | public string SRS { get; set; } = "WGS84"; // initialize to min value of int. Can use any valid value here. Or init in the private constructor. 28 | } 29 | } -------------------------------------------------------------------------------- /Heron/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Heron")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("Heron")] 14 | [assembly: AssemblyCopyright("Copyright © 2025")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | //[assembly: GH_Loading(GH_LoadingDemand.ForceDirect)] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // The following GUID is for the ID of the typelib if this project is exposed to COM 26 | [assembly: Guid("ac46f274-cd33-445b-9347-1dd45a437f88")] 27 | 28 | // Version information for an assembly consists of the following four values: 29 | // 30 | // Major Version 31 | // Minor Version 32 | // Build Number 33 | // Revision 34 | // 35 | // You can specify all the values or you can default the Build and Revision Numbers 36 | // by using the '*' as shown below: 37 | // [assembly: AssemblyVersion("1.0.*")] 38 | [assembly: AssemblyVersion(Heron.HeronVersion.AssemblyVer)] 39 | [assembly: AssemblyFileVersion(Heron.HeronVersion.AssemblyFileVer)] 40 | -------------------------------------------------------------------------------- /Heron/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Heron.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Heron.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap ddtoxy { 67 | get { 68 | object obj = ResourceManager.GetObject("ddtoxy", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap Demo { 77 | get { 78 | object obj = ResourceManager.GetObject("Demo", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Drawing.Bitmap. 85 | /// 86 | internal static System.Drawing.Bitmap eap { 87 | get { 88 | object obj = ResourceManager.GetObject("eap", resourceCulture); 89 | return ((System.Drawing.Bitmap)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap geocode { 97 | get { 98 | object obj = ResourceManager.GetObject("geocode", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized resource of type System.Drawing.Bitmap. 105 | /// 106 | internal static System.Drawing.Bitmap heron_favicon { 107 | get { 108 | object obj = ResourceManager.GetObject("heron_favicon", resourceCulture); 109 | return ((System.Drawing.Bitmap)(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// Looks up a localized resource of type System.Drawing.Bitmap. 115 | /// 116 | internal static System.Drawing.Bitmap heron_icon { 117 | get { 118 | object obj = ResourceManager.GetObject("heron_icon", resourceCulture); 119 | return ((System.Drawing.Bitmap)(obj)); 120 | } 121 | } 122 | 123 | /// 124 | /// Looks up a localized resource of type System.Byte[]. 125 | /// 126 | internal static byte[] HeronServiceEndpoints { 127 | get { 128 | object obj = ResourceManager.GetObject("HeronServiceEndpoints", resourceCulture); 129 | return ((byte[])(obj)); 130 | } 131 | } 132 | 133 | /// 134 | /// Looks up a localized resource of type System.Drawing.Bitmap. 135 | /// 136 | internal static System.Drawing.Bitmap img { 137 | get { 138 | object obj = ResourceManager.GetObject("img", resourceCulture); 139 | return ((System.Drawing.Bitmap)(obj)); 140 | } 141 | } 142 | 143 | /// 144 | /// Looks up a localized resource of type System.Drawing.Bitmap. 145 | /// 146 | internal static System.Drawing.Bitmap layer { 147 | get { 148 | object obj = ResourceManager.GetObject("layer", resourceCulture); 149 | return ((System.Drawing.Bitmap)(obj)); 150 | } 151 | } 152 | 153 | /// 154 | /// Looks up a localized resource of type System.Drawing.Bitmap. 155 | /// 156 | internal static System.Drawing.Bitmap raster { 157 | get { 158 | object obj = ResourceManager.GetObject("raster", resourceCulture); 159 | return ((System.Drawing.Bitmap)(obj)); 160 | } 161 | } 162 | 163 | /// 164 | /// Looks up a localized resource of type System.Drawing.Bitmap. 165 | /// 166 | internal static System.Drawing.Bitmap revgeocode { 167 | get { 168 | object obj = ResourceManager.GetObject("revgeocode", resourceCulture); 169 | return ((System.Drawing.Bitmap)(obj)); 170 | } 171 | } 172 | 173 | /// 174 | /// Looks up a localized resource of type System.Drawing.Bitmap. 175 | /// 176 | internal static System.Drawing.Bitmap shp { 177 | get { 178 | object obj = ResourceManager.GetObject("shp", resourceCulture); 179 | return ((System.Drawing.Bitmap)(obj)); 180 | } 181 | } 182 | 183 | /// 184 | /// Looks up a localized resource of type System.Drawing.Bitmap. 185 | /// 186 | internal static System.Drawing.Bitmap vector { 187 | get { 188 | object obj = ResourceManager.GetObject("vector", resourceCulture); 189 | return ((System.Drawing.Bitmap)(obj)); 190 | } 191 | } 192 | 193 | /// 194 | /// Looks up a localized resource of type System.Drawing.Bitmap. 195 | /// 196 | internal static System.Drawing.Bitmap xytodd { 197 | get { 198 | object obj = ResourceManager.GetObject("xytodd", resourceCulture); 199 | return ((System.Drawing.Bitmap)(obj)); 200 | } 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /Heron/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\ddtoxy.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\Resources\Demo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\Resources\eap.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 129 | 130 | 131 | ..\Resources\geocode.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 132 | 133 | 134 | ..\Resources\img.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 135 | 136 | 137 | ..\Resources\layer.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 138 | 139 | 140 | ..\Resources\raster.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 141 | 142 | 143 | ..\Resources\shp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 144 | 145 | 146 | ..\Resources\vector.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 147 | 148 | 149 | ..\Resources\revgeocode.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 150 | 151 | 152 | ..\Resources\xytodd.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 153 | 154 | 155 | ..\Resources\heron-favicon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 156 | 157 | 158 | ..\Resources\heron-icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 159 | 160 | 161 | ..\Resources\HeronServiceEndpoints.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 162 | 163 | -------------------------------------------------------------------------------- /Heron/Resources/Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/Demo.png -------------------------------------------------------------------------------- /Heron/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/Icon.png -------------------------------------------------------------------------------- /Heron/Resources/ddtoxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/ddtoxy.png -------------------------------------------------------------------------------- /Heron/Resources/eap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/eap.png -------------------------------------------------------------------------------- /Heron/Resources/geocode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/geocode.png -------------------------------------------------------------------------------- /Heron/Resources/heron-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/heron-favicon.png -------------------------------------------------------------------------------- /Heron/Resources/heron-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/heron-icon.png -------------------------------------------------------------------------------- /Heron/Resources/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/img.png -------------------------------------------------------------------------------- /Heron/Resources/layer-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/layer-01.png -------------------------------------------------------------------------------- /Heron/Resources/layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/layer.png -------------------------------------------------------------------------------- /Heron/Resources/raster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/raster.png -------------------------------------------------------------------------------- /Heron/Resources/revgeocode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/revgeocode.png -------------------------------------------------------------------------------- /Heron/Resources/shp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/shp.png -------------------------------------------------------------------------------- /Heron/Resources/vector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/vector.png -------------------------------------------------------------------------------- /Heron/Resources/xytodd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blueherongis/Heron/a267da8aa014bcd6bfa3658cf2a1f67ec258905d/Heron/Resources/xytodd.png -------------------------------------------------------------------------------- /Heron/SpeckleAsync/GH_AsyncComponent.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using Timer = System.Timers.Timer; 10 | 11 | namespace GrasshopperAsyncComponent 12 | { 13 | /// 14 | /// Inherit your component from this class to make all the async goodness available. 15 | /// 16 | public abstract class GH_AsyncComponent : GH_Component 17 | { 18 | public override Guid ComponentGuid => throw new Exception("ComponentGuid should be overriden in any descendant of GH_AsyncComponent!"); 19 | 20 | //List<(string, GH_RuntimeMessageLevel)> Errors; 21 | 22 | Action ReportProgress; 23 | 24 | public ConcurrentDictionary ProgressReports; 25 | 26 | Action Done; 27 | 28 | Timer DisplayProgressTimer; 29 | 30 | int State = 0; 31 | 32 | int SetData = 0; 33 | 34 | public List Workers; 35 | 36 | List Tasks; 37 | 38 | public readonly List CancellationSources; 39 | 40 | /// 41 | /// Set this property inside the constructor of your derived component. 42 | /// 43 | public WorkerInstance BaseWorker { get; set; } 44 | 45 | /// 46 | /// Optional: if you have opinions on how the default system task scheduler should treat your workers, set it here. 47 | /// 48 | public TaskCreationOptions? TaskCreationOptions { get; set; } = null; 49 | 50 | protected GH_AsyncComponent(string name, string nickname, string description, string category, string subCategory) : base(name, nickname, description, category, subCategory) 51 | { 52 | 53 | DisplayProgressTimer = new Timer(333) { AutoReset = false }; 54 | DisplayProgressTimer.Elapsed += DisplayProgress; 55 | 56 | ReportProgress = (id, value) => 57 | { 58 | ProgressReports[id] = value; 59 | if (!DisplayProgressTimer.Enabled) 60 | { 61 | DisplayProgressTimer.Start(); 62 | } 63 | }; 64 | 65 | Done = () => 66 | { 67 | Interlocked.Increment(ref State); 68 | if (State == Workers.Count && SetData == 0) 69 | { 70 | Interlocked.Exchange(ref SetData, 1); 71 | 72 | // We need to reverse the workers list to set the outputs in the same order as the inputs. 73 | Workers.Reverse(); 74 | 75 | Rhino.RhinoApp.InvokeOnUiThread((Action)delegate 76 | { 77 | ExpireSolution(true); 78 | }); 79 | } 80 | }; 81 | 82 | ProgressReports = new ConcurrentDictionary(); 83 | 84 | Workers = new List(); 85 | CancellationSources = new List(); 86 | Tasks = new List(); 87 | } 88 | 89 | public virtual void DisplayProgress(object sender, System.Timers.ElapsedEventArgs e) 90 | { 91 | if (Workers.Count == 0 || ProgressReports.Values.Count == 0) 92 | { 93 | return; 94 | } 95 | 96 | if (Workers.Count == 1) 97 | { 98 | Message = ProgressReports.Values.Last().ToString("0.00%"); 99 | } 100 | else 101 | { 102 | double total = 0; 103 | foreach (var kvp in ProgressReports) 104 | { 105 | total += kvp.Value; 106 | } 107 | 108 | Message = (total / Workers.Count).ToString("0.00%"); 109 | } 110 | 111 | Rhino.RhinoApp.InvokeOnUiThread((Action)delegate 112 | { 113 | OnDisplayExpired(true); 114 | }); 115 | } 116 | 117 | protected override void BeforeSolveInstance() 118 | { 119 | if (State != 0 && SetData == 1) 120 | { 121 | return; 122 | } 123 | 124 | Debug.WriteLine("Killing"); 125 | 126 | foreach (var source in CancellationSources) 127 | { 128 | source.Cancel(); 129 | } 130 | 131 | CancellationSources.Clear(); 132 | Workers.Clear(); 133 | ProgressReports.Clear(); 134 | Tasks.Clear(); 135 | 136 | Interlocked.Exchange(ref State, 0); 137 | } 138 | 139 | protected override void AfterSolveInstance() 140 | { 141 | System.Diagnostics.Debug.WriteLine("After solve instance was called " + State + " ? " + Workers.Count); 142 | // We need to start all the tasks as close as possible to each other. 143 | if (State == 0 && Tasks.Count > 0 && SetData == 0) 144 | { 145 | System.Diagnostics.Debug.WriteLine("After solve INVOKATIONM"); 146 | foreach (var task in Tasks) 147 | { 148 | task.Start(); 149 | } 150 | } 151 | } 152 | 153 | protected override void ExpireDownStreamObjects() 154 | { 155 | // Prevents the flash of null data until the new solution is ready 156 | if (SetData == 1) 157 | { 158 | base.ExpireDownStreamObjects(); 159 | } 160 | } 161 | 162 | protected override void SolveInstance(IGH_DataAccess DA) 163 | { 164 | //return; 165 | if (State == 0) 166 | { 167 | if (BaseWorker == null) 168 | { 169 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Worker class not provided."); 170 | return; 171 | } 172 | 173 | var currentWorker = BaseWorker.Duplicate(); 174 | if (currentWorker == null) 175 | { 176 | AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Could not get a worker instance."); 177 | return; 178 | } 179 | 180 | // Let the worker collect data. 181 | currentWorker.GetData(DA, Params); 182 | 183 | // Create the task 184 | var tokenSource = new CancellationTokenSource(); 185 | currentWorker.CancellationToken = tokenSource.Token; 186 | currentWorker.Id = $"Worker-{DA.Iteration}"; 187 | 188 | var currentRun = TaskCreationOptions != null 189 | ? new Task(() => currentWorker.DoWork(ReportProgress, Done), tokenSource.Token, (TaskCreationOptions)TaskCreationOptions) 190 | : new Task(() => currentWorker.DoWork(ReportProgress, Done), tokenSource.Token); 191 | 192 | // Add cancellation source to our bag 193 | CancellationSources.Add(tokenSource); 194 | 195 | // Add the worker to our list 196 | Workers.Add(currentWorker); 197 | 198 | Tasks.Add(currentRun); 199 | 200 | return; 201 | } 202 | 203 | if (SetData == 0) 204 | { 205 | return; 206 | } 207 | 208 | if (Workers.Count > 0) 209 | { 210 | Interlocked.Decrement(ref State); 211 | Workers[State].SetData(DA); 212 | } 213 | 214 | if (State != 0) 215 | { 216 | return; 217 | } 218 | 219 | CancellationSources.Clear(); 220 | Workers.Clear(); 221 | ProgressReports.Clear(); 222 | Tasks.Clear(); 223 | 224 | Interlocked.Exchange(ref SetData, 0); 225 | 226 | Message = "Done"; 227 | OnDisplayExpired(true); 228 | } 229 | 230 | public void RequestCancellation() 231 | { 232 | foreach (var source in CancellationSources) 233 | { 234 | source.Cancel(); 235 | } 236 | 237 | CancellationSources.Clear(); 238 | Workers.Clear(); 239 | ProgressReports.Clear(); 240 | Tasks.Clear(); 241 | 242 | Interlocked.Exchange(ref State, 0); 243 | Interlocked.Exchange(ref SetData, 0); 244 | Message = "Cancelled"; 245 | OnDisplayExpired(true); 246 | } 247 | 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /Heron/SpeckleAsync/WorkerInstance.cs: -------------------------------------------------------------------------------- 1 | using Grasshopper.Kernel; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrasshopperAsyncComponent 10 | { 11 | 12 | /// 13 | /// A class that holds the actual compute logic and encapsulates the state it needs. Every needs to have one. 14 | /// 15 | public abstract class WorkerInstance 16 | { 17 | 18 | /// 19 | /// The parent component. Useful for passing state back to the host component. 20 | /// 21 | public GH_Component Parent { get; set; } 22 | 23 | /// 24 | /// This token is set by the parent . 25 | /// 26 | public CancellationToken CancellationToken { get; set; } 27 | 28 | /// 29 | /// This is set by the parent . You can set it yourself, but it's not really worth it. 30 | /// 31 | public string Id { get; set; } 32 | 33 | protected WorkerInstance(GH_Component _parent) 34 | { 35 | Parent = _parent; 36 | } 37 | 38 | /// 39 | /// This is a "factory" method. It should return a fresh instance of this class, but with all the necessary state that you might have passed on directly from your component. 40 | /// 41 | /// 42 | public abstract WorkerInstance Duplicate(); 43 | 44 | /// 45 | /// This method is where the actual calculation/computation/heavy lifting should be done. 46 | /// Make sure you always check as frequently as you can if is cancelled. For an example, see the . 47 | /// 48 | /// Call this to report progress up to the parent component. 49 | /// Call this when everything is done. It will tell the parent component that you're ready to . 50 | public abstract void DoWork(Action ReportProgress, Action Done); 51 | 52 | /// 53 | /// Write your data setting logic here. Do not call this function directly from this class. It will be invoked by the parent after you've called `Done` in the function. 54 | /// 55 | /// 56 | public abstract void SetData(IGH_DataAccess DA); 57 | 58 | /// 59 | /// Write your data collection logic here. Do not call this method directly. It will be invoked by the parent . 60 | /// 61 | /// 62 | /// 63 | public abstract void GetData(IGH_DataAccess DA, GH_ComponentParamServer Params); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Heron/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Heron/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Heron.HeronConfiguration": { 3 | "HeronOpenTopographyAPI": "<>" 4 | } 5 | } -------------------------------------------------------------------------------- /Heron/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Brian Washburn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages.dgml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Heron 2 | Heron is a Grasshopper add-on which enables the import and export of GIS data into the Rhino 3d/Grasshopper environment, located, scaled and cropped based on Rhino's EarthAnchorPoint and a clipping polygon. Heron is built on GDAL libraries and can import many GIS vector, raster and topographic file types, export vector GIS data and consume GIS REST services over the web. 3 | 4 | The add-on includes components in five categories. 5 | 6 | ![toolbar-v0_3_9](https://user-images.githubusercontent.com/13613796/147161114-da93d1f6-5e9b-4884-b33e-4ace94beb404.PNG) 7 | # 8 | ### GIS Import | Export 9 | Components for importing and exporting GIS data. 10 | - **Import Vector**: Import vector GIS data clipped to a boundary, including SHP, GeoJSON, OSM, KML, MVT, GDB folders and HTTP sources. 11 | - **Import Topo**: Create a topographic mesh from a raster file (IMG, HGT, ASCII, DEM, TIF, etc) clipped to a boundary. 12 | - **Import Raster**: Import georeferenced raster data. 13 | - **Import OSM**: Import vector OpenStreetMap data clipped to a boundary. Nodes, Ways and Relations are organized onto their own branches in the output. Building massing will also be included if it exists in the OSM data. 14 | - **Import LAZ**: Import LAS & LAZ files. Built on laszip.net. 15 | - **Export Vector**: Export Grasshopper geometry to Shapefile, GeoJSON, KML and GML file formats in the WGS84 (EPSG:4326) spatial reference system. 16 | # 17 | ### GIS Tools 18 | Components for translating between Rhino and GIS coordinates and processing GIS data with GDAL programs. 19 | - **Set EarthAnchorPoint**: Set the Rhino EarthAnchorPoint. Setting the EAP is necessary for most Heron components to work properly. 20 | - **XY to Decimal Degrees**: Convert XY to Decimal Degrees Longitude/Latitude in the WGS84 spatial reference system. 21 | - **Decimal Degrees to XY**: Convert WGS84 Decimal Degrees Longitude/Latitude to X/Y. 22 | - **Coordinate Transformation**: Transform points from a source SRS to a destination SRS. The source points should be in the coordinate system of the source SRS. 23 | - **Gdal Ogr2Ogr**: Manipulate vector data with the GDAL OGR2OGR program given a source dataset, a destination dataset and a list of options. Information about conversion options can be found at https://gdal.org/programs/ogr2ogr.html. 24 | - **Gdal Warp**: Manipulate raster data with the GDAL Warp program given a source dataset, a destination dataset and a list of options. Information about Warp options can be found at https://gdal.org/programs/gdalwarp.html. 25 | - **Gdal Translate**: Manipulate raster data with the GDAL Translate program given a source dataset, a destination dataset and a list of options. Information about Translate options can be found at https://gdal.org/programs/gdal_translate.html. 26 | # 27 | ### GIS REST 28 | Components for interacting with REST web services. 29 | - **ESRI REST Service Geocode**: Get coordinates based on a Point-of-Interest or Address using the ESRI geocode service. 30 | - **ESRI REST Service Reverse Geocode**: Get the closest addresses to XY coordinates using the ESRI reverse geocode service. 31 | - **Get REST Service Layers**: Discover ArcGIS REST Service Layers. 32 | - **Get REST Vector**: Get vector data from ArcGIS REST Services. 33 | - **Get REST Topo**: Get STRM, ALOS and GMRT topographic data from web services. These services include global coverage from the Shuttle Radar Topography Mission (SRTM GL3 90m and SRTM GL1 30m), Advanced Land Observing Satellite (ALOS World 3D - 30m) and Global Multi-Resolution Topography (GMRT including bathymetry). Sources are opentopography.org and gmrt.org. 34 | - **Get REST Raster**: Get raster imagery from ArcGIS REST Services. 35 | - **Get REST OSM**: Get an OSM vector file within a boundary from web services such as the Overpass API. Use a search term to filter results and increase speed. 36 | # 37 | ### GIS API 38 | Components for interacting with tile-based services and services requiring a token. 39 | - **Slippy Viewport**: Projects the boundary of a given Viewport to the World XY plane and calculates a good Zoom level for use with tile-based map components. 40 | - **Slippy Tiles**: Visualize boundaries of slippy map tiles within a given boundary at a given zoom level. See https://en.wikipedia.org/wiki/Tiled_web_map for more information about map tiles. 41 | - **Slippy Raster**: Get raster imagery from a tile-based map service. Use the component menu to select the service. 42 | - **Mapbox Vector**: Get vector data from a Mapbox service. Requires a Mapbox Token. 43 | - **Mapbox Raster**: Get raster imagery from a Mapbox service. Requires a Mapbox Token. 44 | - **Mapbox Topo**: Get mesh topography from a Mapbox service. Requires a Mapbox Token. 45 | # 46 | ### Utilities 47 | Non-GIS components 48 | - **Cubemap from View**: Generate a cubemap from a given plane using the specified display mode. 49 | - **Cubemap from View Plus**: Generate a cubemap from a given plane using the specified display mode. This component is also able to visualize ray casting based on colors in the cubemap. 50 | - **Cubemap to Equirectangular**: Convert a cube map panorama to an equirectangular panorama. 51 | - **Image Filtered Colors**: Get a filtered pixel count of colors contained in an image based on color list. 52 | - **Image Top Colors**: Get a sorted list of the top colors contained in an image. 53 | - **Flip Image**: Flip an image along its vertical, horizontal axis or both. 54 | - **Rotate Image**: Roate an image 90, 180 or 270 degrees. 55 | - **Multi Mesh Patch**: Multithreaded creation of mesh patches from planar polylines. The first polyine in a branch will be considered the outer boundary, any others will be considered holes and should be completely within the outer boundary. 56 | - **Multi SDiff**: This multithreaded boolean solid difference (SDiff) component spreads the branches of input over threads for the boolean operation. 57 | - **Multi Move to Topo**: Move breps, surfaces, meshes, polylines and points to a topography mesh. Breps and closed meshes will be moved to the lowest point on the topography mesh within their footprint. Vertexes of curves and open meshes and control points of surfaces will be moved to the topography mesh. Geometry on a branch will be moved together as a group, but can be moved independently by deselecting 'Group' from the component menu. For a slower, but more detailed projection where curves and open meshes take on the vertexes of the topography mesh, select 'Detailed' from the component menu. 58 | - **Color to Hex**: Convert an RGBA color to hexidecimal format. 59 | - **Hex to Color**: Convert a hexidecimal color to RGBA format. 60 | - **Visual Center**: Find the visual center of closed planar curves. The resulting point will lie within the boundary of the curve and multiple curves on a branch will be treated as a surface with holes. 61 | --------------------------------------------------------------------------------