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("请选择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 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> 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(); list.AddRange(points1); list.AddRange(points2); list.AddRange(points3); list.AddRange(points4); //list = new List() //{ // p1, p2, p3,p4,p5,p6, p7, p8, p9,p10,p11,p12 //}; //}); lists.Add(list); } } Document.Invoke(_ => { var familySymbol = Document .OfClass() .Cast() .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); } }); } /// /// 计算圆弧上的所有自适应布置点角度与整圆(360)的比值[0,1] /// /// 实际起始角度 /// 邻接块角度跨度 /// 标准块角度跨度 /// 数组的数组集合 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] ]; } /// /// 计算起始角度每环的实际起始角度(第一环不用计算就是StartAngle) /// /// 拼装方式 /// 标准块起始角度 /// 错缝变化角度 /// 当前管环面的索引+1 /// 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; } }