using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.IFC;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using System;
using System.Linq;
namespace Szmedi.RvKits.ModelManager
{
///
/// 基于标高的
///
public static class BaseLevelHelpers
{
///
/// 获取基于标高的边界
///
///
///
public static Dictionary GetRegions(List levelList)
{
Dictionary outlines = new();
////获取标高范围
for (int i = 0; i < levelList.Count() - 1; i++)
{
Level baseLevel = levelList.ElementAt(i);
Level topLevel = levelList.ElementAt(i + 1);
XYZ min = new(double.MinValue, double.MinValue, baseLevel.Elevation);
XYZ max = new(double.MaxValue, double.MaxValue, topLevel.Elevation);
Outline outline = new(min, max);
outlines.Add(baseLevel, outline);
}
return outlines;
}
///
/// 修改基于线的族
///
///
///
///
public static void ModifyCurveBasedFamily(Level level, FamilyInstance familyInstance)
{
var originOffset = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM).AsDouble();
var doc = level.Document;
if (familyInstance.Host is not Level)
{
return;
}
if (!familyInstance.Symbol.IsActive)
{
familyInstance.Symbol.Activate();
}
var hostLevel = familyInstance.Host as Level;
var offset = hostLevel.Elevation + originOffset - level.Elevation;
var loc = familyInstance.Location as LocationCurve;
var p1 = loc.Curve.GetEndPoint(0);
var p2 = loc.Curve.GetEndPoint(1);
var line = Line.CreateBound(p1.Add(XYZ.BasisZ * level.Elevation), p2.Add(XYZ.BasisZ * level.Elevation));
var newFamilyInstance = doc.Create.NewFamilyInstance(
level.GetPlaneReference(),
line,
familyInstance.Symbol
);
var offsetParam = newFamilyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM);
offsetParam.Set(offset);
foreach (Parameter param in familyInstance.Parameters)
{
if (param.IsReadOnly || param.Definition.Name == offsetParam.Definition.Name)
{
continue;
}
switch (param.StorageType)
{
case StorageType.None:
break;
case StorageType.Integer:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsInteger());
break;
case StorageType.Double:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsDouble());
break;
case StorageType.String:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsString());
break;
case StorageType.ElementId:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsElementId());
break;
default:
throw new ArgumentOutOfRangeException();
}
}
doc.Delete(familyInstance.Id);
}
///
/// 修改基于标高的族
///
///
///
///
public static void ModifyOneLevelBasedFamily(Level level, FamilyInstance familyInstance)
{
var doc = level.Document;
var baseLevelParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM);
var originLevel = doc.GetElement(baseLevelParam.AsElementId()) as Level;
if (!baseLevelParam.IsReadOnly && baseLevelParam.UserModifiable)
{
baseLevelParam.Set(level.Id);
var param = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM);
if (param != null && param.IsReadOnly == false)
{
var value = param.AsDouble();
param.Set(originLevel.Elevation + value - level.Elevation);
}
}
}
///
/// 修改基于两个标高的族
///
///
///
///
public static void ModifyTwoLevelBasedFamily(List levels, Level level, FamilyInstance familyInstance)
{
var levelOrdered = levels.OrderBy(l => l.Elevation).ToList();
var n = levelOrdered.FindIndex(l => l.Id == level.Id);
var doc = level.Document;
var baseLevelParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM);
var originLevel = doc.GetElement(baseLevelParam.AsElementId()) as Level;
if (!baseLevelParam.IsReadOnly && baseLevelParam.UserModifiable)
{
baseLevelParam.Set(level.Id);
var baseOffestParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM);
var baseOffestValue = baseOffestParam.AsDouble();
baseOffestParam.Set(baseOffestValue + originLevel.Elevation - level.Elevation);
if (n + 1 < levelOrdered.Count)
{
var topLevelParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM);
originLevel = doc.GetElement(topLevelParam.AsElementId()) as Level;
topLevelParam.Set(levelOrdered[n + 1].Id);
var topOffestparam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM);
var topffestValue = topOffestparam.AsDouble();
familyInstance
.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM)
.Set(originLevel.Elevation + topffestValue - levelOrdered[n + 1].Elevation);
}
}
}
///
/// 修改墙标高
///
///
/// 项目中的所有标高
///
///
public static void ModifyWall(View view, List levels, Level level, Wall wall)
{
var doc = wall.Document;
var isExist = new FilteredElementCollector(doc)
.OfClass(typeof(FamilyInstance))
.Cast()
.Any(fi => fi.Host?.Id == wall.Id);
var instances = doc.OfType().Where(ins => ins.Host != null && ins.Host.Id == wall.Id);
//存在主体依赖
if (isExist)
{
return;
}
var levelOrdered = levels.OrderBy(l => l.Elevation).ToList();
var n = levelOrdered.FindIndex(l => l.Id == level.Id);
var wallBox = wall.get_BoundingBox(view);
var minZ = wallBox.Min.Z;
var maxZ = wallBox.Max.Z;
if (ExporterIFCUtils.HasElevationProfile(wall) || instances.Any())
{
return;
}
wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).Set(level.Id);
var originBaseOffest = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(minZ - level.Elevation);
if (n + 1 < levelOrdered.Count)
{
wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(levelOrdered[n + 1].Id);
var originTopOffest = wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(maxZ - levelOrdered[n + 1].Elevation);
}
}
///
/// 修改基于工作平面的族
///
///
///
///
///
public static void ModifyWorkPlaneBasedFamily(Level level, FamilyInstance familyInstance)
{
Parameter baseLevelParam = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_SCHEDULE_ONLY_LEVEL_PARAM);
var doc = level.Document;
//var originLevel = doc.GetElement(baseLevelParam.AsElementId()) as Level;
//var hostParam = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_PARAM);
//var hostParamValue = doc.GetElement(hostParam.AsElementId());
if (familyInstance.Host is Level)
{
if (!familyInstance.Symbol.IsActive)
{
familyInstance.Symbol.Activate();
}
LocationPoint lop = familyInstance.Location as LocationPoint;
FamilyInstance newFamilyInstance = doc.Create.NewFamilyInstance(level.GetPlaneReference(), lop?.Point, familyInstance.HandOrientation, familyInstance.Symbol);
Definition p = newFamilyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM).Definition;
foreach (Parameter param in familyInstance.Parameters)
{
if (param.IsReadOnly || param.Definition.Name == p.Name)
{
continue;
}
switch (param.StorageType)
{
case StorageType.None:
break;
case StorageType.Integer:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsInteger());
break;
case StorageType.Double:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsDouble());
break;
case StorageType.String:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsString());
break;
case StorageType.ElementId:
newFamilyInstance.get_Parameter(param.Definition).Set(param.AsElementId());
break;
default:
throw new ArgumentOutOfRangeException();
}
}
doc.Delete(familyInstance.Id);
}
else
{
if (baseLevelParam.IsReadOnly == false)
{
baseLevelParam.Set(level.Id);
}
}
}
///
/// 设置族实例
///
/// 标高范围,通过GetRegion方法获得
///
public static List SetInstances(List levels)
{
var levelOutlines = GetRegions(levels);
List errors = new();
var doc = levels.FirstOrDefault().Document;
doc.Invoke(ts =>
{
//对比标高,得到实际分层位置
foreach (KeyValuePair keyPair in levelOutlines)
{
//得到在标高范围内的元素
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
Level level = keyPair.Key;
List insideCollector = new FilteredElementCollector(doc).WherePasses(insideFilter).Where(elem => elem is FamilyInstance && (elem.LevelId != level.Id || elem.get_BoundingBox(doc.ActiveView) != null)).ToList();
foreach (Element elem in insideCollector)
{
try
{
//获取构件定位方式,基于标高,基于主体(基于面,基于线,基于主体构件:墙板等),基于点
if (elem is not FamilyInstance familyInstance)
{
continue;
}
FamilyPlacementType placementType = familyInstance.Symbol.Family.FamilyPlacementType;
switch (placementType)
{
case FamilyPlacementType.OneLevelBased:
ModifyOneLevelBasedFamily(level, familyInstance);
break;
case FamilyPlacementType.OneLevelBasedHosted:
break;
case FamilyPlacementType.TwoLevelsBased:
ModifyTwoLevelBasedFamily(levels, level, familyInstance);
break;
case FamilyPlacementType.ViewBased:
break;
case FamilyPlacementType.WorkPlaneBased:
ModifyWorkPlaneBasedFamily(level, familyInstance);
break;
case FamilyPlacementType.CurveBased:
ModifyCurveBasedFamily(level, familyInstance);
break;
case FamilyPlacementType.CurveBasedDetail:
break;
case FamilyPlacementType.CurveDrivenStructural:
break;
case FamilyPlacementType.Adaptive:
break;
case FamilyPlacementType.Invalid:
break;
}
}
catch (Exception ex)
{
errors.Add(new MessageModel(elem, ex.Message));
}
}
}
}, "校正族实例标高");
return errors;
//if (errors.Any())
//{
// var processorViewModel = new ErrorResolveViewModel(uidoc, errors);
// var errorResolveWin = new ErrorResolveWin(processorViewModel);
// WinDialogAssists.ShowAhead(errorResolveWin);
//}
}
///
/// 设置管线
///
///
public static List SetMEPCurves(List levels)
{
List errors = new();
var doc = levels.FirstOrDefault().Document;
var levelOutlines = GetRegions(levels);
doc.Invoke(ts =>
{
//对比标高,得到实际分层位置
foreach (KeyValuePair keyPair in levelOutlines)
{
//得到在标高范围内的元素
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
Level level = keyPair.Key;
List insideCollector = new FilteredElementCollector(doc).WherePasses(insideFilter).Where(elem => elem.LevelId != level.Id || elem.get_BoundingBox(doc.ActiveView) != null).ToList();
foreach (Element elem in insideCollector)
{
try
{
if (elem is Pipe or Duct or CableTray or Conduit)
{
elem.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM).Set(level.Id);
}
}
catch (Exception ex)
{
errors.Add(new MessageModel(elem, ex.Message));
}
}
}
}, "校正管线标高");
return errors;
}
///
/// 设置墙
///
///
public static List SetWalls(List levels)
{
List errors = new();
var doc = levels.FirstOrDefault().Document;
var levelOutlines = GetRegions(levels);
doc.Invoke(_ =>
{
//对比标高,得到实际分层位置
foreach (KeyValuePair keyPair in levelOutlines)
{
//得到在标高范围内的元素
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
Level level = keyPair.Key;
List insideCollector = new FilteredElementCollector(doc).WherePasses(insideFilter).Where(elem => elem.LevelId != level.Id || elem.get_BoundingBox(doc.ActiveView) != null).ToList();
foreach (Element elem in insideCollector)
{
try
{
if (elem is Wall wall)
{
ModifyWall(doc.ActiveView, levels, level, wall);
}
}
catch (Exception ex)
{
errors.Add(new MessageModel(elem, ex.Message));
}
}
}
}, "校正墙体标高");
return errors;
//if (errors.Any())
//{
// var processorViewModel = new ErrorResolveViewModel(uidoc, errors);
// var errorResolveWin = new ErrorResolveWin(processorViewModel);
// WinDialogAssists.ShowAhead(errorResolveWin);
//}
}
}
}