diff --git a/src/DynamoRevit/Resources/LayoutSpecs.json b/src/DynamoRevit/Resources/LayoutSpecs.json index a6852a531..fb413fc99 100644 --- a/src/DynamoRevit/Resources/LayoutSpecs.json +++ b/src/DynamoRevit/Resources/LayoutSpecs.json @@ -265,6 +265,12 @@ { "path": "RevitNodes.Revit.Elements.Topography" }, + { + "path": "RevitNodes.Revit.Elements.Toposolid" + }, + { + "path": "RevitNodes.Revit.Elements.ToposolidType" + }, { "path": "RevitNodes.Revit.Elements.Viewport" }, diff --git a/src/Libraries/RevitNodes/Elements/InternalUtilities/ElementWrapper.cs b/src/Libraries/RevitNodes/Elements/InternalUtilities/ElementWrapper.cs index 25190c752..5072639ea 100644 --- a/src/Libraries/RevitNodes/Elements/InternalUtilities/ElementWrapper.cs +++ b/src/Libraries/RevitNodes/Elements/InternalUtilities/ElementWrapper.cs @@ -244,6 +244,16 @@ public static Topography Wrap(Autodesk.Revit.DB.Architecture.TopographySurface t return Topography.FromExisting(topoSurface, isRevitOwned); } + public static Toposolid Wrap(Autodesk.Revit.DB.Toposolid toposolid, bool isRevitOwned) + { + return Toposolid.FromExisting(toposolid, isRevitOwned); + } + + public static ToposolidType Wrap(Autodesk.Revit.DB.ToposolidType toposolidType, bool isRevitOwned) + { + return ToposolidType.FromExisting(toposolidType, isRevitOwned); + } + public static object Wrap(Autodesk.Revit.DB.Panel ele, bool isRevitOwned) { if (AdaptiveComponentInstanceUtils.IsAdaptiveFamilySymbol(ele.Symbol)) diff --git a/src/Libraries/RevitNodes/Elements/Toposolid.cs b/src/Libraries/RevitNodes/Elements/Toposolid.cs new file mode 100644 index 000000000..c5a367062 --- /dev/null +++ b/src/Libraries/RevitNodes/Elements/Toposolid.cs @@ -0,0 +1,373 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.DesignScript.Geometry; +using Autodesk.DesignScript.Runtime; +using Autodesk.Revit.DB; +using Revit.GeometryConversion; +using RevitServices.Persistence; +using RevitServices.Transactions; +using Curve = Autodesk.DesignScript.Geometry.Curve; +using Pt = Autodesk.DesignScript.Geometry.Point; + +namespace Revit.Elements +{ + /// + /// A Revit Toposolid + /// + public class Toposolid : Element + { + #region Internal properties + + /// + /// An internal handle on the Revit Toposolid + /// + internal Autodesk.Revit.DB.Toposolid InternalToposolid + { + get; private set; + } + + /// + /// Reference to the Element + /// + [SupressImportIntoVM] + public override Autodesk.Revit.DB.Element InternalElement + { + get { return InternalToposolid; } + } + + #endregion + + #region Private constructors + + /// + /// Private constructor + /// + private Toposolid(Autodesk.Revit.DB.Toposolid toposolid) + { + SafeInit(() => InitToposolid(toposolid), true); + } + + /// + /// Private constructor + /// + private Toposolid(List profiles, List points, Autodesk.Revit.DB.ToposolidType toposolidType, Autodesk.Revit.DB.Level level) + { + SafeInit(() => InitToposolid(profiles, points, toposolidType, level)); + } + + /// + /// Private constructor + /// + private Toposolid(List profiles, Autodesk.Revit.DB.ToposolidType toposolidType, Autodesk.Revit.DB.Level level) + { + SafeInit(() => InitToposolid(profiles, toposolidType, level)); + } + + /// + /// Private constructor + /// + private Toposolid(List points, Autodesk.Revit.DB.ToposolidType toposolidType, Autodesk.Revit.DB.Level level) + { + SafeInit(() => InitToposolid(points, toposolidType, level)); + } + + #endregion + + #region Helpers for private constructors + + /// + /// Initialize a toposolid element + /// + private void InitToposolid(Autodesk.Revit.DB.Toposolid toposolid) + { + InternalSetToposolid(toposolid); + } + + /// + /// Initialize a toposolid element + /// + private void InitToposolid(List profiles, List points, Autodesk.Revit.DB.ToposolidType toposolidType, Autodesk.Revit.DB.Level level) + { + TransactionManager.Instance.EnsureInTransaction(Document); + + Autodesk.Revit.DB.Toposolid toposolid = Autodesk.Revit.DB.Toposolid.Create(Document, profiles, points, toposolidType.Id, level.Id); + + InternalSetToposolid(toposolid); + + TransactionManager.Instance.TransactionTaskDone(); + + ElementBinder.CleanupAndSetElementForTrace(Document, InternalToposolid); + } + + /// + /// Initialize a toposolid element + /// + private void InitToposolid(List profiles, Autodesk.Revit.DB.ToposolidType toposolidType, Autodesk.Revit.DB.Level level) + { + TransactionManager.Instance.EnsureInTransaction(Document); + + Autodesk.Revit.DB.Toposolid toposolid = Autodesk.Revit.DB.Toposolid.Create(Document, profiles, toposolidType.Id, level.Id); + + InternalSetToposolid(toposolid); + + TransactionManager.Instance.TransactionTaskDone(); + + ElementBinder.CleanupAndSetElementForTrace(Document, InternalToposolid); + } + + /// + /// Initialize a toposolid element + /// + private void InitToposolid(List points, Autodesk.Revit.DB.ToposolidType toposolidType, Autodesk.Revit.DB.Level level) + { + TransactionManager.Instance.EnsureInTransaction(Document); + + Autodesk.Revit.DB.Toposolid toposolid = Autodesk.Revit.DB.Toposolid.Create(Document, points, toposolidType.Id, level.Id); + + InternalSetToposolid(toposolid); + + TransactionManager.Instance.TransactionTaskDone(); + + ElementBinder.CleanupAndSetElementForTrace(Document, InternalToposolid); + } + + #endregion + + #region Private mutators + + /// + /// Set the InternalToposolid property and the associated element id and unique id + /// + /// + private void InternalSetToposolid(Autodesk.Revit.DB.Toposolid toposolid) + { + InternalToposolid = toposolid; + InternalElementId = toposolid.Id; + InternalUniqueId = toposolid.UniqueId; + } + + #endregion + + #region public properties + /// + /// Get Slab Shape Points + /// + public IEnumerable Points + { + get + { + if (this.InternalToposolid.GetSlabShapeEditor() == null) + { + throw new Exception(Properties.Resources.InvalidShapeEditor); + } + + TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument); + this.InternalToposolid.GetSlabShapeEditor().Enable(); + TransactionManager.Instance.TransactionTaskDone(); + + List points = new List(); + foreach (SlabShapeVertex v in this.InternalToposolid.GetSlabShapeEditor().SlabShapeVertices) + { + points.Add(v.Position.ToPoint()); + } + return points; + } + } + #endregion + + #region Public static constructors + /// + /// Create a Revit Toposolid given its curve outline, points, type and Level + /// + /// + /// + /// + /// + /// + /// + public static Toposolid ByOutlinePointsTypeAndLevel(Curve[] outlineCurves, IEnumerable points, ToposolidType toposolidType, Level level) + { + if (outlineCurves == null) + { + throw new ArgumentNullException(nameof(outlineCurves)); + } + + var toposolid = ByOutlinePointsTypeAndLevel(PolyCurve.ByJoinedCurves(outlineCurves, 0.001, false), points, toposolidType, level); + + return toposolid; + } + + /// + /// Create a Revit Toposolid given its curve outline, points, type and Level + /// + /// + /// + /// + /// + /// + /// + /// + public static Toposolid ByOutlinePointsTypeAndLevel(PolyCurve outline, IEnumerable points, ToposolidType toposolidType, Level level) + { + if (outline == null) + { + throw new ArgumentNullException(nameof(outline)); + } + + if (points == null) + { + throw new ArgumentNullException(nameof(points)); + } + + if (toposolidType == null) + { + throw new ArgumentNullException(nameof(toposolidType)); + } + + if (level == null) + { + throw new ArgumentNullException(nameof(level)); + } + + if (!outline.IsClosed) + { + throw new ArgumentException(Properties.Resources.OpenInputPolyCurveError); + } + + CurveLoop loop = new CurveLoop(); + outline.Curves().ForEach(x => loop.Append(x.ToRevitType())); + + List loops = new List { loop }; + + if (!BoundaryValidation.IsValidHorizontalBoundary(loops)) + { + throw new ArgumentException(Properties.Resources.NotHorizontalInputPolyCurveError); + } + + List xyzList = points.Select(x => x.ToRevitType()).ToList(); + + var toposolid = new Toposolid(loops, xyzList, toposolidType.InternalToposolidType, level.InternalLevel); + DocumentManager.Regenerate(); + return toposolid; + } + + /// + /// Create a Revit Toposolid given its curve outline, type and Level + /// + /// + /// + /// + /// + /// + public static Toposolid ByOutlineTypeAndLevel(Curve[] outlineCurves, ToposolidType toposolidType, Level level) + { + if (outlineCurves == null) + { + throw new ArgumentNullException(nameof(outlineCurves)); + } + + var toposolid = ByOutlineTypeAndLevel(PolyCurve.ByJoinedCurves(outlineCurves, 0.001, false), toposolidType, level); + + return toposolid; + } + + /// + /// Create a Revit Toposolid given its curve outline, type and Level + /// + /// + /// + /// + /// + /// + /// + public static Toposolid ByOutlineTypeAndLevel(PolyCurve outline, ToposolidType toposolidType, Level level) + { + if (outline == null) + { + throw new ArgumentNullException(nameof(outline)); + } + + if (toposolidType == null) + { + throw new ArgumentNullException(nameof(toposolidType)); + } + + if (level == null) + { + throw new ArgumentNullException(nameof(level)); + } + + if (!outline.IsClosed) + { + throw new ArgumentException(Properties.Resources.OpenInputPolyCurveError); + } + + CurveLoop loop = new CurveLoop(); + outline.Curves().ForEach(x => loop.Append(x.ToRevitType())); + + List loops = new List { loop }; + + if (!BoundaryValidation.IsValidHorizontalBoundary(loops)) + { + throw new ArgumentException(Properties.Resources.NotHorizontalInputPolyCurveError); + } + + var toposolid = new Toposolid(loops, toposolidType.InternalToposolidType, level.InternalLevel); + DocumentManager.Regenerate(); + return toposolid; + } + + /// + /// Create a Revit Toposolid given its points, type and Level + /// + /// + /// + /// + /// + /// + public static Toposolid ByPointsTypeAndLevel(IEnumerable points, ToposolidType toposolidType, Level level) + { + if (points == null) + { + throw new ArgumentNullException(nameof(points)); + } + + if (toposolidType == null) + { + throw new ArgumentNullException(nameof(toposolidType)); + } + + if (level == null) + { + throw new ArgumentNullException(nameof(level)); + } + + List xyzList = points.Select(x => x.ToRevitType()).ToList(); + + var toposolid = new Toposolid(xyzList, toposolidType.InternalToposolidType, level.InternalLevel); + DocumentManager.Regenerate(); + return toposolid; + } + + #endregion + + #region Internal static constructors + + /// + /// Create a Toposolid from a user selected Element. + /// + /// + /// + /// + internal static Toposolid FromExisting(Autodesk.Revit.DB.Toposolid toposolid, bool isRevitOwned) + { + return new Toposolid(toposolid) + { + IsRevitOwned = isRevitOwned + }; + } + + #endregion + } +} diff --git a/src/Libraries/RevitNodes/Elements/ToposolidType.cs b/src/Libraries/RevitNodes/Elements/ToposolidType.cs new file mode 100644 index 000000000..dfef85a21 --- /dev/null +++ b/src/Libraries/RevitNodes/Elements/ToposolidType.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DynamoServices; +using RevitServices.Persistence; +using RevitServices.Transactions; + +namespace Revit.Elements +{ + [RegisterForTrace] + public class ToposolidType : ElementType + { + #region Internal properties + + internal Autodesk.Revit.DB.ToposolidType InternalToposolidType => InternalElementType as Autodesk.Revit.DB.ToposolidType; + + #endregion + + #region Private constructors + + /// + /// Private constructor for DSToposolidType + /// + /// + private ToposolidType(Autodesk.Revit.DB.ToposolidType toposolidType) : base(toposolidType) + { + } + + #endregion + + #region Public static constructors + + /// + /// Select a toposolid type from the current document by name + /// + /// + /// + public static new ToposolidType ByName(string name) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + var type = DocumentManager.Instance.ElementsOfType() + .FirstOrDefault(x => x.Name == name); + + if (type == null) + { + throw new Exception(Properties.Resources.ToposolidTypeNotFound); + } + + return new ToposolidType(type) + { + IsRevitOwned = true + }; + } + + #endregion + + #region Internal static constructors + + /// + /// Wrap an element in the associated DS type + /// + /// The ToposolidType + /// + /// + internal static ToposolidType FromExisting(Autodesk.Revit.DB.ToposolidType toposolidType, bool isRevitOwned) + { + return new ToposolidType(toposolidType) + { + IsRevitOwned = isRevitOwned + }; + } + + #endregion + } +} diff --git a/src/Libraries/RevitNodes/Properties/Resources.Designer.cs b/src/Libraries/RevitNodes/Properties/Resources.Designer.cs index 84ff8817d..a21937f42 100644 --- a/src/Libraries/RevitNodes/Properties/Resources.Designer.cs +++ b/src/Libraries/RevitNodes/Properties/Resources.Designer.cs @@ -1392,6 +1392,15 @@ internal static string TopographyNeedsThreePoints { } } + /// + /// Looks up a localized string similar to There is no ToposolidType of the given name in the current Document.. + /// + internal static string ToposolidTypeNotFound { + get { + return ResourceManager.GetString("ToposolidTypeNotFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to Type not found in document.. /// diff --git a/src/Libraries/RevitNodes/Properties/Resources.en-US.resx b/src/Libraries/RevitNodes/Properties/Resources.en-US.resx index 0f18e549d..ecf080c1c 100644 --- a/src/Libraries/RevitNodes/Properties/Resources.en-US.resx +++ b/src/Libraries/RevitNodes/Properties/Resources.en-US.resx @@ -582,4 +582,7 @@ Input value for imageProperty {0} is invalid. There is no texture connected to {1} in {2}. + + There is no ToposolidType of the given name in the current Document. + \ No newline at end of file diff --git a/src/Libraries/RevitNodes/Properties/Resources.resx b/src/Libraries/RevitNodes/Properties/Resources.resx index f41cb55ec..b89074ff7 100644 --- a/src/Libraries/RevitNodes/Properties/Resources.resx +++ b/src/Libraries/RevitNodes/Properties/Resources.resx @@ -607,6 +607,9 @@ Input value for imageProperty {0} is invalid. There is no {1} in {2}. - Input value for imageProperty {0} is invalid. There is no texture connected to {1} in {2}. - + Input value for imageProperty {0} is invalid. There is no texture connected to {1} in {2}. + + + There is no ToposolidType of the given name in the current Document. + \ No newline at end of file diff --git a/src/Libraries/RevitNodes/RevitNodes.csproj b/src/Libraries/RevitNodes/RevitNodes.csproj index 0f6c2d5d1..251061ecd 100644 --- a/src/Libraries/RevitNodes/RevitNodes.csproj +++ b/src/Libraries/RevitNodes/RevitNodes.csproj @@ -117,6 +117,8 @@ + + diff --git a/test/Libraries/RevitNodesTests/Elements/ToposolidTests.cs b/test/Libraries/RevitNodesTests/Elements/ToposolidTests.cs new file mode 100644 index 000000000..56fd9d325 --- /dev/null +++ b/test/Libraries/RevitNodesTests/Elements/ToposolidTests.cs @@ -0,0 +1,88 @@ +using System; +using System.Linq; +using Autodesk.DesignScript.Geometry; +using NUnit.Framework; +using Revit.Elements; +using RevitTestServices; +using RTF.Framework; + +namespace RevitNodesTests.Elements +{ + [TestFixture] + public class ToposolidTests : RevitNodeTestBase + { + [Test] + [TestModel(@".\Empty.rvt")] + public void ToposolidCreationTest_OutlineTypeLevel() + { + var elevation = 100; + var level = Level.ByElevation(elevation); + + var outline = new[] + { + Line.ByStartPointEndPoint(Point.ByCoordinates(0, 0, 0), Point.ByCoordinates(100, 0, 0)), + Line.ByStartPointEndPoint(Point.ByCoordinates(100, 0, 0), Point.ByCoordinates(100, 100, 0)), + Line.ByStartPointEndPoint(Point.ByCoordinates(100, 100, 0), Point.ByCoordinates(0, 100, 0)), + Line.ByStartPointEndPoint(Point.ByCoordinates(0, 100, 0), Point.ByCoordinates(0, 0, 0)) + }; + + var toposolidType = ToposolidType.ByName("Grassland - 16\""); + + var toposolid = Toposolid.ByOutlineTypeAndLevel(outline, toposolidType, level); + var allPoints = toposolid.Points; + Assert.AreEqual(4, allPoints.Count()); + } + + [Test] + [TestModel(@".\Empty.rvt")] + public void ToposolidCreationTest_PointsTypeLevel() + { + var elevation = 100; + var level = Level.ByElevation(elevation); + + var points = new[] + { + Point.ByCoordinates(10, 10, 2), + Point.ByCoordinates(90, 0, 3), + Point.ByCoordinates(90, 90, 4), + Point.ByCoordinates(10, 90, 5) + }; + + var toposolidType = ToposolidType.ByName("Grassland - 16\""); + + var toposolid = Toposolid.ByPointsTypeAndLevel(points, toposolidType, level); + var allPoints = toposolid.Points; + Assert.AreEqual(4, allPoints.Count()); + } + + [Test] + [TestModel(@".\Empty.rvt")] + public void ToposolidCreationTest_OutlinePointsTypeLevel() + { + var elevation = 100; + var level = Level.ByElevation(elevation); + + var outline = new[] + { + Line.ByStartPointEndPoint(Point.ByCoordinates(0, 0, 0), Point.ByCoordinates(100, 0, 0)), + Line.ByStartPointEndPoint(Point.ByCoordinates(100, 0, 0), Point.ByCoordinates(100, 100, 0)), + Line.ByStartPointEndPoint(Point.ByCoordinates(100, 100, 0), Point.ByCoordinates(0, 100, 0)), + Line.ByStartPointEndPoint(Point.ByCoordinates(0, 100, 0), Point.ByCoordinates(0, 0, 0)) + }; + + var points = new[] + { + Point.ByCoordinates(10, 10, 2), + Point.ByCoordinates(90, 0, 3), + Point.ByCoordinates(90, 90, 4), + Point.ByCoordinates(10, 90, 5) + }; + + var toposolidType = ToposolidType.ByName("Grassland - 16\""); + + var toposolid = Toposolid.ByOutlinePointsTypeAndLevel(outline, points, toposolidType, level); + var allPoints = toposolid.Points; + Assert.AreEqual(8, allPoints.Count()); + } + } +} diff --git a/test/Libraries/RevitNodesTests/Elements/ToposolidTypeTest.cs b/test/Libraries/RevitNodesTests/Elements/ToposolidTypeTest.cs new file mode 100644 index 000000000..4e2c84d3c --- /dev/null +++ b/test/Libraries/RevitNodesTests/Elements/ToposolidTypeTest.cs @@ -0,0 +1,32 @@ +using System; +using NUnit.Framework; +using Revit.Elements; +using RevitTestServices; +using RTF.Framework; + +namespace RevitNodesTests.Elements +{ + + [TestFixture] + public class ToposolidTypeTests : RevitNodeTestBase + { + + [Test] + [TestModel(@".\Empty.rvt")] + public void ByName_ValidArgs() + { + var toposolidTypeName = "Grassland - 16\""; + var toposolidType = ToposolidType.ByName(toposolidTypeName); + Assert.NotNull(toposolidType); + Assert.AreEqual(toposolidTypeName, toposolidType.Name); + } + + [Test] + [TestModel(@".\Empty.rvt")] + public void ByName_NullArgument() + { + Assert.Throws(typeof(ArgumentNullException), () => ToposolidType.ByName(null)); + } + } +} + diff --git a/test/Libraries/RevitNodesTests/RevitNodesTests.csproj b/test/Libraries/RevitNodesTests/RevitNodesTests.csproj index 7695d9b51..8b244a8bd 100644 --- a/test/Libraries/RevitNodesTests/RevitNodesTests.csproj +++ b/test/Libraries/RevitNodesTests/RevitNodesTests.csproj @@ -129,6 +129,8 @@ + +