using Autodesk.Revit.Attributes; using Autodesk.Revit.DB; using Autodesk.Revit.UI.Selection; using Nice3point.Revit.Toolkit.External; namespace ShrlAlgoToolkit.RevitAddins.RvCivil; [Transaction(TransactionMode.Manual)] public class SlopedFloorCmd : ExternalCommand { public override void Execute() { Document.Invoke( _ => { Line line1 = null; Line line2 = null; HostObject obj1 = null; HostObject obj2 = null; var refer = UiDocument.Selection.PickObject( ObjectType.Edge, new FuncFilter( elem => elem is HostObject, (r, _) => { obj1 = Document.GetElement(r) as HostObject; var edge = obj1?.GetGeometryObjectFromReference(r) as Edge; if (edge?.AsCurve() is Line l && l.Direction.Z < 0.0001) { line1 = l; return true; } return false; } ), "请选择主体元素其中的一条水平边" ); var elem = Document.GetElement(refer); UiDocument.Selection.PickObject( ObjectType.Edge, new FuncFilter( elem => elem is HostObject && elem.Id != obj1.Id, (r, _) => { obj2 = Document.GetElement(r) as HostObject; var edge1 = obj2?.GetGeometryObjectFromReference(r) as Edge; if ( edge1?.AsCurve() is Line l && l.Direction.Z < 0.0001 && l.Direction.CrossProduct(line1.Direction).IsAlmostEqualTo(XYZ.Zero) && l.Distance(line1.Origin) > Application.ShortCurveTolerance / 304.8 ) { line2 = l; return true; } return false; } ), "请选择与另一条平行的水平边" ); var level1 = Document.GetElement(obj1.LevelId) as Level; var level2 = Document.GetElement(obj2.LevelId) as Level; var baseLevel = level1?.Elevation > level2?.Elevation ? level2 : level1; //基准边,低的边 var lineBase = line1.Origin.Z < line2.Origin.Z ? line1 : line2; var lineAnother = line1.Origin.Z < line2.Origin.Z ? line2 : line1; //if (line1.Origin.Z < line2.Origin.Z) //{ // lineBase = line1; // lineAnother = line2; //} //else //{ // lineBase = line2; // lineAnother = line1; //} var curveArr = new CurveArray(); var planeToProject = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, lineBase.Origin); var p1 = planeToProject.ProjectOf(lineBase.GetEndPoint(0)); var p2 = planeToProject.ProjectOf(lineBase.GetEndPoint(1)); var p3 = planeToProject.ProjectOf(lineAnother.GetEndPoint(0)); var p4 = planeToProject.ProjectOf(lineAnother.GetEndPoint(1)); Line l1; Line l2; Line l3; Line l4; if (lineBase.Direction.IsAlmostEqualTo(lineAnother.Direction)) { l1 = Line.CreateBound(p1, p2); l3 = Line.CreateBound(p4, p3); l4 = Line.CreateBound(p3, p1); l2 = Line.CreateBound(p2, p4); } else { l1 = Line.CreateBound(p1, p2); l3 = Line.CreateBound(p3, p4); l4 = Line.CreateBound(p4, p1); l2 = Line.CreateBound(p2, p3); } curveArr.Append(l1); curveArr.Append(l2); curveArr.Append(l3); curveArr.Append(l4); //var isStructure = obj1.get_Parameter(BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL).AsInteger(); //选择线的中点连线 var centerLine = Line.CreateBound(lineBase.Evaluate(0.5, true), lineAnother.Evaluate(0.5, true)); //中线和边线叉乘,求出楼板面的法向量 var floorNormal = lineBase.Direction.CrossProduct(centerLine.Direction); if (floorNormal.Z < 0) { floorNormal = floorNormal.Negate(); } //坡度角 var radian = floorNormal.AngleTo(XYZ.BasisZ); //另一条楼板边垂直xy的平面 var normal = lineAnother.Direction.CrossProduct(XYZ.BasisZ); var plane = Plane.CreateByNormalAndOrigin(normal, lineAnother.Evaluate(0.5, true)); //点与平面的距离 var centerPoint = lineBase.Evaluate(0.5, true); var perpPoint = plane.ProjectOf(centerPoint); var slopedArrow = Line.CreateBound(centerPoint, new XYZ(perpPoint.X, perpPoint.Y, centerPoint.Z)); //if (lineBase.Origin.Z > lineAnother.Origin.Z) //{ // slopedArrow = slopedArrow.CreateReversed() as Line; //} //即板上表面法向量和Z轴正向之间 //double radian = slopedArrow.Direction.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ); //double slope = Math.Abs(line1.Evaluate(0.5, true).Z - line2.Evaluate(0.5, true).Z); //slopedArrow用以指定在XY平面上绘制的板轮廓,是沿着哪个方向进行坡度变化的。因此,这条线实际上是XY平面上,垂直于板上表面与XY平面交线的一条线。 #if REVIT2018 || REVIT2020 Document.Create.NewSlab(curveArr, baseLevel, slopedArrow, Math.Tan(radian), true); #elif REVIT2025 var floorType = Floor.GetDefaultFloorType(Document, false); if (elem is Floor floor) { floorType = floor.GetTypeId(); } var loops = new List() { CurveLoop.Create(new List() { l1, l2, l3, l4 }) }; Floor.Create(Document, loops, floorType, baseLevel.Id, true, slopedArrow, Math.Tan(radian)); #endif }, "坡度楼板" ); } private static bool IfSameHeight(List vs) { //判断楼板中各端点标高是否相等 List list = new(); foreach (var z in vs) { if (list.Contains(z) == false) { list.Add(z); } } return list.Count == 1; } //编辑子图元 private void EditSubElements(Floor floor) { #if REVIT2018 || REVIT2020 var slabShapeEditor = floor.SlabShapeEditor; #elif REVIT2025 var slabShapeEditor = floor.GetSlabShapeEditor(); #endif if (slabShapeEditor.IsEnabled) { var vertices = slabShapeEditor.SlabShapeVertices; var zList = new List(); foreach (SlabShapeVertex slabShapeVertex in vertices) { zList.Add(slabShapeVertex.Position.Z); } //判断为水平板后重设形状 if (IfSameHeight(zList)) { var floorLevel = floor.Document.GetElement(floor.LevelId) as Level; //获取楼板所在标高 var levelHeight = floorLevel.LookupParameter("立面").AsDouble(); //获取所在标高的标高 var offsetHeight = zList.FirstOrDefault() - levelHeight; floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(offsetHeight); slabShapeEditor.ResetSlabShape(); } } } }