diff --git a/.github/workflows/ci-beta.yml b/.github/workflows/ci-beta.yml
new file mode 100644
index 000000000..b7ade0268
--- /dev/null
+++ b/.github/workflows/ci-beta.yml
@@ -0,0 +1,138 @@
+# Beta-tier proxy, BHoM variant. Bundles the tier's checks plus
+# copyright-compliance (BHoM enforces OSS copyright; the BHE variant omits it).
+# Copy to .github/workflows/ci-beta.yml in each BHoM beta repo.
+# Runs on pull_request, non-blocking until a ruleset requires its checks.
+# Workflow name CI keeps check contexts bare: required contexts are the job names.
+
+name: CI
+
+on:
+ pull_request:
+ branches:
+ - develop
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
+ cancel-in-progress: true
+
+jobs:
+ ci-build:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 30
+ steps:
+ - name: Run build
+ uses: BHoM/CI_Toolkit/.github/actions/ci-build@develop
+ with:
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+
+ ci-code-compliance:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 20
+ permissions:
+ contents: read
+ pull-requests: read
+ actions: write
+ steps:
+ - name: Run code compliance
+ uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
+ with:
+ check_type: code
+ patterns: '*.cs'
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+
+ ci-copyright-compliance:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 20
+ permissions:
+ contents: read
+ pull-requests: read
+ actions: write
+ steps:
+ - name: Run copyright compliance
+ uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
+ with:
+ check_type: copyright
+ patterns: '*.cs'
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+
+ ci-dataset-compliance:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 20
+ permissions:
+ contents: read
+ pull-requests: read
+ actions: write
+ steps:
+ - name: Run dataset compliance
+ uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
+ with:
+ check_type: dataset
+ patterns: ':(icase)*datasets*.json'
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+
+ ci-documentation-compliance:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 20
+ permissions:
+ contents: read
+ pull-requests: read
+ actions: write
+ steps:
+ - name: Run documentation compliance
+ uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
+ with:
+ check_type: documentation
+ patterns: '*.cs'
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+
+ ci-project-compliance:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 20
+ permissions:
+ contents: read
+ pull-requests: read
+ actions: write
+ steps:
+ - name: Run project compliance
+ uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
+ with:
+ check_type: project
+ patterns: '*AssemblyInfo.cs *.csproj'
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+
+ ci-dataset-tests:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 30
+ steps:
+ - name: Run dataset tests
+ uses: BHoM/CI_Toolkit/.github/actions/ci-dataset-tests@develop
+ with:
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+
+ ci-serialisation:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 90
+ steps:
+ - name: Run serialisation
+ uses: BHoM/CI_Toolkit/.github/actions/ci-serialisation@develop
+ with:
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
+ base_ref: ${{ github.base_ref }}
+
+ ci-versioning:
+ runs-on: windows-2025-vs2026
+ timeout-minutes: 90
+ steps:
+ - name: Run versioning
+ uses: BHoM/CI_Toolkit/.github/actions/ci-versioning@develop
+ with:
+ app_id: ${{ secrets.BHOM_APP_ID }}
+ private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
diff --git a/README.md b/README.md
index 6afde4cb9..d5d548b16 100644
--- a/README.md
+++ b/README.md
@@ -8,12 +8,11 @@ A set of tools enabling exchange of information between BHoM and [Revit](https:/
- a set of utility methods supporting conversion and processing of Revit elements
### Known Versions of Software Supported
-Autodesk Revit 2018
-Autodesk Revit 2019
-Autodesk Revit 2020
-Autodesk Revit 2021
Autodesk Revit 2022
Autodesk Revit 2023
+Autodesk Revit 2024
+Autodesk Revit 2025
+Autodesk Revit 2026
### Documentation
For more information about functionality see [Revit_Toolkit Wiki](https://github.com/BHoM/Revit_Toolkit/wiki).
@@ -39,12 +38,11 @@ You will need the following to build Revit_Toolkit:
- [Socket_Toolkit](https://github.com/BHoM/Socket_Toolkit)
Revit_Toolkit needs to be built separately for each version of Revit. To switch between version and specific Revit_Toolkit configurations use Configuration Manager:
-Debug2018 -> Revit 2018
-Debug2019 -> Revit 2019
-Debug2020 -> Revit 2020
-Debug2021 -> Revit 2021
Debug2022 -> Revit 2022
Debug2023 -> Revit 2023
+Debug2024 -> Revit 2024
+Debug2025 -> Revit 2025
+Debug2026 -> Revit 2026
## Want to Contribute? ##
diff --git a/Revit_Adapter/Revit_Adapter.csproj b/Revit_Adapter/Revit_Adapter.csproj
index 622224a45..ca911de60 100644
--- a/Revit_Adapter/Revit_Adapter.csproj
+++ b/Revit_Adapter/Revit_Adapter.csproj
@@ -8,7 +8,7 @@
BHoM
Copyright © https://github.com/BHoM
BH.Adapter.Revit
- 9.2.0.0
+ 9.3.0.0
diff --git a/Revit_Core_Adapter/Revit_Core_Adapter.csproj b/Revit_Core_Adapter/Revit_Core_Adapter.csproj
index e9e2d9f5f..89fda04ba 100644
--- a/Revit_Core_Adapter/Revit_Core_Adapter.csproj
+++ b/Revit_Core_Adapter/Revit_Core_Adapter.csproj
@@ -7,7 +7,7 @@
BHoM
Copyright © https://github.com/BHoM
BH.Revit.Adapter.Core
- 9.2.0.0
+ 9.3.0.0
diff --git a/Revit_Core_Engine/Compute/GeneratePadFoundationType.cs b/Revit_Core_Engine/Compute/GeneratePadFoundationType.cs
index 8c708ce62..0ecbad7b5 100644
--- a/Revit_Core_Engine/Compute/GeneratePadFoundationType.cs
+++ b/Revit_Core_Engine/Compute/GeneratePadFoundationType.cs
@@ -165,7 +165,7 @@ private static FamilySymbol GenerateFreeformType(PadFoundation padFoundation, Do
{
List takenIndices = freeformFamilies.Select(x => Regex.Match(x.Name, $"{Regex.Escape(prefix)}(\\d+)$")).Select(x => int.Parse(x.Groups[1].Value)).ToList();
int newIndex = takenIndices.Count > 0 ? takenIndices.Max() + 1 : 1;
- family = GenerateFreeFormPadFamilyFromTemplate(document, orientedOutline, thickness, newIndex, padFoundation, settings);
+ family = GenerateFreeFormPadFamilyFromTemplate(document, orientedOutline, thickness, newIndex, settings);
}
if (family == null)
@@ -177,7 +177,7 @@ private static FamilySymbol GenerateFreeformType(PadFoundation padFoundation, Do
/***************************************************/
- private static Family GenerateFreeFormPadFamilyFromTemplate(this Document document, Polyline orientedOutline, double thickness, int index, PadFoundation padFoundation, RevitSettings settings = null)
+ private static Family GenerateFreeFormPadFamilyFromTemplate(this Document document, Polyline orientedOutline, double thickness, int index, RevitSettings settings = null)
{
string templateFamilyName = "StructuralFoundations_Pad-Freeform";
string templatePath = Directory.GetFiles(m_FamilyDirectory, $"*{templateFamilyName}.rfa").FirstOrDefault();
@@ -188,7 +188,7 @@ private static Family GenerateFreeFormPadFamilyFromTemplate(this Document docume
try
{
- if (!ReplaceFreeFormExtrusion(familyDocument, orientedOutline, padFoundation))
+ if (!ReplaceFreeFormExtrusion(familyDocument, orientedOutline, thickness))
return null;
return SaveAndLoadFamily(document, familyDocument, $"{Path.GetFileNameWithoutExtension(templatePath)}_{index}");
@@ -205,17 +205,8 @@ private static Family GenerateFreeFormPadFamilyFromTemplate(this Document docume
}
/***************************************************/
- private static double FreeformExtrusionDepth(PadFoundation padFoundation)
- {
- double depth = padFoundation.PadFoundationThickness();
- double h = double.IsNaN(depth) ? double.NaN : depth.FromSI(SpecTypeId.Length);
- if (double.IsNaN(h) || h <= 1e-6)
- h = 0.5.FromSI(SpecTypeId.Length);
- return h;
- }
- /***************************************************/
- private static bool ReplaceFreeFormExtrusion(Document familyDocument, Polyline orientedOutline, PadFoundation padFoundation)
+ private static bool ReplaceFreeFormExtrusion(Document familyDocument, Polyline orientedOutline, double thickness)
{
try
{
@@ -226,7 +217,7 @@ private static bool ReplaceFreeFormExtrusion(Document familyDocument, Polyline o
using (Transaction t = new Transaction(familyDocument, "Update Freeform Pad Foundation Footprint"))
{
t.Start();
- familyDocument.FamilyCreate.NewExtrusion(true, profile, extrusion.Sketch.SketchPlane, -FreeformExtrusionDepth(padFoundation));
+ familyDocument.FamilyCreate.NewExtrusion(true, profile, extrusion.Sketch.SketchPlane, -FreeformExtrusionDepth(thickness));
familyDocument.Delete(extrusion.Id);
t.Commit();
}
diff --git a/Revit_Core_Engine/Compute/GeneratePileFoundationType.cs b/Revit_Core_Engine/Compute/GeneratePileFoundationType.cs
new file mode 100644
index 000000000..7978ffd2b
--- /dev/null
+++ b/Revit_Core_Engine/Compute/GeneratePileFoundationType.cs
@@ -0,0 +1,395 @@
+/*
+ * This file is part of the Buildings and Habitats object Model (BHoM)
+ * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved.
+ *
+ * Each contributor holds copyright over their respective contributions.
+ * The project versioning (Git) records all such contribution source information.
+ *
+ *
+ * The BHoM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3.0 of the License, or
+ * (at your option) any later version.
+ *
+ * The BHoM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this code. If not, see .
+ */
+
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using BH.Engine.Adapters.Revit;
+using BH.Engine.Geometry;
+using BH.oM.Adapters.Revit.Settings;
+using BH.oM.Base.Attributes;
+using BH.oM.Geometry;
+using BH.oM.Physical.Elements;
+using BH.oM.Physical.FramingProperties;
+using BH.oM.Spatial.Layouts;
+using BH.oM.Spatial.ShapeProfiles;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Extrusion = Autodesk.Revit.DB.Extrusion;
+
+namespace BH.Revit.Engine.Core
+{
+ public static partial class Compute
+ {
+ /***************************************************/
+ /**** Public methods ****/
+ /***************************************************/
+
+ [Description("Generates a Revit FamilySymbol for a BHoM PileFoundation by querying existing freeform families in the document or creating a new one from a template file. Falls back to a pad foundation type when the input has no piles.")]
+ [Input("pileFoundation", "BHoM pile foundation to generate the Revit type for.")]
+ [Input("document", "Revit document, in which the family type will be created.")]
+ [Input("settings", "Settings to be used when generating the family type.")]
+ [Output("symbol", "Created Revit family type that represents the input BHoM pile foundation.")]
+ public static FamilySymbol GeneratePileFoundationType(this PileFoundation pileFoundation, Document document, RevitSettings settings = null)
+ {
+ settings = settings.DefaultIfNull();
+
+ if (pileFoundation?.PileCap == null)
+ return null;
+
+ if (pileFoundation.Piles == null || pileFoundation.Piles.Count == 0)
+ {
+ BH.Engine.Base.Compute.RecordWarning($"PileFoundation has no piles; generating a pad foundation type instead. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return pileFoundation.PileCap.GeneratePadFoundationType(document, settings);
+ }
+
+ return GenerateFreeformType(pileFoundation, document, settings);
+ }
+
+ /***************************************************/
+ /**** Private methods ****/
+ /***************************************************/
+
+ private static FamilySymbol GenerateFreeformType(PileFoundation pileFoundation, Document document, RevitSettings settings)
+ {
+ string prefix = "StructuralFoundations_PileFoundation-Freeform_";
+
+ // Get the outline and check if valid
+ Polyline outline = pileFoundation.PileCap.PadFoundationOutline();
+ if (outline?.IIsClosed() != true)
+ {
+ BH.Engine.Base.Compute.RecordError($"Pile foundation outline is invalid. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return null;
+ }
+
+ // Get the thickness and check if valid
+ double thickness = pileFoundation.PileCap.PadFoundationThickness();
+ if (double.IsNaN(thickness))
+ return null;
+
+ double pileDepth = pileFoundation.PileFoundationDepth(settings);
+ if (double.IsNaN(pileDepth))
+ {
+ BH.Engine.Base.Compute.RecordError($"Could not determine pile depth from cap soffit to pile tip. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return null;
+ }
+
+ // Get circular pile profiles and check if same diameter
+ List profiles = pileFoundation.Piles.Select(x => (x.Property as ConstantFramingProperty)?.Profile).OfType().ToList();
+
+ if (profiles.Count != pileFoundation.Piles.Count)
+ {
+ BH.Engine.Base.Compute.RecordError($"All piles must have a circular profile. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return null;
+ }
+
+ double tol = settings.DistanceTolerance;
+ double diameter = profiles[0].Diameter;
+ if (profiles.Any(p => Math.Abs(p.Diameter - diameter) > tol))
+ {
+ BH.Engine.Base.Compute.RecordError($"All piles must have the same diameter. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return null;
+ }
+
+ // Orient the outline to origin
+ Polyline orientedOutline = outline.OrientToOrigin();
+ if (orientedOutline == null)
+ return null;
+
+ // Get the pile layout and check if valid
+ ExplicitLayout layout = pileFoundation.PileFoundationLayout(settings);
+ if (layout?.Points == null || layout.Points.Count == 0)
+ {
+ BH.Engine.Base.Compute.RecordError($"Pile layout is invalid. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return null;
+ }
+
+ // Get all BHoM-generated freeform families in the document
+ List freeformFamilies = new FilteredElementCollector(document).OfClass(typeof(Family)).Cast()
+ .Where(x => Regex.IsMatch(x.Name, $"{prefix}\\d+$")).ToList();
+
+ Family family = freeformFamilies.FirstOrDefault(x => x.IsMatchingOutlineAndLayout(orientedOutline, layout, diameter, settings));
+ if (family == null)
+ {
+ List takenIndices = freeformFamilies.Select(x => Regex.Match(x.Name, $"{Regex.Escape(prefix)}(\\d+)$")).Select(x => int.Parse(x.Groups[1].Value)).ToList();
+ int newIndex = takenIndices.Count > 0 ? takenIndices.Max() + 1 : 1;
+ family = GenerateFreeFormPileFoundationFamilyFromTemplate(document, orientedOutline, layout, diameter, thickness, newIndex);
+ }
+
+ if (family == null)
+ return null;
+
+ return family.FindOrCreateTypeWithDimensions(thickness, diameter);
+ }
+
+ /***************************************************/
+
+ private static Family GenerateFreeFormPileFoundationFamilyFromTemplate(this Document document, Polyline orientedOutline, ExplicitLayout layout, double diameter, double thickness, int index)
+ {
+ string templateFamilyName = "StructuralFoundations_PileFoundation-Freeform";
+ string templatePath = Directory.GetFiles(m_FamilyDirectory, $"*{templateFamilyName}.rfa").FirstOrDefault();
+ if (string.IsNullOrEmpty(templatePath))
+ {
+ BH.Engine.Base.Compute.RecordError($"Pile foundation template '{templateFamilyName}.rfa' not found in {m_FamilyDirectory}.");
+ return null;
+ }
+
+ Document familyDocument = new UIDocument(document).Application.Application.OpenDocumentFile(templatePath);
+ if (familyDocument == null)
+ return null;
+
+ try
+ {
+ if (!ReplaceFreeFormExtrusionWithAssociate(familyDocument, orientedOutline, thickness))
+ return null;
+
+ if (!PlaceNestedPiles(familyDocument, layout, diameter))
+ return null;
+
+ return SaveAndLoadFamily(document, familyDocument, $"{Path.GetFileNameWithoutExtension(templatePath)}_{index}");
+ }
+ catch (Exception ex)
+ {
+ BH.Engine.Base.Compute.RecordError($"Creation of a freeform Revit pile foundation failed with the following error: {ex.Message}");
+ return null;
+ }
+ finally
+ {
+ familyDocument.Close(false);
+ }
+ }
+
+ /***************************************************/
+
+ private static double FreeformExtrusionDepth(double thickness)
+ {
+ double h = double.IsNaN(thickness) ? double.NaN : thickness.FromSI(SpecTypeId.Length);
+ if (double.IsNaN(h) || h <= 1e-6)
+ h = 0.5.FromSI(SpecTypeId.Length);
+ return h;
+ }
+
+ /***************************************************/
+
+ private static bool ReplaceFreeFormExtrusionWithAssociate(Document familyDocument, Polyline orientedOutline, double thickness)
+ {
+ try
+ {
+ if (!ReplaceFreeFormExtrusion(familyDocument, orientedOutline, thickness))
+ return false;
+
+ using (Transaction t = new Transaction(familyDocument, "Update Freeform Pile Foundation Footprint"))
+ {
+ Extrusion extrusion = new FilteredElementCollector(familyDocument).OfClass(typeof(Extrusion)).Cast().FirstOrDefault();
+ if (extrusion == null)
+ return false;
+
+ t.Start();
+
+ FamilyManager familyManager = familyDocument.FamilyManager;
+ Parameter oldStartParam = extrusion.get_Parameter(BuiltInParameter.EXTRUSION_START_PARAM);
+ FamilyParameter associatedStartParameter = oldStartParam != null
+ ? familyManager.GetAssociatedFamilyParameter(oldStartParam)
+ : null;
+
+ Parameter endParam = extrusion.get_Parameter(BuiltInParameter.EXTRUSION_END_PARAM);
+ if (endParam != null && !endParam.IsReadOnly)
+ endParam.Set(0.0);
+
+ if (associatedStartParameter != null)
+ {
+ Parameter newStartParam = extrusion.get_Parameter(BuiltInParameter.EXTRUSION_START_PARAM);
+ familyManager.AssociateElementParameterToFamilyParameter(newStartParam, associatedStartParameter);
+ }
+
+ t.Commit();
+ }
+
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ /***************************************************/
+
+ private static bool PlaceNestedPiles(Document familyDocument, ExplicitLayout layout, double diameter)
+ {
+ List templatePiles = new FilteredElementCollector(familyDocument).OfClass(typeof(FamilyInstance)).Cast().ToList();
+ if (templatePiles.Count == 0)
+ return false;
+
+ FamilyInstance templatePile = templatePiles[0];
+ XYZ pileOrigin = (templatePile.Location as LocationPoint)?.Point;
+ if (pileOrigin == null)
+ return false;
+
+ Extrusion templateVoidExtrusion = new FilteredElementCollector(familyDocument).OfClass(typeof(Extrusion)).Cast().Where(e => !e.IsSolid).OrderBy(e =>
+ {
+ BoundingBoxXYZ bbox = e.get_BoundingBox(null);
+ if (bbox == null)
+ return double.MaxValue;
+ XYZ c = (bbox.Min + bbox.Max) / 2.0;
+ return c.DistanceTo(new XYZ(pileOrigin.X, pileOrigin.Y, c.Z));
+ })
+ .FirstOrDefault();
+
+ try
+ {
+ using (Transaction t = new Transaction(familyDocument, "Place Nested Piles"))
+ {
+ t.Start();
+
+ FamilySymbol nestType = NestedPileSymbol(templatePile.Symbol, diameter);
+ if (nestType == null)
+ {
+ t.RollBack();
+ return false;
+ }
+
+ if (templatePiles.Count > 1)
+ familyDocument.Delete(templatePiles.Skip(1).Select(x => x.Id).ToList());
+
+ List placedPiles = new List();
+ List placedVoids = new List();
+
+ foreach (oM.Geometry.Point pt in layout.Points.Where(p => p != null))
+ {
+ double x = pt.X.FromSI(SpecTypeId.Length);
+ double y = pt.Y.FromSI(SpecTypeId.Length);
+ XYZ delta = new XYZ(x - pileOrigin.X, y - pileOrigin.Y, 0);
+
+ foreach (ElementId id in ElementTransformUtils.CopyElement(familyDocument, templatePile.Id, delta))
+ {
+ FamilyInstance copy = familyDocument.GetElement(id) as FamilyInstance;
+ if (copy != null)
+ placedPiles.Add(copy);
+ }
+
+ if (templateVoidExtrusion != null)
+ {
+ foreach (ElementId id in ElementTransformUtils.CopyElement(familyDocument, templateVoidExtrusion.Id, delta))
+ {
+ Extrusion copy = familyDocument.GetElement(id) as Extrusion;
+ if (copy != null)
+ placedVoids.Add(copy);
+ }
+ }
+ }
+
+ familyDocument.Delete(templatePile.Id);
+ if (templateVoidExtrusion != null)
+ familyDocument.Delete(templateVoidExtrusion.Id);
+
+ foreach (FamilyInstance pile in placedPiles)
+ {
+ if (pile.Symbol.Id != nestType.Id && pile.IsValidType(nestType.Id))
+ pile.ChangeTypeId(nestType.Id);
+ }
+
+ FamilyManager fm = familyDocument.FamilyManager;
+ FamilyParameter radiusParam = fm.get_Parameter("Radius");
+ if (radiusParam != null)
+ fm.Set(radiusParam, (diameter / 2.0).FromSI(SpecTypeId.Length));
+
+ Extrusion cap = new FilteredElementCollector(familyDocument).OfClass(typeof(Extrusion)).Cast().FirstOrDefault(e => e.IsSolid);
+ if (cap != null)
+ {
+ foreach (Extrusion voidExtrusion in placedVoids)
+ {
+ try
+ {
+ if (SolidSolidCutUtils.CanElementCutElement(cap, voidExtrusion, out _))
+ SolidSolidCutUtils.AddCutBetweenSolids(familyDocument, cap, voidExtrusion);
+ }
+ catch { }
+ }
+ }
+
+ t.Commit();
+ }
+ }
+ catch
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /***************************************************/
+
+ private static FamilySymbol NestedPileSymbol(FamilySymbol pileSymbol, double diameter)
+ {
+ if (pileSymbol == null || diameter <= 0)
+ return pileSymbol;
+
+ string typeName = $"Ø{(long)Math.Round(diameter * 1000.0)}";
+ FamilySymbol nestSymbol = pileSymbol.Family.GetFamilySymbolIds().Select(id => pileSymbol.Document.GetElement(id) as FamilySymbol).FirstOrDefault(s => s != null && s.Name.Equals(typeName, StringComparison.OrdinalIgnoreCase));
+
+ if (nestSymbol == null)
+ nestSymbol = pileSymbol.Duplicate(typeName) as FamilySymbol;
+
+ if (nestSymbol == null)
+ return null;
+
+ nestSymbol.SetParameter("Radius", diameter / 2.0);
+
+ if (!nestSymbol.IsActive)
+ nestSymbol.Activate();
+
+ return nestSymbol;
+ }
+
+ /***************************************************/
+
+ private static FamilySymbol FindOrCreateTypeWithDimensions(this Family family, double thickness, double diameter)
+ {
+ List symbols = family.GetFamilySymbolIds().Select(id => family.Document.GetElement(id) as FamilySymbol).Where(s => s != null).ToList();
+ if (symbols.Count == 0)
+ return null;
+
+ string typeName = $"{(long)Math.Round(thickness * 1000.0)}mm thk. Ø{(long)Math.Round(diameter * 1000.0)}";
+ FamilySymbol result = symbols.FirstOrDefault(x => x?.Name == typeName);
+ if (result == null && symbols.Count != 0)
+ {
+ result = symbols.FirstOrDefault(x => !(new FilteredElementCollector(family.Document).WherePasses(new FamilyInstanceFilter(family.Document, x.Id)).Any()));
+ if (result != null)
+ result.Name = typeName;
+ else
+ result = symbols[0].Duplicate(typeName) as FamilySymbol;
+
+ result.SetParameter("Depth", thickness);
+ }
+
+ result?.Activate();
+ return result;
+ }
+
+ /***************************************************/
+ }
+}
diff --git a/Revit_Core_Engine/Convert/Geometry/ToRevit/BoundingBoxXYZ.cs b/Revit_Core_Engine/Convert/Geometry/ToRevit/BoundingBoxXYZ.cs
new file mode 100644
index 000000000..48fc1b071
--- /dev/null
+++ b/Revit_Core_Engine/Convert/Geometry/ToRevit/BoundingBoxXYZ.cs
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Buildings and Habitats object Model (BHoM)
+ * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved.
+ *
+ * Each contributor holds copyright over their respective contributions.
+ * The project versioning (Git) records all such contribution source information.
+ *
+ *
+ * The BHoM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3.0 of the License, or
+ * (at your option) any later version.
+ *
+ * The BHoM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this code. If not, see .
+ */
+
+using Autodesk.Revit.DB;
+using BH.oM.Base.Attributes;
+using BH.oM.Geometry;
+using System.ComponentModel;
+
+namespace BH.Revit.Engine.Core
+{
+ public static partial class Convert
+ {
+ /***************************************************/
+ /**** Public methods ****/
+ /***************************************************/
+
+ [Description("Converts BH.oM.Geometry.BoundingBox to a Revit BoundingBoxXYZ.")]
+ [Input("boundingBox", "BH.oM.Geometry.BoundingBox to be converted.")]
+ [Output("boundingBoxXYZ", "Revit BoundingBoxXYZ resulting from converting the input BH.oM.Geometry.BoundingBox.")]
+ public static BoundingBoxXYZ ToRevit(this BoundingBox boundingBox)
+ {
+ BoundingBoxXYZ result = new BoundingBoxXYZ();
+ result.Enabled = true;
+ result.Min = boundingBox.Min.ToRevit();
+ result.Max = boundingBox.Max.ToRevit();
+ return result;
+ }
+
+ /***************************************************/
+ }
+}
+
+
+
+
+
+
diff --git a/Revit_Core_Engine/Convert/Physical/FromRevit/PileFoundation.cs b/Revit_Core_Engine/Convert/Physical/FromRevit/PileFoundation.cs
new file mode 100644
index 000000000..7b1f8b009
--- /dev/null
+++ b/Revit_Core_Engine/Convert/Physical/FromRevit/PileFoundation.cs
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the Buildings and Habitats object Model (BHoM)
+ * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved.
+ *
+ * Each contributor holds copyright over their respective contributions.
+ * The project versioning (Git) records all such contribution source information.
+ *
+ *
+ * The BHoM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3.0 of the License, or
+ * (at your option) any later version.
+ *
+ * The BHoM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this code. If not, see .
+ */
+
+using Autodesk.Revit.DB;
+using BH.Engine.Adapters.Revit;
+using BH.Engine.Geometry;
+using BH.oM.Adapters.Revit.Settings;
+using BH.oM.Base;
+using BH.oM.Base.Attributes;
+using BH.oM.Geometry;
+using BH.oM.Physical.Elements;
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace BH.Revit.Engine.Core
+{
+ public static partial class Convert
+ {
+ /***************************************************/
+ /**** Public Methods ****/
+ /***************************************************/
+
+ [Description("Converts a Revit FamilyInstance to BH.oM.Physical.Elements.PileFoundation.")]
+ [Input("familyInstance", "Revit FamilyInstance to be converted.")]
+ [Input("settings", "Revit adapter settings to be used while performing the convert.")]
+ [Input("refObjects", "Optional, a collection of objects already processed in the current adapter action, stored to avoid processing the same object more than once.")]
+ [Output("pileFoundation", "BH.oM.Physical.Elements.PileFoundation resulting from converting the input Revit FamilyInstance.")]
+ public static PileFoundation PileFoundationFromRevit(this FamilyInstance familyInstance, RevitSettings settings = null, Dictionary> refObjects = null)
+ {
+ settings = settings.DefaultIfNull();
+
+ PileFoundation pileFoundation = refObjects.GetValue(familyInstance.Id);
+ if (pileFoundation != null)
+ return pileFoundation;
+
+ PlanarSurface location = familyInstance.LocationSurfacePadFoundation(settings);
+ oM.Physical.Constructions.Construction construction = familyInstance.ConstructionPadFoundation(settings, refObjects);
+ PadFoundation pileCap = BH.Engine.Physical.Create.PadFoundation(location, construction, familyInstance.FamilyTypeFullName());
+
+ oM.Geometry.Plane padPlane = location.FitPlane();
+ List piles = new List();
+ foreach (ElementId pileId in familyInstance.GetSubComponentIds())
+ {
+ FamilyInstance pileInstance = familyInstance.Document.GetElement(pileId) as FamilyInstance;
+ Pile pile = pileInstance.PileFromRevit(settings, refObjects);
+
+ if (pile.Location is oM.Geometry.Line line)
+ line.End = line.End.ProjectAlong(padPlane, line.Direction());
+ else
+ BH.Engine.Base.Compute.RecordWarning($"Could not extend the pile to the top of the cap because the pile is not linear. ElementId: {familyInstance.Id.Value()}");
+
+ piles.Add(pile);
+ }
+
+ pileFoundation = BH.Engine.Physical.Create.PileFoundation(pileCap, piles, familyInstance.FamilyTypeFullName());
+
+ //Set identifiers, parameters & custom data
+ pileFoundation.SetIdentifiers(familyInstance);
+ pileFoundation.CopyParameters(familyInstance, settings.MappingSettings);
+ pileFoundation.SetProperties(familyInstance, settings.MappingSettings);
+
+ refObjects.AddOrReplace(familyInstance.Id, pileFoundation);
+ return pileFoundation;
+ }
+
+ /***************************************************/
+ }
+}
diff --git a/Revit_Core_Engine/Convert/Physical/ToRevit/FamilyInstance.cs b/Revit_Core_Engine/Convert/Physical/ToRevit/FamilyInstance.cs
index 167e8595f..e699e07fd 100644
--- a/Revit_Core_Engine/Convert/Physical/ToRevit/FamilyInstance.cs
+++ b/Revit_Core_Engine/Convert/Physical/ToRevit/FamilyInstance.cs
@@ -273,6 +273,61 @@ public static FamilyInstance ToRevitFamilyInstance(this PadFoundation padFoundat
/***************************************************/
+ [Description("Converts BH.oM.Physical.Elements.PileFoundation to a Revit FamilyInstance.")]
+ [Input("pileFoundation", "BH.oM.Physical.Elements.PileFoundation to be converted.")]
+ [Input("document", "Revit document, in which the output of the convert will be created.")]
+ [Input("settings", "Revit adapter settings to be used while performing the convert.")]
+ [Input("refObjects", "Optional, a collection of objects already processed in the current adapter action, stored to avoid processing the same object more than once.")]
+ [Output("instance", "Revit FamilyInstance resulting from converting the input BH.oM.Physical.Elements.PileFoundation.")]
+ public static FamilyInstance ToRevitFamilyInstance(this PileFoundation pileFoundation, Document document, RevitSettings settings = null, Dictionary> refObjects = null)
+ {
+ if (pileFoundation == null || document == null)
+ return null;
+
+ FamilyInstance familyInstance = refObjects.GetValue(document, pileFoundation.BHoM_Guid);
+ if (familyInstance != null)
+ return familyInstance;
+
+ settings = settings.DefaultIfNull();
+
+ if (pileFoundation.PileCap == null)
+ {
+ BH.Engine.Base.Compute.RecordError($"PileFoundation has no PileCap. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return null;
+ }
+
+ FamilySymbol familySymbol = pileFoundation.ElementType(document, settings) as FamilySymbol;
+ if (familySymbol == null)
+ {
+ Compute.ElementTypeNotFoundWarning(pileFoundation);
+ return null;
+ }
+
+ BH.oM.Geometry.Point origin = pileFoundation.PileCap.PadFoundationCentroid();
+
+ Level level = document.LevelAbove(origin.Z, settings);
+
+ familyInstance = document.Create.NewFamilyInstance(origin.ToRevit(), familySymbol, level, StructuralType.Footing);
+ document.Regenerate();
+
+ double pileDepth = pileFoundation.PileFoundationDepth(settings);
+ if (!double.IsNaN(pileDepth))
+ familyInstance.SetParameter("Pile Depth", pileDepth);
+
+ familyInstance.SetLocation(pileFoundation, settings);
+ refObjects.AddOrReplace(pileFoundation, familyInstance);
+
+ if (pileFoundation.Piles != null)
+ {
+ foreach (Pile pile in pileFoundation.Piles)
+ refObjects.AddOrReplace(pile, familyInstance);
+ }
+
+ return familyInstance;
+ }
+
+ /***************************************************/
+
[Description("Converts BH.oM.Physical.Elements.IFramingElement to a Revit FamilyInstance.")]
[Input("framingElement", "BH.oM.Physical.Elements.IFramingElement to be converted.")]
[Input("document", "Revit document, in which the output of the convert will be created.")]
diff --git a/Revit_Core_Engine/Convert/ToRevit.cs b/Revit_Core_Engine/Convert/ToRevit.cs
index d46d343b5..6d2821e9b 100644
--- a/Revit_Core_Engine/Convert/ToRevit.cs
+++ b/Revit_Core_Engine/Convert/ToRevit.cs
@@ -286,6 +286,19 @@ public static Element ToRevit(this BH.oM.Physical.Elements.PadFoundation foundat
/***************************************************/
+ [Description("Converts BH.oM.Physical.Elements.PileFoundation to a Revit FamilyInstance.")]
+ [Input("foundation", "BH.oM.Physical.Elements.PileFoundation to be converted.")]
+ [Input("document", "Revit document, in which the output of the convert will be created.")]
+ [Input("settings", "Revit adapter settings to be used while performing the convert.")]
+ [Input("refObjects", "Optional, a collection of objects already processed in the current adapter action, stored to avoid processing the same object more than once.")]
+ [Output("instance", "Revit FamilyInstance resulting from converting the input BH.oM.Physical.Elements.PileFoundation.")]
+ public static Element ToRevit(this BH.oM.Physical.Elements.PileFoundation foundation, Document document, RevitSettings settings = null, Dictionary> refObjects = null)
+ {
+ return foundation.ToRevitFamilyInstance(document, settings, refObjects);
+ }
+
+ /***************************************************/
+
[Description("Converts BH.oM.MEP.System.MaterialFragments.PipeMaterial to a Revit PipeSegment.")]
[Input("pipeMaterial", "BH.oM.MEP.System.MaterialFragments.PipeMaterial to be converted.")]
[Input("document", "Revit document, in which the output of the convert will be created.")]
diff --git a/Revit_Core_Engine/Create/View/ViewReflectedCeilingPlan.cs b/Revit_Core_Engine/Create/View/ViewReflectedCeilingPlan.cs
deleted file mode 100644
index af65ddc62..000000000
--- a/Revit_Core_Engine/Create/View/ViewReflectedCeilingPlan.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is part of the Buildings and Habitats object Model (BHoM)
- * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved.
- *
- * Each contributor holds copyright over their respective contributions.
- * The project versioning (Git) records all such contribution source information.
- *
- *
- * The BHoM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3.0 of the License, or
- * (at your option) any later version.
- *
- * The BHoM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this code. If not, see .
- */
-
-using Autodesk.Revit.DB;
-using System;
-using System.ComponentModel;
-using BH.oM.Base.Attributes;
-
-namespace BH.Revit.Engine.Core
-{
- public static partial class Create
- {
- /***************************************************/
- /**** Public Methods ****/
- /***************************************************/
-
- [ToBeRemoved("6.1", "Calls to this method are to be replaced with Create.ViewPlan with 'viewFamily' parameter equal to ViewFamily.CeilingPlan.")]
- [Description("Creates and returns a new Reflected Ceiling Plan view in the current Revit file.")]
- [Input("document", "Revit current document to be processed.")]
- [Input("level", "The level that the created Floor Plan refers to.")]
- [Input("viewName", "Optional, name of the new view.")]
- [Input("cropBox", "Optional, the crop region to attempt to apply to the newly created view.")]
- [Input("viewTemplateId", "Optional, the View Template Id to be applied in the view.")]
- [Input("viewDetailLevel", "Optional, the Detail Level of the view.")]
- [Output("viewReflectedCeilingPlan", "The new view.")]
- public static View ViewReflectedCeilingPlan(this Document document, Level level, string viewName = null, CurveLoop cropBox = null, ElementId viewTemplateId = null, ViewDetailLevel viewDetailLevel = ViewDetailLevel.Coarse)
- {
- View newView = null;
-
- ViewFamilyType viewFamilyType = Query.ViewFamilyType(document, ViewFamily.CeilingPlan);
-
- newView = Autodesk.Revit.DB.ViewPlan.Create(document, viewFamilyType.Id, level.Id);
-
- Modify.SetViewDetailLevel(newView, viewDetailLevel);
-
- if (cropBox != null)
- {
- try
- {
- ViewCropRegionShapeManager vcrShapeMgr = newView.GetCropRegionShapeManager();
- newView.CropBoxVisible = true;
- vcrShapeMgr.SetCropShape(cropBox);
- }
- catch (Exception)
- {
- BH.Engine.Base.Compute.RecordWarning("Could not create the Reflected Ceiling Plan with the provided crop box. Check if the crop box is a valid geometry.");
- }
- }
-
- newView.SetViewTemplate(viewTemplateId);
-
- if (!string.IsNullOrEmpty(viewName))
- {
- newView.SetViewName(viewName);
- }
-
- return newView;
- }
-
- /***************************************************/
- }
-}
-
-
-
-
-
diff --git a/Revit_Core_Engine/Files/Families/StructuralFoundations_PileFoundation-Freeform.rfa b/Revit_Core_Engine/Files/Families/StructuralFoundations_PileFoundation-Freeform.rfa
new file mode 100644
index 000000000..8f06370fc
Binary files /dev/null and b/Revit_Core_Engine/Files/Families/StructuralFoundations_PileFoundation-Freeform.rfa differ
diff --git a/Revit_Core_Engine/Modify/SetLocation.cs b/Revit_Core_Engine/Modify/SetLocation.cs
index ffa2f7af1..87c9c1473 100644
--- a/Revit_Core_Engine/Modify/SetLocation.cs
+++ b/Revit_Core_Engine/Modify/SetLocation.cs
@@ -345,6 +345,20 @@ public static bool SetLocation(this FamilyInstance element, Pile pile, RevitSett
/***************************************************/
+ [Description("Sets the location of a given Revit FamilyInstance based on a given BHoM PileFoundation.")]
+ [Input("element", "Revit FamilyInstance to be modified.")]
+ [Input("pileFoundation", "BHoM PileFoundation acting as a source of information about the new location.")]
+ [Input("settings", "Revit adapter settings to be used while performing the operation.")]
+ [Output("success", "True if location of the input Revit FamilyInstance has been successfully set.")]
+ public static bool SetLocation(this FamilyInstance element, PileFoundation pileFoundation, RevitSettings settings)
+ {
+ if (element == null || pileFoundation?.PileCap == null)
+ return false;
+ return element.SetLocation(pileFoundation.PileCap, settings);
+ }
+
+ /***************************************************/
+
[Description("Sets the location of a given Revit FamilyInstance based on a given BHoM PadFoundation.")]
[Input("element", "Revit FamilyInstance to be modified.")]
[Input("padFoundation", "BHoM PadFoundation acting as a source of information about the new location.")]
@@ -939,7 +953,7 @@ private static bool SetLocation(this FamilyInstance element, BH.oM.Geometry.Poin
return success;
}
-
+
/***************************************************/
private static bool UpdateRotationOfVerticalElement(this FamilyInstance element, IFramingElement bhomElement, RevitSettings settings)
{
diff --git a/Revit_Core_Engine/Modify/Update.cs b/Revit_Core_Engine/Modify/Update.cs
index 04b1709fe..cb99a2718 100644
--- a/Revit_Core_Engine/Modify/Update.cs
+++ b/Revit_Core_Engine/Modify/Update.cs
@@ -173,6 +173,27 @@ public static bool Update(this FamilyInstance element, PadFoundation bHoMObject,
/***************************************************/
+ [Description("Updates a Revit pile foundation FamilyInstance from the BHoM PileFoundation using the standard element update, then sets instance Pile Depth.")]
+ [Input("element", "Revit FamilyInstance representing the pile foundation to update.")]
+ [Input("bHoMObject", "BHoM PileFoundation whose properties (and optionally location) should be applied to the Revit instance.")]
+ [Input("settings", "Revit adapter settings used for the underlying element update.")]
+ [Input("setLocationOnUpdate", "If false, only parameters and properties are updated; if true, the instance location is updated as well.")]
+ [Output("success", "True if the underlying Element.Update succeeded.")]
+ public static bool Update(this FamilyInstance element, PileFoundation bHoMObject, RevitSettings settings, bool setLocationOnUpdate)
+ {
+ settings = settings.DefaultIfNull();
+
+ bool result = ((Element)element).Update((IBHoMObject)bHoMObject, settings, setLocationOnUpdate);
+
+ double pileDepth = bHoMObject.PileFoundationDepth(settings);
+ if (!double.IsNaN(pileDepth))
+ element.SetParameter("Pile Depth", pileDepth);
+
+ return result;
+ }
+
+ /***************************************************/
+
[Description("Updates the existing Revit FamilyInstance based on the given BHoM builders work Opening.")]
[Input("element", "Revit FamilyInstance to be updated.")]
[Input("bHoMObject", "BHoM builders work Opening, based on which the Revit element will be updated.")]
diff --git a/Revit_Core_Engine/Query/BHoMType.cs b/Revit_Core_Engine/Query/BHoMType.cs
index c42b3298e..e266e3811 100644
--- a/Revit_Core_Engine/Query/BHoMType.cs
+++ b/Revit_Core_Engine/Query/BHoMType.cs
@@ -92,14 +92,13 @@ public static Type BHoMType(this FamilyInstance familyInstance, Discipline disci
case Discipline.Architecture:
if (category == Autodesk.Revit.DB.BuiltInCategory.OST_StructuralFoundation)
{
- BoundingBoxXYZ bbox = familyInstance.get_BoundingBox(null);
+ BoundingBoxXYZ bbox = familyInstance.PhysicalBounds();
double width = Math.Max(bbox.Max.X - bbox.Min.X, bbox.Max.Y - bbox.Min.Y);
double height = bbox.Max.Z - bbox.Min.Z;
- if (height < width)
+ if (familyInstance.GetSubComponentIds().Count != 0)
+ return typeof(BH.oM.Physical.Elements.PileFoundation);
+ else if (height < width)
return typeof(BH.oM.Physical.Elements.PadFoundation);
- else if (familyInstance.GetSubComponentIds().Count != 0)
- //return typeof(BH.oM.Physical.Elements.PileFoundation);
- return null; // Temporarily disabled until PileFoundation is properly implemented in the Revit adapter.
else
return typeof(BH.oM.Physical.Elements.Pile);
}
diff --git a/Revit_Core_Engine/Query/Connectors.cs b/Revit_Core_Engine/Query/Connectors.cs
index 280c06e41..c697c794b 100644
--- a/Revit_Core_Engine/Query/Connectors.cs
+++ b/Revit_Core_Engine/Query/Connectors.cs
@@ -58,7 +58,12 @@ private static List SortedConnectors(this MEPCurve mepCurve)
foreach (Connector conn in connSet)
connList.Add(conn);
- connList = connList.OrderBy(x => x.Origin.DistanceTo(startPoint)).ToList();
+ // Order by distance from the start point. Logical connectors have no Origin, so they are sorted to the end rather than crashing the query.
+ connList = connList.OrderBy(x =>
+ {
+ try { return x.Origin.DistanceTo(startPoint); }
+ catch { return double.MaxValue; }
+ }).ToList();
return connList;
}
diff --git a/Revit_Core_Engine/Query/ElementIds/ElementIdsByBHoMType.cs b/Revit_Core_Engine/Query/ElementIds/ElementIdsByBHoMType.cs
index a9514cdbb..c7ae58f1e 100644
--- a/Revit_Core_Engine/Query/ElementIds/ElementIdsByBHoMType.cs
+++ b/Revit_Core_Engine/Query/ElementIds/ElementIdsByBHoMType.cs
@@ -27,10 +27,10 @@
using BH.oM.Adapters.Revit.Properties;
using BH.oM.Adapters.Revit.Settings;
using BH.oM.Base;
+using BH.oM.Base.Attributes;
using BH.oM.Physical.Elements;
using BH.oM.Physical.FramingProperties;
using BH.oM.Physical.Materials;
-using BH.oM.Base.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -109,7 +109,7 @@ public static IEnumerable ElementIdsByBHoMType(this Document document
else
unsupportedAPITypes.Add(new Tuple(t, t.SupportedAPIType()));
}
-
+
elementIds.UnionWith(collector.WherePasses(new LogicalOrFilter(filters)).ToElementIds());
foreach (Tuple unsupportedAPIType in unsupportedAPITypes)
{
@@ -127,6 +127,10 @@ public static IEnumerable ElementIdsByBHoMType(this Document document
if (types.Any(x => typeof(Autodesk.Revit.DB.Wall).IsAssignableFrom(x)))
elementIds = elementIds.RemoveStackedWallParts(document);
+ // Filter out pile sub-components that are nested
+ if (type == typeof(Pile))
+ elementIds = new HashSet(elementIds.Select(x => (document.GetElement(x) as FamilyInstance)).Where(x => x.SuperComponent == null).Select(x => x.Id));
+
//Revit returns additional "parent" Autodesk.Revit.DB.Panel with no geometry when pulling all panels from model. This part of the code filter them out
if (type == typeof(Window))
elementIds = elementIds.RemoveEmptyPanelIds(document);
diff --git a/Revit_Core_Engine/Query/ElementType.cs b/Revit_Core_Engine/Query/ElementType.cs
index 48be1da8b..12533b2d3 100644
--- a/Revit_Core_Engine/Query/ElementType.cs
+++ b/Revit_Core_Engine/Query/ElementType.cs
@@ -99,6 +99,27 @@ public static FamilySymbol ElementType(this BH.oM.Physical.Elements.PadFoundatio
/***************************************************/
+ [Description("Returns the Revit FamilySymbol to use when converting a BHoM PileFoundation.")]
+ [Input("pileFoundation", "BHoM pile foundation to find or generate a correspondent Revit family type for.")]
+ [Input("document", "Revit document to search for the element type or host generated types.")]
+ [Input("settings", "Revit adapter settings to be used while performing the query.")]
+ [Output("familySymbol", "Revit FamilySymbol to be used when converting the input pile foundation to Revit.")]
+ public static FamilySymbol ElementType(this BH.oM.Physical.Elements.PileFoundation pileFoundation, Document document, RevitSettings settings = null)
+ {
+ FamilySymbol result = pileFoundation.GeneratePileFoundationType(document, settings);
+ pileFoundation.FamilyAndTypeNames(out string familyName, out string familyTypeName);
+
+ if (!string.IsNullOrWhiteSpace(familyName) && result.FamilyName != familyName)
+ BH.Engine.Base.Compute.RecordWarning($"BHoM PileFoundation's name does not match Revit family name derived from its geometry. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+
+ if (!string.IsNullOrWhiteSpace(familyTypeName) && result.Name != familyTypeName)
+ BH.Engine.Base.Compute.RecordWarning($"BHoM PileFoundation's name does not match Revit type name derived from its geometry. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+
+ return result;
+ }
+
+ /***************************************************/
+
[Description("Returns the Revit element type to be used when converting a given BHoM IInstance to Revit.")]
[Input("instance", "BHoM IInstance to find a correspondent Revit element type for.")]
[Input("document", "Revit document to parse in search for the element type.")]
diff --git a/Revit_Core_Engine/Query/IsMatchingOutlineAndLayout.cs b/Revit_Core_Engine/Query/IsMatchingOutlineAndLayout.cs
new file mode 100644
index 000000000..221778669
--- /dev/null
+++ b/Revit_Core_Engine/Query/IsMatchingOutlineAndLayout.cs
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the Buildings and Habitats object Model (BHoM)
+ * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved.
+ *
+ * Each contributor holds copyright over their respective contributions.
+ * The project versioning (Git) records all such contribution source information.
+ *
+ *
+ * The BHoM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3.0 of the License, or
+ * (at your option) any later version.
+ *
+ * The BHoM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this code. If not, see .
+ */
+
+using Autodesk.Revit.DB;
+using BH.Engine.Adapters.Revit;
+using BH.Engine.Geometry;
+using BH.oM.Adapters.Revit.Settings;
+using BH.oM.Base.Attributes;
+using BH.oM.Geometry;
+using BH.oM.Spatial.Layouts;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+
+namespace BH.Revit.Engine.Core
+{
+ public static partial class Query
+ {
+ /***************************************************/
+ /**** Public methods ****/
+ /***************************************************/
+
+ [Description("Checks whether a pile foundation family matches the pile-cap outline, pile layout and pile diameter.")]
+ [Input("family", "Revit pile foundation family to compare.")]
+ [Input("orientedOutline", "Oriented pile-cap outline.")]
+ [Input("layout", "Explicit pile layout points.")]
+ [Input("diameter", "Pile diameter to match against the family.")]
+ [Input("settings", "Revit adapter settings.")]
+ [Output("matches", "True if outline, layout and diameter all match.")]
+ public static bool IsMatchingOutlineAndLayout(this Family family, Polyline orientedOutline, ExplicitLayout layout, double diameter, RevitSettings settings)
+ {
+ if (family == null || orientedOutline == null || layout?.Points == null || diameter <= 0)
+ return false;
+
+ settings = settings.DefaultIfNull();
+ double tol = settings.DistanceTolerance;
+
+ if (!family.IsMatchingOutline(orientedOutline, settings))
+ return false;
+
+ if (!family.IsMatchingPileLayout(layout, tol))
+ return false;
+
+ if (!family.IsMatchingPileDiameter(diameter, tol))
+ return false;
+
+ return true;
+ }
+
+ /***************************************************/
+ /**** Private methods ****/
+ /***************************************************/
+
+ private static bool IsMatchingPileLayout(this Family family, ExplicitLayout layout, double tol)
+ {
+ List familyPilePoints = family.PileLayoutPoints();
+ if (familyPilePoints == null || familyPilePoints.Count != layout.Points.Count)
+ return false;
+
+ foreach (oM.Geometry.Point layoutPt in layout.Points)
+ {
+ oM.Geometry.Point xy = new oM.Geometry.Point { X = layoutPt.X, Y = layoutPt.Y, Z = 0 };
+ if (!familyPilePoints.Any(fp => fp.Distance(xy) <= tol))
+ return false;
+ }
+
+ return true;
+ }
+
+ /***************************************************/
+
+ private static bool IsMatchingPileDiameter(this Family family, double diameter, double tol)
+ {
+ Document doc = family.Document;
+ FamilyInstance host = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).Cast().FirstOrDefault(fi => fi.Symbol?.Family?.Id == family.Id);
+ if (host == null)
+ return false;
+ FamilyInstance nest = host.GetSubComponentIds().Select(id => doc.GetElement(id) as FamilyInstance).FirstOrDefault(fi => fi != null);
+ FamilySymbol nestSymbol = nest?.Symbol;
+ if (nestSymbol == null)
+ return false;
+ double radius = nestSymbol.LookupParameterDouble("Radius");
+ if (!double.IsNaN(radius))
+ return Math.Abs(radius * 2.0 - diameter) <= tol;
+ double nestDiameter = nestSymbol.LookupParameterDouble("Diameter");
+ if (!double.IsNaN(nestDiameter))
+ return Math.Abs(nestDiameter - diameter) <= tol;
+ return false;
+ }
+
+ /***************************************************/
+
+ private static List PileLayoutPoints(this Family family)
+ {
+ Document doc = family.Document;
+
+ FamilyInstance host = new FilteredElementCollector(doc)
+ .OfClass(typeof(FamilyInstance))
+ .Cast()
+ .FirstOrDefault(fi => fi.Symbol?.Family?.Id == family.Id);
+
+ if (host == null)
+ return null;
+
+ Transform toFamily = host.GetTotalTransform().Inverse;
+ List points = new List();
+
+ foreach (ElementId id in host.GetSubComponentIds())
+ {
+ FamilyInstance nest = doc.GetElement(id) as FamilyInstance;
+ XYZ projectPt = (nest?.Location as LocationPoint)?.Point;
+ if (projectPt == null)
+ continue;
+
+ XYZ local = toFamily.OfPoint(projectPt);
+ oM.Geometry.Point p = local.PointFromRevit();
+ points.Add(new oM.Geometry.Point { X = p.X, Y = p.Y, Z = 0 });
+ }
+
+ return points.Count > 0 ? points : null;
+ }
+
+ /***************************************************/
+ }
+}
diff --git a/Revit_Core_Engine/Query/Level.cs b/Revit_Core_Engine/Query/Level.cs
index 48b3ae5c1..6db691dd9 100644
--- a/Revit_Core_Engine/Query/Level.cs
+++ b/Revit_Core_Engine/Query/Level.cs
@@ -42,24 +42,33 @@ public static Level Level(this Element element)
if (element == null)
return null;
+ Level level = null;
Document doc = element.Document;
ElementId levelId = element.LevelId;
// First priority: Check LevelId property (most direct way to get level)
if (levelId.Value() != -1)
- return doc.GetElement(levelId) as Level;
+ level = doc.GetElement(levelId) as Level;
+ if (level != null)
+ return level;
// Second priority: Check level parameters (LevelParameter or BaseLevelParameter)
Parameter levelParameter = element.LevelParameter() ?? element.BaseLevelParameter();
if (levelParameter != null)
- return doc.GetElement(levelParameter.AsElementId()) as Level;
+ level = doc.GetElement(levelParameter?.AsElementId()) as Level;
+ if (level != null)
+ return level;
// Third priority: Check if element is work plane-based and hosted on a level
if (element.IsWorkPlaneLevelBased())
- return (element as FamilyInstance)?.Host as Level;
+ level = (element as FamilyInstance)?.Host as Level;
+ if (level != null)
+ return level;
- // No level found
- return null;
+ // Fourth priority: Use the LevelBelow method to find the level below the element's location point
+ level = element.Document.LevelBelow(element.LocationPoint());
+
+ return level;
}
/***************************************************/
diff --git a/Revit_Core_Engine/Query/LevelParameter.cs b/Revit_Core_Engine/Query/LevelParameter.cs
index 6cffd7f3d..c49358d5a 100644
--- a/Revit_Core_Engine/Query/LevelParameter.cs
+++ b/Revit_Core_Engine/Query/LevelParameter.cs
@@ -35,7 +35,7 @@ public static partial class Query
[Description("Returns the element parameter that stores the level of the element. Checks multiple built-in level parameters in order of preference.")]
[Input("element", "Element to get the level parameter from.")]
- [Output("parameter", "Parameter that stores the level, or null if not found or parameter is read-only.")]
+ [Output("parameter", "Level parameter of the element, or null if not found.")]
public static Parameter LevelParameter(this Element element)
{
if (element == null)
@@ -45,14 +45,15 @@ public static Parameter LevelParameter(this Element element)
.Select(x => element.get_Parameter(x))
.Where(x => x != null)
.OrderByDescending(x => x.AsElementId().Value() != -1) // Valid ElementIds first
- .FirstOrDefault(x => !x.IsReadOnly);
+ .ThenBy(x => x.IsReadOnly) // Editable parameters first
+ .FirstOrDefault();
}
/***************************************************/
[Description("Returns the element parameter that stores the base level of the element. Checks multiple built-in base level parameters in order of preference.")]
[Input("element", "Element to get the base level parameter from.")]
- [Output("parameter", "Parameter that stores the base level, or null if not found or parameter is read-only.")]
+ [Output("parameter", "Base level parameter of the element, or null if not found.")]
public static Parameter BaseLevelParameter(this Element element)
{
if (element == null)
@@ -62,14 +63,15 @@ public static Parameter BaseLevelParameter(this Element element)
.Select(x => element.get_Parameter(x))
.Where(x => x != null)
.OrderByDescending(x => x.AsElementId().Value() != -1) // Valid ElementIds first
- .FirstOrDefault(x => !x.IsReadOnly);
+ .ThenBy(x => x.IsReadOnly) // Editable parameters first
+ .FirstOrDefault();
}
/***************************************************/
[Description("Returns the element parameter that stores the top level of the element. Checks multiple built-in top level parameters in order of preference.")]
[Input("element", "Element to get the top level parameter from.")]
- [Output("parameter", "Parameter that stores the top level, or null if not found or parameter is read-only.")]
+ [Output("parameter", "Top level parameter of the element, or null if not found.")]
public static Parameter TopLevelParameter(this Element element)
{
if (element == null)
@@ -79,7 +81,8 @@ public static Parameter TopLevelParameter(this Element element)
.Select(x => element.get_Parameter(x))
.Where(x => x != null)
.OrderByDescending(x => x.AsElementId().Value() != -1) // Valid ElementIds first
- .FirstOrDefault(x => !x.IsReadOnly);
+ .ThenBy(x => x.IsReadOnly) // Editable parameters first
+ .FirstOrDefault();
}
/***************************************************/
diff --git a/Revit_Core_Engine/Query/LocationPoint.cs b/Revit_Core_Engine/Query/LocationPoint.cs
index f818a1ab9..8460a93f5 100644
--- a/Revit_Core_Engine/Query/LocationPoint.cs
+++ b/Revit_Core_Engine/Query/LocationPoint.cs
@@ -70,7 +70,12 @@ public static XYZ LocationPoint(this Element element, bool useRoomCalculationPoi
// Fallback to bounding box center
if (locationPoint == null)
{
- BoundingBoxXYZ bbox = element.PhysicalBounds() ?? element.get_BoundingBox(null);
+ BoundingBoxXYZ bbox = null;
+ if (element is DirectShape)
+ bbox = element.get_BoundingBox(null);
+ else
+ bbox = element.PhysicalBounds() ?? element.get_BoundingBox(null);
+
if (bbox != null)
locationPoint = (bbox.Max + bbox.Min) / 2;
}
diff --git a/Revit_Core_Engine/Query/PileFoundation.cs b/Revit_Core_Engine/Query/PileFoundation.cs
new file mode 100644
index 000000000..21ddd2da6
--- /dev/null
+++ b/Revit_Core_Engine/Query/PileFoundation.cs
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the Buildings and Habitats object Model (BHoM)
+ * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved.
+ *
+ * Each contributor holds copyright over their respective contributions.
+ * The project versioning (Git) records all such contribution source information.
+ *
+ *
+ * The BHoM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3.0 of the License, or
+ * (at your option) any later version.
+ *
+ * The BHoM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this code. If not, see .
+ */
+
+using BH.Engine.Adapters.Revit;
+using BH.Engine.Geometry;
+using BH.oM.Adapters.Revit.Settings;
+using BH.oM.Base.Attributes;
+using BH.oM.Geometry;
+using BH.oM.Physical.Elements;
+using BH.oM.Spatial.Layouts;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+
+namespace BH.Revit.Engine.Core
+{
+ public static partial class Query
+ {
+ /***************************************************/
+ /**** Public methods ****/
+ /***************************************************/
+
+ [Description("Builds an ExplicitLayout of pile positions in the oriented cap coordinate system.")]
+ [Input("pileFoundation", "BHoM pile foundation to extract pile positions from.")]
+ [Input("settings", "Revit adapter settings.")]
+ [Output("layout", "Explicit layout of pile XY positions in the oriented cap coordinate system.")]
+ public static ExplicitLayout PileFoundationLayout(this PileFoundation pileFoundation, RevitSettings settings = null)
+ {
+ settings = settings.DefaultIfNull();
+
+ Polyline outline = pileFoundation.PileCap.PadFoundationOutline();
+ (Vector translation, double rotation) = outline.TransformToOriginInXY();
+ if (translation == null || double.IsNaN(rotation))
+ return null;
+
+ List points = new List();
+ foreach (Pile pile in pileFoundation.Piles)
+ {
+ Line line = pile.Location as Line;
+ if (line == null)
+ return null;
+
+ Point basePt = line.Start.Z < line.End.Z ? line.Start : line.End;
+ Point local = basePt.Translate(translation).Rotate(new Point(), Vector.ZAxis, rotation);
+ points.Add(new Point { X = local.X, Y = local.Y, Z = 0 });
+ }
+
+ return new ExplicitLayout(points);
+ }
+
+ /***************************************************/
+
+ [Description("Gets the pile embedment depth below the pile cap soffit. GH pile lines are typically snapped to the top of the cap; Revit Pile Depth is measured from the bottom of the cap.")]
+ [Input("pileFoundation", "BHoM pile foundation to extract pile depth from.")]
+ [Input("settings", "Revit adapter settings (distance tolerance for the top-vs-soffit check).")]
+ [Output("pileDepth", "Depth from cap soffit to pile tip in SI units, or NaN if invalid.")]
+ public static double PileFoundationDepth(this PileFoundation pileFoundation, RevitSettings settings = null)
+ {
+ settings = settings.DefaultIfNull();
+
+ if (pileFoundation?.Piles == null || pileFoundation.Piles.Count == 0 || pileFoundation.PileCap == null)
+ return double.NaN;
+
+ double thickness = pileFoundation.PileCap.PadFoundationThickness();
+ if (double.IsNaN(thickness))
+ return double.NaN;
+
+ Point centroid = pileFoundation.PileCap.PadFoundationCentroid();
+ if (centroid == null)
+ return double.NaN;
+
+ double capTop = centroid.Z;
+ double capBottom = capTop - thickness;
+
+ List pileLines = pileFoundation.Piles.Select(p => p.Location as Line).Where(l => l != null).ToList();
+
+ if (pileLines.Count == 0)
+ return double.NaN;
+
+ // Get pile location lines and check if vertical and same top and bottom Z
+ if (pileLines.Count != pileFoundation.Piles.Count)
+ {
+ BH.Engine.Base.Compute.RecordError($"All piles must have a Line location. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return double.NaN;
+ }
+
+ foreach (BH.oM.Geometry.Line line in pileLines)
+ {
+ if (1 - Math.Abs(line.Direction().DotProduct(Vector.ZAxis)) > settings.AngleTolerance)
+ {
+ BH.Engine.Base.Compute.RecordError($"Only vertical piles are supported. BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ return double.NaN;
+ }
+ }
+
+ double tol = settings.DistanceTolerance;
+ double pileTop = pileLines.Max(l => Math.Max(l.Start.Z, l.End.Z));
+ double pileBottom = pileLines.Min(l => Math.Min(l.Start.Z, l.End.Z));
+
+ if (Math.Abs(pileTop - capBottom) > tol)
+ {
+ BH.Engine.Base.Compute.RecordWarning($"Pile top is not at the bottom of the pile cap. " + $"Pile Depth was set from the bottom of the cap to the bottom of the pile. " + $"BHoM_Guid: {pileFoundation.BHoM_Guid}");
+ }
+
+ double pileDepth = capBottom - pileBottom;
+ if (pileDepth <= 0)
+ return double.NaN;
+
+ return pileDepth;
+ }
+
+ /***************************************************/
+ }
+}
diff --git a/Revit_Core_Engine/Revit_Core_Engine.csproj b/Revit_Core_Engine/Revit_Core_Engine.csproj
index 4514c7144..ed8296864 100644
--- a/Revit_Core_Engine/Revit_Core_Engine.csproj
+++ b/Revit_Core_Engine/Revit_Core_Engine.csproj
@@ -6,7 +6,7 @@
BHoM
Copyright © https://github.com/BHoM
BH.Revit.Engine.Core
- 9.2.0.0
+ 9.3.0.0
@@ -68,6 +68,14 @@
+
+
+
+
+
+
+
+
..\libs\$(RevitVersion)\RevitAPI.dll
@@ -79,6 +87,11 @@
+
+ False
+ $(ProgramData)\BHoM\Assemblies\Analytical_Engine.dll
+ False
+
False
$(ProgramData)\BHoM\Assemblies\Analytical_oM.dll
@@ -119,6 +132,11 @@
$(ProgramData)\BHoM\Assemblies\Diffing_Engine.dll
False
+
+ False
+ $(ProgramData)\BHoM\Assemblies\Dimensional_Engine.dll
+ False
+
False
$(ProgramData)\BHoM\Assemblies\Dimensional_oM.dll
diff --git a/Revit_Engine/Create/Settings/MappingSettings.cs b/Revit_Engine/Create/Settings/MappingSettings.cs
index 53750b8a4..4765f1af7 100644
--- a/Revit_Engine/Create/Settings/MappingSettings.cs
+++ b/Revit_Engine/Create/Settings/MappingSettings.cs
@@ -34,7 +34,8 @@ public static partial class Create
/***************************************************/
/**** Public methods ****/
/***************************************************/
-
+
+ [PreviousVersion("9.3", "BH.Engine.Adapters.Revit.Create.MappingSettings(System.Collections.Generic.IEnumerable, System.String, System.String)")]
[Description("Creates an entity holding information about the enforced convert relationships between Revit families and BHoM types on Pull as well as mapping between Revit parameters and BHoM object properties.")]
[InputFromProperty("parameterMaps")]
[InputFromProperty("familyMaps")]
@@ -57,26 +58,6 @@ public static MappingSettings MappingSettings(IEnumerable paramete
}
/***************************************************/
-
- [ToBeRemoved("4.3", "More up to date version with a larger number of parameters has been added.")]
- [Description("Created an entity holding information about conversion-specific Revit parameter names as well as relationships between object's property names (or names of RevitParameters attached to it) and Revit parameter names.")]
- [InputFromProperty("parameterMaps")]
- [InputFromProperty("tagsParameter")]
- [InputFromProperty("materialGradeParameter")]
- [Output("mappingSettings")]
- public static MappingSettings MappingSettings(IEnumerable parameterMaps = null, string tagsParameter = "", string materialGradeParameter = "")
- {
- MappingSettings mappingSettings = new MappingSettings();
- if (parameterMaps != null)
- mappingSettings = mappingSettings.AddParameterMaps(parameterMaps);
-
- mappingSettings.TagsParameter = tagsParameter;
- mappingSettings.MaterialGradeParameter = materialGradeParameter;
-
- return mappingSettings;
- }
-
- /***************************************************/
}
}
diff --git a/Revit_Engine/Revit_Engine.csproj b/Revit_Engine/Revit_Engine.csproj
index 38eb18538..9d0388907 100644
--- a/Revit_Engine/Revit_Engine.csproj
+++ b/Revit_Engine/Revit_Engine.csproj
@@ -8,7 +8,7 @@
BHoM
Copyright © https://github.com/BHoM
BH.Engine.Revit
- 9.2.0.0
+ 9.3.0.0
diff --git a/Revit_Engine/Versioning_93.json b/Revit_Engine/Versioning_93.json
new file mode 100644
index 000000000..ad7462735
--- /dev/null
+++ b/Revit_Engine/Versioning_93.json
@@ -0,0 +1,51 @@
+{
+ "Namespace": {
+ "ToNew": {
+
+ },
+ "ToOld": {
+
+ }
+ },
+ "Type": {
+ "ToNew": {
+
+ },
+ "ToOld": {
+
+ }
+ },
+ "Method": {
+ "ToNew": {
+
+ },
+ "ToOld": {
+
+ }
+ },
+ "Property": {
+ "ToNew": {
+
+ },
+ "ToOld": {
+
+ }
+ },
+ "Dataset": {
+ "ToNew": {
+
+ },
+ "ToOld": {
+
+ },
+ "MessageForDeleted": {
+
+ }
+ },
+ "MessageForDeleted": {
+ "BH.Revit.Engine.Core.Create.ViewReflectedCeilingPlan(Autodesk.Revit.DB.Document, Autodesk.Revit.DB.Level, System.String, Autodesk.Revit.DB.CurveLoop, Autodesk.Revit.DB.ElementId, Autodesk.Revit.DB.ViewDetailLevel)": "Calls to this method to be replaced with Create.ViewPlan with 'viewFamily' parameter equal to ViewFamily.CeilingPlan."
+ },
+ "MessageForNoUpgrade": {
+
+ }
+}
\ No newline at end of file
diff --git a/Revit_oM/Revit_oM.csproj b/Revit_oM/Revit_oM.csproj
index 26344f79e..42b38f09d 100644
--- a/Revit_oM/Revit_oM.csproj
+++ b/Revit_oM/Revit_oM.csproj
@@ -7,7 +7,7 @@
BHoM
Copyright © https://github.com/BHoM
BH.oM.Revit
- 9.2.0.0
+ 9.3.0.0
..\Build\