Files
SzmediTools/Szmedi.RvKits/ModelManager/BaseLevelHelpers.cs
2025-09-16 16:06:41 +08:00

426 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
/// <summary>
/// 基于标高的
/// </summary>
public static class BaseLevelHelpers
{
/// <summary>
/// 获取基于标高的边界
/// </summary>
/// <param name="levelList"></param>
/// <returns></returns>
public static Dictionary<Level, Outline> GetRegions(List<Level> levelList)
{
Dictionary<Level, Outline> 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;
}
/// <summary>
/// 修改基于线的族
/// </summary>
/// <param name="doc"></param>
/// <param name="level"></param>
/// <param name="familyInstance"></param>
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);
}
/// <summary>
/// 修改基于标高的族
/// </summary>
/// <param name="doc"></param>
/// <param name="level"></param>
/// <param name="familyInstance"></param>
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);
}
}
}
/// <summary>
/// 修改基于两个标高的族
/// </summary>
/// <param name="levels"></param>
/// <param name="level"></param>
/// <param name="familyInstance"></param>
public static void ModifyTwoLevelBasedFamily(List<Level> 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);
}
}
}
/// <summary>
/// 修改墙标高
/// </summary>
/// <param name="view"></param>
/// <param name="levels">项目中的所有标高</param>
/// <param name="level"></param>
/// <param name="wall"></param>
public static void ModifyWall(View view, List<Level> levels, Level level, Wall wall)
{
var doc = wall.Document;
var isExist = new FilteredElementCollector(doc)
.OfClass(typeof(FamilyInstance))
.Cast<FamilyInstance>()
.Any(fi => fi.Host?.Id == wall.Id);
var instances = doc.OfType<FamilyInstance>().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);
}
}
/// <summary>
/// 修改基于工作平面的族
/// </summary>
/// <param name="doc"></param>
/// <param name="level"></param>
/// <param name="familyInstance"></param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
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);
}
}
}
/// <summary>
/// 设置族实例
/// </summary>
/// <param name="levelOutlines">标高范围通过GetRegion方法获得</param>
/// <returns></returns>
public static List<MessageModel> SetInstances(List<Level> levels)
{
var levelOutlines = GetRegions(levels);
List<MessageModel> errors = new();
var doc = levels.FirstOrDefault().Document;
doc.Invoke(ts =>
{
//对比标高,得到实际分层位置
foreach (KeyValuePair<Level, Outline> keyPair in levelOutlines)
{
//得到在标高范围内的元素
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
Level level = keyPair.Key;
List<Element> 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);
//}
}
/// <summary>
/// 设置管线
/// </summary>
/// <returns></returns>
public static List<MessageModel> SetMEPCurves(List<Level> levels)
{
List<MessageModel> errors = new();
var doc = levels.FirstOrDefault().Document;
var levelOutlines = GetRegions(levels);
doc.Invoke(ts =>
{
//对比标高,得到实际分层位置
foreach (KeyValuePair<Level, Outline> keyPair in levelOutlines)
{
//得到在标高范围内的元素
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
Level level = keyPair.Key;
List<Element> 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;
}
/// <summary>
/// 设置墙
/// </summary>
/// <returns></returns>
public static List<MessageModel> SetWalls(List<Level> levels)
{
List<MessageModel> errors = new();
var doc = levels.FirstOrDefault().Document;
var levelOutlines = GetRegions(levels);
doc.Invoke(_ =>
{
//对比标高,得到实际分层位置
foreach (KeyValuePair<Level, Outline> keyPair in levelOutlines)
{
//得到在标高范围内的元素
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
Level level = keyPair.Key;
List<Element> 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);
//}
}
}
}