diff --git a/Install/Program Files to Install/Autodesk.SteelConnections.ASIFC.dll b/Install/Program Files to Install/Autodesk.SteelConnections.ASIFC.dll
index f19e8b75..2208cd4e 100644
Binary files a/Install/Program Files to Install/Autodesk.SteelConnections.ASIFC.dll and b/Install/Program Files to Install/Autodesk.SteelConnections.ASIFC.dll differ
diff --git a/Install/Program Files to Install/DefaultUserDefinedParameterSets.txt b/Install/Program Files to Install/DefaultUserDefinedParameterSets.txt
index bb46a284..c5a487c2 100644
--- a/Install/Program Files to Install/DefaultUserDefinedParameterSets.txt
+++ b/Install/Program Files to Install/DefaultUserDefinedParameterSets.txt
@@ -14,6 +14,10 @@
# Pressure, Ratio, Real, Text, ThermalTransmittance, ThermodynamicTemperature, Volume,
# VolumetricFlowRate
#
+# Since 24.1.0, type properties are not exported in case they are not specified in the user-defined property sets file.
+# To export type properties for the IFCElement, for example,
+# a user should include "IFCElementType" in the proper .txt file.
+#
# Example property set definition for COBie:
#
#PropertySet: COBie_Specification T IfcElementType
diff --git a/Install/Program Files to Install/bundle/Contents/Resources/ADSKIFCExporterHelp.htm b/Install/Program Files to Install/bundle/Contents/Resources/ADSKIFCExporterHelp.htm
index 073841ad..4068aac2 100644
--- a/Install/Program Files to Install/bundle/Contents/Resources/ADSKIFCExporterHelp.htm
+++ b/Install/Program Files to Install/bundle/Contents/Resources/ADSKIFCExporterHelp.htm
@@ -236,6 +236,34 @@
Support Information
or if you have an inquiry specific to this add-in, send us an e-mail to: Revit.apps@autodesk.com
Version History
+
24.1.1.6
+
+ General:
+
+
This is the minor update of IFC Exporter for Revit 2024.
+
It contains a various improvements and bug fixes for the basic Revit 2024.
+
+
+
+
+ Bug Fixes:
+
+
The default import processor has been changed to Hybrid
+
+
+
+
+ Bug Fixes:
+
+
Fixed a bunch of potential bugs related to the compatibility with older Revit versions.
+
Fix sketch-based openings in sloped slabs.
+
Fixed placement of some specific wall sweep elements.
+
+
+
+
+
+
24.1.0.22
General:
diff --git a/Install/Program Files to Install/bundle/PackageContents.xml b/Install/Program Files to Install/bundle/PackageContents.xml
index c50f769c..6b607fd1 100644
--- a/Install/Program Files to Install/bundle/PackageContents.xml
+++ b/Install/Program Files to Install/bundle/PackageContents.xml
@@ -4,7 +4,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/Install/RevitIFCSetupWix/Product.wxs b/Install/RevitIFCSetupWix/Product.wxs
index 4ce070cc..2271a0b6 100644
--- a/Install/RevitIFCSetupWix/Product.wxs
+++ b/Install/RevitIFCSetupWix/Product.wxs
@@ -2,7 +2,7 @@
-
+
diff --git a/Install/RevitIFCSetupWix/RevitIFCSetupWix.wixproj b/Install/RevitIFCSetupWix/RevitIFCSetupWix.wixproj
index 500ea3b6..888bc8fe 100644
--- a/Install/RevitIFCSetupWix/RevitIFCSetupWix.wixproj
+++ b/Install/RevitIFCSetupWix/RevitIFCSetupWix.wixproj
@@ -6,7 +6,7 @@
3.87dfbd495-c588-4c7b-b8f6-5b793adb06f22.0
- IFC for Revit 2024.1.0.22
+ IFC for Revit 2024.1.1.6Package$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets
diff --git a/Install/RevitIFCSetupWix/buildInstaller.bat b/Install/RevitIFCSetupWix/buildInstaller.bat
index c1dd5db0..e394f267 100644
--- a/Install/RevitIFCSetupWix/buildInstaller.bat
+++ b/Install/RevitIFCSetupWix/buildInstaller.bat
@@ -11,9 +11,9 @@ rem It is necessary to add the Wix bin directory to the system path temporarily
SET PATH=%PATH%;%WixRoot%
candle.exe -dProjectDir=%2 -ext WixUtilExtension %2Product.wxs
-light.exe -ext WixUtilExtension -out RevitIFC2024.1.0.msi product.wixobj -ext WixUIExtension
+light.exe -ext WixUtilExtension -out RevitIFC2024.1.1.msi product.wixobj -ext WixUIExtension
-copy RevitIFC2024.1.0.msi %1..\Releasex64
-del RevitIFC2024.1.0.msi
+copy RevitIFC2024.1.1.msi %1..\Releasex64
+del RevitIFC2024.1.1.msi
-echo %1..\Releasex64\RevitIFC2024.1.0.msi
+echo %1..\Releasex64\RevitIFC2024.1.1.msi
diff --git a/Source/IFCExporterUIOverride/IFCAddressInformationUI.xaml b/Source/IFCExporterUIOverride/IFCAddressInformationUI.xaml
index c3db7e0a..ea3bcc8a 100644
--- a/Source/IFCExporterUIOverride/IFCAddressInformationUI.xaml
+++ b/Source/IFCExporterUIOverride/IFCAddressInformationUI.xaml
@@ -28,7 +28,7 @@
-
+
diff --git a/Source/IFCExporterUIOverride/IFCExporterUIWindow.xaml b/Source/IFCExporterUIOverride/IFCExporterUIWindow.xaml
index 86e6b841..be07def3 100644
--- a/Source/IFCExporterUIOverride/IFCExporterUIWindow.xaml
+++ b/Source/IFCExporterUIOverride/IFCExporterUIWindow.xaml
@@ -81,9 +81,9 @@
-
-
-
+
+
+
diff --git a/Source/IFCExporterUIOverride/Properties/AssemblyInfo.cs b/Source/IFCExporterUIOverride/Properties/AssemblyInfo.cs
index 98ee2ed8..fd15a6db 100644
--- a/Source/IFCExporterUIOverride/Properties/AssemblyInfo.cs
+++ b/Source/IFCExporterUIOverride/Properties/AssemblyInfo.cs
@@ -66,6 +66,6 @@
// The following information is used in the Open Source version as the release version number.
// The number will show up in the Title bar of the export dialog as well as at the IFC header file
// This number must be manually updated prior to releasing the new version
-[assembly: AssemblyVersion("24.1.0.22")]
-[assembly: AssemblyFileVersion("24.1.0.22")]
+[assembly: AssemblyVersion("24.1.1.6")]
+[assembly: AssemblyFileVersion("24.1.1.6")]
#endif
\ No newline at end of file
diff --git a/Source/IFCExporterUIOverride/Properties/Resources.Designer.cs b/Source/IFCExporterUIOverride/Properties/Resources.Designer.cs
index 3a83cbd1..aca80384 100644
--- a/Source/IFCExporterUIOverride/Properties/Resources.Designer.cs
+++ b/Source/IFCExporterUIOverride/Properties/Resources.Designer.cs
@@ -96,6 +96,15 @@ public static string AddressInformation {
}
}
+ ///
+ /// Looks up a localized string similar to Entering a value here will reset the Purpose field to "USERDEFINED"..
+ ///
+ public static string AddressInformationTooltip {
+ get {
+ return ResourceManager.GetString("AddressInformationTooltip", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Address line 1.
///
@@ -2373,6 +2382,15 @@ public static string TessellationDetails {
}
}
+ ///
+ /// Looks up a localized string similar to Use this option if any tessellated geometry should remain as triangulated faces, or if the export performance is affected..
+ ///
+ public static string TriangulationOnlyTooltip {
+ get {
+ return ResourceManager.GetString("TriangulationOnlyTooltip", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Unknown alternate UI version.
///
@@ -2526,6 +2544,15 @@ public static string UseTypeNameOnlyForIfcType {
}
}
+ ///
+ /// Looks up a localized string similar to Use this option to export the IFC type name as the Revit type name without the family name..
+ ///
+ public static string UseTypeNameOnlyTooltip {
+ get {
+ return ResourceManager.GetString("UseTypeNameOnlyTooltip", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Use visible Revit name as the IFCEntity name.
///
@@ -2535,6 +2562,15 @@ public static string UseVisibleRevitNameAsEntityName {
}
}
+ ///
+ /// Looks up a localized string similar to Use this option to export IFC entity name as the visible Revit name..
+ ///
+ public static string UseVisibleRevitNameTooltip {
+ get {
+ return ResourceManager.GetString("UseVisibleRevitNameTooltip", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Path does not exist.
///
diff --git a/Source/IFCExporterUIOverride/Properties/Resources.resx b/Source/IFCExporterUIOverride/Properties/Resources.resx
index 1dd1cd91..2ecaee70 100644
--- a/Source/IFCExporterUIOverride/Properties/Resources.resx
+++ b/Source/IFCExporterUIOverride/Properties/Resources.resx
@@ -959,4 +959,19 @@
IFC-SG Regulatory Requirements View
+
+ Entering a value here will reset the Purpose field to "USERDEFINED".
+
+
+ If this option is checked, don't create a container for floors and roofs unless exporting parts.
+
+
+ Use this option if any tessellated geometry should remain as triangulated faces, or if the export performance is affected.
+
+
+ Use this option to export the IFC type name as the Revit type name without the family name.
+
+
+ Use this option to export IFC entity name as the visible Revit name.
+
\ No newline at end of file
diff --git a/Source/Revit.IFC.Common/Enums/IFC4x3EntityType.cs b/Source/Revit.IFC.Common/Enums/IFC4x3EntityType.cs
index dd9e988e..61ddb163 100644
--- a/Source/Revit.IFC.Common/Enums/IFC4x3EntityType.cs
+++ b/Source/Revit.IFC.Common/Enums/IFC4x3EntityType.cs
@@ -1,8 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
namespace Revit.IFC.Common.Enums.IFC4x3
{
///
diff --git a/Source/Revit.IFC.Common/Enums/IFCEntityType.cs b/Source/Revit.IFC.Common/Enums/IFCEntityType.cs
index 49b313b1..4fecbc2b 100644
--- a/Source/Revit.IFC.Common/Enums/IFCEntityType.cs
+++ b/Source/Revit.IFC.Common/Enums/IFCEntityType.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Revit.IFC.Common.Enums
+namespace Revit.IFC.Common.Enums
{
///
/// IFC entity types. Combining IFC2x2_ADD1, IFC2x3_TC1, IFC4 (Add2) and IFC4x entities, which are non-abstract
@@ -478,7 +473,6 @@ public enum IFCEntityType
IfcInventory,
IfcIrregularTimeSeries,
IfcIrregularTimeSeriesValue,
- IfcIshapeProfileDef,
IfcIShapeProfileDef,
IfcJunctionBox,
IfcJunctionBoxType,
diff --git a/Source/Revit.IFC.Common/Properties/AssemblyInfo.cs b/Source/Revit.IFC.Common/Properties/AssemblyInfo.cs
index d3a36c0d..457f87b5 100644
--- a/Source/Revit.IFC.Common/Properties/AssemblyInfo.cs
+++ b/Source/Revit.IFC.Common/Properties/AssemblyInfo.cs
@@ -13,8 +13,8 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("24.1.0.22")]
-[assembly: AssemblyFileVersion("24.1.0.22")]
+[assembly: AssemblyVersion("24.1.1.6")]
+[assembly: AssemblyFileVersion("24.1.1.6")]
#endif
diff --git a/Source/Revit.IFC.Export/Exporter/HostedSweepExporter.cs b/Source/Revit.IFC.Export/Exporter/HostedSweepExporter.cs
index 32fdc46e..5aed8a29 100644
--- a/Source/Revit.IFC.Export/Exporter/HostedSweepExporter.cs
+++ b/Source/Revit.IFC.Export/Exporter/HostedSweepExporter.cs
@@ -46,7 +46,7 @@ public static void Export(ExporterIFC exporterIFC, HostedSweep hostedSweep, Geom
if (catId == new ElementId(BuiltInCategory.OST_Gutter))
ExportGutter(exporterIFC, hostedSweep, geometryElement, productWrapper);
else
- ProxyElementExporter.Export(exporterIFC, hostedSweep, geometryElement, productWrapper);
+ GenericElementExporter.ExportElement(exporterIFC, hostedSweep, geometryElement, productWrapper);
}
///
diff --git a/Source/Revit.IFC.Export/Exporter/WallSweepExporter.cs b/Source/Revit.IFC.Export/Exporter/WallSweepExporter.cs
index e443ec73..4f5ef559 100644
--- a/Source/Revit.IFC.Export/Exporter/WallSweepExporter.cs
+++ b/Source/Revit.IFC.Export/Exporter/WallSweepExporter.cs
@@ -46,7 +46,7 @@ public static void Export(ExporterIFC exporterIFC, WallSweep wallSweep, Geometry
if (wallSweepInfo.WallSweepType == WallSweepType.Reveal)
return;
- if (!ProxyElementExporter.Export(exporterIFC, wallSweep, geometryElement, productWrapper))
+ if (!GenericElementExporter.ExportElement(exporterIFC, wallSweep, geometryElement, productWrapper))
return;
HostObjectExporter.ExportHostObjectMaterials(exporterIFC, wallSweep, productWrapper.GetAnElement(),
diff --git a/Source/Revit.IFC.Export/Properties/AssemblyInfo.cs b/Source/Revit.IFC.Export/Properties/AssemblyInfo.cs
index 71b64f90..5fe57fc0 100644
--- a/Source/Revit.IFC.Export/Properties/AssemblyInfo.cs
+++ b/Source/Revit.IFC.Export/Properties/AssemblyInfo.cs
@@ -14,8 +14,8 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("24.1.0.22")]
-[assembly: AssemblyFileVersion("24.1.0.22")]
+[assembly: AssemblyVersion("24.1.1.6")]
+[assembly: AssemblyFileVersion("24.1.1.6")]
#endif
diff --git a/Source/Revit.IFC.Export/Utility/OpeningUtil.cs b/Source/Revit.IFC.Export/Utility/OpeningUtil.cs
index 82fd0174..9de9d659 100644
--- a/Source/Revit.IFC.Export/Utility/OpeningUtil.cs
+++ b/Source/Revit.IFC.Export/Utility/OpeningUtil.cs
@@ -485,24 +485,19 @@ static public IFCAnyHandle CreateOpening(ExporterIFC exporterIFC, IFCAnyHandle h
lcs = GeometryUtil.CreateTransformFromPlane(curveLoops[0].GetPlane());
}
- ElementId catId = CategoryUtil.GetSafeCategoryId(insertElement);
-
if (extrusionData.ScaledExtrusionLength < MathUtil.Eps())
{
- double thickness = 0.0;
- if (hostElement is Floor)
- ParameterUtil.GetDoubleValueFromElement(hostElement, BuiltInParameter.FLOOR_ATTR_THICKNESS_PARAM, out thickness);
- else if (hostElement is RoofBase)
- ParameterUtil.GetDoubleValueFromElement(hostElement, BuiltInParameter.ROOF_ATTR_THICKNESS_PARAM, out thickness);
- else if (hostElement is Ceiling)
- ParameterUtil.GetDoubleValueFromElement(hostElement, BuiltInParameter.CEILING_THICKNESS, out thickness);
+ double extrusionLength = 0.0;
+ if (hostElement is Floor || hostElement is RoofBase || hostElement is Ceiling)
+ extrusionLength = CalculateOpeningExtrusionInFloorRoofOrCeiling(hostElement, extrusionData);
- if (thickness < MathUtil.Eps())
+ if (extrusionLength < MathUtil.Eps())
return null;
- extrusionData.ScaledExtrusionLength = UnitUtil.ScaleLength(thickness);
+ extrusionData.ScaledExtrusionLength = UnitUtil.ScaleLength(extrusionLength);
}
+ ElementId catId = CategoryUtil.GetSafeCategoryId(insertElement);
IFCAnyHandle openingHnd = null;
IFCAnyHandle openingProdRepHnd = RepresentationUtil.CreateExtrudedProductDefShape(exporterIFC, insertElement, catId,
curveLoops, lcs, extrusionData.ExtrusionDirection, extrusionData.ScaledExtrusionLength);
@@ -596,5 +591,43 @@ static bool GetOpeningDirections(Element hostElem, out XYZ perpToWall, out XYZ w
return isLinearWall;
}
+
+ ///
+ /// Calculates extrusion length for openings in floor roof or ceiling based on the element thickness for not sloped elements,
+ /// and based on bounding box for sloped. Also defines the extrusion direction for sloped elements.
+ ///
+ /// The host element.
+ /// The opening extrusion data
+ /// The extrusion length
+ private static double CalculateOpeningExtrusionInFloorRoofOrCeiling(Element hostElement, IFCExtrusionData extrusionData)
+ {
+ double extrusionLength = 0.0;
+ //Use the element thickness for not sloped elements, if the host element is sloped, the extrusions of the resulting opening will not intersect the host element.
+ //To handle such cases using bounding box height instead of thickness.
+ //
+ double slopeValue = 0.0;
+ ParameterUtil.GetDoubleValueFromElement(hostElement, BuiltInParameter.ROOF_SLOPE, out slopeValue);
+ if (MathUtil.IsAlmostZero(slopeValue))
+ {
+ if (hostElement is Floor)
+ ParameterUtil.GetDoubleValueFromElement(hostElement, BuiltInParameter.FLOOR_ATTR_THICKNESS_PARAM, out extrusionLength);
+ else if (hostElement is RoofBase)
+ ParameterUtil.GetDoubleValueFromElement(hostElement, BuiltInParameter.ROOF_ATTR_THICKNESS_PARAM, out extrusionLength);
+ else if (hostElement is Ceiling)
+ ParameterUtil.GetDoubleValueFromElement(hostElement, BuiltInParameter.CEILING_THICKNESS, out extrusionLength);
+ }
+ else
+ {
+ BoundingBoxXYZ hostElementBoundingBox = hostElement.get_BoundingBox(hostElement.Document.GetElement(hostElement.OwnerViewId) as View);
+ extrusionLength = hostElementBoundingBox.Max.Z - hostElementBoundingBox.Min.Z;
+
+ //Need to recheck the ExtrusionDirection.
+ //If slope is positive value the host it will be above.
+ //
+ extrusionData.ExtrusionDirection = (slopeValue > 0) ? XYZ.BasisZ : -XYZ.BasisZ;
+ }
+
+ return extrusionLength;
+ }
}
}
\ No newline at end of file
diff --git a/Source/Revit.IFC.Import.Core/Properties/AssemblyInfo.cs b/Source/Revit.IFC.Import.Core/Properties/AssemblyInfo.cs
index af54ca93..53e712b7 100644
--- a/Source/Revit.IFC.Import.Core/Properties/AssemblyInfo.cs
+++ b/Source/Revit.IFC.Import.Core/Properties/AssemblyInfo.cs
@@ -13,8 +13,8 @@
[assembly: AssemblyDescription("Revit.IFC.Import.Core")]
[assembly: AssemblyCompany("Autodesk")]
[assembly: AssemblyCopyright("@2012-2023 Autodesk, Inc. All rights reserved.")]
-[assembly: AssemblyVersion("24.1.0.22")]
-[assembly: AssemblyFileVersion("24.1.0.22")]
+[assembly: AssemblyVersion("24.1.1.6")]
+[assembly: AssemblyFileVersion("24.1.1.6")]
// Version information can now be found in Source\Foundation\RevitENU\Version.cs
//
diff --git a/Source/Revit.IFC.Import/Data/IFCBuildingElementProxy.cs b/Source/Revit.IFC.Import/Data/IFCBuildingElementProxy.cs
index d3c4dbbb..3a8354f7 100644
--- a/Source/Revit.IFC.Import/Data/IFCBuildingElementProxy.cs
+++ b/Source/Revit.IFC.Import/Data/IFCBuildingElementProxy.cs
@@ -140,7 +140,7 @@ protected override void Create(Document doc)
geomObjs.Add(solid.GeometryObject);
}
- DirectShape buildingElementProxyShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs, Id, EntityType);
+ DirectShape buildingElementProxyShape = IFCElementUtil.CreateElement(doc, GetCategoryId(doc), GlobalId, geomObjs, Id, EntityType);
if (buildingElementProxyShape != null)
{
CreatedElementId = buildingElementProxyShape.Id;
diff --git a/Source/Revit.IFC.Import/Data/IFCBuildingStorey.cs b/Source/Revit.IFC.Import/Data/IFCBuildingStorey.cs
index 2a8c977a..1bdaad36 100644
--- a/Source/Revit.IFC.Import/Data/IFCBuildingStorey.cs
+++ b/Source/Revit.IFC.Import/Data/IFCBuildingStorey.cs
@@ -17,6 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
+using System;
using System.Collections.Generic;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
@@ -32,13 +33,6 @@ namespace Revit.IFC.Import.Data
///
public class IFCBuildingStorey : IFCSpatialStructureElement
{
- static ElementId ViewPlanTypeId { get; set; } = ElementId.InvalidElementId;
-
- ///
- /// Returns true if we have tried to set ViewPlanTypeId. ViewPlanTypeId may or may not have a valid value.
- ///
- static bool ViewPlanTypeIdInitialized { get; set; } = false;
-
///
/// Returns the associated Plan View for the level.
///
@@ -53,14 +47,24 @@ public class IFCBuildingStorey : IFCSpatialStructureElement
/// Get the default family type for creating ViewPlans.
///
///
- ///
+ /// The default family type.
public static ElementId GetViewPlanTypeId(Document doc)
{
- if (ViewPlanTypeIdInitialized == false)
+ // There are theoretical cases where this could fail, but no such cases have been
+ // seen in practice.
+ if (Importer.TheCache.ViewPlanTypeIdInitialized == false)
{
- ViewFamily viewFamilyToUse = (doc.Application.Product == ProductType.Structure) ? ViewFamily.StructuralPlan : ViewFamily.FloorPlan;
-
- ViewPlanTypeIdInitialized = true;
+ // Basically, we only want to use the StructuralPlan if Structure is our only valid
+ // option.
+ ViewFamily viewFamilyToUse;
+ if (doc.Application.IsArchitectureEnabled || doc.Application.IsSystemsEnabled)
+ viewFamilyToUse = ViewFamily.FloorPlan;
+ else if (doc.Application.IsStructureEnabled)
+ viewFamilyToUse = ViewFamily.StructuralPlan;
+ else
+ viewFamilyToUse = ViewFamily.FloorPlan;
+
+ Importer.TheCache.ViewPlanTypeIdInitialized = true;
FilteredElementCollector collector = new FilteredElementCollector(doc);
ICollection viewFamilyTypes = collector.OfClass(typeof(ViewFamilyType)).ToElements();
foreach (Element element in viewFamilyTypes)
@@ -68,12 +72,12 @@ public static ElementId GetViewPlanTypeId(Document doc)
ViewFamilyType viewFamilyType = element as ViewFamilyType;
if (viewFamilyType.ViewFamily == viewFamilyToUse)
{
- ViewPlanTypeId = viewFamilyType.Id;
+ Importer.TheCache.ViewPlanTypeId = viewFamilyType.Id;
break;
}
}
}
- return ViewPlanTypeId;
+ return Importer.TheCache.ViewPlanTypeId;
}
///
@@ -98,7 +102,7 @@ protected override void CreateParametersInternal(Document doc, Element element)
{
// Set "IfcElevation" parameter.
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterDouble(doc, element, category, this, "IfcElevation", SpecTypeId.Length, UnitTypeId.Feet, Elevation, Id);
+ ParametersToSet.AddParameterDouble(doc, element, category, this, "IfcElevation", SpecTypeId.Length, UnitTypeId.Feet, Elevation, Id);
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCDistributionPort.cs b/Source/Revit.IFC.Import/Data/IFCDistributionPort.cs
index cde28cb2..e55bcc8a 100644
--- a/Source/Revit.IFC.Import/Data/IFCDistributionPort.cs
+++ b/Source/Revit.IFC.Import/Data/IFCDistributionPort.cs
@@ -80,8 +80,9 @@ protected override void CreateParametersInternal(Document doc, Element element)
if (element != null)
{
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "Flow Direction", FlowDirection.ToString(), Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "System Type", SystemType.ToString(), Id);
+
+ ParametersToSet.AddStringParameter(doc, element, category, this, "Flow Direction", FlowDirection.ToString(), Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "System Type", SystemType.ToString(), Id);
}
}
@@ -110,14 +111,16 @@ protected override void Create(Document doc)
// 2016+ only.
XYZ origin = lcs.Origin;
- Point point = XYZ.IsWithinLengthLimits(origin) ? Point.Create(origin, GraphicsStyleId) : null;
+
+ ElementId graphicsStyleId = GetGraphicsStyleId(doc);
+ Point point = XYZ.IsWithinLengthLimits(origin) ? Point.Create(origin, graphicsStyleId) : null;
// 2015+: create cone(s) for the direction of flow.
CurveLoop rightTrangle = new CurveLoop();
const double radius = 0.04;
const double height = 0.12;
- SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, GraphicsStyleId);
+ SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, graphicsStyleId);
Frame coordinateFrame = new Frame(lcs.Origin, lcs.BasisX, lcs.BasisY, lcs.BasisZ);
@@ -145,8 +148,7 @@ protected override void Create(Document doc)
oppositeRightTrangle.Append(Line.CreateBound(pt1, oppPt2));
oppositeRightTrangle.Append(Line.CreateBound(oppPt2, oppPt3));
oppositeRightTrangle.Append(Line.CreateBound(oppPt3, pt1));
- IList oppositeCurveLoops = new List();
- oppositeCurveLoops.Add(oppositeRightTrangle);
+ IList oppositeCurveLoops = new List() { oppositeRightTrangle };
oppositePortArrow = GeometryCreationUtilities.CreateRevolvedGeometry(oppositeCoordinateFrame, oppositeCurveLoops, 0.0, Math.PI * 2.0, solidOptions);
}
@@ -161,7 +163,7 @@ protected override void Create(Document doc)
if (oppositePortArrow != null)
geomObjs.Add(oppositePortArrow);
- DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs, Id, EntityType);
+ DirectShape directShape = IFCElementUtil.CreateElement(doc, GetCategoryId(doc), GlobalId, geomObjs, Id, EntityType);
if (directShape != null)
{
CreatedGeometry = geomObjs;
diff --git a/Source/Revit.IFC.Import/Data/IFCDistributionSystem.cs b/Source/Revit.IFC.Import/Data/IFCDistributionSystem.cs
index 21e3bca2..f212b21b 100644
--- a/Source/Revit.IFC.Import/Data/IFCDistributionSystem.cs
+++ b/Source/Revit.IFC.Import/Data/IFCDistributionSystem.cs
@@ -17,6 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
+using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.IFC;
@@ -139,7 +140,7 @@ public static IFCDistributionSystem ProcessIFCDistributionSystem(IFCAnyHandle if
///
/// Indicates whether we should create a separate DirectShape for this IFC entity.
- /// For IfcDistributionSystem, a DIrectShape should be created.
+ /// For IfcDistributionSystem, a DirectShape should be created.
///
/// True if a DirectShape container is created, False otherwise.
public override bool CreateContainer() { return true; }
@@ -162,8 +163,8 @@ protected override void CreateParametersInternal(Document doc, Element element)
// Add IfcSystemClassification parameter.
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "SystemClassification", systemClassificationString, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "SystemName", LongName, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "SystemClassification", systemClassificationString, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "SystemName", LongName, Id);
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCDoorStyle.cs b/Source/Revit.IFC.Import/Data/IFCDoorStyle.cs
index f957f212..1fd1fa18 100644
--- a/Source/Revit.IFC.Import/Data/IFCDoorStyle.cs
+++ b/Source/Revit.IFC.Import/Data/IFCDoorStyle.cs
@@ -116,11 +116,20 @@ protected override void CreateParametersInternal(Document doc, Element element)
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
if (category != null)
{
- Importer.TheProcessor.SetStringParameter(element, Id, BuiltInParameter.DOOR_OPERATION_TYPE, OperationType.ToString(), false);
- Importer.TheProcessor.SetStringParameter(element, Id, BuiltInParameter.DOOR_CONSTRUCTION_TYPE, ConstructionType.ToString(), false);
-
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcOperationType", OperationType.ToString(), Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcConstructionType", ConstructionType.ToString(), Id);
+ IFCDefaultProcessor processor = Importer.TheProcessor as IFCDefaultProcessor;
+ if (processor != null)
+ {
+ processor.SetElementStringParameter(element, Id, BuiltInParameter.DOOR_OPERATION_TYPE, OperationType.ToString(), false, ParametersToSet);
+ processor.SetElementStringParameter(element, Id, BuiltInParameter.DOOR_CONSTRUCTION_TYPE, ConstructionType.ToString(), false, ParametersToSet);
+ }
+ else
+ {
+ Importer.TheProcessor.SetStringParameter(element, Id, BuiltInParameter.DOOR_OPERATION_TYPE, OperationType.ToString(), false);
+ Importer.TheProcessor.SetStringParameter(element, Id, BuiltInParameter.DOOR_CONSTRUCTION_TYPE, ConstructionType.ToString(), false);
+ }
+
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcOperationType", OperationType.ToString(), Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcConstructionType", ConstructionType.ToString(), Id);
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCDoorType.cs b/Source/Revit.IFC.Import/Data/IFCDoorType.cs
index 6f18f179..8cbc3e79 100644
--- a/Source/Revit.IFC.Import/Data/IFCDoorType.cs
+++ b/Source/Revit.IFC.Import/Data/IFCDoorType.cs
@@ -98,8 +98,18 @@ protected override void CreateParametersInternal(Document doc, Element element)
{
base.CreateParametersInternal(doc, element);
- if (element != null)
+ if (element == null)
+ return;
+
+ IFCDefaultProcessor processor = Importer.TheProcessor as IFCDefaultProcessor;
+ if (processor != null)
+ {
+ processor.SetElementStringParameter(element, Id, BuiltInParameter.DOOR_OPERATION_TYPE, OperationType.ToString(), false, ParametersToSet);
+ }
+ else
+ {
Importer.TheProcessor.SetStringParameter(element, Id, BuiltInParameter.DOOR_OPERATION_TYPE, OperationType.ToString(), false);
+ }
}
}
}
\ No newline at end of file
diff --git a/Source/Revit.IFC.Import/Data/IFCDoorWindowPropertyBase.cs b/Source/Revit.IFC.Import/Data/IFCDoorWindowPropertyBase.cs
index 35a548b8..7e78c806 100644
--- a/Source/Revit.IFC.Import/Data/IFCDoorWindowPropertyBase.cs
+++ b/Source/Revit.IFC.Import/Data/IFCDoorWindowPropertyBase.cs
@@ -98,7 +98,8 @@ protected override void Process(IFCAnyHandle ifcDoorWindowPropertyBase)
/// The element being created.
/// The parameters of the element. Cached for performance.
/// The name of the property set created, if it was created, and a Boolean value if it should be added to the property set list.
- public override Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap)
+ public override Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, ParametersToSet parametersToSet)
{
IDictionary parametersToAdd = new Dictionary();
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
@@ -114,17 +115,17 @@ public override Tuple CreatePropertySet(Document doc, Element elem
// and so will always be in feet.
ForgeTypeId unitType = (!Importer.TheProcessor.ScaleValues && valueType == SpecTypeId.Length) ?
UnitTypeId.Feet : null;
- IFCPropertySet.AddParameterDouble(doc, element, category, objDef, name, valueType, unitType, property.Value, Id);
+ parametersToSet.AddParameterDouble(doc, element, category, objDef, name, valueType, unitType, property.Value, Id);
continue;
}
switch (existingParameter.StorageType)
{
case StorageType.String:
- existingParameter.Set(property.Value.ToString());
+ parametersToSet.AddStringParameter(existingParameter, property.Value.ToString());
break;
case StorageType.Double:
- existingParameter.Set(property.Value);
+ parametersToSet.AddDoubleParameter(existingParameter, property.Value);
break;
default:
Importer.TheLog.LogError(Id, "couldn't create parameter: " + name + " of storage type: " + existingParameter.StorageType.ToString(), false);
@@ -138,14 +139,14 @@ public override Tuple CreatePropertySet(Document doc, Element elem
Parameter existingParameter = null;
if (!parameterGroupMap.TryFindParameter(name, out existingParameter))
{
- IFCPropertySet.AddParameterString(doc, element, category, objDef, property.Key, property.Value, Id);
+ parametersToSet.AddStringParameter(doc, element, category, objDef, property.Key, property.Value, Id);
continue;
}
switch (existingParameter.StorageType)
{
case StorageType.String:
- existingParameter.Set(property.Value);
+ parametersToSet.AddStringParameter(existingParameter, property.Value);
break;
default:
Importer.TheLog.LogError(Id, "couldn't create parameter: " + name + " of storage type: " + existingParameter.StorageType.ToString(), false);
diff --git a/Source/Revit.IFC.Import/Data/IFCElement.cs b/Source/Revit.IFC.Import/Data/IFCElement.cs
index a6256fa9..1a67c0b0 100644
--- a/Source/Revit.IFC.Import/Data/IFCElement.cs
+++ b/Source/Revit.IFC.Import/Data/IFCElement.cs
@@ -217,7 +217,7 @@ protected override void CreateParametersInternal(Document doc, Element element)
// Set "Tag" parameter.
string ifcTag = Tag;
if (!string.IsNullOrWhiteSpace(ifcTag))
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcTag", ifcTag, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcTag", ifcTag, Id);
IFCFeatureElementSubtraction ifcFeatureElementSubtraction = FillsOpening;
if (ifcFeatureElementSubtraction != null)
@@ -225,8 +225,8 @@ protected override void CreateParametersInternal(Document doc, Element element)
IFCElement ifcElement = ifcFeatureElementSubtraction.VoidsElement;
if (ifcElement != null)
{
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcContainedInHost", ifcElement.Name, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcContainedInHostGUID", ifcElement.GlobalId, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcContainedInHost", ifcElement.Name, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcContainedInHostGUID", ifcElement.GlobalId, Id);
}
}
@@ -241,13 +241,13 @@ protected override void CreateParametersInternal(Document doc, Element element)
if (!string.IsNullOrWhiteSpace(name))
{
string parameterName = "IfcElement HasPorts Name " + ((numPorts == 0) ? "" : (numPorts + 1).ToString());
- IFCPropertySet.AddParameterString(doc, element, category, this, parameterName, name, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, parameterName, name, Id);
}
if (!string.IsNullOrWhiteSpace(guid))
{
string parameterName = "IfcElement HasPorts IfcGUID " + ((numPorts == 0) ? "" : (numPorts + 1).ToString());
- IFCPropertySet.AddParameterString(doc, element, category, this, parameterName, guid, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, parameterName, guid, Id);
}
numPorts++;
diff --git a/Source/Revit.IFC.Import/Data/IFCElementAssembly.cs b/Source/Revit.IFC.Import/Data/IFCElementAssembly.cs
index af2900eb..abffc09c 100644
--- a/Source/Revit.IFC.Import/Data/IFCElementAssembly.cs
+++ b/Source/Revit.IFC.Import/Data/IFCElementAssembly.cs
@@ -99,8 +99,8 @@ protected override void CreateParametersInternal(Document doc, Element element)
if (element != null)
{
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcPredefinedType", PredefinedType, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcAssemblyPlace", AssemblyPlace.ToString(), Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcPredefinedType", PredefinedType, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcAssemblyPlace", AssemblyPlace.ToString(), Id);
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCElementQuantity.cs b/Source/Revit.IFC.Import/Data/IFCElementQuantity.cs
index bd6106f1..16047231 100644
--- a/Source/Revit.IFC.Import/Data/IFCElementQuantity.cs
+++ b/Source/Revit.IFC.Import/Data/IFCElementQuantity.cs
@@ -128,7 +128,8 @@ public static IFCElementQuantity ProcessIFCElementQuantity(IFCAnyHandle ifcEleme
/// The element being created.
/// The parameters of the element. Cached for performance.
/// The name of the property set created, if it was created, and a Boolean value if it should be added to the property set list.
- public override Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap)
+ public override Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, ParametersToSet parametersToSet)
{
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
@@ -138,7 +139,7 @@ public override Tuple CreatePropertySet(Document doc, Element elem
foreach (IFCPhysicalQuantity quantity in IFCQuantities.Values)
{
string fullName = CreatePropertyName(quantity.Name);
- quantity.Create(doc, element, category, objDef, parameterGroupMap, fullName, parametersCreated);
+ quantity.Create(doc, element, category, objDef, parameterGroupMap, fullName, parametersCreated, parametersToSet);
}
return Tuple.Create(quotedName, true);
diff --git a/Source/Revit.IFC.Import/Data/IFCElementType.cs b/Source/Revit.IFC.Import/Data/IFCElementType.cs
index af06b50c..5ad5514f 100644
--- a/Source/Revit.IFC.Import/Data/IFCElementType.cs
+++ b/Source/Revit.IFC.Import/Data/IFCElementType.cs
@@ -104,7 +104,7 @@ protected override void CreateParametersInternal(Document doc, Element element)
if (!string.IsNullOrWhiteSpace(ElementType))
{
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcElementType", ElementType, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcElementType", ElementType, Id);
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCGroup.cs b/Source/Revit.IFC.Import/Data/IFCGroup.cs
index b93c55b0..b0de2edd 100644
--- a/Source/Revit.IFC.Import/Data/IFCGroup.cs
+++ b/Source/Revit.IFC.Import/Data/IFCGroup.cs
@@ -219,7 +219,7 @@ protected override void Create(Document doc)
}
}
- DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geometryObjects, Id, EntityType);
+ DirectShape directShape = IFCElementUtil.CreateElement(doc, GetCategoryId(doc), GlobalId, geometryObjects, Id, EntityType);
if (directShape != null)
{
CreatedElementId = directShape.Id;
diff --git a/Source/Revit.IFC.Import/Data/IFCImportFile.cs b/Source/Revit.IFC.Import/Data/IFCImportFile.cs
index 10348837..dcccf5ba 100644
--- a/Source/Revit.IFC.Import/Data/IFCImportFile.cs
+++ b/Source/Revit.IFC.Import/Data/IFCImportFile.cs
@@ -585,29 +585,44 @@ private static void UpdateDocumentFileMetrics(Document doc, string ifcFileName)
return;
Parameter originalImporterVersion = projInfo.LookupParameter("Revit Importer Version");
- if (originalTimeStampParam != null && originalTimeStampParam.StorageType != StorageType.String)
+ if (originalImporterVersion != null && originalImporterVersion.StorageType != StorageType.String)
return;
+ Parameter originalImportMethod = projInfo.LookupParameter(IFCImportOptions.ImportMethodParameter);
+ if (originalImportMethod != null && originalImportMethod.StorageType != StorageType.String)
+ return;
+
Category category = IFCPropertySet.GetCategoryForParameterIfValid(projInfo, -1);
- if (originalFileName != null)
- originalFileName.Set(ifcFileName);
- else
- IFCPropertySet.AddParameterString(doc, projInfo, category, TheFile.IFCProject, "Original IFC File Name", ifcFileName, -1);
- if (originalFileSizeParam != null)
- originalFileSizeParam.Set(ifcFileLength.ToString());
- else
- IFCPropertySet.AddParameterString(doc, projInfo, category, TheFile.IFCProject, "Original IFC File Size", ifcFileLength.ToString(), -1);
+ using (ParameterSetter setter = new ParameterSetter())
+ {
+ ParametersToSet parametersToSet = setter.ParametersToSet;
- if (originalTimeStampParam != null)
- originalTimeStampParam.Set(ticks.ToString());
- else
- IFCPropertySet.AddParameterString(doc, projInfo, category, TheFile.IFCProject, "Revit File Last Updated", ticks.ToString(), -1);
+ if (originalFileName != null)
+ parametersToSet.AddStringParameter(originalFileName, ifcFileName);
+ else
+ parametersToSet.AddStringParameter(doc, projInfo, category, TheFile.IFCProject, "Original IFC File Name", ifcFileName, -1);
- if (originalImporterVersion != null)
- originalImporterVersion.Set(IFCImportOptions.ImporterVersion);
- else
- IFCPropertySet.AddParameterString(doc, projInfo, category, TheFile.IFCProject, "Revit Importer Version", IFCImportOptions.ImporterVersion, -1);
+ if (originalFileSizeParam != null)
+ parametersToSet.AddStringParameter(originalFileSizeParam, ifcFileLength.ToString());
+ else
+ parametersToSet.AddStringParameter(doc, projInfo, category, TheFile.IFCProject, "Original IFC File Size", ifcFileLength.ToString(), -1);
+
+ if (originalTimeStampParam != null)
+ parametersToSet.AddStringParameter(originalTimeStampParam, ticks.ToString());
+ else
+ parametersToSet.AddStringParameter(doc, projInfo, category, TheFile.IFCProject, "Revit File Last Updated", ticks.ToString(), -1);
+
+ if (originalImporterVersion != null)
+ parametersToSet.AddStringParameter(originalImporterVersion, IFCImportOptions.ImporterVersion);
+ else
+ parametersToSet.AddStringParameter(doc, projInfo, category, TheFile.IFCProject, "Revit Importer Version", IFCImportOptions.ImporterVersion, -1);
+
+ if (originalImportMethod != null)
+ parametersToSet.AddStringParameter(originalImportMethod, Importer.TheOptions.CurrentImportMethod.ToString());
+ else
+ parametersToSet.AddStringParameter(doc, projInfo, category, TheFile.IFCProject, IFCImportOptions.ImportMethodParameter, Importer.TheOptions.CurrentImportMethod.ToString(), -1);
+ }
}
private bool DontDeleteSpecialElement(ElementId elementId)
@@ -638,6 +653,9 @@ public void EndImport(Document doc, string fileName)
foreach (ElementId elementId in Importer.TheCache.GUIDToElementMap.Values)
{
+ if (Importer.TheHybridInfo?.HybridElements.Contains(elementId) ?? false)
+ continue;
+
if (DontDeleteSpecialElement(elementId))
continue;
@@ -653,6 +671,9 @@ public void EndImport(Document doc, string fileName)
foreach (ElementId elementId in Importer.TheCache.GridNameToElementMap.Values)
{
+ if (Importer.TheHybridInfo?.HybridElements.Contains(elementId) ?? false)
+ continue;
+
Element element = doc.GetElement(elementId);
if (element == null)
continue;
diff --git a/Source/Revit.IFC.Import/Data/IFCMappedItem.cs b/Source/Revit.IFC.Import/Data/IFCMappedItem.cs
index 722042ce..eec928ea 100644
--- a/Source/Revit.IFC.Import/Data/IFCMappedItem.cs
+++ b/Source/Revit.IFC.Import/Data/IFCMappedItem.cs
@@ -63,18 +63,20 @@ override protected void Process(IFCAnyHandle item)
{
base.Process(item);
+ IFCAnyHandle mappingSource = IFCImportHandleUtil.GetRequiredInstanceAttribute(item, "MappingSource", false);
+ if (mappingSource == null)
+ return;
+
+ MappingSource = IFCRepresentationMap.ProcessIFCRepresentationMap(mappingSource);
+ if (MappingSource.IsHybridOnly())
+ return;
+
// We will not fail if the transform is not given, but instead assume it to be the identity.
IFCAnyHandle mappingTarget = IFCImportHandleUtil.GetRequiredInstanceAttribute(item, "MappingTarget", false);
if (mappingTarget != null)
MappingTarget = IFCCartesianTransformOperator.ProcessIFCCartesianTransformOperator(mappingTarget);
else
MappingTarget = IFCCartesianTransformOperator.ProcessIFCCartesianTransformOperator();
-
- IFCAnyHandle mappingSource = IFCImportHandleUtil.GetRequiredInstanceAttribute(item, "MappingSource", false);
- if (mappingSource == null)
- return;
-
- MappingSource = IFCRepresentationMap.ProcessIFCRepresentationMap(mappingSource);
}
private int FindAlternateGeometrySource(int originalId)
@@ -101,6 +103,12 @@ protected override void CreateShapeInternal(IFCImportShapeEditScope shapeEditSco
{
base.CreateShapeInternal(shapeEditScope, scaledLcs, guid);
+ // Optimization for hybrid import. MappingTarget will be null in this case.
+ if (MappingTarget == null)
+ {
+ return;
+ }
+
// Check scale; if it is uniform, create an instance. If not, create a shape directly.
// TODO: Instead allow creation of instances based on similar scaling.
double scaleX = MappingTarget.Scale;
@@ -129,15 +137,19 @@ protected override void CreateShapeInternal(IFCImportShapeEditScope shapeEditSco
if (canCreateType)
{
int mappingSourceId = MappingSource.Id;
+
int geometrySourceId = FindAlternateGeometrySource(mappingSourceId);
MappingSource.CreateShape(shapeEditScope, null, guid);
- if (shapeEditScope.Creator != null)
+ // IFCDefaultProcessor doesn't implement PostProcessMappedItem. Skip this call to avoid
+ // GetCategoryId(), which can create an unnecessary subcategory (which also forces an
+ // unnecessary regeneration).
+ if ((shapeEditScope.Creator != null) && !(Importer.TheProcessor is IFCDefaultProcessor))
{
Importer.TheProcessor.PostProcessMappedItem(shapeEditScope.Creator.Id,
shapeEditScope.Creator.GlobalId,
shapeEditScope.Creator.EntityType.ToString(),
- shapeEditScope.Creator.CategoryId,
+ shapeEditScope.Creator.GetCategoryId(shapeEditScope.Document),
geometrySourceId,
newScaledLcs);
}
diff --git a/Source/Revit.IFC.Import/Data/IFCMaterial.cs b/Source/Revit.IFC.Import/Data/IFCMaterial.cs
index a281e602..c8762f61 100644
--- a/Source/Revit.IFC.Import/Data/IFCMaterial.cs
+++ b/Source/Revit.IFC.Import/Data/IFCMaterial.cs
@@ -87,7 +87,7 @@ protected override void Process(IFCAnyHandle ifcMaterial)
if (IFCImportFile.TheFile.SchemaVersionAtLeast(IFCSchemaVersion.IFC2x3))
hasRepresentation = IFCAnyHandleUtil.GetAggregateInstanceAttribute>(ifcMaterial, "HasRepresentation");
- if (hasRepresentation != null && hasRepresentation.Count == 1)
+ if ((hasRepresentation?.Count ?? 0) == 1)
{
if (!IFCAnyHandleUtil.IsSubTypeOf(hasRepresentation[0], IFCEntityType.IfcMaterialDefinitionRepresentation))
Importer.TheLog.LogUnexpectedTypeError(hasRepresentation[0], IFCEntityType.IfcMaterialDefinitionRepresentation, false);
@@ -108,7 +108,7 @@ private static string GetMaterialName(int id, string originalName)
if (revitMaterialName != null)
return revitMaterialName;
- return String.Format(Resources.IFCDefaultMaterialName, id);
+ return string.Format(Resources.IFCDefaultMaterialName, id);
}
///
@@ -116,8 +116,7 @@ private static string GetMaterialName(int id, string originalName)
///
public IList GetMaterials()
{
- IList materials = new List();
- materials.Add(this);
+ IList materials = new List() { this };
return materials;
}
diff --git a/Source/Revit.IFC.Import/Data/IFCObject.cs b/Source/Revit.IFC.Import/Data/IFCObject.cs
index df7dd41c..d6b0ce2c 100644
--- a/Source/Revit.IFC.Import/Data/IFCObject.cs
+++ b/Source/Revit.IFC.Import/Data/IFCObject.cs
@@ -319,7 +319,7 @@ protected override void CreateParametersInternal(Document doc, Element element)
if (!string.IsNullOrWhiteSpace(objectTypeOverride))
{
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "ObjectTypeOverride", objectTypeOverride, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "ObjectTypeOverride", objectTypeOverride, Id);
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCObjectDefinition.cs b/Source/Revit.IFC.Import/Data/IFCObjectDefinition.cs
index 089c62b3..ecb3ee2b 100644
--- a/Source/Revit.IFC.Import/Data/IFCObjectDefinition.cs
+++ b/Source/Revit.IFC.Import/Data/IFCObjectDefinition.cs
@@ -1,4 +1,4 @@
-//
+//
// Revit IFC Import library: this library works with Autodesk(R) Revit(R) to import IFC files.
// Copyright (C) 2013 Autodesk, Inc.
//
@@ -19,7 +19,9 @@
using System;
using System.Collections.Generic;
+using System.Configuration;
using System.Linq;
+using System.Runtime.Remoting;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.IFC;
using Revit.IFC.Common.Enums;
@@ -37,7 +39,7 @@ public abstract class IFCObjectDefinition : IFCRoot
ICollection m_AssignmentGroups = null; //HasAssignments
private IFCMaterial m_TheMaterial = null;
-
+
private bool m_TheMaterialIsSet = false;
private IDictionary m_AdditionalIntParameters = null;
@@ -46,6 +48,8 @@ public abstract class IFCObjectDefinition : IFCRoot
private IFCObjectDefinition m_Nests = null;
+ protected ParametersToSet ParametersToSet { get; set; } = new ParametersToSet();
+
///
/// The IFCObjectDefinition that is nested by this.
///
@@ -62,15 +66,41 @@ public IFCObjectDefinition NestsWhole
}
}
+ protected ElementId CategoryIdCache { get; set; } = ElementId.InvalidElementId;
+
+ protected ElementId GraphicsStyleIdCache { get; set; } = ElementId.InvalidElementId;
+
+ private void CalculateCategoryAndGStyleIds(Document doc)
+ {
+ CategoryIdCache = IFCCategoryUtil.GetCategoryIdForEntity(doc, this, out ElementId gstyleId);
+ GraphicsStyleIdCache = gstyleId;
+ }
+
///
/// The category id corresponding to the element created for this IFCObjectDefinition.
///
- public ElementId CategoryId { get; protected set; } = ElementId.InvalidElementId;
+ public ElementId GetCategoryId(Document doc)
+ {
+ if (CategoryIdCache == ElementId.InvalidElementId)
+ {
+ CalculateCategoryAndGStyleIds(doc);
+ }
+
+ return CategoryIdCache;
+ }
///
/// The graphics style id corresponding to the element created for this IFCObjectDefinition.
///
- public ElementId GraphicsStyleId { get; protected set; } = ElementId.InvalidElementId;
+ public ElementId GetGraphicsStyleId(Document doc)
+ {
+ if (GraphicsStyleIdCache == ElementId.InvalidElementId)
+ {
+ CalculateCategoryAndGStyleIds(doc);
+ }
+
+ return GraphicsStyleIdCache;
+ }
///
/// Returns true if sub-elements should be grouped; false otherwise.
@@ -109,7 +139,10 @@ public virtual bool GroupSubElements()
///
public bool IsHybridImportContainer()
{
- return (Importer.TheOptions.IsHybridImport && IsAllowedToAggregateGeometry() && (Importer.TheHybridInfo?.ContainerMap?.ContainsKey(Id) ?? false));
+ return Importer.TheOptions.IsHybridImport &&
+ IsAllowedToAggregateGeometry() &&
+ ((ComposedObjectDefinitions?.Count ?? 0) > 0) &&
+ (Importer.TheHybridInfo?.ContainerMap?.ContainsKey(Id) ?? false);
}
///
@@ -359,8 +392,8 @@ protected IFCObjectDefinition()
/// The document.
protected override void Create(Document doc)
{
- if (MaterialSelect != null)
- MaterialSelect.Create(doc);
+ // We will not process the MaterialSelect here, as if we actually need the material information, we will create
+ // it then. This is an optimization for Hybrid mode but should work for Legacy also.
base.Create(doc);
@@ -400,6 +433,18 @@ protected virtual bool CutSolidByVoids(IFCSolidInfo solidInfo)
return true;
}
+ private void AddPlanViewCurves(Document doc, DirectShape containerDirectShape, IList planViewCurves)
+ {
+ if (doc == null || containerDirectShape == null || ((planViewCurves?.Count ?? 0) == 0) || !(this is IFCProduct))
+ return;
+
+ using (IFCImportShapeEditScope planViewScope = IFCImportShapeEditScope.Create(doc, this as IFCProduct))
+ {
+ planViewScope.AddPlanViewCurves(planViewCurves, Id);
+ planViewScope.SetPlanViewRep(containerDirectShape);
+ }
+ }
+
///
/// Creates or populates Revit elements based on the information contained in this class.
///
@@ -447,46 +492,54 @@ protected virtual void TraverseSubElements(Document doc)
}
}
- if (GroupSubElements())
+ if (GroupSubElements() && subElementIds.Count > 0)
{
- if (subElementIds.Count > 0)
+ if (CreatedElementId != ElementId.InvalidElementId)
{
- if (CreatedElementId != ElementId.InvalidElementId && groupedSubElementGeometries.Count == 0)
- {
- // If CreateDuplicateContainerGeometry is false, then
- // groupedSubElementGeometries is empty and we then create a new
- // DirectShape with no content in it.
- //
- // For files such as NW-55644 that has geometry on the slab element and
- // children with geometry, this means that the slab geometry is thrown away
- return;
- }
-
- if (CreatedElementId != ElementId.InvalidElementId)
- subElementIds.Add(CreatedElementId);
-
- // We aren't yet actually grouping the elements. DirectShape doesn't support grouping, and
- // the Group element doesn't support adding parameters. For now, we will create a DirectShape that "forgets"
- // the association, which is good enough for link.
- DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, groupedSubElementGeometries, Id, EntityType);
- //Group group = doc.Create.NewGroup(subElementIds);
-
- if (directShape != null)
+ if (Importer.TheOptions.IsHybridImport)
{
- CreatedElementId = directShape.Id;
- CreatedGeometry = groupedSubElementGeometries;
-
- if (groupedSubElementFootprintCurves.Count != 0 && this is IFCProduct)
+ DirectShape containerDirectShape = doc.GetElement(CreatedElementId) as DirectShape;
+ if (containerDirectShape != null)
{
- using (IFCImportShapeEditScope planViewScope = IFCImportShapeEditScope.Create(doc, this as IFCProduct))
+ if (groupedSubElementGeometries != null)
{
- planViewScope.AddPlanViewCurves(groupedSubElementFootprintCurves, Id);
- planViewScope.SetPlanViewRep(directShape);
+ containerDirectShape.AppendShape(groupedSubElementGeometries);
}
+ AddPlanViewCurves(doc, containerDirectShape, groupedSubElementFootprintCurves);
+ return;
}
}
- else
- Importer.TheLog.LogCreationError(this, null, false);
+
+ // If CreateDuplicateContainerGeometry is false, then
+ // groupedSubElementGeometries is empty and we then create a new
+ // DirectShape with no content in it.
+ //
+ // For files such as NW-55644 that has geometry on the slab element and
+ // children with geometry, this means that the slab geometry is thrown away
+ if (groupedSubElementGeometries.Count == 0 && !Importer.TheOptions.IsHybridImport)
+ {
+ return;
+ }
+ }
+
+ if (CreatedElementId != ElementId.InvalidElementId)
+ subElementIds.Add(CreatedElementId);
+
+ // We aren't yet actually grouping the elements. DirectShape doesn't support grouping, and
+ // the Group element doesn't support adding parameters. For now, we will create a DirectShape that "forgets"
+ // the association, which is good enough for link.
+ DirectShape directShape = IFCElementUtil.CreateElement(doc, GetCategoryId(doc), GlobalId, groupedSubElementGeometries, Id, EntityType);
+ //Group group = doc.Create.NewGroup(subElementIds);
+
+ if (directShape != null)
+ {
+ CreatedElementId = directShape.Id;
+ CreatedGeometry = groupedSubElementGeometries;
+ AddPlanViewCurves(doc, directShape, groupedSubElementFootprintCurves);
+ }
+ else
+ {
+ Importer.TheLog.LogCreationError(this, null, false);
}
}
}
@@ -501,9 +554,19 @@ protected override void Process(IFCAnyHandle ifcObjectDefinition)
PredefinedType = GetPredefinedType(ifcObjectDefinition);
+ ElementId createdElementId = ElementId.InvalidElementId;
+ if (Importer.TheOptions.IsHybridImport)
+ {
+ Importer.TheHybridInfo?.HybridMap?.TryGetValue(GlobalId, out createdElementId);
+ }
+
// If we aren't importing this category, skip processing.
if (!IFCCategoryUtil.CanImport(EntityType, PredefinedType))
+ {
+ if (createdElementId != ElementId.InvalidElementId)
+ Importer.TheHybridInfo.ElementsToDelete?.Add(createdElementId);
throw new InvalidOperationException("Don't Import");
+ }
HashSet nests = IFCAnyHandleUtil.GetAggregateInstanceAttribute>(ifcObjectDefinition, "Nests");
if (nests != null && nests.Count != 0)
@@ -533,11 +596,17 @@ protected override void Process(IFCAnyHandle ifcObjectDefinition)
foreach (IFCAnyHandle hasAssociation in hasAssociations)
{
if (IFCAnyHandleUtil.IsSubTypeOf(hasAssociation, IFCEntityType.IfcRelAssociatesMaterial))
+ {
ProcessIFCRelAssociatesMaterial(hasAssociation);
+ }
else if (IFCAnyHandleUtil.IsSubTypeOf(hasAssociation, IFCEntityType.IfcRelAssociatesClassification))
+ {
ProcessRelAssociatesClassification(hasAssociation);
+ }
else
+ {
Importer.TheLog.LogUnhandledSubTypeError(hasAssociation, IFCEntityType.IfcRelAssociates, false);
+ }
}
}
@@ -792,10 +861,9 @@ private void SetName(Document doc, Element element, Category category)
}
}
- string name = string.IsNullOrWhiteSpace(Name) ? "" : Name;
// 2015: Revit links don't show the name of a selected item inside the link.
// 2015: DirectShapes don't have a built-in "Name" parameter.
- IFCPropertySet.AddParameterString(doc, element, category, this, IFCSharedParameters.IfcName, Name, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, IFCSharedParameters.IfcName, Name, Id);
}
///
@@ -810,9 +878,18 @@ private void SetDescription(Document doc, Element element, Category category)
// If the element has the built-in ALL_MODEL_DESCRIPTION parameter, populate that also.
// We will create/populate the parameter even if the description is empty or null.
string description = string.IsNullOrWhiteSpace(Description) ? string.Empty : Description;
- Importer.TheProcessor.SetStringParameter(element, Id, BuiltInParameter.ALL_MODEL_DESCRIPTION, description, true);
-
- IFCPropertySet.AddParameterString(doc, element, category, this, IFCSharedParameters.IfcDescription, description, Id);
+
+ IFCDefaultProcessor processor = Importer.TheProcessor as IFCDefaultProcessor;
+ if (processor != null)
+ {
+ processor.SetElementStringParameter(element, Id, BuiltInParameter.ALL_MODEL_DESCRIPTION, description, true, ParametersToSet);
+ }
+ else
+ {
+ Importer.TheProcessor.SetStringParameter(element, Id, BuiltInParameter.ALL_MODEL_DESCRIPTION, description, true);
+ }
+
+ ParametersToSet.AddStringParameter(doc, element, category, this, IFCSharedParameters.IfcDescription, description, Id);
}
///
@@ -839,7 +916,7 @@ private void SetMaterialParameter(Document doc, Element element, Category catego
materialNames += ";" + val;
}
if (materialNames != null)
- IFCPropertySet.AddParameterString(doc, element, category, this, IFCSharedParameters.IfcMaterial, materialNames, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, IFCSharedParameters.IfcMaterial, materialNames, Id);
}
///
@@ -882,7 +959,7 @@ private void SetGroupsParameter(IList groups, string parameterName, Do
if (category == null)
return;
- string groupNames = String.Empty;
+ string groupNames = string.Empty;
foreach (IFCGroup group in groups)
{
@@ -890,14 +967,14 @@ private void SetGroupsParameter(IList groups, string parameterName, Do
if (string.IsNullOrWhiteSpace(name))
continue;
- if (!String.IsNullOrEmpty(groupNames))
+ if (!string.IsNullOrEmpty(groupNames))
groupNames += ";";
groupNames += name;
}
- if (!String.IsNullOrEmpty(groupNames))
- IFCPropertySet.AddParameterString(doc, element, category, this, parameterName, groupNames, Id);
+ if (!string.IsNullOrEmpty(groupNames))
+ ParametersToSet.AddStringParameter(doc, element, category, this, parameterName, groupNames, Id);
}
///
@@ -943,8 +1020,11 @@ protected virtual void CreateParametersInternal(Document doc, Element element)
{
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- Importer.TheProcessor.CreateOrUpdateElement(Id, GlobalId, EntityType.ToString(), CategoryId.Value, null);
-
+ if (!Importer.IsDefaultProcessor())
+ {
+ Importer.TheProcessor.CreateOrUpdateElement(Id, GlobalId, EntityType.ToString(), GetCategoryId(doc).Value, null);
+ }
+
// Set the element name.
SetName(doc, element, category);
@@ -957,11 +1037,20 @@ protected virtual void CreateParametersInternal(Document doc, Element element)
// Set the "IfcSystem" and "IfcGroup" parameters.
SetSystemAndGroupParameter(doc, element, category);
+ IFCDefaultProcessor processor = Importer.TheProcessor as IFCDefaultProcessor;
+
bool elementIsType = (element is ElementType);
if (!string.IsNullOrWhiteSpace(GlobalId))
{
BuiltInParameter ifcGUIDId = GetGUIDParameter(element, elementIsType);
- Importer.TheProcessor.SetStringParameter(element, Id, ifcGUIDId, GlobalId, true);
+ if (processor != null)
+ {
+ processor.SetElementStringParameter(element, Id, ifcGUIDId, GlobalId, true, ParametersToSet);
+ }
+ else
+ {
+ Importer.TheProcessor.SetStringParameter(element, Id, ifcGUIDId, GlobalId, true);
+ }
}
// Set the built-in parameters.
@@ -969,21 +1058,35 @@ protected virtual void CreateParametersInternal(Document doc, Element element)
if (!string.IsNullOrWhiteSpace(entityName))
{
BuiltInParameter ifcExportElementAsParam = elementIsType ? BuiltInParameter.IFC_EXPORT_ELEMENT_TYPE_AS : BuiltInParameter.IFC_EXPORT_ELEMENT_AS;
- Importer.TheProcessor.SetStringParameter(element, Id, ifcExportElementAsParam, entityName, true);
+ if (processor != null)
+ {
+ processor.SetElementStringParameter(element, Id, ifcExportElementAsParam, entityName, true, ParametersToSet);
+ }
+ else
+ {
+ Importer.TheProcessor.SetStringParameter(element, Id, ifcExportElementAsParam, entityName, true);
+ }
}
if (!string.IsNullOrWhiteSpace(predefinedType))
{
BuiltInParameter ifcPredefinedTypeParam = elementIsType ? BuiltInParameter.IFC_EXPORT_PREDEFINEDTYPE_TYPE : BuiltInParameter.IFC_EXPORT_PREDEFINEDTYPE;
- Importer.TheProcessor.SetStringParameter(element, Id, ifcPredefinedTypeParam, predefinedType, true);
+ if (processor != null)
+ {
+ processor.SetElementStringParameter(element, Id, ifcPredefinedTypeParam, predefinedType, true, ParametersToSet);
+ }
+ else
+ {
+ Importer.TheProcessor.SetStringParameter(element, Id, ifcPredefinedTypeParam, predefinedType, true);
+ }
}
// Set the IFCElementAssembly Parameter
if (Decomposes != null)
{
string containerParamName = (Decomposes is IFCElementAssembly) ? "IfcElementAssembly" : "IfcDecomposes";
string containerParamGUIDName = (Decomposes is IFCElementAssembly) ? "IfcElementAssemblyGUID" : "IfcDecomposesGUID";
- IFCPropertySet.AddParameterString(doc, element, category, this, containerParamName, Decomposes.Name, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, containerParamGUIDName, Decomposes.GlobalId, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, containerParamName, Decomposes.Name, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, containerParamGUIDName, Decomposes.GlobalId, Id);
}
// Set additional parameters (if any), e.g. for Classification assignments
@@ -992,13 +1095,22 @@ protected virtual void CreateParametersInternal(Document doc, Element element)
foreach (KeyValuePair parItem in AdditionalIntParameters)
{
if (parItem.Value is string)
- IFCPropertySet.AddParameterString(doc, element, category, this, parItem.Key, (string)parItem.Value, Id);
+ {
+ ParametersToSet.AddStringParameter(doc, element, category, this, parItem.Key,
+ (string)parItem.Value, Id);
+ }
else if (parItem.Value is double)
- IFCPropertySet.AddParameterDouble(doc, element, category, this, parItem.Key, SpecTypeId.Custom, UnitTypeId.General, (double)parItem.Value, Id);
+ {
+ ParametersToSet.AddParameterDouble(doc, element, category, this, parItem.Key, SpecTypeId.Custom, UnitTypeId.General, (double)parItem.Value, Id);
+ }
else if (parItem.Value is int)
- IFCPropertySet.AddParameterInt(doc, element, category, this, parItem.Key, (int)parItem.Value, Id);
+ {
+ ParametersToSet.AddParameterInt(doc, element, category, this, parItem.Key, (int)parItem.Value, Id);
+ }
else if (parItem.Value is bool)
- IFCPropertySet.AddParameterBoolean(doc, element, category, this, parItem.Key, (bool)parItem.Value, Id);
+ {
+ ParametersToSet.AddParameterBoolean(doc, element, category, this, parItem.Key, (bool)parItem.Value, Id);
+ }
}
}
}
@@ -1015,12 +1127,16 @@ protected void CreateParameters(Document doc)
return;
// Create Revit parameters corresponding to IFC entity values, not in a property set.
- CreateParametersInternal(doc, element);
+ using (ParameterSetter setter = new ParameterSetter())
+ {
+ ParametersToSet = setter.ParametersToSet;
+ CreateParametersInternal(doc, element);
- // Now create parameters related to property sets. Note we want to add the parameters above first,
- // so we can use them for creating schedules in CreatePropertySets.
- string propertySetsCreated = "";
- CreatePropertySets(doc, element, propertySetsCreated);
+ // Now create parameters related to property sets. Note we want to add the parameters above first,
+ // so we can use them for creating schedules in CreatePropertySets.
+ string propertySetsCreated = "";
+ CreatePropertySets(doc, element, propertySetsCreated);
+ }
}
///
@@ -1048,15 +1164,14 @@ public static ElementId CreateElement(Document doc, IFCObjectDefinition objDef)
{
if ((createdElementId == ElementId.InvalidElementId) && objDef.IsValidForCreation)
{
- ElementId gstyleId;
- objDef.CategoryId = IFCCategoryUtil.GetCategoryIdForEntity(doc, objDef, out gstyleId);
- objDef.GraphicsStyleId = gstyleId;
-
if (objDef is IFCObject)
{
IFCObject asObject = objDef as IFCObject;
foreach (IFCTypeObject typeObject in asObject.TypeObjects)
- IFCObjectDefinition.CreateElement(doc, typeObject);
+ {
+ typeObject.CalculateCategoryAndGStyleIdsFromObject(doc, asObject);
+ CreateElement(doc, typeObject);
+ }
}
objDef.Create(doc);
@@ -1095,7 +1210,8 @@ protected void CreatePropertySetsBase(Document doc, Element element, string prop
IFCParameterSetByGroup parameterGroupMap = IFCParameterSetByGroup.Create(element);
foreach (IFCPropertySetDefinition propertySet in propertySets.Values)
{
- Tuple newPropertySetCreated = propertySet.CreatePropertySet(doc, element, this, parameterGroupMap);
+ Tuple newPropertySetCreated = propertySet.CreatePropertySet(doc, element, this,
+ parameterGroupMap, ParametersToSet);
if (newPropertySetCreated == null || !newPropertySetCreated.Item2 || string.IsNullOrWhiteSpace(newPropertySetCreated.Item1))
continue;
@@ -1108,7 +1224,7 @@ protected void CreatePropertySetsBase(Document doc, Element element, string prop
// Add property set-based parameters.
// We are going to create this "fake" parameter so that we can filter elements in schedules based on their property sets.
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, propertySetListName, propertySetsCreated, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, propertySetListName, propertySetsCreated, Id);
}
///
diff --git a/Source/Revit.IFC.Import/Data/IFCPhysicalComplexQuantity.cs b/Source/Revit.IFC.Import/Data/IFCPhysicalComplexQuantity.cs
index dd532703..36c89d14 100644
--- a/Source/Revit.IFC.Import/Data/IFCPhysicalComplexQuantity.cs
+++ b/Source/Revit.IFC.Import/Data/IFCPhysicalComplexQuantity.cs
@@ -139,12 +139,15 @@ public static IFCPhysicalComplexQuantity ProcessIFCPhysicalComplexQuantity(IFCAn
/// The parameters.
/// The name of the containing quantity set with quantity name.
/// The names of the created parameters.
- public override void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap, string quantityFullName, ISet createdParameters)
+ public override void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, string quantityFullName, ISet createdParameters,
+ ParametersToSet parametersToSet)
{
foreach (IFCPhysicalQuantity quantity in HasQuantities)
{
string complexFullName = AppendComplexQuantityName(quantityFullName, quantity.Name);
- quantity.Create(doc, element, category, objDef, parameterGroupMap, complexFullName, createdParameters);
+ quantity.Create(doc, element, category, objDef, parameterGroupMap, complexFullName, createdParameters,
+ parametersToSet);
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCPhysicalQuantity.cs b/Source/Revit.IFC.Import/Data/IFCPhysicalQuantity.cs
index b7a7d683..9ca2779f 100644
--- a/Source/Revit.IFC.Import/Data/IFCPhysicalQuantity.cs
+++ b/Source/Revit.IFC.Import/Data/IFCPhysicalQuantity.cs
@@ -112,6 +112,8 @@ public static IFCPhysicalQuantity ProcessIFCPhysicalQuantity(IFCAnyHandle ifcPhy
/// The parameters of the element. Cached for performance.
/// The name of the containing quantity set with quantity name.
/// The names of the created parameters.
- public abstract void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap, string quantityFullName, ISet createdParameters);
+ public abstract void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, string quantityFullName, ISet createdParameters,
+ ParametersToSet parametersToSet);
}
}
\ No newline at end of file
diff --git a/Source/Revit.IFC.Import/Data/IFCPhysicalSimpleQuantity.cs b/Source/Revit.IFC.Import/Data/IFCPhysicalSimpleQuantity.cs
index 12f4143c..21f78326 100644
--- a/Source/Revit.IFC.Import/Data/IFCPhysicalSimpleQuantity.cs
+++ b/Source/Revit.IFC.Import/Data/IFCPhysicalSimpleQuantity.cs
@@ -141,7 +141,9 @@ public static IFCPhysicalSimpleQuantity ProcessIFCPhysicalSimpleQuantity(IFCAnyH
/// The parameters of the element. Cached for performance.
/// The name of the containing quantity set with quantity name.
/// The names of the created parameters.
- public override void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap, string quantityFullName, ISet createdParameters)
+ public override void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, string quantityFullName, ISet createdParameters,
+ ParametersToSet parametersToSet)
{
double baseValue = 0.0;
IFCDataPrimitiveType type = Value.PrimitiveType;
@@ -194,7 +196,7 @@ public override void Create(Document doc, Element element, Category category, IF
specTypeId = IFCDataUtil.GetUnitTypeFromData(Value, SpecTypeId.Number);
}
- bool created = IFCPropertySet.AddParameterDouble(doc, element, category, objDef, parameterName, specTypeId, unitsTypeId, doubleValueToUse, Id);
+ bool created = parametersToSet.AddParameterDouble(doc, element, category, objDef, parameterName, specTypeId, unitsTypeId, doubleValueToUse, Id);
if (created)
createdParameters.Add(parameterName);
@@ -206,10 +208,10 @@ public override void Create(Document doc, Element element, Category category, IF
switch (existingParameter.StorageType)
{
case StorageType.String:
- existingParameter.Set(doubleValueToUse.ToString());
+ parametersToSet.AddStringParameter(existingParameter, doubleValueToUse.ToString());
break;
case StorageType.Double:
- existingParameter.Set(doubleValueToUse);
+ parametersToSet.AddDoubleParameter(existingParameter, doubleValueToUse);
break;
default:
setValue = false;
diff --git a/Source/Revit.IFC.Import/Data/IFCPort.cs b/Source/Revit.IFC.Import/Data/IFCPort.cs
index 4eb4c667..904211c6 100644
--- a/Source/Revit.IFC.Import/Data/IFCPort.cs
+++ b/Source/Revit.IFC.Import/Data/IFCPort.cs
@@ -177,33 +177,33 @@ protected override void CreateParametersInternal(Document doc, Element element)
{
string guid = portOwner.GlobalId;
if (!string.IsNullOrWhiteSpace(guid))
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcElement ContainedIn IfcGUID", guid, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcElement ContainedIn IfcGUID", guid, Id);
string name = portOwner.Name;
if (!string.IsNullOrWhiteSpace(name))
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcElement ContainedIn Name", name, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcElement ContainedIn Name", name, Id);
}
if (ConnectedFrom != null)
{
string guid = ConnectedFrom.GlobalId;
if (!string.IsNullOrWhiteSpace(guid))
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcPort ConnectedFrom IfcGUID", guid, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcPort ConnectedFrom IfcGUID", guid, Id);
string name = ConnectedFrom.Name;
if (!string.IsNullOrWhiteSpace(name))
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcPort ConnectedFrom Name", name, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcPort ConnectedFrom Name", name, Id);
}
if (ConnectedTo != null)
{
string guid = ConnectedTo.GlobalId;
if (!string.IsNullOrWhiteSpace(guid))
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcPort ConnectedTo IfcGUID", guid, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcPort ConnectedTo IfcGUID", guid, Id);
string name = ConnectedTo.Name;
if (!string.IsNullOrWhiteSpace(name))
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcPort ConnectedTo Name", name, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcPort ConnectedTo Name", name, Id);
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCProduct.cs b/Source/Revit.IFC.Import/Data/IFCProduct.cs
index c1d726fb..326d2785 100644
--- a/Source/Revit.IFC.Import/Data/IFCProduct.cs
+++ b/Source/Revit.IFC.Import/Data/IFCProduct.cs
@@ -1,4 +1,4 @@
-//
+//
// Revit IFC Import library: this library works with Autodesk(R) Revit(R) to import IFC files.
// Copyright (C) 2013 Autodesk, Inc.
//
@@ -112,19 +112,9 @@ protected override void Process(IFCAnyHandle ifcProduct)
IFCAnyHandle ifcProductRepresentation = IFCImportHandleUtil.GetOptionalInstanceAttribute(ifcProduct, "Representation");
if (!IFCAnyHandleUtil.IsNullOrHasNoValue(ifcProductRepresentation))
{
- // IFCRepresentationItem should know that it is processing something for Hybrid IFC Imports.
- // Then it will create IFCHybridRepresentationItems, which are placeholders for body geometry created via AnyCAD.
- // This is so data for Representation Item will still exist, even if legacy geometry does not.
- if ((Importer.TheOptions.IsHybridImport) && (Importer.TheHybridInfo?.HybridMap?.ContainsKey(GlobalId) ?? false))
- {
- Importer.TheHybridInfo.RepresentationsAlreadyCreated = true;
- }
-
- ProductRepresentation = IFCProductRepresentation.ProcessIFCProductRepresentation(ifcProductRepresentation);
-
- if ((Importer.TheOptions.IsHybridImport) && (Importer.TheHybridInfo?.RepresentationsAlreadyCreated ?? false))
- {
- Importer.TheHybridInfo.RepresentationsAlreadyCreated = false;
+ using (RepresentationsAlreadyCreatedSetter setter = new RepresentationsAlreadyCreatedSetter(GlobalId))
+ {
+ ProductRepresentation = IFCProductRepresentation.ProcessIFCProductRepresentation(ifcProductRepresentation);
}
}
}
@@ -188,14 +178,14 @@ protected override void CreateParametersInternal(Document doc, Element element)
}
if (ifcPresentationLayer != null)
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcPresentationLayer", ifcPresentationLayer, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcPresentationLayer", ifcPresentationLayer, Id);
// Set the container name of the element.
string containerName = ContainingStructure?.Name;
if (containerName != null)
{
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcSpatialContainer", containerName, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcSpatialContainer GUID", ContainingStructure.GlobalId, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcSpatialContainer", containerName, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcSpatialContainer GUID", ContainingStructure.GlobalId, Id);
}
}
}
@@ -308,6 +298,18 @@ protected override bool CutSolidByVoids(IFCSolidInfo solidInfo)
return true;
}
+ private Transform CalculateLocalCoordinateSystem()
+ {
+ Transform lcs = IFCImportFile.TheFile.IFCProject.WorldCoordinateSystem;
+ if (lcs == null)
+ return ObjectLocation?.TotalTransform ?? Transform.Identity;
+
+ if (ObjectLocation != null)
+ return lcs.Multiply(ObjectLocation.TotalTransform);
+
+ return lcs;
+ }
+
///
/// Creates or populates Revit elements based on the information contained in this class.
///
@@ -362,28 +364,10 @@ protected override void Create(Document doc)
// IFCImportShapeEditScope will not create Body geometry for Hybrid IFC Import, but it may need to create other geometry.
using (IFCImportShapeEditScope shapeEditScope = IFCImportShapeEditScope.Create(doc, this))
{
- shapeEditScope.GraphicsStyleId = GraphicsStyleId;
- shapeEditScope.CategoryId = CategoryId;
+ Transform lcs = CalculateLocalCoordinateSystem();
+
shapeEditScope.PreventInstances = preventInstances;
- // The name can be added as well. but it is usually less useful than 'oid'
- string myId = GlobalId; // + "(" + Name + ")";
-
- Transform lcs = IFCImportFile.TheFile.IFCProject.WorldCoordinateSystem;
- if (lcs == null)
- lcs = (ObjectLocation != null) ? ObjectLocation.TotalTransform : Transform.Identity;
- else if (ObjectLocation != null)
- lcs = lcs.Multiply(ObjectLocation.TotalTransform);
-
- // If we are not applying transforms to the geometry, then pass in the identity matrix.
- // Lower down this method we then pass lcs to the consumer element, so that it can apply
- // the transform as required.
- Transform transformToUse = Importer.TheProcessor.ApplyTransforms ? lcs : Transform.Identity;
- if (Importer.TheOptions.IsHybridImport && (Importer.TheHybridInfo != null))
- {
- transformToUse = transformToUse.Multiply(Importer.TheHybridInfo.LargeCoordinateTransform);
- }
-
// Hybrid Import only: An IfcProduct whose DirectShape will be a container might not have a DirectShape created yet.
// If this is the case, create an empty DirectShape for the container.
// If so, create an empty DirectShape to hold container Geometry.
@@ -395,11 +379,22 @@ protected override void Create(Document doc)
Importer.TheLog.LogComment(Id, $"Creating Empty Container for {GlobalId}:{CreatedElementId}", false);
}
}
-
- // For Hybrid Import Containers, there may be the possibility that there is no valid top-level Geometry. In that
- // case, don't create the ProductRepresentation.
+
if (HasValidTopLevelGeometry())
{
+ // If we are not applying transforms to the geometry, then pass in the identity matrix.
+ // Lower down this method we then pass lcs to the consumer element, so that it can apply
+ // the transform as required.
+ Transform transformToUse = Importer.TheProcessor.ApplyTransforms ? lcs : Transform.Identity;
+ if (Importer.TheOptions.IsHybridImport && (
+ Importer.TheHybridInfo != null))
+ {
+ transformToUse.Origin += Importer.TheHybridInfo.LargeCoordinateOriginOffset;
+ }
+
+ // The name can be added as well. but it is usually less useful than 'oid'
+ string myId = GlobalId; // + "(" + Name + ")";
+
ProductRepresentation.CreateProductRepresentation(shapeEditScope, transformToUse, myId);
}
@@ -407,14 +402,13 @@ protected override void Create(Document doc)
// geometry, but it will contain parameters that are needed for the DirectShape imported for Hybrid IFC Import.
if (Importer.TheOptions.IsHybridImport && GlobalId != null)
{
- // "Create" a DirectShape Element.
- // This is for those Elements imported via the ATF Pipeline, or for those Elements created above simply to hold an empty container.
- ElementId hybridElementId = ElementId.InvalidElementId;
- if (Importer.TheHybridInfo?.HybridMap?.TryGetValue(GlobalId, out hybridElementId) ?? false)
+ if ((Importer.TheHybridInfo?.HybridMap?.TryGetValue(GlobalId, out ElementId hybridElementId) ?? false) &&
+ hybridElementId != ElementId.InvalidElementId)
{
- // If GlobalId is in the HybridMap, handle Hybrid Product Creation from Hybrid Import.
+ // "Create" a DirectShape Element.
+ // This is for those Elements imported via the ATF Pipeline, or for those Elements created above simply to hold an empty container.
+ CreatedGeometry = Importer.TheHybridInfo.HandleHybridProductCreation(shapeEditScope, this, ref hybridElementId);
CreatedElementId = hybridElementId;
- CreatedElementId = Importer.TheHybridInfo.HandleHybridProductCreation(shapeEditScope, this);
}
}
@@ -443,7 +437,9 @@ protected override void Create(Document doc)
DirectShape shape = Importer.TheCache.UseElementByGUID(doc, GlobalId);
if (shape == null)
- shape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, null, Id, EntityType);
+ {
+ shape = IFCElementUtil.CreateElement(doc, GetCategoryId(doc), GlobalId, null, Id, EntityType);
+ }
List directShapeGeometries = new List();
foreach (IFCSolidInfo geometryObject in Solids)
diff --git a/Source/Revit.IFC.Import/Data/IFCProject.cs b/Source/Revit.IFC.Import/Data/IFCProject.cs
index 9ea19f8f..e3c94caa 100644
--- a/Source/Revit.IFC.Import/Data/IFCProject.cs
+++ b/Source/Revit.IFC.Import/Data/IFCProject.cs
@@ -215,30 +215,39 @@ protected override void Process(IFCAnyHandle ifcProjectHandle)
// we should probably augment Processor.AddParameter to ensure that CreateOrUpdateElement
// is called before anything is attempted to be added. This is a special case, though,
// as in Revit we don't actually create an element for the IfcProject.
- Importer.TheProcessor.CreateOrUpdateElement(Id, GlobalId, EntityType.ToString(), CategoryId.Value, null);
+ if (!Importer.IsDefaultProcessor())
+ {
+ Importer.TheProcessor.CreateOrUpdateElement(Id, GlobalId, EntityType.ToString(), GetCategoryId(doc).Value, null);
+ }
Category category = IFCPropertySet.GetCategoryForParameterIfValid(projectInfo, Id);
- IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.Name", geoRefName, Id);
- if (!string.IsNullOrEmpty(desc))
- IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.Description", desc, Id);
- if (!string.IsNullOrEmpty(geodeticDatum))
- IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.GeodeticDatum", geodeticDatum, Id);
- if (!string.IsNullOrEmpty(verticalDatum))
- IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.VerticalDatum", verticalDatum, Id);
- if (!string.IsNullOrEmpty(mapProj))
- IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.MapProjection", mapProj, Id);
- if (!string.IsNullOrEmpty(mapZone))
- IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.MapZone", mapZone, Id);
- if (!IFCAnyHandleUtil.IsNullOrHasNoValue(mapUnit))
+
+ using (ParameterSetter setter = new ParameterSetter())
{
- IFCUnit mapUnitIfc = IFCUnit.ProcessIFCUnit(mapUnit);
- string unitStr = UnitUtils.GetTypeCatalogStringForUnit(mapUnitIfc.Unit);
- IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.MapUnit", unitStr, Id);
- double convFactor = UnitUtils.Convert(1.0, mapUnitIfc.Unit, IFCImportFile.TheFile.IFCUnits.GetIFCProjectUnit(SpecTypeId.Length).Unit);
- eastings = convFactor * eastings;
- northings = convFactor * northings;
- orthogonalHeight = convFactor * orthogonalHeight;
- geoRef = new XYZ(eastings, northings, orthogonalHeight);
+ ParametersToSet parametersToSet = setter.ParametersToSet;
+ parametersToSet.AddStringParameter(doc, projectInfo, category, this, "IfcProjectedCRS.Name", geoRefName, Id);
+ if (!string.IsNullOrEmpty(desc))
+ parametersToSet.AddStringParameter(doc, projectInfo, category, this, "IfcProjectedCRS.Description", desc, Id);
+ if (!string.IsNullOrEmpty(geodeticDatum))
+ parametersToSet.AddStringParameter(doc, projectInfo, category, this, "IfcProjectedCRS.GeodeticDatum", geodeticDatum, Id);
+ if (!string.IsNullOrEmpty(verticalDatum))
+ parametersToSet.AddStringParameter(doc, projectInfo, category, this, "IfcProjectedCRS.VerticalDatum", verticalDatum, Id);
+ if (!string.IsNullOrEmpty(mapProj))
+ parametersToSet.AddStringParameter(doc, projectInfo, category, this, "IfcProjectedCRS.MapProjection", mapProj, Id);
+ if (!string.IsNullOrEmpty(mapZone))
+ parametersToSet.AddStringParameter(doc, projectInfo, category, this, "IfcProjectedCRS.MapZone", mapZone, Id);
+
+ if (!IFCAnyHandleUtil.IsNullOrHasNoValue(mapUnit))
+ {
+ IFCUnit mapUnitIfc = IFCUnit.ProcessIFCUnit(mapUnit);
+ string unitStr = UnitUtils.GetTypeCatalogStringForUnit(mapUnitIfc.Unit);
+ parametersToSet.AddStringParameter(doc, projectInfo, category, this, "IfcProjectedCRS.MapUnit", unitStr, Id);
+ double convFactor = UnitUtils.Convert(1.0, mapUnitIfc.Unit, IFCImportFile.TheFile.IFCUnits.GetIFCProjectUnit(SpecTypeId.Length).Unit);
+ eastings = convFactor * eastings;
+ northings = convFactor * northings;
+ orthogonalHeight = convFactor * orthogonalHeight;
+ geoRef = new XYZ(eastings, northings, orthogonalHeight);
+ }
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCProperty.cs b/Source/Revit.IFC.Import/Data/IFCProperty.cs
index a74c3b91..beb043c3 100644
--- a/Source/Revit.IFC.Import/Data/IFCProperty.cs
+++ b/Source/Revit.IFC.Import/Data/IFCProperty.cs
@@ -24,6 +24,8 @@
using Revit.IFC.Common.Utility;
using Revit.IFC.Common.Enums;
using Revit.IFC.Import.Utility;
+using Revit.IFC.Import.Core;
+using System.Runtime.Remoting;
namespace Revit.IFC.Import.Data
{
@@ -114,6 +116,18 @@ private bool IsValidParameterType(Parameter parameter, IFCDataPrimitiveType data
return false;
}
+ private bool AddStringTypeParameter(bool multilineTableProperty, Document doc, Element element, Category category,
+ IFCObjectDefinition objDef, string parameterName, string stringValueToUse, ParametersToSet parametersToSet)
+ {
+ if (multilineTableProperty)
+ {
+ return parametersToSet.AddParameterMultilineString(doc, element, category, objDef, parameterName,
+ stringValueToUse, Id);
+ }
+
+ return parametersToSet.AddStringParameter(doc, element, category, objDef, parameterName, stringValueToUse, Id);
+ }
+
///
/// Create a property for a given element.
///
@@ -123,7 +137,9 @@ private bool IsValidParameterType(Parameter parameter, IFCDataPrimitiveType data
/// The parameters of the element. Cached for performance.
/// The name of the containing property set.
/// The names of the created parameters.
- public void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap, string propertyFullName, ISet createdParameters)
+ public void Create(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, string propertyFullName, ISet createdParameters,
+ ParametersToSet parametersToSet)
{
// Try to get the single value from the property. If we can't get a single value, get it as a string.
IFCPropertyValue propertyValueToUse = null;
@@ -258,25 +274,26 @@ public void Create(Document doc, Element element, Category category, IFCObjectDe
case IFCDataPrimitiveType.String:
case IFCDataPrimitiveType.Enumeration:
case IFCDataPrimitiveType.Binary:
- created = multilineTableProperty ? IFCPropertySet.AddParameterMultilineString(doc, element, category, objDef, parameterName, stringValueToUse, Id):
- IFCPropertySet.AddParameterString(doc, element, category, objDef, parameterName, stringValueToUse, Id);
+ created = AddStringTypeParameter(multilineTableProperty, doc, element, category,
+ objDef, parameterName, stringValueToUse, parametersToSet);
break;
case IFCDataPrimitiveType.Integer:
- created = IFCPropertySet.AddParameterInt(doc, element, category, objDef, parameterName, intValueToUse.Value, Id);
+ created = parametersToSet.AddParameterInt(doc, element, category, objDef, parameterName,
+ intValueToUse.Value, Id);
break;
case IFCDataPrimitiveType.Boolean:
- created = IFCPropertySet.AddParameterBoolean(doc, element, category, objDef, parameterName, boolValueToUse.Value, Id);
+ created = parametersToSet.AddParameterBoolean(doc, element, category, objDef, parameterName, boolValueToUse.Value, Id);
break;
case IFCDataPrimitiveType.Logical:
if (logicalValueToUse != IFCLogical.Unknown)
- created = IFCPropertySet.AddParameterBoolean(doc, element, category, objDef, parameterName, (logicalValueToUse == IFCLogical.True), Id);
+ created = parametersToSet.AddParameterBoolean(doc, element, category, objDef, parameterName, (logicalValueToUse == IFCLogical.True), Id);
break;
case IFCDataPrimitiveType.Number:
case IFCDataPrimitiveType.Double:
- created = IFCPropertySet.AddParameterDouble(doc, element, category, objDef, parameterName, specTypeId, unitsTypeId, doubleValueToUse.Value, Id);
+ created = parametersToSet.AddParameterDouble(doc, element, category, objDef, parameterName, specTypeId, unitsTypeId, doubleValueToUse.Value, Id);
break;
case IFCDataPrimitiveType.Instance:
- created = IFCPropertySet.AddParameterElementId(doc, element, category, objDef, parameterName, elementIdValueToUse, Id);
+ created = parametersToSet.AddParameterElementId(doc, element, category, objDef, parameterName, elementIdValueToUse, Id);
break;
}
@@ -286,7 +303,6 @@ public void Create(Document doc, Element element, Category category, IFCObjectDe
return;
}
- bool couldSetValue = false;
switch (existingParameter.StorageType)
{
case StorageType.String:
@@ -296,20 +312,20 @@ public void Create(Document doc, Element element, Category category, IFCObjectDe
case IFCDataPrimitiveType.String:
case IFCDataPrimitiveType.Enumeration:
case IFCDataPrimitiveType.Binary:
- couldSetValue = existingParameter.Set(stringValueToUse);
+ parametersToSet.AddStringParameter(existingParameter, stringValueToUse);
break;
case IFCDataPrimitiveType.Integer:
- couldSetValue = existingParameter.Set(intValueToUse.Value.ToString());
+ parametersToSet.AddStringParameter(existingParameter, intValueToUse.Value.ToString());
break;
case IFCDataPrimitiveType.Boolean:
- couldSetValue = existingParameter.Set(boolValueToUse.Value ? "True" : "False");
+ parametersToSet.AddStringParameter(existingParameter, boolValueToUse.Value ? "True" : "False");
break;
case IFCDataPrimitiveType.Logical:
- couldSetValue = existingParameter.Set(logicalValueToUse.ToString());
+ parametersToSet.AddStringParameter(existingParameter, logicalValueToUse.ToString());
break;
case IFCDataPrimitiveType.Number:
case IFCDataPrimitiveType.Double:
- couldSetValue = existingParameter.Set(doubleValueToUse.ToString());
+ parametersToSet.AddStringParameter(existingParameter, doubleValueToUse.ToString());
break;
default:
break;
@@ -318,26 +334,23 @@ public void Create(Document doc, Element element, Category category, IFCObjectDe
break;
case StorageType.Integer:
if (dataType == IFCDataPrimitiveType.Integer)
- couldSetValue = existingParameter.Set(intValueToUse.Value);
+ parametersToSet.AddIntegerParameter(existingParameter, intValueToUse.Value);
else if (dataType == IFCDataPrimitiveType.Boolean)
- couldSetValue = existingParameter.Set(boolValueToUse.Value ? 1 : 0);
- else if (dataType == IFCDataPrimitiveType.Logical)
- couldSetValue = (logicalValueToUse == IFCLogical.Unknown) ? true : existingParameter.Set((logicalValueToUse == IFCLogical.True) ? 1 : 0);
+ parametersToSet.AddIntegerParameter(existingParameter, boolValueToUse.Value ? 1 : 0);
+ else if (dataType == IFCDataPrimitiveType.Logical && logicalValueToUse != IFCLogical.Unknown)
+ parametersToSet.AddIntegerParameter(existingParameter, (logicalValueToUse == IFCLogical.True) ? 1 : 0);
break;
case StorageType.Double:
if (dataType == IFCDataPrimitiveType.Double)
- couldSetValue = existingParameter.Set(doubleValueToUse.Value);
+ parametersToSet.AddDoubleParameter(existingParameter, doubleValueToUse.Value);
else if (dataType == IFCDataPrimitiveType.Integer)
- couldSetValue = existingParameter.Set(intValueToUse.Value);
+ parametersToSet.AddDoubleParameter(existingParameter, intValueToUse.Value);
else if (dataType == IFCDataPrimitiveType.Boolean)
- couldSetValue = existingParameter.Set(boolValueToUse.Value ? 1 : 0);
+ parametersToSet.AddDoubleParameter(existingParameter, boolValueToUse.Value ? 1 : 0);
else if ((dataType == IFCDataPrimitiveType.Logical) && (logicalValueToUse != IFCLogical.Unknown))
- couldSetValue = existingParameter.Set((logicalValueToUse == IFCLogical.True) ? 1 : 0);
+ parametersToSet.AddDoubleParameter(existingParameter, (logicalValueToUse == IFCLogical.True) ? 1 : 0);
break;
}
-
- if (!couldSetValue)
- Importer.TheLog.LogError(Id, "Couldn't create parameter: " + Name + " of storage type: " + existingParameter.StorageType.ToString(), false);
}
}
}
\ No newline at end of file
diff --git a/Source/Revit.IFC.Import/Data/IFCPropertySet.cs b/Source/Revit.IFC.Import/Data/IFCPropertySet.cs
index 34d08846..e5860da1 100644
--- a/Source/Revit.IFC.Import/Data/IFCPropertySet.cs
+++ b/Source/Revit.IFC.Import/Data/IFCPropertySet.cs
@@ -105,289 +105,6 @@ private static bool IsDisallowedCategory(Category category)
return false;
}
- public static Parameter AddParameterBase(Document doc, Element element, Category category, string parameterName, int parameterSetId, ForgeTypeId specId)
- {
- bool isElementType = (element is ElementType);
- Definitions definitions = isElementType ? Importer.TheCache.TypeGroupDefinitions : Importer.TheCache.InstanceGroupDefinitions;
-
- bool newlyCreated = false;
- Definition definition = definitions.get_Item(parameterName);
- if (definition == null)
- {
- ExternalDefinitionCreationOptions option = new ExternalDefinitionCreationOptions(parameterName, specId);
- definition = definitions.Create(option);
- if (definition == null)
- {
- Importer.TheLog.LogError(parameterSetId, "Couldn't create parameter: " + parameterName, false);
- return null;
- }
- newlyCreated = true;
- }
-
- Guid guid = (definition as ExternalDefinition).GUID;
-
- Parameter parameter = null;
- ElementBinding binding = null;
- bool reinsert = false;
-
- if (!newlyCreated)
- {
- BindingMap bindingMap = Importer.TheCache.GetParameterBinding(doc);
- binding = bindingMap.get_Item(definition) as ElementBinding;
- reinsert = (binding != null);
- }
-
- if (binding == null)
- {
- if (isElementType)
- binding = new TypeBinding();
- else
- binding = new InstanceBinding();
- }
-
- // The binding can fail if we haven't identified a "bad" category above. Use try/catch as a safety net.
- try
- {
- if (!reinsert || !binding.Categories.Contains(category))
- {
- binding.Categories.Insert(category);
-
- BindingMap bindingMap = Importer.TheCache.GetParameterBinding(doc);
- if (reinsert)
- bindingMap.ReInsert(definition, binding, GroupTypeId.Ifc);
- else
- bindingMap.Insert(definition, binding, GroupTypeId.Ifc);
- }
-
- parameter = element.get_Parameter(guid);
- }
- catch
- {
- }
-
- if (parameter == null)
- Importer.TheLog.LogError(parameterSetId, "Couldn't create parameter: " + parameterName, false);
-
- return parameter;
- }
-
- ///
- /// Adds a parameter with the name of an element represented by an ElementId to an element.
- ///
- /// The document.
- /// The element.
- /// The category of the element.
- /// The parameter name.
- /// The parameter value.
- /// The id of the containing parameter set, for reporting errors.
- /// True if the parameter was successfully added, false otherwise.
- public static bool AddParameterElementId(Document doc, Element element, Category category, IFCObjectDefinition objDef, string parameterName, ElementId parameterValue, int parameterSetId)
- {
- if (doc == null || element == null || category == null)
- return false;
-
- Element parameterElement = doc.GetElement(parameterValue);
- if (parameterElement == null)
- return false;
-
- string name = parameterElement.Name;
- if (string.IsNullOrEmpty(name))
- return false;
-
- bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
- if (processedParameter.HasValue)
- return processedParameter.Value;
-
- Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.Text);
- if (parameter == null)
- return false;
-
- parameter.Set(name);
- return true;
- }
-
- ///
- /// Add a Boolean parameter to an element.
- ///
- /// The document.
- /// The element.
- /// The category of the element.
- /// The parameter name.
- /// The parameter value.
- /// The id of the containing parameter set, for reporting errors.
- /// True if the parameter was successfully added, false otherwise.
- public static bool AddParameterBoolean(Document doc, Element element, Category category, IFCObjectDefinition objDef, string parameterName, bool parameterValue, int parameterSetId)
- {
- if (doc == null || element == null || category == null)
- return false;
-
- bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
- if (processedParameter.HasValue)
- return processedParameter.Value;
-
- Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.Boolean.YesNo);
- if (parameter == null)
- return false;
-
- parameter.Set(parameterValue ? 1 : 0);
- return true;
- }
-
- ///
- /// Add an int parameter to an element.
- ///
- /// The document.
- /// The element.
- /// The category of the element.
- /// The parameter name.
- /// The parameter value.
- /// The id of the containing parameter set, for reporting errors.
- /// True if the parameter was successfully added, false otherwise.
- public static bool AddParameterInt(Document doc, Element element, Category category, IFCObjectDefinition objDef, string parameterName, int parameterValue, int parameterSetId)
- {
- if (doc == null || element == null || category == null)
- return false;
-
- bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
- if (processedParameter.HasValue)
- return processedParameter.Value;
-
- Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.Int.Integer);
- if (parameter == null)
- return false;
-
- parameter.Set(parameterValue);
- return true;
- }
-
- private static ForgeTypeId CalculateUnitsTypeId(ForgeTypeId unitsTypeId,
- ForgeTypeId specTypeId)
- {
- if (unitsTypeId != null || Importer.TheProcessor.ScaleValues)
- return unitsTypeId;
-
- // We can look up the units when the values are not scaled.
- var units = IFCImportFile.TheFile.IFCUnits.GetIFCProjectUnit(specTypeId);
- return (units != null) ? units.Unit : UnitTypeId.General;
- }
-
- ///
- /// Add a double parameter to an element.
- ///
- /// The document.
- /// The element.
- /// The category of the element.
- /// The parameter name.
- /// Identifier of the parameter spec (e.g. length)
- /// Identifier of the unscaled parameter units (e.g. mm)
- /// The parameter value, scaled into document units.
- /// The id of the containing parameter set, for reporting errors.
- /// True if the parameter was successfully added, false otherwise.
- public static bool AddParameterDouble(Document doc, Element element, Category category,
- IFCObjectDefinition objDef, string parameterName, ForgeTypeId specTypeId,
- ForgeTypeId unitsTypeId, double parameterValue, int parameterSetId)
- {
- if (doc == null || element == null || category == null)
- return false;
-
- unitsTypeId = CalculateUnitsTypeId(unitsTypeId, specTypeId);
- bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id,
- specTypeId, unitsTypeId, parameterSetId, parameterName, parameterValue);
- if (processedParameter.HasValue)
- return processedParameter.Value;
-
- Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, specTypeId);
- if (parameter == null)
- return false;
-
- parameter.Set(parameterValue);
- return true;
- }
-
- ///
- /// Add a string parameter to an element.
- ///
- /// The document.
- /// The element.
- /// The category of the element.
- /// The parameter name.
- /// The parameter value.
- /// The id of the containing parameter set, for reporting errors.
- /// True if the parameter was successfully added, false otherwise.
- public static bool AddParameterString(Document doc, Element element, Category category, IFCObjectDefinition objDef, string parameterName, string parameterValue, int parameterSetId)
- {
- if (doc == null || element == null || category == null)
- return false;
-
- bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
- if (processedParameter.HasValue)
- return processedParameter.Value;
-
- Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.Text);
- if (parameter == null)
- return false;
-
- parameter.Set(parameterValue);
- return true;
- }
-
- ///
- /// Add a multistring parameter to an element.
- ///
- /// The document.
- /// The element.
- /// The category of the element.
- /// The parameter name.
- /// The parameter value.
- /// The id of the containing parameter set, for reporting errors.
- /// True if the parameter was successfully added, false otherwise.
- public static bool AddParameterMultilineString(Document doc, Element element, Category category, IFCObjectDefinition objDef, string parameterName, string parameterValue, int parameterSetId)
- {
- if (doc == null || element == null || category == null)
- return false;
-
- bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
- if (processedParameter.HasValue)
- return processedParameter.Value;
-
- Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.MultilineText);
- if (parameter == null)
- return false;
-
- parameter.Set(parameterValue);
- return true;
- }
-
- ///
- /// Add a string parameter to an element.
- ///
- /// The document.
- /// The element.
- /// The category of the element.
- /// The IFCObjectDefinition that created the element.
- /// The enum corresponding to the parameter name.
- /// The parameter value.
- /// The id of the containing parameter set, for reporting errors.
- /// True if the parameter was successfully added, false otherwise.
- public static bool AddParameterString(Document doc, Element element, Category category, IFCObjectDefinition objDef, IFCSharedParameters name, string parameterValue, int parameterSetId)
- {
- if (doc == null || element == null || category == null || objDef == null)
- return false;
-
- string parameterName = objDef.GetSharedParameterName(name, element is ElementType);
-
- bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
- if (processedParameter.HasValue)
- return processedParameter.Value;
-
- Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.Text);
- if (parameter == null)
- return false;
-
- parameter.Set(parameterValue);
- return true;
- }
-
public static Category GetCategoryForParameterIfValid(Element element, int id)
{
Category category = element.Category;
@@ -415,7 +132,8 @@ public static Category GetCategoryForParameterIfValid(Element element, int id)
/// The element being created.
/// The parameters of the element. Cached for performance.
/// The name of the property set created, if it was created, and a Boolean value if it should be added to the property set list.
- public override Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap)
+ public override Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, ParametersToSet parametersToSet)
{
Category category = GetCategoryForParameterIfValid(element, Id);
if (category == null)
@@ -429,7 +147,8 @@ public override Tuple CreatePropertySet(Document doc, Element elem
bool elementIsType = (element is ElementType);
string typeString = elementIsType ? " " + Resources.IFCTypeSchedule : string.Empty;
string fullName = CreatePropertyName(property.Name, typeString);
- property.Create(doc, element, category, objDef, parameterGroupMap, fullName, parametersCreated);
+ property.Create(doc, element, category, objDef, parameterGroupMap, fullName, parametersCreated,
+ parametersToSet);
}
return Tuple.Create(quotedName, true);
diff --git a/Source/Revit.IFC.Import/Data/IFCPropertySetDefinition.cs b/Source/Revit.IFC.Import/Data/IFCPropertySetDefinition.cs
index 015057c2..f291105a 100644
--- a/Source/Revit.IFC.Import/Data/IFCPropertySetDefinition.cs
+++ b/Source/Revit.IFC.Import/Data/IFCPropertySetDefinition.cs
@@ -127,7 +127,8 @@ public static IFCPropertySetDefinition ProcessIFCPropertySetDefinition(IFCAnyHan
/// The element being created.
/// The parameters of the element. Cached for performance.
/// The name of the property set created, if it was created, and a Boolean value if it should be added to the property set list.
- public virtual Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef, IFCParameterSetByGroup parameterGroupMap)
+ public virtual Tuple CreatePropertySet(Document doc, Element element, IFCObjectDefinition objDef,
+ IFCParameterSetByGroup parameterGroupMap, ParametersToSet parametersToSet)
{
return new Tuple(null, false);
}
diff --git a/Source/Revit.IFC.Import/Data/IFCProxy.cs b/Source/Revit.IFC.Import/Data/IFCProxy.cs
index 0402ae54..d209cec9 100644
--- a/Source/Revit.IFC.Import/Data/IFCProxy.cs
+++ b/Source/Revit.IFC.Import/Data/IFCProxy.cs
@@ -106,14 +106,14 @@ protected override void CreateParametersInternal(Document doc, Element element)
string ifcTag = Tag;
if (!string.IsNullOrWhiteSpace(ifcTag))
{
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcTag", ifcTag, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcTag", ifcTag, Id);
}
// Set "ProxyType" parameter.
string ifcProxyType = ProxyType;
if (!string.IsNullOrWhiteSpace(ifcProxyType))
{
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcProxyType", ifcProxyType, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcProxyType", ifcProxyType, Id);
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCRepresentation.cs b/Source/Revit.IFC.Import/Data/IFCRepresentation.cs
index 4c5986d5..78541c92 100644
--- a/Source/Revit.IFC.Import/Data/IFCRepresentation.cs
+++ b/Source/Revit.IFC.Import/Data/IFCRepresentation.cs
@@ -74,6 +74,24 @@ protected IFCRepresentation()
}
+ ///
+ /// Determine if the IFCRepresentationMap only has at least 1 IFCHybridInformation.
+ ///
+ /// True if the IFCRepresentationMap only has at least 1 IFCHybridInformation.
+ public bool IsHybridOnly()
+ {
+ if ((RepresentationItems?.Count ?? 0) == 0)
+ return false;
+
+ foreach (IFCRepresentationItem item in RepresentationItems)
+ {
+ if (!(item is IFCHybridRepresentationItem))
+ return false;
+ }
+
+ return true;
+ }
+
private IFCRepresentationIdentifier GetRepresentationIdentifier(string identifier, IFCAnyHandle ifcRepresentation)
{
if (Enum.TryParse(identifier, true, out IFCRepresentationIdentifier ifcRepresentationIdentifier))
@@ -139,19 +157,13 @@ override protected void Process(IFCAnyHandle ifcRepresentation)
{
base.Process(ifcRepresentation);
- IFCAnyHandle representationContext = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcRepresentation, "ContextOfItems", false);
- if (representationContext != null)
- Context = IFCRepresentationContext.ProcessIFCRepresentationContext(representationContext);
-
string identifier = IFCImportHandleUtil.GetOptionalStringAttribute(ifcRepresentation, "RepresentationIdentifier", null);
Identifier = GetRepresentationIdentifier(identifier, ifcRepresentation);
- RepresentationType = IFCImportHandleUtil.GetOptionalStringAttribute(ifcRepresentation, "RepresentationType", null);
+ LayerAssignment = IFCPresentationLayerAssignment.GetTheLayerAssignment(ifcRepresentation);
HashSet items =
- IFCAnyHandleUtil.GetAggregateInstanceAttribute>(ifcRepresentation, "Items");
-
- LayerAssignment = IFCPresentationLayerAssignment.GetTheLayerAssignment(ifcRepresentation);
+ IFCAnyHandleUtil.GetAggregateInstanceAttribute>(ifcRepresentation, "Items");
if (items == null)
{
@@ -195,10 +207,21 @@ override protected void Process(IFCAnyHandle ifcRepresentation)
{
Importer.TheLog.LogError(item.StepId, ex.Message, false);
}
+
if (repItem != null)
RepresentationItems.Add(repItem);
}
}
+
+ // If we have a body representation and we have already gone through Hybrid, skip the rest of the work here.
+ if (Identifier == IFCRepresentationIdentifier.Body && (Importer.TheHybridInfo?.RepresentationsAlreadyCreated ?? false))
+ return;
+
+ IFCAnyHandle representationContext = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcRepresentation, "ContextOfItems", false);
+ if (representationContext != null)
+ Context = IFCRepresentationContext.ProcessIFCRepresentationContext(representationContext);
+
+ RepresentationType = IFCImportHandleUtil.GetOptionalStringAttribute(ifcRepresentation, "RepresentationType", null);
}
///
diff --git a/Source/Revit.IFC.Import/Data/IFCRepresentationItem.cs b/Source/Revit.IFC.Import/Data/IFCRepresentationItem.cs
index 45cf6e34..14ed537a 100644
--- a/Source/Revit.IFC.Import/Data/IFCRepresentationItem.cs
+++ b/Source/Revit.IFC.Import/Data/IFCRepresentationItem.cs
@@ -72,6 +72,10 @@ override protected void Process(IFCAnyHandle item)
LayerAssignment = IFCPresentationLayerAssignment.GetTheLayerAssignment(item);
+ // Don't bother processing styled items we will never use.
+ if (this is IFCHybridRepresentationItem)
+ return;
+
// IFC2x has a different representation for styled items which we don't support.
ICollection styledByItems = null;
if (Importer.TheCache.StyledByItems.TryGetValue(item, out styledByItems))
@@ -213,7 +217,6 @@ public static IFCRepresentationItem ProcessIFCRepresentationItem(IFCAnyHandle if
if (skipBodyGeometry)
{
- Importer.TheLog.LogComment(ifcRepresentationItem.Id, "Hybrid Import Adding Dummy IfcRepresentationItem, since geometry is already imported", true);
return IFCHybridRepresentationItem.ProcessIFCHybridRepresentationItem(ifcRepresentationItem);
}
diff --git a/Source/Revit.IFC.Import/Data/IFCRepresentationMap.cs b/Source/Revit.IFC.Import/Data/IFCRepresentationMap.cs
index 52ca8adc..dfcc3838 100644
--- a/Source/Revit.IFC.Import/Data/IFCRepresentationMap.cs
+++ b/Source/Revit.IFC.Import/Data/IFCRepresentationMap.cs
@@ -93,6 +93,15 @@ protected IFCRepresentationMap(IFCAnyHandle representationMap)
Process(representationMap);
}
+ ///
+ /// Determine if the IFCRepresentationMap only has at least 1 IFCHybridInformation.
+ ///
+ /// True if the IFCRepresentationMap only has at least 1 IFCHybridInformation.
+ public bool IsHybridOnly()
+ {
+ return MappedRepresentation?.IsHybridOnly() ?? false;
+ }
+
///
/// Create geometry for a particular representation map.
///
@@ -168,7 +177,8 @@ public void CreateShape(IFCImportShapeEditScope shapeEditScope, Transform scaled
if (directShapeType == null)
{
string directShapeTypeName = Id.ToString();
- directShapeType = IFCElementUtil.CreateElementType(doc, directShapeTypeName, shapeEditScope.CategoryId, Id, null, EntityType);
+ directShapeType = IFCElementUtil.CreateElementType(doc, directShapeTypeName,
+ shapeEditScope.CategoryId, Id, null, EntityType);
typeId = Id;
}
diff --git a/Source/Revit.IFC.Import/Data/IFCSite.cs b/Source/Revit.IFC.Import/Data/IFCSite.cs
index 32a9cb4f..65c3bbf6 100644
--- a/Source/Revit.IFC.Import/Data/IFCSite.cs
+++ b/Source/Revit.IFC.Import/Data/IFCSite.cs
@@ -434,6 +434,7 @@ public static void ProcessSiteLocations(Document doc, IList sites)
protected override void CreateParametersInternal(Document doc, Element element)
{
base.CreateParametersInternal(doc, element);
+
string parameterName = "LandTitleNumber";
// TODO: move this to new shared parameter names override function.
@@ -448,7 +449,7 @@ protected override void CreateParametersInternal(Document doc, Element element)
if (!string.IsNullOrWhiteSpace(landTitleNumber))
{
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, parameterName, landTitleNumber, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, parameterName, landTitleNumber, Id);
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCSpace.cs b/Source/Revit.IFC.Import/Data/IFCSpace.cs
index cd651eb0..4c9b96b0 100644
--- a/Source/Revit.IFC.Import/Data/IFCSpace.cs
+++ b/Source/Revit.IFC.Import/Data/IFCSpace.cs
@@ -76,15 +76,15 @@ protected override void CreateParametersInternal(Document doc, Element element)
Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
// Set "ElevationWithFlooring" parameter.
- IFCPropertySet.AddParameterDouble(doc, element, category, this, "ElevationWithFlooring", SpecTypeId.Length, UnitTypeId.Feet, ElevationWithFlooring, Id);
+ ParametersToSet.AddParameterDouble(doc, element, category, this, "ElevationWithFlooring", SpecTypeId.Length, UnitTypeId.Feet, ElevationWithFlooring, Id);
// Set "PredefinedType" parameter.
if (PredefinedType != null)
{
if (IFCImportFile.TheFile.SchemaVersionAtLeast(IFCSchemaVersion.IFC4Obsolete))
- IFCPropertySet.AddParameterString(doc, element, category, this, "PredefinedType", PredefinedType, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "PredefinedType", PredefinedType, Id);
else
- IFCPropertySet.AddParameterString(doc, element, category, this, "InteriorOrExteriorSpace", PredefinedType, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "InteriorOrExteriorSpace", PredefinedType, Id);
}
// Set "IfcZone" parameter.
@@ -105,7 +105,7 @@ protected override void CreateParametersInternal(Document doc, Element element)
}
if (zoneNames != null)
- IFCPropertySet.AddParameterString(doc, element, category, this, "IfcZone", zoneNames, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, "IfcZone", zoneNames, Id);
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCSpatialStructureElement.cs b/Source/Revit.IFC.Import/Data/IFCSpatialStructureElement.cs
index 6d1c120b..5076e455 100644
--- a/Source/Revit.IFC.Import/Data/IFCSpatialStructureElement.cs
+++ b/Source/Revit.IFC.Import/Data/IFCSpatialStructureElement.cs
@@ -120,20 +120,19 @@ protected override void CreateParametersInternal(Document doc, Element element)
{
base.CreateParametersInternal(doc, element);
+ if (element == null)
+ return;
- if (element != null)
+ // Set "ObjectTypeOverride" parameter.
+ string longName = LongName;
+ if (!string.IsNullOrWhiteSpace(longName))
{
- // Set "ObjectTypeOverride" parameter.
- string longName = LongName;
- if (!string.IsNullOrWhiteSpace(longName))
- {
- string parameterName = "LongNameOverride";
- if (element is ProjectInfo)
- parameterName = EntityType.ToString() + " " + parameterName;
+ string parameterName = "LongNameOverride";
+ if (element is ProjectInfo)
+ parameterName = EntityType.ToString() + " " + parameterName;
- Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
- IFCPropertySet.AddParameterString(doc, element, category, this, parameterName, longName, Id);
- }
+ Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, parameterName, longName, Id);
}
}
@@ -257,37 +256,37 @@ protected void CreatePostalParameters(Document doc, Element element, IFCPostalAd
string typeName = EntityType.ToString() + " ";
if (!string.IsNullOrWhiteSpace(postalAddress.Purpose))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "Purpose", postalAddress.Purpose, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "Purpose", postalAddress.Purpose, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.Description))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "Description", postalAddress.Description, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "Description", postalAddress.Description, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.UserDefinedPurpose))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "UserDefinedPurpose", postalAddress.UserDefinedPurpose, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "UserDefinedPurpose", postalAddress.UserDefinedPurpose, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.InternalLocation))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "InternalLocation", postalAddress.InternalLocation, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "InternalLocation", postalAddress.InternalLocation, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.PostalBox))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "PostalBox", postalAddress.PostalBox, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "PostalBox", postalAddress.PostalBox, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.Town))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "Town", postalAddress.Town, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "Town", postalAddress.Town, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.Region))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "Region", postalAddress.Region, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "Region", postalAddress.Region, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.PostalCode))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "PostalCode", postalAddress.PostalCode, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "PostalCode", postalAddress.PostalCode, Id);
if (!string.IsNullOrWhiteSpace(postalAddress.Country))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "Country", postalAddress.Country, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "Country", postalAddress.Country, Id);
if (postalAddress.AddressLines != null)
{
- string jointAddress = String.Join(", ", postalAddress.AddressLines);
+ string jointAddress = string.Join(", ", postalAddress.AddressLines);
if (!string.IsNullOrWhiteSpace(jointAddress))
- IFCPropertySet.AddParameterString(doc, element, category, this, typeName + "AddressLines", jointAddress, Id);
+ ParametersToSet.AddStringParameter(doc, element, category, this, typeName + "AddressLines", jointAddress, Id);
}
}
}
diff --git a/Source/Revit.IFC.Import/Data/IFCStyledItem.cs b/Source/Revit.IFC.Import/Data/IFCStyledItem.cs
index daadd2ba..3098fcbf 100644
--- a/Source/Revit.IFC.Import/Data/IFCStyledItem.cs
+++ b/Source/Revit.IFC.Import/Data/IFCStyledItem.cs
@@ -190,6 +190,11 @@ public IFCSurfaceStyle GetSurfaceStyle()
/// The document.
public void Create(IFCImportShapeEditScope shapeEditScope)
{
+ // If we have an IFCHybridRepresentationItem, there's no reason to create the styled item, because
+ // we won't use it.
+ if (Item is IFCHybridRepresentationItem)
+ return;
+
// TODO: support cut pattern id and cut pattern color.
if (m_CreatedElementId != ElementId.InvalidElementId || !IsValidForCreation)
return;
diff --git a/Source/Revit.IFC.Import/Data/IFCTypeObject.cs b/Source/Revit.IFC.Import/Data/IFCTypeObject.cs
index 0c92586f..5eca2c71 100644
--- a/Source/Revit.IFC.Import/Data/IFCTypeObject.cs
+++ b/Source/Revit.IFC.Import/Data/IFCTypeObject.cs
@@ -120,6 +120,18 @@ protected override string GetPredefinedType(IFCAnyHandle ifcObjectDefinition)
return null;
}
+ ///
+ /// Get the category id for an object from another object.
+ ///
+ /// The document.
+ /// The other IFCObjectDefinition.
+ /// This is intended for IFCTypeObjects to have the same category id as their entities.
+ public void CalculateCategoryAndGStyleIdsFromObject(Document doc, IFCObject obj)
+ {
+ CategoryIdCache = obj.GetCategoryId(doc);
+ GraphicsStyleIdCache = obj.GetGraphicsStyleId(doc);
+ }
+
///
/// Processes IfcTypeObject attributes.
///
@@ -193,7 +205,7 @@ protected override void Create(Document doc)
if (shapeType == null)
{
- shapeType = IFCElementUtil.CreateElementType(doc, GetVisibleName(), CategoryId, Id, GlobalId, EntityType);
+ shapeType = IFCElementUtil.CreateElementType(doc, GetVisibleName(), GetCategoryId(doc), Id, GlobalId, EntityType);
}
else
{
diff --git a/Source/Revit.IFC.Import/Data/IFCTypeProduct.cs b/Source/Revit.IFC.Import/Data/IFCTypeProduct.cs
index 4918407b..47c37001 100644
--- a/Source/Revit.IFC.Import/Data/IFCTypeProduct.cs
+++ b/Source/Revit.IFC.Import/Data/IFCTypeProduct.cs
@@ -25,6 +25,7 @@
using Revit.IFC.Common.Enums;
using Revit.IFC.Common.Utility;
using Revit.IFC.Import.Enums;
+using Revit.IFC.Import.Utility;
namespace Revit.IFC.Import.Data
{
@@ -115,37 +116,27 @@ protected override void Process(IFCAnyHandle ifcTypeProduct)
Tag = IFCAnyHandleUtil.GetStringAttribute(ifcTypeProduct, "Tag");
- // IFCRepresentationItem should know that it is processing something for Hybrid IFC Imports.
- // Then it will create IFCHybridRepresentationItems, which are placeholders for body geometry created by AnyCAD.
- // This is so data for Representation Item will still exist, even if legacy geometry does not.
- if ((Importer.TheOptions.IsHybridImport) && (Importer.TheHybridInfo?.HybridMap?.ContainsKey(GlobalId) ?? false))
+ using (RepresentationsAlreadyCreatedSetter setter = new RepresentationsAlreadyCreatedSetter(GlobalId))
{
- Importer.TheHybridInfo.RepresentationsAlreadyCreated = true;
- }
-
- IList representationMapsHandle = IFCAnyHandleUtil.GetAggregateInstanceAttribute>(ifcTypeProduct, "RepresentationMaps");
- if (representationMapsHandle != null && representationMapsHandle.Count > 0)
- {
- foreach (IFCAnyHandle representationMapHandle in representationMapsHandle)
+ IList representationMapsHandle = IFCAnyHandleUtil.GetAggregateInstanceAttribute>(ifcTypeProduct, "RepresentationMaps");
+ if (representationMapsHandle?.Count > 0)
{
- IFCRepresentationMap representationMap = IFCRepresentationMap.ProcessIFCRepresentationMap(representationMapHandle);
- if (representationMap != null)
+ foreach (IFCAnyHandle representationMapHandle in representationMapsHandle)
{
- RepresentationMaps.Add(representationMap);
-
- // Traditionally we would create a "dummy" DirectShapeType for each IfcRepresentationMap. In the case where the IfcRepresentationMap is not used by another other IfcTypeProduct,
- // we would like to stop creating the "dummy" DirectShapeType and store the geometry in the DirectShapeType associated with the IfcTypeProduct. However, IfcRepresentationMap
- // does not have an INVERSE relationship to its IfcTypeProduct(s), at least in IFC2x3.
- // As such, we keep track of the IfcRepresentationMaps that have the relationship described above for future correspondence.
- RegisterRepresentationMapWithTypeProject(representationMap, this);
+ IFCRepresentationMap representationMap = IFCRepresentationMap.ProcessIFCRepresentationMap(representationMapHandle);
+ if (representationMap != null)
+ {
+ RepresentationMaps.Add(representationMap);
+
+ // Traditionally we would create a "dummy" DirectShapeType for each IfcRepresentationMap. In the case where the IfcRepresentationMap is not used by another other IfcTypeProduct,
+ // we would like to stop creating the "dummy" DirectShapeType and store the geometry in the DirectShapeType associated with the IfcTypeProduct. However, IfcRepresentationMap
+ // does not have an INVERSE relationship to its IfcTypeProduct(s), at least in IFC2x3.
+ // As such, we keep track of the IfcRepresentationMaps that have the relationship described above for future correspondence.
+ RegisterRepresentationMapWithTypeProject(representationMap, this);
+ }
}
}
}
-
- if ((Importer.TheOptions.IsHybridImport) && (Importer.TheHybridInfo?.RepresentationsAlreadyCreated ?? false))
- {
- Importer.TheHybridInfo.RepresentationsAlreadyCreated = false;
- }
}
///
diff --git a/Source/Revit.IFC.Import/Importer.cs b/Source/Revit.IFC.Import/Importer.cs
index be6f0a25..ca366fef 100644
--- a/Source/Revit.IFC.Import/Importer.cs
+++ b/Source/Revit.IFC.Import/Importer.cs
@@ -29,6 +29,7 @@
using Revit.IFC.Import.Utility;
using IFCImportOptions = Revit.IFC.Import.Utility.IFCImportOptions;
using Revit.IFC.Import.Core;
+using static Revit.IFC.Import.Utility.IFCImportOptions;
namespace Revit.IFC.Import
{
@@ -99,8 +100,6 @@ public class Importer : IIFCImporterServer
IFCImportLog m_ImportLog = null;
- IFCImportHybridInfo m_ImportHybridInfo = null;
-
private static HashSet m_ImportPostedErrors = null;
///
@@ -155,6 +154,14 @@ static public IFCImportCache TheCache
protected set { TheImporter.m_ImportCache = value; }
}
+ ///
+ /// Determines if we are using the default (i.e., Revit) processor.
+ ///
+ /// True if we are using the default processor.
+ /// This function can be used to short-circuit function calls that do unnecessary
+ /// work (e.g., creating custom sub-categories.)
+ static public bool IsDefaultProcessor() { return TheProcessor is IFCDefaultProcessor; }
+
static public IIFCFileProcessor TheProcessor { get => TheOptions?.Processor; }
static public IFCImportHybridInfo TheHybridInfo { get; protected set; } = null;
@@ -188,7 +195,7 @@ public static Importer CreateImporter(Document originalDocument, string ifcFileN
Importer importer = new Importer();
TheImporter = importer;
TheCache = IFCImportCache.Create(originalDocument, ifcFileName);
- TheOptions = importer.m_ImportOptions = IFCImportOptions.Create(importOptions, ifcFileName);
+ TheOptions = importer.m_ImportOptions = IFCImportOptions.Create(importOptions, ifcFileName, originalDocument);
TheLog = IFCImportLog.CreateLog(ifcFileName, "log.html", !TheOptions.DisableLogging);
return importer;
}
@@ -200,9 +207,33 @@ private Document LoadLinkDocument(Document originalDocument, string linkedFileNa
Application application = originalDocument.Application;
+ Document doc = application.OpenDocumentFile(linkedFileName);
+ if (doc == null)
+ {
+ return null;
+ }
+
+ ProjectInfo projInfo = doc.ProjectInformation;
+ if (projInfo == null)
+ {
+ doc.Close();
+ return null;
+ }
+
+ // Check to see if the projInfo ImportMethod parameter equals the current method of import.
+ // If it does not, then update current method to match original method.
+ bool isHybridImport = false;
+ Parameter originalImportMethod = projInfo.LookupParameter(ImportMethodParameter);
+ if ((originalImportMethod?.StorageType ?? StorageType.None) == StorageType.String)
+ {
+ isHybridImport = Enum.TryParse(originalImportMethod.AsString(), true, out ImportMethod existingMethod) &&
+ existingMethod == ImportMethod.Hybrid;
+ }
+ TheOptions.IsHybridImport = isHybridImport;
+
// We won't catch any exceptions here, yet.
// There could be a number of reasons why this fails, to be investigated.
- return application.OpenDocumentFile(linkedFileName);
+ return doc;
}
private Document CreateLinkDocument(Document originalDocument)
@@ -277,9 +308,10 @@ private Document CreateLinkDocument(Document originalDocument)
return ifcDocument;
}
- private Document LoadOrCreateLinkDocument(Document originalDocument, string linkedFileName)
+ private (Document ifcDocument, bool doUpdate) LoadOrCreateLinkDocument(Document originalDocument, string linkedFileName)
{
Document ifcDocument = null;
+ bool doUpdate = true;
try
{
@@ -290,6 +322,7 @@ private Document LoadOrCreateLinkDocument(Document originalDocument, string link
if (ifcDocument == null)
{
ifcDocument = CreateLinkDocument(originalDocument);
+ doUpdate = false;
}
if (ifcDocument == null)
@@ -300,10 +333,10 @@ private Document LoadOrCreateLinkDocument(Document originalDocument, string link
finally
{
if(ifcDocument == null)
- Importer.TheLog.LogError(-1, "Could not create document for cached IFC Revit file while importing: " + linkedFileName + ", aborting.", false);
+ TheLog.LogError(-1, "Could not create document for cached IFC Revit file while importing: " + linkedFileName + ", aborting.", false);
}
- return ifcDocument;
+ return (ifcDocument, doUpdate);
}
///
@@ -355,7 +388,7 @@ private bool NeedsReload(Document doc, string originalIFCFileName)
if (checkFileTimestamp)
{
// Ignore ticks - only needs to be accurate to the second, or 10,000,000 ticks.
- Int64 diffTicks = infoIFC.LastWriteTimeUtc.Ticks - TheOptions.OriginalTimeStamp.Ticks;
+ long diffTicks = infoIFC.LastWriteTimeUtc.Ticks - TheOptions.OriginalTimeStamp.Ticks;
if (diffTicks < 0 || diffTicks >= 10000000)
return true;
}
@@ -375,7 +408,7 @@ public static TransactionStatus StartReferenceIFCTransaction(Transaction transac
TransactionStatus transactionStatus = transaction.GetStatus();
if (transactionStatus == TransactionStatus.Started)
{
- TheLog.LogWarning(-1, "Attempting to start ReferenceIFC Transaction when already started", true);
+ TheLog.LogComment(-1, "Attempting to start ReferenceIFC Transaction when already started", true);
return transactionStatus;
}
@@ -462,13 +495,81 @@ private bool DocumentUpToDate(Document doc, string ifcFileName)
return true;
}
+ private void LogEndImportDetailed(Document ifcDocument)
+ {
+ if (!TheOptions.VerboseLogging || TheHybridInfo == null)
+ return;
+
+ TheLog.LogWarning(-1, "--- Hybrid IFC Import: Start of Detailed Logging after Hybrid IFC Import. ---", false);
+ TheLog.LogWarning(-1, "Hybrid IFC Import: If an IfcGuid does not appear in the following list, then it was processed entirely via legacy code.", false);
+ TheLog.LogWarning(-1, "Hybrid IFC Import: If an IfcGuid is no longer in the Hybrid Map, but its ElementId is in the Elements to be deleted list, this is normal.", false);
+ TheHybridInfo.LogHybridMapDetailed();
+ TheHybridInfo.LogElementsToDeleteDetailed();
+ TheLog.LogWarning(-1, "--- Hybrid IFC Import: End of Logging detailed Information after Hybrid IFC Import.---", false);
+
+ FilteredElementCollector collector = new FilteredElementCollector(ifcDocument);
+
+ List supportedElementTypes = new List() { typeof(DirectShape) };
+ ElementMulticlassFilter multiclassFilter = new ElementMulticlassFilter(supportedElementTypes);
+ collector.WherePasses(multiclassFilter);
+
+ int numDirectShapes = collector.GetElementCount();
+ if (numDirectShapes == 0)
+ {
+ ifcDocument.Application.WriteJournalComment("Hybrid IFC Import: No IFCProducts Imported.", false);
+ }
+ else if (numDirectShapes != (Importer.TheHybridInfo.HybridElements?.Count ?? 0))
+ {
+ ifcDocument.Application.WriteJournalComment("---- Hybrid IFC Import: Some DirectShapes processed within Revit. ---", false);
+
+ IList directShapeElements = collector.ToElements();
+ // This is inefficient, but we need to reliably get the IFCGuids
+
+ // HybridMap is for IFC GlobalId --> ElementId. This is used for almost all of the Hybrid IFC Import processing.
+ // reverseLookup is for ElementId --> IFC GlobalId. This is used to find the ElementId associated with a given IFC GlobalId (for logging purposes).
+ IDictionary reverseLookup = new Dictionary();
+ foreach (KeyValuePair pair in TheHybridInfo.HybridMap)
+ {
+ try
+ {
+ ElementId elementId = pair.Value;
+ string ifcGuid = pair.Key;
+ reverseLookup.Add(pair.Value, pair.Key);
+ }
+ catch (ArgumentException ex)
+ {
+ TheLog.LogWarning(-1, $"Duplicate ElementId found when reversing Hybrid Map for logging {ex.Message}", false);
+ }
+ }
+
+ // Log (into journal) IFC GlobalIds & ElementIds that were imported by AnyCAD or via Revit alone.
+ ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Count of DirectShapes imported via AnyCAD: {Importer.TheHybridInfo.HybridElements.Count}", false);
+ foreach (Element element in directShapeElements)
+ {
+ string ifcGuid;
+ if (reverseLookup.TryGetValue(element.Id, out ifcGuid))
+ {
+ ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: AnyCAD DirectShape (IFC GUID, ElementId): ({ifcGuid}, {element.Id})", false);
+ }
+ }
+
+ ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Count of DirectShapes falling back to Revit: {numDirectShapes - Importer.TheHybridInfo.HybridElements.Count}", false);
+ foreach (Element element in directShapeElements)
+ {
+ if (reverseLookup.ContainsKey(element.Id))
+ continue;
+ string ifcGuid = IFCGUIDUtil.GetGUID(element);
+ ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Fallback DirectShape (IFC GUID, ElementId): ({ifcGuid}, {element.Id})", false);
+ }
+ }
+ }
+
///
/// Import an IFC file into a given document for Reference only.
///
/// The host document for the import.
/// The full file name of the document.
- /// The list of configurable options for this import.
- public void ReferenceIFC(Document document, string origFullFileName, IDictionary options)
+ public void ReferenceIFC(Document document, string origFullFileName)
{
// We need to generate a local file name for all of the intermediate files (the log file, the cache file, and the shared parameters file).
string localFileName = ImporterIFCUtils.GetLocalFileName(document, origFullFileName);
@@ -482,12 +583,17 @@ public void ReferenceIFC(Document document, string origFullFileName, IDictionary
m_ImportLog = IFCImportLog.CreateLog(localFileName, "log.html", !m_ImportOptions.DisableLogging);
Document originalDocument = document;
- Document ifcDocument = null;
+ Document ifcDocument;
+ bool doUpdate = false;
+
if (TheOptions.Action == IFCImportAction.Link)
{
string linkedFileName = IFCImportFile.GetRevitFileName(localFileName);
- ifcDocument = LoadOrCreateLinkDocument(originalDocument, linkedFileName);
+ // NOTE: This will update IsHybridImport if we are reloading an existing document - we will use
+ // whatever method we originally used. If a user wants to switch, they will have to delete the
+ // cache file. Do not use IsHybridImport before this call.
+ (ifcDocument, doUpdate) = LoadOrCreateLinkDocument(originalDocument, linkedFileName);
}
else
{
@@ -532,7 +638,7 @@ public void ReferenceIFC(Document document, string origFullFileName, IDictionary
}
else
{
- TheHybridInfo = m_ImportHybridInfo = new IFCImportHybridInfo(ifcDocument, localFileName);
+ TheHybridInfo = new IFCImportHybridInfo(ifcDocument, localFileName, doUpdate);
if (TheHybridInfo != null)
{
BasePoint newSurveyPoint = BasePoint.GetSurveyPoint(ifcDocument);
@@ -540,7 +646,7 @@ public void ReferenceIFC(Document document, string origFullFileName, IDictionary
if (!newPosition.IsAlmostEqualTo(originalPosition))
{
- TheHybridInfo.LargeCoordinateTransform = Transform.CreateTranslation(newPosition - originalPosition);
+ TheHybridInfo.LargeCoordinateOriginOffset = originalPosition - newPosition;
}
}
}
@@ -565,73 +671,7 @@ public void ReferenceIFC(Document document, string origFullFileName, IDictionary
theFile.EndImport(ifcDocument, localFileName);
// Make sure to log detailed information after EndImport.
- if (Importer.TheOptions.VerboseLogging && Importer.TheHybridInfo != null)
- {
- Importer.TheLog.LogWarning(-1, "--- Hybrid IFC Import: Start of Detailed Logging after Hybrid IFC Import. ---", false);
- Importer.TheLog.LogWarning(-1, "Hybrid IFC Import: If an IfcGuid does not appear in the following list, then it was processed entirely via legacy code.", false);
- Importer.TheLog.LogWarning(-1, "Hybrid IFC Import: If an IfcGuid is no longer in the Hybrid Map, but its ElementId is in the Elements to be deleted list, this is normal.", false);
- Importer.TheHybridInfo.LogHybridMapDetailed();
- Importer.TheHybridInfo.LogElementsToDeleteDetailed();
- Importer.TheLog.LogWarning(-1, "--- Hybrid IFC Import: End of Logging detailed Information after Hybrid IFC Import.---", false);
-
- FilteredElementCollector collector = new FilteredElementCollector(ifcDocument);
-
- List supportedElementTypes = new List();
- supportedElementTypes.Add(typeof(DirectShape));
- ElementMulticlassFilter multiclassFilter = new ElementMulticlassFilter(supportedElementTypes);
- collector.WherePasses(multiclassFilter);
-
- int numDirectShapes = collector.GetElementCount();
- if (numDirectShapes == 0)
- {
- ifcDocument.Application.WriteJournalComment("Hybrid IFC Import: No IFCProducts Imported.", false);
- }
- else if (numDirectShapes != (Importer.TheHybridInfo.HybridElements?.Count ?? 0))
- {
- ifcDocument.Application.WriteJournalComment("---- Hybrid IFC Import: Some DirectShapes processed within Revit. ---", false);
-
- IList directShapeElements = collector.ToElements();
- // This is inefficient, but we need to reliably get the IFCGuids
-
- // HybridMap is for IFC GlobalId --> ElementId. This is used for almost all of the Hybrid IFC Import processing.
- // reverseLookup is for ElementId --> IFC GlobalId. This is used to find the ElementId associated with a given IFC GlobalId (for logging purposes).
- IDictionary reverseLookup = new Dictionary();
- foreach (KeyValuePair pair in Importer.TheHybridInfo.HybridMap)
- {
- try
- {
- ElementId elementId = pair.Value;
- string ifcGuid = pair.Key;
- reverseLookup.Add(pair.Value, pair.Key);
- }
- catch (ArgumentException ex)
- {
- Importer.TheLog.LogWarning(-1, $"Duplicate ElementId found when reversing Hybrid Map for logging {ex.Message}", false);
- }
- }
-
- // Log (into journal) IFC GlobalIds & ElementIds that were imported by AnyCAD or via Revit alone.
- ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Count of DirectShapes imported via AnyCAD: {Importer.TheHybridInfo.HybridElements.Count}", false);
- foreach (Element element in directShapeElements)
- {
- String ifcGuid;
- if (reverseLookup.TryGetValue(element.Id, out ifcGuid))
- {
- ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: AnyCAD DirectShape (IFC GUID, ElementId): ({ifcGuid}, {element.Id})", false);
- }
- }
-
- ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Count of DirectShapes falling back to Revit: {numDirectShapes - Importer.TheHybridInfo.HybridElements.Count}", false);
- foreach (Element element in directShapeElements)
- {
- if (reverseLookup.ContainsKey(element.Id))
- continue;
- string ifcGuid = IFCGUIDUtil.GetGUID(element);
- ifcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Fallback DirectShape (IFC GUID, ElementId): ({ifcGuid}, {element.Id})", false);
- }
- }
- }
-
+ LogEndImportDetailed(ifcDocument);
}
if (TheOptions.Action == IFCImportAction.Link)
@@ -656,7 +696,7 @@ public void ImportIFC(ImporterIFC importer)
string fullIFCFileName = importer.FullFileName;
IDictionary options = importer.GetOptions();
- TheOptions = m_ImportOptions = IFCImportOptions.Create(options, fullIFCFileName);
+ TheOptions = m_ImportOptions = IFCImportOptions.Create(options, fullIFCFileName, importer.Document);
// An early check, based on the options set - if we are allowed to use an up-to-date existing file on disk, use it.
try
@@ -673,7 +713,7 @@ public void ImportIFC(ImporterIFC importer)
}
else
{
- ReferenceIFC(importer.Document, fullIFCFileName, options);
+ ReferenceIFC(importer.Document, fullIFCFileName);
}
}
catch (Exception ex)
@@ -690,6 +730,7 @@ public void ImportIFC(ImporterIFC importer)
TheLog?.Close();
TheLog = null;
IFCImportFile.TheFile?.Close();
+ TheHybridInfo = null;
}
}
diff --git a/Source/Revit.IFC.Import/Processors/IFCDefaultProcessor.cs b/Source/Revit.IFC.Import/Processors/IFCDefaultProcessor.cs
index 07f8954e..7ada9475 100644
--- a/Source/Revit.IFC.Import/Processors/IFCDefaultProcessor.cs
+++ b/Source/Revit.IFC.Import/Processors/IFCDefaultProcessor.cs
@@ -1,7 +1,9 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using Autodesk.Revit.DB;
using Revit.IFC.Import.Core;
+using Revit.IFC.Import.Utility;
namespace Revit.IFC.Import
{
@@ -60,7 +62,8 @@ public bool PostProcessProduct(int ifcId,
return null;
}
- public void SetStringParameter(Element element, int objDefId, BuiltInParameter parameterId, string value, bool allowUnfound)
+ public void SetElementStringParameter(Element element, int objDefId, BuiltInParameter parameterId, string value,
+ bool allowUnfound, ParametersToSet parametersToSet)
{
Parameter parameter = element?.get_Parameter(parameterId);
if (parameter == null)
@@ -82,7 +85,13 @@ public void SetStringParameter(Element element, int objDefId, BuiltInParameter p
return;
}
- parameter.Set(value);
+ parametersToSet.AddStringParameter(parameter, value);
+ }
+
+ public void SetStringParameter(Element element, int objDefId, BuiltInParameter parameterId, string value, bool allowUnfound)
+ {
+ // No longer used.
+ return;
}
public bool PostProcessRepresentationMap(int typeId,
diff --git a/Source/Revit.IFC.Import/Properties/AssemblyInfo.cs b/Source/Revit.IFC.Import/Properties/AssemblyInfo.cs
index ed08b54f..813b0c7d 100644
--- a/Source/Revit.IFC.Import/Properties/AssemblyInfo.cs
+++ b/Source/Revit.IFC.Import/Properties/AssemblyInfo.cs
@@ -12,8 +12,8 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("24.1.0.22")]
-[assembly: AssemblyFileVersion("24.1.0.22")]
+[assembly: AssemblyVersion("24.1.1.6")]
+[assembly: AssemblyFileVersion("24.1.1.6")]
#endif
#region Using directives
diff --git a/Source/Revit.IFC.Import/Revit.IFC.Import.csproj b/Source/Revit.IFC.Import/Revit.IFC.Import.csproj
index 0771fdb4..ef25bbdd 100644
--- a/Source/Revit.IFC.Import/Revit.IFC.Import.csproj
+++ b/Source/Revit.IFC.Import/Revit.IFC.Import.csproj
@@ -269,6 +269,7 @@
+
diff --git a/Source/Revit.IFC.Import/Utility/IFCCategoryUtil.cs b/Source/Revit.IFC.Import/Utility/IFCCategoryUtil.cs
index 419a102f..1d86652a 100644
--- a/Source/Revit.IFC.Import/Utility/IFCCategoryUtil.cs
+++ b/Source/Revit.IFC.Import/Utility/IFCCategoryUtil.cs
@@ -396,10 +396,14 @@ private static void InitEntityTypeToCategoryMaps()
m_EntityTypeToCategory[IFCEntityType.IfcAirToAirHeatRecovery] = BuiltInCategory.OST_MechanicalEquipment;
m_EntityTypeToCategory[IFCEntityType.IfcAirToAirHeatRecoveryType] = BuiltInCategory.OST_MechanicalEquipment;
m_EntityTypeToCategory[IFCEntityType.IfcAlarmType] = BuiltInCategory.OST_GenericModel;
- m_EntityTypeToCategory[IFCEntityType.IfcAlignment] = BuiltInCategory.OST_Alignments;
- m_EntityTypeToCategory[IFCEntityType.IfcAlignmentHorizontal] = BuiltInCategory.OST_Alignments;
- m_EntityTypeToCategory[IFCEntityType.IfcAlignmentSegment] = BuiltInCategory.OST_Alignments;
- m_EntityTypeToCategory[IFCEntityType.IfcAlignmentVertical] = BuiltInCategory.OST_Alignments;
+
+ // NOTE: We do have BuiltInCategory.OST_Alignments, and you can create a DirectShape of that type, but the
+ // Alignment update code isn't very happy about it. So we will map to generic model for now.
+ m_EntityTypeToCategory[IFCEntityType.IfcAlignment] = BuiltInCategory.OST_GenericModel;
+ m_EntityTypeToCategory[IFCEntityType.IfcAlignmentHorizontal] = BuiltInCategory.OST_GenericModel;
+ m_EntityTypeToCategory[IFCEntityType.IfcAlignmentSegment] = BuiltInCategory.OST_GenericModel;
+ m_EntityTypeToCategory[IFCEntityType.IfcAlignmentVertical] = BuiltInCategory.OST_GenericModel;
+
m_EntityTypeToCategory[IFCEntityType.IfcAnnotation] = BuiltInCategory.OST_GenericModel;
m_EntityTypeToCategory[IFCEntityType.IfcAudioVisualAppliance] = BuiltInCategory.OST_AudioVisualDevices;
m_EntityTypeToCategory[IFCEntityType.IfcAudioVisualApplianceType] = BuiltInCategory.OST_AudioVisualDevices;
@@ -432,8 +436,8 @@ private static void InitEntityTypeToCategoryMaps()
m_EntityTypeToCategory[IFCEntityType.IfcControllerType] = BuiltInCategory.OST_SpecialityEquipment;
m_EntityTypeToCategory[IFCEntityType.IfcCovering] = BuiltInCategory.OST_GenericModel;
m_EntityTypeToCategory[IFCEntityType.IfcCoveringType] = BuiltInCategory.OST_GenericModel;
- m_EntityTypeToCategory[IFCEntityType.IfcCurtainWall] = BuiltInCategory.OST_CurtaSystem;
- m_EntityTypeToCategory[IFCEntityType.IfcCurtainWallType] = BuiltInCategory.OST_CurtaSystem;
+ m_EntityTypeToCategory[IFCEntityType.IfcCurtainWall] = BuiltInCategory.OST_Walls;
+ m_EntityTypeToCategory[IFCEntityType.IfcCurtainWallType] = BuiltInCategory.OST_Walls;
m_EntityTypeToCategory[IFCEntityType.IfcDamper] = BuiltInCategory.OST_DuctAccessory;
m_EntityTypeToCategory[IFCEntityType.IfcDamperType] = BuiltInCategory.OST_DuctAccessory;
m_EntityTypeToCategory[IFCEntityType.IfcDiscreteAccessory] = BuiltInCategory.OST_SpecialityEquipment;
@@ -526,7 +530,11 @@ private static void InitEntityTypeToCategoryMaps()
m_EntityTypeToCategory[IFCEntityType.IfcRampType] = BuiltInCategory.OST_Ramps;
m_EntityTypeToCategory[IFCEntityType.IfcRampFlight] = BuiltInCategory.OST_Ramps;
m_EntityTypeToCategory[IFCEntityType.IfcRampFlightType] = BuiltInCategory.OST_Ramps;
- m_EntityTypeToCategory[IFCEntityType.IfcReferent] = BuiltInCategory.OST_Alignments;
+
+ // NOTE: We do have BuiltInCategory.OST_Alignments, and you can create a DirectShape of that type, but the
+ // Alignment update code isn't very happy about it. So we will map to generic model for now.
+ m_EntityTypeToCategory[IFCEntityType.IfcReferent] = BuiltInCategory.OST_GenericModel;
+
m_EntityTypeToCategory[IFCEntityType.IfcReinforcingBar] = BuiltInCategory.OST_Rebar;
m_EntityTypeToCategory[IFCEntityType.IfcReinforcingBarType] = BuiltInCategory.OST_Rebar;
m_EntityTypeToCategory[IFCEntityType.IfcReinforcingMesh] = BuiltInCategory.OST_FabricAreas;
@@ -702,7 +710,7 @@ private static bool InitFromFile()
if (string.IsNullOrWhiteSpace(ifcClassName))
continue;
IFCEntityType ifcClassType;
- if (!Enum.TryParse(ifcClassName, true, out ifcClassType))
+ if (!Enum.TryParse(ifcClassName, true, out ifcClassType))
{
Importer.TheLog.LogWarning(-1, "Unknown class name in IFC entity to category mapping file: " + ifcClassName, true);
continue;
diff --git a/Source/Revit.IFC.Import/Utility/IFCElementUtil.cs b/Source/Revit.IFC.Import/Utility/IFCElementUtil.cs
index 6bd79821..2ad2d024 100644
--- a/Source/Revit.IFC.Import/Utility/IFCElementUtil.cs
+++ b/Source/Revit.IFC.Import/Utility/IFCElementUtil.cs
@@ -153,7 +153,7 @@ static public DirectShapeType CreateElementType(Document doc, string name, Eleme
{
DirectShapeTypeOptions options = new DirectShapeTypeOptions();
options.AllowDuplicateNames = true;
- ElementId validCategoryId = IFCElementUtil.GetDSValidCategoryId(doc, categoryId, id);
+ ElementId validCategoryId = GetDSValidCategoryId(doc, categoryId, id);
DirectShapeType directShapeType = DirectShapeType.Create(doc, name, validCategoryId, options);
Importer.TheCache.CreatedDirectShapeTypes[id] = directShapeType.Id;
diff --git a/Source/Revit.IFC.Import/Utility/IFCImportCache.cs b/Source/Revit.IFC.Import/Utility/IFCImportCache.cs
index a96921e7..62e8d676 100644
--- a/Source/Revit.IFC.Import/Utility/IFCImportCache.cs
+++ b/Source/Revit.IFC.Import/Utility/IFCImportCache.cs
@@ -173,6 +173,17 @@ public BindingMap GetParameterBinding(Document doc)
///
public IDictionary GridNameToElementMap { get; } = new Dictionary();
+ ///
+ /// The view plane type if, if ViewPlanTypeIdInitialized is true and we found one.
+ ///
+ public ElementId ViewPlanTypeId { get; set; } = ElementId.InvalidElementId;
+
+ ///
+ /// Returns true if we have tried to set ViewPlanTypeId. ViewPlanTypeId may or may not have a valid value.
+ ///
+ public bool ViewPlanTypeIdInitialized { get; set; } = false;
+
+
private bool HavePreProcessedGrids { get; set; } = false;
///
@@ -220,11 +231,13 @@ public void CreateExistingElementMaps(Document document)
// These are the only element types currently created in .NET code. This list needs to be updated when a new
// type is created.
- List supportedElementTypes = new List();
- supportedElementTypes.Add(typeof(DirectShape));
- supportedElementTypes.Add(typeof(DirectShapeType));
- supportedElementTypes.Add(typeof(Level));
- supportedElementTypes.Add(typeof(Grid));
+ List supportedElementTypes = new List()
+ {
+ typeof(DirectShape),
+ typeof(DirectShapeType),
+ typeof(Level),
+ typeof(Grid)
+ };
ElementMulticlassFilter multiclassFilter = new ElementMulticlassFilter(supportedElementTypes);
collector.WherePasses(multiclassFilter);
diff --git a/Source/Revit.IFC.Import/Utility/IFCImportHybridInfo.cs b/Source/Revit.IFC.Import/Utility/IFCImportHybridInfo.cs
index 6807b936..e6c46d7e 100644
--- a/Source/Revit.IFC.Import/Utility/IFCImportHybridInfo.cs
+++ b/Source/Revit.IFC.Import/Utility/IFCImportHybridInfo.cs
@@ -32,9 +32,41 @@
namespace Revit.IFC.Import.Utility
{
///
- /// Provide methods to perform Hybrid IFC Import.
+ /// A helper class to set and unset RepresentationsAlreadyCreated, with the "using" keyword.
///
- public class IFCImportHybridInfo
+ public class RepresentationsAlreadyCreatedSetter : IDisposable
+ {
+ ///
+ /// The constructor.
+ ///
+ /// The GUID to check.
+ public RepresentationsAlreadyCreatedSetter(string guid)
+ {
+ // IFCRepresentationItem should know that it is processing something for Hybrid IFC Imports.
+ // Then it will create IFCHybridRepresentationItems, which are placeholders for body geometry created via AnyCAD.
+ // This is so data for Representation Item will still exist, even if legacy geometry does not.
+ if (Importer.TheHybridInfo?.HybridMap?.ContainsKey(guid) ?? false)
+ {
+ Importer.TheHybridInfo.RepresentationsAlreadyCreated = true;
+ }
+ }
+
+ ///
+ /// The Dispose method.
+ ///
+ public void Dispose()
+ {
+ if (Importer.TheHybridInfo != null)
+ {
+ Importer.TheHybridInfo.RepresentationsAlreadyCreated = false;
+ }
+ }
+ }
+
+///
+/// Provide methods to perform Hybrid IFC Import.
+///
+public class IFCImportHybridInfo
{
///
/// Keeps track of Elements imported (DirectShape/DirectShapeTypes) by AnyCAD
@@ -75,9 +107,9 @@ public class IFCImportHybridInfo
public string IfcInputFile { get; set; } = null;
///
- /// Transform applied to all Elements created via open-source processing within Revit.
+ /// Origin offset applied to all Elements created via legacy processing within Revit.
///
- public Transform LargeCoordinateTransform { get; set; } = Transform.Identity;
+ public XYZ LargeCoordinateOriginOffset { get; set; } = XYZ.Zero;
///
/// Keeps track of one-to-many mapping of entities that will result in container to sub-Element relationships.
@@ -91,7 +123,13 @@ public class IFCImportHybridInfo
///
private IFCHybridImport HybridImporter { get; set; } = null;
- public IFCImportHybridInfo(Document ifcDocument, string ifcInputFile)
+ ///
+ /// Create a new IFCImportHybridInfo.
+ ///
+ /// The document that will contain elements created by AnyCAD.
+ /// The IFC file to import.
+ /// If true, update an existing document (don't recreate elements).
+ public IFCImportHybridInfo(Document ifcDocument, string ifcInputFile, bool doUpdate)
{
HybridImporter = new IFCHybridImport();
@@ -110,17 +148,16 @@ public IFCImportHybridInfo(Document ifcDocument, string ifcInputFile)
// Import Elements
//
- int? elementsImported = ImportElements();
+ int? elementsImported = ImportElements(doUpdate);
if (elementsImported == null)
{
- IfcDocument.Application.WriteJournalComment("Hybrid IFC Import: elementsImportedList = null -- reverting to fallback for entire import.", false);
Importer.TheLog.LogError(-1, "Hybrid IFC Import: Unknown Error during Element Import -- aborting", true);
return;
}
if (elementsImported == 0)
{
- IfcDocument.Application.WriteJournalComment("Hybrid IFC Import: elementsImportedList empty -- reverting to fallback for entire import.", false);
+ Importer.TheLog.LogError(-1, "Hybrid IFC Import: elementsImportedList empty -- reverting to fallback for entire import.", false);
return;
}
@@ -129,7 +166,6 @@ public IFCImportHybridInfo(Document ifcDocument, string ifcInputFile)
int? associationsPerformed = AssociateElementsWithIFCGuids();
if (associationsPerformed == null)
{
- IfcDocument.Application.WriteJournalComment("Hybrid IFC Import: Hybrid IFC Map null -- falling back to Revit for entire import.", false);
Importer.TheLog.LogError(-1, "Hybrid IFC Import: Unknown Error during Element / IFC Guid association.", true);
return;
}
@@ -137,15 +173,17 @@ public IFCImportHybridInfo(Document ifcDocument, string ifcInputFile)
// Not an error, but this may hinder the Import Later.
if (associationsPerformed != elementsImported)
{
- IfcDocument.Application.WriteJournalComment("Hybrid IFC Import: Count of Elements in map differs from elements Imported -- falling back to Revit for part of import.", false);
Importer.TheLog.LogWarning(-1, "Hybrid IFC Import: Number of Element / IFC Guid associations do not match number of imported Elements.", false);
}
- Importer.TheLog.LogComment(-1, "--- Hybrid IFC Import: Start of Logging detailed Information about AnyCAD Import ---", false);
- Importer.TheLog.LogComment(-1, "Hybrid IFC Import: If an IfcGuid does not appear in the following list, then it will fallback to Revit processing ---", false);
- LogImportedElementsDetailed();
- LogHybridMapDetailed();
- Importer.TheLog.LogComment(-1, "--- Hybrid IFC Import: End of Logging detailed Information about AnyCAD Import ---", false);
+ if (Importer.TheOptions.VerboseLogging)
+ {
+ Importer.TheLog.LogComment(-1, "--- Hybrid IFC Import: Start of Logging detailed Information about AnyCAD Import ---", false);
+ Importer.TheLog.LogComment(-1, "Hybrid IFC Import: If an IfcGuid does not appear in the following list, then it will fallback to Revit processing ---", false);
+ LogImportedElementsDetailed();
+ LogHybridMapDetailed();
+ Importer.TheLog.LogComment(-1, "--- Hybrid IFC Import: End of Logging detailed Information about AnyCAD Import ---", false);
+ }
}
///
@@ -228,7 +266,7 @@ public void LogHybridMapDetailed ()
///
/// Log ElementIds that will be deleted at the end of Import. These is populated when Revit must create a new DirectShape for a category change.
///
- public void LogElementsToDeleteDetailed ()
+ public void LogElementsToDeleteDetailed()
{
Importer.TheLog.LogComment(-1, "--- Hybrid IFC Import: Start Elements to be deleted Details. ---", false);
foreach (ElementId elementId in ElementsToDelete)
@@ -254,16 +292,14 @@ public void LogElementsToDeleteDetailed ()
}
///
- /// Import Elements from IFC File using AnyCAD.
- /// Imported Elements will be in the HybridElements data member.
+ /// Import Elements from IFC File using AnyCAD. Imported Elements will be in the HybridElements data member.
///
- /// Number of Elements returned.
- ///
- public int? ImportElements()
+ /// The number of elements created.
+ public int? ImportElements(bool update)
{
if (HybridImporter == null)
{
- throw new InvalidOperationException("Attempting to import elements with null IFCHybridImporter");
+ throw new ArgumentNullException("Attempting to import elements with null IFCHybridImporter");
}
if (IfcDocument == null)
@@ -278,11 +314,33 @@ public void LogElementsToDeleteDetailed ()
return null;
}
- HybridElements = HybridImporter.ImportElements(IfcDocument, IfcInputFile);
+ if (update)
+ {
+ //IFC Extension back - compatibility:
+ //HybridImporter.UpdateElements method available since Revit 2024.1, handle it for addin usage with the previous Revit versions.
+ //
+ try
+ {
+ TryToUpdateElements();
+ }
+ catch(MissingMethodException)
+ {
+ HybridElements = HybridImporter.ImportElements(IfcDocument, IfcInputFile);
+ }
+ }
+ else
+ {
+ HybridElements = HybridImporter.ImportElements(IfcDocument, IfcInputFile);
+ }
return HybridElements?.Count;
}
+ private void TryToUpdateElements()
+ {
+ HybridElements = HybridImporter.UpdateElements(IfcDocument, IfcInputFile);
+ }
+
///
/// Associate ElementIds with IFCGuids. In other words, populate the IFCGuid --> ElementId map.
///
@@ -326,15 +384,13 @@ public void LogElementsToDeleteDetailed ()
{
HybridMap.Add(ifcGuid, elementId);
}
- catch (ArgumentException ex)
+ catch (ArgumentException)
{
Importer.TheLog.LogWarning(-1, "Duplicate IFC Global Ids. This will cause some IFC entities to fallback to Revit processing.", false);
- IfcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Duplicate IFC GUIDs detected in Hybrid IFC Map. Exception message = {ex.Message}", false);
}
- catch (Exception ex)
+ catch (Exception)
{
Importer.TheLog.LogWarning(-1, "Error in adding items to IFC GUID-to-ElementId map. This will cause some IFC entities to fallback to Revit processing.", false);
- IfcDocument.Application.WriteJournalComment($"Hybrid IFC Import: Exception adding items to IFC GUID-to-ElementId map. Exception message = {ex.Message}", false);
}
}
return HybridMap?.Count;
@@ -384,14 +440,15 @@ public ElementId CreateEmptyContainer(IFCProduct ifcProduct)
return ElementId.InvalidElementId;
}
- // If Container is already in HybridMAp, DirectShape has already been created.
+ // If Container is already in HybridMap, DirectShape has already been created.
ElementId containerElementId;
if (HybridMap.TryGetValue(ifcProduct.GlobalId, out containerElementId))
{
return containerElementId;
}
- DirectShape emptyContainerDS = IFCElementUtil.CreateElement(IfcDocument, ifcProduct.CategoryId, ifcProduct.GlobalId, null, ifcProduct.Id, ifcProduct.EntityType);
+ DirectShape emptyContainerDS = IFCElementUtil.CreateElement(IfcDocument, ifcProduct.GetCategoryId(IfcDocument),
+ ifcProduct.GlobalId, null, ifcProduct.Id, ifcProduct.EntityType);
if (emptyContainerDS == null)
{
return ElementId.InvalidElementId;
@@ -424,7 +481,8 @@ public ElementId CreateContainer(IFCGroup ifcGroup)
return ElementId.InvalidElementId;
}
- DirectShape directShape = DirectShape.CreateElement(IfcDocument, IFCElementUtil.GetDSValidCategoryId(IfcDocument, ifcGroup.CategoryId, ifcGroup.Id));
+ ElementId categoryId = IFCElementUtil.GetDSValidCategoryId(IfcDocument, ifcGroup.GetCategoryId(IfcDocument), ifcGroup.Id);
+ DirectShape directShape = DirectShape.CreateElement(IfcDocument, categoryId);
if (directShape == null)
{
return ElementId.InvalidElementId;
@@ -467,142 +525,109 @@ public ElementId CreateContainer(IFCGroup ifcGroup)
/// empty
///
/// Entity that may exhibit special-case behavior.
+ /// The element id of the existing DirectShape.
/// ElementId of new DirectShape if new Element created, ElementId.InvalidElement otherwise.
- public ElementId CreateElementForSpecialCases(IFCObjectDefinition objectDefinition)
+ private void UpdateElementForSpecialCases(IFCObjectDefinition objectDefinition, ref ElementId hybridElementId)
{
if (objectDefinition == null)
{
Importer.TheLog.LogNullError(objectDefinition.EntityType);
- return ElementId.InvalidElementId;
+ return;
}
- ElementId newElementId = ElementId.InvalidElementId;
- // Special Cases:
- // 1. Columns that should be Structure Columns.
- // 2. Containers that have sub-elements.
+ // Special Case: columns that should be structural columns.
if (IFCCategoryUtil.IsSpecialColumnCase(objectDefinition))
{
- newElementId = (objectDefinition is IFCProduct architecturalColumn) ? CreateStructuralColumnDirectShape(architecturalColumn) : ElementId.InvalidElementId;
- }
- else if (objectDefinition.IsHybridImportContainer())
- {
- newElementId = (objectDefinition is IFCProduct container) ? CreateContainer(container) : ElementId.InvalidElementId;
- }
+ if (objectDefinition is IFCProduct architecturalColumn)
+ {
+ try
+ {
+ UpdateStructuralColumnDirectShape(architecturalColumn, hybridElementId);
+ }
+ catch (MissingMethodException)
+ {
+ ElementId specialCaseElementId = CreateStructuralColumnDirectShape(architecturalColumn, hybridElementId);
- // If special case processing resulted in an error, or did not change the ElementId, there is no need to replace
- // the old ElementId with a new one.
- if ((newElementId != ElementId.InvalidElementId) && (newElementId != objectDefinition.CreatedElementId))
- {
- ReplaceElementId(objectDefinition.GlobalId, objectDefinition.CreatedElementId, newElementId);
+ if ((specialCaseElementId != ElementId.InvalidElementId) && (specialCaseElementId != hybridElementId))
+ {
+ ElementId hybridElementIdToDelete = new ElementId(hybridElementId.Value);
+ // specialCaseElementId has replaced hybridElementId in the HybridMap.
+ // The hybridElementId will be deleted later.
+ Importer.TheHybridInfo.ElementsToDelete.Add(hybridElementIdToDelete);
+ hybridElementId = specialCaseElementId;
+ }
+ }
+ }
}
-
- return newElementId;
}
///
- /// Populate Container DirectShape Element with sub-Element Geometry.
- /// This will not actually create the DirectShape. The DirectShape should already exist and be within the HybridMap.
+ /// Update a DirectShape and its type to be a Structural Column.
///
- /// IFCProduct representing the Container.
- /// ElementId of the DirectShape if successful, ElementId.InvalidElementId otherwise.
- protected ElementId CreateContainer(IFCProduct containerProduct)
+ /// Column that needs a Category change from OST_Column to OST_StructuralColumn.
+ private void UpdateStructuralColumnDirectShape(IFCProduct ifcColumn, ElementId hybridElementId)
{
- // If nothing is in the HybridMap, just return. Nothing needs to be done.
- if ((containerProduct == null) || ((HybridMap?.Count ?? 0) == 0))
+ if (ifcColumn == null)
{
- Importer.TheLog.LogNullError(containerProduct.EntityType);
+ Importer.TheLog.LogError(-1, "IfcColumn invalid during DirectShape recategorization.", false);
+ return;
}
- int stepId = containerProduct.Id;
- string containerGuid = containerProduct.GlobalId;
- ElementId containerCategoryId = containerProduct.CategoryId;
- if ((stepId < 1) || string.IsNullOrEmpty(containerGuid) || (containerCategoryId == ElementId.InvalidElementId))
+ int stepId = ifcColumn.Id;
+ ElementId ifcColumnCategory = ifcColumn.GetCategoryId(IfcDocument);
+ if (ifcColumnCategory != new ElementId(BuiltInCategory.OST_StructuralColumns))
{
- Importer.TheLog.LogError(stepId, "Cannot create Container Geometry for IfcProduct -- invalid entity", false);
- return ElementId.InvalidElementId;
+ Importer.TheLog.LogWarning(stepId, "IfcColumn is not a Structural Column", false);
+ return;
}
- if (HybridMap == null)
+ DirectShape directShape = IfcDocument.GetElement(hybridElementId) as DirectShape;
+ ElementId directShapeCategory = (directShape?.Category?.Id ?? ElementId.InvalidElementId);
+ if (directShapeCategory == ElementId.InvalidElementId)
{
- Importer.TheLog.LogWarning(stepId, $"No Sub-elements imported for {containerProduct.GlobalId} via Hybrid. Nothing to reference", false);
- return ElementId.InvalidElementId;
+ Importer.TheLog.LogWarning(stepId, "Unable to determine Category of DirectShape.", false);
+ return;
}
- IList newGeometryObjects = new List();
-
- // If there is any Geometry already within the DirectShape (there may be an Axis Curve for an IfcWall, for instance,
- // add it to the Shape used at the end. This will overwrite the current Geometry.
- ElementId containerDirectShapeElementId = ElementId.InvalidElementId;
- if (!HybridMap.TryGetValue(containerGuid, out containerDirectShapeElementId))
+ if (directShapeCategory == ifcColumnCategory)
{
- return ElementId.InvalidElementId;
+ Importer.TheLog.LogComment(stepId, "Category of Column and DirectShape agree. No recategorization needed.", false);
+ return;
}
- DirectShape containerDirectShape = IfcDocument.GetElement(containerDirectShapeElementId) as DirectShape;
- if (containerDirectShape == null)
- {
- return ElementId.InvalidElementId;
- }
+ //IFC Extension back-compatibility:
+ //ImporterIFCUtils.UpdateDirectShapeCategory method available since Revit 2024.1, handle it for addin usage with the previous Revit versions.
+ //Handle this with using CreateStructuralColumnDirectShape instead by catching MissingMethodExseption in UpdateElementForSpecialCases.
+ //
- Options options = new Options();
- GeometryElement oldContainerGeometryElement = containerDirectShape?.get_Geometry(options);
- if (oldContainerGeometryElement != null)
+ ImporterIFCUtils.UpdateDirectShapeCategory(directShape, new ElementId(BuiltInCategory.OST_StructuralColumns));
+
+ (IList newGeomObjects, ElementId directShapeTypeId) =
+ DuplicateGeometryForDirectShape(directShape, ifcColumn);
+ if ((newGeomObjects?.Count ?? 0) == 0)
{
- foreach (GeometryObject geomObj in oldContainerGeometryElement)
- {
- if (geomObj != null)
- {
- newGeometryObjects.Add(geomObj);
- }
- }
+ Importer.TheLog.LogError(stepId, "Unable to duplicate Geometry for DirectShape recategorization.", false);
+ return;
}
- // Iterate through all the sub-elements.
- HashSet relatedObjects = null;
- if (!(ContainerMap?.TryGetValue(stepId, out relatedObjects) ?? false))
+ GeometryInstance newDirectShapeGeometryInstance = newGeomObjects.First() as GeometryInstance;
+ if (newDirectShapeGeometryInstance == null)
{
- Importer.TheLog.LogComment(stepId, $"No Related Objects for Container {containerProduct.GlobalId}.", false);
- return ElementId.InvalidElementId;
+ Importer.TheLog.LogWarning(stepId, "Duplicate Geometry is not a GeometryInstance. Using old Geometry.", false);
+ return;
}
- foreach (IFCObjectDefinition relatedObject in relatedObjects)
+ ElementId directShapeGeomTypeId = newDirectShapeGeometryInstance.GetSymbolGeometryId().SymbolId;
+ if (directShapeGeomTypeId == ElementId.InvalidElementId)
{
- // Get the DirectShape for each sub-element. It should be there.
- ElementId subElementId;
- if (!HybridMap.TryGetValue(relatedObject.GlobalId, out subElementId))
- {
- Importer.TheLog.LogWarning(stepId, $"{relatedObject.GlobalId} is not an Aggregate of {containerProduct.GlobalId}", false);
- continue;
- }
-
- DirectShape subElementDirectShape = IfcDocument.GetElement(subElementId) as DirectShape;
- if (subElementDirectShape == null)
- {
- continue;
- }
-
- // Duplicate sub-Element Geometry using the Category of the Container Geometry.
- IList newSubElementGeometries = DuplicateGeometryForDirectShape(subElementDirectShape, containerProduct);
- if ((newSubElementGeometries?.Count ?? 0) == 0)
- {
- Importer.TheLog.LogError(stepId, "Unable to duplicate Geometry for DirectShape recategorization.", false);
- return ElementId.InvalidElementId;
- }
-
- // Reference new sub-Element Geometry.
- GeometryInstance newSubElementGeometryInstance = newSubElementGeometries.First() as GeometryInstance; ;
- if (newSubElementGeometryInstance == null)
- {
- Importer.TheLog.LogWarning(stepId, "Duplicate Geometry is not a GeometryInstance. Using old Geometry.", false);
- return ElementId.InvalidElementId;
- }
-
- newGeometryObjects.Add(newSubElementGeometryInstance);
+ Importer.TheLog.LogWarning(stepId, "Even though new DirectShape Geometry created, unable to find DirectShapeType.", false);
+ return;
}
- // Set the Geometry of the containerDirectShape to newGeometryObjects.
- containerDirectShape.SetShape(newGeometryObjects);
- return containerDirectShape.Id;
+ directShape.SetShape(newGeomObjects);
+
+ if (directShapeTypeId == directShapeGeomTypeId)
+ directShape.SetTypeId(directShapeGeomTypeId);
}
///
@@ -611,7 +636,7 @@ protected ElementId CreateContainer(IFCProduct containerProduct)
///
/// Column that needs a Category change from OST_Column to OST_StructuralColumn.
/// ElementId of new Structural Column for successful creation, ElementId.InvalidElementId otherwise.
- protected ElementId CreateStructuralColumnDirectShape(IFCProduct ifcColumn)
+ private ElementId CreateStructuralColumnDirectShape(IFCProduct ifcColumn, ElementId hybridElementId)
{
if (ifcColumn == null)
{
@@ -620,15 +645,14 @@ protected ElementId CreateStructuralColumnDirectShape(IFCProduct ifcColumn)
}
int stepId = ifcColumn.Id;
- ElementId ifcColumnCategory = ifcColumn.CategoryId;
+ ElementId ifcColumnCategory = ifcColumn.GetCategoryId(IfcDocument);
if (ifcColumnCategory != new ElementId(BuiltInCategory.OST_StructuralColumns))
{
Importer.TheLog.LogWarning(stepId, "IfcColumn is not a Structural Column", false);
return ElementId.InvalidElementId;
}
- ElementId oldDirectShapeElementId = ifcColumn.CreatedElementId;
- DirectShape oldDirectShape = IfcDocument.GetElement(oldDirectShapeElementId) as DirectShape;
+ DirectShape oldDirectShape = IfcDocument.GetElement(hybridElementId) as DirectShape;
ElementId oldDirectShapeCategory = (oldDirectShape?.Category?.Id ?? ElementId.InvalidElementId);
if (oldDirectShapeCategory == ElementId.InvalidElementId)
{
@@ -643,7 +667,8 @@ protected ElementId CreateStructuralColumnDirectShape(IFCProduct ifcColumn)
}
// Perform Deep copy of Geometry and DirectShapeTypes.
- IList newGeomObjects = DuplicateGeometryForDirectShape(oldDirectShape, ifcColumn);
+ (IList newGeomObjects, ElementId directShapeTypeId)
+ = DuplicateGeometryForDirectShape(oldDirectShape, ifcColumn);
if ((newGeomObjects?.Count ?? 0) == 0)
{
Importer.TheLog.LogError(stepId, "Unable to duplicate Geometry for DirectShape recategorization.", false);
@@ -657,15 +682,14 @@ protected ElementId CreateStructuralColumnDirectShape(IFCProduct ifcColumn)
return ElementId.InvalidElementId;
}
- ElementId directShapeTypeId = newDirectShapeGeometryInstance.GetSymbolGeometryId().SymbolId;
+ directShapeTypeId = newDirectShapeGeometryInstance.GetSymbolGeometryId().SymbolId;
if (directShapeTypeId == ElementId.InvalidElementId)
{
Importer.TheLog.LogWarning(stepId, "Even though new DirectShape Geometry created, unable to find DirectShapeType.", false);
return ElementId.InvalidElementId;
}
- IList structuralColumnGeometry = new List();
- structuralColumnGeometry.Add(newDirectShapeGeometryInstance);
+ IList structuralColumnGeometry = new List() { newDirectShapeGeometryInstance };
DirectShape newDirectShape = IFCElementUtil.CreateElement(IfcDocument, ifcColumnCategory, ifcColumn.GlobalId, structuralColumnGeometry, stepId, ifcColumn.EntityType);
if (newDirectShape == null)
@@ -678,6 +702,8 @@ protected ElementId CreateStructuralColumnDirectShape(IFCProduct ifcColumn)
return newDirectShape.Id;
}
+
+
///
/// Duplicates Geometry within DirectShape for a new DirectShape creation.
/// This is to drive the process where the DirectShape -> GInstance -> DirectShapeType -> etc. will be preserved.
@@ -685,33 +711,46 @@ protected ElementId CreateStructuralColumnDirectShape(IFCProduct ifcColumn)
/// ElementId for the exiting DirectShape.
/// IfcProduct corresponding to the DirectShape.
/// List of Geometry Objects for the new DirectShape.
- protected IList DuplicateGeometryForDirectShape(DirectShape oldDirectShape, IFCProduct ifcProduct)
+ private GeometryInstance GetDirectShapeGeometryInstance(DirectShape directShape)
{
- int stepId = ifcProduct?.Id ?? -1;
- if ((oldDirectShape == null) || (stepId <= 0))
- {
- return null;
- }
-
// DirectShape should have one and only one GeometryInstance, and no other GeometryObjects.
Options options = new Options();
- GeometryElement geometryElement = oldDirectShape?.get_Geometry(options);
+ GeometryElement geometryElement = directShape?.get_Geometry(options);
if ((geometryElement?.Count() ?? 0) == 0)
{
return null;
}
- GeometryInstance oldDirectShapeGeometryInstance = geometryElement?.First() as GeometryInstance;
+ return geometryElement?.First() as GeometryInstance;
+ }
+
+ ///
+ /// Duplicates Geometry within DirectShape for a new DirectShape creation.
+ /// This is to drive the process where the DirectShape -> GInstance -> DirectShapeType -> etc. will be preserved.
+ ///
+ /// ElementId for the exiting DirectShape.
+ /// IfcProduct corresponding to the DirectShape.
+ /// List of Geometry Objects for the new DirectShape and the old DirectShapeType element id.
+ protected (IList, ElementId) DuplicateGeometryForDirectShape(DirectShape oldDirectShape, IFCProduct ifcProduct)
+ {
+ int stepId = ifcProduct?.Id ?? -1;
+ if (stepId <= 0)
+ {
+ return (null, ElementId.InvalidElementId);
+ }
+
+ // DirectShape should have one and only one GeometryInstance, and no other GeometryObjects.
+ GeometryInstance oldDirectShapeGeometryInstance = GetDirectShapeGeometryInstance(oldDirectShape);
GeometryElement oldDirectShapeTypeGeometryElement = oldDirectShapeGeometryInstance?.SymbolGeometry;
if (oldDirectShapeTypeGeometryElement == null)
{
- return null;
+ return (null, ElementId.InvalidElementId);
}
ElementId oldDirectShapeTypeElementId = oldDirectShapeGeometryInstance?.GetSymbolGeometryId().SymbolId ?? ElementId.InvalidElementId;
if (oldDirectShapeTypeElementId == ElementId.InvalidElementId)
{
- return null;
+ return (null, ElementId.InvalidElementId);
}
// Reminder: the passed-in IfcProduct may be a Container for the DirectShape.
@@ -724,18 +763,19 @@ protected IList DuplicateGeometryForDirectShape(DirectShape oldD
}
// Most of the work happens here to Copy DirectShapeTypes.
- ElementId newDirectShapeTypeId = DeepCopyDirectShapeType(oldDirectShapeTypeElementId, oldDirectShapeTypeGeometryElement, ifcProduct.CategoryId, ifcTypeObject);
+ ElementId newDirectShapeTypeId = DeepCopyDirectShapeType(oldDirectShapeTypeElementId,
+ oldDirectShapeTypeGeometryElement, ifcProduct.GetCategoryId(IfcDocument), ifcTypeObject);
string definitionId = GetDirectShapeTypeDefinitionId(newDirectShapeTypeId);
if (string.IsNullOrEmpty(definitionId))
{
- return null;
+ return (null, ElementId.InvalidElementId);
}
// Create new GeoemtryInstance to add new DirectShapeType using the same Trf.
// String = ifcTypeObject.GlobalId + oldDirectShapeTypeElementId (as a string).
IList newGeomObjects = DirectShape.CreateGeometryInstance(IfcDocument, definitionId, oldDirectShapeGeometryInstance.Transform);
- return newGeomObjects;
+ return (newGeomObjects, oldDirectShapeTypeElementId);
}
///
@@ -944,20 +984,23 @@ public IList DuplicateDirectShapeGeometry(IList direc
///
/// Some data is contained in the ShapeEditScope (but not actual geometry).
/// IFCProduct to edit.
- public ElementId HandleHybridProductCreation(IFCImportShapeEditScope shapeEditScope, IFCProduct ifcProduct)
+ /// The associated element id.
+ /// The list of created geometries.
+ public IList HandleHybridProductCreation(IFCImportShapeEditScope shapeEditScope,
+ IFCProduct ifcProduct, ref ElementId hybridElementId)
{
- if (!Importer.TheOptions.IsHybridImport || (shapeEditScope == null) || (ifcProduct == null) || (ifcProduct.CreatedElementId == ElementId.InvalidElementId))
+ IList createdGeometries = new List();
+
+ if (!Importer.TheOptions.IsHybridImport || (shapeEditScope == null) || (ifcProduct == null) || (hybridElementId == ElementId.InvalidElementId))
{
- return ElementId.InvalidElementId;
+ return createdGeometries;
}
- ElementId hybridElementId = ifcProduct.CreatedElementId;
-
// Get DirectShape to "Create". It's already created, so Revit is not really creating it here.
DirectShape directShape = IfcDocument.GetElement(hybridElementId) as DirectShape;
if (directShape == null)
{
- return ElementId.InvalidElementId;
+ return createdGeometries;
}
// Get solids for IFCProduct. Only Points and Curves should be contained within "Solids".
@@ -975,6 +1018,11 @@ public ElementId HandleHybridProductCreation(IFCImportShapeEditScope shapeEditSc
{
wireframeBuilder.AddCurve(currObject as Curve);
}
+ else
+ {
+ continue;
+ }
+ createdGeometries.Add(currObject);
}
directShape.AppendShape(wireframeBuilder);
@@ -992,20 +1040,8 @@ public ElementId HandleHybridProductCreation(IFCImportShapeEditScope shapeEditSc
// Handle Special Cases:
// 1. Possible Category Change for Structural Columns. This requires a whole new DirectShape/DirectShapeType tree creation.
// 2. Containers for IfcRelAggregates (e.g., IfcWall & IfcBuildingElementParts).
- // In either of these, the specialCaseElementId may end up being the same as the original CreatedElementId.
- // If new ElementId is in
- // This means that there was no new Element created, so don't delete the ElementId in that case.
- ElementId newCreatedId = hybridElementId;
- ElementId specialCaseElementId = Importer.TheHybridInfo.CreateElementForSpecialCases(ifcProduct);
- if ((specialCaseElementId != ElementId.InvalidElementId) && (specialCaseElementId != hybridElementId))
- {
- // specialCaseElementId has replaced hybridElementId in the HybridMap.
- // The hybridElementId will be deleted later.
- Importer.TheHybridInfo.ElementsToDelete.Add(hybridElementId);
- newCreatedId = specialCaseElementId;
- }
-
- return newCreatedId;
+ Importer.TheHybridInfo.UpdateElementForSpecialCases(ifcProduct, ref hybridElementId);
+ return createdGeometries;
}
///
diff --git a/Source/Revit.IFC.Import/Utility/IFCImportOptions.cs b/Source/Revit.IFC.Import/Utility/IFCImportOptions.cs
index 64714038..999e7e1d 100644
--- a/Source/Revit.IFC.Import/Utility/IFCImportOptions.cs
+++ b/Source/Revit.IFC.Import/Utility/IFCImportOptions.cs
@@ -78,6 +78,25 @@ public void Dispose()
}
}
+ ///
+ /// Choice of Import Method stored to ProjectInfo.
+ ///
+ public enum ImportMethod
+ {
+ Hybrid,
+ Legacy
+ }
+
+ ///
+ /// Simply returns whether the CurrentImportMethod is Hybrid or Legacy. Useful when checking for previous import.
+ ///
+ public ImportMethod CurrentImportMethod => IsHybridImport ? ImportMethod.Hybrid : ImportMethod.Legacy;
+
+ ///
+ /// Defines parameter storing Import Method in ProjectInfo.
+ ///
+ public static string ImportMethodParameter => "Import Method";
+
///
/// If true, does an import optimized for performance that minimizes unnecessary functionality.
///
@@ -85,7 +104,7 @@ public void Dispose()
///
/// If we are linking, specify the file name of the intermediate Revit file. This can be null, and
- /// the .NET code will detemine the file name.
+ /// the .NET code will determine the file name.
///
public string RevitLinkFileName { get; protected set; } = null;
@@ -184,13 +203,13 @@ public static string ImporterVersion
/// True: Hybrid (legacy + AnyCAD)
/// False: legacy only
///
- public bool IsHybridImport { get; protected set; } = false;
+ public bool IsHybridImport { get; set; } = false;
protected IFCImportOptions()
{
}
- protected IFCImportOptions(IDictionary options, string ifcFileName)
+ protected IFCImportOptions(IDictionary options, string ifcFileName, Document doc)
{
// "Intent": covers what the import operation is intended to create.
// The two options are:
@@ -300,23 +319,32 @@ protected IFCImportOptions(IDictionary options, string ifcFileNa
ImportIFCOptions importIFCOptions = ImportIFCOptions.GetImportIFCOptions();
string linkProcessor = importIFCOptions.LinkProcessor;
- // For now, only use hybrid import if revit.ini has "AnyCAD" set and we are importing
- // STEP (.ifc) files.
- // In the future, this will change to:
- // IsHybridImport = (string.Compare(linkProcessor, "Legacy", true) != 0);
- IsHybridImport = (string.Compare(linkProcessor, "AnyCAD", true) == 0) &&
- (ifcFileName.EndsWith(".ifc"));
+ string revitVersion = doc.Application.VersionBuild;
+ if (revitVersion.StartsWith("24.0"))
+ {
+ // For Revit 24.0.x, only use hybrid import if revit.ini has "AnyCAD" set.
+ IsHybridImport = (string.Compare(linkProcessor, "AnyCAD", true) == 0) &&
+ (ifcFileName.EndsWith(".ifc")) && (Processor is IFCDefaultProcessor);
+ }
+ else
+ {
+ // For Revit 24.1.x
+ // Use hybrid import if revit.ini does not have "Legacy" in it and we are using
+ // the default (Revit) processor. For other processors (e.g., Navis), revert
+ // to Legacy.
+ IsHybridImport = (string.Compare(linkProcessor, "Legacy", true) != 0) &&
+ (Processor is IFCDefaultProcessor);
+ }
}
///
- /// Populate a new IFCImportOptions class with values based on the opions passed in by the user.
+ /// Populate a new IFCImportOptions class with values based on the options passed in by the user.
///
/// The user-set options for this import.
- /// The name of the IFC file.
/// The new IFCImportOptions class.
- static public IFCImportOptions Create(IDictionary options, string ifcFileName)
+ static public IFCImportOptions Create(IDictionary options, string ifcFileName, Document doc)
{
- return new IFCImportOptions(options, ifcFileName);
+ return new IFCImportOptions(options, ifcFileName, doc);
}
}
}
\ No newline at end of file
diff --git a/Source/Revit.IFC.Import/Utility/IFCImportShapeEditScope.cs b/Source/Revit.IFC.Import/Utility/IFCImportShapeEditScope.cs
index 298eabc6..e2eaab0f 100644
--- a/Source/Revit.IFC.Import/Utility/IFCImportShapeEditScope.cs
+++ b/Source/Revit.IFC.Import/Utility/IFCImportShapeEditScope.cs
@@ -70,12 +70,18 @@ private IList MaterialIdList
///
/// The id of the associated graphics style, if any.
///
- public ElementId GraphicsStyleId { get; set; } = ElementId.InvalidElementId;
+ public ElementId GraphicsStyleId
+ {
+ get { return Creator?.GetGraphicsStyleId(Document) ?? ElementId.InvalidElementId; }
+ }
///
/// The id of the associated category.
///
- public ElementId CategoryId { get; set; } = ElementId.InvalidElementId;
+ public ElementId CategoryId
+ {
+ get { return Creator?.GetCategoryId(Document) ?? ElementId.InvalidElementId; }
+ }
private void PushMaterialId(ElementId materialId)
diff --git a/Source/Revit.IFC.Import/Utility/ParametersToSet.cs b/Source/Revit.IFC.Import/Utility/ParametersToSet.cs
new file mode 100644
index 00000000..b5d00939
--- /dev/null
+++ b/Source/Revit.IFC.Import/Utility/ParametersToSet.cs
@@ -0,0 +1,427 @@
+using Autodesk.Revit.DB;
+using Revit.IFC.Import.Data;
+using Revit.IFC.Import.Enums;
+using System;
+using System.Collections.Generic;
+
+namespace Revit.IFC.Import.Utility
+{
+ public class ParameterSetter : IDisposable
+ {
+ public ParameterSetter()
+ {
+ ParametersToSet = new ParametersToSet();
+ }
+
+ public void Dispose()
+ {
+ if (ParametersToSet != null)
+ {
+ //IFC Extension back - compatibility:
+ //Parameter.SetMultiple method available since Revit 2024.1, handle it for addin usage with the previous Revit versions.
+ //
+ try
+ {
+ TryToSetMultipleParameters();
+ }
+ catch (MissingMethodException)
+ {
+ foreach (Tuple parameterAndParameterValue in ParametersToSet.ParameterList)
+ {
+ Parameter param = parameterAndParameterValue.Item1;
+ ParameterValue paramValue = parameterAndParameterValue.Item2;
+
+ if(param != null)
+ {
+ StorageType storageType = param.StorageType;
+ switch (storageType)
+ {
+ case StorageType.Integer:
+ {
+ param.Set((int)(paramValue as IntegerParameterValue)?.Value);
+ break;
+ }
+ case StorageType.Double:
+ {
+ param.Set((double)(paramValue as DoubleParameterValue)?.Value);
+ break;
+ }
+ case StorageType.String:
+ {
+ param.Set((string)(paramValue as StringParameterValue)?.Value);
+ break;
+ }
+ case StorageType.ElementId:
+ {
+ param.Set((ElementId)(paramValue as ElementIdParameterValue)?.Value);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void TryToSetMultipleParameters()
+ {
+ Parameter.SetMultiple(ParametersToSet.ParameterList);
+ }
+
+ public ParametersToSet ParametersToSet { get; private set; } = null;
+ }
+
+ ///
+ /// A list of parameters and values, intended to be set at once for performance reasons.
+ ///
+ public class ParametersToSet
+ {
+ ///
+ /// The default constructor.
+ ///
+ public ParametersToSet() { }
+
+ ///
+ /// Clears the list.
+ ///
+ public void Clear()
+ {
+ ParameterList.Clear();
+ }
+
+ ///
+ /// Adds an integer parameter.
+ ///
+ /// The parameter.
+ /// The integer value.
+ public void AddIntegerParameter(Parameter parameter, int value)
+ {
+ if (parameter == null)
+ return;
+
+ ParameterValue intValue = new IntegerParameterValue(value);
+ ParameterList.Add(Tuple.Create(parameter, intValue));
+ }
+
+ ///
+ /// Adds a double parameter.
+ ///
+ /// The parameter.
+ /// The double value.
+ public void AddDoubleParameter(Parameter parameter, double value)
+ {
+ if (parameter == null)
+ return;
+
+ ParameterValue stringValue = new DoubleParameterValue(value);
+ ParameterList.Add(Tuple.Create(parameter, stringValue));
+ }
+
+ private Parameter AddParameterBase(Document doc, Element element, Category category, string parameterName, int parameterSetId, ForgeTypeId specId)
+ {
+ bool isElementType = (element is ElementType);
+ Definitions definitions = isElementType ? Importer.TheCache.TypeGroupDefinitions : Importer.TheCache.InstanceGroupDefinitions;
+
+ bool newlyCreated = false;
+ Definition definition = definitions.get_Item(parameterName);
+ if (definition == null)
+ {
+ ExternalDefinitionCreationOptions option = new ExternalDefinitionCreationOptions(parameterName, specId);
+ definition = definitions.Create(option);
+ if (definition == null)
+ {
+ Importer.TheLog.LogError(parameterSetId, "Couldn't create parameter: " + parameterName, false);
+ return null;
+ }
+ newlyCreated = true;
+ }
+
+ Guid guid = (definition as ExternalDefinition).GUID;
+
+ Parameter parameter = null;
+ ElementBinding binding = null;
+ bool reinsert = false;
+
+ if (!newlyCreated)
+ {
+ BindingMap bindingMap = Importer.TheCache.GetParameterBinding(doc);
+ binding = bindingMap.get_Item(definition) as ElementBinding;
+ reinsert = (binding != null);
+ }
+
+ if (binding == null)
+ {
+ if (isElementType)
+ binding = new TypeBinding();
+ else
+ binding = new InstanceBinding();
+ }
+
+ // The binding can fail if we haven't identified a "bad" category above. Use try/catch as a safety net.
+ try
+ {
+ if (!reinsert || !binding.Categories.Contains(category))
+ {
+ binding.Categories.Insert(category);
+
+ BindingMap bindingMap = Importer.TheCache.GetParameterBinding(doc);
+ if (reinsert)
+ bindingMap.ReInsert(definition, binding, GroupTypeId.Ifc);
+ else
+ bindingMap.Insert(definition, binding, GroupTypeId.Ifc);
+ }
+
+ parameter = element.get_Parameter(guid);
+ }
+ catch
+ {
+ }
+
+ if (parameter == null)
+ Importer.TheLog.LogError(parameterSetId, "Couldn't create parameter: " + parameterName, false);
+
+ return parameter;
+ }
+
+ ///
+ /// Add a string parameter to an element.
+ ///
+ /// The document.
+ /// The element.
+ /// The category of the element.
+ /// The IFCObjectDefinition that created the element.
+ /// The enum corresponding to the parameter name.
+ /// The parameter value.
+ /// The id of the containing parameter set, for reporting errors.
+ /// True if the parameter was successfully added, false otherwise.
+ public bool AddStringParameter(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ IFCSharedParameters name, string parameterValue, int parameterSetId)
+ {
+ if (doc == null || element == null || category == null || objDef == null || parameterValue == null)
+ return false;
+
+ string parameterName = objDef.GetSharedParameterName(name, element is ElementType);
+
+ bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
+ if (processedParameter.HasValue)
+ return processedParameter.Value;
+
+ Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.Text);
+ if (parameter == null)
+ return false;
+
+ AddStringParameter(parameter, parameterValue);
+ return true;
+ }
+
+ ///
+ /// Add a string parameter to an element.
+ ///
+ /// The document.
+ /// The element.
+ /// The category of the element.
+ /// The parameter name.
+ /// The parameter value.
+ /// The id of the containing parameter set, for reporting errors.
+ /// True if the parameter was successfully added, false otherwise.
+ public bool AddStringParameter(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ string parameterName, string parameterValue, int parameterSetId)
+ {
+ if (doc == null || element == null || category == null)
+ return false;
+
+ bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
+ if (processedParameter.HasValue)
+ return processedParameter.Value;
+
+ Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.Text);
+ if (parameter == null)
+ return false;
+
+ AddStringParameter(parameter, parameterValue);
+ return true;
+ }
+
+ ///
+ /// Adds a string parameter.
+ ///
+ /// The parameter.
+ /// The string value.
+ public void AddStringParameter(Parameter parameter, string value)
+ {
+ if (parameter == null)
+ return;
+
+ ParameterValue stringValue = new StringParameterValue(value == null ? string.Empty : value);
+ ParameterList.Add(Tuple.Create(parameter, stringValue));
+ }
+
+ ///
+ /// Adds a parameter with the name of an element represented by an ElementId to an element.
+ ///
+ /// The document.
+ /// The element.
+ /// The category of the element.
+ /// The parameter name.
+ /// The parameter value.
+ /// The id of the containing parameter set, for reporting errors.
+ /// True if the parameter was successfully added, false otherwise.
+ public bool AddParameterElementId(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ string parameterName, ElementId parameterValue, int parameterSetId)
+ {
+ if (doc == null || element == null || category == null)
+ return false;
+
+ Element parameterElement = doc.GetElement(parameterValue);
+ if (parameterElement == null)
+ return false;
+
+ string name = parameterElement.Name;
+ if (string.IsNullOrEmpty(name))
+ return false;
+
+ bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
+ if (processedParameter.HasValue)
+ return processedParameter.Value;
+
+ Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.Text);
+ if (parameter == null)
+ return false;
+
+ AddStringParameter(parameter, name);
+ return true;
+ }
+
+ ///
+ /// Add a Boolean parameter to an element.
+ ///
+ /// The document.
+ /// The element.
+ /// The category of the element.
+ /// The parameter name.
+ /// The parameter value.
+ /// The id of the containing parameter set, for reporting errors.
+ /// True if the parameter was successfully added, false otherwise.
+ public bool AddParameterBoolean(Document doc, Element element, Category category,
+ IFCObjectDefinition objDef, string parameterName, bool parameterValue, int parameterSetId)
+ {
+ if (doc == null || element == null || category == null)
+ return false;
+
+ bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
+ if (processedParameter.HasValue)
+ return processedParameter.Value;
+
+ Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.Boolean.YesNo);
+ if (parameter == null)
+ return false;
+
+ AddIntegerParameter(parameter, parameterValue ? 1 : 0);
+ return true;
+ }
+
+ ///
+ /// Add an int parameter to an element.
+ ///
+ /// The document.
+ /// The element.
+ /// The category of the element.
+ /// The parameter name.
+ /// The parameter value.
+ /// The id of the containing parameter set, for reporting errors.
+ /// True if the parameter was successfully added, false otherwise.
+ public bool AddParameterInt(Document doc, Element element, Category category, IFCObjectDefinition objDef,
+ string parameterName, int parameterValue, int parameterSetId)
+ {
+ if (doc == null || element == null || category == null)
+ return false;
+
+ bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
+ if (processedParameter.HasValue)
+ return processedParameter.Value;
+
+ Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.Int.Integer);
+ if (parameter == null)
+ return false;
+
+ AddIntegerParameter(parameter, parameterValue);
+ return true;
+ }
+
+ private static ForgeTypeId CalculateUnitsTypeId(ForgeTypeId unitsTypeId,
+ ForgeTypeId specTypeId)
+ {
+ if (unitsTypeId != null || Importer.TheProcessor.ScaleValues)
+ return unitsTypeId;
+
+ // We can look up the units when the values are not scaled.
+ var units = IFCImportFile.TheFile.IFCUnits.GetIFCProjectUnit(specTypeId);
+ return (units != null) ? units.Unit : UnitTypeId.General;
+ }
+
+
+ ///
+ /// Add a double parameter to an element.
+ ///
+ /// The document.
+ /// The element.
+ /// The category of the element.
+ /// The parameter name.
+ /// Identifier of the parameter spec (e.g. length)
+ /// Identifier of the unscaled parameter units (e.g. mm)
+ /// The parameter value, scaled into document units.
+ /// The id of the containing parameter set, for reporting errors.
+ /// True if the parameter was successfully added, false otherwise.
+ public bool AddParameterDouble(Document doc, Element element, Category category,
+ IFCObjectDefinition objDef, string parameterName, ForgeTypeId specTypeId,
+ ForgeTypeId unitsTypeId, double parameterValue, int parameterSetId)
+ {
+ if (doc == null || element == null || category == null)
+ return false;
+
+ unitsTypeId = CalculateUnitsTypeId(unitsTypeId, specTypeId);
+ bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id,
+ specTypeId, unitsTypeId, parameterSetId, parameterName, parameterValue);
+ if (processedParameter.HasValue)
+ return processedParameter.Value;
+
+ Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, specTypeId);
+ if (parameter == null)
+ return false;
+
+ AddDoubleParameter(parameter, parameterValue);
+ return true;
+ }
+
+ ///
+ /// Add a multistring parameter to an element.
+ ///
+ /// The document.
+ /// The element.
+ /// The category of the element.
+ /// The parameter name.
+ /// The parameter value.
+ /// The id of the containing parameter set, for reporting errors.
+ /// True if the parameter was successfully added, false otherwise.
+ public bool AddParameterMultilineString(Document doc, Element element, Category category,
+ IFCObjectDefinition objDef, string parameterName, string parameterValue, int parameterSetId)
+ {
+ if (doc == null || element == null || category == null)
+ return false;
+
+ bool? processedParameter = Importer.TheProcessor.ProcessParameter(objDef.Id, parameterSetId, parameterName, parameterValue);
+ if (processedParameter.HasValue)
+ return processedParameter.Value;
+
+ Parameter parameter = AddParameterBase(doc, element, category, parameterName, parameterSetId, SpecTypeId.String.MultilineText);
+ if (parameter == null)
+ return false;
+
+ AddStringParameter(parameter, parameterValue);
+ return true;
+ }
+
+ public IList> ParameterList { get; private set; } =
+ new List>();
+ };
+}
\ No newline at end of file