/// <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.IsValidHandle(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 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.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); //if (MathUtil.IsAlmostZero(matWidth)) // continue; 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 != 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.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; }
private void Stream(ArrayList data, HostObjAttributes hostAtt) { data.Add(new Snoop.Data.ClassSeparator(typeof(HostObjAttributes))); data.Add(new Snoop.Data.Object("Compound Structure", hostAtt.GetCompoundStructure())); ContFootingType contFootingType = hostAtt as ContFootingType; if (contFootingType != null) { Stream(data, contFootingType); return; } CurtainSystemType curSysType = hostAtt as CurtainSystemType; if (curSysType != null) { Stream(data, curSysType); return; } FloorType floorType = hostAtt as FloorType; if (floorType != null) { Stream(data, floorType); return; } HostedSweepType hostSweepType = hostAtt as HostedSweepType; if (hostSweepType != null) { Stream(data, hostSweepType); return; } RoofType roofType = hostAtt as RoofType; if (roofType != null) { Stream(data, roofType); return; } WallType wallType = hostAtt as WallType; if (wallType != null) { Stream(data, wallType); return; } }
/// <summary> /// Exports materials for host object. /// </summary> /// <param name="exporterIFC">The ExporterIFC object.</param> /// <param name="hostObject">The host object.</param> /// <param name="elemHnds">The host IFC handles.</param> /// <param name="geometryElement">The geometry element.</param> /// <param name="productWrapper">The ProductWrapper.</param> /// <param name="levelId">The level id.</param> /// <param name="direction">The IFCLayerSetDirection.</param> /// <param name="containsBRepGeometry">True if the geometry contains BRep geoemtry. If so, we will export an IfcMaterialList</param> /// <returns>True if exported successfully, false otherwise.</returns> public static bool ExportHostObjectMaterials(ExporterIFC exporterIFC, HostObject hostObject, IList <IFCAnyHandle> elemHnds, GeometryElement geometryElement, ProductWrapper productWrapper, ElementId levelId, Toolkit.IFCLayerSetDirection direction, bool containsBRepGeometry) { if (hostObject == null) { return(true); //nothing to do } if (elemHnds == null || (elemHnds.Count == 0)) { return(true); //nothing to do } IFCFile file = exporterIFC.GetFile(); using (IFCTransaction tr = new IFCTransaction(file)) { if (productWrapper != null) { productWrapper.ClearFinishMaterials(); } double scaledOffset = 0.0, scaledWallWidth = 0.0, wallHeight = 0.0; Wall wall = hostObject 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; } } ElementId typeElemId = hostObject.GetTypeId(); IFCAnyHandle materialLayerSet = ExporterCacheManager.MaterialLayerSetCache.Find(typeElemId); // Roofs with no components are only allowed one material. We will arbitrarily choose the thickest material. IFCAnyHandle primaryMaterialHnd = ExporterCacheManager.MaterialLayerSetCache.FindPrimaryMaterialHnd(typeElemId); if (IFCAnyHandleUtil.IsNullOrHasNoValue(materialLayerSet)) { HostObjAttributes hostObjAttr = hostObject.Document.GetElement(typeElemId) as HostObjAttributes; if (hostObjAttr == null) { return(true); //nothing to do } List <ElementId> matIds = new List <ElementId>(); List <double> widths = new List <double>(); List <MaterialFunctionAssignment> functions = new List <MaterialFunctionAssignment>(); ElementId baseMatId = CategoryUtil.GetBaseMaterialIdForElement(hostObject); CompoundStructure cs = hostObjAttr.GetCompoundStructure(); if (cs != null) { //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 i = 0; i < cs.LayerCount; ++i) { ElementId matId = cs.GetMaterialId(i); if (matId != ElementId.InvalidElementId) { matIds.Add(matId); } else { matIds.Add(baseMatId); } widths.Add(cs.GetLayerWidth(i)); // save layer function into ProductWrapper, // it's used while exporting "Function" of Pset_CoveringCommon functions.Add(cs.GetLayerFunction(i)); } } if (matIds.Count == 0) { matIds.Add(baseMatId); widths.Add(cs != null ? cs.GetWidth() : 0); functions.Add(MaterialFunctionAssignment.None); } // 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 < matIds.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.FileVersion != IFCVersion.IFC4 && almostZeroWidth) { continue; } if (almostZeroWidth) { widths[ii] = 0.0; } IFCAnyHandle materialHnd = CategoryUtil.GetOrCreateMaterialHandle(exporterIFC, matIds[ii]); if (primaryMaterialHnd == null || (widths[ii] > thickestLayer)) { primaryMaterialHnd = materialHnd; thickestLayer = widths[ii]; } widthIndices.Add(ii); materialHnds.Add(materialHnd); if ((productWrapper != null) && (functions[ii] == MaterialFunctionAssignment.Finish1 || functions[ii] == MaterialFunctionAssignment.Finish2)) { productWrapper.AddFinishMaterial(materialHnd); } } int numLayersToCreate = widthIndices.Count; if (numLayersToCreate == 0) { return(false); } if (!containsBRepGeometry) { IList <IFCAnyHandle> layers = new List <IFCAnyHandle>(numLayersToCreate); for (int ii = 0; ii < numLayersToCreate; ii++) { int widthIndex = widthIndices[ii]; double scaledWidth = UnitUtil.ScaleLength(widths[widthIndex]); IFCAnyHandle materialLayer = IFCInstanceExporter.CreateMaterialLayer(file, materialHnds[ii], scaledWidth, null); layers.Add(materialLayer); } string layerSetName = exporterIFC.GetFamilyName(); materialLayerSet = IFCInstanceExporter.CreateMaterialLayerSet(file, layers, layerSetName); ExporterCacheManager.MaterialLayerSetCache.Register(typeElemId, materialLayerSet); ExporterCacheManager.MaterialLayerSetCache.RegisterPrimaryMaterialHnd(typeElemId, primaryMaterialHnd); } else { foreach (IFCAnyHandle elemHnd in elemHnds) { CategoryUtil.CreateMaterialAssociations(exporterIFC, elemHnd, matIds); } } } // IfcMaterialLayerSetUsage is not supported for IfcWall, only IfcWallStandardCase. IFCAnyHandle layerSetUsage = null; for (int ii = 0; ii < elemHnds.Count; ii++) { IFCAnyHandle elemHnd = elemHnds[ii]; if (IFCAnyHandleUtil.IsNullOrHasNoValue(elemHnd)) { continue; } SpaceBoundingElementUtil.RegisterSpaceBoundingElementHandle(exporterIFC, elemHnd, hostObject.Id, levelId); if (containsBRepGeometry) { continue; } HashSet <IFCAnyHandle> relDecomposesSet = IFCAnyHandleUtil.GetRelDecomposes(elemHnd); IList <IFCAnyHandle> subElemHnds = null; if (relDecomposesSet != null && relDecomposesSet.Count == 1) { IFCAnyHandle relAggregates = relDecomposesSet.First(); if (IFCAnyHandleUtil.IsTypeOf(relAggregates, IFCEntityType.IfcRelAggregates)) { subElemHnds = IFCAnyHandleUtil.GetAggregateInstanceAttribute <List <IFCAnyHandle> >(relAggregates, "RelatedObjects"); } } bool hasSubElems = (subElemHnds != null && subElemHnds.Count != 0); bool isRoof = IFCAnyHandleUtil.IsTypeOf(elemHnd, IFCEntityType.IfcRoof); if (!hasSubElems && !isRoof && !IFCAnyHandleUtil.IsTypeOf(elemHnd, IFCEntityType.IfcWall)) { if (layerSetUsage == null) { bool flipDirSense = true; if (wall != null) { // if we have flipped the center curve on export, we need to take that into account here. // We flip the center curve on export if it is an arc and it has a negative Z direction. LocationCurve locCurve = wall.Location as LocationCurve; if (locCurve != null) { Curve curve = locCurve.Curve; Plane defPlane = new Plane(XYZ.BasisX, XYZ.BasisY, XYZ.Zero); bool curveFlipped = GeometryUtil.MustFlipCurve(defPlane, curve); flipDirSense = !(wall.Flipped ^ curveFlipped); } } else if (hostObject is Floor) { flipDirSense = false; } double offsetFromReferenceLine = flipDirSense ? -scaledOffset : scaledOffset; IFCDirectionSense sense = flipDirSense ? IFCDirectionSense.Negative : IFCDirectionSense.Positive; layerSetUsage = IFCInstanceExporter.CreateMaterialLayerSetUsage(file, materialLayerSet, direction, sense, offsetFromReferenceLine); } ExporterCacheManager.MaterialLayerRelationsCache.Add(layerSetUsage, elemHnd); } else { if (hasSubElems) { foreach (IFCAnyHandle subElemHnd in subElemHnds) { if (!IFCAnyHandleUtil.IsNullOrHasNoValue(subElemHnd)) { ExporterCacheManager.MaterialLayerRelationsCache.Add(materialLayerSet, subElemHnd); } } } else if (!isRoof) { ExporterCacheManager.MaterialLayerRelationsCache.Add(materialLayerSet, elemHnd); } else if (primaryMaterialHnd != null) { ExporterCacheManager.MaterialLayerRelationsCache.Add(primaryMaterialHnd, elemHnd); } } } tr.Commit(); return(true); } }