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-02-10 20:53:40 +08:00
|
|
|
|
|
2025-04-24 20:56:44 +08:00
|
|
|
|
namespace ShrlAlgoToolkit.RevitAddins.RvIndependent.MetroTunnel;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
[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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-04 08:52:23 +08:00
|
|
|
|
Document.Invoke(_ =>
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|