/// <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> /// 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) { DirectShapeType shapeType = Importer.TheCache.UseElementByGUID <DirectShapeType>(doc, GlobalId); if (shapeType == null) { shapeType = IFCElementUtil.CreateElementType(doc, GetVisibleName(), CategoryId, Id); } else { // If we used the element from the cache, we want to make sure that the IFCRepresentationMap can access it // instead of creating a new element. Importer.TheCache.CreatedDirectShapeTypes[Id] = shapeType.Id; } if (shapeType == null) { throw new InvalidOperationException("Couldn't create DirectShapeType for IfcTypeObject."); } m_CreatedElementId = shapeType.Id; base.Create(doc); TraverseSubElements(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) { DirectShapeType shapeType = Importer.TheCache.UseElementByGUID <DirectShapeType>(doc, GlobalId); if (shapeType == null) { shapeType = DirectShapeType.Create(doc, GetName("DirectShapeType"), IFCElementUtil.GetDSValidCategoryId(doc, CategoryId, Id)); } if (shapeType == null) { throw new InvalidOperationException("Couldn't create DirectShapeType for IfcTypeObject."); } m_CreatedElementId = shapeType.Id; base.Create(doc); TraverseSubElements(doc); }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected virtual void TraverseSubElements(Document doc) { IList <ElementId> subElementIds = new List <ElementId>(); if (ComposedObjectDefinitions != null) { foreach (IFCObjectDefinition objectDefinition in ComposedObjectDefinitions) { IFCObjectDefinition.CreateElement(doc, objectDefinition); if (objectDefinition.CreatedElementId != ElementId.InvalidElementId) { subElementIds.Add(objectDefinition.CreatedElementId); } } } if (GroupSubElements()) { if (subElementIds.Count > 0) { 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, Importer.ImportAppGUID(), GlobalId); //Group group = doc.Create.NewGroup(subElementIds); if (directShape != null) { CreatedElementId = directShape.Id; } else { IFCImportFile.TheLog.LogCreationError(this, null, false); } } } }
/// <summary> /// Create geometry for a particular representation map. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <remarks>For this function, if lcs is null, we will create a library item for the geometry.</remarks> public void CreateShape(IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { bool creatingLibraryDefinition = (lcs == null); if (MappedRepresentation != null) { // Look for cached shape; if found, return. if (creatingLibraryDefinition) { if (IFCImportFile.TheFile.ShapeLibrary.FindDefinitionType(Id.ToString()) != ElementId.InvalidElementId) { return; } } Transform mappingTransform = null; if (lcs == null) { mappingTransform = MappingOrigin; } else { if (MappingOrigin == null) { mappingTransform = lcs; } else { mappingTransform = lcs.Multiply(MappingOrigin); } } Transform scaledMappingTransform = null; if (scaledLcs == null) { scaledMappingTransform = mappingTransform; } else { if (MappingOrigin == null) { scaledMappingTransform = scaledLcs; } else { scaledMappingTransform = scaledLcs.Multiply(MappingOrigin); } } int numExistingSolids = shapeEditScope.Creator.Solids.Count; int numExistingCurves = shapeEditScope.Creator.FootprintCurves.Count; MappedRepresentation.CreateShape(shapeEditScope, mappingTransform, scaledMappingTransform, guid); if (creatingLibraryDefinition) { int numNewSolids = shapeEditScope.Creator.Solids.Count; int numNewCurves = shapeEditScope.Creator.FootprintCurves.Count; if ((numExistingSolids != numNewSolids) || (numExistingCurves != numNewCurves)) { IList <GeometryObject> mappedSolids = new List <GeometryObject>(); for (int ii = numExistingSolids; ii < numNewSolids; ii++) { mappedSolids.Add(shapeEditScope.Creator.Solids[numExistingSolids].GeometryObject); shapeEditScope.Creator.Solids.RemoveAt(numExistingSolids); } IList <Curve> mappedCurves = new List <Curve>(); for (int ii = numExistingCurves; ii < numNewCurves; ii++) { mappedCurves.Add(shapeEditScope.Creator.FootprintCurves[numExistingCurves]); shapeEditScope.Creator.FootprintCurves.RemoveAt(numExistingCurves); } shapeEditScope.AddPlanViewCurves(mappedCurves, Id); Document doc = IFCImportFile.TheFile.Document; DirectShapeType directShapeType = null; IFCTypeProduct typeProduct = null; if (Importer.TheCache.RepMapToTypeProduct.TryGetValue(Id, out typeProduct)) { ElementId directShapeTypeId = ElementId.InvalidElementId; if (Importer.TheCache.CreatedDirectShapeTypes.TryGetValue(typeProduct.Id, out directShapeTypeId)) { directShapeType = doc.GetElement(directShapeTypeId) as DirectShapeType; } } if (directShapeType == null) { string directShapeTypeName = Id.ToString(); directShapeType = IFCElementUtil.CreateElementType(doc, directShapeTypeName, shapeEditScope.CategoryId, Id); } // Note that this assumes that there is only one 2D rep per DirectShapeType. directShapeType.AppendShape(mappedSolids); if (mappedCurves.Count != 0) { shapeEditScope.SetPlanViewRep(directShapeType); } IFCImportFile.TheFile.ShapeLibrary.AddDefinitionType(Id.ToString(), directShapeType.Id); } } } }
/// <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) { Transform lcs = (ObjectLocation != null) ? ObjectLocation.TotalTransform : Transform.Identity; if (ProductRepresentation != null) { if (ProductRepresentation.IsValid()) { using (IFCImportShapeEditScope shapeEditScope = IFCImportShapeEditScope.Create(doc, this)) { shapeEditScope.GraphicsStyleId = m_GraphicsStyleId; shapeEditScope.CategoryId = CategoryId; // The name can be added as well. but it is usually less useful than 'oid' string myId = GlobalId; // + "(" + Name + ")"; ProductRepresentation.CreateProductRepresentation(shapeEditScope, lcs, lcs, myId); int numSolids = Solids.Count; int numVoids = Voids.Count; if ((numSolids > 0) && (numVoids > 0)) { // We may have some GeometryInstances. These need to be "exploded" to do the cutting. for (int solidIdx = 0; solidIdx < numSolids; solidIdx++) { if (Solids[solidIdx].GeometryObject is GeometryInstance) { //// This code currently doesn't work, so commented out. //GeometryInstance geomInst = Solids[solidIdx].GeometryObject as GeometryInstance; //GeometryElement geomElem = geomInst.GetInstanceGeometry(); //foreach (GeometryObject geomObj in geomElem) //{ //if (geomObj is Solid) //Solids.Add(IFCSolidInfo.Create(Solids[solidIdx].Id, geomObj as Solid)); //else if (geomObj is Mesh) //Solids.Add(IFCSolidInfo.Create(Solids[solidIdx].Id, geomObj as Mesh)); //else if (geomObj is GeometryInstance) //IFCImportFile.TheLog.LogError(Solids[solidIdx].Id, "Can't cut nested mapped items, ignoring " + numVoids + " void(s).", false); // Other items are irrelevant here. //} //Solids.RemoveAt(solidIdx); //solidIdx--; //numSolids--; } } // 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++) { if (!(Solids[solidIdx].GeometryObject is Solid)) { // Assume that we only deal with solids, meshes and instances. string typeName = (Solids[solidIdx].GeometryObject is Mesh) ? "mesh" : "instance"; IFCImportFile.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)) { IFCImportFile.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); 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, Importer.ImportAppGUID(), GlobalId); } 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)) { IFCImportFile.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); m_CreatedElementId = shape.Id; } } } } else { IFCImportFile.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 virtual void TraverseSubElements(Document doc) { IList <ElementId> subElementIds = new List <ElementId>(); // These two should only be populated if GroupSubElements() is true and we are duplicating geometry for containers. List <GeometryObject> groupedSubElementGeometries = new List <GeometryObject>(); List <Curve> groupedSubElementFootprintCurves = new List <Curve>(); if (ComposedObjectDefinitions != null) { foreach (IFCObjectDefinition objectDefinition in ComposedObjectDefinitions) { IFCObjectDefinition.CreateElement(doc, objectDefinition); if (objectDefinition.CreatedElementId != ElementId.InvalidElementId) { subElementIds.Add(objectDefinition.CreatedElementId); // CreateDuplicateContainerGeometry is currently an API-only option (no UI), set to true by default. if (GroupSubElements() && Importer.TheOptions.CreateDuplicateContainerGeometry) { IList <GeometryObject> subGeometries = GetOrCloneGeometry(doc, objectDefinition); if (subGeometries != null) { groupedSubElementGeometries.AddRange(subGeometries); } if (objectDefinition is IFCProduct) { groupedSubElementFootprintCurves.AddRange((objectDefinition as IFCProduct).FootprintCurves); } } } } } if (GroupSubElements()) { if (subElementIds.Count > 0) { 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); //Group group = doc.Create.NewGroup(subElementIds); if (directShape != null) { CreatedElementId = directShape.Id; CreatedGeometry = groupedSubElementGeometries; if (groupedSubElementFootprintCurves.Count != 0 && this is IFCProduct) { using (IFCImportShapeEditScope planViewScope = IFCImportShapeEditScope.Create(doc, this as IFCProduct)) { planViewScope.AddPlanViewCurves(groupedSubElementFootprintCurves, Id); planViewScope.SetPlanViewRep(directShape); } } } else { Importer.TheLog.LogCreationError(this, null, false); } } } }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected virtual void TraverseSubElements(Document doc) { IList <ElementId> subElementIds = new List <ElementId>(); // These two should only be populated if GroupSubElements() is true and we are duplicating // geometry for containers. List <GeometryObject> groupedSubElementGeometries = new List <GeometryObject>(); List <Curve> groupedSubElementFootprintCurves = new List <Curve>(); foreach (IFCObjectDefinition objectDefinition in ComposedObjectDefinitions) { CreateElement(doc, objectDefinition); if (objectDefinition.CreatedElementId == ElementId.InvalidElementId) { continue; } subElementIds.Add(objectDefinition.CreatedElementId); // CreateDuplicateContainerGeometry is currently an API-only option (no UI), set to true by default. // // NAVIS_TODO - This is wrong if Importer.TheProcessor.ApplyTransforms is false if (!GroupSubElements() || !Importer.TheOptions.CreateDuplicateContainerGeometry) { continue; } IList <GeometryObject> subGeometries = GetOrCloneGeometry(doc, objectDefinition); if (subGeometries != null) { groupedSubElementGeometries.AddRange(subGeometries); } if (objectDefinition is IFCProduct) { groupedSubElementFootprintCurves.AddRange((objectDefinition as IFCProduct).FootprintCurves); } } if (groupedSubElementGeometries.Count > 0) { // Add main element geometry to include it in direct shape // and be able to assign parameters to the whole geometry and not just to subelements IList <GeometryObject> elementGeometry = GetOrCloneGeometry(doc, this); if ((elementGeometry?.Count ?? 0) > 0) { groupedSubElementGeometries.AddRange(elementGeometry); Importer.TheLog.LogWarning(Id, "Entity contains both geometry and sub-entities with geometry. This may result in duplicate geometry.", false); } } if (GroupSubElements()) { if (subElementIds.Count > 0) { 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) { CreatedElementId = directShape.Id; CreatedGeometry = groupedSubElementGeometries; if (groupedSubElementFootprintCurves.Count != 0 && this is IFCProduct) { using (IFCImportShapeEditScope planViewScope = IFCImportShapeEditScope.Create(doc, this as IFCProduct)) { planViewScope.AddPlanViewCurves(groupedSubElementFootprintCurves, Id); planViewScope.SetPlanViewRep(directShape); } } } else { Importer.TheLog.LogCreationError(this, null, false); } } } }
/// <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) { Transform lcs = (ObjectLocation != null) ? ObjectLocation.TotalTransform : Transform.Identity; // 2016+ only. Point point = Point.Create(lcs.Origin, GraphicsStyleId); // 2015+: create cone(s) for the direction of flow. CurveLoop rightTrangle = new CurveLoop(); const double radius = 0.5 / 12.0; const double height = 1.5 / 12.0; SolidOptions solidOptions = new SolidOptions(ElementId.InvalidElementId, GraphicsStyleId); Frame coordinateFrame = new Frame(lcs.Origin, lcs.BasisX, lcs.BasisY, lcs.BasisZ); // The origin is at the base of the cone for everything but source - then it is at the top of the cone. XYZ pt1 = FlowDirection == IFCFlowDirection.Source ? lcs.Origin - height * lcs.BasisZ : lcs.Origin; XYZ pt2 = pt1 + radius * lcs.BasisX; XYZ pt3 = pt1 + height * lcs.BasisZ; rightTrangle.Append(Line.CreateBound(pt1, pt2)); rightTrangle.Append(Line.CreateBound(pt2, pt3)); rightTrangle.Append(Line.CreateBound(pt3, pt1)); IList <CurveLoop> curveLoops = new List <CurveLoop>(); curveLoops.Add(rightTrangle); Solid portArrow = GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, curveLoops, 0.0, Math.PI * 2.0, solidOptions); Solid oppositePortArrow = null; if (FlowDirection == IFCFlowDirection.SourceAndSink) { Frame oppositeCoordinateFrame = new Frame(lcs.Origin, -lcs.BasisX, lcs.BasisY, -lcs.BasisZ); CurveLoop oppositeRightTrangle = new CurveLoop(); XYZ oppPt2 = pt1 - radius * lcs.BasisX; XYZ oppPt3 = pt1 - height * lcs.BasisZ; oppositeRightTrangle.Append(Line.CreateBound(pt1, oppPt2)); oppositeRightTrangle.Append(Line.CreateBound(oppPt2, oppPt3)); oppositeRightTrangle.Append(Line.CreateBound(oppPt3, pt1)); IList <CurveLoop> oppositeCurveLoops = new List <CurveLoop>(); oppositeCurveLoops.Add(oppositeRightTrangle); oppositePortArrow = GeometryCreationUtilities.CreateRevolvedGeometry(oppositeCoordinateFrame, oppositeCurveLoops, 0.0, Math.PI * 2.0, solidOptions); } if (portArrow != null) { IList <GeometryObject> geomObjs = new List <GeometryObject>(); if (point != null) { geomObjs.Add(point); } geomObjs.Add(portArrow); if (oppositePortArrow != null) { geomObjs.Add(oppositePortArrow); } DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs, Id); if (directShape != null) { CreatedGeometry = geomObjs; CreatedElementId = directShape.Id; } else { Importer.TheLog.LogCreationError(this, null, false); } } }
/// <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> /// Create geometry for a particular representation map. /// </summary> /// <param name="shapeEditScope">The geometry creation scope.</param> /// <param name="lcs">Local coordinate system for the geometry, without scale.</param> /// <param name="scaledLcs">Local coordinate system for the geometry, including scale, potentially non-uniform.</param> /// <remarks>For this function, if lcs is null, we will create a library item for the geometry.</remarks> public void CreateShape(IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid) { bool creatingLibraryDefinition = (lcs == null); if (MappedRepresentation != null) { // Look for cached shape; if found, return. if (creatingLibraryDefinition) { if (IFCImportFile.TheFile.ShapeLibrary.FindDefinitionType(Id.ToString()) != ElementId.InvalidElementId) { return; } } Transform mappingTransform = null; if (lcs == null) { mappingTransform = MappingOrigin; } else { if (MappingOrigin == null) { mappingTransform = lcs; } else { mappingTransform = lcs.Multiply(MappingOrigin); } } Transform scaledMappingTransform = null; if (scaledLcs == null) { scaledMappingTransform = mappingTransform; } else { if (MappingOrigin == null) { scaledMappingTransform = scaledLcs; } else { scaledMappingTransform = scaledLcs.Multiply(MappingOrigin); } } int numExistingSolids = shapeEditScope.Creator.Solids.Count; int numExistingCurves = shapeEditScope.Creator.FootprintCurves.Count; MappedRepresentation.CreateShape(shapeEditScope, mappingTransform, scaledMappingTransform, guid); if (creatingLibraryDefinition) { int numNewSolids = shapeEditScope.Creator.Solids.Count; int numNewCurves = shapeEditScope.Creator.FootprintCurves.Count; if ((numExistingSolids != numNewSolids) || (numExistingCurves != numNewCurves)) { IList <GeometryObject> mappedSolids = new List <GeometryObject>(); for (int ii = numExistingSolids; ii < numNewSolids; ii++) { mappedSolids.Add(shapeEditScope.Creator.Solids[numExistingSolids].GeometryObject); shapeEditScope.Creator.Solids.RemoveAt(numExistingSolids); } IList <Curve> mappedCurves = new List <Curve>(); for (int ii = numExistingCurves; ii < numNewCurves; ii++) { mappedCurves.Add(shapeEditScope.Creator.FootprintCurves[numExistingCurves]); shapeEditScope.Creator.FootprintCurves.RemoveAt(numExistingCurves); } shapeEditScope.AddPlanViewCurves(mappedCurves, Id); //IFCImportFile.TheFile.ShapeLibrary.AddDefinition(Id.ToString(), mappedItems); Document doc = IFCImportFile.TheFile.Document; DirectShapeType directShapeType = DirectShapeType.Create(doc, Id.ToString(), IFCElementUtil.GetDSValidCategoryId(doc, shapeEditScope.CategoryId, Id)); directShapeType.SetShape(mappedSolids); shapeEditScope.SetPlanViewRep(directShapeType); IFCImportFile.TheFile.ShapeLibrary.AddDefinitionType(Id.ToString(), directShapeType.Id); } } } }
/// <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) { // Try to get the location: // 1. From the ObjectLocation, if it exists. This should be exact. // 2. From the ObjectLocation of the element that the port is associated to, if it exists. // This should be approximate. // 3. Default to the origin. Transform lcs = ObjectLocation?.TotalTransform; if (lcs == null) { lcs = ContainedIn?.ObjectLocation?.TotalTransform; } if (lcs == null) { lcs = Transform.Identity; } // 2016+ only. XYZ origin = lcs.Origin; 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); Frame coordinateFrame = new Frame(lcs.Origin, lcs.BasisX, lcs.BasisY, lcs.BasisZ); // The origin is at the base of the cone for everything but source - then it is at the top of the cone. XYZ pt1 = FlowDirection == IFCFlowDirection.Source ? lcs.Origin - height * lcs.BasisZ : lcs.Origin; XYZ pt2 = pt1 + radius * lcs.BasisX; XYZ pt3 = pt1 + height * lcs.BasisZ; rightTrangle.Append(Line.CreateBound(pt1, pt2)); rightTrangle.Append(Line.CreateBound(pt2, pt3)); rightTrangle.Append(Line.CreateBound(pt3, pt1)); IList <CurveLoop> curveLoops = new List <CurveLoop>(); curveLoops.Add(rightTrangle); Solid portArrow = GeometryCreationUtilities.CreateRevolvedGeometry(coordinateFrame, curveLoops, 0.0, Math.PI * 2.0, solidOptions); Solid oppositePortArrow = null; if (FlowDirection == IFCFlowDirection.SourceAndSink) { Frame oppositeCoordinateFrame = new Frame(lcs.Origin, -lcs.BasisX, lcs.BasisY, -lcs.BasisZ); CurveLoop oppositeRightTrangle = new CurveLoop(); XYZ oppPt2 = pt1 - radius * lcs.BasisX; XYZ oppPt3 = pt1 - height * lcs.BasisZ; oppositeRightTrangle.Append(Line.CreateBound(pt1, oppPt2)); oppositeRightTrangle.Append(Line.CreateBound(oppPt2, oppPt3)); oppositeRightTrangle.Append(Line.CreateBound(oppPt3, pt1)); IList <CurveLoop> oppositeCurveLoops = new List <CurveLoop>(); oppositeCurveLoops.Add(oppositeRightTrangle); oppositePortArrow = GeometryCreationUtilities.CreateRevolvedGeometry(oppositeCoordinateFrame, oppositeCurveLoops, 0.0, Math.PI * 2.0, solidOptions); } if (portArrow != null) { IList <GeometryObject> geomObjs = new List <GeometryObject>(); if (point != null) { geomObjs.Add(point); } geomObjs.Add(portArrow); if (oppositePortArrow != null) { geomObjs.Add(oppositePortArrow); } DirectShape directShape = IFCElementUtil.CreateElement(doc, CategoryId, GlobalId, geomObjs, Id, EntityType); if (directShape != null) { CreatedGeometry = geomObjs; CreatedElementId = directShape.Id; } else { Importer.TheLog.LogCreationError(this, null, false); } } }