예제 #1
0
 /// <summary>
 /// Boolean intersect geometric operation, return a new solid as the result
 /// </summary>
 /// <param name="solid1">Operation solid 1</param>
 /// <param name="solid2">Operation solid 2</param>
 /// <returns>The operation result</returns>
 public static Solid BooleanOperation_Intersect(Solid solid1, Solid solid2)
 {
     return(BooleanOperationsUtils.ExecuteBooleanOperation(solid1, solid2, BooleanOperationsType.Intersect));
 }
예제 #2
0
 /// <summary>
 /// Boolean union geometric operation, modify the original solid as the result
 /// </summary>
 /// <param name="solid1">Operation solid 1 and operation result</param>
 /// <param name="solid2">Operation solid 2</param>
 public static void BooleanOperation_Union(ref Solid solid1, Solid solid2)
 {
     BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(solid1, solid2, BooleanOperationsType.Union);
 }
예제 #3
0
 /// <summary>
 /// Boolean difference geometric operation, modify the original solid as the result
 /// </summary>
 /// <param name="solid1">Operation solid 1 and operation result</param>
 /// <param name="solid2">Operation solid 2</param>
 public static void BooleanOperation_Difference(ref Solid solid1, Solid solid2)
 {
     BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(solid1, solid2, BooleanOperationsType.Difference);
 }
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;
            Selection     sel   = uidoc.Selection;

            // Retrieve all floors from the model

            var floors
                = new FilteredElementCollector(doc)
                  .OfClass(typeof(Floor))
                  .ToElements()
                  .Cast <Floor>()
                  .ToList();

            if (2 != floors.Count)
            {
                message = "Please create two intersected floors";
                return(Result.Failed);
            }

            // Retrieve the floor solids

            Options opt = new Options();

            var geometry1 = floors[0].get_Geometry(opt);
            var geometry2 = floors[1].get_Geometry(opt);

            var solid1 = geometry1.FirstOrDefault() as Solid;
            var solid2 = geometry2.FirstOrDefault() as Solid;

            // Calculate the intersection solid

            var intersectedSolid = BooleanOperationsUtils
                                   .ExecuteBooleanOperation(solid1, solid2,
                                                            BooleanOperationsType.Intersect);

            // Search for the metric mass family template file

            string template_path = DirSearch(
                app.FamilyTemplatePath,
                "Metric Mass.rft");

            // Create a new temporary family

            var family_doc = app.NewFamilyDocument(
                template_path);

            // Create a free form element
            // from the intersection solid

            using (var t = new Transaction(family_doc))
            {
                t.Start("Add Free Form Element");

                var freeFormElement = FreeFormElement.Create(
                    family_doc, intersectedSolid);

                t.Commit();
            }

            string dir = Path.GetTempPath();

            string filepath = Path.Combine(dir,
                                           "floor_intersection_family.rfa");

            SaveAsOptions sao = new SaveAsOptions()
            {
                OverwriteExistingFile = true
            };

            family_doc.SaveAs(filepath, sao);

            // Create 3D View

            var viewFamilyType
                = new FilteredElementCollector(family_doc)
                  .OfClass(typeof(ViewFamilyType))
                  .OfType <ViewFamilyType>()
                  .FirstOrDefault(x =>
                                  x.ViewFamily == ViewFamily.ThreeDimensional);

            View3D threeDView;

            using (var t = new Transaction(family_doc))
            {
                t.Start("Create 3D View");

                threeDView = View3D.CreateIsometric(
                    family_doc, viewFamilyType.Id);

                t.Commit();
            }

            // Export to SAT

            var viewSet = new List <ElementId>()
            {
                threeDView.Id
            };

            SATExportOptions exportOptions
                = new SATExportOptions();

            var res = family_doc.Export(dir,
                                        "SolidFile.sat", viewSet, exportOptions);

            return(Result.Succeeded);
        }
예제 #5
0
 /// <summary>
 /// Boolean intersect geometric operation, modify the original solid as the result
 /// </summary>
 /// <param name="solid1">Operation solid 1 and operation result</param>
 /// <param name="solid2">Operation solid 2</param>
 public static void BooleanOperation_Intersect(ref Solid solid1, Solid solid2)
 {
     BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(solid1, solid2, BooleanOperationsType.Intersect);
 }
예제 #6
0
 /// <summary>
 /// Gets the result of between a solid and a solid cross.
 /// </summary>
 /// <param name="solid1"></param>
 /// <param name="solid2"></param>
 /// <returns></returns>
 public static bool CrossSolid(this Solid solid1, Solid solid2)
 {
     return(BooleanOperationsUtils.ExecuteBooleanOperation(solid1, solid2, BooleanOperationsType.Intersect).Volume > 0);
 }
예제 #7
0
        /// <summary>
        /// Execute a Boolean operation, and catch the exception.
        /// </summary>
        /// <param name="id">The id of the object demanding the Boolean operation.</param>
        /// <param name="secondId">The id of the object providing the second solid.</param>
        /// <param name="firstSolid">The first solid parameter to ExecuteBooleanOperation.</param>
        /// <param name="secondSolid">The second solid parameter to ExecuteBooleanOperation.</param>
        /// <param name="opType">The Boolean operation type.</param>
        /// <param name="suggestedShiftDirection">If the Boolean operation fails, a unit vector used to retry with a small shift.  Can be null.</param>
        /// <returns>The result of the Boolean operation, or the first solid if the operation fails.</returns>
        public static Solid ExecuteSafeBooleanOperation(int id, int secondId, Solid firstSolid, Solid secondSolid, BooleanOperationsType opType, XYZ suggestedShiftDirection)
        {
            const double footToMillimeter = 1.0 / 304.8;

            // Perform default operations if one of the arguments is null.
            if (firstSolid == null || secondSolid == null)
            {
                if (firstSolid == null && secondSolid == null)
                {
                    return(null);
                }

                switch (opType)
                {
                case BooleanOperationsType.Union:
                {
                    if (firstSolid == null)
                    {
                        return(secondSolid);
                    }

                    return(firstSolid);
                }

                case BooleanOperationsType.Difference:
                {
                    if (firstSolid == null)
                    {
                        return(null);
                    }

                    return(firstSolid);
                }

                default:
                    // for .Intersect
                    return(null);
                }
            }

            Solid resultSolid       = null;
            bool  failedAllAttempts = true;

            // We will attempt to do the Boolean operation 3 times:
            // 1st pass: With the passed-in arguments.
            // 2nd pass: With a 1mm shift in a direction in suggestedShiftDirection, or +Z if suggestedShiftDirection is null
            // 3rd pass: With a 1mm shift in a direction in -suggestedShiftDirection, or -Z if suggestedShiftDirection is null
            for (int ii = 0; ii < 3; ii++)
            {
                try
                {
                    resultSolid = null;

                    Solid secondOperand = secondSolid;
                    if (ii > 0)
                    {
                        // 1 mm shift.
                        XYZ       shiftDirection   = (suggestedShiftDirection == null) ? new XYZ(0, 0, 1) : suggestedShiftDirection;
                        Transform secondSolidShift = Transform.CreateTranslation(shiftDirection * ((ii == 1) ? footToMillimeter : -footToMillimeter));
                        secondOperand = SolidUtils.CreateTransformed(secondOperand, secondSolidShift);
                    }

                    resultSolid       = BooleanOperationsUtils.ExecuteBooleanOperation(firstSolid, secondOperand, opType);
                    failedAllAttempts = false;
                }
                catch (Exception ex)
                {
                    if (ii < 2)
                    {
                        continue;
                    }

                    Importer.TheLog.LogError(id, ex.Message, false);
                    resultSolid = firstSolid;
                }

                if (SolidValidator.IsValidGeometry(resultSolid))
                {
                    // If we got here not on out first attempt, generate a warning, unless we got here because we gave up on our 3rd attempt.
                    if (ii > 0 && !failedAllAttempts)
                    {
                        Importer.TheLog.LogWarning(id, "The second argument in the Boolean " +
                                                   opType.ToString() +
                                                   " operation was shifted by 1mm to allow the operation to succeed.  This may result in a very small difference in appearance.", false);
                    }
                    return(resultSolid);
                }
            }

            Importer.TheLog.LogError(id, opType.ToString() + " operation failed with void from #" + secondId.ToString(), false);
            return(firstSolid);
        }
예제 #8
0
        /// <summary>
        /// Creates a negative block family from the geometry of the target element and boundaries.
        /// </summary>
        /// <remarks>This is the main implementation of the sample command.</remarks>
        /// <param name="targetElement">The target solid element.</param>
        /// <param name="boundaries">The selected curve element boundaries.</param>
        /// <param name="familyLoadOptions">The family load options when loading the new family.</param>
        /// <param name="familyTemplate">The family template.</param>
        public static FailureCondition CreateNegativeBlock(Element targetElement, IList <Reference> boundaries, IFamilyLoadOptions familyLoadOptions, String familyTemplate)
        {
            Document doc = targetElement.Document;

            Autodesk.Revit.ApplicationServices.Application app = doc.Application;

            // Get curve loop for boundary
            IList <Curve> curves = GetContiguousCurvesFromSelectedCurveElements(doc, boundaries);
            CurveLoop     loop   = null;

            try
            {
                loop = CurveLoop.Create(curves);
            }
            catch (Autodesk.Revit.Exceptions.ArgumentException)
            {
                // Curves are not contiguous
                return(FailureCondition.CurvesNotContigous);
            }
            List <CurveLoop> loops = new List <CurveLoop>();

            loops.Add(loop);

            // Get elevation of loop
            double elevation = curves[0].GetEndPoint(0).Z;

            // Get height for extrusion
            BoundingBoxXYZ bbox   = targetElement.get_BoundingBox(null);
            double         height = bbox.Max.Z - elevation;

            if (height <= 1e-5)
            {
                return(FailureCondition.CurveLoopAboveTarget);
            }

            height += 1;

            // Create family
            Document familyDoc = app.NewFamilyDocument(familyTemplate);

            // Create block from boundaries
            Solid block = GeometryCreationUtilities.CreateExtrusionGeometry(loops, XYZ.BasisZ, height);

            // Subtract target element
            IList <Solid> fromElement = GetTargetSolids(targetElement);

            int solidCount = fromElement.Count;

            // Merge all found solids into single one
            Solid toSubtract = null;

            if (solidCount == 1)
            {
                toSubtract = fromElement[0];
            }

            else if (solidCount > 1)
            {
                toSubtract =
                    BooleanOperationsUtils.ExecuteBooleanOperation(fromElement[0], fromElement[1], BooleanOperationsType.Union);
            }

            if (solidCount > 2)
            {
                for (int i = 2; i < solidCount; i++)
                {
                    toSubtract = BooleanOperationsUtils.ExecuteBooleanOperation(toSubtract, fromElement[i],
                                                                                BooleanOperationsType.Union);
                }
            }

            // Subtract merged solid from overall block
            try
            {
                BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(block, toSubtract,
                                                                                     BooleanOperationsType.Difference);
            }
            catch (Autodesk.Revit.Exceptions.InvalidOperationException)
            {
                return(FailureCondition.NoIntersection);
            }

            // Create freeform element
            using (Transaction t = new Transaction(familyDoc, "Add element"))
            {
                t.Start();
                RevitFreeFormElement element = Autodesk.Revit.DB.FreeFormElement.Create(familyDoc, block);
                t.Commit();
            }

            // Load family into document
            Family family = familyDoc.LoadFamily(doc, familyLoadOptions);

            familyDoc.Close(false);

            // Get symbol as first symbol of loaded family
            FilteredElementCollector collector = new FilteredElementCollector(doc);

            collector.WherePasses(new FamilySymbolFilter(family.Id));
            FamilySymbol fs = collector.FirstElement() as FamilySymbol;


            // Place instance at location of original curves
            using (Transaction t2 = new Transaction(doc, "Place instance"))
            {
                t2.Start();
                if (!fs.IsActive)
                {
                    fs.Activate();
                }
                doc.Create.NewFamilyInstance(XYZ.Zero, fs, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
                t2.Commit();
            }

            return(FailureCondition.Success);
        }
예제 #9
0
        /// <summary>
        /// This method takes the solidsList and clips all of its solids between the given range.
        /// </summary>
        /// <param name="elem">
        /// The Element from which we obtain our BoundingBoxXYZ.
        /// </param>
        /// <param name="geomElem">
        /// The top-level GeometryElement from which to gather X and Y coordinates for the intersecting solid.
        /// </param>
        /// <param name="range">
        /// The IFCRange whose Z values we use to create an intersecting solid to clip the solids in this class's internal solidsList.
        /// If range boundaries are equal, method returns, performing no clippings.
        /// </param>
        public void ClipSolidsList(GeometryElement geomElem, IFCRange range)
        {
            if (geomElem == null)
            {
                throw new ArgumentNullException("geomElemToUse");
            }
            if (MathUtil.IsAlmostEqual(range.Start, range.End) || solidsList.Count == 0)
            {
                return;
            }

            double bottomZ;
            double boundDifference;

            if (range.Start < range.End)
            {
                bottomZ         = range.Start;
                boundDifference = range.End - range.Start;
            }
            else
            {
                bottomZ         = range.End;
                boundDifference = range.Start - range.End;
            }

            Autodesk.Revit.DB.Document doc = ExporterCacheManager.Document;
            Autodesk.Revit.ApplicationServices.Application application = doc.Application;
            Autodesk.Revit.Creation.Application            app         = application.Create;

            // create a new solid using the X and Y of the bounding box on the top level GeometryElement and the Z of the IFCRange
            BoundingBoxXYZ elemBoundingBox = geomElem.GetBoundingBox();
            XYZ            pointA          = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ            pointB          = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ            pointC          = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Max.Y, bottomZ);
            XYZ            pointD          = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Max.Y, bottomZ);

            List <Curve> perimeter = new List <Curve>();

            perimeter.Add(app.NewLineBound(pointA, pointB));
            perimeter.Add(app.NewLineBound(pointB, pointC));
            perimeter.Add(app.NewLineBound(pointC, pointD));
            perimeter.Add(app.NewLineBound(pointD, pointA));

            List <CurveLoop> boxPerimeterList = new List <CurveLoop>();

            boxPerimeterList.Add(CurveLoop.Create(perimeter));
            Solid intersectionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boxPerimeterList, XYZ.BasisZ, boundDifference);

            // cycle through the elements in solidsList and intersect them against intersectionSolid to create a new list
            List <Solid> clippedSolidsList = new List <Solid>();
            Solid        currSolid;

            foreach (Solid solid in solidsList)
            {
                currSolid = BooleanOperationsUtils.ExecuteBooleanOperation(solid, intersectionSolid, BooleanOperationsType.Intersect);
                if (currSolid != null && currSolid.Volume != 0)
                {
                    clippedSolidsList.Add(currSolid);
                }
            }
            solidsList = clippedSolidsList;
        }
예제 #10
0
        /// <summary>
        /// Execute a Boolean operation, and catch the exception.
        /// </summary>
        /// <param name="id">The id of the object demanding the Boolean operation.</param>
        /// <param name="secondId">The id of the object providing the second solid.</param>
        /// <param name="firstSolid">The first solid parameter to ExecuteBooleanOperation.</param>
        /// <param name="secondSolid">The second solid parameter to ExecuteBooleanOperation.</param>
        /// <param name="opType">The Boolean operation type.</param>
        /// <param name="suggestedShiftDirection">If the Boolean operation fails, a unit vector used to retry with a small shift.  Can be null.</param>
        /// <returns>The result of the Boolean operation, or the first solid if the operation fails.</returns>
        public static Solid ExecuteSafeBooleanOperation(int id, int secondId, Solid firstSolid, Solid secondSolid, BooleanOperationsType opType, XYZ suggestedShiftDirection)
        {
            const double footToMillimeter = 1.0 / 304.8;

            // Perform default operations if one of the arguments is null.
            if (firstSolid == null || secondSolid == null)
            {
                if (firstSolid == null && secondSolid == null)
                {
                    return(null);
                }

                switch (opType)
                {
                case BooleanOperationsType.Union:
                {
                    if (firstSolid == null)
                    {
                        return(secondSolid);
                    }

                    return(firstSolid);
                }

                case BooleanOperationsType.Difference:
                {
                    if (firstSolid == null)
                    {
                        return(null);
                    }

                    return(firstSolid);
                }

                default:
                    // for .Intersect
                    return(null);
                }
            }

            Solid resultSolid       = null;
            bool  failedAllAttempts = true;

            // We will attempt to do the Boolean operation here.
            // In the first pass, we will try to do the Boolean operation as-is.
            // For subsequent passes, we will shift the second operand by a small distance in
            // a given direction, using the following formula:
            // We start with a 1mm shift, and try each of (up to 4) shift directions given by
            // the shiftDirections list below, in alternating positive and negative directions.
            // In none of these succeed, we will increment the distance by 1mm and try again
            // until we reach numPasses.
            // Boolean operations are expensive, and as such we want to limit the number of
            // attempts we make here to balance fidelity and performance.  Initial experimentation
            // suggests that a maximum 3mm shift is a good first start for this balance.
            IList <XYZ> shiftDirections = new List <XYZ>()
            {
                suggestedShiftDirection,
                XYZ.BasisZ,
                XYZ.BasisX,
                XYZ.BasisY
            };

            const int numberOfNudges     = 4;
            const int numPasses          = numberOfNudges * 8 + 1; // 1 base, 8 possible nudges up to 0.75mm.
            double    currentShiftFactor = 0.0;

            for (int ii = 0; ii < numPasses; ii++)
            {
                try
                {
                    resultSolid = null;

                    Solid secondOperand = secondSolid;
                    if (ii > 0)
                    {
                        int shiftDirectionIndex = (ii - 1) % 4;
                        XYZ shiftDirectionToUse = shiftDirections[shiftDirectionIndex];
                        if (shiftDirectionToUse == null)
                        {
                            continue;
                        }

                        // ((ii + 3) >> 3) * 0.25mm shift.  Basically, a 0.25mm shift for every 8 attempts.
                        currentShiftFactor = ((ii + 1) >> 3) * 0.25;
                        int       posOrNegDirection = (ii % 2 == 1) ? 1 : -1;
                        double    scale             = currentShiftFactor * posOrNegDirection * footToMillimeter;
                        Transform secondSolidShift  = Transform.CreateTranslation(scale * shiftDirectionToUse);
                        secondOperand = SolidUtils.CreateTransformed(secondOperand, secondSolidShift);
                    }

                    resultSolid       = BooleanOperationsUtils.ExecuteBooleanOperation(firstSolid, secondOperand, opType);
                    failedAllAttempts = false;
                }
                catch (Exception ex)
                {
                    string msg = ex.Message;

                    // This is the only error that we are trying to catch and fix.
                    // For any other error, we will re-throw.
                    if (!msg.Contains("Failed to perform the Boolean operation for the two solids"))
                    {
                        throw ex;
                    }

                    if (ii < numPasses - 1)
                    {
                        continue;
                    }

                    Importer.TheLog.LogError(id, msg, false);
                    resultSolid = firstSolid;
                }

                if (SolidValidator.IsValidGeometry(resultSolid))
                {
                    // If we got here not on out first attempt, generate a warning, unless we got here because we gave up on our 3rd attempt.
                    if (ii > 0 && !failedAllAttempts)
                    {
                        Importer.TheLog.LogWarning(id, "The second argument in the Boolean " +
                                                   opType.ToString() +
                                                   " operation was shifted by " + currentShiftFactor +
                                                   "mm to allow the operation to succeed.  This may result in a very small difference in appearance.", false);
                    }
                    return(resultSolid);
                }
            }

            Importer.TheLog.LogError(id, opType.ToString() + " operation failed with void from #" + secondId.ToString(), false);
            return(firstSolid);
        }
예제 #11
0
        /// <summary>
        /// Retrieve all plan view boundary loops from
        /// all solids of the given element geometry
        /// united together.
        /// </summary>
        internal static JtLoops GetPlanViewBoundaryLoopsGeo(
            Autodesk.Revit.Creation.Application creapp,
            GeometryElement geo,
            ref int nFailures)
        {
            Solid union = null;

            Plane plane = Plane.CreateByOriginAndBasis(
                XYZ.Zero, XYZ.BasisX, XYZ.BasisY);

            foreach (GeometryObject obj in geo)
            {
                Solid solid = obj as Solid;

                if (null != solid &&
                    0 < solid.Faces.Size)
                {
                    // Some solids, e.g. in the standard
                    // content 'Furniture Chair - Office'
                    // cause an extrusion analyser failure,
                    // so skip adding those.

                    try
                    {
                        ExtrusionAnalyzer extrusionAnalyzer
                            = ExtrusionAnalyzer.Create(
                                  solid, plane, XYZ.BasisZ);
                    }
                    catch (Autodesk.Revit.Exceptions
                           .InvalidOperationException)
                    {
                        solid = null;
                        ++nFailures;
                    }

                    if (null != solid)
                    {
                        if (null == union)
                        {
                            union = solid;
                        }
                        else
                        {
                            try
                            {
                                union = BooleanOperationsUtils
                                        .ExecuteBooleanOperation(union, solid,
                                                                 BooleanOperationsType.Union);
                            }
                            catch (Autodesk.Revit.Exceptions
                                   .InvalidOperationException)
                            {
                                ++nFailures;
                            }
                        }
                    }
                }
            }

            JtLoops loops = new JtLoops(1);

            AddLoops(creapp, loops, union, ref nFailures);

            return(loops);
        }
예제 #12
0
        /// <summary>
        /// Gets the rectangular openings.
        /// </summary>
        /// <returns></returns>
        /// <remarks>This method uses walls, doors, windows and generic models bounding boxes to determine the rectangles.
        /// These objects can be in the host file or in linked Revit files.</remarks>
        public static IList <Autodesk.DesignScript.Geometry.Rectangle> GetRectangularOpenings()
        {
            Utils.Log(string.Format("OpeningUtils.GetRectangularOpenings started...", ""));

            Autodesk.Revit.DB.Document doc = DocumentManager.Instance.CurrentDBDocument;

            //look for Walls, Doors, Windows, Generic Models in the current document and in the linked documents
            ElementCategoryFilter wallFilter    = new ElementCategoryFilter(BuiltInCategory.OST_Walls);
            ElementCategoryFilter doorFilter    = new ElementCategoryFilter(BuiltInCategory.OST_Doors);
            ElementCategoryFilter windowFilter  = new ElementCategoryFilter(BuiltInCategory.OST_Windows);
            ElementCategoryFilter genericFilter = new ElementCategoryFilter(BuiltInCategory.OST_GenericModel);

            IList <ElementFilter> filterList = new List <ElementFilter>()
            {
                wallFilter, doorFilter, windowFilter, genericFilter
            };

            LogicalOrFilter orFilter = new LogicalOrFilter(filterList);

            IList <Autodesk.DesignScript.Geometry.Solid> solids = new List <Autodesk.DesignScript.Geometry.Solid>();

            IList <Autodesk.DesignScript.Geometry.Rectangle> output = new List <Autodesk.DesignScript.Geometry.Rectangle>();

            foreach (Autodesk.Revit.DB.Element e in new FilteredElementCollector(doc)
                     .WherePasses(orFilter)
                     .WhereElementIsNotElementType()
                     .Where(x =>
                            x.Parameters.Cast <Autodesk.Revit.DB.Parameter>()
                            .First(p => p.Id.IntegerValue == (int)BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS).HasValue))
            {
                string comments = e.Parameters.Cast <Autodesk.Revit.DB.Parameter>().First(p => p.Id.IntegerValue == (int)BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS).AsString();

                if (comments.ToLower() != "opening")
                {
                    continue;
                }

                Transform tr = Transform.Identity;

                if (e is Instance)
                {
                    Instance instance = e as Instance;
                    tr = instance.GetTotalTransform();
                }

                IList <Autodesk.Revit.DB.Solid> temp = new List <Autodesk.Revit.DB.Solid>();

                foreach (GeometryObject go in e.get_Geometry(new Options()))
                {
                    if (go is GeometryInstance)
                    {
                        GeometryInstance geoInstance = go as GeometryInstance;

                        foreach (var gi in geoInstance.SymbolGeometry)
                        {
                            if (gi is Autodesk.Revit.DB.Solid)
                            {
                                Autodesk.Revit.DB.Solid s = gi as Autodesk.Revit.DB.Solid;
                                s = SolidUtils.CreateTransformed(s, tr);
                                temp.Add(s);
                            }
                        }
                    }
                    else
                    {
                        if (go is Autodesk.Revit.DB.Solid)
                        {
                            Autodesk.Revit.DB.Solid s = go as Autodesk.Revit.DB.Solid;
                            s = SolidUtils.CreateTransformed(s, tr);
                            temp.Add(s);
                        }
                    }
                }

                if (temp.Count > 0)
                {
                    Autodesk.Revit.DB.Solid s0 = temp[0];
                    for (int i = 1; i < temp.Count; ++i)
                    {
                        s0 = BooleanOperationsUtils.ExecuteBooleanOperation(s0, temp[i], BooleanOperationsType.Union);
                    }

                    solids.Add(s0.ToProtoType());
                }
            }

            foreach (RevitLinkInstance rli in new FilteredElementCollector(doc).OfClass(typeof(RevitLinkInstance)).WhereElementIsNotElementType())
            {
                Autodesk.Revit.DB.Document link = rli.GetLinkDocument();

                foreach (Autodesk.Revit.DB.Element e in new FilteredElementCollector(link)
                         .WherePasses(orFilter)
                         .WhereElementIsNotElementType()
                         .Where(x =>
                                x.Parameters.Cast <Autodesk.Revit.DB.Parameter>()
                                .First(p => p.Id.IntegerValue == (int)BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS).HasValue))
                {
                    Transform tr = rli.GetTotalTransform();

                    string comments = e.Parameters.Cast <Autodesk.Revit.DB.Parameter>().First(p => p.Id.IntegerValue == (int)BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS).AsString();

                    if (comments.ToLower() != "opening")
                    {
                        continue;
                    }

                    if (e is Instance)
                    {
                        Instance instance = e as Instance;
                        tr = tr.Multiply(instance.GetTotalTransform());
                    }

                    IList <Autodesk.Revit.DB.Solid> temp = new List <Autodesk.Revit.DB.Solid>();

                    foreach (var go in e.get_Geometry(new Options()))
                    {
                        if (go is GeometryInstance)
                        {
                            GeometryInstance geoInstance = go as GeometryInstance;

                            foreach (var gi in geoInstance.SymbolGeometry)
                            {
                                if (gi is Autodesk.Revit.DB.Solid)
                                {
                                    Autodesk.Revit.DB.Solid s = gi as Autodesk.Revit.DB.Solid;
                                    s = SolidUtils.CreateTransformed(s, tr);
                                    temp.Add(s);
                                }
                            }
                        }
                        else
                        {
                            if (go is Autodesk.Revit.DB.Solid)
                            {
                                Autodesk.Revit.DB.Solid s = go as Autodesk.Revit.DB.Solid;
                                s = SolidUtils.CreateTransformed(s, tr);
                                temp.Add(s);
                            }
                        }
                    }

                    if (temp.Count > 0)
                    {
                        Autodesk.Revit.DB.Solid s0 = temp[0];
                        for (int i = 1; i < temp.Count; ++i)
                        {
                            s0 = BooleanOperationsUtils.ExecuteBooleanOperation(s0, temp[i], BooleanOperationsType.Union);
                        }

                        solids.Add(s0.ToProtoType());
                    }
                }
            }

            foreach (var s in solids)
            {
                IList <Autodesk.DesignScript.Geometry.Point> points = new List <Autodesk.DesignScript.Geometry.Point>();

                foreach (var v in s.Vertices)
                {
                    points.Add(v.PointGeometry);
                }

                points = Autodesk.DesignScript.Geometry.Point.PruneDuplicates(points);

                Autodesk.DesignScript.Geometry.Plane plane = Autodesk.DesignScript.Geometry.Plane.ByBestFitThroughPoints(points);

                plane = Autodesk.DesignScript.Geometry.Plane.ByOriginNormal(points.Last(), plane.Normal);

                IList <Autodesk.DesignScript.Geometry.Point> temp = new List <Autodesk.DesignScript.Geometry.Point>();

                foreach (var p in points)
                {
                    foreach (var q in p.Project(plane, plane.Normal))
                    {
                        temp.Add(q as Autodesk.DesignScript.Geometry.Point);
                    }

                    foreach (var q in p.Project(plane, plane.Normal.Reverse()))
                    {
                        temp.Add(q as Autodesk.DesignScript.Geometry.Point);
                    }
                }

                temp = Autodesk.DesignScript.Geometry.Point.PruneDuplicates(temp);

                CoordinateSystem cs = CoordinateSystem.ByPlane(plane);

                IList <Autodesk.DesignScript.Geometry.Point> relative = new List <Autodesk.DesignScript.Geometry.Point>();

                foreach (var p in temp)
                {
                    relative.Add(p.Transform(cs.Inverse()) as Autodesk.DesignScript.Geometry.Point);
                }

                var min = Autodesk.DesignScript.Geometry.Point.ByCoordinates(relative.Min(p => p.X),
                                                                             relative.Min(p => p.Y),
                                                                             relative.Min(p => p.Z));
                //.Transform(cs) as Autodesk.DesignScript.Geometry.Point;

                var max = Autodesk.DesignScript.Geometry.Point.ByCoordinates(relative.Max(p => p.X),
                                                                             relative.Max(p => p.Y),
                                                                             relative.Max(p => p.Z));
                //.Transform(cs) as Autodesk.DesignScript.Geometry.Point;

                double width  = max.X - min.X;
                double height = max.Y - min.Y;

                min = min.Transform(cs) as Autodesk.DesignScript.Geometry.Point;
                max = max.Transform(cs) as Autodesk.DesignScript.Geometry.Point;

                plane = Autodesk.DesignScript.Geometry.Plane.ByOriginNormal(Autodesk.DesignScript.Geometry.Line.ByStartPointEndPoint(min, max).PointAtParameter(0.5), plane.Normal);

                Autodesk.DesignScript.Geometry.Rectangle rectangle = Autodesk.DesignScript.Geometry.Rectangle.ByWidthLength(plane,
                                                                                                                            width,
                                                                                                                            height);

                output.Add(rectangle);

                plane.Dispose();
                cs.Dispose();
                min.Dispose();
                max.Dispose();
            }

            Utils.Log(string.Format("OpeningUtils.GetRectangularOpenings completed.", ""));

            return(output);
        }
예제 #13
0
        private void OnIdling(object sender, IdlingEventArgs e)
        {
            //var App = sender as Application;
            var docsInApp = App.Documents.Cast <Document>();
            var doc       = docsInApp.FirstOrDefault();
            var uidoc     = new UIDocument(doc);
            var uiapp     = uidoc.Application;

            try
            {
                var ActiveDoc = docsInApp.FirstOrDefault();

                if (ids_add.Count != 1)
                {
                    return;
                }

                var modelline = ids_add.First().GetElement(ActiveDoc) as ModelLine;
                var line      = modelline.GeometryCurve as Line;

                //MessageBox.Show(line.Length.ToString());

                var linedir = line.Direction;
                var startpo = line.StartPoint();
                var endpo   = line.EndPoint();

                var updir = XYZ.BasisZ;

                var leftNorm  = updir.CrossProduct(linedir).Normalize();
                var rightNorm = updir.CrossProduct(-linedir).Normalize();

                var leftspacePlane  = default(Plane); // Plane.CreateByNormalAndOrigin(leftNorm, startpo);
                var rightspacePlane = default(Plane); //Plane.CreateByNormalAndOrigin(rightNorm, startpo);

#if Revit2016
                leftspacePlane  = new Plane(leftNorm, startpo);
                rightspacePlane = new Plane(rightNorm, startpo);
#endif
#if Revit2019
                leftspacePlane  = Plane.CreateByNormalAndOrigin(leftNorm, startpo);
                rightspacePlane = Plane.CreateByNormalAndOrigin(rightNorm, startpo);
#endif



                //var slapshapeEditor = floor.SlabShapeEditor;
                //剪切楼板

                //var verticals = slapshapeEditor.SlabShapeVertices.Cast<XYZ>();
                //var upfaceRef = HostObjectUtils.GetTopFaces(floor);
                //var upface = floor.GetGeometryObjectFromReference(upfaceRef.FirstOrDefault());

                var geoele = floor.get_Geometry(new Options()
                {
                    ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine
                });

                var solid = geoele.Getsolids().FirstOrDefault();


                var newsolid1 = BooleanOperationsUtils.CutWithHalfSpace(solid, leftspacePlane);
                var newsolid2 = BooleanOperationsUtils.CutWithHalfSpace(solid, rightspacePlane);

                var upface1 = newsolid1.GetFacesOfGeometryObject().Where(m => m.ComputeNormal(new UV()).IsSameDirection(XYZ.BasisZ))
                              .FirstOrDefault();

                var upface2 = newsolid2.GetFacesOfGeometryObject().Where(m => m.ComputeNormal(new UV()).IsSameDirection(XYZ.BasisZ))
                              .FirstOrDefault();


                var curveloop1  = upface1.GetEdgesAsCurveLoops().FirstOrDefault();
                var curvearray1 = curveloop1.ToCurveArray();

                var curveloop2  = upface2.GetEdgesAsCurveLoops().FirstOrDefault();
                var curvearray2 = curveloop2.ToCurveArray();


                ActiveDoc.Invoke(m =>
                {
                    var newfloor1 = ActiveDoc.Create.NewFloor(curvearray1, floor.FloorType, floor.LevelId.GetElement(ActiveDoc) as Level, false);
                    var newfloor2 = ActiveDoc.Create.NewFloor(curvearray2, floor.FloorType,
                                                              floor.LevelId.GetElement(ActiveDoc) as Level, false);
                    doc.Delete(floor.Id);
                }, "newfloor");

                //var newfloor2 =
                //    ActiveDoc.Create.NewFloor(, floor.FloorType, floor.LevelId.GetElement(ActiveDoc) as Level, false);


                //slapshapeEditor.DrawSplitLine()
                if (this != null)
                {
                    uiapp.Idling -= OnIdling;
                }
            }
            catch (Exception e1)
            {
                MessageBox.Show(e1.ToString());
                uiapp.Idling -= OnIdling;
            }
        }
예제 #14
0
        /***************************************************/
        /****              Private Methods              ****/
        /***************************************************/

        private static List <ISurface> GetOpeningGeometry(Transaction t, Document doc, List <HostObject> hosts, List <ElementId> inserts, FamilyInstance familyInstance, RevitSettings settings = null)
        {
            List <List <Solid> > solidsWithOpening = new List <List <Solid> >();

            foreach (HostObject h in hosts)
            {
                solidsWithOpening.Add(h.Solids(new Options()).Select(x => SolidUtils.Clone(x)).ToList());
            }

            // Rollback and restart of the transaction is needed because otherwise the object, to which familyInstance is pointing can become invalidated.
            FailureHandlingOptions failureHandlingOptions = t.GetFailureHandlingOptions().SetClearAfterRollback(true);

            t.RollBack(failureHandlingOptions);
            t.Start();

            List <ISurface>  surfaces = new List <ISurface> ();
            List <CurveLoop> loops    = new List <CurveLoop>();

            try
            {
                doc.Delete(inserts);
                doc.Regenerate();

                for (int i = 0; i < hosts.Count; i++)
                {
                    HostObject h = hosts[i];

                    List <Autodesk.Revit.DB.Plane> planes = h.IPanelPlanes();
                    if (planes.Count == 0)
                    {
                        continue;
                    }

                    List <Solid> fullSolids = h.Solids(new Options()).SelectMany(x => SolidUtils.SplitVolumes(x)).ToList();
                    if (h is Wall)
                    {
                        fullSolids = fullSolids.Select(x => BooleanOperationsUtils.CutWithHalfSpace(x, planes[0])).ToList();
                        planes[0]  = Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(-planes[0].Normal, planes[0].Origin);
                    }

                    foreach (Solid s in fullSolids)
                    {
                        foreach (Solid s2 in solidsWithOpening[i])
                        {
                            BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(s, s2, BooleanOperationsType.Difference);
                        }

                        foreach (Autodesk.Revit.DB.Face f in s.Faces)
                        {
                            PlanarFace pf = f as PlanarFace;
                            if (pf == null)
                            {
                                continue;
                            }

                            if (planes.Any(x => Math.Abs(1 - pf.FaceNormal.DotProduct(x.Normal)) <= settings.DistanceTolerance && Math.Abs((pf.Origin - x.Origin).DotProduct(x.Normal)) <= settings.AngleTolerance))
                            {
                                loops.AddRange(pf.GetEdgesAsCurveLoops());
                            }
                        }
                    }
                }
            }
            catch
            {
                loops = null;
            }

            t.RollBack(failureHandlingOptions);

            if (loops != null)
            {
                surfaces.AddRange(loops.Select(x => new PlanarSurface(x.FromRevit(), null)));
            }
            else if (surfaces.Count != 0)
            {
                BH.Engine.Reflection.Compute.RecordWarning(String.Format("Geometrical processing of a Revit element failed due to an internal Revit error. Converted opening might be missing one or more of its surfaces. Revit ElementId: {0}", familyInstance.Id));
            }

            return(surfaces);
        }
예제 #15
0
 /// <summary>
 /// Boolean union geometric operation, return a new solid as the result
 /// </summary>
 /// <param name="solid1">Operation solid 1</param>
 /// <param name="solid2">Operation solid 2</param>
 /// <returns>The operation result</returns>
 public static Solid BooleanOperation_Union(Solid solid1, Solid solid2)
 {
     return(BooleanOperationsUtils.ExecuteBooleanOperation(solid1, solid2, BooleanOperationsType.Union));
 }
예제 #16
0
        /// <summary>
        /// This method takes the solidsList and clips all of its solids between the given range.
        /// </summary>
        /// <param name="elem">The Element from which we obtain our BoundingBoxXYZ.</param>
        /// <param name="geomElem">The top-level GeometryElement from which to gather X and Y
        /// coordinates for the intersecting solid.</param>
        /// <param name="range">The IFCRange whose Z values we use to create an intersecting
        /// solid to clip the solids in this class's internal solidsList.
        /// If range boundaries are equal, method returns, performing no clippings.</param>
        public void ClipSolidsList(GeometryElement geomElem, IFCRange range)
        {
            if (geomElem == null)
            {
                throw new ArgumentNullException("geomElemToUse");
            }

            if (MathUtil.IsAlmostEqual(range.Start, range.End) || SolidsCount() == 0)
            {
                return;
            }

            double bottomZ;
            double boundDifference;

            if (range.Start < range.End)
            {
                bottomZ         = range.Start;
                boundDifference = range.End - range.Start;
            }
            else
            {
                bottomZ         = range.End;
                boundDifference = range.Start - range.End;
            }

            // create a new solid using the X and Y of the bounding box on the top level GeometryElement and the Z of the IFCRange
            BoundingBoxXYZ elemBoundingBox = geomElem.GetBoundingBox();
            XYZ            pointA          = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ            pointB          = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Min.Y, bottomZ);
            XYZ            pointC          = new XYZ(elemBoundingBox.Max.X, elemBoundingBox.Max.Y, bottomZ);
            XYZ            pointD          = new XYZ(elemBoundingBox.Min.X, elemBoundingBox.Max.Y, bottomZ);

            List <Curve> perimeter = new List <Curve>();

            try
            {
                perimeter.Add(Line.CreateBound(pointA, pointB));
                perimeter.Add(Line.CreateBound(pointB, pointC));
                perimeter.Add(Line.CreateBound(pointC, pointD));
                perimeter.Add(Line.CreateBound(pointD, pointA));
            }
            catch
            {
                // One of the boundary lines was invalid.  Do nothing.
                return;
            }

            List <CurveLoop> boxPerimeterList = new List <CurveLoop>();

            boxPerimeterList.Add(CurveLoop.Create(perimeter));
            Solid intersectionSolid = GeometryCreationUtilities.CreateExtrusionGeometry(boxPerimeterList, XYZ.BasisZ, boundDifference);

            // cycle through the elements in solidsList and intersect them against intersectionSolid to create a new list
            List <SolidInfo> clippedSolidsList = new List <SolidInfo>();
            Solid            currSolid;

            foreach (SolidInfo solidAndElement in m_SolidInfoList)
            {
                Solid solid = solidAndElement.Solid;

                try
                {
                    // ExecuteBooleanOperation can throw if it fails.  In this case, just ignore the clipping.
                    currSolid = BooleanOperationsUtils.ExecuteBooleanOperation(solid, intersectionSolid, BooleanOperationsType.Intersect);
                    if (currSolid != null && currSolid.Volume != 0)
                    {
                        clippedSolidsList.Add(new SolidInfo(currSolid, solidAndElement.OwnerElement));
                    }
                }
                catch
                {
                    // unable to perform intersection, add original solid instead
                    clippedSolidsList.Add(solidAndElement);
                }
            }

            m_SolidInfoList = clippedSolidsList;
        }
예제 #17
0
 /// <summary>
 /// Boolean difference geometric operation, return a new solid as the result
 /// </summary>
 /// <param name="solid1">Operation solid 1</param>
 /// <param name="solid2">Operation solid 2</param>
 /// <returns>The operation result</returns>
 public static Solid BooleanOperation_Difference(Solid solid1, Solid solid2)
 {
     return(BooleanOperationsUtils.ExecuteBooleanOperation(solid1, solid2, BooleanOperationsType.Difference));
 }
예제 #18
0
        public double GetWallAsOpeningArea(
            Element elemOpening,
            Solid solidRoom)
        {
            Document doc = elemOpening.Document;

            Wall wallAsOpening = elemOpening as Wall; // most likely an embedded curtain wall

            Options options = doc.Application.Create.NewGeometryOptions();

            options.ComputeReferences        = true;
            options.IncludeNonVisibleObjects = true;

            List <Element> walls = new List <Element>();

            walls.Add(wallAsOpening);

            // To my recollection this won't
            // pick up an edited wall profile

            List <List <XYZ> > polygons = GetWallProfilePolygons(
                walls, options);

            IList <CurveLoop> solidProfile
                = XYZAsCurveloop(polygons.First());

            Solid solidOpening = GeometryCreationUtilities
                                 .CreateExtrusionGeometry(solidProfile,
                                                          wallAsOpening.Orientation, 1);

            Solid intersectSolid = BooleanOperationsUtils
                                   .ExecuteBooleanOperation(solidOpening,
                                                            solidRoom, BooleanOperationsType.Intersect);

            if (intersectSolid.Faces.Size.Equals(0))
            {
                // Then we are extruding in the wrong direction

                solidOpening = GeometryCreationUtilities
                               .CreateExtrusionGeometry(solidProfile,
                                                        wallAsOpening.Orientation.Negate(), 1);

                intersectSolid = BooleanOperationsUtils
                                 .ExecuteBooleanOperation(solidOpening,
                                                          solidRoom, BooleanOperationsType.Intersect);
            }

            if (DebugHandler.EnableSolidUtilityVolumes)
            {
                using (Transaction t = new Transaction(doc))
                {
                    t.Start("Test1");
                    ShapeCreator.CreateDirectShape(doc,
                                                   intersectSolid, "namesolid");
                    t.Commit();
                }
            }

            double openingArea = GetLargestFaceArea(
                intersectSolid);

            LogCreator.LogEntry(";_______OPENINGAREA;"
                                + elemOpening.Id.ToString() + ";"
                                + elemOpening.Category.Name + ";"
                                + elemOpening.Name + ";"
                                + (openingArea * 0.09290304).ToString());

            return(openingArea);
        }