private void GetFabricSheetParams(FabricSheet sheet) { if (sheet == null) { return; } MeshLength = sheet.CutOverallLength; MeshWidth = sheet.CutOverallWidth; if (sheet == null) { return; } Document doc = sheet.Document; Element fabricSheetTypeElem = doc?.GetElement(sheet.GetTypeId()); FabricSheetType fabricSheetType = fabricSheetTypeElem as FabricSheetType; SteelGrade = NamingUtil.GetOverrideStringValue(sheet, "SteelGrade", null); Element majorFabricWireTypeElem = doc?.GetElement(fabricSheetType?.MajorDirectionWireType); FabricWireType majorFabricWireType = (majorFabricWireTypeElem == null) ? null : (majorFabricWireTypeElem as FabricWireType); if (majorFabricWireType != null) { LongitudinalBarNominalDiameter = UnitUtil.ScaleLength(majorFabricWireType.WireDiameter); double localRadius = LongitudinalBarNominalDiameter / 2.0; LongitudinalBarCrossSectionArea = localRadius * localRadius * Math.PI; } Element minorFabricWireTypeElem = doc?.GetElement(fabricSheetType?.MinorDirectionWireType); FabricWireType minorFabricWireType = (minorFabricWireTypeElem == null) ? null : (minorFabricWireTypeElem as FabricWireType); if (minorFabricWireType != null) { TransverseBarNominalDiameter = UnitUtil.ScaleLength(minorFabricWireType.WireDiameter); double localRadius = TransverseBarNominalDiameter / 2.0; TransverseBarCrossSectionArea = localRadius * localRadius * Math.PI; } LongitudinalBarSpacing = UnitUtil.ScaleLength(fabricSheetType.MajorSpacing); TransverseBarSpacing = UnitUtil.ScaleLength(fabricSheetType.MinorSpacing); }
/// <summary> /// Creates an opening from extrusion data. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="hostObjHnd">The host handle.</param> /// <param name="hostPlacement">The host placement.</param> /// <param name="hostElement">The host element.</param> /// <param name="insertElement">The opening element.</param> /// <param name="openingGUID">The opening GUID.</param> /// <param name="extrusionData">The extrusion data.</param> /// <param name="plane">The plane.</param> /// <param name="isRecess">True if it is a recess.</param> /// <returns>The opening handle.</returns> static public IFCAnyHandle CreateOpening(ExporterIFC exporterIFC, IFCAnyHandle hostObjHnd, IFCAnyHandle hostPlacement, Element hostElement, Element insertElement, string openingGUID, IFCExtrusionData extrusionData, Plane plane, bool isRecess, PlacementSetter setter, ProductWrapper localWrapper) { IFCFile file = exporterIFC.GetFile(); IList <CurveLoop> curveLoops = extrusionData.GetLoops(); if (curveLoops.Count == 0) { return(null); } if (plane == null) { // assumption: first curve loop defines the plane. if (!curveLoops[0].HasPlane()) { return(null); } plane = curveLoops[0].GetPlane(); } ElementId catId = CategoryUtil.GetSafeCategoryId(insertElement); IFCAnyHandle openingProdRepHnd = RepresentationUtil.CreateExtrudedProductDefShape(exporterIFC, insertElement, catId, curveLoops, plane, extrusionData.ExtrusionDirection, extrusionData.ScaledExtrusionLength); string openingObjectType = isRecess ? "Recess" : "Opening"; IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); string openingName = NamingUtil.GetNameOverride(insertElement, null); if (string.IsNullOrEmpty(openingName)) { openingName = NamingUtil.GetNameOverride(hostElement, NamingUtil.CreateIFCObjectName(exporterIFC, hostElement)); } IFCAnyHandle openingHnd = IFCInstanceExporter.CreateOpeningElement(file, openingGUID, ownerHistory, openingName, null, openingObjectType, ExporterUtil.CreateLocalPlacement(file, hostPlacement, null), openingProdRepHnd, null); IFCExtrusionCreationData ecData = null; if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities) { double height, width; ecData = new IFCExtrusionCreationData(); if (GeometryUtil.ComputeHeightWidthOfCurveLoop(curveLoops[0], plane, out height, out width)) { ecData.ScaledHeight = UnitUtil.ScaleLength(height); ecData.ScaledWidth = UnitUtil.ScaleLength(width); } else { double area = ExporterIFCUtils.ComputeAreaOfCurveLoops(curveLoops); ecData.ScaledArea = UnitUtil.ScaleArea(area); } PropertyUtil.CreateOpeningQuantities(exporterIFC, openingHnd, ecData); } if (localWrapper != null) { Element elementForProperties = null; if (GUIDUtil.IsGUIDFor(insertElement, openingGUID)) { elementForProperties = insertElement; } localWrapper.AddElement(elementForProperties, openingHnd, setter, ecData, true); } string voidGuid = GUIDUtil.CreateGUID(); IFCInstanceExporter.CreateRelVoidsElement(file, voidGuid, ownerHistory, null, null, hostObjHnd, openingHnd); return(openingHnd); }
/// <summary> /// Creates a creator from DoorWindowInfo. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="doorWindowInfo">The DoorWindowInfo.</param> /// <param name="instanceHandle">The instance handle.</param> /// <param name="levelId">The level id.</param> /// <returns>The creator.</returns> public static DoorWindowDelayedOpeningCreator Create(ExporterIFC exporterIFC, DoorWindowInfo doorWindowInfo, IFCAnyHandle instanceHandle, ElementId levelId) { if (exporterIFC == null || doorWindowInfo == null) { return(null); } DoorWindowDelayedOpeningCreator doorWindowDelayedOpeningCreator = null; if (doorWindowInfo.HasRealWallHost) { Document doc = doorWindowInfo.HostObject.Document; Wall wall = doorWindowInfo.HostObject as Wall; FamilyInstance famInst = doorWindowInfo.InsertInstance; ElementId hostId = wall != null ? wall.Id : ElementId.InvalidElementId; ElementId instId = famInst != null ? famInst.Id : ElementId.InvalidElementId; doorWindowDelayedOpeningCreator = new DoorWindowDelayedOpeningCreator(); doorWindowDelayedOpeningCreator.HostId = hostId; doorWindowDelayedOpeningCreator.InsertId = instId; doorWindowDelayedOpeningCreator.PosHingeSide = doorWindowInfo.PosHingeSide; doorWindowDelayedOpeningCreator.DoorWindowHnd = instanceHandle; doorWindowDelayedOpeningCreator.LevelId = levelId; doorWindowDelayedOpeningCreator.CreatedFromDoorWindowInfo = true; WallType wallType = doc.GetElement(wall.GetTypeId()) as WallType; double unScaledWidth = ((wallType != null) && (wallType.Kind != WallKind.Curtain)) ? wallType.Width : 0.0; if (!MathUtil.IsAlmostZero(unScaledWidth)) { IFCAnyHandle openingHnd = exporterIFC.GetDoorWindowOpeningHandle(instId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(openingHnd)) { XYZ cutDir = null; CurveLoop cutLoop = null; try { cutLoop = ExporterIFCUtils.GetInstanceCutoutFromWall(wall.Document, wall, famInst, out cutDir); } catch { cutLoop = null; // Couldn't create opening for door in wall - report as error in log when we create log file. } if (cutLoop != null) { if (doorWindowDelayedOpeningCreator.ExtrusionData == null) { doorWindowDelayedOpeningCreator.ExtrusionData = new List <IFCExtrusionData>(); } IFCExtrusionData extrusionData = new IFCExtrusionData(); extrusionData.ExtrusionDirection = cutDir; extrusionData.ScaledExtrusionLength = UnitUtil.ScaleLength(unScaledWidth); extrusionData.AddLoop(cutLoop); doorWindowDelayedOpeningCreator.ScaledHostWidth = UnitUtil.ScaleLength(unScaledWidth); doorWindowDelayedOpeningCreator.ExtrusionData.Add(extrusionData); doorWindowDelayedOpeningCreator.HasValidGeometry = true; } else { // Couldn't create opening for door in wall - report as error in log when we create log file. } } } } return(doorWindowDelayedOpeningCreator); }
/// <summary> /// Excutes the creator. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="doc">The document.</param> public void Execute(ExporterIFC exporterIFC, Document doc) { IFCAnyHandle hostObjHnd = !IFCAnyHandleUtil.IsNullOrHasNoValue(HostHnd) ? HostHnd : DoorWindowUtil.GetHndForHostAndLevel(exporterIFC, HostId, LevelId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjHnd)) { return; } IList <DoorWindowOpeningInfo> doorWindowOpeningInfoList = new List <DoorWindowOpeningInfo>(); Element doorElem = doc.GetElement(InsertId); string openingGUID = GUIDUtil.CreateSubElementGUID(doorElem, (int)IFCDoorSubElements.DoorOpening); if (ExtrusionData != null) { foreach (IFCExtrusionData extrusionData in ExtrusionData) { if (doorWindowOpeningInfoList.Count > 0) { openingGUID = GUIDUtil.CreateGUID(); } DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd, HostId, InsertId, openingGUID, extrusionData.GetLoops()[0], extrusionData.ExtrusionDirection, UnitUtil.UnscaleLength(extrusionData.ScaledExtrusionLength), PosHingeSide, IsRecess); if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd)) { doorWindowOpeningInfoList.Add(openingInfo); } } } if (Solids != null) { foreach (Solid solid in Solids) { if (doorWindowOpeningInfoList.Count > 0) { openingGUID = GUIDUtil.CreateGUID(); } DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd, HostId, InsertId, openingGUID, solid, ScaledHostWidth, IsRecess); if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd)) { doorWindowOpeningInfoList.Add(openingInfo); } } } if (IFCAnyHandleUtil.IsNullOrHasNoValue(DoorWindowHnd)) { return; } bool foundOpening = false; bool foundHeight = false; bool foundWidth = false; bool?isDoorOrWindowOpening = null; foreach (DoorWindowOpeningInfo openingInfo in doorWindowOpeningInfoList) { // If we've updated the door/window placement, and set its height and width, there's nothing more to do here. if (foundOpening && foundHeight && foundWidth) { break; } // update original door or window to be relative to the first opening we find. // We only allow one IfcRelFillsElement per door or window, so only do this for the first opening. if (!foundOpening) { IFCFile file = exporterIFC.GetFile(); IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle; IFCAnyHandle openingHnd = openingInfo.OpeningHnd; foundOpening = true; string relGUID = GUIDUtil.CreateGUID(); IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, openingHnd, DoorWindowHnd); IFCAnyHandle openingPlacement = IFCAnyHandleUtil.GetObjectPlacement(openingHnd); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(openingPlacement)) { IFCAnyHandle origObjectPlacement = IFCAnyHandleUtil.GetObjectPlacement(DoorWindowHnd); Transform relTransform = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(origObjectPlacement, openingPlacement); IFCAnyHandle newLocalPlacement = ExporterUtil.CreateLocalPlacement(file, openingPlacement, relTransform.Origin, relTransform.BasisZ, relTransform.BasisX); IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "ObjectPlacement", newLocalPlacement); origObjectPlacement.Delete(); } } // The first entry for a particular door may not have the height or width set, so keep looking until we find an entry that does. if (!isDoorOrWindowOpening.HasValue) { isDoorOrWindowOpening = IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcDoor) || IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcWindow); } if (!(foundHeight && foundWidth) && isDoorOrWindowOpening.Value) { double openingHeight = openingInfo.OpeningHeight; double openingWidth = openingInfo.OpeningWidth; if (openingHeight > MathUtil.Eps()) { foundHeight = true; IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallHeight", UnitUtil.ScaleLength(openingHeight)); } if (openingWidth > MathUtil.Eps()) { foundWidth = true; IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallWidth", UnitUtil.ScaleLength(openingWidth)); } } } }
/// <summary> /// Collect information about material layer. /// For IFC4RV Architectural exchange, it will generate IfcMatrialConstituentSet along with the relevant IfcShapeAspect and the width in the quantityset /// For IFC4RV Structural exchange, it will generate multiple components as IfcBuildingElementPart for each layer /// For others IfcMaterialLayer will be created /// </summary> private void CollectMaterialLayerSet() { ElementId typeElemId = m_Element.GetTypeId(); MaterialIds = new List <Tuple <ElementId, string, double> >(); IFCAnyHandle materialLayerSet = ExporterCacheManager.MaterialSetCache.FindLayerSet(typeElemId); // Roofs with no components are only allowed one material. We will arbitrarily choose the thickest material. PrimaryMaterialHandle = ExporterCacheManager.MaterialSetCache.FindPrimaryMaterialHnd(typeElemId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet)) { List <double> widths = new List <double>(); List <MaterialFunctionAssignment> functions = new List <MaterialFunctionAssignment>(); HostObjAttributes hostObjAttr = m_Element.Document.GetElement(typeElemId) as HostObjAttributes; if (hostObjAttr == null) { // It does not have the HostObjAttribute (where we will get the compound structure for material layer set. // We will define a single material instead and create the material layer set of this single material if there is enough information (At least Material id and thickness) FamilyInstance familyInstance = m_Element as FamilyInstance; if (familyInstance == null) { return; } FamilySymbol familySymbol = familyInstance.Symbol; ICollection <ElementId> famMatIds = familySymbol.GetMaterialIds(false); if (famMatIds.Count == 0) { // For some reason Plate type may not return any Material id ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element); Material material = m_Element.Document.GetElement(baseMatId) as Material; if (material == null) { return; } string layerName = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name); double matWidth = 0.0; Parameter thicknessPar = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS); if (thicknessPar != null) { matWidth = thicknessPar.AsDouble(); } widths.Add(matWidth); if (baseMatId != ElementId.InvalidElementId) { MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, layerName, matWidth)); } // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS functions.Add(MaterialFunctionAssignment.None); } else { foreach (ElementId matid in famMatIds) { // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS Parameter thicknessPar = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS); double matWidth = 0.0; if (thicknessPar == null) { matWidth = ParameterUtil.GetSpecialThicknessParameter(familySymbol); } else { matWidth = thicknessPar.AsDouble(); } if (MathUtil.IsAlmostZero(matWidth)) { continue; } widths.Add(matWidth); ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element); if (matid != ElementId.InvalidElementId) { Material material = m_Element.Document.GetElement(matid) as Material; if (material != null) { string layerName = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name); MaterialIds.Add(new Tuple <ElementId, string, double>(matid, layerName, matWidth)); } } else { MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, null, matWidth)); } functions.Add(MaterialFunctionAssignment.None); } } } else { ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element); CompoundStructure cs = hostObjAttr.GetCompoundStructure(); if (cs != null) { double scaledOffset = 0.0, scaledWallWidth = 0.0, wallHeight = 0.0; Wall wall = m_Element as Wall; if (wall != null) { scaledWallWidth = UnitUtil.ScaleLength(wall.Width); scaledOffset = -scaledWallWidth / 2.0; BoundingBoxXYZ boundingBox = wall.get_BoundingBox(null); if (boundingBox != null) { wallHeight = boundingBox.Max.Z - boundingBox.Min.Z; } } //TODO: Vertically compound structures are not yet supported by export. if (!cs.IsVerticallyHomogeneous() && !MathUtil.IsAlmostZero(wallHeight)) { cs = cs.GetSimpleCompoundStructure(wallHeight, wallHeight / 2.0); } for (int ii = 0; ii < cs.LayerCount; ++ii) { double matWidth = cs.GetLayerWidth(ii); //if (MathUtil.IsAlmostZero(matWidth)) // continue; ElementId matId = cs.GetMaterialId(ii); if (matId != ElementId.InvalidElementId) { Material material = m_Element.Document.GetElement(matId) as Material; if (material != null) { string layerName = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name); MaterialIds.Add(new Tuple <ElementId, string, double>(matId, layerName, matWidth)); } } else { MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, null, matWidth)); } widths.Add(matWidth); // save layer function into ProductWrapper, // it's used while exporting "Function" of Pset_CoveringCommon functions.Add(cs.GetLayerFunction(ii)); } } if (MaterialIds.Count == 0) { double matWidth = cs != null?cs.GetWidth() : 0.0; widths.Add(matWidth); if (baseMatId != ElementId.InvalidElementId) { Material material = m_Element.Document.GetElement(baseMatId) as Material; if (material != null) { string layerName = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Name", material.Name); MaterialIds.Add(new Tuple <ElementId, string, double>(baseMatId, layerName, matWidth)); } } functions.Add(MaterialFunctionAssignment.None); } } if (m_ProductWrapper != null) { m_ProductWrapper.ClearFinishMaterials(); } // We can't create IfcMaterialLayers without creating an IfcMaterialLayerSet. So we will simply collate here. IList <IFCAnyHandle> materialHnds = new List <IFCAnyHandle>(); IList <int> widthIndices = new List <int>(); double thickestLayer = 0.0; for (int ii = 0; ii < MaterialIds.Count; ++ii) { // Require positive width for IFC2x3 and before, and non-negative width for IFC4. if (widths[ii] < -MathUtil.Eps()) { continue; } bool almostZeroWidth = MathUtil.IsAlmostZero(widths[ii]); if (!ExporterCacheManager.ExportOptionsCache.ExportAs4 && almostZeroWidth) { continue; } if (almostZeroWidth) { widths[ii] = 0.0; } IFCAnyHandle materialHnd = CategoryUtil.GetOrCreateMaterialHandle(m_ExporterIFC, MaterialIds[ii].Item1); if (PrimaryMaterialHandle == null || (widths[ii] > thickestLayer)) { PrimaryMaterialHandle = materialHnd; thickestLayer = widths[ii]; } widthIndices.Add(ii); materialHnds.Add(materialHnd); if ((m_ProductWrapper != null) && (functions[ii] == MaterialFunctionAssignment.Finish1 || functions[ii] == MaterialFunctionAssignment.Finish2)) { m_ProductWrapper.AddFinishMaterial(materialHnd); } } int numLayersToCreate = widthIndices.Count; if (numLayersToCreate == 0) { MaterialLayerSetHandle = materialLayerSet; return; } // If it is a single material, check single material override (only IfcMaterial without IfcMaterialLayerSet with only 1 member) if (numLayersToCreate == 1 && ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { string paramValue; ParameterUtil.GetStringValueFromElementOrSymbol(m_Element, "IfcSingleMaterialOverride", out paramValue); if (!string.IsNullOrEmpty(paramValue)) { IFCAnyHandle singleMaterialOverrideHnd = IFCInstanceExporter.CreateMaterial(m_ExporterIFC.GetFile(), paramValue, null, null); ExporterCacheManager.MaterialHandleCache.Register(MaterialIds[0].Item1, singleMaterialOverrideHnd); MaterialLayerSetHandle = singleMaterialOverrideHnd; return; } } IFCFile file = m_ExporterIFC.GetFile(); Document document = ExporterCacheManager.Document; IList <IFCAnyHandle> layers = new List <IFCAnyHandle>(numLayersToCreate); IList <Tuple <string, IFCAnyHandle> > layerWidthQuantities = new List <Tuple <string, IFCAnyHandle> >(); HashSet <string> layerNameUsed = new HashSet <string>(); double totalWidth = 0.0; for (int ii = 0; ii < numLayersToCreate; ii++) { int widthIndex = widthIndices[ii]; double scaledWidth = UnitUtil.ScaleLength(widths[widthIndex]); string layerName = "Layer"; string description = null; string category = null; int? priority = null; IFCLogical?isVentilated = null; int isVentilatedValue; Material material = document.GetElement(MaterialIds[ii].Item1) as Material; if (material != null) { if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.IsVentilated", out isVentilatedValue) != null) { if (isVentilatedValue == 0) { isVentilated = IFCLogical.False; } else if (isVentilatedValue == 1) { isVentilated = IFCLogical.True; } } if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { layerName = MaterialIds[ii].Item2; if (string.IsNullOrEmpty(layerName)) { layerName = "Layer"; } // Ensure layer name is unique layerName = NamingUtil.GetUniqueNameWithinSet(layerName, ref layerNameUsed); description = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Description", IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Description")); category = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Category", IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Category")); int priorityValue; if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.Priority", out priorityValue) != null) { priority = priorityValue; } } } if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { // Skip component that has zero width (the will be no geometry associated to it if (MathUtil.IsAlmostZero(scaledWidth)) { continue; } IFCAnyHandle materialConstituent = IFCInstanceExporter.CreateMaterialConstituent(file, materialHnds[ii], name: layerName, description: description, category: category); layers.Add(materialConstituent); IFCAnyHandle layerQtyHnd = IFCInstanceExporter.CreateQuantityLength(file, "Width", description, null, scaledWidth); totalWidth += scaledWidth; layerWidthQuantities.Add(new Tuple <string, IFCAnyHandle>(layerName, layerQtyHnd)); } else { IFCAnyHandle materialLayer = IFCInstanceExporter.CreateMaterialLayer(file, materialHnds[ii], scaledWidth, isVentilated, name: layerName, description: description, category: category, priority: priority); layers.Add(materialLayer); } } if (layers.Count > 0) { Element type = document.GetElement(typeElemId); string layerSetName = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Name", m_ExporterIFC.GetFamilyName()); string layerSetDesc = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Description", null); if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { HashSet <IFCAnyHandle> constituents = new HashSet <IFCAnyHandle>(layers); MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialConstituentSet(file, constituents, name: layerSetName, description: layerSetDesc); foreach (Tuple <string, IFCAnyHandle> layerWidthQty in layerWidthQuantities) { LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreatePhysicalComplexQuantity(file, layerWidthQty.Item1, null, new HashSet <IFCAnyHandle>() { layerWidthQty.Item2 }, "Layer", null, null)); } // Finally create the total width as a quantity LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreateQuantityLength(file, "Width", null, null, totalWidth)); } else { MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialLayerSet(file, layers, layerSetName, layerSetDesc); } ExporterCacheManager.MaterialSetCache.RegisterLayerSet(typeElemId, MaterialLayerSetHandle, this); } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(PrimaryMaterialHandle)) { ExporterCacheManager.MaterialSetCache.RegisterPrimaryMaterialHnd(typeElemId, PrimaryMaterialHandle); } } else { MaterialLayerSetHandle = materialLayerSet; MaterialLayerSetInfo mlsInfo = ExporterCacheManager.MaterialSetCache.FindMaterialLayerSetInfo(typeElemId); if (mlsInfo != null) { MaterialIds = mlsInfo.MaterialIds; PrimaryMaterialHandle = mlsInfo.PrimaryMaterialHandle; LayerQuantityWidthHnd = mlsInfo.LayerQuantityWidthHnd; } } return; }
private void GenerateIFCObjectsIfNeeded() { if (m_needToGenerateIFCObjects) { m_needToGenerateIFCObjects = false; } else { return; } IFCAnyHandle materialLayerSet = null; if (m_ProductWrapper != null && !m_ProductWrapper.ToNative().IsValidObject) { m_ProductWrapper = null; } m_ProductWrapper?.ClearFinishMaterials(); // We can't create IfcMaterialLayers without creating an IfcMaterialLayerSet. So we will simply collate here. IList <IFCAnyHandle> materialHnds = new List <IFCAnyHandle>(); IList <int> widthIndices = new List <int>(); double thickestLayer = 0.0; for (int ii = 0; ii < MaterialIds.Count; ++ii) { // Require positive width for IFC2x3 and before, and non-negative width for IFC4. if (MaterialIds[ii].m_matWidth < -MathUtil.Eps()) { continue; } bool almostZeroWidth = MathUtil.IsAlmostZero(MaterialIds[ii].m_matWidth); if (!ExporterCacheManager.ExportOptionsCache.ExportAs4 && almostZeroWidth) { continue; } if (almostZeroWidth) { MaterialIds[ii].m_matWidth = 0.0; } IFCAnyHandle materialHnd = CategoryUtil.GetOrCreateMaterialHandle(m_ExporterIFC, MaterialIds[ii].m_baseMatId); if (m_PrimaryMaterialHandle == null || (MaterialIds[ii].m_matWidth > thickestLayer)) { m_PrimaryMaterialHandle = materialHnd; thickestLayer = MaterialIds[ii].m_matWidth; } widthIndices.Add(ii); materialHnds.Add(materialHnd); if ((m_ProductWrapper != null) && (MaterialIds[ii].m_function == MaterialFunctionAssignment.Finish1 || MaterialIds[ii].m_function == MaterialFunctionAssignment.Finish2)) { m_ProductWrapper.AddFinishMaterial(materialHnd); } } int numLayersToCreate = widthIndices.Count; if (numLayersToCreate == 0) { m_MaterialLayerSetHandle = materialLayerSet; return; } // If it is a single material, check single material override (only IfcMaterial without IfcMaterialLayerSet with only 1 member) if (numLayersToCreate == 1 && ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { m_MaterialLayerSetHandle = ExporterUtil.GetSingleMaterial(m_ExporterIFC, m_Element, MaterialIds[0].m_baseMatId) ?? materialHnds[0]; return; } IFCFile file = m_ExporterIFC.GetFile(); Document document = ExporterCacheManager.Document; IList <IFCAnyHandle> layers = new List <IFCAnyHandle>(numLayersToCreate); IList <Tuple <string, IFCAnyHandle> > layerWidthQuantities = new List <Tuple <string, IFCAnyHandle> >(); HashSet <string> layerNameUsed = new HashSet <string>(); double totalWidth = 0.0; for (int ii = 0; ii < numLayersToCreate; ii++) { int widthIndex = widthIndices[ii]; double scaledWidth = UnitUtil.ScaleLength(MaterialIds[widthIndex].m_matWidth); string layerName = "Layer"; string description = null; string category = null; int? priority = null; IFCLogical?isVentilated = null; int isVentilatedValue; Material material = document.GetElement(MaterialIds[ii].m_baseMatId) as Material; if (material != null) { if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.IsVentilated", out isVentilatedValue) != null) { if (isVentilatedValue == 0) { isVentilated = IFCLogical.False; } else if (isVentilatedValue == 1) { isVentilated = IFCLogical.True; } } if (ExporterCacheManager.ExportOptionsCache.ExportAs4) { layerName = MaterialIds[ii].m_layerName; if (string.IsNullOrEmpty(layerName)) { layerName = "Layer"; } // Ensure layer name is unique layerName = NamingUtil.GetUniqueNameWithinSet(layerName, ref layerNameUsed); description = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Description", IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Description")); category = NamingUtil.GetOverrideStringValue(material, "IfcMaterialLayer.Category", IFCAnyHandleUtil.GetStringAttribute(materialHnds[ii], "Category")); int priorityValue; if (ParameterUtil.GetIntValueFromElement(material, "IfcMaterialLayer.Priority", out priorityValue) != null) { priority = priorityValue; } } } if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { // Skip component that has zero width (the will be no geometry associated to it if (MathUtil.IsAlmostZero(scaledWidth)) { continue; } IFCAnyHandle materialConstituent = IFCInstanceExporter.CreateMaterialConstituent(file, materialHnds[ii], name: layerName, description: description, category: category); layers.Add(materialConstituent); IFCAnyHandle layerQtyHnd = IFCInstanceExporter.CreateQuantityLength(file, "Width", description, null, scaledWidth); totalWidth += scaledWidth; layerWidthQuantities.Add(new Tuple <string, IFCAnyHandle>(layerName, layerQtyHnd)); } else { IFCAnyHandle materialLayer = IFCInstanceExporter.CreateMaterialLayer(file, materialHnds[ii], scaledWidth, isVentilated, name: layerName, description: description, category: category, priority: priority); layers.Add(materialLayer); } } ElementId typeElemId = m_Element.GetTypeId(); if (layers.Count > 0) { Element type = document.GetElement(typeElemId); string layerSetName = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Name", m_ExporterIFC.GetFamilyName()); string layerSetDesc = NamingUtil.GetOverrideStringValue(type, "IfcMaterialLayerSet.Description", null); if (ExporterCacheManager.ExportOptionsCache.ExportAs4ReferenceView) { HashSet <IFCAnyHandle> constituents = new HashSet <IFCAnyHandle>(layers); m_MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialConstituentSet(file, constituents, name: layerSetName, description: layerSetDesc); foreach (Tuple <string, IFCAnyHandle> layerWidthQty in layerWidthQuantities) { m_LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreatePhysicalComplexQuantity(file, layerWidthQty.Item1, null, new HashSet <IFCAnyHandle>() { layerWidthQty.Item2 }, "Layer", null, null)); } // Finally create the total width as a quantity m_LayerQuantityWidthHnd.Add(IFCInstanceExporter.CreateQuantityLength(file, "Width", null, null, totalWidth)); } else { m_MaterialLayerSetHandle = IFCInstanceExporter.CreateMaterialLayerSet(file, layers, layerSetName, layerSetDesc); } ExporterCacheManager.MaterialSetCache.RegisterLayerSet(typeElemId, m_MaterialLayerSetHandle, this); } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(m_PrimaryMaterialHandle)) { ExporterCacheManager.MaterialSetCache.RegisterPrimaryMaterialHnd(typeElemId, m_PrimaryMaterialHandle); } }
/// <summary> /// Collect information about material layer. /// For IFC4RV Architectural exchange, it will generate IfcMatrialConstituentSet along with the relevant IfcShapeAspect and the width in the quantityset /// For IFC4RV Structural exchange, it will generate multiple components as IfcBuildingElementPart for each layer /// For others IfcMaterialLayer will be created /// </summary> private void CollectMaterialLayerSet() { ElementId typeElemId = m_Element.GetTypeId(); IFCAnyHandle materialLayerSet = ExporterCacheManager.MaterialSetCache.FindLayerSet(typeElemId); // Roofs with no components are only allowed one material. We will arbitrarily choose the thickest material. m_PrimaryMaterialHandle = ExporterCacheManager.MaterialSetCache.FindPrimaryMaterialHnd(typeElemId); bool materialHandleIsNotValid = IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet); if (IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet) || materialHandleIsNotValid) { if (materialHandleIsNotValid) { UnregisterIFCHandles(); } m_needToGenerateIFCObjects = true; List <double> widths = new List <double>(); List <MaterialFunctionAssignment> functions = new List <MaterialFunctionAssignment>(); HostObjAttributes hostObjAttr = m_Element.Document.GetElement(typeElemId) as HostObjAttributes; if (hostObjAttr == null) { // It does not have the HostObjAttribute (where we will get the compound structure for material layer set. // We will define a single material instead and create the material layer set of this single material if there is enough information (At least Material id and thickness) FamilyInstance familyInstance = m_Element as FamilyInstance; if (familyInstance == null) { return; } FamilySymbol familySymbol = familyInstance.Symbol; ICollection <ElementId> famMatIds = familySymbol.GetMaterialIds(false); if (famMatIds.Count == 0) { // For some reason Plate type may not return any Material id ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element); Material material = m_Element.Document.GetElement(baseMatId) as Material; if (material == null) { return; } string layerName = NamingUtil.GetMaterialLayerName(material); double matWidth = 0.0; Parameter thicknessPar = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS); if (thicknessPar != null) { matWidth = thicknessPar.AsDouble(); } widths.Add(matWidth); if (baseMatId != ElementId.InvalidElementId) { MaterialIds.Add(new MaterialInfo(baseMatId, layerName, matWidth, MaterialFunctionAssignment.None)); } // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS functions.Add(MaterialFunctionAssignment.None); } else { foreach (ElementId matid in famMatIds) { // How to get the thickness? For CurtainWall Panel (PanelType), there is a builtin parameter CURTAINWALL_SYSPANEL_THICKNESS double matWidth = familySymbol.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS)?.AsDouble() ?? ParameterUtil.GetSpecialThicknessParameter(familySymbol); if (MathUtil.IsAlmostZero(matWidth)) { continue; } widths.Add(matWidth); ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element); if (matid != ElementId.InvalidElementId) { Material material = m_Element.Document.GetElement(matid) as Material; if (material != null) { string layerName = NamingUtil.GetMaterialLayerName(material); MaterialIds.Add(new MaterialInfo(matid, layerName, matWidth, MaterialFunctionAssignment.None)); } } else { MaterialIds.Add(new MaterialInfo(baseMatId, null, matWidth, MaterialFunctionAssignment.None)); } functions.Add(MaterialFunctionAssignment.None); } } } else { ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(m_Element); CompoundStructure cs = hostObjAttr.GetCompoundStructure(); if (cs != null) { double scaledOffset = 0.0, scaledWallWidth = 0.0, wallHeight = 0.0; Wall wall = m_Element as Wall; if (wall != null) { scaledWallWidth = UnitUtil.ScaleLength(wall.Width); scaledOffset = -scaledWallWidth / 2.0; BoundingBoxXYZ boundingBox = wall.get_BoundingBox(null); if (boundingBox != null) { wallHeight = boundingBox.Max.Z - boundingBox.Min.Z; } } //TODO: Vertically compound structures are not yet supported by export. if (!cs.IsVerticallyHomogeneous() && !MathUtil.IsAlmostZero(wallHeight)) { cs = cs.GetSimpleCompoundStructure(wallHeight, wallHeight / 2.0); } for (int ii = 0; ii < cs.LayerCount; ++ii) { double matWidth = cs.GetLayerWidth(ii); ElementId matId = cs.GetMaterialId(ii); widths.Add(matWidth); // save layer function into ProductWrapper, // it's used while exporting "Function" of Pset_CoveringCommon functions.Add(cs.GetLayerFunction(ii)); if (matId != ElementId.InvalidElementId) { Material material = m_Element.Document.GetElement(matId) as Material; if (material != null) { string layerName = NamingUtil.GetMaterialLayerName(material); MaterialIds.Add(new MaterialInfo(matId, layerName, matWidth, functions.Last())); } } else { MaterialIds.Add(new MaterialInfo(baseMatId, null, matWidth, functions.Last())); } } } if (MaterialIds.Count == 0) { double matWidth = cs?.GetWidth() ?? 0.0; widths.Add(matWidth); if (baseMatId != ElementId.InvalidElementId) { Material material = m_Element.Document.GetElement(baseMatId) as Material; if (material != null) { string layerName = NamingUtil.GetMaterialLayerName(material); MaterialIds.Add(new MaterialInfo(baseMatId, layerName, matWidth, MaterialFunctionAssignment.None)); } } functions.Add(MaterialFunctionAssignment.None); } } } else { m_needToGenerateIFCObjects = false; m_MaterialLayerSetHandle = materialLayerSet; MaterialLayerSetInfo mlsInfo = ExporterCacheManager.MaterialSetCache.FindMaterialLayerSetInfo(typeElemId); if (mlsInfo != null) { MaterialIds = mlsInfo.MaterialIds; m_PrimaryMaterialHandle = mlsInfo.PrimaryMaterialHandle; m_LayerQuantityWidthHnd = mlsInfo.LayerQuantityWidthHnd; } } return; }
/// <summary> /// Excutes the creator. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="doc">The document.</param> public void Execute(ExporterIFC exporterIFC, Document doc) { IFCAnyHandle hostObjHnd = !IFCAnyHandleUtil.IsNullOrHasNoValue(HostHnd) ? HostHnd : DoorWindowUtil.GetHndForHostAndLevel(exporterIFC, HostId, LevelId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjHnd)) { return; } IList <DoorWindowOpeningInfo> doorWindowOpeningInfoList = new List <DoorWindowOpeningInfo>(); Element doorElem = doc.GetElement(InsertId); string openingGUID = GUIDUtil.CreateSubElementGUID(doorElem, (int)IFCDoorSubElements.DoorOpening); if (ExtrusionData != null) { foreach (IFCExtrusionData extrusionData in ExtrusionData) { if (doorWindowOpeningInfoList.Count > 0) { openingGUID = GUIDUtil.CreateGUID(); } DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd, HostId, InsertId, openingGUID, extrusionData.GetLoops()[0], extrusionData.ExtrusionDirection, UnitUtil.UnscaleLength(extrusionData.ScaledExtrusionLength), PosHingeSide, IsRecess); if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd)) { doorWindowOpeningInfoList.Add(openingInfo); } } } if (Solids != null) { foreach (Solid solid in Solids) { if (doorWindowOpeningInfoList.Count > 0) { openingGUID = GUIDUtil.CreateGUID(); } DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd, HostId, InsertId, openingGUID, solid, ScaledHostWidth, IsRecess); if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd)) { doorWindowOpeningInfoList.Add(openingInfo); } } } if (IFCAnyHandleUtil.IsNullOrHasNoValue(DoorWindowHnd)) { return; } foreach (DoorWindowOpeningInfo openingInfo in doorWindowOpeningInfoList) { IFCFile file = exporterIFC.GetFile(); IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle(); IFCAnyHandle openingHnd = openingInfo.OpeningHnd; double openingHeight = openingInfo.OpeningHeight; double openingWidth = openingInfo.OpeningWidth; // update original door. string relGUID = GUIDUtil.CreateGUID(); IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, openingHnd, DoorWindowHnd); IFCAnyHandle openingPlacement = IFCAnyHandleUtil.GetObjectPlacement(openingHnd); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(openingPlacement)) { IFCAnyHandle origObjectPlacement = IFCAnyHandleUtil.GetObjectPlacement(DoorWindowHnd); Transform relTransform = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(origObjectPlacement, openingPlacement); IFCAnyHandle newLocalPlacement = ExporterUtil.CreateLocalPlacement(file, openingPlacement, relTransform.Origin, relTransform.BasisZ, relTransform.BasisX); IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "ObjectPlacement", newLocalPlacement); origObjectPlacement.Delete(); } if (IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcDoor) || IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcWindow)) { if (openingHeight > MathUtil.Eps()) { IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallHeight", UnitUtil.ScaleLength(openingHeight)); } if (openingWidth > MathUtil.Eps()) { IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallWidth", UnitUtil.ScaleLength(openingWidth)); } } } }