Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull of facade elements optimised + extraction of profile and material from mullions implemented #1395

Merged
merged 22 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c1586d9
facade pull optimisation in progress
pawelbaran Aug 7, 2023
c135866
invalid mullions ruled out
pawelbaran Aug 7, 2023
02a1776
check against invalid cells added
pawelbaran Aug 7, 2023
21f6d26
extraction of edge mullions optimised
pawelbaran Aug 7, 2023
91da7bb
curved walls accommodated
pawelbaran Aug 7, 2023
8d538d2
code cleaned up
pawelbaran Aug 7, 2023
4db9405
commented out code deleted
pawelbaran Aug 7, 2023
961fdf3
private methods cleaned up
pawelbaran Aug 7, 2023
fd34772
typo fixed
pawelbaran Aug 8, 2023
74684d7
profile extraction introduced
pawelbaran Aug 8, 2023
5e76580
material extraction unified for framing and mullions
pawelbaran Aug 8, 2023
4f90863
descriptions added
pawelbaran Aug 8, 2023
a1a7e55
support for curtain systems added
pawelbaran Aug 9, 2023
cddc12c
conversion of individual panels and openings restored
pawelbaran Aug 9, 2023
995ffe1
support for curtain systems extended to architecture and physical dis…
pawelbaran Aug 9, 2023
1426a4c
input type of MullionElementProperty limited to Mullion
pawelbaran Aug 9, 2023
aa7200f
FrameEdgeProperty creating dummy profiles removed
pawelbaran Aug 9, 2023
e955365
Mullion cloned to keep curve direction from flipping for panels
enarhi Aug 9, 2023
e802602
Fixed CW ExternalEdge check to check per elemId
enarhi Aug 9, 2023
606da3c
Added rotation for mullion profile to fit BHoM FrameEdgeProperty stan…
enarhi Aug 9, 2023
b5a34fc
tweaks following the review by @vietle-bh
pawelbaran Aug 10, 2023
f62d705
missing versioning added
pawelbaran Aug 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 41 additions & 8 deletions Revit_Core_Engine/Convert/Facade/FromRevit/CurtainWall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,9 @@ public static CurtainWall CurtainWallFromRevit(this Wall wall, RevitSettings set
if (curtainPanels == null || !curtainPanels.Any())
BH.Engine.Base.Compute.RecordError(String.Format("Processing of panels of Revit curtain wall failed. BHoM curtain wall without location has been returned. Revit ElementId: {0}", wall.Id.IntegerValue));


// Get external edges of whole curtain wall
List<FrameEdge> extEdges = new List<FrameEdge>();
List<IElement1D> cwEdgeCrvs = curtainPanels.ExternalEdges();
foreach (ICurve crv in cwEdgeCrvs)
{
FrameEdge frameEdge = new FrameEdge { Curve = crv };
extEdges.Add(frameEdge);
}
List<FrameEdge> allEdges = curtainPanels.SelectMany(x => x.Edges).ToList();
List<FrameEdge> extEdges = allEdges.Distinct().Where(x => allEdges.Count(y => x.ElementId() == y.ElementId()) == 1).ToList();

bHoMCurtainWall = new CurtainWall { ExternalEdges = extEdges, Openings = curtainPanels.ToList(), Name = wall.WallType.Name };

Expand All @@ -95,6 +89,45 @@ public static CurtainWall CurtainWallFromRevit(this Wall wall, RevitSettings set
}

/***************************************************/

[Description("Converts a Revit Wall to BH.oM.Facade.Elements.CurtainSystem.")]
[Input("system", "Revit CurtainSystem 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("curtainWall", "BH.oM.Facade.Elements.CurtainWall resulting from converting the input Revit CurtainSystem.")]
public static CurtainWall CurtainWallFromRevit(this CurtainSystem system, RevitSettings settings = null, Dictionary<string, List<IBHoMObject>> refObjects = null)
{
if (system == null)
return null;

settings = settings.DefaultIfNull();

CurtainWall bHoMCurtainWall = refObjects.GetValue<CurtainWall>(system.Id);
if (bHoMCurtainWall != null)
return bHoMCurtainWall;

IEnumerable<oM.Facade.Elements.Opening> curtainPanels = system.ICurtainGrids().SelectMany(x => x.FacadeCurtainPanels(system.Document, settings, refObjects)).ToList();

if (curtainPanels == null || !curtainPanels.Any())
BH.Engine.Base.Compute.RecordError(String.Format("Processing of panels of Revit curtain wall failed. BHoM curtain wall without location has been returned. Revit ElementId: {0}", system.Id.IntegerValue));

// Get external edges of whole curtain wall
List<FrameEdge> allEdges = curtainPanels.SelectMany(x => x.Edges).ToList();
List<FrameEdge> extEdges = allEdges.Distinct().Where(x => allEdges.Count(y => x == y) == 1).ToList();

bHoMCurtainWall = new CurtainWall { ExternalEdges = extEdges, Openings = curtainPanels.ToList(), Name = system.FamilyTypeFullName() };

//Set identifiers, parameters & custom data
bHoMCurtainWall.SetIdentifiers(system);
bHoMCurtainWall.CopyParameters(system, settings.MappingSettings);
bHoMCurtainWall.SetProperties(system, settings.MappingSettings);

refObjects.AddOrReplace(system.Id, bHoMCurtainWall);

return bHoMCurtainWall;
}

/***************************************************/
}
}

Expand Down
5 changes: 4 additions & 1 deletion Revit_Core_Engine/Convert/Facade/FromRevit/Opening.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ public static oM.Facade.Elements.Opening FacadeOpeningFromRevit(this FamilyInsta
if (opening != null)
return opening;

FrameEdgeProperty frameEdgeProperty = familyInstance.FrameEdgeProperty(settings, refObjects);
// Extraction of frame edge property from Revit FamilyInstance is not implemented yet
BH.Engine.Base.Compute.RecordWarning($"Extraction of frame edge property from a Revit opening is currently not supported, property set to null. ElementId: {familyInstance.Id.IntegerValue}");
FrameEdgeProperty frameEdgeProperty = null;

BH.oM.Geometry.ISurface location = familyInstance.OpeningSurface(host, settings);

List<FrameEdge> edges = new List<FrameEdge>();
Expand Down
108 changes: 106 additions & 2 deletions Revit_Core_Engine/Convert/Structure/FromRevit/Profile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static partial class Convert
/***************************************************/
/**** Public Methods ****/
/***************************************************/

[Description("Converts a Revit FamilySymbol to BH.oM.Spatial.ShapeProfiles.IProfile.")]
[Input("familySymbol", "Revit FamilySymbol to be converted.")]
[Input("settings", "Revit adapter settings to be used while performing the convert.")]
Expand Down Expand Up @@ -131,6 +131,92 @@ public static IProfile ProfileFromRevit(this FamilySymbol familySymbol, RevitSet
return profile;
}

/***************************************************/

[Description("Converts a Revit MullionType to BH.oM.Spatial.ShapeProfiles.IProfile.")]
[Input("mullionType", "Revit MullionType 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("profile", "BH.oM.Spatial.ShapeProfiles.IProfile resulting from converting the input Revit MullionType.")]
public static IProfile ProfileFromRevit(this MullionType mullionType, RevitSettings settings = null, Dictionary<string, List<IBHoMObject>> refObjects = null)
{
settings = settings.DefaultIfNull();

IProfile profile = refObjects.GetValue<IProfile>(mullionType.Id);
if (profile != null)
return profile;

// The algorithm below is so convoluted because mullion type does not have a profile
// Instead, one needs to extract the geometry of one of the instances
// The instance to be queried needs to have its start (bottom) face exposed
// In simple words, it needs to be the first mullion in a chain of mullions of same type

// First, take arbitrary mullion of a given type
Document doc = mullionType.Document;
Mullion representativeMullion = new FilteredElementCollector(doc)
.OfClass(typeof(FamilyInstance))
.Where(x => x is Mullion)
.Cast<Mullion>()
.FirstOrDefault(x => x.MullionType.Id.IntegerValue == mullionType.Id.IntegerValue && x.MullionLine() != null);

if (representativeMullion == null)
{
BH.Engine.Base.Compute.RecordError($"Profile could not be extracted from a mullion. ElementId: {mullionType.Id.IntegerValue}");
return null;
}

// Find the first mullion in the chain the arbitrary one belongs to
List<Mullion> allMullionsInWall = new FilteredElementCollector(doc)
.OfClass(typeof(FamilyInstance))
.Where(x => x is Mullion)
.Cast<Mullion>()
.Where(x => x.Host.Id.IntegerValue == representativeMullion.Host.Id.IntegerValue
&& x.MullionType.Id.IntegerValue == mullionType.Id.IntegerValue)
.ToList();

BH.oM.Geometry.Line line = representativeMullion.MullionLine();
BH.oM.Geometry.Vector direction = line.Direction();
foreach (Mullion candidateMullion in allMullionsInWall)
{
// Skip mullions that are not collinear with the representative mullion
BH.oM.Geometry.Line candidateLine = candidateMullion.MullionLine();
if (candidateLine == null || !candidateLine.IsCollinear(line))
continue;

// Update the representative mullion if the candidate:
// - is collinear (check above)
// - has the same direction
// - has start before the current representative mullion, counting along the mullion direction
if ((candidateLine.Start - line.Start).DotProduct(direction) > 0)
pawelbaran marked this conversation as resolved.
Show resolved Hide resolved
{
representativeMullion = candidateMullion;
line = candidateLine;
}
}

// Find the instance geometry and extract profile from it
Options options = new Options();
options.DetailLevel = ViewDetailLevel.Fine;
options.IncludeNonVisibleObjects = false;
GeometryInstance instance = representativeMullion.get_Geometry(options).FirstOrDefault(x => x is GeometryInstance) as GeometryInstance;
MullionType instanceSymbol = instance.Symbol as MullionType;
if (instanceSymbol != null)
profile = instanceSymbol.FreeFormProfileFromRevit(settings);

if (profile == null)
return null;

//Set identifiers, parameters & custom data
profile.SetIdentifiers(mullionType);
profile.CopyParameters(mullionType, settings.MappingSettings);
profile.SetProperties(mullionType, settings.MappingSettings);

profile.Name = mullionType.Name;
refObjects.AddOrReplace(mullionType.Id, profile);

return profile;
}


/***************************************************/
/**** Private Methods ****/
Expand Down Expand Up @@ -610,7 +696,7 @@ private static FreeFormProfile FreeFormProfileFromRevit(this FamilySymbol family
XYZ direction;
if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.CurveDrivenStructural)
direction = XYZ.BasisX;
else if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.TwoLevelsBased)
else if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.TwoLevelsBased || familySymbol is MullionType)
direction = XYZ.BasisZ;
else
{
Expand Down Expand Up @@ -714,6 +800,13 @@ private static FreeFormProfile FreeFormProfileFromRevit(this FamilySymbol family
if (adjustment.Length() > settings.DistanceTolerance)
profileCurves = profileCurves.Select(x => x.ITranslate(adjustment)).ToList();

// If Mullion, rotate 90 degrees to match orientation of Mullions on CurtainWalls per BHoM Standard of -X is Exterior, +X is Interior
if (familySymbol is MullionType)
{
double angle = -Math.PI * 0.5;
profileCurves = profileCurves.Select(x => x.IRotate(oM.Geometry.Point.Origin, Vector.ZAxis, angle)).ToList();
}

// Check if the curves are in the horizontal plane, if not then align them.
if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.CurveDrivenStructural)
{
Expand Down Expand Up @@ -753,6 +846,17 @@ private static Solid SingleSolid(this GeometryElement geometryElement)
return solid;
}

/***************************************************/

private static BH.oM.Geometry.Line MullionLine(this Mullion mullion)
{
Curve curve = mullion?.LocationCurve;
if (curve == null)
return null;
else
return new oM.Geometry.Line { Start = curve.GetEndPoint(0).PointFromRevit(), End = curve.GetEndPoint(1).PointFromRevit() };
}


/***************************************************/
/**** Private helpers ****/
Expand Down
20 changes: 20 additions & 0 deletions Revit_Core_Engine/Query/BHoMType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,26 @@ public static Type BHoMType(this RoofBase roofBase, Discipline discipline, Revit

/***************************************************/

[Description("Finds a suitable BHoM type to convert the given Revit CurtainSystem to, based on the requested engineering discipline and adapter settings.")]
[Input("system", "Revit CurtainSystem to find a correspondent BHoM type.")]
[Input("discipline", "Engineering discipline based on the BHoM discipline classification.")]
[Input("settings", "Revit adapter settings to be used while performing the search for the correspondent type.")]
[Output("bHoMType", "A suitable BHoM type to convert the given Revit CurtainSystem to.")]
public static Type BHoMType(this CurtainSystem system, Discipline discipline, RevitSettings settings = null)
{
switch (discipline)
{
case Discipline.Facade:
case Discipline.Architecture:
case Discipline.Physical:
return typeof(BH.oM.Facade.Elements.CurtainWall);
}

return null;
}

/***************************************************/

[Description("Finds a suitable BHoM type to convert the given Revit HostObjAttributes to, based on the requested engineering discipline and adapter settings.")]
[Input("hostObjAttributes", "Revit HostObjAttributes to find a correspondent BHoM type.")]
[Input("discipline", "Engineering discipline based on the BHoM discipline classification.")]
Expand Down
2 changes: 1 addition & 1 deletion Revit_Core_Engine/Query/CurtainWallMullions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static List<FrameEdge> CurtainWallMullions(this CurtainGrid curtainGrid,
List<FrameEdge> result = new List<FrameEdge>();
List<Element> mullions = curtainGrid.GetMullionIds().Select(x => document.GetElement(x)).ToList();

foreach (Mullion mullion in mullions)
foreach (Mullion mullion in mullions.Where(x => x.get_BoundingBox(null) != null))
{
result.Add(mullion.FrameEdgeFromRevit(settings, refObjects));
}
Expand Down
Loading