1314 lines
42 KiB
C#
1314 lines
42 KiB
C#
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Reflection;
|
||
using System.Runtime.CompilerServices;
|
||
using System.Text;
|
||
using System.Windows;
|
||
|
||
using Autodesk.Revit.DB;
|
||
using Autodesk.Revit.DB.Visual;
|
||
using Autodesk.Revit.UI;
|
||
using Autodesk.Revit.UI.Selection;
|
||
|
||
using Sai.Toolkit.Revit.Helpers;
|
||
|
||
namespace Sai.Toolkit.Revit.Assist;
|
||
|
||
public static class DocumentAssist
|
||
{
|
||
/// <summary>
|
||
/// 轴网标注
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="chainDimensionLine"></param>
|
||
/// <param name="extremeWallVariant"></param>
|
||
/// <param name="grids"></param>
|
||
/// <returns></returns>
|
||
public static Dimension CreateDimensionByExtremeGrids(
|
||
this Document doc,
|
||
Line chainDimensionLine,
|
||
ExtremeWallVariant extremeWallVariant,
|
||
List<Grid> grids
|
||
)
|
||
{
|
||
Dimension result;
|
||
if (!grids.Any())
|
||
{
|
||
result = null;
|
||
}
|
||
else
|
||
{
|
||
Dimension dimension = null;
|
||
ReferenceArray referenceArray = new();
|
||
if (extremeWallVariant is ExtremeWallVariant.Left or ExtremeWallVariant.Right)
|
||
{
|
||
var list = (
|
||
from g in grids
|
||
where ((Line)g.Curve).Direction.DotProduct(XYZ.BasisY) < 0.0001
|
||
select g
|
||
).ToList();
|
||
if (list.Any())
|
||
{
|
||
list.Sort((g1, g2) => g1.Curve.GetEndPoint(0).Y.CompareTo(g2.Curve.GetEndPoint(0).Y));
|
||
List<Grid> list2 = [list.First(), list.Last()];
|
||
foreach (var grid in list2)
|
||
{
|
||
referenceArray.Append(new Reference(grid));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var list3 = (
|
||
from g in grids
|
||
where ((Line)g.Curve).Direction.DotProduct(XYZ.BasisX) < 0.0001
|
||
select g
|
||
).ToList();
|
||
if (list3.Any())
|
||
{
|
||
list3.Sort((g1, g2) => g1.Curve.GetEndPoint(0).X.CompareTo(g2.Curve.GetEndPoint(0).X));
|
||
List<Grid> list4 = [list3.First(), list3.Last()];
|
||
foreach (var grid2 in list4)
|
||
{
|
||
referenceArray.Append(new Reference(grid2));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!referenceArray.IsEmpty && referenceArray.Size > 1)
|
||
{
|
||
dimension = doc.Create.NewDimension(doc.ActiveView, chainDimensionLine, referenceArray);
|
||
}
|
||
|
||
result = dimension;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
/// <summary>
|
||
/// 获取所有可预览视图ID
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="doc"></param>
|
||
/// <param name="setting"></param>
|
||
/// <returns></returns>
|
||
public static ElementId FindPreviewId<T>(this Document doc, DocumentPreviewSettings setting) where T : View
|
||
{
|
||
var collector = new FilteredElementCollector(doc).OfClass(typeof(T));
|
||
if (!collector.Any())
|
||
{
|
||
return new FilteredElementCollector(doc).OfClass(typeof(ViewPlan)).FirstElementId();
|
||
}
|
||
|
||
var viewForPreview = collector.OfType<T>().First(v => setting.IsViewIdValidForPreview(v.Id));
|
||
return viewForPreview.Id;
|
||
}
|
||
/// <summary>
|
||
/// 获取标高范围框
|
||
/// </summary>
|
||
/// <remarks>最低标高除了包含以上部分,还包含以下部分,最高标高包含以上部分</remarks>
|
||
/// <param name="doc"></param>
|
||
/// <returns></returns>
|
||
public static Dictionary<Level, Outline> GetLevelRanges(this Document doc)
|
||
{
|
||
var levels = doc.OfClass<Level>().Cast<Level>().OrderBy(l => l.Elevation).ToList();
|
||
Dictionary<Level, Outline> levelOutlines = [];
|
||
//获取标高范围
|
||
for (var i = 0; i < levels.Count; i++)
|
||
{
|
||
var baseLevel = levels[i];
|
||
XYZ min = new(double.MinValue, double.MinValue, baseLevel.Elevation);
|
||
XYZ max;
|
||
Outline outline;
|
||
if (i == 0)
|
||
{
|
||
min = new XYZ(double.MinValue, double.MinValue, double.MinValue);
|
||
var topLevel = levels[i + 1];
|
||
max = new XYZ(double.MaxValue, double.MaxValue, topLevel.Elevation);
|
||
outline = new Outline(min, max);
|
||
}
|
||
else if (i < levels.Count - 1)
|
||
{
|
||
var topLevel = levels[i + 1];
|
||
max = new XYZ(double.MaxValue, double.MaxValue, topLevel.Elevation);
|
||
outline = new Outline(min, max);
|
||
}
|
||
else//最后一个标高以上
|
||
{
|
||
max = new XYZ(double.MaxValue, double.MaxValue, double.MaxValue);
|
||
outline = new Outline(min, max);
|
||
}
|
||
|
||
levelOutlines.Add(baseLevel, outline);
|
||
}
|
||
|
||
return levelOutlines;
|
||
}
|
||
public static Dimension CreateDimensionByOverallWalls(
|
||
this Document doc,
|
||
Line chainDimensionLine,
|
||
IReadOnlyCollection<Wall> sideWalls,
|
||
ExtremeWallVariant extremeWallVariant
|
||
)
|
||
{
|
||
Dimension dimension = null;
|
||
var list = sideWalls.Where(w => w.Orientation.DotProduct(XYZ.BasisX) < 0.0001).ToList();
|
||
var list2 = sideWalls.Where(w => w.Orientation.DotProduct(XYZ.BasisY) < 0.0001).ToList();
|
||
|
||
Dimension result;
|
||
if (!list.Any() && !list2.Any())
|
||
{
|
||
result = null;
|
||
}
|
||
else
|
||
{
|
||
ReferenceArray referenceArray = new();
|
||
if (extremeWallVariant is ExtremeWallVariant.Right or ExtremeWallVariant.Left)
|
||
{
|
||
List<PlanarFace> list3 = [];
|
||
foreach (var wall in list)
|
||
{
|
||
foreach (var planarFace in wall.GetFaces())
|
||
{
|
||
if (planarFace.IsHorizontal())
|
||
{
|
||
list3.Add(planarFace);
|
||
}
|
||
}
|
||
|
||
var elementArray = ((LocationCurve)wall.Location).get_ElementsAtJoin(0);
|
||
var elementArray2 = ((LocationCurve)wall.Location).get_ElementsAtJoin(1);
|
||
List<Wall> list4 = [];
|
||
foreach (Element element in elementArray)
|
||
{
|
||
var wallFromListById = (from w in list where w.Id == element.Id select w).First();
|
||
if (wallFromListById != null)
|
||
{
|
||
list4.Add(wallFromListById);
|
||
}
|
||
}
|
||
|
||
foreach (Element element2 in elementArray2)
|
||
{
|
||
var wallFromListById2 = (from w in list where w.Id == element2.Id select w).First();
|
||
if (wallFromListById2 != null)
|
||
{
|
||
list4.Add(wallFromListById2);
|
||
}
|
||
}
|
||
|
||
foreach (var wall2 in list4)
|
||
{
|
||
foreach (var planarFace2 in wall2.GetFaces())
|
||
{
|
||
if (planarFace2.IsHorizontal())
|
||
{
|
||
list3.Add(planarFace2);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
list3.Sort((f1, f2) => f1.GetMinY().CompareTo(f2.GetMinY()));
|
||
referenceArray.Append(list3.First().Reference);
|
||
referenceArray.Append(list3.Last().Reference);
|
||
}
|
||
|
||
if (extremeWallVariant is ExtremeWallVariant.Top or ExtremeWallVariant.Bottom)
|
||
{
|
||
List<PlanarFace> list5 = [];
|
||
foreach (var wall3 in list2)
|
||
{
|
||
foreach (var planarFace3 in wall3.GetFaces())
|
||
{
|
||
if (planarFace3.IsVertical())
|
||
{
|
||
list5.Add(planarFace3);
|
||
}
|
||
}
|
||
|
||
var elementArray3 = ((LocationCurve)wall3.Location).get_ElementsAtJoin(0);
|
||
var elementArray4 = ((LocationCurve)wall3.Location).get_ElementsAtJoin(1);
|
||
List<Wall> list6 = [];
|
||
foreach (Element element3 in elementArray3)
|
||
{
|
||
var wallFromListById3 = (from w in list where w.Id == element3.Id select w).First();
|
||
if (wallFromListById3 != null)
|
||
{
|
||
list6.Add(wallFromListById3);
|
||
}
|
||
}
|
||
|
||
foreach (Element element4 in elementArray4)
|
||
{
|
||
var wallFromListById4 = (from w in list where w.Id == element4.Id select w).First();
|
||
if (wallFromListById4 != null)
|
||
{
|
||
list6.Add(wallFromListById4);
|
||
}
|
||
}
|
||
|
||
foreach (var wall4 in list6)
|
||
{
|
||
foreach (var planarFace4 in wall4.GetFaces())
|
||
{
|
||
var isVertical2 = planarFace4.IsVertical();
|
||
if (isVertical2)
|
||
{
|
||
list5.Add(planarFace4);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
list5.Sort((f1, f2) => f1.GetMinX().CompareTo(f2.GetMinX()));
|
||
referenceArray.Append(list5[0].Reference);
|
||
referenceArray.Append(list5.Last().Reference);
|
||
}
|
||
|
||
if (!referenceArray.IsEmpty)
|
||
{
|
||
doc.Invoke(_ =>
|
||
{
|
||
dimension = doc.Create.NewDimension(doc.ActiveView, chainDimensionLine, referenceArray);
|
||
});
|
||
}
|
||
|
||
result = dimension;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建房间
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="level"></param>
|
||
/// <param name="phase"></param>
|
||
public static void CreateRoom(this Document doc, Level level, Phase phase)
|
||
{
|
||
// 获取基于标高level的一个视图
|
||
var defaultView = new FilteredElementCollector(doc)
|
||
.OfClass(typeof(View))
|
||
.Cast<View>()
|
||
.FirstOrDefault(v => v.GenLevel != null && v.GenLevel.Id == level.Id);
|
||
// 确保视图不为空
|
||
if (defaultView != null)
|
||
{
|
||
var defaultPhase = defaultView.get_Parameter(BuiltInParameter.VIEW_PHASE);
|
||
if (defaultPhase != null && defaultPhase.AsElementId() == phase.Id)
|
||
{
|
||
var circuits = doc.get_PlanTopology(level, phase).Circuits;
|
||
foreach (PlanCircuit planCircuit in circuits)
|
||
{
|
||
doc.Create.NewRoom(null, planCircuit);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建表格
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="legend"></param>
|
||
/// <param name="rowCount"></param>
|
||
/// <param name="columnCount"></param>
|
||
/// <param name="gridWidth"></param>
|
||
/// <param name="gridHeight"></param>
|
||
public static void CreateTable(
|
||
this Document doc,
|
||
View legend,
|
||
int rowCount,
|
||
int columnCount,
|
||
double gridWidth,
|
||
double gridHeight
|
||
)
|
||
{
|
||
CurveArray curveArray = new();
|
||
|
||
for (var i = 0; i <= rowCount; i++) //水平网格
|
||
{
|
||
var l = Line.CreateBound(XYZ.Zero, XYZ.BasisX * gridWidth * columnCount)
|
||
.CreateOffset(gridHeight * i, -XYZ.BasisZ);
|
||
curveArray.Append(l);
|
||
}
|
||
|
||
Curve line = Line.CreateBound(XYZ.Zero, XYZ.BasisY * rowCount * gridHeight);
|
||
curveArray.Append(line);
|
||
for (var i = 0; i <= columnCount; i++) //垂直网格
|
||
{
|
||
line = line.CreateOffset(gridWidth, XYZ.BasisZ);
|
||
curveArray.Append(line);
|
||
}
|
||
|
||
doc.Create.NewDetailCurveArray(legend, curveArray);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建表格
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="legend">图例视图</param>
|
||
/// <param name="rowCount">行数</param>
|
||
/// <param name="columnCount">列数</param>
|
||
/// <param name="gridHeight">单元格高度</param>
|
||
/// <param name="gridWidths">各列对应的宽度</param>
|
||
public static void CreateTable(
|
||
this Document doc,
|
||
View legend,
|
||
int rowCount,
|
||
int columnCount,
|
||
double gridHeight,
|
||
params double[] gridWidths
|
||
)
|
||
{
|
||
if (columnCount != gridWidths.Length)
|
||
{
|
||
return;
|
||
}
|
||
|
||
CurveArray curveArray = new();
|
||
var totalWidth = 0.0;
|
||
foreach (var w in gridWidths)
|
||
{
|
||
totalWidth += w;
|
||
}
|
||
|
||
for (var i = 0; i <= rowCount; i++) //水平网格
|
||
{
|
||
var c = Line.CreateBound(XYZ.Zero, XYZ.BasisX * totalWidth).CreateOffset(gridHeight * i, -XYZ.BasisZ);
|
||
curveArray.Append(c);
|
||
}
|
||
|
||
Curve line = Line.CreateBound(XYZ.Zero, XYZ.BasisY * rowCount * gridHeight);
|
||
curveArray.Append(line);
|
||
for (var i = 0; i < columnCount; i++) //垂直网格
|
||
{
|
||
line = line.CreateOffset(gridWidths[i], XYZ.BasisZ);
|
||
curveArray.Append(line);
|
||
}
|
||
|
||
doc.Create.NewDetailCurveArray(legend, curveArray);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建表格
|
||
/// </summary>
|
||
/// <param name="legend">图例视图</param>
|
||
/// <param name="rowCount">行数(含标题行)</param>
|
||
/// <param name="columnCount">列数</param>
|
||
/// <param name="headHeight"></param>
|
||
/// <param name="gridHeight">单元格高度</param>
|
||
/// <param name="gridWidths">各单元格对应的宽度</param>
|
||
public static void CreateTable(
|
||
View legend,
|
||
int rowCount,
|
||
int columnCount,
|
||
double headHeight,
|
||
double gridHeight,
|
||
params double[] gridWidths
|
||
)
|
||
{
|
||
var doc = legend.Document;
|
||
if (columnCount != gridWidths.Length)
|
||
{
|
||
MessageBox.Show("列数和提供的列宽数量不一致。", "提示");
|
||
return;
|
||
}
|
||
|
||
CurveArray curveArray = new();
|
||
var totalWidth = 0.0;
|
||
foreach (var w in gridWidths)
|
||
{
|
||
totalWidth += w;
|
||
}
|
||
|
||
for (var i = 0; i <= rowCount - 1; i++) //水平网格
|
||
{
|
||
var c = Line.CreateBound(XYZ.Zero, XYZ.BasisX * totalWidth).CreateOffset(gridHeight * i, -XYZ.BasisZ);
|
||
curveArray.Append(c);
|
||
}
|
||
|
||
//标题行
|
||
var line = Line.CreateBound(XYZ.Zero, XYZ.BasisX * totalWidth)
|
||
.CreateOffset((gridHeight * (rowCount - 1)) + headHeight, -XYZ.BasisZ);
|
||
curveArray.Append(line);
|
||
//列
|
||
line = Line.CreateBound(XYZ.Zero, XYZ.BasisY * (((rowCount - 1) * gridHeight) + headHeight));
|
||
curveArray.Append(line);
|
||
for (var i = 0; i < columnCount; i++) //垂直网格
|
||
{
|
||
line = line.CreateOffset(gridWidths[i], XYZ.BasisZ);
|
||
curveArray.Append(line);
|
||
}
|
||
|
||
doc.Create.NewDetailCurveArray(legend, curveArray);
|
||
}
|
||
|
||
public static void CreateTag(this Document doc, List<Reference> references, TagMode tagMode, bool hasLeader)
|
||
{
|
||
foreach (var refer in references)
|
||
{
|
||
try
|
||
{
|
||
IndependentTag.Create(
|
||
doc,
|
||
doc.ActiveView.Id,
|
||
refer,
|
||
hasLeader,
|
||
tagMode,
|
||
TagOrientation.Horizontal,
|
||
new XYZ(0, 0, 0)
|
||
);
|
||
}
|
||
catch
|
||
{
|
||
// ignored
|
||
}
|
||
}
|
||
}
|
||
|
||
public static void DeleteFamilyType(this Document famdoc)
|
||
{
|
||
// 得到FamilyManager
|
||
var familyMgr = famdoc.FamilyManager;
|
||
if (familyMgr.CurrentType != null)
|
||
{
|
||
// 只有当前族类型存在,我们才能调用下面的删除方法
|
||
familyMgr.DeleteCurrentType();
|
||
// 一般来说,当删除结束后,第一个族类型会成为当前类型,
|
||
// 但是为了确保安全, 建议你显式设置成你需要的类型
|
||
if (familyMgr.Types.Size != 0)
|
||
{
|
||
var type = familyMgr.Types.Cast<FamilyType>().ElementAt(0);
|
||
familyMgr.CurrentType = type;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除定位点重合的族实例
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="cardInstances"></param>
|
||
public static void DeleteOverlapInstance(this Document doc, List<FamilyInstance> cardInstances)
|
||
{
|
||
List<ElementId> idsToDelete = [];
|
||
|
||
foreach (var ins in cardInstances)
|
||
{
|
||
var lp = ins.GetLocXYZ();
|
||
foreach (var card in cardInstances)
|
||
{
|
||
var lpt = card.GetLocXYZ();
|
||
if (!card.Id.Equals(ins.Id) && lp.IsAlmostEqualTo(lpt))
|
||
{
|
||
idsToDelete.Add(ins.Id);
|
||
idsToDelete.Add(card.Id);
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
doc.Delete(idsToDelete);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复制图例
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="legendName"></param>
|
||
/// <param name="viewScale">比例</param>
|
||
/// <returns></returns>
|
||
public static View DuplicateLegend(Document doc, string legendName, int viewScale)
|
||
{
|
||
var legends = doc.OfClass<View>()
|
||
.OfCategory(BuiltInCategory.OST_Views)
|
||
.Cast<View>()
|
||
.Where(v => v.ViewType == ViewType.Legend)
|
||
.ToList();
|
||
|
||
if (!legends.Any())
|
||
{
|
||
MessageBox.Show("当前项目中没有图例", "温馨提示");
|
||
return null;
|
||
}
|
||
|
||
var legendToCopy = legends.FirstOrDefault();
|
||
|
||
var newLegendId = legendToCopy?.Duplicate(ViewDuplicateOption.Duplicate);
|
||
var newLegend = doc.GetElement(newLegendId) as View;
|
||
for (var i = 0; i < 100; i++)
|
||
{
|
||
try
|
||
{
|
||
newLegend!.Name = $"{legendName} {i}";
|
||
break;
|
||
}
|
||
catch (Autodesk.Revit.Exceptions.ArgumentException) { }
|
||
}
|
||
|
||
newLegend!.Scale = viewScale;
|
||
return newLegend;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 翻转工作平面
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="id"></param>
|
||
public static void FlipWorkPlane(this Document doc, ElementId id)
|
||
{
|
||
var fi = (FamilyInstance)doc.GetElement(id);
|
||
if (fi != null)
|
||
{
|
||
fi.IsWorkPlaneFlipped = !fi.IsWorkPlaneFlipped;
|
||
}
|
||
}
|
||
|
||
public static FamilySymbol GetAndActiveDefaultFamilySymbol(this Document doc, string rfaFile)
|
||
{
|
||
var family = GetOrLoadedFamily(doc, rfaFile);
|
||
FamilySymbol symbol = null;
|
||
if (family != null)
|
||
{
|
||
var symbolId = family.GetFamilySymbolIds().FirstOrDefault();
|
||
symbol = doc.GetElement(symbolId) as FamilySymbol;
|
||
Debug.Assert(symbol != null, nameof(symbol) + " != null");
|
||
if (!symbol.IsActive)
|
||
{
|
||
symbol.Activate();
|
||
}
|
||
}
|
||
|
||
return symbol;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取族中的元素
|
||
/// </summary>
|
||
/// <param name="famdoc"></param>
|
||
/// <returns></returns>
|
||
public static List<ElementId> GetFamilySolidForm(this Document famdoc)
|
||
{
|
||
var ids = new List<ElementId>();
|
||
if (famdoc.IsFamilyDocument)
|
||
{
|
||
var solids = new FilteredElementCollector(famdoc)
|
||
.OfClass(typeof(GenericForm))
|
||
.Cast<GenericForm>()
|
||
.Where(x => x.IsSolid)
|
||
.Select(y => y.Id);
|
||
|
||
var fiids = new FilteredElementCollector(famdoc).OfClass(typeof(FamilyInstance)).Select(y => y.Id);
|
||
ids.AddRange(solids);
|
||
ids.AddRange(fiids);
|
||
}
|
||
|
||
return ids;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 填充样式
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="patternName"></param>
|
||
/// <returns></returns>
|
||
public static ElementId GetFillPatternElemId(this Document doc, string patternName)
|
||
{
|
||
var fillPatternElemId = ElementId.InvalidElementId;
|
||
var fecOfFpe = new FilteredElementCollector(doc).OfClass(typeof(FillPatternElement));
|
||
foreach (var element in fecOfFpe.ToElements())
|
||
{
|
||
var fpe = element as FillPatternElement;
|
||
var fp = fpe.GetFillPattern();
|
||
if (null != fp && fp.Name == patternName)
|
||
{
|
||
fillPatternElemId = fpe.Id;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return fillPatternElemId;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取已载入同名族,若无,则载入
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="familyPath"></param>
|
||
/// <returns></returns>
|
||
public static Family GetOrLoadedFamily(this Document doc, string familyPath)
|
||
{
|
||
var family = new FilteredElementCollector(doc)
|
||
.OfClass(typeof(Family))
|
||
.Cast<Family>()
|
||
.FirstOrDefault(f => f.Name == Path.GetFileNameWithoutExtension(familyPath));
|
||
if (family == null && File.Exists(familyPath))
|
||
{
|
||
doc.LoadFamily(familyPath, new LoadFamilyOptions(), out family);
|
||
}
|
||
|
||
return family;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或创建文字类型
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="textSymbolName">文字类型名称</param>
|
||
/// <param name="fontFamily"></param>
|
||
/// <param name="fontSize"></param>
|
||
/// <param name="widthScale"></param>
|
||
/// <returns></returns>
|
||
public static TextNoteType GetOrNewTextNoteType(
|
||
this Document doc,
|
||
string textSymbolName,
|
||
string fontFamily,
|
||
string fontSize,
|
||
string widthScale
|
||
)
|
||
{
|
||
var textNoteType = new FilteredElementCollector(doc)
|
||
.OfClass(typeof(TextNoteType))
|
||
.OfType<TextNoteType>()
|
||
.FirstOrDefault(x => x.Name.Contains(textSymbolName));
|
||
if (textNoteType != null)
|
||
{
|
||
return textNoteType;
|
||
}
|
||
|
||
textNoteType =
|
||
new FilteredElementCollector(doc)
|
||
.OfClass(typeof(TextNoteType))
|
||
.Cast<TextNoteType>()
|
||
.FirstOrDefault()
|
||
?.Duplicate(textSymbolName) as TextNoteType;
|
||
if (textNoteType != null)
|
||
{
|
||
textNoteType.get_Parameter(BuiltInParameter.TEXT_FONT).SetValueString(fontFamily);
|
||
textNoteType.get_Parameter(BuiltInParameter.TEXT_SIZE).SetValueString(fontSize);
|
||
textNoteType.get_Parameter(BuiltInParameter.TEXT_WIDTH_SCALE).SetValueString(widthScale);
|
||
}
|
||
|
||
return textNoteType;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 射线法获取参照
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="vector"></param>
|
||
public static Reference GetSpotDimensionReference(this Document doc, XYZ vector)
|
||
{
|
||
Reference reference = null;
|
||
if (doc.ActiveView is ViewPlan view)
|
||
{
|
||
//可能存在贯穿标高的构件,需修改射线贯穿距离
|
||
#region 视图范围
|
||
|
||
var range = view.GetViewRange();
|
||
var bottomLevel = doc.GetElement(range.GetLevelId(PlanViewPlane.BottomClipPlane)) as Level;
|
||
var b = range.GetOffset(PlanViewPlane.BottomClipPlane);
|
||
var topLevel = doc.GetElement(range.GetLevelId(PlanViewPlane.TopClipPlane)) as Level;
|
||
var t = range.GetOffset(PlanViewPlane.TopClipPlane);
|
||
var bot = bottomLevel.Elevation + b;
|
||
var tt = topLevel.Elevation + t;
|
||
var p1 = new XYZ(vector.X, vector.Y, bot);
|
||
var p2 = new XYZ(vector.X, vector.Y, tt);
|
||
|
||
#endregion 视图范围
|
||
|
||
var v3d = new FilteredElementCollector(doc)
|
||
.OfClass(typeof(View3D))
|
||
.Cast<View3D>()
|
||
.FirstOrDefault(v => !v.IsTemplate);
|
||
|
||
//射线法找到相交的元素
|
||
ReferenceIntersector intersector = new(v3d);
|
||
var refer = intersector.FindNearest(p1, XYZ.BasisZ)?.GetReference();
|
||
var refer1 = intersector.FindNearest(p2, -XYZ.BasisZ)?.GetReference();
|
||
|
||
if (refer != null && refer1 != null)
|
||
{
|
||
reference = refer.GlobalPoint.Z > refer1.GlobalPoint.Z ? refer : refer1;
|
||
}
|
||
}
|
||
|
||
return reference;
|
||
//Line l2 = Line.CreateUnbound(vector, XYZ.BasisZ);
|
||
}
|
||
|
||
/// <summary>
|
||
/// dwg图层隐藏
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="reference">选择的dwg引用,PointOnElement</param>
|
||
/// <param name="graphicStyleId"></param>
|
||
/// <param name="geoElem"></param>
|
||
public static void HideDwgLayer(
|
||
this Document doc,
|
||
Reference reference,
|
||
out ElementId graphicStyleId,
|
||
out GeometryElement geoElem
|
||
)
|
||
{
|
||
var dwg = doc.GetElement(reference) as ImportInstance;
|
||
graphicStyleId = null;
|
||
Options opts =
|
||
new()
|
||
{
|
||
ComputeReferences = true,
|
||
IncludeNonVisibleObjects = true,
|
||
DetailLevel = 0
|
||
};
|
||
geoElem = dwg?.get_Geometry(opts);
|
||
var geoObj = dwg?.GetGeometryObjectFromReference(reference);
|
||
if (
|
||
geoObj != null
|
||
&& geoObj.GraphicsStyleId != ElementId.InvalidElementId
|
||
&& doc.GetElement(geoObj.GraphicsStyleId) is GraphicsStyle gsSelected
|
||
)
|
||
{
|
||
//图层Id
|
||
graphicStyleId = gsSelected.GraphicsStyleCategory.Id;
|
||
|
||
doc.Invoke(
|
||
_ =>
|
||
{
|
||
doc.ActiveView.SetCategoryHidden(gsSelected.GraphicsStyleCategory.Id, true);
|
||
},
|
||
"隐藏图层"
|
||
);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 链接cad
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="linkPaths"></param>
|
||
public static void LinkDwgByPaths(this Document doc, params string[] linkPaths)
|
||
{
|
||
if (doc is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(doc));
|
||
}
|
||
|
||
if (linkPaths is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(linkPaths));
|
||
}
|
||
|
||
var options = new DWGImportOptions { OrientToView = true };
|
||
//var li = linkPaths.ToList();
|
||
//li.ForEach(famdoc.Link(linkPath, options, famdoc.ActiveView, out _));
|
||
foreach (var linkPath in linkPaths)
|
||
{
|
||
doc.Link(linkPath, options, doc.ActiveView, out _);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 链接Revit
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="linkPaths"></param>
|
||
/// <returns></returns>
|
||
public static void LinkRvt(this Document doc, params string[] linkPaths)
|
||
{
|
||
if (doc is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(doc));
|
||
}
|
||
|
||
if (linkPaths is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(linkPaths));
|
||
}
|
||
|
||
foreach (var linkPath in linkPaths)
|
||
{
|
||
var filePath = new FilePath(linkPath);
|
||
var linkOption = new RevitLinkOptions(false);
|
||
var result = RevitLinkType.Create(doc, filePath, linkOption);
|
||
|
||
var instance = RevitLinkInstance.Create(doc, result.ElementId);
|
||
|
||
if (doc.GetElement(instance.GetTypeId()) is not RevitLinkType type)
|
||
{
|
||
return;
|
||
}
|
||
|
||
type.AttachmentType = AttachmentType.Attachment;
|
||
|
||
type.PathType = PathType.Relative;
|
||
}
|
||
}
|
||
|
||
public static void ReadImporterFile(
|
||
this Document revitDoc,
|
||
ShapeImporterSourceFormat sourceFormat,
|
||
BuiltInCategory builtInCategory
|
||
)
|
||
{
|
||
//ofd.Filter = "SAT Files (.sat)|.sat";
|
||
FileOpenDialog ofd = new("*");
|
||
|
||
if (ofd.Show() == ItemSelectionDialogResult.Confirmed)
|
||
{
|
||
ShapeImporter shapeImporter = new() { InputFormat = sourceFormat };
|
||
var mp = ofd.GetSelectedModelPath();
|
||
var fileName = ModelPathUtils.ConvertModelPathToUserVisiblePath(mp);
|
||
var shapes = shapeImporter.Convert(revitDoc, fileName);
|
||
|
||
if (shapes.Count != 0)
|
||
{
|
||
using Transaction tr = new(revitDoc, "创建内建模型");
|
||
tr.Start();
|
||
var dsImportedSat = DirectShape.CreateElement(revitDoc, new ElementId(builtInCategory));
|
||
dsImportedSat.SetShape(shapes);
|
||
|
||
tr.Commit();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除Revit链接
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="linkPaths"></param>
|
||
/// <returns></returns>
|
||
public static void RemoveLinks(this Document doc, params string[] linkPaths)
|
||
{
|
||
if (doc is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(doc));
|
||
}
|
||
|
||
if (linkPaths is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(linkPaths));
|
||
}
|
||
|
||
foreach (var linkPath in linkPaths)
|
||
{
|
||
var links = new FilteredElementCollector(doc).OfClass(typeof(RevitLinkInstance));
|
||
|
||
foreach (var link in links)
|
||
{
|
||
if (link.Name.Split(':').Length != 3)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (link is not RevitLinkInstance instance)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (link.Name == Path.GetFileName(linkPath))
|
||
{
|
||
var type = doc.GetElement(instance.GetTypeId()) as RevitLinkType;
|
||
|
||
type?.Unload(null);
|
||
|
||
doc.Invoke(_ =>
|
||
{
|
||
doc.Delete(instance.Id);
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public static void RenameFamilyType(this Document famdoc, string oldTypeName, string newTypeName)
|
||
{
|
||
if (famdoc.IsFamilyDocument)
|
||
{
|
||
// 得到FamilyManager
|
||
var familyMgr = famdoc.FamilyManager;
|
||
// 族类型的名字,保证在所有族类型中唯一
|
||
var isExist = false;
|
||
foreach (FamilyType t in familyMgr.Types)
|
||
{
|
||
if (t.Name == oldTypeName)
|
||
{
|
||
familyMgr.CurrentType = t;
|
||
familyMgr.RenameCurrentType(newTypeName);
|
||
isExist = true;
|
||
}
|
||
}
|
||
|
||
if (!isExist)
|
||
{
|
||
familyMgr.NewType(newTypeName);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var familySymbol = new FilteredElementCollector(famdoc)
|
||
.WhereElementIsElementType()
|
||
.FirstOrDefault(t => t.Name == oldTypeName);
|
||
if (familySymbol != null)
|
||
{
|
||
familySymbol.Name = newTypeName;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置中心文件
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="centralPath"></param>
|
||
/// <returns></returns>
|
||
public static void SetCentralFile(this Document doc, string centralPath)
|
||
{
|
||
if (doc is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(doc));
|
||
}
|
||
|
||
if (centralPath is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(centralPath));
|
||
}
|
||
|
||
var saveOption = new SaveAsOptions { OverwriteExistingFile = true };
|
||
|
||
var sharingOption = new WorksharingSaveAsOptions
|
||
{
|
||
SaveAsCentral = true,
|
||
OpenWorksetsDefault = SimpleWorksetConfiguration.LastViewed
|
||
};
|
||
|
||
saveOption.SetWorksharingOptions(sharingOption);
|
||
|
||
doc.SaveAs(centralPath, saveOption);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置Revit链接集合
|
||
/// </summary>
|
||
/// <param name="centralPath"></param>
|
||
/// <param name="linkPaths"></param>
|
||
public static void SetLinkList(string centralPath, List<string> linkPaths)
|
||
{
|
||
if (centralPath is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(centralPath));
|
||
}
|
||
|
||
if (linkPaths is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(linkPaths));
|
||
}
|
||
|
||
var transData = TransmissionData.ReadTransmissionData(new FilePath(centralPath));
|
||
|
||
if (transData is null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// If found not the link, don't submit, otherwise throw file writing exception.
|
||
var flag = false;
|
||
|
||
foreach (var referId in transData.GetAllExternalFileReferenceIds())
|
||
{
|
||
var extRef = transData.GetLastSavedReferenceData(referId);
|
||
|
||
if (extRef.ExternalFileReferenceType != ExternalFileReferenceType.RevitLink)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var userPath = ModelPathUtils.ConvertModelPathToUserVisiblePath(extRef.GetPath());
|
||
|
||
var linkPath = linkPaths.FirstOrDefault(w => w != null && userPath.Contains(Path.GetFileName(w)));
|
||
|
||
if (linkPath is null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var elmId = extRef.GetReferencingId();
|
||
|
||
transData.SetDesiredReferenceData(elmId, new FilePath(linkPath), PathType.Relative, true);
|
||
|
||
flag = true;
|
||
}
|
||
|
||
if (!flag)
|
||
{
|
||
return;
|
||
}
|
||
|
||
transData.IsTransmitted = true;
|
||
|
||
TransmissionData.WriteTransmissionData(new FilePath(centralPath), transData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置Revit链接
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="filePaths"></param>
|
||
public static void SetLinks(this Document doc, params string[] filePaths)
|
||
{
|
||
if (doc is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(doc));
|
||
}
|
||
|
||
if (filePaths is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filePaths));
|
||
}
|
||
|
||
foreach (var filePath in filePaths)
|
||
{
|
||
if (!File.Exists(filePath))
|
||
{
|
||
throw new FileNotFoundException(filePath);
|
||
}
|
||
|
||
// main elementFunc modifies repeatedly, so the performance is poor.
|
||
var linkTypes = doc.OfClass<RevitLinkType>().Where(w => filePath.Contains(w.Name));
|
||
|
||
if (linkTypes.FirstOrDefault(f => f.Name.Split('-').Length == 5) is not RevitLinkType type)
|
||
{
|
||
return;
|
||
}
|
||
|
||
type.LoadFrom(new FilePath(filePath), new WorksetConfiguration(WorksetConfigurationOption.OpenLastViewed));
|
||
|
||
type.PathType = PathType.Relative;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除0长度标注
|
||
/// </summary>
|
||
/// <param name="dimension"></param>
|
||
/// <param name="referenceArray"></param>
|
||
/// <returns></returns>
|
||
public static bool TryRemoveZeroes(this Dimension dimension, out ReferenceArray referenceArray)
|
||
{
|
||
referenceArray = new ReferenceArray();
|
||
var document = dimension.Document;
|
||
var isEmpty = dimension.Segments.IsEmpty;
|
||
if (isEmpty)
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
for (var i = 0; i < dimension.NumberOfSegments; i++)
|
||
{
|
||
var dimensionSegment = dimension.Segments.get_Item(i);
|
||
|
||
var value = dimensionSegment.Value;
|
||
if (!(value != null && Math.Abs(value.Value) < 0.0001))
|
||
{
|
||
var isEmpty2 = referenceArray.IsEmpty;
|
||
if (isEmpty2)
|
||
{
|
||
var refer = dimension.References.get_Item(i);
|
||
var element = document.GetElement(refer);
|
||
if (element is Grid or Level)
|
||
{
|
||
refer = new Reference(element);
|
||
}
|
||
|
||
referenceArray.Append(refer);
|
||
}
|
||
|
||
var refer1 = dimension.References.get_Item(i + 1);
|
||
var element1 = document.GetElement(refer1);
|
||
if (element1 is Grid or Level)
|
||
{
|
||
refer1 = new Reference(element1);
|
||
}
|
||
|
||
referenceArray.Append(refer1);
|
||
}
|
||
}
|
||
|
||
return referenceArray.Size < dimension.References.Size;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏或者显示图层
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="reference"></param>
|
||
/// <param name="bl">tr是显示 false是隐藏</param>
|
||
public static void VisLayer(this Document doc, Reference reference, bool bl)
|
||
{
|
||
var element = doc.GetElement(reference);
|
||
//GeometryElement geoElem = elementFunc.get_Geometry(new Options()); //几何图元
|
||
var geoObj = element.GetGeometryObjectFromReference(reference); //几何对象
|
||
if (geoObj.GraphicsStyleId != ElementId.InvalidElementId)
|
||
{
|
||
if (doc.GetElement(geoObj.GraphicsStyleId) is GraphicsStyle gs)
|
||
{
|
||
var targetCategory = gs.GraphicsStyleCategory;
|
||
doc.ActiveView.SetCategoryHidden(targetCategory.Id, bl);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 发光材质
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
public static void GetIllumMaterial(this Document doc)
|
||
{
|
||
var materials = doc.OfClass<Material>().Cast<Material>();
|
||
StringBuilder sb = new();
|
||
|
||
foreach (var material in materials)
|
||
{
|
||
if (doc.GetElement(material.AppearanceAssetId) is AppearanceAssetElement assetElem)
|
||
{
|
||
var asset = assetElem.GetRenderingAsset();
|
||
var prop = asset.FindByName("generic_self_illum_luminance");
|
||
|
||
var d = prop as AssetPropertyDouble;
|
||
if (d?.Value > 0)
|
||
{
|
||
sb.AppendLine(material.Name);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 射线法查找所有的Element
|
||
/// </summary>
|
||
/// <param name="doc">Dcument</param>
|
||
/// <param name="filter">例如:ElementClassFilter filter = new ElementClassFilter(typeof(CableTray))</param>
|
||
/// <param name="targetRef">目标对象</param>
|
||
/// <param name="center">射源</param>
|
||
/// <param name="direction">方向</param>
|
||
/// <returns>返回该射线</returns>
|
||
public static IList<Element> XRayFindAll(
|
||
this Document doc,
|
||
ElementFilter filter,
|
||
FindReferenceTarget targetRef,
|
||
XYZ center,
|
||
XYZ direction
|
||
)
|
||
{
|
||
var view3D = doc.OfClass<View3D>().Cast<View3D>().First(v3 => !v3.IsTemplate);
|
||
var refWithContexts = new ReferenceIntersector(filter, targetRef, view3D).Find(center, direction);
|
||
if (refWithContexts == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var resultElements = new List<Element>();
|
||
foreach (var rwc in refWithContexts)
|
||
{
|
||
var reference = rwc.GetReference();
|
||
var hitElement = doc.GetElement(reference);
|
||
if (hitElement != null)
|
||
{
|
||
resultElements.Add(hitElement);
|
||
}
|
||
}
|
||
|
||
return resultElements;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 射线法查找最近的Element
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
/// <param name="filter">例如:ElementClassFilter filter = new ElementClassFilter(typeof(CableTray))</param>
|
||
/// <param name="targetRef">目标对象</param>
|
||
/// <param name="center">射源</param>
|
||
/// <param name="direction">方向</param>
|
||
/// <param name="hitElement">被击中的Element</param>
|
||
/// <returns>返回该射线</returns>
|
||
public static Line XRayFindNearest(
|
||
this Document doc,
|
||
ElementFilter filter,
|
||
FindReferenceTarget targetRef,
|
||
XYZ center,
|
||
XYZ direction,
|
||
ref Element hitElement
|
||
)
|
||
{
|
||
var view3D = doc
|
||
.OfClass<View3D>()
|
||
.Cast<View3D>()
|
||
.First(v3 => !v3.IsTemplate);
|
||
ReferenceIntersector refIntersector = new(filter, targetRef, view3D);
|
||
var rwc = refIntersector.FindNearest(center, direction);
|
||
if (rwc == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var reference = rwc.GetReference();
|
||
var intersection = reference.GlobalPoint;
|
||
hitElement = doc.GetElement(reference);
|
||
Line result = null;
|
||
if (!center.IsAlmostEqualTo(intersection))
|
||
{
|
||
result = Line.CreateBound(center, intersection);
|
||
}
|
||
else
|
||
{
|
||
hitElement = null;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
#if REVIT2021
|
||
/// <summary>
|
||
/// 修改测量点
|
||
/// </summary>
|
||
/// <param name="doc"></param>
|
||
public static void ResetBasePoint(this Document doc)
|
||
{
|
||
var surveyPoint = BasePoint.GetSurveyPoint(doc);
|
||
var pos = surveyPoint.Position;
|
||
var sharedPos = surveyPoint.SharedPosition;
|
||
//surveyPoint.Position.Subtract(pos);
|
||
|
||
var projectBasePoint = BasePoint.GetProjectBasePoint(doc);
|
||
var pos1 = projectBasePoint.Position;
|
||
var sharePos1 = projectBasePoint.SharedPosition;
|
||
using (Transaction trans = new(doc, "移动测量点"))
|
||
{
|
||
trans.Start();
|
||
|
||
ElementTransformUtils.MoveElement(doc, surveyPoint.Id, sharedPos.Negate());
|
||
doc.Regenerate();
|
||
ElementTransformUtils.MoveElement(doc, surveyPoint.Id, pos.Negate());
|
||
|
||
ElementTransformUtils.MoveElement(doc, projectBasePoint.Id, pos1.Negate());
|
||
projectBasePoint.get_Parameter(BuiltInParameter.BASEPOINT_ANGLETON_PARAM).Set(0);
|
||
trans.Commit();
|
||
}
|
||
if (
|
||
!(
|
||
surveyPoint.SharedPosition.IsAlmostEqualTo(XYZ.Zero)
|
||
&& projectBasePoint.SharedPosition.IsAlmostEqualTo(XYZ.Zero)
|
||
)
|
||
)
|
||
{
|
||
MessageBox.Show("请修改测量点的裁剪状态", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
}
|
||
#endif
|
||
}
|