@@ -307,7 +307,16 @@ public void OnIFCExport(object sender, CommandEventArgs args)
307
307
if ( selectedConfig . ExportLinkedFiles == true )
308
308
{
309
309
exportOptions . AddOption ( "ExportingLinks" , true . ToString ( ) ) ;
310
- ExportLinkedDocuments ( document , fullName , linksGUIDsCache , exportOptions ) ;
310
+ try
311
+ {
312
+ // Newer version of export linked documents
313
+ ExportLinkedDocuments ( document , fullName , linksGUIDsCache , exportOptions ) ;
314
+ }
315
+ catch
316
+ {
317
+ // Older version which uses copy of linked file, doesn't work for cloud documents
318
+ ExportLinkedDocumentsOldVersion ( document , fullName , linksGUIDsCache , exportOptions ) ;
319
+ }
311
320
exportOptions . AddOption ( "ExportingLinks" , false . ToString ( ) ) ;
312
321
}
313
322
}
@@ -396,6 +405,20 @@ private void AddExpandedElementIdContent(ref string messageString, string format
396
405
messageString += string . Format ( formatString , ElementIdListToString ( items ) ) ;
397
406
}
398
407
408
+ private string GetLinkFileName ( Document linkDocument , string linkPathName )
409
+ {
410
+ int index = linkPathName . LastIndexOf ( "\\ " ) ;
411
+ if ( index <= 0 )
412
+ return linkDocument . Title ;
413
+
414
+ string linkFileName = linkPathName . Substring ( index + 1 ) ;
415
+ // remove the extension
416
+ index = linkFileName . LastIndexOf ( '.' ) ;
417
+ if ( index > 0 )
418
+ linkFileName = linkFileName . Substring ( 0 , index ) ;
419
+ return linkFileName ;
420
+ }
421
+
399
422
public void ExportLinkedDocuments ( Autodesk . Revit . DB . Document document , string fileName , Dictionary < ElementId , string > linksGUIDsCache , IFCExportOptions exportOptions )
400
423
{
401
424
// get the extension
@@ -440,17 +463,254 @@ public void ExportLinkedDocuments(Autodesk.Revit.DB.Document document, string fi
440
463
linkPathName = linkDocument . PathName ;
441
464
442
465
// get the link file name
443
- String linkFileName = "" ;
444
- index = linkPathName . LastIndexOf ( "\\ " ) ;
445
- if ( index > 0 )
446
- linkFileName = linkPathName . Substring ( index + 1 ) ;
466
+ string linkFileName = GetLinkFileName ( linkDocument , linkPathName ) ;
467
+
468
+ // add to names count dictionary
469
+ if ( ! rvtLinkNamesDict . Keys . Contains ( linkFileName ) )
470
+ rvtLinkNamesDict . Add ( linkFileName , 0 ) ;
471
+ rvtLinkNamesDict [ linkFileName ] ++ ;
472
+
473
+ // add to names instances dictionary
474
+ if ( ! rvtLinkNamesToInstancesDict . Keys . Contains ( linkPathName ) )
475
+ rvtLinkNamesToInstancesDict . Add ( linkPathName , new List < RevitLinkInstance > ( ) ) ;
476
+ rvtLinkNamesToInstancesDict [ linkPathName ] . Add ( rvtLinkInstance ) ;
477
+ }
478
+ }
479
+ catch
480
+ {
481
+ }
482
+
483
+ // get the link instances
484
+ // We will keep track of the instances we can't export.
485
+ // Reasons we can't export:
486
+ // 1. The path for the linked instance doesn't exist.
487
+ // 2. Couldn't create a temporary document for exporting the linked instance.
488
+ // 3. The document for the linked instance can't be found.
489
+ // 4. The linked instance is mirrored, non-conformal, or scaled.
490
+ IList < string > pathDoesntExist = new List < string > ( ) ;
491
+ IList < string > noTempDoc = new List < string > ( ) ;
492
+ IList < ElementId > cantFindDoc = new List < ElementId > ( ) ;
493
+ IList < ElementId > nonConformalInst = new List < ElementId > ( ) ;
494
+ IList < ElementId > scaledInst = new List < ElementId > ( ) ;
495
+ IList < ElementId > instHasReflection = new List < ElementId > ( ) ;
496
+
497
+ foreach ( KeyValuePair < string , List < RevitLinkInstance > > linkPathNames in rvtLinkNamesToInstancesDict )
498
+ {
499
+ string linkPathName = linkPathNames . Key ;
500
+
501
+ // get the link instances
502
+ List < RevitLinkInstance > currRvtLinkInstances = rvtLinkNamesToInstancesDict [ linkPathName ] ;
503
+ IList < string > serTransforms = new List < string > ( ) ;
504
+ IList < string > linkFileNames = new List < string > ( ) ;
505
+
506
+ Document linkDocument = null ;
507
+ double lengthScaleFactorLink = 1.0 ;
508
+
509
+ foreach ( RevitLinkInstance currRvtLinkInstance in currRvtLinkInstances )
510
+ {
511
+ // Nothing to report if the element itself is null.
512
+ if ( currRvtLinkInstance == null )
513
+ continue ;
514
+
515
+ // get the link document and the unit scale
516
+ if ( linkDocument == null )
517
+ {
518
+ linkDocument = currRvtLinkInstance . GetLinkDocument ( ) ;
519
+
520
+ lengthScaleFactorLink = UnitUtils . ConvertFromInternalUnits (
521
+ 1.0 ,
522
+ linkDocument . GetUnits ( ) . GetFormatOptions ( SpecTypeId . Length ) . GetUnitTypeId ( ) ) ;
523
+ }
524
+
525
+ if ( linkDocument == null )
526
+ {
527
+ cantFindDoc . Add ( currRvtLinkInstance . Id ) ;
528
+ continue ;
529
+ }
530
+
531
+ // get the link transform
532
+ Transform tr = currRvtLinkInstance . GetTransform ( ) ;
533
+
534
+ // We can't handle non-conformal, scaled, or mirrored transforms.
535
+ if ( ! tr . IsConformal )
536
+ {
537
+ nonConformalInst . Add ( currRvtLinkInstance . Id ) ;
538
+ continue ;
539
+ }
540
+
541
+ if ( tr . HasReflection )
542
+ {
543
+ instHasReflection . Add ( currRvtLinkInstance . Id ) ;
544
+ continue ;
545
+ }
546
+
547
+ if ( ! MathUtil . IsAlmostEqual ( tr . Determinant , 1.0 ) )
548
+ {
549
+ scaledInst . Add ( currRvtLinkInstance . Id ) ;
550
+ continue ;
551
+ }
552
+
553
+ // get the link file path and name
554
+ String linkFileName = GetLinkFileName ( linkDocument , linkPathName ) ;
555
+
556
+ //if link was an IFC file then make a different formating to the file name
557
+ if ( ( linkPathName . Length >= 4 && linkPathName . Substring ( linkPathName . Length - 4 ) . ToLower ( ) == ".ifc" ) ||
558
+ ( linkPathName . Length >= 7 && linkPathName . Substring ( linkPathName . Length - 7 ) . ToLower ( ) == ".ifcxml" ) ||
559
+ ( linkPathName . Length >= 7 && linkPathName . Substring ( linkPathName . Length - 7 ) . ToLower ( ) == ".ifczip" ) )
560
+ {
561
+ String fName = fileName ;
562
+
563
+ //get output path and add to the new file name
564
+ index = fName . LastIndexOf ( "\\ " ) ;
565
+ if ( index > 0 )
566
+ fName = fName . Substring ( 0 , index + 1 ) ;
567
+ else
568
+ fName = "" ;
569
+
570
+ //construct IFC file name
571
+ linkFileName = fName + linkFileName + "-" ;
572
+
573
+ //add guid
574
+ linkFileName += linksGUIDsCache [ currRvtLinkInstance . Id ] ;
575
+ }
447
576
else
448
- linkFileName = linkDocument . Title ;
577
+ {
578
+ // check if there are multiple instances with the same name
579
+ bool bMultiple = ( rvtLinkNamesDict [ linkFileName ] > 1 ) ;
449
580
450
- // remove the extension
451
- index = linkFileName . LastIndexOf ( '.' ) ;
452
- if ( index > 0 )
453
- linkFileName = linkFileName . Substring ( 0 , index ) ;
581
+ // add the path
582
+ linkFileName = fileName + "-" + linkFileName ;
583
+
584
+ // add the guid
585
+ if ( bMultiple )
586
+ {
587
+ linkFileName += "-" ;
588
+ linkFileName += linksGUIDsCache [ currRvtLinkInstance . Id ] ;
589
+ }
590
+ }
591
+
592
+ // add the extension
593
+ linkFileName += sExtension ;
594
+
595
+ linkFileNames . Add ( linkFileName ) ;
596
+
597
+ // scale the transform origin
598
+ tr . Origin *= lengthScaleFactorLink ;
599
+
600
+ // serialize transform
601
+ serTransforms . Add ( SerializeTransform ( tr ) ) ;
602
+ }
603
+
604
+ // IFC export requires an open transaction, although no changes should be made
605
+ if ( linkDocument != null )
606
+ {
607
+ Transaction transaction = new Transaction ( linkDocument , "Export IFC Link" ) ;
608
+ transaction . Start ( ) ;
609
+ FailureHandlingOptions failureOptions = transaction . GetFailureHandlingOptions ( ) ;
610
+ failureOptions . SetClearAfterRollback ( false ) ;
611
+ transaction . SetFailureHandlingOptions ( failureOptions ) ;
612
+
613
+ // export
614
+ try
615
+ {
616
+ int numLinkInstancesToExport = linkFileNames . Count ;
617
+ exportOptions . AddOption ( "NumberOfExportedLinkInstances" , numLinkInstancesToExport . ToString ( ) ) ;
618
+
619
+ for ( int ind = 0 ; ind < numLinkInstancesToExport ; ind ++ )
620
+ {
621
+ string optionName = ( ind == 0 ) ? "ExportLinkInstanceTransform" : "ExportLinkInstanceTransform" + ( ind + 1 ) . ToString ( ) ;
622
+ exportOptions . AddOption ( optionName , serTransforms [ ind ] ) ;
623
+
624
+ // Don't pass in file name for the first link instance.
625
+ if ( ind == 0 )
626
+ continue ;
627
+ optionName = "ExportLinkInstanceFileName" + ( ind + 1 ) . ToString ( ) ;
628
+ exportOptions . AddOption ( optionName , linkFileNames [ ind ] ) ;
629
+ }
630
+ // Pass in the first value; the rest will be in the options.
631
+ String path_ = Path . GetDirectoryName ( linkFileNames [ 0 ] ) ;
632
+ String fileName_ = Path . GetFileName ( linkFileNames [ 0 ] ) ;
633
+ bool result = linkDocument . Export ( path_ , fileName_ , exportOptions ) ; // pass in the options here
634
+ }
635
+ catch
636
+ {
637
+ }
638
+
639
+ // rollback the transaction
640
+ transaction . RollBack ( ) ;
641
+ }
642
+
643
+ // Show user errors, if any.
644
+ int numBadInstances = pathDoesntExist . Count + noTempDoc . Count + cantFindDoc . Count + nonConformalInst . Count
645
+ + scaledInst . Count + instHasReflection . Count ;
646
+ if ( numBadInstances > 0 )
647
+ {
648
+ using ( TaskDialog taskDialog = new TaskDialog ( Properties . Resources . IFCExport ) )
649
+ {
650
+ taskDialog . MainInstruction = string . Format ( Properties . Resources . LinkInstanceExportErrorMain , numBadInstances ) ;
651
+ taskDialog . MainIcon = TaskDialogIcon . TaskDialogIconWarning ;
652
+ taskDialog . TitleAutoPrefix = false ;
653
+
654
+ string expandedContent = "" ;
655
+ AddExpandedStringContent ( ref expandedContent , Properties . Resources . LinkInstanceExportErrorPath , pathDoesntExist ) ;
656
+ AddExpandedStringContent ( ref expandedContent , Properties . Resources . LinkInstanceExportCantCreateDoc , noTempDoc ) ;
657
+ AddExpandedElementIdContent ( ref expandedContent , Properties . Resources . LinkInstanceExportCantFindDoc , cantFindDoc ) ;
658
+ AddExpandedElementIdContent ( ref expandedContent , Properties . Resources . LinkInstanceExportNonConformal , nonConformalInst ) ;
659
+ AddExpandedElementIdContent ( ref expandedContent , Properties . Resources . LinkInstanceExportScaled , scaledInst ) ;
660
+ AddExpandedElementIdContent ( ref expandedContent , Properties . Resources . LinkInstanceExportHasReflection , instHasReflection ) ;
661
+
662
+ taskDialog . ExpandedContent = expandedContent ;
663
+ TaskDialogResult result = taskDialog . Show ( ) ;
664
+ }
665
+ }
666
+ }
667
+ }
668
+
669
+ public void ExportLinkedDocumentsOldVersion ( Autodesk . Revit . DB . Document document , string fileName , Dictionary < ElementId , string > linksGUIDsCache , IFCExportOptions exportOptions )
670
+ {
671
+ // get the extension
672
+ int index = fileName . LastIndexOf ( '.' ) ;
673
+ if ( index <= 0 )
674
+ return ;
675
+ string sExtension = fileName . Substring ( index ) ;
676
+ fileName = fileName . Substring ( 0 , index ) ;
677
+
678
+ // get all the revit link instances
679
+ FilteredElementCollector collector = new FilteredElementCollector ( document ) ;
680
+ ElementFilter elementFilter = new ElementClassFilter ( typeof ( RevitLinkInstance ) ) ;
681
+ List < RevitLinkInstance > rvtLinkInstances = collector . WherePasses ( elementFilter ) . Cast < RevitLinkInstance > ( ) . ToList ( ) ;
682
+
683
+ IDictionary < String , int > rvtLinkNamesDict = new Dictionary < String , int > ( ) ;
684
+ IDictionary < String , List < RevitLinkInstance > > rvtLinkNamesToInstancesDict = new Dictionary < String , List < RevitLinkInstance > > ( ) ;
685
+
686
+ try
687
+ {
688
+ // get the link types
689
+ foreach ( RevitLinkInstance rvtLinkInstance in rvtLinkInstances )
690
+ {
691
+ // get the instance
692
+ if ( rvtLinkInstance == null )
693
+ continue ;
694
+
695
+ // check the cache
696
+ if ( linksGUIDsCache . Keys . Contains ( rvtLinkInstance . Id ) == false )
697
+ continue ;
698
+
699
+ // get the link document
700
+ Document linkDocument = rvtLinkInstance . GetLinkDocument ( ) ;
701
+ if ( linkDocument == null )
702
+ continue ;
703
+
704
+ // get the link file path and name
705
+ String linkPathName = "" ;
706
+ Parameter originalFileNameParam = linkDocument . ProjectInformation . LookupParameter ( "Original IFC File Name" ) ;
707
+ if ( originalFileNameParam != null && originalFileNameParam . StorageType == StorageType . String )
708
+ linkPathName = originalFileNameParam . AsString ( ) ;
709
+ else
710
+ linkPathName = linkDocument . PathName ;
711
+
712
+ // get the link file name
713
+ string linkFileName = GetLinkFileName ( linkDocument , linkPathName ) ;
454
714
455
715
// add to names count dictionary
456
716
if ( ! rvtLinkNamesDict . Keys . Contains ( linkFileName ) )
0 commit comments