Separar suelos y cubiertas multicuerpo
Revit Macro
Descripción
Esta macro te servirá para seleccionar y limpiar categorías de sistema de Revit con más de una región o cuerpo, lo que resulta muy útil para corregir errores de modelado.
- SelectMultibodyFloors: selecciona suelos visibles en la vista con más de un cuerpo. Ten en cuenta que aquellos suelos divididos en dos o más cuerpos por una abertura también serán seleccionados.
- SelectMultibodyCeilings: selecciona falsos techos visibles en la vista con más de un cuerpo. Ten en cuenta que aquellos techos divididos en dos o más cuerpos por una abertura también serán seleccionados. Ten en cuenta que la API de Revit no permite (2019) crear techos automáticamente, así que solo podemos aspiarar a seleccionar los que estén erróneos.
- SplitMultibodyFloors: selecciona y divide los suelos visibles en la vista con más de un cuerpo o región. Por favor ten en cuenta que los suelos cortados o divididos por aberturas se recrearán con la geometría visible.
/*
* Created by SharpDevelop.
* User: Roberto Molinos [Modelical]
* Date: 3/20/2015
* Time: 1:42 AM
*/
using System;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB.Macros;
namespace GeometryCleaner
{
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.DB.Macros.AddInId("6ACE9B39-339F-4D56-BC11-9D6973B54D94")]
public partial class ThisApplication
{
private void Module_Startup(object sender, EventArgs e)
{
}
private void Module_Shutdown(object sender, EventArgs e)
{
}
#region Revit Macros generated code
private void InternalStartup()
{
this.Startup += new System.EventHandler(Module_Startup);
this.Shutdown += new System.EventHandler(Module_Shutdown);
}
#endregion
const double _eps = 1.0e-9;
public void SelectMultibodyFloors()
{
Document document = this.ActiveUIDocument.Document;
UIDocument uidoc = new UIDocument (document);
List<ElementId> ids = new List<ElementId>();
List<ElementId> badIds = new List<ElementId>();
List<int> cs = new List<int>();
FilteredElementCollector collector = new FilteredElementCollector(document,this.ActiveUIDocument.ActiveView.Id);
ICollection<Element> elems = collector.WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_Floors)).WhereElementIsNotElementType().ToElements();
Autodesk.Revit.DB.Options geomOption = document.Application.Create.NewGeometryOptions();
Transaction tempTransaction = new Transaction(document, "Temp geometry extraction");
tempTransaction.Start();
foreach (Element e in elems)
{
if (e is Floor)
{
Floor f = e as Floor;
if (!PartUtils.HasAssociatedParts(document, f.Id))
{
FloorType fType = f.FloorType;
CompoundStructure comStruct = fType.GetCompoundStructure();
int c = 0;
for (int j = 0; j < comStruct.LayerCount; j++)
{
IList<CompoundStructureLayer> cslList = comStruct.GetLayers();
bool countLayer = true;
if(comStruct.GetLayerFunction(j) == MaterialFunctionAssignment.Membrane)
{
countLayer = false;
}
if(comStruct.GetLayerFunction(j) == MaterialFunctionAssignment.StructuralDeck)
{
if(comStruct.GetDeckEmbeddingType(j) != StructDeckEmbeddingType.Standalone)
{
countLayer = false;
}
}
if (countLayer)
{
c++;
}
}
cs.Add(c);
ids.Add(f.Id);
}
}
}
PartUtils.CreateParts(document,ids);
document.Regenerate();
int i = 0;
foreach (ElementId fid in ids)
{
ICollection<ElementId> partIds = PartUtils.GetAssociatedParts(document,fid,false,false);
if (cs[i] != partIds.Count)
{
badIds.Add(fid);
//TaskDialog.Show("Warning", "Multibody Object Found");
}
i++;
}
tempTransaction.RollBack();
using (Transaction transaction = new Transaction(document, "Select Multibody Floors"))
{
if(transaction.Start() == TransactionStatus.Started)
{
uidoc.Selection.SetElementIds(badIds);
if(transaction.Commit() == TransactionStatus.Committed)
{
TaskDialog.Show("Selected " , badIds.Count.ToString() + " floor(s) with multiple bodies.");
}
else
{
transaction.RollBack();
}
}
}
}
public void SelectMultibodyCeilings()
{
Document document = this.ActiveUIDocument.Document;
UIDocument uidoc = new UIDocument (document);
List<ElementId> ids = new List<ElementId>();
List<ElementId> badIds = new List<ElementId>();
List<int> cs = new List<int>();
ElementFilter ff = new ElementCategoryFilter(BuiltInCategory.OST_Ceilings);
FilteredElementCollector collector = new FilteredElementCollector(document,this.ActiveUIDocument.ActiveView.Id);
ICollection<Element> elems = collector.WherePasses(ff).WhereElementIsNotElementType().ToElements();
Autodesk.Revit.DB.Options geomOption = document.Application.Create.NewGeometryOptions();
Transaction tempTransaction = new Transaction(document, "Temp geometry extraction");
tempTransaction.Start();
foreach (Element e in elems)
{
if (e is Ceiling)
{
Ceiling f = e as Ceiling;
if (!PartUtils.HasAssociatedParts(document, f.Id))
{
ElementId fTypeId = f.GetTypeId();
CeilingType fType = document.GetElement(fTypeId) as CeilingType;
CompoundStructure comStruct = fType.GetCompoundStructure();
int c = 0;
for (int j = 0; j < comStruct.LayerCount; j++)
{
IList<CompoundStructureLayer> cslList = comStruct.GetLayers();
bool countLayer = true;
if(comStruct.GetLayerFunction(j) == MaterialFunctionAssignment.Membrane)
{
countLayer = false;
}
if(comStruct.GetLayerFunction(j) == MaterialFunctionAssignment.StructuralDeck)
{
if(comStruct.GetDeckEmbeddingType(j) != StructDeckEmbeddingType.Standalone)
{
countLayer = false;
}
}
if (countLayer)
{
c++;
}
}
cs.Add(c);
ids.Add(f.Id);
}
}
}
PartUtils.CreateParts(document,ids);
document.Regenerate();
int i = 0;
foreach (ElementId fid in ids)
{
ICollection<ElementId> partIds = PartUtils.GetAssociatedParts(document,fid,false,false);
if (cs[i] != partIds.Count)
{
badIds.Add(fid);
//TaskDialog.Show("Warning", "Multibody Object Found");
}
i++;
}
tempTransaction.RollBack();
using (Transaction transaction = new Transaction(document, "Select Multibody Ceilings"))
{
if(transaction.Start() == TransactionStatus.Started)
{
uidoc.Selection.SetElementIds(badIds);
if(transaction.Commit() == TransactionStatus.Committed)
{
TaskDialog.Show("Selected " , badIds.Count.ToString() + " ceiling(s) with multiple bodies.");
}
else
{
transaction.RollBack();
}
}
}
}
public void SplitDisjointFloors()
{
Document document = this.ActiveUIDocument.Document;
UIDocument uidoc = new UIDocument (document);
List<ElementId> ids = new List<ElementId>();
List<ElementId> badIds = new List<ElementId>();
List<int> cs = new List<int>();
ElementFilter ff = new ElementCategoryFilter(BuiltInCategory.OST_Floors);
FilteredElementCollector collector = new FilteredElementCollector(document,this.ActiveUIDocument.ActiveView.Id);
ICollection<Element> elems = collector.WherePasses(ff).WhereElementIsNotElementType().ToElements();
Autodesk.Revit.DB.Options geomOption = document.Application.Create.NewGeometryOptions();
Transaction tempTransaction = new Transaction(document, "Temp geometry extraction");
tempTransaction.Start();
foreach (Element e in elems)
{
Floor f = e as Floor;
if (f != null)
{
if (!PartUtils.HasAssociatedParts(document, f.Id))
{
FloorType fType = f.FloorType;
CompoundStructure comStruct = fType.GetCompoundStructure();
int c = 0;
for (int j = 0; j < comStruct.LayerCount; j++)
{
IList<CompoundStructureLayer> cslList = comStruct.GetLayers();
bool countLayer = true;
if(comStruct.GetLayerFunction(j) == MaterialFunctionAssignment.Membrane)
{
countLayer = false;
}
if(comStruct.GetLayerFunction(j) == MaterialFunctionAssignment.StructuralDeck)
{
if(comStruct.GetDeckEmbeddingType(j) != StructDeckEmbeddingType.Standalone)
{
countLayer = false;
}
}
if (countLayer)
{
c++;
}
}
cs.Add(c);
ids.Add(f.Id);
}
}
}
PartUtils.CreateParts(document,ids);
document.Regenerate();
int i = 0;
foreach (ElementId fid in ids)
{
ICollection<ElementId> partIds = PartUtils.GetAssociatedParts(document,fid,false,false);
if (cs[i] != partIds.Count)
{
badIds.Add(fid);
//TaskDialog.Show("Warning", "Multibody Object Found");
}
i++;
}
tempTransaction.RollBack();
using (Transaction transaction = new Transaction(document, "Split Multibody Floors"))
{
if(transaction.Start() == TransactionStatus.Started)
{
//uidoc.Selection.SetElementIds(badIds);
List<Floor> badFloors = new List<Floor>();
foreach (ElementId badId in badIds)
{
Floor sourceFloor = document.GetElement(badId) as Floor;
if (sourceFloor == null) continue;
//int c = 0;
Autodesk.Revit.DB.GeometryElement floorGeometryElement = sourceFloor.get_Geometry( geomOption );
foreach( Autodesk.Revit.DB.GeometryObject geometryObject in floorGeometryElement )
{
var floorSolid = geometryObject as Solid;
if( floorSolid == null )
continue;
var topFace = GetTopFace( floorSolid );
if( topFace == null )
throw new NotSupportedException(
"Floor does not have top face" );
if( topFace.EdgeLoops.IsEmpty )
throw new NotSupportedException(
"Floor top face does not have edges" );
EdgeArrayArray eaa = topFace.EdgeLoops;
foreach (EdgeArray ea in eaa)
{
CurveArray floorCurveArray = GetCurveArrayFromEdgeArary( ea );
document.Create.NewFloor(floorCurveArray,sourceFloor.FloorType,document.GetElement(sourceFloor.LevelId) as Level,false);
}
break;
// Create new floor using source
// floor outer boundaries
}
document.Delete(badId);
}
if(transaction.Commit() == TransactionStatus.Committed)
{
TaskDialog.Show("Split " , badIds.Count.ToString() + " floors with several bodies.");
}
else
{
transaction.RollBack();
}
}
}
}
private CurveArray GetCurveArrayFromEdgeArary(EdgeArray edgeArray )
{
CurveArray curveArray =
new CurveArray();
foreach( Edge edge in edgeArray )
{
var edgeCurve =
edge.AsCurve();
curveArray.Append( edgeCurve );
}
return curveArray;
}
private PlanarFace GetTopFace( Solid solid )
{
PlanarFace topFace = null;
FaceArray faces = solid.Faces;
foreach( Face f in faces )
{
PlanarFace pf = f as PlanarFace;
if( null != pf
&& ( Math.Abs( pf.Normal.X - 0 ) < _eps && Math.Abs( pf.Normal.Y - 0 ) < _eps ) )
{
if( ( null == topFace )
|| ( topFace.Origin.Z < pf.Origin.Z ) )
{
topFace = pf;
}
}
}
return topFace;
}
}
}
Aquí puedes descargar el archivo cs.
Gracias a Jeremy Tammik y Spiderinnet por sus valiosos ejemplos.
Plataforma
Revit.
Tipo
Revit API Macro.