├── .gitattributes ├── .gitignore ├── README.md ├── RvtToTopoJson.addin ├── RvtToTopoJson.sln └── RvtToTopoJson ├── App.cs ├── Command.cs ├── FileExport.cs ├── GeoJson.cs ├── Helpers.cs ├── Properties └── AssemblyInfo.cs ├── RvtToTopoJson.addin ├── RvtToTopoJson.csproj ├── TopoJson.cs └── packages.config /.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 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RvtToTopoJson 2 | 3 | Export Rooms from Revit to GeoJson for Power BI Shape Maps. 4 | 5 | [![Watch the video](https://img.youtube.com/vi/O-y7gwi6wtk/maxresdefault.jpg)](https://youtu.be/O-y7gwi6wtk) 6 | 7 | - Credits: https://forums.autodesk.com/t5/revit-architecture-forum/projecting-revit-model-on-a-map-using-geojson/td-p/7973803 8 | - GeoJson wiki: https://macwright.org/2015/03/23/geojson-second-bite.html 9 | - https://docs.microsoft.com/en-us/power-bi/visuals/desktop-shape-map 10 | - GeoJson to TopoJson converter: 11 | - https://mapshaper.org/ 12 | - http://jeffpaine.github.io/geojson-topojson/ 13 | 14 | ## How it should work 15 | 16 | - The External Command code is saved in [GeoJson.cs](https://github.com/giobel/RvtToTopoJson/blob/master/RvtToTopoJson/GeoJson.cs). It takes a Room corner points, its name and its area and it exports them as GeoJson using the GeoJSON.Net library (credits to Daniel Ignjat for sharing his code on the Autodesk Forum). The GeoJson file is saved as C:\Temp\export.json. 17 | - I've then used mapshaper to transform it into a TopoJson. This file can be imported in Power BI using a Shape map. The TopoJson file can be expanded to access its properties but it's not the best way to do it (I think it would be better to save Room Name and Area in a csv file and use that as a table source in Power BI). 18 | - To update all the maps at the same time, the tables must have a relationship between them. I've manually created a new Table merging the Room Names and link it to the Name's column of the other Tables. Again, this is not the best way to do it. Having the Room Names and Areas in a database and pull the data from there would be the best option. 19 | 20 | ## Bugs 21 | 22 | Currently it does not support rooms with internal boundaries (i.e. columns or shaft openings) 23 | 24 | ![image](https://user-images.githubusercontent.com/27025848/78952722-d4a1e500-7b19-11ea-8e63-303c2fce3102.png) 25 | 26 | -------------------------------------------------------------------------------- /RvtToTopoJson.addin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giobel/RvtToTopoJson/fd9a94e41c81615ed1370c0ec4b30ca7bd9e0f33/RvtToTopoJson.addin -------------------------------------------------------------------------------- /RvtToTopoJson.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2036 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RvtToTopoJson", "RvtToTopoJson\RvtToTopoJson.csproj", "{32130E5C-5707-431F-BF4D-8BE464625C52}" 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 | {32130E5C-5707-431F-BF4D-8BE464625C52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {32130E5C-5707-431F-BF4D-8BE464625C52}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {32130E5C-5707-431F-BF4D-8BE464625C52}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {32130E5C-5707-431F-BF4D-8BE464625C52}.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 = {57B2D2C6-A177-4CE7-8223-DE95F9104E33} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /RvtToTopoJson/App.cs: -------------------------------------------------------------------------------- 1 | #region Namespaces 2 | using System; 3 | using System.Collections.Generic; 4 | using Autodesk.Revit.ApplicationServices; 5 | using Autodesk.Revit.Attributes; 6 | using Autodesk.Revit.DB; 7 | using Autodesk.Revit.UI; 8 | #endregion 9 | 10 | namespace RvtToTopoJson 11 | { 12 | class App : IExternalApplication 13 | { 14 | public Result OnStartup(UIControlledApplication a) 15 | { 16 | return Result.Succeeded; 17 | } 18 | 19 | public Result OnShutdown(UIControlledApplication a) 20 | { 21 | return Result.Succeeded; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /RvtToTopoJson/Command.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.Collections.Generic; 3 | //using System.Linq; 4 | 5 | //using Autodesk.Revit.DB; 6 | //using Autodesk.Revit.UI; 7 | //using Autodesk.Revit.Attributes; 8 | //using Autodesk.Revit.ApplicationServices; 9 | //using GeoJSON.Net.Geometry; 10 | //using Newtonsoft.Json; 11 | //using Autodesk.Revit.UI.Selection; 12 | //using GeoJSON.Net.Feature; 13 | //using System.IO; 14 | 15 | //namespace RvtToTopoJson 16 | //{ 17 | // [TransactionAttribute(TransactionMode.Manual)] 18 | // [RegenerationAttribute(RegenerationOption.Manual)] 19 | // public class Command : IExternalCommand 20 | // { 21 | // UIApplication uiApp; 22 | // Document doc; 23 | 24 | // public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) 25 | // { 26 | // uiApp = commandData.Application; 27 | // UIDocument uidoc = uiApp.ActiveUIDocument; 28 | // doc = uiApp.ActiveUIDocument.Document; 29 | 30 | // //Create a topojson object 31 | // TopoJson.Welcome wel = new TopoJson.Welcome() 32 | // { 33 | // Type = "Topology", 34 | // Transform = new TopoJson.Transform { Scale = new long[2] { 1, 1 }, Translate = new long[2] { 0, 0 } }, 35 | // Objects = new TopoJson.Objects 36 | // { 37 | // Example = new TopoJson.Example 38 | // { 39 | // Type = "GeometryCollection", 40 | // Geometries = new List(), 41 | // } 42 | // }, 43 | // Arcs = new List>>() 44 | // }; 45 | 46 | // List roomProperties = new List(); 47 | 48 | // //roomProperties.Add(new TopoJson.Properties() { Postal = "WA", RoomName = "Corridor", Area = 123 }); 49 | // //roomProperties.Add(new TopoJson.Properties() { Postal = "SA", RoomName = "Kitchen", Area = 456 }); 50 | 51 | // IList roomReferences = uidoc.Selection.PickObjects(ObjectType.Element, "Select some rooms"); 52 | 53 | // double oldX = 0; 54 | // double oldY = 0; 55 | 56 | // foreach (Reference re in roomReferences) 57 | // { 58 | // Element roomElement = doc.GetElement(re); 59 | 60 | // string roomName = roomElement.LookupParameter("Name").AsString(); 61 | 62 | // SpatialElement se = doc.GetElement(re) as SpatialElement; 63 | 64 | // //add room properties 65 | // roomProperties.Add(new TopoJson.Properties() { Number = se.Number, RoomName = roomName, Area = se.Area }); 66 | 67 | // for (int i = 0; i < roomProperties.Count; i++) 68 | // { 69 | // wel.Objects.Example.Geometries.Add(new TopoJson.Geometry 70 | // { 71 | // Type = "Polygon", 72 | // Properties = roomProperties[i], 73 | // Arcs = new List> { new List { i } } 74 | // }); 75 | // } 76 | 77 | // SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions(); 78 | 79 | // IList> loops = se.GetBoundarySegments(opt); 80 | 81 | // foreach (IList loop in loops) 82 | // { 83 | // List> nestedList = new List>(); 84 | 85 | 86 | // ElementId segId = new ElementId(123456); 87 | 88 | 89 | // foreach (BoundarySegment seg in loop) 90 | // { 91 | 92 | // Line segLine = seg.GetCurve() as Line; 93 | // XYZ endPt = segLine.Origin; 94 | 95 | // if (segId == seg.ElementId) 96 | // { 97 | 98 | // } 99 | // else 100 | // { 101 | // //nestedList.Add(new List { endPt.X - oldX, endPt.Y - oldY }); 102 | // nestedList.Add(new List { endPt.X, endPt.Y }); 103 | // } 104 | 105 | // segId = seg.ElementId; 106 | 107 | // oldX = endPt.X; 108 | // oldY = endPt.Y; 109 | 110 | // } 111 | 112 | // wel.Arcs.Add(nestedList); 113 | // } 114 | 115 | 116 | // } 117 | 118 | // #region GeoJson 119 | // Transform ttr = doc.ActiveProjectLocation.GetTotalTransform().Inverse; 120 | // Transform projectlocationTransform = GetProjectLocationTransform(doc); 121 | 122 | // List multiPolygon = new List(); 123 | 124 | // List positions = new List(); 125 | // List positionsfortxt = new List(); 126 | // Position firstpos; 127 | // XYZ p; 128 | 129 | 130 | // foreach (Reference re in roomReferences) 131 | // { 132 | // Element roomElement = doc.GetElement(re); 133 | 134 | // multiPolygon.Add(Helpers.RoomBoundary(doc, re, ttr)); 135 | // } 136 | 137 | 138 | 139 | // #endregion 140 | 141 | // #region File Export 142 | // //EXPORT GEOJSON 143 | // FileExport export = new FileExport(multiPolygon); 144 | // export.ExportGEOJson("coordinates"); 145 | 146 | // StreamWriter writeGeojson = new StreamWriter(@"C:\Temp\Samples\export" + ".json"); 147 | // //writegoeJson.WriteLine(json); 148 | // writeGeojson.Flush(); 149 | // writeGeojson.Close(); 150 | 151 | // #endregion 152 | 153 | // var welcome = TopoJson.Serialize.ToJson(wel); 154 | 155 | // StreamWriter writetext = new StreamWriter(@"C:\Temp\Samples\topoJson" + ".json"); 156 | // writetext.WriteLine(welcome); 157 | // writetext.Flush(); 158 | // writetext.Close(); 159 | 160 | 161 | // //Activate command in revit 162 | // #region Revit Start Command 163 | // Transaction trans = new Transaction(doc); 164 | // trans.Start("GeoReader"); 165 | // trans.Commit(); 166 | // TaskDialog.Show("File was built", "Success"); 167 | // #endregion 168 | // return Result.Succeeded; 169 | // } 170 | 171 | // private Transform GetProjectLocationTransform(Document doc) 172 | // { 173 | // // Retrieve the active project location position. 174 | 175 | // ProjectPosition projectPosition 176 | // = doc.ActiveProjectLocation.GetProjectPosition(XYZ.Zero); 177 | 178 | // // Create a translation vector for the offsets 179 | 180 | // XYZ translationVector = new XYZ( 181 | // projectPosition.EastWest, 182 | // projectPosition.NorthSouth, 183 | // projectPosition.Elevation); 184 | 185 | // Transform translationTransform 186 | // = Transform.CreateTranslation( 187 | // translationVector); 188 | 189 | // // Create a rotation for the angle about true north 190 | 191 | // Transform rotationTransform 192 | // = Transform.CreateRotation( 193 | // XYZ.BasisZ, projectPosition.Angle); 194 | 195 | // // Combine the transforms 196 | 197 | // Transform finalTransform 198 | // = translationTransform.Multiply( 199 | // rotationTransform); 200 | 201 | // return finalTransform; 202 | // } 203 | 204 | 205 | 206 | // } 207 | 208 | //} 209 | -------------------------------------------------------------------------------- /RvtToTopoJson/FileExport.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using Newtonsoft.Json; 4 | using GeoJSON.Net.Geometry; 5 | using GeoJSON.Net.Feature; 6 | 7 | //credits https://forums.autodesk.com/t5/revit-architecture-forum/projecting-revit-model-on-a-map-using-geojson/td-p/7973803 8 | 9 | namespace RvtToTopoJson 10 | { 11 | public class FileExport { 12 | private string exportString = ""; 13 | 14 | public string ExportString { get => exportString; set => exportString = value; } 15 | 16 | private List poly = new List(); 17 | 18 | public FileExport(List poly) { 19 | this.poly=poly; 20 | } 21 | 22 | public void CreateTextFile(string name, IDictionary> data) { 23 | StreamWriter writetext = new StreamWriter(name); 24 | foreach (var a in data.Keys) 25 | { 26 | ExportString += a + ",\n"; 27 | foreach (var i in data[a]) 28 | { 29 | ExportString += i.ToString() + ",\n"; 30 | } 31 | } 32 | writetext.WriteLine(ExportString); 33 | writetext.Flush(); 34 | writetext.Close(); 35 | 36 | } 37 | public void CreateTextFile(string name, HashSet data) { 38 | StreamWriter writetext = new StreamWriter(name); 39 | foreach (var i in data) 40 | { 41 | ExportString += i.ToString() + "\n"; 42 | } 43 | writetext.WriteLine(ExportString); 44 | writetext.Flush(); 45 | writetext.Close(); 46 | } 47 | public MultiPolygon Geometries(List polygons) { 48 | var multipolygon = new MultiPolygon(polygons); 49 | return multipolygon; 50 | } 51 | public void ExportGEOJson(string name) { 52 | var feature = new Feature(Geometries(poly)); 53 | string json = JsonConvert.SerializeObject(feature,Formatting.Indented); 54 | StreamWriter writetext = new StreamWriter(name+".json"); 55 | writetext.WriteLine(json); 56 | writetext.Flush(); 57 | writetext.Close(); 58 | } 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /RvtToTopoJson/GeoJson.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using Autodesk.Revit.DB; 4 | using Autodesk.Revit.UI; 5 | using Autodesk.Revit.Attributes; 6 | using GeoJSON.Net.Geometry; 7 | using RvtToTopoJson; 8 | using System.IO; 9 | using Autodesk.Revit.UI.Selection; 10 | using GeoJSON.Net.Feature; 11 | using Newtonsoft.Json; 12 | using System.Linq; 13 | using System; 14 | 15 | namespace RvtToTopoJson 16 | { 17 | [TransactionAttribute(TransactionMode.Manual)] 18 | [RegenerationAttribute(RegenerationOption.Manual)] 19 | public class CreateGeoJson : IExternalCommand 20 | { 21 | private List multiPolygon = new List(); 22 | private List positions = new List(); 23 | private List positionsfortxt = new List(); 24 | Position firstpos; 25 | UIApplication uiApp; 26 | Document doc; 27 | private bool initiated = false; 28 | XYZ p; 29 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) 30 | { 31 | uiApp = commandData.Application; 32 | UIDocument uidoc = uiApp.ActiveUIDocument; 33 | doc = uidoc.Document; 34 | 35 | try 36 | { 37 | 38 | Transform ttr = doc.ActiveProjectLocation.GetTotalTransform().Inverse; 39 | Transform projectlocationTransform = GetProjectLocationTransform(doc); 40 | 41 | IList roomReferences = uidoc.Selection.PickObjects(ObjectType.Element, "Select some rooms"); 42 | 43 | SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions(); 44 | 45 | //control the boundary location 46 | opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center; 47 | 48 | var features = new List(); 49 | 50 | foreach (Reference re in roomReferences) 51 | { 52 | 53 | Element roomElement = doc.GetElement(re); 54 | 55 | string roomName = ""; 56 | try 57 | { 58 | //roomName = roomElement.LookupParameter("Name").AsString(); 59 | roomName = roomElement.get_Parameter(BuiltInParameter.ROOM_NAME).AsString(); 60 | 61 | } 62 | catch 63 | { 64 | TaskDialog.Show("Error", "Parameter \"Name\" not found in Room element"); 65 | return Result.Failed; 66 | } 67 | 68 | SpatialElement se = doc.GetElement(re) as SpatialElement; 69 | 70 | //multiPolygon.Add(Helpers.RoomBoundary(doc, re, ttr)); 71 | 72 | IList> loops = se.GetBoundarySegments(opt); 73 | 74 | var featureProps = new Dictionary { { "Name", roomName }, { "Area", se.Area } }; 75 | 76 | var coordinates = new List(); 77 | 78 | foreach (IList loop in loops) 79 | { 80 | ElementId segId = new ElementId(123456); 81 | 82 | foreach (BoundarySegment seg in loop) 83 | { 84 | Line segLine = seg.GetCurve() as Line; 85 | XYZ endPt = segLine.GetEndPoint(0); 86 | 87 | if (segId == seg.ElementId) 88 | { 89 | 90 | } 91 | else 92 | { 93 | //TaskDialog.Show("re", $"{endPt.Y} {endPt.X}"); 94 | coordinates.Add(new Position(endPt.Y * 0.3048, endPt.X * 0.3048)); 95 | } 96 | 97 | segId = seg.ElementId; 98 | 99 | } 100 | } 101 | 102 | coordinates.Add(coordinates.First()); 103 | 104 | var polygon = new Polygon(new List { new LineString(coordinates) }); 105 | 106 | features.Add(new Feature(polygon, featureProps)); 107 | 108 | } 109 | 110 | 111 | var models = new FeatureCollection(features); 112 | 113 | 114 | 115 | #region File Export 116 | //EXPORT GEOJSON 117 | var serializedData = JsonConvert.SerializeObject(models, Formatting.Indented); 118 | StreamWriter writetext = new StreamWriter(@"C:\Temp\export.json"); 119 | writetext.WriteLine(serializedData); 120 | writetext.Flush(); 121 | writetext.Close(); 122 | 123 | #endregion 124 | //Activate command in revit 125 | #region Revit Start Command 126 | Transaction trans = new Transaction(doc); 127 | trans.Start("GeoReader"); 128 | trans.Commit(); 129 | TaskDialog.Show("File was built", "Success"); 130 | #endregion 131 | 132 | 133 | return Result.Succeeded; 134 | } 135 | catch (Exception ex) 136 | { 137 | TaskDialog.Show("Error", ex.Message); 138 | return Result.Failed; 139 | } 140 | } 141 | 142 | 143 | Transform GetProjectLocationTransform(Document doc) 144 | { 145 | // Retrieve the active project location position. 146 | 147 | ProjectPosition projectPosition 148 | = doc.ActiveProjectLocation.GetProjectPosition(XYZ.Zero); 149 | 150 | // Create a translation vector for the offsets 151 | 152 | XYZ translationVector = new XYZ( 153 | projectPosition.EastWest, 154 | projectPosition.NorthSouth, 155 | projectPosition.Elevation); 156 | 157 | Transform translationTransform 158 | = Transform.CreateTranslation( 159 | translationVector); 160 | 161 | // Create a rotation for the angle about true north 162 | 163 | Transform rotationTransform 164 | = Transform.CreateRotation( 165 | XYZ.BasisZ, projectPosition.Angle); 166 | 167 | // Combine the transforms 168 | 169 | Transform finalTransform 170 | = translationTransform.Multiply( 171 | rotationTransform); 172 | 173 | return finalTransform; 174 | } 175 | 176 | } 177 | 178 | public class Request 179 | { 180 | public int Id { get; set; } 181 | public string Name { get; set; } 182 | public Fence Fence { get; set; } 183 | } 184 | public class Fence 185 | { 186 | public int Type { get; set; } 187 | public FeatureCollection Values { get; set; } 188 | } 189 | } 190 | 191 | -------------------------------------------------------------------------------- /RvtToTopoJson/Helpers.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.Revit.DB; 2 | using GeoJSON.Net.Geometry; 3 | using System.Collections.Generic; 4 | 5 | namespace RvtToTopoJson 6 | { 7 | internal class Helpers 8 | { 9 | public double Area { get; set; } 10 | public string RoomName { get; set; } 11 | 12 | public static Polygon RoomBoundary(Document doc, Reference re, Transform ttr) 13 | { 14 | SpatialElement se = doc.GetElement(re) as SpatialElement; 15 | 16 | SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions(); 17 | 18 | IList> loops = se.GetBoundarySegments(opt); 19 | 20 | List positions = new List(); 21 | 22 | 23 | foreach (IList loop in loops) 24 | { 25 | 26 | ElementId segId = new ElementId(123456); 27 | 28 | foreach (BoundarySegment seg in loop) 29 | { 30 | Line segLine = seg.GetCurve() as Line; 31 | 32 | XYZ endPt = segLine.Origin; 33 | 34 | XYZ p = ttr.OfPoint(endPt); 35 | 36 | Position firstpos = new Position(p.Y, p.X, p.Z); 37 | 38 | 39 | if (segId == seg.ElementId) 40 | { 41 | 42 | } 43 | else 44 | { 45 | positions.Add(new Position(p.Y, p.X, p.Z)); 46 | } 47 | 48 | positions.Add(firstpos); 49 | 50 | segId = seg.ElementId; 51 | 52 | } 53 | } 54 | 55 | return new Polygon(new List { new LineString(positions) }); 56 | } 57 | 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /RvtToTopoJson/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Allgemeine Informationen über eine Assembly werden über die folgenden 6 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 7 | // die einer Assembly zugeordnet sind. 8 | [assembly: AssemblyTitle("dokaGeoreader")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("dokaGeoreader")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly 18 | // für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von 19 | // COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. 20 | [assembly: ComVisible(false)] 21 | 22 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 23 | [assembly: Guid("32130e5c-5707-431f-bf4d-8be464625c52")] 24 | 25 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 26 | // 27 | // Hauptversion 28 | // Nebenversion 29 | // Buildnummer 30 | // Revision 31 | // 32 | // Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, 33 | // indem Sie "*" wie unten gezeigt eingeben: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /RvtToTopoJson/RvtToTopoJson.addin: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Command RevitGeoJson 5 | Some description for RevitGeoJson 6 | .\RvtToTopoJson\RvtToTopoJson.dll 7 | RvtToTopoJson.CreateGeoJson 8 | 99605c33-5b4e-4641-9361-818c81026ea9 9 | com.typepad.thebuildingcoder 10 | The Building Coder, http://thebuildingcoder.typepad.com 11 | 12 | 13 | Application RevitGeoJson 14 | .\RvtToTopoJson\RvtToTopoJson.dll 15 | RvtToTopoJson.App 16 | fc82fb14-1b85-4580-b86d-1e385c09d85b 17 | com.typepad.thebuildingcoder 18 | The Building Coder, http://thebuildingcoder.typepad.com 19 | 20 | 21 | -------------------------------------------------------------------------------- /RvtToTopoJson/RvtToTopoJson.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {32130E5C-5707-431F-BF4D-8BE464625C52} 8 | Library 9 | Properties 10 | RvtToTopoJson 11 | RvtToTopoJson 12 | v4.7.2 13 | 512 14 | Program 15 | C:\Program Files\Autodesk\Revit 2018\revit.exe 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\GeoJSON.Net.1.1.73\lib\net45\GeoJSON.Net.dll 38 | 39 | 40 | ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll 41 | False 42 | 43 | 44 | ..\..\..\..\..\..\Program Files\Autodesk\Revit 2019\RevitAPI.dll 45 | False 46 | 47 | 48 | ..\..\..\..\..\..\Program Files\Autodesk\Revit 2019\RevitAPIUI.dll 49 | False 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /RvtToTopoJson/TopoJson.cs: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // To parse this JSON data, add NuGet 'Newtonsoft.Json' then do: 4 | // 5 | // using QuickType; 6 | // 7 | // var welcome = Welcome.FromJson(jsonString); 8 | using System; 9 | using System.Collections.Generic; 10 | 11 | using System.Globalization; 12 | using Newtonsoft.Json; 13 | using Newtonsoft.Json.Converters; 14 | 15 | 16 | namespace TopoJson 17 | { 18 | 19 | public partial class Welcome 20 | { 21 | [JsonProperty("type")] 22 | public string Type { get; set; } 23 | 24 | [JsonProperty("transform")] 25 | public Transform Transform { get; set; } 26 | 27 | [JsonProperty("objects")] 28 | public Objects Objects { get; set; } 29 | 30 | [JsonProperty("arcs")] 31 | public List>> Arcs { get; set; } 32 | } 33 | 34 | public partial class Objects 35 | { 36 | [JsonProperty("example")] 37 | public Example Example { get; set; } 38 | } 39 | 40 | public partial class Example 41 | { 42 | [JsonProperty("type")] 43 | public string Type { get; set; } 44 | 45 | [JsonProperty("geometries")] 46 | public List Geometries { get; set; } 47 | } 48 | 49 | public partial class Geometry 50 | { 51 | [JsonProperty("type")] 52 | public string Type { get; set; } 53 | 54 | [JsonProperty("properties")] 55 | public Properties Properties { get; set; } 56 | 57 | [JsonProperty("arcs")] 58 | public List> Arcs { get; set; } 59 | } 60 | 61 | public partial class Properties 62 | { 63 | [JsonProperty("Number")] 64 | public string Number { get; set; } 65 | 66 | [JsonProperty("Room Name")] 67 | public string RoomName { get; set; } 68 | 69 | [JsonProperty("Area")] 70 | public double Area { get; set; } 71 | } 72 | 73 | public partial class Transform 74 | { 75 | [JsonProperty("scale")] 76 | public long[] Scale { get; set; } 77 | 78 | [JsonProperty("translate")] 79 | public long[] Translate { get; set; } 80 | } 81 | 82 | public partial class Welcome 83 | { 84 | public static Welcome FromJson(string json) => JsonConvert.DeserializeObject(json, Converter.Settings); 85 | } 86 | 87 | public static class Serialize 88 | { 89 | public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, Converter.Settings); 90 | } 91 | 92 | internal static class Converter 93 | { 94 | public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings 95 | { 96 | MetadataPropertyHandling = MetadataPropertyHandling.Ignore, 97 | DateParseHandling = DateParseHandling.None, 98 | Formatting = Formatting.Indented, 99 | Converters = 100 | { 101 | new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } 102 | }, 103 | }; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /RvtToTopoJson/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | --------------------------------------------------------------------------------