├── .gitignore
├── CustomExporterAdnMeshJson.sln
├── CustomExporterAdnMeshJson
├── AdnMeshData.cs
├── CentroidVolume.cs
├── Command.cs
├── CustomExporterAdnMeshJson.addin
├── CustomExporterAdnMeshJson.csproj
├── ExportContextAdnMesh.cs
├── NormalLookupXyz.cs
├── PointInt.cs
├── Properties
│ └── AssemblyInfo.cs
├── Util.cs
├── VertexLookupInt.cs
└── x.cs
├── LICENSE
└── README.md
/.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 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomExporterAdnMeshJson", "CustomExporterAdnMeshJson\CustomExporterAdnMeshJson.csproj", "{AE586BA5-6657-49A6-A3D6-7A85088923CE}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {AE586BA5-6657-49A6-A3D6-7A85088923CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {AE586BA5-6657-49A6-A3D6-7A85088923CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {AE586BA5-6657-49A6-A3D6-7A85088923CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {AE586BA5-6657-49A6-A3D6-7A85088923CE}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/AdnMeshData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using Autodesk.Revit.DB;
6 |
7 | namespace CustomExporterAdnMeshJson
8 | {
9 | ///
10 | /// The data format specifying one solid for the
11 | /// WebGL viewer, defining its centre, colour, id,
12 | /// triangular facets, their vertex coordinates,
13 | /// indices and normals.
14 | ///
15 | class AdnMeshData
16 | {
17 | int FacetCount { get; set; } // optional
18 | int VertexCount { get; set; } // optional
19 | int[] VertexCoords { get; set; }
20 | int[] VertexIndices { get; set; } // triangles
21 | double[] Normals { get; set; }
22 | int[] NormalIndices { get; set; } // not optional, one normal per vertex
23 | int[] Center { get; set; }
24 | int Color { get; set; }
25 | string Id { get; set; }
26 |
27 | ///
28 | /// Apply this factor to all point data when
29 | /// saving to JSON to accomodate the expected
30 | /// scaling.
31 | ///
32 | const double _export_factor = 0.002;
33 |
34 | public AdnMeshData(
35 | VertexLookupInt vertices,
36 | List vertexIndices,
37 | NormalLookupXyz normals,
38 | List normalIndices,
39 | PointInt center,
40 | Color color,
41 | double transparency,
42 | string id )
43 | {
44 | int n = vertexIndices.Count;
45 |
46 | Debug.Assert( 0 == (n % 3),
47 | "expected triples of 3D point vertex indices" );
48 |
49 | Debug.Assert( normalIndices.Count == n,
50 | "expected a normal for each vertex" );
51 |
52 | FacetCount = n / 3;
53 |
54 | n = vertices.Count;
55 | VertexCount = n;
56 | VertexCoords = new int[n * 3];
57 | int i = 0;
58 | foreach( PointInt p in vertices.Keys )
59 | {
60 | VertexCoords[i++] = p.X;
61 | VertexCoords[i++] = p.Y;
62 | VertexCoords[i++] = p.Z;
63 | }
64 | VertexIndices = vertexIndices.ToArray();
65 |
66 | n = normals.Count;
67 | Normals = new double[n * 3];
68 | i = 0;
69 | foreach( XYZ v in normals.Keys )
70 | {
71 | Normals[i++] = v.X;
72 | Normals[i++] = v.Y;
73 | Normals[i++] = v.Z;
74 | }
75 | NormalIndices = normalIndices.ToArray();
76 |
77 | Center = new int[3];
78 | i = 0;
79 | Center[i++] = center.X;
80 | Center[i++] = center.Y;
81 | Center[i] = center.Z;
82 |
83 | byte alpha = (byte) (
84 | ( 100 - transparency ) * 2.55555555 );
85 |
86 | Color = ConvertClr(
87 | color.Red, color.Green, color.Blue, alpha );
88 |
89 | Id = id;
90 | }
91 |
92 | ///
93 | /// Convert colour and transparency to
94 | /// the required integer format.
95 | ///
96 | static int ConvertClr( byte r, byte g, byte b, byte a )
97 | {
98 | return ( r << 24 ) + ( g << 16 ) + ( b << 8 ) + a;
99 | }
100 |
101 | public string ToJson()
102 | {
103 | // I did think of using a JSON serialiser,
104 | // either one of these two provided by the
105 | // .NET framework or one of the other libraries:
106 | // System.Runtime.Serialization.Json.DataContractJsonSerializer
107 | // System.Web.Script.Serialization.JavaScriptSerializer
108 | // However, reading this comparison and alternative
109 | // implementation, I decided to just write the couple
110 | // of lines myself.
111 | // http://procbits.com/2011/08/11/fridaythe13th-the-best-json-parser-for-silverlight-and-net
112 |
113 | string s = string.Format
114 | ( "\n \"FacetCount\":{0},"
115 | + "\n \"VertexCount\":{1},"
116 | + "\n \"VertexCoords\":[{2}],"
117 | + "\n \"VertexIndices\":[{3}],"
118 | + "\n \"Normals\":[{4}],"
119 | + "\n \"NormalIndices\":[{5}],"
120 | + "\n \"Center\":[{6}],"
121 | + "\n \"Color\":[{7}],"
122 | + "\n \"Id\":\"{8}\"",
123 | FacetCount,
124 | VertexCount,
125 | string.Join( ",", VertexCoords.Select( i => ( _export_factor * i ).ToString( "0.#" ) ).ToArray() ),
126 | string.Join( ",", VertexIndices.Select( i => i.ToString() ).ToArray() ),
127 | string.Join( ",", Normals.Select( a => a.ToString( "0.####" ) ).ToArray() ),
128 | string.Join( ",", NormalIndices.Select( i => i.ToString() ) ),
129 | string.Join( ",", Center.Select( i => ( _export_factor * i ).ToString( "0.#" ) ) ),
130 | Color,
131 | Id );
132 |
133 | return "\n{" + s + "\n}";
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/CentroidVolume.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Autodesk.Revit.DB;
3 |
4 | namespace CustomExporterAdnMeshJson
5 | {
6 | ///
7 | /// Calculate and store the centroid and volume
8 | /// from a set of triangular facets.
9 | ///
10 | class CentroidVolume
11 | {
12 | XYZ _centroid;
13 | double _volume;
14 |
15 | public CentroidVolume()
16 | {
17 | Init();
18 | }
19 |
20 | public void Init()
21 | {
22 | _centroid = XYZ.Zero;
23 | _volume = 0.0;
24 | }
25 |
26 | public void AddTriangle( XYZ[] p )
27 | {
28 | double vol
29 | = p[0].X * ( p[1].Y * p[2].Z - p[2].Y * p[1].Z )
30 | + p[0].Y * ( p[1].Z * p[2].X - p[2].Z * p[1].X )
31 | + p[0].Z * ( p[1].X * p[2].Y - p[2].X * p[1].Y );
32 |
33 | _centroid += vol * ( p[0] + p[1] + p[2] );
34 | _volume += vol;
35 | }
36 |
37 | ///
38 | /// Set centroid coordinates and volume
39 | /// to their final values when completed.
40 | ///
41 | public void Complete()
42 | {
43 | _centroid /= 4 * _volume;
44 | _volume /= 6;
45 | }
46 |
47 | public XYZ Centroid
48 | {
49 | get
50 | {
51 | return _centroid;
52 | }
53 | }
54 |
55 | public double Volume
56 | {
57 | get
58 | {
59 | return _volume;
60 | }
61 | }
62 |
63 | override public string ToString()
64 | {
65 | return Util.RealString( _volume ) + "@"
66 | + Util.PointString( _centroid );
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/Command.cs:
--------------------------------------------------------------------------------
1 | #region Namespaces
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using Autodesk.Revit.ApplicationServices;
6 | using Autodesk.Revit.Attributes;
7 | using Autodesk.Revit.DB;
8 | using Autodesk.Revit.UI;
9 | using Autodesk.Revit.UI.Selection;
10 | using System.IO;
11 | #endregion
12 |
13 | namespace CustomExporterAdnMeshJson
14 | {
15 | ///
16 | /// ADN mesh data custom exporter
17 | /// external command mainline.
18 | ///
19 | [Transaction( TransactionMode.ReadOnly )]
20 | public class Command : IExternalCommand
21 | {
22 | public Result Execute(
23 | ExternalCommandData commandData,
24 | ref string message,
25 | ElementSet elements )
26 | {
27 | UIApplication uiapp = commandData.Application;
28 | UIDocument uidoc = uiapp.ActiveUIDocument;
29 | Application app = uiapp.Application;
30 | Document doc = uidoc.Document;
31 |
32 | // This command requires an active document
33 |
34 | if( null == uidoc )
35 | {
36 | message = "Please run this command in an active project document.";
37 | return Result.Failed;
38 | }
39 |
40 | View3D view = doc.ActiveView as View3D;
41 |
42 | if( null == view )
43 | {
44 | message = "Please run this command in a 3D view.";
45 | return Result.Failed;
46 | }
47 |
48 | // Instantiate our custom context
49 |
50 | ExportContextAdnMesh context
51 | = new ExportContextAdnMesh( doc );
52 |
53 | // Instantiate a custom exporter with it
54 |
55 | using( CustomExporter exporter
56 | = new CustomExporter( doc, context ) )
57 | {
58 | // Tell the exporter whether we need face info.
59 | // If not, it is better to exclude them, since
60 | // processing faces takes significant time and
61 | // memory. In any case, tessellated polymeshes
62 | // can be exported (and will be sent to the
63 | // context). Excluding faces just excludes the calls,
64 | // not the actual processing of face tessellation.
65 | // Meshes of the faces will still be received by
66 | // the context.
67 |
68 | //exporter.IncludeFaces = false; // removed in Revit 2017
69 |
70 | exporter.IncludeGeometricObjects = false; // Revit 2017
71 |
72 | try
73 | {
74 | exporter.Export( view );
75 | }
76 | catch( Autodesk.Revit.Exceptions.ExternalApplicationException ex )
77 | {
78 | Debug.Print( "ExternalApplicationException " + ex.Message );
79 | }
80 | }
81 |
82 | // Save ADN mesh data in JSON format
83 |
84 | StreamWriter s = new StreamWriter(
85 | "C:/tmp/test.json" );
86 |
87 | s.Write( "[" );
88 |
89 | int i = 0;
90 |
91 | foreach( AdnMeshData d in context.MeshData )
92 | {
93 | if( 0 < i ) { s.Write( ',' ); }
94 |
95 | s.Write( d.ToJson() );
96 |
97 | ++i;
98 | }
99 |
100 | s.Write( "\n]\n" );
101 | s.Close();
102 |
103 | return Result.Succeeded;
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/CustomExporterAdnMeshJson.addin:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Export ADN Mesh Data to JSON
5 | Export ADN Mesh Data to JSON
6 | CustomExporterAdnMeshJson.dll
7 | CustomExporterAdnMeshJson.Command
8 | 92037c5b-5799-4367-818c-bbc22ffb4097
9 | TBC_
10 | The Building Coder, http://thebuildingcoder.typepad.com
11 |
12 |
13 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/CustomExporterAdnMeshJson.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | None
6 |
7 |
8 |
9 |
10 | Debug
11 | AnyCPU
12 |
13 |
14 |
15 |
16 | {AE586BA5-6657-49A6-A3D6-7A85088923CE}
17 | Library
18 | Properties
19 | CustomExporterAdnMeshJson
20 | v4.5.2
21 | 512
22 |
23 |
24 | true
25 | full
26 | false
27 | bin\Debug\
28 | DEBUG;TRACE
29 | prompt
30 | 4
31 | Program
32 | $(ProgramW6432)\Autodesk\Revit 2014\Revit.exe
33 | false
34 |
35 |
36 | pdbonly
37 | true
38 | bin\Release\
39 | TRACE
40 | prompt
41 | 4
42 | Program
43 | $(ProgramW6432)\Autodesk\Revit 2014\Revit.exe
44 | false
45 |
46 |
47 |
48 | ..\..\..\..\Program Files\Autodesk\Revit 2017\RevitAPI.dll
49 | False
50 |
51 |
52 | ..\..\..\..\Program Files\Autodesk\Revit 2017\RevitAPIUI.dll
53 | False
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | copy "$(ProjectDir)CustomExporterAdnMeshJson.addin" "$(AppData)\Autodesk\REVIT\Addins\2017"
79 | copy "$(ProjectDir)bin\debug\CustomExporterAdnMeshJson.dll" "$(AppData)\Autodesk\REVIT\Addins\2017"
80 |
81 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/ExportContextAdnMesh.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using Autodesk.Revit.DB;
5 |
6 | namespace CustomExporterAdnMeshJson
7 | {
8 | ///
9 | /// Custom exporter IExportContext implementation to
10 | /// capture ADN mesh data.
11 | ///
12 | class ExportContextAdnMesh : IExportContext
13 | {
14 | Document _doc;
15 |
16 | ///
17 | /// Stack of transformations for
18 | /// link and instance elements.
19 | ///
20 | Stack _transformationStack
21 | = new Stack();
22 |
23 | ///
24 | /// List of triangle vertices.
25 | ///
26 | VertexLookupInt _vertices = new VertexLookupInt();
27 |
28 | ///
29 | /// List of triangles, defined as
30 | /// triples of vertex indices.
31 | ///
32 | List _triangles = new List();
33 |
34 | ///
35 | /// List of normal vectors, defined by an index
36 | /// into the normal lookup for each triangle vertex.
37 | ///
38 | List _normalIndices = new List();
39 |
40 | NormalLookupXyz _normals = new NormalLookupXyz();
41 |
42 | ///
43 | /// Calculate center of gravity of current element.
44 | ///
45 | CentroidVolume _centroid_volume
46 | = new CentroidVolume();
47 |
48 | Color _color;
49 | double _transparency;
50 | List _data;
51 |
52 | public ExportContextAdnMesh( Document doc )
53 | {
54 | _doc = doc;
55 | _data = new List();
56 | _transformationStack.Push( Transform.Identity );
57 | }
58 |
59 | public AdnMeshData[] MeshData
60 | {
61 | get
62 | {
63 | return _data.ToArray();
64 | }
65 | }
66 |
67 | Transform CurrentTransform
68 | {
69 | get
70 | {
71 | return _transformationStack.Peek();
72 | }
73 | }
74 |
75 | ///
76 | /// Store a triangle, adding new vertices for it
77 | /// to our vertex lookup dictionary if needed and
78 | /// accumulating its volume and centroid contribution.
79 | ///
80 | void StoreTriangle(
81 | IList vertices,
82 | PolymeshFacet triangle,
83 | XYZ normal )
84 | {
85 | // Retrieve the three triangle vertices
86 |
87 | Transform currentTransform = CurrentTransform;
88 |
89 | XYZ[] p = new XYZ[] {
90 | currentTransform.OfPoint( vertices[triangle.V1] ),
91 | currentTransform.OfPoint( vertices[triangle.V2] ),
92 | currentTransform.OfPoint( vertices[triangle.V3] )
93 | };
94 |
95 | // Ensure the three are ordered counter-clockwise
96 |
97 | //XYZ v = p[1] - p[0];
98 | //XYZ w = p[2] - p[0];
99 |
100 | //Debug.Assert( Util.IsRightHanded( v, w, normal ),
101 | // "expected counter-clockwise vertex order" );
102 |
103 | // Centroid and volume calculation
104 |
105 | _centroid_volume.AddTriangle( p );
106 |
107 | // Store vertex, facet and normals
108 |
109 | for( int i = 0; i < 3; ++i )
110 | {
111 | PointInt q = new PointInt( p[i] );
112 |
113 | _triangles.Add( _vertices.AddVertex( q ) );
114 |
115 | _normalIndices.Add( _normals.AddNormal(
116 | currentTransform.OfVector( normal ) ) );
117 | }
118 | }
119 |
120 | public void Finish()
121 | {
122 | Debug.Print( "Finish" );
123 | }
124 |
125 | public bool IsCanceled()
126 | {
127 | return false;
128 | }
129 |
130 | // Removed in Revit 2017:
131 | //public void OnDaylightPortal(
132 | // DaylightPortalNode node )
133 | //{
134 | // throw new NotImplementedException();
135 | //}
136 |
137 | public RenderNodeAction OnElementBegin(
138 | ElementId elementId )
139 | {
140 | string s = elementId.IntegerValue.ToString();
141 |
142 | Debug.Print( "ElementBegin id " + s );
143 |
144 | _vertices.Clear();
145 | _triangles.Clear();
146 | _normals.Clear();
147 | _normalIndices.Clear();
148 | _centroid_volume.Init();
149 |
150 | return RenderNodeAction.Proceed;
151 | }
152 |
153 | public void OnElementEnd( ElementId elementId )
154 | {
155 | Debug.Print( "ElementEnd" );
156 |
157 | // Set centroid coordinates to their final value
158 |
159 | _centroid_volume.Complete();
160 |
161 | string metadataId = _doc.GetElement(
162 | elementId ).UniqueId;
163 |
164 | AdnMeshData meshData = new AdnMeshData(
165 | _vertices, _triangles, _normals, _normalIndices,
166 | new PointInt( _centroid_volume.Centroid ),
167 | _color, _transparency, metadataId );
168 |
169 | _data.Add( meshData );
170 | }
171 |
172 | public RenderNodeAction OnFaceBegin( FaceNode node )
173 | {
174 | Debug.Print( "OnFaceBegin not implemented." );
175 | throw new NotImplementedException();
176 | return RenderNodeAction.Skip;
177 | }
178 |
179 | public void OnFaceEnd( FaceNode node )
180 | {
181 | Debug.Print( "OnFaceEnd not implemented." );
182 | throw new NotImplementedException();
183 | }
184 |
185 | public RenderNodeAction OnInstanceBegin(
186 | InstanceNode node )
187 | {
188 | FamilySymbol symbol = _doc.GetElement(
189 | node.GetSymbolId() ) as FamilySymbol;
190 |
191 | Debug.Assert( null != symbol,
192 | "expected valid family symbol" );
193 |
194 | Debug.Print( "InstanceBegin "
195 | + symbol.Category.Name + " : "
196 | + symbol.Family.Name + " : "
197 | + symbol.Name );
198 |
199 | _transformationStack.Push( CurrentTransform
200 | .Multiply( node.GetTransform() ) );
201 |
202 | return RenderNodeAction.Proceed;
203 | }
204 |
205 | public void OnInstanceEnd( InstanceNode node )
206 | {
207 | Debug.Print( "InstanceEnd" );
208 |
209 | _transformationStack.Pop();
210 | }
211 |
212 | public void OnLight( LightNode node )
213 | {
214 | Debug.Print( "OnLight not implemented." );
215 | throw new NotImplementedException();
216 | }
217 |
218 | public RenderNodeAction OnLinkBegin( LinkNode node )
219 | {
220 | _transformationStack.Push( CurrentTransform
221 | .Multiply( node.GetTransform() ) );
222 |
223 | return RenderNodeAction.Proceed;
224 | }
225 |
226 | public void OnLinkEnd( LinkNode node )
227 | {
228 | _transformationStack.Pop();
229 | }
230 |
231 | public void OnMaterial( MaterialNode node )
232 | {
233 | Color c = node.Color;
234 | double t = node.Transparency;
235 |
236 | string s = string.Format( "({0},{1},{2})",
237 | c.Red, c.Green, c.Blue );
238 |
239 | Debug.Print( "Colour " + s + ", transparency "
240 | + t.ToString( "0.##" ) );
241 |
242 | _color = c;
243 | _transparency = t;
244 | }
245 |
246 | public void OnPolymesh( PolymeshTopology node )
247 | {
248 | int nPts = node.NumberOfPoints;
249 | int nFacets = node.NumberOfFacets;
250 |
251 | DistributionOfNormals distrib
252 | = node.DistributionOfNormals;
253 |
254 | Debug.Print( string.Format(
255 | "Polymesh {0} vertices {1} facets",
256 | nPts, nFacets ) );
257 |
258 | int iFacet = 0;
259 | int iPoint = 0;
260 |
261 | IList vertices = node.GetPoints();
262 | IList normals = node.GetNormals();
263 | XYZ normal;
264 |
265 | foreach( PolymeshFacet triangle in node.GetFacets() )
266 | {
267 | // Just grab one normal per facet; ignore the
268 | // three normals per point if they differ.
269 |
270 | if( DistributionOfNormals.OnePerFace == distrib )
271 | {
272 | normal = node.GetNormal( 0 );
273 | }
274 | else if( DistributionOfNormals.OnEachFacet
275 | == distrib )
276 | {
277 | normal = node.GetNormal( iFacet++ );
278 | }
279 | else
280 | {
281 | Debug.Assert( DistributionOfNormals
282 | .AtEachPoint == distrib, "what else?" );
283 |
284 | normal = node.GetNormal( triangle.V1 )
285 | + node.GetNormal( triangle.V2 )
286 | + node.GetNormal( triangle.V3 );
287 | normal /= 3.0;
288 | }
289 |
290 | StoreTriangle( vertices, triangle, normal );
291 | }
292 | }
293 |
294 | public void OnRPC( RPCNode node )
295 | {
296 | Debug.Print( "OnRPC not implemented." );
297 | throw new NotImplementedException();
298 | }
299 |
300 | public RenderNodeAction OnViewBegin( ViewNode node )
301 | {
302 | View3D view = _doc.GetElement( node.ViewId )
303 | as View3D;
304 |
305 | Debug.Assert( null != view,
306 | "expected valid 3D view" );
307 |
308 | Debug.Print( "ViewBegin " + view.Name );
309 |
310 | return RenderNodeAction.Proceed;
311 | }
312 |
313 | public void OnViewEnd( ElementId elementId )
314 | {
315 | Debug.Print( "ViewEnd" );
316 | }
317 |
318 | public bool Start()
319 | {
320 | Debug.Print( "Start" );
321 | return true;
322 | }
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/NormalLookupXyz.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Autodesk.Revit.DB;
4 |
5 | namespace CustomExporterAdnMeshJson
6 | {
7 | ///
8 | /// A facet normal vector lookup class to avoid
9 | /// duplicate normal vector definitions.
10 | ///
11 | public class NormalLookupXyz : Dictionary
12 | {
13 | #region XyzVectorEqualityComparer
14 | ///
15 | /// Define equality for Revit XYZ vectors.
16 | ///
17 | class XyzVectorEqualityComparer : IEqualityComparer
18 | {
19 | const double _eps = 1.0e-9;
20 |
21 | public bool Equals( XYZ v, XYZ w )
22 | {
23 | return v.IsAlmostEqualTo( w,
24 | _eps );
25 | }
26 |
27 | public int GetHashCode( XYZ v )
28 | {
29 | return Util.PointString( v ).GetHashCode();
30 | }
31 | }
32 | #endregion // XyzVectorEqualityComparer
33 |
34 | public NormalLookupXyz()
35 | : base( new XyzVectorEqualityComparer() )
36 | {
37 | }
38 |
39 | ///
40 | /// Return the index of the given normal vector,
41 | /// adding a new entry if required.
42 | ///
43 | public int AddNormal( XYZ v )
44 | {
45 | return ContainsKey( v )
46 | ? this[v]
47 | : this[v] = Count;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/PointInt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Autodesk.Revit.DB;
3 |
4 | namespace CustomExporterAdnMeshJson
5 | {
6 | ///
7 | /// An integer-based 3D point class.
8 | ///
9 | class PointInt : IComparable
10 | {
11 | public int X { get; set; }
12 | public int Y { get; set; }
13 | public int Z { get; set; }
14 |
15 | //public PointInt( int x, int y, int z )
16 | //{
17 | // X = x;
18 | // Y = y;
19 | // Z = z;
20 | //}
21 |
22 | const double _feet_to_mm = 25.4 * 12;
23 |
24 | static int ConvertFeetToMillimetres( double d )
25 | {
26 | return (int) ( _feet_to_mm * d + 0.5 );
27 | }
28 |
29 | ///
30 | /// Create an integer-based point in millimetres
31 | /// from a given point in imperial coordinates.
32 | ///
33 | public PointInt( XYZ p )
34 | {
35 | X = ConvertFeetToMillimetres( p.X );
36 | Y = ConvertFeetToMillimetres( p.Y );
37 | Z = ConvertFeetToMillimetres( p.Z );
38 | }
39 |
40 | public int CompareTo( PointInt a )
41 | {
42 | int d = X - a.X;
43 |
44 | if( 0 == d )
45 | {
46 | d = Y - a.Y;
47 |
48 | if( 0 == d )
49 | {
50 | d = Z - a.Z;
51 | }
52 | }
53 | return d;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeremytammik/CustomExporterAdnMeshJson/23a95aad8f4a3cca85a72b32e2b699bde1d46bcb/CustomExporterAdnMeshJson/Properties/AssemblyInfo.cs
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/Util.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Autodesk.Revit.DB;
3 |
4 | namespace CustomExporterAdnMeshJson
5 | {
6 | ///
7 | /// Utility methods.
8 | ///
9 | class Util
10 | {
11 | ///
12 | /// Return a string for a real number
13 | /// formatted to two decimal places.
14 | ///
15 | public static string RealString( double a )
16 | {
17 | return a.ToString( "0.##" );
18 | }
19 |
20 | ///
21 | /// Return a string for an XYZ point
22 | /// or vector with its coordinates
23 | /// formatted to two decimal places.
24 | ///
25 | public static string PointString( XYZ p )
26 | {
27 | return string.Format( "({0},{1},{2})",
28 | RealString( p.X ),
29 | RealString( p.Y ),
30 | RealString( p.Z ) );
31 | }
32 |
33 | ///
34 | /// Return the signed volume of the paralleliped
35 | /// spanned by the vectors a, b and c. In German,
36 | /// this is also known as Spatprodukt.
37 | ///
38 | public static double SignedParallelipedVolume(
39 | XYZ a,
40 | XYZ b,
41 | XYZ c )
42 | {
43 | return a.CrossProduct( b ).DotProduct( c );
44 | }
45 |
46 | ///
47 | /// Return true if the three vectors a, b and c
48 | /// form a right handed coordinate system, i.e.
49 | /// the signed volume of the paralleliped spanned
50 | /// by them is positive.
51 | ///
52 | public static bool IsRightHanded( XYZ a, XYZ b, XYZ c )
53 | {
54 | return 0 < SignedParallelipedVolume( a, b, c );
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/VertexLookupInt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace CustomExporterAdnMeshJson
7 | {
8 | ///
9 | /// A vertex lookup class to avoid
10 | /// duplicate vertex definitions.
11 | ///
12 | class VertexLookupInt : Dictionary
13 | {
14 | #region PointIntEqualityComparer
15 | ///
16 | /// Define equality for integer-based PointInt.
17 | ///
18 | class PointIntEqualityComparer : IEqualityComparer
19 | {
20 | public bool Equals( PointInt p, PointInt q )
21 | {
22 | return 0 == p.CompareTo( q );
23 | }
24 |
25 | public int GetHashCode( PointInt p )
26 | {
27 | return ( p.X.ToString()
28 | + "," + p.Y.ToString()
29 | + "," + p.Z.ToString() )
30 | .GetHashCode();
31 | }
32 | }
33 | #endregion // PointIntEqualityComparer
34 |
35 | public VertexLookupInt()
36 | : base( new PointIntEqualityComparer() )
37 | {
38 | }
39 |
40 | ///
41 | /// Return the index of the given vertex,
42 | /// adding a new entry if required.
43 | ///
44 | public int AddVertex( PointInt p )
45 | {
46 | return ContainsKey( p )
47 | ? this[p]
48 | : this[p] = Count;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/CustomExporterAdnMeshJson/x.cs:
--------------------------------------------------------------------------------
1 | #region Assembly RevitAPI.dll, v4.0.30319
2 | // C:\Program Files\Autodesk\Revit 2014\RevitAPI.dll
3 | #endregion
4 |
5 | using System;
6 |
7 | namespace Autodesk.Revit.DB
8 | {
9 | // Summary:
10 | // An interface that is used in custom export to process a Revit model. An
11 | // instance of this class is passed in as a parameter of a CustomExporter.
12 | // The methods herein are then called at times of exporting entities of the
13 | // model.
14 | public interface IExportContext
15 | {
16 | // Summary:
17 | // This method is called at the very end of the export proces, after all entities
18 | // were processed (or after the process was cancelled).
19 | void Finish();
20 | //
21 | // Summary:
22 | // This method is queried at the begining of every element.
23 | //
24 | // Returns:
25 | // Return True if you wish to cancel the exporting process, or False otherwise.
26 | bool IsCanceled();
27 | //
28 | // Summary:
29 | // This method marks the beginning of export of a daylight portal.
30 | //
31 | // Parameters:
32 | // node:
33 | // A node describing the daylight portal object.
34 | void OnDaylightPortal( DaylightPortalNode node );
35 | //
36 | // Summary:
37 | // This method marks the beginning of an element to be exported
38 | //
39 | // Parameters:
40 | // elementId:
41 | // The Id of the element that is about to be processed
42 | //
43 | // Returns:
44 | // Return RenderNodeAction.Skip if you wish to skip exporting this element,
45 | // or return RenderNodeAction.Proceed otherwise.
46 | RenderNodeAction OnElementBegin( ElementId elementId );
47 | //
48 | // Summary:
49 | // This method marks the end of an element being exported
50 | //
51 | // Parameters:
52 | // elementId:
53 | // The Id of the element that has just been processed
54 | void OnElementEnd( ElementId elementId );
55 | //
56 | // Summary:
57 | // This method marks the beginning of a Face to be exported
58 | //
59 | // Parameters:
60 | // node:
61 | // An output node that represents a Face.
62 | //
63 | // Returns:
64 | // Return RenderNodeAction.Proceed if you wish to receive geometry (polymesh)
65 | // for this face, or return RenderNodeAction.Skip otherwise.
66 | //
67 | // Remarks:
68 | // Note that OnFaceBeging (as well as OnFaceEnd) is called only if the custom
69 | // exporter was set up to include faces in the output stream. See CustomExporter.IncudeFaces
70 | // for mode details.
71 | RenderNodeAction OnFaceBegin( FaceNode node );
72 | //
73 | // Summary:
74 | // This method marks the end of the current face being exported.
75 | //
76 | // Parameters:
77 | // node:
78 | // An output node that represents a Face.
79 | void OnFaceEnd( FaceNode node );
80 | //
81 | // Summary:
82 | // This method marks the beginning of a family instance to be exported
83 | //
84 | // Returns:
85 | // Return RenderNodeAction.Skip if you wish to skip processing this family instance,
86 | // or return RenderNodeAction.Proceed otherwise.
87 | RenderNodeAction OnInstanceBegin( InstanceNode node );
88 | //
89 | // Summary:
90 | // This method marks the end of a family instance being exported
91 | //
92 | // Parameters:
93 | // node:
94 | // An output node that represents a family instance.
95 | void OnInstanceEnd( InstanceNode node );
96 | //
97 | // Summary:
98 | // This method marks the beginning of export of a light object.
99 | //
100 | // Parameters:
101 | // node:
102 | // A node describing the light object.
103 | void OnLight( LightNode node );
104 | //
105 | // Summary:
106 | // This method marks the beginning of a link instance to be exported.
107 | //
108 | // Returns:
109 | // Return RenderNodeAction.Skip if you wish to skip processing this link instance,
110 | // or return RenderNodeAction.Proceed otherwise.
111 | RenderNodeAction OnLinkBegin( LinkNode node );
112 | //
113 | // Summary:
114 | // This method marks the end of a link instance being exported.
115 | //
116 | // Parameters:
117 | // node:
118 | // An output node that represents a Revit link.
119 | void OnLinkEnd( LinkNode node );
120 | //
121 | // Summary:
122 | // This method marks a change of the material.
123 | //
124 | // Parameters:
125 | // node:
126 | // A node describing the current material.
127 | void OnMaterial( MaterialNode node );
128 | //
129 | // Summary:
130 | // This method is called when a tessellated polymesh of a 3d face is being output.
131 | //
132 | // Parameters:
133 | // node:
134 | // A node representing topology of the polymesh
135 | void OnPolymesh( PolymeshTopology node );
136 | //
137 | // Summary:
138 | // This method marks the beginning of export of an RPC object.
139 | //
140 | // Parameters:
141 | // node:
142 | // A node with asset information about the RPC object.
143 | void OnRPC( RPCNode node );
144 | //
145 | // Summary:
146 | // This method marks the beginning of a 3D view to be exported
147 | //
148 | // Parameters:
149 | // node:
150 | // Geometry node associated with the view
151 | //
152 | // Returns:
153 | // Return RenderNodeAction.Skip if you wish to skip exporting this view, or
154 | // return RenderNodeAction.Proceed otherwise.
155 | RenderNodeAction OnViewBegin( ViewNode node );
156 | //
157 | // Summary:
158 | // This method marks the end of a 3D view being exported
159 | //
160 | // Parameters:
161 | // elementId:
162 | // The Id of the 3D view that has just been processed
163 | void OnViewEnd( ElementId elementId );
164 | //
165 | // Summary:
166 | // This method is called at the very start of the export proces, still before
167 | // the first entity of the model was send out.
168 | //
169 | // Returns:
170 | // Return True if you are ready to proceed with processing the export.
171 | bool Start();
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Jeremy Tammik
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CustomExporterAdnMeshJson
2 |
3 | C# .NET Revit API add-in geometry CustomExporter to ADN mesh JSON format.
4 |
5 | For more information, please refer to [The Building Coder](http://thebuildingcoder.typepad.com) discussion on
6 | the [ADN Mesh Data Custom Exporter to JSON](http://thebuildingcoder.typepad.com/blog/2013/07/adn-mesh-data-custom-exporter-to-json.html).
7 |
8 |
9 | ## Author
10 |
11 | Jeremy Tammik,
12 | [The Building Coder](http://thebuildingcoder.typepad.com) and
13 | [The 3D Web Coder](http://the3dwebcoder.typepad.com),
14 | [Forge](http://forge.autodesk.com) [Platform](https://developer.autodesk.com) Development,
15 | [ADN](http://www.autodesk.com/adn)
16 | [Open](http://www.autodesk.com/adnopen),
17 | [Autodesk Inc.](http://www.autodesk.com)
18 |
19 |
20 | ## License
21 |
22 | This sample is licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT).
23 | Please see the [LICENSE](LICENSE) file for full details.
24 |
--------------------------------------------------------------------------------