Files
Shrlalgo.RvKits/ShrlAlgoToolkit.RevitAddins/RvIndependent/MetroTunnel/MetroTunnelCmd.cs
2025-12-23 21:35:54 +08:00

327 lines
14 KiB
C#
Raw 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 System.Windows;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Diagnostics;
using Nice3point.Revit.Toolkit.External;
namespace ShrlAlgoToolkit.RevitAddins.RvIndependent.MetroTunnel;
[Transaction(TransactionMode.Manual)]
public class MetroTunnelCmd : ExternalCommand
{
public override void Execute()
{
MetroTunnelViewModel viewModel = new();
MetroTunnelView view = new(viewModel);
view.ShowDialog();
if (view.DialogResult == false)
{
Result = Result.Cancelled;
return;
}
var importInstance = UiDocument.SelectObject<ImportInstance>("请选择dwg实例");
if (importInstance == null || !importInstance.Category.Name.EndsWith(".dwg"))
{
MessageBox.Show("请选择dwg隧道中心线", "提示");
Result = Result.Cancelled;
return;
}
var curves = importInstance.GetCurves();
if (curves.Count == 0)
{
ErrorMessage = "所选dwg参照不存在曲线";
Result = Result.Failed;
return;
}
List<XYZ> points = [];
//精度,每条曲线均分数
double precision = 3;
for (var i = 0; i < curves.Count; i++)
{
var curve = curves[i];
//points.Add(curve.GetEndPoint(0));
if (curve is Arc)
{
for (var j = 0; j < precision; j++)
{
points.Add(curve.Evaluate(j / precision, true));
}
}
if (i == curves.Count - 1)
{
points.Add(curve.GetEndPoint(1));
}
}
var spline = HermiteSpline.Create(points, false);
//var dividePoint = spline.Divide();
//起始角度
var startAngle = viewModel.StartAngle;
//前邻接块角度
var frontBehindAngle = viewModel.FrontTubeAngle;
//后邻接块角度
var backBehindAngle = viewModel.BackTubeAngle;
//标准块角度
var standardAngle = viewModel.StandardTubeAngle;
//管片宽度
var width = viewModel.TubeWidth / 304.8;
//管片厚度
var thickness = viewModel.TubeThickness / 304.8;
//大圆半径
var outerDiameter = viewModel.TubeOuterDiameter / 304.8;
;
//小圆半径
var interDiameter = outerDiameter - (2 * thickness);
//错缝变化角度
var switchAngle = viewModel.StaggerAngle;
SegmentPlacementType placementType = 0;
var num = Math.Floor(spline.Length / width);
List<List<XYZ>> lists = [];
for (var i = 0; i < num - 1; i++)
{
//var p1 = spline.Evaluate(i * 2000 / 304.8, false);
//if (spline.IsInsideEx((i + 1) * 2000 / 304.8))
//{
// var p2 = spline.Evaluate((i + 1) * 2000 / 304.8, false);
//}
//basicX为切向量basicY为法向量垂直该点basicZ为basicX叉乘basicY
var transform1 = spline.ComputeDerivatives(i * width, false);
var transform2 = spline.ComputeDerivatives((i + 1) * width, false);
//Frame frame1 = new Frame();
//frame1.Transform(transform1);
//平面法向与路线曲线方向相反,即平面法向面向人视角,在创建圆时才能保证角度旋转准确
//var frontPlane = Plane.CreateByNormalAndOrigin(-transform1.BasisX, transform1.Origin);
var frontRight = transform1.BasisX.CrossProduct(XYZ.BasisZ).Normalize();
var frontTop = frontRight.CrossProduct(transform1.BasisX).Normalize();
var frontPlane = Plane.CreateByOriginAndBasis(transform1.Origin, frontRight, frontTop);
//Frame frame2 = new Frame();
//frame1.Transform(transform2);
//var backPlane = Plane.CreateByNormalAndOrigin(transform2.BasisX, transform2.Origin);
var backRight = transform2.BasisX.CrossProduct(XYZ.BasisZ).Normalize();
var backTop = backRight.CrossProduct(transform2.BasisX).Normalize();
var backPlane = Plane.CreateByOriginAndBasis(transform2.Origin, backRight, backTop);
var frontOuterCircle = Arc.Create(frontPlane, outerDiameter / 2, 0, Math.PI * 2);
var frontInnerCircle = Arc.Create(frontPlane, interDiameter / 2, 0, Math.PI * 2);
var backOuterCircle = Arc.Create(backPlane, outerDiameter / 2, 0, Math.PI * 2);
var backInnerCircle = Arc.Create(backPlane, interDiameter / 2, 0, Math.PI * 2);
//frontOuterCircle.MakeBound(0, frontOuterCircle.Length);
//frontInnerCircle.MakeBound(0, frontInnerCircle.Length);
//backOuterCircle.MakeBound(0, backOuterCircle.Length);
//backInnerCircle.MakeBound(0, backInnerCircle.Length);
//doc.Invoke(ts =>
//{
// if (i < 10)
// {
// doc.Create.NewModelCurve(frontFaceOuterCircle, sk1);
// doc.Create.NewModelCurve(frontFaceInnerCircle, sk1);
// doc.Create.NewModelCurve(backFaceOuterCircle, sk2);
// doc.Create.NewModelCurve(backFaceInnerCircle, sk2);
// }
//});
var actuallyFrontStartAngle = MetroTunnelCmd.GetReallyStartAngle(placementType, startAngle, switchAngle, i);
var actuallyBackStartAngle = MetroTunnelCmd.GetReallyStartAngle(placementType, startAngle, switchAngle, i + 1);
var param = MetroTunnelCmd.CurveParameters(actuallyFrontStartAngle, frontBehindAngle, standardAngle);
var param1 = MetroTunnelCmd.CurveParameters(actuallyBackStartAngle, backBehindAngle, standardAngle);
for (var j = 0; j < param.Length; j++)
{
var paramF = param[j];
var paramB = param1[j];
//doc.Invoke(_ =>
//{
//var sk1 = SketchPlane.Create(doc, frontPlane);
//var sk2 = SketchPlane.Create(doc, backPlane);
//var p1 = frontInnerCircle.Evaluate(paramF[0], true);
//var p2 = frontInnerCircle.Evaluate(paramF[1], true);
//var p3 = frontInnerCircle.Evaluate(paramF[2], true);
var arc1 = Arc.Create(
frontPlane,
interDiameter / 2,
(paramF[0] > paramF[2] ? paramF[0] - 1 : paramF[0]) * 360.0.ToRadian(),
paramF[2] * 360.0.ToRadian()
);
var points1 = arc1.GetEquivalentPoints(2);
//var mc1 = doc.Create.NewModelCurve(arc1, sk1);
//var l1 = mc1.GeometryCurve.Length;
//var p4 = backInnerCircle.Evaluate(paramB[0], true);
//var p5 = backInnerCircle.Evaluate(paramB[1], true);
//var p6 = backInnerCircle.Evaluate(paramB[2], true);
var arc2 = Arc.Create(
backPlane,
interDiameter / 2,
(paramB[0] > paramB[2] ? paramB[0] - 1 : paramB[0]) * 360.0.ToRadian(),
paramB[2] * 360.0.ToRadian()
);
//var mc2 = doc.Create.NewModelCurve(arc2, sk2);
var points2 = arc2.GetEquivalentPoints(2);
//if (j == 0)
//{
// doc.Create.NewModelCurve(Arc.Create(p1, 2, 0, 2 * Math.PI, frontPlane.XVec, frontPlane.YVec), sk1);
// doc.Create.NewModelCurve(Arc.Create(frontInnerCircle.Evaluate(0, true), 2, 0, 2 * Math.PI, frontPlane.XVec, frontPlane.YVec), sk1);
// doc.Create.NewModelCurve(frontOuterCircle, sk1);
// doc.Create.NewModelCurve(Arc.Create(p2, 2, 0, 2 * Math.PI, frontPlane.XVec, frontPlane.YVec), sk1);
// doc.Create.NewModelCurve(Arc.Create(p3, 2, 0, 2 * Math.PI, frontPlane.XVec, frontPlane.YVec), sk1);
// doc.Create.NewModelCurve(Line.CreateBound(frontPlane.Origin, frontPlane.Origin + frontPlane.XVec), sk1);
// doc.Create.NewModelCurve(Line.CreateBound(frontPlane.Origin, frontPlane.Origin + frontPlane.YVec), sk1);
// //doc.Create.NewModelCurve(Arc.Create(backInnerCircle.Evaluate(0, true), 2, 0, 2 * Math.PI, frontPlane.XVec, frontPlane.YVec), sk2);
//}
//var l2 = mc2.GeometryCurve.Length;
//var p7 = frontOuterCircle.Evaluate(paramF[0], true);
//var p8 = frontOuterCircle.Evaluate(paramF[1], true);
//var p9 = frontOuterCircle.Evaluate(paramF[2], true);
//doc.Create.NewModelCurve(Arc.Create(p7, p9, p8), sk1);
//var p10 = backOuterCircle.Evaluate(paramB[0] , true);
//var p11 = backOuterCircle.Evaluate(paramB[1], true);
//var p12 = backOuterCircle.Evaluate(paramB[2], true);
//doc.Create.NewModelCurve(Arc.Create(p10, p12, p11), sk2);
var arc3 = Arc.Create(
frontPlane,
outerDiameter / 2,
(paramF[0] > paramF[2] ? paramF[0] - 1 : paramF[0]) * 360.0.ToRadian(),
paramF[2] * 360.0.ToRadian()
);
var points3 = arc3.GetEquivalentPoints(2);
var arc4 = Arc.Create(
backPlane,
outerDiameter / 2,
(paramB[0] > paramB[2] ? paramB[0] - 1 : paramB[0]) * 360.0.ToRadian(),
paramB[2] * 360.0.ToRadian()
);
var points4 = arc4.GetEquivalentPoints(2);
var list = new List<XYZ>();
list.AddRange(points1);
list.AddRange(points2);
list.AddRange(points3);
list.AddRange(points4);
//list = new List<XYZ>()
//{
// p1, p2, p3,p4,p5,p6, p7, p8, p9,p10,p11,p12
//};
//});
lists.Add(list);
}
}
Document.Invoke(_ =>
{
var familySymbol = Document
.OfClass<FamilySymbol>()
.Cast<FamilySymbol>()
.First(
symbol => symbol.Name == "盾构管片" && AdaptiveComponentInstanceUtils.IsAdaptiveFamilySymbol(symbol)
);
if (!familySymbol.IsActive)
{
familySymbol.Activate();
}
for (var i = 0; i < lists.Count; i++)
{
var list = lists[i];
if (i == 100)
{
return;
}
familySymbol.CreateAdaptiveComponent(list);
}
});
}
/// <summary>
/// 计算圆弧上的所有自适应布置点角度与整圆360的比值[0,1]
/// </summary>
/// <param name="startAngle">实际起始角度</param>
/// <param name="behindAngle">邻接块角度跨度</param>
/// <param name="standardAngle">标准块角度跨度</param>
/// <returns>数组的数组集合</returns>
private static double[][] CurveParameters(double startAngle, double behindAngle, double standardAngle)
{
var x = startAngle / 360;
//封顶块
var fdq = 360 - (standardAngle * 3) - (behindAngle * 2);
Guard.IsGreaterThan(fdq, 0, "封顶块角度跨度不能为负");
var a0 = startAngle + behindAngle;
var b0 = a0 + fdq;
var c0 = b0 + behindAngle;
var d0 = c0 + standardAngle;
var e0 = d0 + standardAngle;
var aq = a0 / 360;
var bq = b0 / 360;
var cq = c0 / 360;
var dq = d0 / 360;
var eq = e0 / 360;
var xaq = (x + aq) / 2;
var abq = (aq + bq) / 2;
var bcq = (bq + cq) / 2;
var cdq = (cq + dq) / 2;
var deq = (dq + eq) / 2;
var con = (eq - 1 + x) / 2;
var exq = con < 0 ? 1 + con : con;
return
[
[x, xaq, aq],
[aq, abq, bq],
[bq, bcq, cq],
[cq, cdq, dq],
[dq, deq, eq],
[eq, exq, x]
];
}
/// <summary>
/// 计算起始角度每环的实际起始角度第一环不用计算就是StartAngle
/// </summary>
/// <param name="placementType">拼装方式</param>
/// <param name="startAngle">标准块起始角度</param>
/// <param name="switchAngle">错缝变化角度</param>
/// <param name="currentFaceNumber">当前管环面的索引+1</param>
/// <returns></returns>
private static double GetReallyStartAngle(
SegmentPlacementType placementType,
double startAngle,
double switchAngle,
int currentFaceNumber
)
{
double result = default;
switch (placementType)
{
case SegmentPlacementType.Common:
result = startAngle + (switchAngle * (0.5 - (0.5 * Math.Pow(1, currentFaceNumber))));
break;
case SegmentPlacementType.Swing:
result = startAngle + (switchAngle * (0.5 + (0.5 * Math.Pow(-1, currentFaceNumber))));
break;
case SegmentPlacementType.ClockWise:
result = startAngle + (switchAngle * (currentFaceNumber - 1));
break;
case SegmentPlacementType.CounterClockWise:
result =
startAngle
- (switchAngle * (currentFaceNumber - 1))
- (Math.Floor((startAngle - (switchAngle * (currentFaceNumber - 1))) / 360) * 360);
break;
}
return result;
}
}