/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { // If we created an element above, then we will set the shape of it to be the same of the shapes of the contained spaces. IList <GeometryObject> geomObjs = new List <GeometryObject>(); foreach (IFCObjectDefinition objDef in RelatedObjects) { if (!(objDef is IFCSpace)) { continue; } // This lets us create a copy of the space geometry with the Zone graphics style. IList <IFCSolidInfo> solids = IFCElement.CloneElementGeometry(doc, objDef as IFCProduct, this, false); if (solids != null) { foreach (IFCSolidInfo solidGeom in solids) { geomObjs.Add(solidGeom.GeometryObject); } } } DirectShape zoneElement = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs); if (zoneElement != null) { CreatedElementId = zoneElement.Id; CreatedGeometry = geomObjs; } base.Create(doc); }
/// <summary> /// Gets the elements hosted by this host element, if any. /// </summary> /// <param name="hostElement">The host element.</param> /// <returns>The hosted elements, or null. An unfilled opening counts as a hosted element.</returns> static public IList<IFCElement> GetHostedElements(IFCElement hostElement) { if (hostElement == null) return null; ICollection<IFCFeatureElementSubtraction> openings = hostElement.Openings; if (openings == null || (openings.Count == 0)) return null; IList<IFCElement> hostedElements = new List<IFCElement>(); foreach (IFCFeatureElementSubtraction opening in openings) { if (!(opening is IFCOpeningElement)) hostedElements.Add(opening); else { IFCOpeningElement openingElement = opening as IFCOpeningElement; if (openingElement.FilledByElement != null) hostedElements.Add(openingElement.FilledByElement); else hostedElements.Add(openingElement); } } return hostedElements; }
/// <summary> /// Processes IfcOpeningElement attributes. /// </summary> /// <param name="ifcOpeningElement">The IfcOpeningElement handle.</param> protected override void Process(IFCAnyHandle ifcOpeningElement) { base.Process(ifcOpeningElement); ICollection <IFCAnyHandle> hasFillings = IFCAnyHandleUtil.GetAggregateInstanceAttribute <List <IFCAnyHandle> >(ifcOpeningElement, "HasFillings"); if (hasFillings != null) { // Assume that there is only one filling for the opening, and take first found. foreach (IFCAnyHandle hasFilling in hasFillings) { IFCAnyHandle relatedFillingElement = IFCAnyHandleUtil.GetInstanceAttribute(hasFilling, "RelatedBuildingElement"); if (IFCAnyHandleUtil.IsNullOrHasNoValue(relatedFillingElement)) { continue; } IFCEntity filledByElement; IFCImportFile.TheFile.EntityMap.TryGetValue(relatedFillingElement.StepId, out filledByElement); if (filledByElement == null) { FilledByElement = IFCElement.ProcessIFCElement(relatedFillingElement); } else { FilledByElement = filledByElement as IFCElement; } FilledByElement.FillsOpening = this; break; } } }
/// <summary> /// Processes an IFCElementComponent object. /// </summary> /// <param name="ifcElementComponent">The IfcElementComponent handle.</param> /// <returns>The IFCElementComponent object.</returns> /// <remarks>IFCBuildingElementPart has changed from a subtype of the abstract IFCBuildingElement to IFCElementComponent from IFC2x3 to IFC4. /// Instead of having different parents, we will keep IFCBuildingElementPart as a child of IFCBuildingElement. This means, though, that /// this function can only return an IFCElement, the (normally) abstract parent of each.</remarks> public static IFCElement ProcessIFCElementComponent(IFCAnyHandle ifcElementComponent) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcElementComponent)) { Importer.TheLog.LogNullError(IFCEntityType.IfcElementComponent); return(null); } IFCEntity elementComponent; IFCImportFile.TheFile.EntityMap.TryGetValue(ifcElementComponent.StepId, out elementComponent); if (elementComponent != null) { return(elementComponent as IFCElement); } IFCElement newIFCElementComponent = null; // other subclasses not handled yet. if (IFCImportFile.TheFile.SchemaVersionAtLeast(IFCSchemaVersion.IFC4Obsolete) && IFCAnyHandleUtil.IsValidSubTypeOf(ifcElementComponent, IFCEntityType.IfcBuildingElementPart)) { newIFCElementComponent = IFCBuildingElementPart.ProcessIFCBuildingElementPart(ifcElementComponent); } else { newIFCElementComponent = new IFCElementComponent(ifcElementComponent); } return(newIFCElementComponent); }
private IList <GeometryObject> GetOrCloneGeometry(Document doc, IFCObjectDefinition objectDefinition) { if (!(objectDefinition is IFCBuildingElementPart)) { return(objectDefinition.CreatedGeometry); } // In the case of IFCBuildingElementPart, we want the container to have a copy of the geometry in the category of the parent, // as otherwise the geometry will be controlled by default by the Parts category instead of the parent category. IList <IFCSolidInfo> clonedGeometry = IFCElement.CloneElementGeometry(doc, objectDefinition as IFCProduct, this, false); if (clonedGeometry == null) { return(null); } IList <GeometryObject> geomObjs = new List <GeometryObject>(); foreach (IFCSolidInfo solid in clonedGeometry) { geomObjs.Add(solid.GeometryObject); } return(geomObjs); }
/// <summary> /// Processes IfcOpeningElement attributes. /// </summary> /// <param name="ifcOpeningElement">The IfcOpeningElement handle.</param> protected override void Process(IFCAnyHandle ifcOpeningElement) { base.Process(ifcOpeningElement); ICollection<IFCAnyHandle> hasFillings = IFCAnyHandleUtil.GetAggregateInstanceAttribute<List<IFCAnyHandle>>(ifcOpeningElement, "HasFillings"); if (hasFillings != null) { // Assume that there is only one filling for the opening, and take first found. foreach (IFCAnyHandle hasFilling in hasFillings) { IFCAnyHandle relatedFillingElement = IFCAnyHandleUtil.GetInstanceAttribute(hasFilling, "RelatedBuildingElement"); if (IFCAnyHandleUtil.IsNullOrHasNoValue(relatedFillingElement)) continue; IFCEntity filledByElement; IFCImportFile.TheFile.EntityMap.TryGetValue(relatedFillingElement.StepId, out filledByElement); if (filledByElement == null) FilledByElement = IFCElement.ProcessIFCElement(relatedFillingElement); else FilledByElement = filledByElement as IFCElement; FilledByElement.FillsOpening = this; break; } } }
/// <summary> /// Processes an IfcElement object. /// </summary> /// <param name="ifcElement">The IfcElement handle.</param> /// <returns>The IFCElement object.</returns> public static IFCElement ProcessIFCElement(IFCAnyHandle ifcElement) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcElement)) { IFCImportFile.TheLog.LogNullError(IFCEntityType.IfcElement); return(null); } IFCEntity cachedIFCElement; IFCImportFile.TheFile.EntityMap.TryGetValue(ifcElement.StepId, out cachedIFCElement); if (cachedIFCElement != null) { return(cachedIFCElement as IFCElement); } IFCElement newIFCElement = null; // other subclasses not handled yet! if (IFCAnyHandleUtil.IsSubTypeOf(ifcElement, IFCEntityType.IfcFeatureElement)) { newIFCElement = IFCFeatureElement.ProcessIFCFeatureElement(ifcElement); } else { newIFCElement = new IFCElement(ifcElement); } return(newIFCElement); }
/// <summary> /// Create a copying of the geometry of an entity with a different graphics style. /// </summary> /// <param name="doc">The document.</param> /// <param name="original">The IFCProduct we are partially copying.</param> /// <param name="parentEntity">The IFCObjectDefinition we are going to add the geometry to.</param> /// <param name="cloneParentMaterial">Determine whether to use the one material of the parent entity, if it exists and is unique.</param> /// <returns>The list of geometries created with a new category and possibly material.</returns> public static IList <IFCSolidInfo> CloneElementGeometry(Document doc, IFCProduct original, IFCObjectDefinition parentEntity, bool cloneParentMaterial) { using (TemporaryDisableLogging disableLogging = new TemporaryDisableLogging()) { IFCElement clone = new IFCElement(); // Note that the GlobalId is left to null here; this allows us to later decide not to create a DirectShape for the result. // Get the ObjectLocation and ProductRepresentation from the original entity, which is all we need to create geometry. clone.ObjectLocation = original.ObjectLocation; clone.ProductRepresentation = original.ProductRepresentation; clone.MaterialSelect = original.MaterialSelect; // Get the EntityType and PredefinedType from the parent to ensure that it "matches" the category and graphics style of the parent. clone.EntityType = parentEntity.EntityType; clone.PredefinedType = parentEntity.PredefinedType; if (cloneParentMaterial) { // This will only work if the parent entity has one material. IFCMaterial parentMaterial = parentEntity.GetTheMaterial(); if (parentMaterial != null) { clone.MaterialSelect = parentMaterial; } } IList <GeometryObject> geomObjs = new List <GeometryObject>(); CreateElement(doc, clone); return(clone.Solids); } }
/// <summary> /// Gets the host of a hosted element, if any. /// </summary> /// <param name="hostedElement">The hosted element.</param> /// <returns>The host, or null.</returns> static public IFCElement GetHost(IFCElement hostedElement) { if (hostedElement == null) return null; IFCFeatureElementSubtraction fillsOpening = hostedElement.FillsOpening; if (fillsOpening == null) return null; return fillsOpening.VoidsElement; }
/// <summary> /// Post-process IfcPort attributes. /// </summary> public override void PostProcess() { base.PostProcess(); // Force ContainedIn, ConnectedFrom and ConnectedTo to be created in the respective getters. IFCElement containedIn = ContainedIn; IFCPort connectedFrom = ConnectedFrom; IFCPort connectedTo = ConnectedTo; }
/// <summary> /// Processes an IfcProduct object. /// </summary> /// <param name="ifcProduct">The IfcProduct handle.</param> /// <returns>The IFCProduct object.</returns> public static IFCProduct ProcessIFCProduct(IFCAnyHandle ifcProduct) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcProduct)) { Importer.TheLog.LogNullError(IFCEntityType.IfcProduct); return(null); } try { IFCEntity cachedProduct; if (IFCImportFile.TheFile.EntityMap.TryGetValue(ifcProduct.StepId, out cachedProduct)) { return(cachedProduct as IFCProduct); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcProduct, IFCEntityType.IfcSpatialStructureElement)) { return(IFCSpatialStructureElement.ProcessIFCSpatialStructureElement(ifcProduct)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcProduct, IFCEntityType.IfcElement)) { return(IFCElement.ProcessIFCElement(ifcProduct)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcProduct, IFCEntityType.IfcGrid)) { return(IFCGrid.ProcessIFCGrid(ifcProduct)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcProduct, IFCEntityType.IfcProxy)) { return(IFCProxy.ProcessIFCProxy(ifcProduct)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcProduct, IFCEntityType.IfcDistributionPort)) { return(IFCDistributionPort.ProcessIFCDistributionPort(ifcProduct)); } } catch (Exception ex) { HandleError(ex.Message, ifcProduct, true); return(null); } Importer.TheLog.LogUnhandledSubTypeError(ifcProduct, IFCEntityType.IfcProduct, false); return(null); }
/// <summary> /// Creates or populates Revit element params based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> /// <param name="element">The element.</param> protected override void CreateParametersInternal(Document doc, Element element) { base.CreateParametersInternal(doc, element); if (element != null) { Category category = IFCPropertySet.GetCategoryForParameterIfValid(element, Id); // Set "Tag" parameter. string ifcTag = Tag; if (!string.IsNullOrWhiteSpace(ifcTag)) { IFCPropertySet.AddParameterString(doc, element, category, "IfcTag", ifcTag, Id); } IFCFeatureElementSubtraction ifcFeatureElementSubtraction = FillsOpening; if (ifcFeatureElementSubtraction != null) { IFCElement ifcElement = ifcFeatureElementSubtraction.VoidsElement; if (ifcElement != null) { string ifcContainerName = ifcElement.Name; IFCPropertySet.AddParameterString(doc, element, category, "IfcContainedInHost", ifcContainerName, Id); } } // Create two parameters for each port: one for name, and one for GUID. // Note that Ports will never be null, as it is initialized the first time it is accessed. int numPorts = 0; foreach (IFCPort port in Ports) { string name = port.Name; string guid = port.GlobalId; if (!string.IsNullOrWhiteSpace(name)) { string parameterName = "IfcElement HasPorts Name " + ((numPorts == 0) ? "" : (numPorts + 1).ToString()); IFCPropertySet.AddParameterString(doc, element, category, parameterName, name, Id); } if (!string.IsNullOrWhiteSpace(guid)) { string parameterName = "IfcElement HasPorts IfcGUID " + ((numPorts == 0) ? "" : (numPorts + 1).ToString()); IFCPropertySet.AddParameterString(doc, element, category, parameterName, guid, Id); } numPorts++; } } }
/// <summary> /// Create a simplified copy of a IFCFeatureElement, intended explicitly for the purpose of voiding a particular IFCElement. /// </summary> /// <param name="original">The IFCFeatureElement we are partially copying.</param> /// <param name="parentEntity">The IFCElement we are voiding.</param> /// <returns>A new IFCFeatureElement that is a minimal copy of original with influence by parentEntity.</returns> public static IFCFeatureElement CreateOpeningClone(IFCFeatureElement original, IFCElement parentEntity) { IFCFeatureElement clone = new IFCFeatureElement(); // Note that the GlobalId is left to null here; this allows us to later decide not to create a DirectShape for the result. // Get the ObjectLocation and ProductRepresentation from the original entity, which is all we need to create geometry. clone.ObjectLocation = original.ObjectLocation; clone.ProductRepresentation = original.ProductRepresentation; // Get the EntityType and ShapeType from the parent to ensure that it "matches" the category and graphics style of the parent. clone.EntityType = parentEntity.EntityType; clone.ShapeType = parentEntity.ShapeType; // Copy the material of the parent entity to try to match the color of the opening faces. // This will work nicely if the parent entity is one material. IFCMaterial parentMaterial = parentEntity.GetTheMaterial(); if (parentMaterial != null) clone.MaterialSelect = parentMaterial; return clone; }
/// <summary> /// Create a simplified copy of a IFCFeatureElement, intended explicitly for the purpose of voiding a particular IFCElement. /// </summary> /// <param name="original">The IFCFeatureElement we are partially copying.</param> /// <param name="parentEntity">The IFCElement we are voiding.</param> /// <returns>A new IFCFeatureElement that is a minimal copy of original with influence by parentEntity.</returns> public static IFCFeatureElement CreateOpeningClone(IFCFeatureElement original, IFCElement parentEntity) { IFCFeatureElement clone = new IFCFeatureElement(); // Note that the GlobalId is left to null here; this allows us to later decide not to create a DirectShape for the result. // Get the ObjectLocation and ProductRepresentation from the original entity, which is all we need to create geometry. clone.ObjectLocation = original.ObjectLocation; clone.ProductRepresentation = original.ProductRepresentation; // Get the EntityType and ShapeType from the parent to ensure that it "matches" the category and graphics style of the parent. clone.EntityType = parentEntity.EntityType; clone.ShapeType = parentEntity.ShapeType; // Copy the material of the parent entity to try to match the color of the opening faces. // This will work nicely if the parent entity is one material. IFCMaterial parentMaterial = parentEntity.GetTheMaterial(); if (parentMaterial != null) { clone.MaterialSelect = parentMaterial; } return(clone); }
/// <summary> /// Create a copying of the geometry of an entity with a different graphics style. /// </summary> /// <param name="doc">The document.</param> /// <param name="original">The IFCProduct we are partially copying.</param> /// <param name="parentEntity">The IFCObjectDefinition we are going to add the geometry to.</param> /// <param name="cloneParentMaterial">Determine whether to use the one material of the parent entity, if it exists and is unique.</param> /// <returns>The list of geometries created with a new category and possibly material.</returns> public static IList<IFCSolidInfo> CloneElementGeometry(Document doc, IFCProduct original, IFCObjectDefinition parentEntity, bool cloneParentMaterial) { using (TemporaryDisableLogging disableLogging = new TemporaryDisableLogging()) { IFCElement clone = new IFCElement(); // Note that the GlobalId is left to null here; this allows us to later decide not to create a DirectShape for the result. // Get the ObjectLocation and ProductRepresentation from the original entity, which is all we need to create geometry. clone.ObjectLocation = original.ObjectLocation; clone.ProductRepresentation = original.ProductRepresentation; clone.MaterialSelect = original.MaterialSelect; // Get the EntityType and PredefinedType from the parent to ensure that it "matches" the category and graphics style of the parent. clone.EntityType = parentEntity.EntityType; clone.PredefinedType = parentEntity.PredefinedType; if (cloneParentMaterial) { // This will only work if the parent entity has one material. IFCMaterial parentMaterial = parentEntity.GetTheMaterial(); if (parentMaterial != null) clone.MaterialSelect = parentMaterial; } IList<GeometryObject> geomObjs = new List<GeometryObject>(); CreateElement(doc, clone); return clone.Solids; } }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { bool preventInstances = false; IFCElement element = this as IFCElement; if (element != null) { preventInstances = this is IFCOpeningElement; foreach (IFCFeatureElement opening in element.Openings) { try { preventInstances = true; // Create the actual Revit element based on the IFCFeatureElement here. ElementId openingId = CreateElement(doc, opening); // This gets around the issue that the Boolean operation between the void(s) in the IFCFeatureElement and // the solid(s) in the IFCElement may use the Graphics Style of the voids in the resulting Solid(s), meaning // that some faces may disappear when we turn off the visibility of IfcOpeningElements. IList <IFCSolidInfo> voids = IFCElement.CloneElementGeometry(doc, opening, this, true); if (voids != null) { foreach (IFCSolidInfo voidGeom in voids) { IFCVoidInfo voidInfo = new IFCVoidInfo(voidGeom); if (!Importer.TheProcessor.ApplyTransforms) { // If we aren't applying transforms, then the Voids and Solids will be // in different coordinate spaces, so we need the transform of the // void, so we can transform it into the Solid coordinate space voidInfo.TotalTransform = opening?.ObjectLocation?.TotalTransform; } Voids.Add(voidInfo); } } } catch (Exception ex) { Importer.TheLog.LogError(opening.Id, ex.Message, false); } } } if (HasValidTopLevelGeometry()) { using (IFCImportShapeEditScope shapeEditScope = IFCImportShapeEditScope.Create(doc, this)) { shapeEditScope.GraphicsStyleId = GraphicsStyleId; shapeEditScope.CategoryId = CategoryId; 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; ProductRepresentation.CreateProductRepresentation(shapeEditScope, transformToUse, transformToUse, myId); int numSolids = Solids.Count; // Attempt to cut each solid with each void. for (int solidIdx = 0; solidIdx < numSolids; solidIdx++) { if (!CutSolidByVoids(Solids[solidIdx])) { Solids.RemoveAt(solidIdx); solidIdx--; numSolids--; } } bool addedCurves = shapeEditScope.AddPlanViewCurves(FootprintCurves, Id); if ((numSolids > 0 || addedCurves)) { if (GlobalId != null) { // If the GlobalId is null, this is a fake IfcProduct that we don't want to create into a DirectShape, or // add to the caches in any way. We only wanted to gather its geometry. DirectShape shape = Importer.TheCache.UseElementByGUID <DirectShape>(doc, GlobalId); if (shape == null) { shape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, null, Id, EntityType); } List <GeometryObject> directShapeGeometries = new List <GeometryObject>(); foreach (IFCSolidInfo geometryObject in Solids) { // We need to check if the solid created is good enough for DirectShape. If not, warn and use a fallback Mesh. GeometryObject currObject = geometryObject.GeometryObject; if (currObject is Solid) { Solid solid = currObject as Solid; if (!shape.IsValidGeometry(solid)) { Importer.TheLog.LogWarning(Id, "Couldn't create valid solid, reverting to mesh.", false); directShapeGeometries.AddRange(IFCGeometryUtil.CreateMeshesFromSolid(solid)); currObject = null; } } if (currObject != null) { directShapeGeometries.Add(currObject); } } // We will use the first IfcTypeObject id, if it exists. In general, there should be 0 or 1. IFCTypeObject typeObjectToUse = null; foreach (IFCTypeObject typeObject in TypeObjects) { if (typeObject.IsValidForCreation && typeObject.CreatedElementId != ElementId.InvalidElementId) { typeObjectToUse = typeObject; break; } } if (!Importer.TheProcessor.PostProcessProduct(Id, typeObjectToUse?.Id, lcs, directShapeGeometries)) { if (shape != null) { shape.SetShape(directShapeGeometries); shapeEditScope.SetPlanViewRep(shape); if (typeObjectToUse != null && typeObjectToUse.CreatedElementId != ElementId.InvalidElementId) { shape.SetTypeId(typeObjectToUse.CreatedElementId); } } } PresentationLayerNames.UnionWith(shapeEditScope.PresentationLayerNames); CreatedElementId = shape.Id; CreatedGeometry = directShapeGeometries; } } } } else { if (this is IFCElement || this is IFCGrid) { IList <IFCEntity> visitedEntities = new List <IFCEntity>(); visitedEntities.Add(this); if (!HasValidSubElementGeometry(visitedEntities)) { // We will not warn if this is an IfcSpatialStructureElement; those aren't expected to have their own geometry. Importer.TheLog.LogWarning(Id, "There is no valid geometry for this " + EntityType.ToString() + "; entity will not be built.", false); } } } base.Create(doc); }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { bool preventInstances = false; IFCElement element = this as IFCElement; if (element != null) { IFCOpeningElement openingElement = element as IFCOpeningElement; if (openingElement != null) { preventInstances = true; } foreach (IFCFeatureElement opening in element.Openings) { try { preventInstances = true; // Create the actual Revit element based on the IFCFeatureElement here. ElementId openingId = CreateElement(doc, opening); // This gets around the issue that the Boolean operation between the void(s) in the IFCFeatureElement and // the solid(s) in the IFCElement may use the Graphics Style of the voids in the resulting Solid(s), meaning // that some faces may disappear when we turn off the visibility of IfcOpeningElements. IList <IFCSolidInfo> voids = IFCElement.CloneElementGeometry(doc, opening, this, true); if (voids != null) { foreach (IFCSolidInfo voidGeom in voids) { Voids.Add(voidGeom); } } } catch (Exception ex) { Importer.TheLog.LogError(opening.Id, ex.Message, false); } } } if (HasValidTopLevelGeometry()) { using (IFCImportShapeEditScope shapeEditScope = IFCImportShapeEditScope.Create(doc, this)) { shapeEditScope.GraphicsStyleId = GraphicsStyleId; shapeEditScope.CategoryId = CategoryId; 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); } ProductRepresentation.CreateProductRepresentation(shapeEditScope, lcs, lcs, myId); int numSolids = Solids.Count; int numVoids = Voids.Count; if ((numSolids > 0) && (numVoids > 0)) { // This may be different than before, with the addition of solids from FamilyInstances. numSolids = Solids.Count; // Attempt to cut each solid with each void. for (int solidIdx = 0; solidIdx < numSolids; solidIdx++) { // We only cut body representation items. if (Solids[solidIdx].RepresentationType != IFCRepresentationIdentifier.Body) { continue; } if (!(Solids[solidIdx].GeometryObject is Solid)) { string typeName = (Solids[solidIdx].GeometryObject is Mesh) ? "mesh" : "instance"; Importer.TheLog.LogError(Id, "Can't cut " + typeName + " geometry, ignoring " + numVoids + " void(s).", false); continue; } for (int voidIdx = 0; voidIdx < numVoids; voidIdx++) { if (!(Voids[voidIdx].GeometryObject is Solid)) { Importer.TheLog.LogError(Id, "Can't cut Solid geometry with a Mesh (# " + Voids[voidIdx].Id + "), ignoring.", false); continue; } Solids[solidIdx].GeometryObject = IFCGeometryUtil.ExecuteSafeBooleanOperation(Solids[solidIdx].Id, Voids[voidIdx].Id, Solids[solidIdx].GeometryObject as Solid, Voids[voidIdx].GeometryObject as Solid, BooleanOperationsType.Difference, null); if ((Solids[solidIdx].GeometryObject as Solid).Faces.IsEmpty) { Solids.RemoveAt(solidIdx); solidIdx--; numSolids--; break; } } } } bool addedCurves = shapeEditScope.AddPlanViewCurves(FootprintCurves, Id); if ((numSolids > 0 || addedCurves)) { if (GlobalId != null) { // If the GlobalId is null, this is a fake IfcProduct that we don't want to create into a DirectShape, or // add to the caches in any way. We only wanted to gather its geometry. DirectShape shape = Importer.TheCache.UseElementByGUID <DirectShape>(doc, GlobalId); if (shape == null) { shape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, null, Id); } List <GeometryObject> directShapeGeometries = new List <GeometryObject>(); foreach (IFCSolidInfo geometryObject in Solids) { // We need to check if the solid created is good enough for DirectShape. If not, warn and use a fallback Mesh. GeometryObject currObject = geometryObject.GeometryObject; if (currObject is Solid) { Solid solid = currObject as Solid; if (!shape.IsValidGeometry(solid)) { Importer.TheLog.LogWarning(Id, "Couldn't create valid solid, reverting to mesh.", false); directShapeGeometries.AddRange(IFCGeometryUtil.CreateMeshesFromSolid(solid)); currObject = null; } } if (currObject != null) { directShapeGeometries.Add(currObject); } } // We will use the first IfcTypeObject id, if it exists. In general, there should be 0 or 1. ElementId typeId = ElementId.InvalidElementId; foreach (IFCTypeObject typeObject in TypeObjects) { if (typeObject.IsValidForCreation && typeObject.CreatedElementId != ElementId.InvalidElementId) { typeId = typeObject.CreatedElementId; break; } } shape.SetShape(directShapeGeometries); shapeEditScope.SetPlanViewRep(shape); if (typeId != ElementId.InvalidElementId) { shape.SetTypeId(typeId); } PresentationLayerNames.UnionWith(shapeEditScope.PresentationLayerNames); CreatedElementId = shape.Id; CreatedGeometry = directShapeGeometries; } } } } else { if (this is IFCElement || this is IFCGrid) { IList <IFCEntity> visitedEntities = new List <IFCEntity>(); visitedEntities.Add(this); if (!HasValidSubElementGeometry(visitedEntities)) { // We will not warn if this is an IfcSpatialStructureElement; those aren't expected to have their own geometry. Importer.TheLog.LogWarning(Id, "There is no valid geometry for this " + EntityType.ToString() + "; entity will not be built.", false); } } } base.Create(doc); }
/// <summary> /// Processes an IfcElement object. /// </summary> /// <param name="ifcElement">The IfcElement handle.</param> /// <returns>The IFCElement object.</returns> public static IFCElement ProcessIFCElement(IFCAnyHandle ifcElement) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcElement)) { Importer.TheLog.LogNullError(IFCEntityType.IfcElement); return null; } IFCEntity cachedIFCElement; IFCImportFile.TheFile.EntityMap.TryGetValue(ifcElement.StepId, out cachedIFCElement); if (cachedIFCElement != null) return (cachedIFCElement as IFCElement); IFCElement newIFCElement = null; // other subclasses not handled yet. if (IFCAnyHandleUtil.IsSubTypeOf(ifcElement, IFCEntityType.IfcBuildingElement)) newIFCElement = IFCBuildingElement.ProcessIFCBuildingElement(ifcElement); else if (IFCAnyHandleUtil.IsSubTypeOf(ifcElement, IFCEntityType.IfcFeatureElement)) newIFCElement = IFCFeatureElement.ProcessIFCFeatureElement(ifcElement); else if (IFCAnyHandleUtil.IsSubTypeOf(ifcElement, IFCEntityType.IfcElementAssembly)) newIFCElement = IFCElementAssembly.ProcessIFCElementAssembly(ifcElement); else if (IFCAnyHandleUtil.IsSubTypeOf(ifcElement, IFCEntityType.IfcElementComponent)) newIFCElement = IFCElementComponent.ProcessIFCElementComponent(ifcElement); else newIFCElement = new IFCElement(ifcElement); return newIFCElement; }