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

257 lines
9.4 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.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Nice3point.Revit.Toolkit.External;
using System;
using System.Linq;
namespace Szmedi.RvKits.Civil;
[Transaction(TransactionMode.Manual)]
public class SlopedFloorCmd : ExternalCommand
{
public override void Execute()
{
#region SelectExecute
using Transaction trans = new(Document, "坡度楼板");
try
{
Line line1 = null;
Line line2 = null;
HostObject obj1 = null;
HostObject obj2 = null;
UiDocument.Selection.PickObject(
ObjectType.Edge,
new FuncFilter(
elem => elem is HostObject,
(r, p) =>
{
obj1 = Document.GetElement(r) as HostObject;
Edge edge = obj1.GetGeometryObjectFromReference(r) as Edge;
if (edge.AsCurve() is Line l && l.Direction.Z < 0.0001)
{
line1 = l;
return true;
}
return false;
}
),
"请选择主体图元其中的一条水平边"
);
UiDocument.Selection.PickObject(
ObjectType.Edge,
new FuncFilter(
elem => elem is HostObject && elem.Id.IntegerValue != obj1.Id.IntegerValue,
(r, p) =>
{
obj2 = Document.GetElement(r) as HostObject;
Edge 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)
)
{
line2 = l;
return true;
}
return false;
}
),
"请选择另一个主体图元的水平边(与第一条平行)"
);
Level level1 = Document.GetElement(obj1.LevelId) as Level;
Level level2 = Document.GetElement(obj2.LevelId) as Level;
Level baseLevel = level1.Elevation > level2.Elevation ? level2 : level1;
//基准边,低的边
Line lineBase;
Line lineAnother;
if (line1.Origin.Z < line2.Origin.Z)
{
lineBase = line1;
lineAnother = line2;
}
else
{
lineBase = line2;
lineAnother = line1;
}
CurveArray curveArr = new();
Plane planeToProject = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, lineBase.Origin);
SignedDistanceTo(planeToProject, lineBase.GetEndPoint(0), out XYZ p1);
SignedDistanceTo(planeToProject, lineBase.GetEndPoint(1), out XYZ p2);
SignedDistanceTo(planeToProject, lineAnother.GetEndPoint(0), out XYZ p3);
SignedDistanceTo(planeToProject, lineAnother.GetEndPoint(1), out XYZ p4);
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);
}
trans.Start();
curveArr.Append(l1);
curveArr.Append(l2);
curveArr.Append(l3);
curveArr.Append(l4);
//var isStructure = obj1.get_Parameter(BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL).AsInteger();
//选择线的中点连线
Line centerLine = Line.CreateBound(lineBase.Evaluate(0.5, true), lineAnother.Evaluate(0.5, true));
//中线和边线叉乘,求出楼板面的法向量
XYZ floorNormal = lineBase.Direction.CrossProduct(centerLine.Direction);
if (floorNormal.Z < 0)
{
floorNormal = floorNormal.Negate();
}
//坡度角
double radian = floorNormal.AngleTo(XYZ.BasisZ);
//另一条楼板边垂直xy的平面
XYZ normal = lineAnother.Direction.CrossProduct(XYZ.BasisZ);
Plane plane = Plane.CreateByNormalAndOrigin(normal, lineAnother.Evaluate(0.5, true));
//点与平面的距离
XYZ centerPoint = lineBase.Evaluate(0.5, true);
double distance = SignedDistanceTo(plane, centerPoint, out XYZ perpPoint);
Line 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平面交线的一条线。
Document.Create.NewSlab(curveArr, baseLevel, slopedArrow, Math.Tan(radian), true);
trans.Commit();
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
if (trans.GetStatus() == TransactionStatus.Started)
{
trans.Commit();
}
}
catch (Exception ex)
{
ErrorMessage = ex.Message;
if (trans.GetStatus() == TransactionStatus.Started)
{
trans.RollBack();
}
Result = Result.Failed;
}
#endregion SelectExecute
}
public bool IfSameHeight(List<double> vs)
{
//判断楼板中各端点标高是否相等
List<double> list = new();
foreach (double z in vs)
{
if (list.Contains(z) == false)
{
list.Add(z);
}
}
return list.Count == 1;
}
/// <summary>
/// 得到垂足
/// </summary>
/// <param name="p0"></param>
/// <param name="p1"></param>
/// <param name="pX">经过该点作与p0,p1所在直线的垂线</param>
/// <returns></returns>
public static XYZ PerpIntersection(XYZ pX, XYZ p0, XYZ p1)
{
//直线向量和p0点到px点的点积
XYZ v0 = pX - p0;
XYZ v1 = p1 - p0;
double dotProduct = v0.DotProduct(v1); //|v0||v1|cos α
double length = v1.GetLength(); //直线的长度|v1|
XYZ normalize = v1 / length; //直线单位向量
double m = dotProduct / length; //垂足的模
return (normalize * m) + p0;
//var nu3 = nu / (nu2 * nu2);
//XYZ result = p0 + v1 * nu3;
//return result;
//double num = (pX.X - p0.X) * (p1.X - p0.X) + (pX.Y - p0.Y) * (p1.Y - p0.Y) + (pX.Z - p0.Z) * (p1.Z - p0.Z);
//double num2 = p0.DistanceTo(p1);//直线的长度
//num /= num2 * num2;
//return new XYZ(p0.X + num * (p1.X - p0.X), p0.Y + num * (p1.Y - p0.Y), p0.Z + num * (p1.Z - p0.Z));
}
private void EditSubElements(Floor floor)
{
SlabShapeEditor slabShapeEditor = floor.SlabShapeEditor;
if (slabShapeEditor.IsEnabled)
{
SlabShapeVertexArray vertices = slabShapeEditor.SlabShapeVertices;
List<double> z_list = new();
foreach (SlabShapeVertex slabShapeVertex in vertices)
{
z_list.Add(slabShapeVertex.Position.Z);
}
//判断为水平板后重设形状
if (IfSameHeight(z_list))
{
Level floor_level = floor.Document.GetElement(floor.LevelId) as Level; //获取楼板所在标高
double level_height = double.Parse(floor_level.LookupParameter("立面").AsValueString()); //获取所在标高的标高
double offset_height = (z_list.FirstOrDefault() * 304.8) - level_height;
floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).SetValueString(offset_height.ToString());
slabShapeEditor.ResetSlabShape();
}
}
}
/// <summary>
/// 点与平面的距离
/// </summary>
/// <param name="plane"></param>
/// <param name="p"></param>
/// <param name="projectPoint"></param>
/// <returns></returns>
private double SignedDistanceTo(Plane plane, XYZ p, out XYZ projectPoint)
{
XYZ v = p - plane.Origin;
//垂向距离(可正可负,夹角钝角为负)
double perp = v.DotProduct(plane.Normal);
projectPoint = p - (perp * plane.Normal);
return plane.Normal.DotProduct(v);
}
}