Files
Shrlalgo.RvKits/ShrlAlgoToolkit.RevitAddins/RvIndependent/MetroTunnel/MetroTunnelCmd.cs

328 lines
14 KiB
C#
Raw Normal View History

2024-09-22 11:05:41 +08:00
using System.Windows;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Diagnostics;
using Nice3point.Revit.Toolkit.External;
2025-04-24 20:56:44 +08:00
namespace ShrlAlgoToolkit.RevitAddins.RvIndependent.MetroTunnel;
2024-09-22 11:05:41 +08:00
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.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(ts =>
{
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;
}
}