257 lines
9.4 KiB
C#
257 lines
9.4 KiB
C#
|
|
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|