コード例 #1
0
ファイル: IFCProduct.cs プロジェクト: lfcastel/revit-ifc
        /// <summary>
        /// Cut a IFCSolidInfo by the voids in this IFCProduct, if any.
        /// </summary>
        /// <param name="solidInfo">The solid information.</param>
        /// <returns>False if the return solid is empty; true otherwise.</returns>
        protected override bool CutSolidByVoids(IFCSolidInfo solidInfo)
        {
            int numVoids = Voids.Count;

            if (numVoids == 0)
            {
                return(true);
            }

            // We only cut body representation items.
            if (solidInfo.RepresentationType != IFCRepresentationIdentifier.Body)
            {
                return(true);
            }

            if (!(solidInfo.GeometryObject is Solid))
            {
                string typeName = (solidInfo.GeometryObject is Mesh) ? "mesh" : "instance";
                Importer.TheLog.LogError(Id, "Can't cut " + typeName + " geometry, ignoring " + numVoids + " void(s).", false);
                return(true);
            }

            for (int voidIdx = 0; voidIdx < numVoids; voidIdx++)
            {
                Solid voidObject = Voids[voidIdx].GeometryObject as Solid;
                if (voidObject == null)
                {
                    Importer.TheLog.LogError(Id, "Can't cut Solid geometry with a Mesh (# " + Voids[voidIdx].Id + "), ignoring.", false);
                    return(true);
                }

                solidInfo.GeometryObject = IFCGeometryUtil.ExecuteSafeBooleanOperation(solidInfo.Id, Voids[voidIdx].Id,
                                                                                       (solidInfo.GeometryObject as Solid), voidObject, BooleanOperationsType.Difference, null);
                if (solidInfo.GeometryObject == null || (solidInfo.GeometryObject as Solid).Faces.IsEmpty)
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Return geometry for a particular representation item.
        /// </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>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        /// <returns>The created geometry.</returns>
        public IList <GeometryObject> CreateGeometry(
            IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            IList <GeometryObject> firstSolids = FirstOperand.CreateGeometry(shapeEditScope, lcs, scaledLcs, guid);

            if (firstSolids != null)
            {
                foreach (GeometryObject potentialSolid in firstSolids)
                {
                    if (!(potentialSolid is Solid))
                    {
                        Importer.TheLog.LogError((FirstOperand as IFCRepresentationItem).Id, "Can't perform Boolean operation on a Mesh.", false);
                        return(firstSolids);
                    }
                }
            }

            IList <GeometryObject> secondSolids = null;

            if (SecondOperand != null)
            {
                try
                {
                    using (IFCImportShapeEditScope.BuildPreferenceSetter setter =
                               new IFCImportShapeEditScope.BuildPreferenceSetter(shapeEditScope, IFCImportShapeEditScope.BuildPreferenceType.ForceSolid))
                    {
                        // Before we process the second operand, we are going to see if there is a uniform material set for the first operand
                        // (corresponding to the solid in the Boolean operation).  We will try to suggest the same material for the voids to avoid arbitrary
                        // setting of material information for the cut faces.
                        IFCStyledItem firstOperandStyledItem = GetStyledItemFromOperand(FirstOperand as IFCRepresentationItem);
                        using (IFCImportShapeEditScope.IFCMaterialStack stack =
                                   new IFCImportShapeEditScope.IFCMaterialStack(shapeEditScope, firstOperandStyledItem, null))
                        {
                            secondSolids = SecondOperand.CreateGeometry(shapeEditScope, lcs, scaledLcs, guid);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // We will allow something to be imported, in the case where the second operand is invalid.
                    // If the first (base) operand is invalid, we will still fail the import of this solid.
                    if (SecondOperand is IFCRepresentationItem)
                    {
                        Importer.TheLog.LogError((SecondOperand as IFCRepresentationItem).Id, ex.Message, false);
                    }
                    else
                    {
                        throw ex;
                    }
                    secondSolids = null;
                }
            }

            IList <GeometryObject> resultSolids = null;

            if (firstSolids == null)
            {
                resultSolids = secondSolids;
            }
            else if (secondSolids == null || BooleanOperator == null)
            {
                if (BooleanOperator == null)
                {
                    Importer.TheLog.LogError(Id, "Invalid BooleanOperationsType.", false);
                }
                resultSolids = firstSolids;
            }
            else
            {
                BooleanOperationsType booleanOperationsType = BooleanOperationsType.Difference;
                switch (BooleanOperator)
                {
                case IFCBooleanOperator.Difference:
                    booleanOperationsType = BooleanOperationsType.Difference;
                    break;

                case IFCBooleanOperator.Intersection:
                    booleanOperationsType = BooleanOperationsType.Intersect;
                    break;

                case IFCBooleanOperator.Union:
                    booleanOperationsType = BooleanOperationsType.Union;
                    break;

                default:
                    Importer.TheLog.LogError(Id, "Invalid BooleanOperationsType.", true);
                    break;
                }

                resultSolids = new List <GeometryObject>();
                foreach (GeometryObject firstSolid in firstSolids)
                {
                    Solid resultSolid = (firstSolid as Solid);

                    int secondId = (SecondOperand == null) ? -1 : (SecondOperand as IFCRepresentationItem).Id;
                    XYZ suggestedShiftDirection = (SecondOperand == null) ? null : SecondOperand.GetSuggestedShiftDirection(lcs);
                    foreach (GeometryObject secondSolid in secondSolids)
                    {
                        resultSolid = IFCGeometryUtil.ExecuteSafeBooleanOperation(Id, secondId, resultSolid, secondSolid as Solid, booleanOperationsType, suggestedShiftDirection);
                        if (resultSolid == null)
                        {
                            break;
                        }
                    }

                    if (resultSolid != null)
                    {
                        resultSolids.Add(resultSolid);
                    }
                }
            }

            return(resultSolids);
        }
コード例 #3
0
        /// <summary>
        /// Create geometry for an IfcHalfSpaceSolid.
        /// </summary>
        /// <param name="shapeEditScope">The shape edit 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>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        /// <returns>A list containing one geometry for the IfcHalfSpaceSolid.</returns>
        protected virtual IList <GeometryObject> CreateGeometryInternal(
            IFCImportShapeEditScope shapeEditScope, Transform unscaledLcs, Transform scaledLcs, string guid)
        {
            IFCPlane ifcPlane = BaseSurface as IFCPlane;
            Plane    plane    = ifcPlane.Plane;
            XYZ      origin   = plane.Origin;
            XYZ      xVec     = plane.XVec;
            XYZ      yVec     = plane.YVec;

            // Set some huge boundaries for now.
            const double largeCoordinateValue = 100000;

            XYZ[] corners = new XYZ[4] {
                unscaledLcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin),
                unscaledLcs.OfPoint((xVec * largeCoordinateValue) + (yVec * -largeCoordinateValue) + origin),
                unscaledLcs.OfPoint((xVec * largeCoordinateValue) + (yVec * largeCoordinateValue) + origin),
                unscaledLcs.OfPoint((xVec * -largeCoordinateValue) + (yVec * largeCoordinateValue) + origin)
            };

            IList <CurveLoop> loops = new List <CurveLoop>();
            CurveLoop         loop  = new CurveLoop();

            for (int ii = 0; ii < 4; ii++)
            {
                if (AgreementFlag)
                {
                    loop.Append(Line.CreateBound(corners[(5 - ii) % 4], corners[(4 - ii) % 4]));
                }
                else
                {
                    loop.Append(Line.CreateBound(corners[ii], corners[(ii + 1) % 4]));
                }
            }
            loops.Add(loop);

            XYZ          normal       = unscaledLcs.OfVector(AgreementFlag ? -plane.Normal : plane.Normal);
            SolidOptions solidOptions = new SolidOptions(GetMaterialElementId(shapeEditScope), shapeEditScope.GraphicsStyleId);
            Solid        baseSolid    = GeometryCreationUtilities.CreateExtrusionGeometry(loops, normal, largeCoordinateValue, solidOptions);

            if (BaseBoundingCurve != null)
            {
                CurveLoop polygonalBoundary = BaseBoundingCurve.CurveLoop;

                Transform unscaledTotalTransform = unscaledLcs.Multiply(BaseBoundingCurveTransform);
                Transform scaledTotalTransform   = scaledLcs.Multiply(BaseBoundingCurveTransform);

                // Make sure this bounding polygon extends below base of half-space soild.
                Transform moveBaseTransform = Transform.Identity;
                moveBaseTransform.Origin = new XYZ(0, 0, -largeCoordinateValue);

                unscaledTotalTransform = unscaledTotalTransform.Multiply(moveBaseTransform);
                scaledTotalTransform   = scaledTotalTransform.Multiply(moveBaseTransform);

                CurveLoop         transformedPolygonalBoundary = IFCGeometryUtil.CreateTransformed(polygonalBoundary, Id, unscaledTotalTransform, scaledTotalTransform);
                IList <CurveLoop> boundingLoops = new List <CurveLoop>();
                boundingLoops.Add(transformedPolygonalBoundary);

                Solid boundingSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boundingLoops, unscaledTotalTransform.BasisZ, 2.0 * largeCoordinateValue,
                                                                                        solidOptions);
                baseSolid = IFCGeometryUtil.ExecuteSafeBooleanOperation(Id, BaseBoundingCurve.Id, baseSolid, boundingSolid, BooleanOperationsType.Intersect, null);
            }

            IList <GeometryObject> returnList = new List <GeometryObject>();

            returnList.Add(baseSolid);
            return(returnList);
        }
コード例 #4
0
        /// <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);
        }
コード例 #5
0
        /// <summary>
        /// Return geometry for a particular representation item.
        /// </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>
        /// <param name="guid">The guid of an element for which represntation is being created.</param>
        /// <returns>The created geometry.</returns>
        public IList <GeometryObject> CreateGeometry(
            IFCImportShapeEditScope shapeEditScope, Transform lcs, Transform scaledLcs, string guid)
        {
            IList <GeometryObject> firstSolids = FirstOperand.CreateGeometry(shapeEditScope, lcs, scaledLcs, guid);

            if (firstSolids != null)
            {
                foreach (GeometryObject potentialSolid in firstSolids)
                {
                    if (!(potentialSolid is Solid))
                    {
                        IFCImportFile.TheLog.LogError((FirstOperand as IFCRepresentationItem).Id, "Can't perform Boolean operation on a Mesh.", false);
                        return(firstSolids);
                    }
                }
            }

            IList <GeometryObject> secondSolids = null;

            if (SecondOperand != null)
            {
                try
                {
                    using (IFCImportShapeEditScope.IFCTargetSetter setter =
                               new IFCImportShapeEditScope.IFCTargetSetter(shapeEditScope, TessellatedShapeBuilderTarget.Solid, TessellatedShapeBuilderFallback.Abort))
                    {
                        secondSolids = SecondOperand.CreateGeometry(shapeEditScope, lcs, scaledLcs, guid);
                    }
                }
                catch (Exception ex)
                {
                    // We will allow something to be imported, in the case where the second operand is invalid.
                    // If the first (base) operand is invalid, we will still fail the import of this solid.
                    if (SecondOperand is IFCRepresentationItem)
                    {
                        IFCImportFile.TheLog.LogError((SecondOperand as IFCRepresentationItem).Id, ex.Message, false);
                    }
                    else
                    {
                        throw ex;
                    }
                    secondSolids = null;
                }
            }

            IList <GeometryObject> resultSolids = null;

            if (firstSolids == null)
            {
                resultSolids = secondSolids;
            }
            else if (secondSolids == null)
            {
                resultSolids = firstSolids;
            }
            else
            {
                BooleanOperationsType booleanOperationsType = BooleanOperationsType.Difference;
                switch (BooleanOperator)
                {
                case IFCBooleanOperator.Difference:
                    booleanOperationsType = BooleanOperationsType.Difference;
                    break;

                case IFCBooleanOperator.Intersection:
                    booleanOperationsType = BooleanOperationsType.Intersect;
                    break;

                case IFCBooleanOperator.Union:
                    booleanOperationsType = BooleanOperationsType.Union;
                    break;

                default:
                    IFCImportFile.TheLog.LogError(Id, "Invalid BooleanOperationsType.", true);
                    break;
                }

                resultSolids = new List <GeometryObject>();
                foreach (GeometryObject firstSolid in firstSolids)
                {
                    Solid resultSolid = (firstSolid as Solid);

                    int secondId = (SecondOperand == null) ? -1 : (SecondOperand as IFCRepresentationItem).Id;
                    foreach (GeometryObject secondSolid in secondSolids)
                    {
                        resultSolid = IFCGeometryUtil.ExecuteSafeBooleanOperation(Id, secondId, resultSolid, secondSolid as Solid, booleanOperationsType);
                        if (resultSolid == null)
                        {
                            break;
                        }
                    }

                    if (resultSolid != null)
                    {
                        resultSolids.Add(resultSolid);
                    }
                }
            }

            return(resultSolids);
        }
コード例 #6
0
        /// <summary>
        /// Cut a IFCSolidInfo by the voids in this IFCProduct, if any.
        /// </summary>
        /// <param name="solidInfo">The solid information.</param>
        /// <returns>False if the return solid is empty; true otherwise.</returns>
        protected override bool CutSolidByVoids(IFCSolidInfo solidInfo)
        {
            // We only cut "Body" representation items.
            if (solidInfo.RepresentationType != IFCRepresentationIdentifier.Body)
            {
                return(true);
            }

            IList <IFCVoidInfo> voidsToUse = null;
            List <IFCVoidInfo>  partVoids  = null;

            IList <IFCVoidInfo> parentVoids = (Decomposes as IFCProduct)?.Voids;

            if (parentVoids != null)
            {
                partVoids = new List <IFCVoidInfo>();
                partVoids.AddRange(Voids);
                partVoids.AddRange(parentVoids);
                voidsToUse = partVoids;
            }
            else
            {
                voidsToUse = Voids;
            }

            int numVoids = voidsToUse.Count;

            if (numVoids == 0)
            {
                return(true);
            }

            if (!(solidInfo.GeometryObject is Solid))
            {
                string typeName = (solidInfo.GeometryObject is Mesh) ? "mesh" : "instance";
                Importer.TheLog.LogError(Id, "Can't cut " + typeName + " geometry, ignoring " + numVoids + " void(s).", false);
                return(true);
            }

            foreach (IFCVoidInfo voidInfo in voidsToUse)
            {
                Solid voidObject = voidInfo.GeometryObject as Solid;
                if (voidObject == null)
                {
                    Importer.TheLog.LogError(Id, "Can't cut Solid geometry with a Mesh (# " + voidInfo.Id + "), ignoring.", false);
                    continue;
                }

                var voidTransform = voidInfo.TotalTransform;

                if (voidTransform != null && voidTransform.IsIdentity == false)
                {
                    // Transform the void into the space of the solid.
                    var t = ObjectLocation.TotalTransform.Inverse.Multiply(voidTransform);
                    voidObject = SolidUtils.CreateTransformed(voidObject, t);
                }

                solidInfo.GeometryObject = IFCGeometryUtil.ExecuteSafeBooleanOperation(solidInfo.Id, voidInfo.Id,
                                                                                       (solidInfo.GeometryObject as Solid), voidObject, BooleanOperationsType.Difference, null);

                if (solidInfo.GeometryObject == null || (solidInfo.GeometryObject as Solid).Faces.IsEmpty)
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #7
0
        /// <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);
        }