Files

727 lines
30 KiB
C#
Raw Permalink Normal View History

2025-09-16 16:06:41 +08:00
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
namespace Szmedi.RvKits.DrawingTools
{
[Transaction(TransactionMode.Manual)]
public class DimensionView3dCmd : ExternalCommand
{
public override void Execute()
{
ViewFamilyType viewFamilyType = new FilteredElementCollector(Document)
.OfClass(typeof(ViewFamilyType))
.Cast<ViewFamilyType>()
.FirstOrDefault(t => t.ViewFamily == ViewFamily.ThreeDimensional);
IEnumerable<Grid> grids = new FilteredElementCollector(Document).OfClass(typeof(Grid)).Cast<Grid>();
View3D myView = null;
int n = 100;
if (!grids.Any())
{
Result = Result.Cancelled;
return;
}
Document.Invoke(
_ =>
{
if (viewFamilyType != null)
{
myView = View3D.CreateIsometric(Document, viewFamilyType.Id);
}
for (int i = 0; i < n; i++)
{
try
{
myView.Name = $"三维轴测视图_{i}";
break;
}
catch (Autodesk.Revit.Exceptions.ArgumentException) { }
}
myView.SaveOrientationAndLock();
List<ModelCurve> mcurves = Create3dGrid(myView, grids);
Document.Regenerate();
CreateDimension(Document, myView, mcurves);
},
"三维标注"
);
UiDocument.ActiveView = myView;
}
/// <summary>
/// 获取族实例所有面(实际为族类型的所有面)
/// </summary>
/// <param name="instance"></param>
/// <param name="options"></param>
/// <returns></returns>
public static List<Face> GetFacesByFamilyInstance(FamilyInstance instance, Options options)
{
List<Face> faces = new();
//根据打开的方式得到几何信息
GeometryElement geometry = instance.get_Geometry(options);
foreach (GeometryObject geomObj in geometry)
{
//geomObj为几何实例
GeometryInstance geomInstance = geomObj as GeometryInstance;
if (geomInstance == null)
{
continue;
}
//族实例未修改过(连接,剪切,复制,扩展)
bool usesSymbolGeometry = instance is not null && !instance.HasModifiedGeometry();
bool bo = instance.HasModifiedGeometry();
GeometryElement instanceGeometry = usesSymbolGeometry
? geomInstance.GetSymbolGeometry()
: geomInstance.GetInstanceGeometry();
if (instanceGeometry != null)
{
//instanceGeometry.GetTransformed();
//从实例中找到实例的几何体
foreach (GeometryObject instObj in instanceGeometry)
{
//三维的实体
Solid instSolid = instObj as Solid;
if (instSolid == null || instSolid.Faces.Size == 0 || instSolid.Edges.Size == 0)
{
continue;
}
foreach (Face face in instSolid.Faces)
{
faces.Add(face);
}
}
}
//geomObj为几何体
Solid solid = geomObj as Solid;
if (solid != null)
{
if (solid.Faces.Size == 0 || solid.Edges.Size == 0)
{
continue;
}
foreach (Face face in solid.Faces)
{
faces.Add(face);
}
}
}
return faces;
}
/// <summary>
/// 获取元素侧面
/// </summary>
/// <param name="elem"></param>
/// <returns></returns>
public static List<Face> GetSideFacesByElement(Element elem)
{
Options opt = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
GeometryElement ge = elem.get_Geometry(opt);
List<Face> lstpf = new();
foreach (GeometryObject obj in ge)
{
Solid solid = obj as Solid;
if (solid != null)
{
foreach (Face face in solid.Faces)
{
PlanarFace pf = face as PlanarFace;
if (pf != null)
{
//点乘即面的法向与Z轴始终垂直
double dotp = pf.FaceNormal.DotProduct(XYZ.BasisZ);
if (dotp is < 1.0e-09 and > (-1.0e-09)) //近似为0
{
lstpf.Add(pf);
}
//if (pf.FaceNormal.CrossProduct(wall.Orientation).IsZeroLength())
//{
// lstpf.Add(pf);
//}
}
CylindricalFace cy = face as CylindricalFace;
if (cy != null)
{
lstpf.Add(cy);
}
}
return lstpf;
}
}
return lstpf;
}
private List<ModelCurve> Create3dGrid(View view, IEnumerable<Grid> grids)
{
Document Document = view.Document;
List<TextNoteType> textnotetypes = new FilteredElementCollector(Document)
.OfClass(typeof(TextNoteType))
.Cast<TextNoteType>()
.ToList();
TextNoteType textnotetype = textnotetypes.FirstOrDefault();
List<ModelCurve> curves = new();
IEnumerable<bool> gridGroups = grids
.GroupBy(g => g.Curve.ComputeDerivatives(0, true).BasisX.Normalize().X)
.Select(s => s.Count() > 1);
Plane plane = Plane.CreateByOriginAndBasis(XYZ.Zero, XYZ.BasisX, XYZ.BasisY);
SketchPlane sketch = SketchPlane.Create(Document, plane);
foreach (Grid grid in grids)
{
Curve curve = grid.Curve;
XYZ startp = curve.GetEndPoint(0);
XYZ endp = curve.GetEndPoint(1);
int radius = 2;
XYZ direction = curve.ComputeDerivatives(0, true).BasisX.Normalize().Negate();
XYZ direction1 = curve.ComputeDerivatives(1, true).BasisX.Normalize();
SketchPlane gridSketch = SketchPlane.Create(Document, new Reference(grid));
XYZ loc = startp + (direction * radius);
XYZ loc1 = endp + (direction1 * radius);
Arc circle = Arc.Create(loc, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
Arc circle1 = Arc.Create(loc1, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
TextNoteOptions options =
new(textnotetype.Id)
{
HorizontalAlignment = HorizontalTextAlignment.Center,
#if REVIT2019 || REVIT2020
VerticalAlignment = VerticalTextAlignment.Middle
#endif
};
//Text.FromStringOriginAndScale(grid.Name, loc, size);
//Text.FromStringOriginAndScale(grid.Name, loc1, size);
TextNote.Create(Document, view.Id, loc, grid.Name, options);
TextNote.Create(Document, view.Id, loc1, grid.Name, options);
ModelCurve gridLine = Document.Create.NewModelCurve(grid.Curve, gridSketch);
Document.Create.NewModelCurve(circle, sketch);
Document.Create.NewModelCurve(circle1, sketch);
curves.Add(gridLine);
}
return curves;
}
internal static MethodInfo GenerateTransientDisplayMethod()
{
Type geometryElementType = typeof(GeometryElement);
MethodInfo[] geometryElementTypeMethods = geometryElementType.GetMethods(
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic
);
MethodInfo method = geometryElementTypeMethods.FirstOrDefault(x => x.Name == "SetForTransientDisplay");
return method;
}
private ReferenceArray RemoveZeroSegements(Wall wall, ReferenceArray wallLengthRefernceArray, Dimension lengthdim)
{
List<Reference> referencesdelete = new();
ReferenceArray finallengthreferenceArray = new();
for (int i = 0; i < lengthdim.NumberOfSegments; i++)
{
if (lengthdim.Segments.get_Item(i).ValueString == "0")
{
if (lengthdim.References.get_Item(i).ElementId == wall.Id)
{
referencesdelete.Add(lengthdim.References.get_Item(i));
}
if (lengthdim.References.get_Item(i + 1).ElementId == wall.Id)
{
referencesdelete.Add(lengthdim.References.get_Item(i + 1));
}
}
}
for (int i = 0; i < wallLengthRefernceArray.Size; i++)
{
bool isContain = false;
Reference reference = wallLengthRefernceArray.get_Item(i);
foreach (Reference referdelete in referencesdelete)
{
if (reference.EqualTo(referdelete))
{
isContain = true;
}
}
if (!isContain)
{
finallengthreferenceArray.Append(reference);
}
}
return finallengthreferenceArray;
}
public void CreateBeamsDimension(Document Document)
{
FilteredElementCollector col = new(Document, Document.ActiveView.Id);
ElementCategoryFilter categoryFilter1 = new(BuiltInCategory.OST_StructuralFraming);
col.WherePasses(categoryFilter1);
IEnumerable<Element> beams = col.GroupBy(g => g.Name).Select(s => s.FirstOrDefault());
foreach (FamilyInstance familyInstance in beams)
{
XYZ loc = (familyInstance.Location as LocationPoint).Point;
List<Face> faces = GetSideFacesByElement(familyInstance);
if (faces.Count == 0) //找不到实例的几何元素时,需从类型集合查找
{
Options options = new() { ComputeReferences = true };
faces = GetFacesByFamilyInstance(familyInstance, options);
for (int i = faces.Count - 1; i >= 0; i--)
{
PlanarFace pf = faces[i] as PlanarFace;
if (pf.FaceNormal.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero))
{
faces.Remove(faces[i]); //移除顶面底面
}
}
}
ReferenceArray referenceArray = new();
ReferenceArrayArray referenceArrayArray = new();
GetParallFacesReferenceArray(faces, faces.FirstOrDefault(), referenceArray, referenceArrayArray);
foreach (ReferenceArray array in referenceArrayArray)
{
PlanarFace face = familyInstance.GetGeometryObjectFromReference(array.get_Item(0)) as PlanarFace;
Line line = Line.CreateUnbound(loc, face.FaceNormal).CreateOffset(600 / 304.8, XYZ.BasisZ) as Line;
Document.Create.NewDimension(Document.ActiveView, line, array);
}
}
}
public void CreateColumnsDimension(Document Document, View view)
{
FilteredElementCollector col = new(Document, view.Id);
ElementCategoryFilter categoryFilter1 = new(BuiltInCategory.OST_StructuralColumns);
ElementCategoryFilter categoryFilter2 = new(BuiltInCategory.OST_Columns);
LogicalOrFilter andFilter = new(categoryFilter1, categoryFilter2);
col.WherePasses(andFilter);
IEnumerable<Element> columns = col.GroupBy(g => g.Name).Select(s => s.FirstOrDefault());
foreach (FamilyInstance familyInstance in columns)
{
XYZ loc = (familyInstance.Location as LocationPoint).Point;
List<Face> faces = GetSideFacesByElement(familyInstance);
if (faces.Count == 0) //找不到实例的几何元素时,需从类型集合查找
{
Options options = new() { ComputeReferences = true };
faces = GetFacesByFamilyInstance(familyInstance, options);
for (int i = faces.Count - 1; i >= 0; i--)
{
if (faces[i] is PlanarFace)
{
PlanarFace pf = faces[i] as PlanarFace;
if (pf.FaceNormal.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero))
{
faces.Remove(faces[i]); //移除顶面底面
}
}
}
}
ReferenceArray referenceArray = new();
ReferenceArrayArray referenceArrayArray = new();
GetParallFacesReferenceArray(faces, faces.FirstOrDefault(), referenceArray, referenceArrayArray);
foreach (ReferenceArray array in referenceArrayArray)
{
if (array.Size == 0)
{
continue;
}
PlanarFace face = familyInstance.GetGeometryObjectFromReference(array.get_Item(0)) as PlanarFace;
Line line = Line.CreateUnbound(loc, face.FaceNormal).CreateOffset(600 / 304.8, XYZ.BasisZ) as Line;
Document.Create.NewDimension(Document.ActiveView, line, array);
}
}
}
private void CreateDimension(Document Document, View view, List<ModelCurve> mcurves)
{
List<Curve> lines = mcurves.Where(c => c is ModelLine).Select(mc => mc.GeometryCurve).ToList();
List<List<Curve>> groups = new();
GetParallLineGroups(lines, groups);
foreach (List<Curve> g in groups)
{
List<Line> gx = g.ConvertAll(x => x as Line);
if (!gx.Any())
{
continue;
}
XYZ direction = gx.FirstOrDefault()?.Direction;
//IOrderedEnumerable<Line> orderedlist = null;
//if (direction.AngleTo(XYZ.BasisX) >= direction.AngleTo(XYZ.BasisY))
//{
// orderedlist = gx.OrderBy(l => l.Direction.X);
//}
//else
//{
// orderedlist = gx.OrderBy(l => l.Direction.Y);
//}
if (g.Count <= 1)
{
continue;
}
Line line =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(0), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1500 / 304.8, XYZ.BasisZ) as Line;
Line line1 =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(1), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1500 / 304.8, XYZ.BasisZ) as Line;
ReferenceArray arrayAll = new();
foreach (Curve l in g)
{
arrayAll.Append(l.Reference);
}
Dimension dimension1 = Document.Create.NewDimension(view, line, arrayAll);
Dimension dimension2 = Document.Create.NewDimension(view, line1, arrayAll);
Document.Regenerate();
Line line3 =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(0), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1000 / 304.8, XYZ.BasisZ) as Line;
Line line4 =
Line.CreateUnbound(g.FirstOrDefault()?.GetEndPoint(1), direction.CrossProduct(XYZ.BasisZ))
.CreateOffset(1000 / 304.8, XYZ.BasisZ) as Line;
ReferenceArray array = new();
array.Append(dimension1.References.get_Item(0));
array.Append(dimension1.References.get_Item(arrayAll.Size - 1));
Document.Create.NewDimension(view, line3, array);
Document.Create.NewDimension(view, line4, array);
Document.Regenerate();
}
}
private void CreateWallDimension(Document Document, View view)
{
FilteredElementCollector wallCol = new FilteredElementCollector(Document, view.Id).OfClass(typeof(Wall));
foreach (Wall wall in wallCol)
{
if (wall.WallType.Kind != WallKind.Basic)
{
continue;
}
LocationCurve loc = wall.Location as LocationCurve;
ReferenceArray wallThickReferenceArray = new();
ReferenceArray wallLengthRefernceArray = new();
List<Face> faces = GetSideFacesByElement(wall);
foreach (Face face in faces)
{
PlanarFace pf = face as PlanarFace;
if (pf == null || face.Reference == null || pf.OrientationMatchesSurfaceOrientation == false)
{
continue;
}
if (pf.FaceNormal.CrossProduct(wall.Orientation).IsAlmostEqualTo(XYZ.Zero))
{
if (Document.GetElement(face.Reference).Id == wall.Id)
{
wallThickReferenceArray.Append(face.Reference);
}
}
else if (pf.FaceNormal.DotProduct(wall.Orientation) < 0.001)
{
wallLengthRefernceArray.Append(face.Reference);
}
}
try
{
int scale = Document.ActiveView.Scale;
Autodesk.Revit.DB.Transform tranform = Autodesk.Revit.DB.Transform.CreateTranslation(
wall.Orientation * scale * 15 / 304.8
);
Line wallcurve = (wall.Location as LocationCurve).Curve as Line;
Line lengthLine = wallcurve.CreateTransformed(tranform) as Line;
Dimension lengthdim = Document.Create.NewDimension(Document.ActiveView, lengthLine, wallLengthRefernceArray);
Document.Regenerate();
ReferenceArray finallengthreferenceArray = RemoveZeroSegements(wall, wallLengthRefernceArray, lengthdim);
Document.Delete(lengthdim.Id);
Document.Create.NewDimension(Document.ActiveView, lengthLine, finallengthreferenceArray);
Line thickLine = Line.CreateUnbound(wallcurve.Evaluate(0.2, true), wall.Orientation);
Dimension thickdim = Document.Create.NewDimension(Document.ActiveView, thickLine, wallThickReferenceArray);
if (lengthdim.Segments.Size > 2)
{
ReferenceArray referenceArray = new();
Reference refer1 = lengthdim.References.get_Item(0);
Reference refer2 = lengthdim.References.get_Item(lengthdim.References.Size - 1);
referenceArray.Append(refer1);
referenceArray.Append(refer2);
Autodesk.Revit.DB.Transform tranform1 = Autodesk.Revit.DB.Transform.CreateTranslation(
wall.Orientation * scale * 25 / 304.8
);
Line lengthLine1 = wallcurve.CreateTransformed(tranform1) as Line;
Document.Create.NewDimension(Document.ActiveView, lengthLine1, referenceArray);
}
}
catch (Exception) { }
}
}
public void GetParallFacesReferenceArray(
List<Face> faces,
Face firstFace,
ReferenceArray referenceArray,
ReferenceArrayArray referenceArrayArray
)
{
if (referenceArrayArray.Size == 0)
{
referenceArrayArray.Append(referenceArray);
}
for (int i = 0; i < faces.Count; i++)
{
if (faces[i] is not PlanarFace)
{
continue;
}
PlanarFace tempFace = faces[i] as PlanarFace;
PlanarFace pf = firstFace as PlanarFace;
XYZ facenormal = pf.FaceNormal;
//把初始的第一个添加进集合
if (tempFace.FaceNormal.CrossProduct(facenormal).IsAlmostEqualTo(XYZ.Zero))
{
referenceArray.Append(tempFace.Reference);
faces.Remove(tempFace);
GetParallFacesReferenceArray(faces, tempFace, referenceArray, referenceArrayArray);
}
if (i == faces.Count() - 1)
{
referenceArray = new ReferenceArray();
GetParallFacesReferenceArray(faces, faces.FirstOrDefault(), referenceArray, referenceArrayArray);
if (!faces.Any())
{
referenceArrayArray.Append(referenceArray);
}
}
}
}
/// <summary>
/// 递归找到所有平行线集合
/// </summary>
public static void GetParallLineGroups(List<Curve> lines, List<List<Curve>> groups)
{
Curve firstLine = lines.FirstOrDefault();
lines = lines.FindAll(curve => curve is Line);
List<Curve> group = new() { firstLine };
groups.Add(group);
Line line = firstLine as Line;
lines.Remove(firstLine);
for (int i = lines.Count - 1; i >= 0; i--)
{
if (lines[i] is not Line)
{
continue;
}
Line tempLine = lines[i] as Line;
if (
tempLine.Direction.CrossProduct(line.Direction).IsAlmostEqualTo(XYZ.Zero)
&& Math.Abs(tempLine.Length - line.Length) < 0.00001
)
{
group.Add(tempLine);
lines.Remove(tempLine);
//GetParallFaces(faces, tempFace, ZoomRBGroup, groups);
}
}
if (lines.Count >= 1)
{
GetParallLineGroups(lines, groups);
}
}
private void TransientGrid(Document Document, Grid grid)
{
double radius = 1.5;
double size = 1.8;
XYZ startp = grid.Curve.GetEndPoint(0);
XYZ endp = grid.Curve.GetEndPoint(1);
XYZ direction = grid.Curve.ComputeDerivatives(0, true).BasisX.Normalize().Negate();
XYZ direction1 = grid.Curve.ComputeDerivatives(1, true).BasisX.Normalize();
XYZ loc = startp + (direction * radius);
XYZ loc1 = endp + (direction1 * radius);
IEnumerable<Curve> text = Text.FromStringOriginAndScale(grid.Name, loc, size);
IEnumerable<Curve> text1 = Text.FromStringOriginAndScale(grid.Name, loc1, size);
Arc circle = Arc.Create(loc, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
Arc circle1 = Arc.Create(loc1, radius, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY);
List<GeometryObject> geoms = new() { grid.Curve, circle, circle1 };
geoms.AddRange(text);
geoms.AddRange(text1);
MethodInfo method = GenerateTransientDisplayMethod();
object[] argsM = new object[4];
argsM[0] = Document;
argsM[1] = ElementId.InvalidElementId;
argsM[2] = geoms;
argsM[3] = ElementId.InvalidElementId;
ElementId transientElementId = (ElementId)method.Invoke(null, argsM);
MessageBox.Show(transientElementId.IntegerValue.ToString(), "元素ID");
//doc.Delete(transientElementId);
}
}
public class TransientElementMaker : ITransientElementMaker
{
private readonly Document _document;
public List<GeometryObject> GeometryObjects { get; set; }
public TransientElementMaker(Document document)
{
_document = document;
}
public void Execute()
{
if (GeometryObjects != null)
{
DirectShape ds = DirectShape.CreateElement(_document, new ElementId(BuiltInCategory.OST_GenericModel));
//CreateUtils.CreateCube(), CreateUtils.CreateSphere()为创建一个立方体与球体Solid,文略
//ds.AppendShape(GeometryObjects);
ds.AppendShape(new List<GeometryObject> { CreateCube() });
}
}
public Solid CreateCube()
{
CurveLoop cubeBaseLines = new();
cubeBaseLines.Append(Line.CreateBound(new XYZ(0, 0, 0), new XYZ(100, 0, 0)));
cubeBaseLines.Append(Line.CreateBound(new XYZ(100, 0, 0), new XYZ(100, 100, 0)));
cubeBaseLines.Append(Line.CreateBound(new XYZ(100, 100, 0), new XYZ(0, 100, 0)));
cubeBaseLines.Append(Line.CreateBound(new XYZ(0, 100, 0), new XYZ(0, 0, 0)));
Solid solidCube = GeometryCreationUtilities.CreateExtrusionGeometry(new List<CurveLoop> { cubeBaseLines }, XYZ.BasisZ, 100);
return solidCube;
}
}
public static class Text
{
public static IEnumerable<Curve> FromStringOriginAndScale(string text, XYZ origin, double scale)
{
//http://msdn.microsoft.com/en-us/library/ms745816(v=vs.110).aspx
List<Curve> crvs = new();
FontFamily font = new("Arial");
FontStyle fontStyle = FontStyles.Normal;
FontWeight fontWeight = FontWeights.Medium;
//if (Bold == true) fontWeight = FontWeights.Bold;
//if (Italic == true) fontStyle = FontStyles.Italic;
// Create the formatted text based on the properties set.
#if REVIT2019||REVIT2020
System.Windows.Media.FormattedText formattedText =
new(
text,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(font, fontStyle, fontWeight, FontStretches.Normal),
1,
Brushes.Black,
1 // This brush does not matter since we use the geometry of the text.
);
#elif REVIT2018
var formattedText = new System.Windows.Media.FormattedText(
text,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(font, fontStyle, fontWeight, FontStretches.Normal),
1,
Brushes.Black // This brush does not matter since we use the geometry of the text.
,
1.25
);
#endif
// Build the geometry object that represents the text.
Geometry textGeometry = formattedText.BuildGeometry(new System.Windows.Point(0, 0));
foreach (PathFigure figure in textGeometry.GetFlattenedPathGeometry().Figures)
{
System.Windows.Point init = figure.StartPoint;
System.Windows.Point a = figure.StartPoint;
System.Windows.Point b;
foreach (PathSegment segment in figure.GetFlattenedPathFigure().Segments)
{
if (segment is System.Windows.Media.LineSegment lineSeg)
{
b = lineSeg.Point;
Line crv = LineBetweenPoints(origin, scale, a, b);
a = b;
crvs.Add(crv);
}
if (segment is PolyLineSegment plineSeg)
{
foreach (System.Windows.Point segPt in plineSeg.Points)
{
Line crv = LineBetweenPoints(origin, scale, a, segPt);
a = segPt;
crvs.Add(crv);
}
}
}
}
return crvs;
}
private static Line LineBetweenPoints(XYZ origin, double scale, System.Windows.Point a, System.Windows.Point b)
{
XYZ pt1 = new((a.X * scale) + origin.X, ((-a.Y + 1) * scale) + origin.Y, origin.Z);
XYZ pt2 = new((b.X * scale) + origin.X, ((-b.Y + 1) * scale) + origin.Y, origin.Z);
Line crv = Line.CreateBound(pt1, pt2);
return crv;
}
}
}