24
24
using BH . Engine . Adapters . Revit ;
25
25
using BH . Engine . Base ;
26
26
using BH . Engine . Geometry ;
27
- using BH . Engine . Graphics ;
28
27
using BH . oM . Adapter ;
29
28
using BH . oM . Adapters . Revit ;
30
29
using BH . oM . Adapters . Revit . Enums ;
@@ -87,7 +86,8 @@ protected override IEnumerable<IBHoMObject> Read(IRequest request, ActionConfig
87
86
}
88
87
}
89
88
90
- Dictionary < Document , IRequest > requestsByLinks = request . SplitRequestTreeByLinks ( this . Document ) ;
89
+ // Split the request into separate requests per each link model
90
+ Dictionary < ElementId , IRequest > requestsByLinks = request . SplitRequestTreeByLinks ( this . Document ) ;
91
91
if ( requestsByLinks == null )
92
92
{
93
93
BH . Engine . Base . Compute . RecordError ( $ "Pull failed due to issues with the request containing { nameof ( FilterByLink ) } . Please try to restructure the used Request and try again.") ;
@@ -96,12 +96,49 @@ protected override IEnumerable<IBHoMObject> Read(IRequest request, ActionConfig
96
96
97
97
RevitSettings settings = RevitSettings . DefaultIfNull ( ) ;
98
98
99
+ // Group links that hold the same document and have same transform
100
+ // Addresses the case when there is a nested link being loaded via more than one parent link
101
+ // Same document linked in multiple locations is being pulled per each location
102
+ // Performance is not affected by multiple converts of same elements thanks to refObjects
103
+ Dictionary < ( Document , Transform ) , List < IRequest > > requestsByDocumentAndTransform = new Dictionary < ( Document , Transform ) , List < IRequest > > ( ) ;
104
+ foreach ( KeyValuePair < ElementId , IRequest > requestByLink in requestsByLinks )
105
+ {
106
+ Document doc ;
107
+ Transform transform = Transform . Identity ;
108
+ if ( requestByLink . Key . IntegerValue == - 1 )
109
+ doc = this . Document ;
110
+ else
111
+ {
112
+ var linkInstance = this . Document . GetElement ( requestByLink . Key ) as RevitLinkInstance ;
113
+ doc = linkInstance . GetLinkDocument ( ) ;
114
+
115
+ Transform linkTransform = linkInstance . GetTotalTransform ( ) ;
116
+ if ( ! linkTransform . IsIdentity )
117
+ transform = linkTransform ;
118
+ }
119
+
120
+ ( Document doc , Transform transform ) tuple ;
121
+ if ( requestsByDocumentAndTransform . Keys . All ( x => x . Item1 . Title != doc . Title || ! x . Item2 . AlmostEqual ( transform ) ) )
122
+ {
123
+ tuple = ( doc , transform ) ;
124
+ requestsByDocumentAndTransform . Add ( tuple , new List < IRequest > ( ) ) ;
125
+ }
126
+ else
127
+ tuple = requestsByDocumentAndTransform . Keys . First ( x => x . Item1 . Title == doc . Title && x . Item2 . AlmostEqual ( transform ) ) ;
128
+
129
+ requestsByDocumentAndTransform [ tuple ] . Add ( requestByLink . Value ) ;
130
+ }
131
+
132
+ // Global refObjects help sharing the refObjects when pulling from same document linked in a few different locations (e.g. copy-pasted link)
133
+ // Thanks to sharing refObjects, an element is processed only once even if FromRevit is called against it multiple times
134
+ Dictionary < string , Dictionary < string , List < IBHoMObject > > > globalRefObjects = new Dictionary < string , Dictionary < string , List < IBHoMObject > > > ( ) ;
99
135
List < IBHoMObject > result = new List < IBHoMObject > ( ) ;
100
- foreach ( KeyValuePair < Document , IRequest > requestByLink in requestsByLinks )
136
+ foreach ( var kvp in requestsByDocumentAndTransform )
101
137
{
102
- result . AddRange ( Read ( requestByLink . Key , requestByLink . Value , pullConfig , settings ) ) ;
138
+ result . AddRange ( Read ( kvp . Key . Item1 , kvp . Key . Item2 , kvp . Value , pullConfig , settings , globalRefObjects ) ) ;
103
139
}
104
140
141
+ // Restore selection
105
142
this . UIDocument . Selection . SetElementIds ( selected ) ;
106
143
107
144
return result ;
@@ -112,31 +149,26 @@ protected override IEnumerable<IBHoMObject> Read(IRequest request, ActionConfig
112
149
/**** Public Methods ****/
113
150
/***************************************************/
114
151
115
- public static List < IBHoMObject > Read ( Document document , IRequest request , RevitPullConfig pullConfig = null , RevitSettings settings = null )
152
+ public static List < IBHoMObject > Read ( Document document , Transform transform , List < IRequest > requests , RevitPullConfig pullConfig = null , RevitSettings settings = null , Dictionary < string , Dictionary < string , List < IBHoMObject > > > globalRefObjects = null )
116
153
{
117
154
if ( document == null )
118
155
{
119
156
BH . Engine . Base . Compute . RecordError ( "BHoM objects could not be read because provided Revit document is null." ) ;
120
157
return new List < IBHoMObject > ( ) ;
121
158
}
122
159
123
- if ( request == null )
124
- {
125
- BH . Engine . Base . Compute . RecordError ( "BHoM objects could not be read because provided IRequest is null." ) ;
126
- return new List < IBHoMObject > ( ) ;
127
- }
128
-
129
160
pullConfig = pullConfig . DefaultIfNull ( ) ;
130
161
settings = settings . DefaultIfNull ( ) ;
131
162
163
+ // Prefilter only elements from open worksets if requested
132
164
IEnumerable < ElementId > worksetPrefilter = null ;
133
165
if ( ! pullConfig . IncludeClosedWorksets )
134
166
worksetPrefilter = document . OpenWorksetsPrefilter ( ) ;
135
167
136
- List < ElementId > elementIds = request . IElementIds ( document , pullConfig . Discipline , settings , worksetPrefilter ) . RemoveGridSegmentIds ( document ) ? . ToList ( ) ;
137
- if ( elementIds == null )
138
- return new List < IBHoMObject > ( ) ;
168
+ // Get elementIds from all requests
169
+ List < ElementId > elementIds = new LogicalOrRequest { Requests = requests } . ElementIds ( document , pullConfig . Discipline , settings , worksetPrefilter ) . RemoveGridSegmentIds ( document ) . ToList ( ) ;
139
170
171
+ // Get elementIds of nested elements if requested
140
172
if ( pullConfig . IncludeNestedElements )
141
173
{
142
174
List < ElementId > elemIds = new List < ElementId > ( ) ;
@@ -153,12 +185,12 @@ public static List<IBHoMObject> Read(Document document, IRequest request, RevitP
153
185
elementIds . AddRange ( elemIds ) ;
154
186
}
155
187
156
- return Read ( document , elementIds , pullConfig , settings ) ;
188
+ return Read ( document , transform , elementIds . ToList ( ) , pullConfig , settings , globalRefObjects ) ;
157
189
}
158
190
159
191
/***************************************************/
160
192
161
- public static List < IBHoMObject > Read ( Document document , List < ElementId > elementIds , RevitPullConfig pullConfig = null , RevitSettings settings = null )
193
+ public static List < IBHoMObject > Read ( Document document , Transform transform , List < ElementId > elementIds , RevitPullConfig pullConfig = null , RevitSettings settings = null , Dictionary < string , Dictionary < string , List < IBHoMObject > > > globalRefObjects = null )
162
194
{
163
195
if ( document == null )
164
196
{
@@ -175,129 +207,128 @@ public static List<IBHoMObject> Read(Document document, List<ElementId> elementI
175
207
pullConfig = pullConfig . DefaultIfNull ( ) ;
176
208
settings = settings . DefaultIfNull ( ) ;
177
209
178
- PullGeometryConfig geometryConfig = pullConfig . GeometryConfig ;
179
- if ( geometryConfig == null )
180
- geometryConfig = new PullGeometryConfig ( ) ;
181
-
182
- PullRepresentationConfig representationConfig = pullConfig . RepresentationConfig ;
183
- if ( representationConfig == null )
184
- representationConfig = new PullRepresentationConfig ( ) ;
185
-
186
210
Discipline discipline = pullConfig . Discipline ;
187
211
if ( discipline == Discipline . Undefined )
188
212
{
189
213
BH . Engine . Base . Compute . RecordNote ( $ "Conversion discipline has not been specified, default { Discipline . Physical } will be used.") ;
190
214
discipline = Discipline . Physical ;
191
215
}
192
216
193
- Options geometryOptions = BH . Revit . Engine . Core . Create . Options ( ViewDetailLevel . Fine , geometryConfig . IncludeNonVisible , false ) ;
194
- Options meshOptions = BH . Revit . Engine . Core . Create . Options ( geometryConfig . MeshDetailLevel . ViewDetailLevel ( ) , geometryConfig . IncludeNonVisible , false ) ;
195
- Options renderMeshOptions = BH . Revit . Engine . Core . Create . Options ( representationConfig . DetailLevel . ViewDetailLevel ( ) , representationConfig . IncludeNonVisible , false ) ;
217
+ // Set up refObjects
218
+ if ( globalRefObjects == null )
219
+ globalRefObjects = new Dictionary < string , Dictionary < string , List < IBHoMObject > > > ( ) ;
220
+
221
+ if ( ! globalRefObjects . ContainsKey ( document . Title ) )
222
+ globalRefObjects . Add ( document . Title , new Dictionary < string , List < IBHoMObject > > ( ) ) ;
223
+
224
+ Dictionary < string , List < IBHoMObject > > refObjects = globalRefObjects [ document . Title ] ;
196
225
197
- Transform linkTransform = null ;
198
- TransformMatrix bHoMTransform = null ;
199
- if ( document . IsLinked )
226
+ // Get the elements already processed for a given document
227
+ // Only relevant in case of same document linked in multiple locations
228
+ // Helps avoid getting same element processed multiple times
229
+ List < IBHoMObject > result = new List < IBHoMObject > ( ) ;
230
+ List < ElementId > remainingElementIds = new List < ElementId > ( ) ;
231
+ foreach ( ElementId id in elementIds )
200
232
{
201
- linkTransform = document . LinkTransform ( ) ;
202
- if ( linkTransform ? . IsIdentity == false )
203
- bHoMTransform = linkTransform . FromRevit ( ) ;
233
+ var existing = refObjects . GetValues < IBHoMObject > ( id ) ;
234
+ if ( existing != null )
235
+ result . AddRange ( existing ) ;
236
+ else
237
+ remainingElementIds . Add ( id ) ;
204
238
}
205
239
206
- Dictionary < string , List < IBHoMObject > > refObjects = new Dictionary < string , List < IBHoMObject > > ( ) ;
207
-
208
240
// Extract panel geometry of walls, floors, slabs and roofs prior to running the converts (this is an optimisation aimed to reduce the number of view regenerations)
209
241
if ( ! document . IsLinked )
210
- document . CachePanelGeometry ( elementIds , discipline , settings , refObjects ) ;
211
-
212
- List < IBHoMObject > result = new List < IBHoMObject > ( ) ;
213
- foreach ( ElementId id in elementIds )
242
+ document . CachePanelGeometry ( remainingElementIds , discipline , settings , refObjects ) ;
243
+
244
+ // Set up all geometry/representation configs
245
+ PullGeometryConfig geometryConfig = pullConfig . GeometryConfig ;
246
+ if ( geometryConfig == null )
247
+ geometryConfig = new PullGeometryConfig ( ) ;
248
+
249
+ PullRepresentationConfig representationConfig = pullConfig . RepresentationConfig ;
250
+ if ( representationConfig == null )
251
+ representationConfig = new PullRepresentationConfig ( ) ;
252
+
253
+ Options geometryOptions = BH . Revit . Engine . Core . Create . Options ( ViewDetailLevel . Fine , geometryConfig . IncludeNonVisible , false ) ;
254
+ Options meshOptions = BH . Revit . Engine . Core . Create . Options ( geometryConfig . MeshDetailLevel . ViewDetailLevel ( ) , geometryConfig . IncludeNonVisible , false ) ;
255
+ Options renderMeshOptions = BH . Revit . Engine . Core . Create . Options ( representationConfig . DetailLevel . ViewDetailLevel ( ) , representationConfig . IncludeNonVisible , false ) ;
256
+
257
+ // Convert each element in coordinate system of the document that owns it
258
+ // Transformation from that document's coordinate system to the coordinate system of host document done further downstream
259
+ foreach ( ElementId id in remainingElementIds )
214
260
{
215
261
Element element = document . GetElement ( id ) ;
216
262
if ( element == null )
217
263
continue ;
218
264
219
- IEnumerable < IBHoMObject > iBHoMObjects = Read ( element , discipline , linkTransform , settings , refObjects ) ;
220
-
221
- if ( iBHoMObjects != null && iBHoMObjects . Any ( ) )
265
+ IEnumerable < IBHoMObject > converted = Read ( element , discipline , settings , refObjects ) ;
266
+ if ( converted != null )
222
267
{
223
268
if ( pullConfig . PullMaterialTakeOff )
224
269
{
225
- foreach ( IBHoMObject iBHoMObject in iBHoMObjects )
270
+ foreach ( IBHoMObject obj in converted )
226
271
{
227
272
oM . Physical . Materials . VolumetricMaterialTakeoff takeoff = element . VolumetricMaterialTakeoff ( settings , refObjects ) ;
228
273
if ( takeoff != null )
229
- iBHoMObject . Fragments . AddOrReplace ( takeoff ) ;
274
+ obj . Fragments . AddOrReplace ( takeoff ) ;
230
275
}
231
276
}
232
277
233
278
List < ICurve > edges = null ;
234
279
if ( geometryConfig . PullEdges )
235
- {
236
280
edges = element . Curves ( geometryOptions , settings , true ) . FromRevit ( ) ;
237
- if ( bHoMTransform != null )
238
- edges = edges . Select ( x => x ? . ITransform ( bHoMTransform ) ) . ToList ( ) ;
239
- }
240
281
241
282
List < ISurface > surfaces = null ;
242
283
if ( geometryConfig . PullSurfaces )
243
- {
244
284
surfaces = element . Faces ( geometryOptions , settings ) . Select ( x => x . IFromRevit ( ) ) . ToList ( ) ;
245
- if ( bHoMTransform != null )
246
- surfaces = surfaces . Select ( x => x ? . ITransform ( bHoMTransform ) ) . ToList ( ) ;
247
- }
248
285
249
286
List < oM . Geometry . Mesh > meshes = null ;
250
287
if ( geometryConfig . PullMeshes )
251
- {
252
288
meshes = element . MeshedGeometry ( meshOptions , settings ) ;
253
- if ( bHoMTransform != null )
254
- meshes = meshes . Select ( x => x ? . Transform ( bHoMTransform ) ) . ToList ( ) ;
255
- }
256
289
257
290
if ( geometryConfig . PullEdges || geometryConfig . PullSurfaces || geometryConfig . PullMeshes )
258
291
{
259
292
RevitGeometry geometry = new RevitGeometry ( edges , surfaces , meshes ) ;
260
- foreach ( IBHoMObject iBHoMObject in iBHoMObjects )
293
+ foreach ( IBHoMObject obj in converted )
261
294
{
262
- iBHoMObject . Fragments . AddOrReplace ( geometry ) ;
295
+ obj . Fragments . AddOrReplace ( geometry ) ;
263
296
}
264
297
}
265
298
266
299
if ( representationConfig . PullRenderMesh )
267
300
{
268
301
List < RenderMesh > renderMeshes = element . RenderMeshes ( renderMeshOptions , settings ) ;
269
- if ( bHoMTransform != null )
270
- renderMeshes = renderMeshes . Select ( x => x ? . Transform ( bHoMTransform ) ) . ToList ( ) ;
271
-
272
302
RevitRepresentation representation = new RevitRepresentation ( renderMeshes ) ;
273
- foreach ( IBHoMObject iBHoMObject in iBHoMObjects )
303
+ foreach ( IBHoMObject obj in converted )
274
304
{
275
- iBHoMObject . Fragments . AddOrReplace ( representation ) ;
305
+ obj . Fragments . AddOrReplace ( representation ) ;
276
306
}
277
307
}
278
308
279
- result . AddRange ( iBHoMObjects ) ;
309
+ result . AddRange ( converted ) ;
280
310
}
281
311
}
282
312
283
313
bool [ ] activePulls = new bool [ ] { geometryConfig . PullEdges , geometryConfig . PullSurfaces , geometryConfig . PullMeshes , representationConfig . PullRenderMesh } ;
284
314
if ( activePulls . Count ( x => x ) > 1 )
285
315
BH . Engine . Base . Compute . RecordWarning ( "Pull of more than one geometry/representation type has been specified in RevitPullConfig. Please consider this can be time consuming due to the amount of conversions." ) ;
286
316
287
- return result ;
317
+ // Postprocess clones the output and transforms it to the coordinate system of the host model
318
+ return result . Select ( x => x . IPostprocess ( transform , settings ) ) . Where ( x => x != null ) . ToList ( ) ;
288
319
}
289
320
290
321
/***************************************************/
291
322
292
- public static List < IBHoMObject > Read ( Element element , Discipline discipline , Transform transform , RevitSettings settings = null , Dictionary < string , List < IBHoMObject > > refObjects = null )
323
+ public static List < IBHoMObject > Read ( Element element , Discipline discipline , RevitSettings settings = null , Dictionary < string , List < IBHoMObject > > refObjects = null )
293
324
{
294
325
if ( element == null || ! element . IsValidObject )
295
326
return new List < IBHoMObject > ( ) ;
296
327
297
328
List < IBHoMObject > result = null ;
298
329
try
299
330
{
300
- result = element . IFromRevit ( discipline , transform , settings , refObjects ) ;
331
+ result = element . IFromRevit ( discipline , settings , refObjects ) ;
301
332
}
302
333
catch ( Exception exception )
303
334
{
@@ -323,6 +354,3 @@ public static List<IBHoMObject> Read(Element element, Discipline discipline, Tra
323
354
/***************************************************/
324
355
}
325
356
}
326
-
327
-
328
-
0 commit comments