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() .FirstOrDefault(t => t.ViewFamily == ViewFamily.ThreeDimensional); IEnumerable grids = new FilteredElementCollector(Document).OfClass(typeof(Grid)).Cast(); 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 mcurves = Create3dGrid(myView, grids); Document.Regenerate(); CreateDimension(Document, myView, mcurves); }, "三维标注" ); UiDocument.ActiveView = myView; } /// /// 获取族实例所有面(实际为族类型的所有面) /// /// /// /// public static List GetFacesByFamilyInstance(FamilyInstance instance, Options options) { List 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; } /// /// 获取元素侧面 /// /// /// public static List GetSideFacesByElement(Element elem) { Options opt = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine }; GeometryElement ge = elem.get_Geometry(opt); List 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 Create3dGrid(View view, IEnumerable grids) { Document Document = view.Document; List textnotetypes = new FilteredElementCollector(Document) .OfClass(typeof(TextNoteType)) .Cast() .ToList(); TextNoteType textnotetype = textnotetypes.FirstOrDefault(); List curves = new(); IEnumerable 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 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 beams = col.GroupBy(g => g.Name).Select(s => s.FirstOrDefault()); foreach (FamilyInstance familyInstance in beams) { XYZ loc = (familyInstance.Location as LocationPoint).Point; List 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 columns = col.GroupBy(g => g.Name).Select(s => s.FirstOrDefault()); foreach (FamilyInstance familyInstance in columns) { XYZ loc = (familyInstance.Location as LocationPoint).Point; List 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 mcurves) { List lines = mcurves.Where(c => c is ModelLine).Select(mc => mc.GeometryCurve).ToList(); List> groups = new(); GetParallLineGroups(lines, groups); foreach (List g in groups) { List gx = g.ConvertAll(x => x as Line); if (!gx.Any()) { continue; } XYZ direction = gx.FirstOrDefault()?.Direction; //IOrderedEnumerable 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 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 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); } } } } /// /// 递归找到所有平行线集合 /// public static void GetParallLineGroups(List lines, List> groups) { Curve firstLine = lines.FirstOrDefault(); lines = lines.FindAll(curve => curve is Line); List 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 text = Text.FromStringOriginAndScale(grid.Name, loc, size); IEnumerable 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 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 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 { 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 { cubeBaseLines }, XYZ.BasisZ, 100); return solidCube; } } public static class Text { public static IEnumerable FromStringOriginAndScale(string text, XYZ origin, double scale) { //http://msdn.microsoft.com/en-us/library/ms745816(v=vs.110).aspx List 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; } } }