调整代码
This commit is contained in:
495
ShrlAlgoToolkit.RevitAddins/Mep/ClashResolveViewModel.cs
Normal file
495
ShrlAlgoToolkit.RevitAddins/Mep/ClashResolveViewModel.cs
Normal file
@@ -0,0 +1,495 @@
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
using ShrlAlgoToolkit.RevitAddins.Common.Assists;
|
||||
|
||||
namespace ShrlAlgoToolkit.RevitAddins.RvMEP;
|
||||
|
||||
public partial class ClashResolveViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial AdjustDirection AdjustDirection { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial AdjustType AdjustType { get; set; } = AdjustType.OneSide;
|
||||
|
||||
/// <summary>
|
||||
/// 正在执行命令
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(RevitAddins.RvMEP.ClashResolveViewModel.ResolveCommand))]
|
||||
public partial bool CanRunning { get; set; } = true;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double Angle { get; set; } = 90.0;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial double Offset { get; set; } = 800;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial LocationType LocationType { get; set; } = LocationType.Manual;
|
||||
public ActionEventHandler ActionEventHandler { get; } = new();
|
||||
partial void OnLocationTypeChanged(LocationType value)
|
||||
{
|
||||
KeyIntPtrHelper.RaiseEscTwice();
|
||||
}
|
||||
[RelayCommand]
|
||||
private static void Closing()
|
||||
{
|
||||
//关闭窗口退出选择
|
||||
KeyIntPtrHelper.RaiseEscTwice();
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(RevitAddins.RvMEP.ClashResolveViewModel.CanRunning))]
|
||||
private void Resolve()
|
||||
{
|
||||
CanRunning = false;
|
||||
|
||||
ActionEventHandler.Raise(uiapp =>
|
||||
{
|
||||
var uidoc = uiapp.ActiveUIDocument;
|
||||
var doc = uidoc.Document;
|
||||
MEPCurve mepCurveToBend = default;
|
||||
XYZ breakPoint1 = default;
|
||||
XYZ breakPoint2 = default;
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (LocationType)
|
||||
{
|
||||
case LocationType.Manual:
|
||||
|
||||
{
|
||||
var reference1 = uidoc.Selection.PickObject(
|
||||
ObjectType.PointOnElement,
|
||||
new FuncFilter(
|
||||
e =>
|
||||
e is MEPCurve mepCurve and not InsulationLiningBase
|
||||
&& mepCurve.GetCurve() is Line line
|
||||
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
|
||||
),
|
||||
"请选择翻弯的管线上的点"
|
||||
);
|
||||
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
|
||||
if (mepCurveToBend.Pinned)
|
||||
{
|
||||
MessageBox.Show("错误", "请解锁图元");
|
||||
CanRunning = true;
|
||||
return;
|
||||
}
|
||||
var reference2 = uidoc.Selection.PickObject(
|
||||
ObjectType.PointOnElement,
|
||||
new FuncFilter(e => e.Id == mepCurveToBend!.Id),
|
||||
"请选择另一个翻弯管线上的点或确定单侧翻弯的需要偏移一侧"
|
||||
);
|
||||
//两个断点,breakPoint1距离原直线起点近,反向时,交换值
|
||||
breakPoint1 = mepCurveToBend.GetCurve().Project(reference1.GlobalPoint).XYZPoint;
|
||||
breakPoint2 = mepCurveToBend.GetCurve().Project(reference2.GlobalPoint).XYZPoint;
|
||||
}
|
||||
break;
|
||||
case LocationType.Reference:
|
||||
|
||||
{
|
||||
var reference = uidoc.Selection.PickObject(
|
||||
ObjectType.Element,
|
||||
new FuncFilter(
|
||||
e =>
|
||||
e is MEPCurve mepCurve and not InsulationLiningBase
|
||||
&& mepCurve.GetCurve() is Line line
|
||||
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
|
||||
),
|
||||
"请选择参照的管线"
|
||||
);
|
||||
//参考的管线定位
|
||||
var referenceMEPCurve = doc.GetElement(reference);
|
||||
var referenceLine = referenceMEPCurve.GetCurve() as Line;
|
||||
|
||||
var reference1 = uidoc.Selection.PickObject(
|
||||
ObjectType.PointOnElement,
|
||||
new FuncFilter(
|
||||
e =>
|
||||
e is MEPCurve mepCurve and not InsulationLiningBase
|
||||
&& mepCurve.GetCurve() is Line line
|
||||
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
|
||||
&& e.Id != referenceMEPCurve!.Id
|
||||
),
|
||||
"请选择翻弯的管线或确定单侧翻弯的需要偏移一侧"
|
||||
);
|
||||
//翻弯的管线定位
|
||||
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
|
||||
var bendLine = mepCurveToBend.GetCurve() as Line;
|
||||
|
||||
var result = bendLine!.Intersect(referenceLine, out var array);
|
||||
|
||||
XYZ intersectPoint = default;
|
||||
switch (result)
|
||||
{
|
||||
case SetComparisonResult.Overlap:
|
||||
intersectPoint = array.get_Item(0).XYZPoint;
|
||||
break;
|
||||
case SetComparisonResult.Disjoint:
|
||||
{
|
||||
IList<ClosestPointsPairBetweenTwoCurves> points =
|
||||
[];
|
||||
bendLine.ComputeClosestPoints(referenceLine, true, true, false, out points);
|
||||
var point = points.FirstOrDefault()?.XYZPointOnFirstCurve;
|
||||
if (bendLine.IsInsideEx(point, 0.2))
|
||||
{
|
||||
intersectPoint = point;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
breakPoint1 = intersectPoint - (bendLine.Direction * Offset / 304.8);
|
||||
breakPoint2 = intersectPoint + (bendLine.Direction * Offset / 304.8);
|
||||
if (
|
||||
reference1.GlobalPoint.DistanceTo(breakPoint1)
|
||||
< reference1.GlobalPoint.DistanceTo(breakPoint2)
|
||||
) //距离近的是breakpoint2
|
||||
{
|
||||
(breakPoint1, breakPoint2) = (breakPoint2, breakPoint1);
|
||||
}
|
||||
|
||||
if (
|
||||
intersectPoint == default
|
||||
|| !bendLine.IsInsideEx(breakPoint1, 0.2)
|
||||
|| !bendLine.IsInsideEx(breakPoint2, 0.2)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var originBaseLine = mepCurveToBend.GetCurve() as Line;
|
||||
var baseLine = originBaseLine!.Clone() as Line;
|
||||
//原管线的方向
|
||||
var direction = baseLine?.Direction;
|
||||
var startPoint = baseLine!.GetEndPoint(0);
|
||||
var endPoint = baseLine.GetEndPoint(1);
|
||||
var breakLine = Line.CreateBound(breakPoint1, breakPoint2);
|
||||
//var minLength = mepCurveToBend.GetConnectors().OfType<Connector>().FirstOrDefault().GetExtensionLength();
|
||||
//if (breakLine.Length < minLength)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
var translateDirection = AdjustDirection switch
|
||||
{
|
||||
AdjustDirection.Up => XYZ.BasisZ,
|
||||
AdjustDirection.Down => -XYZ.BasisZ,
|
||||
AdjustDirection.Left => XYZ.BasisZ.CrossProduct(breakLine.Direction),
|
||||
AdjustDirection.Right => -XYZ.BasisZ.CrossProduct(breakLine.Direction),
|
||||
_ => null
|
||||
};
|
||||
switch (AdjustType)
|
||||
{
|
||||
case AdjustType.OneSide:
|
||||
|
||||
{
|
||||
MEPCurve baseMepCurve1;
|
||||
MEPCurve baseMepCurve2;
|
||||
|
||||
var newMepCurveId = mepCurveToBend.BreakByPoint(breakPoint1);
|
||||
var newMepCurve = doc.GetElement(newMepCurveId) as MEPCurve;
|
||||
|
||||
//baseMepCurve2始终是打断后生成的新管线,并且是需要偏移的管线
|
||||
if ((newMepCurve.GetCurve() as Line).IsInsideEx(breakPoint2))
|
||||
{
|
||||
baseMepCurve1 = mepCurveToBend;
|
||||
baseMepCurve2 = newMepCurve;
|
||||
}
|
||||
else
|
||||
{
|
||||
baseMepCurve1 = newMepCurve;
|
||||
baseMepCurve2 = mepCurveToBend;
|
||||
}
|
||||
//移动新生成的管线
|
||||
ElementTransformUtils.MoveElement(
|
||||
doc,
|
||||
baseMepCurve2.Id,
|
||||
translateDirection * Offset / 304.8
|
||||
);
|
||||
doc.Regenerate();
|
||||
////偏移变换
|
||||
//var translateTransform = Transform.CreateTranslation(translateDirection * Offset / 304.8);
|
||||
//
|
||||
//var originOffsetUnboundLine = baseLine.CreateTransformed(translateTransform) as Line;
|
||||
//需要偏移直线定位线
|
||||
var originOffsetUnboundLine = baseMepCurve2.GetCurve();
|
||||
//用于判断交点是否在偏移后的直线内,避免生成不了
|
||||
var originOffsetLine = originOffsetUnboundLine.Clone() as Line;
|
||||
originOffsetUnboundLine.MakeUnbound();
|
||||
|
||||
var radian = Angle.ToRadian();
|
||||
//反向时角度取补角
|
||||
if (breakLine.Direction.IsAlmostEqualTo(-direction))
|
||||
{
|
||||
radian = (180 - Angle).ToRadian();
|
||||
}
|
||||
|
||||
var rotation = Transform.CreateRotationAtPoint(
|
||||
direction.CrossProduct(translateDirection),
|
||||
radian,
|
||||
breakPoint1
|
||||
);
|
||||
//因为原来的管线可能被移动,所以用baseline的克隆线
|
||||
var unboundAngleLine = baseLine.CreateTransformed(rotation) as Line;
|
||||
unboundAngleLine!.MakeUnbound();
|
||||
//偏移管线与倾斜管线交点
|
||||
var offsetIntersectPoint = originOffsetUnboundLine.IntersectionPoint(unboundAngleLine);
|
||||
var isInside = originOffsetLine.IsInsideEx(offsetIntersectPoint); //当角度线于偏移直线交点在偏移直线内时
|
||||
//var flag2 = breakPoint1!.DistanceTo(offsetIntersectPoint) > minLength; //偏移间距大于一定一定值
|
||||
if (!isInside)
|
||||
{
|
||||
MessageBox.Show("管线偏移角度过大或过小,导致交点不在偏移的管线范围内");
|
||||
break;
|
||||
}
|
||||
//if (!flag2)
|
||||
//{
|
||||
// MessageBox.Show("管线偏移距离过近");
|
||||
// break;
|
||||
//}
|
||||
//if (isInside)
|
||||
else
|
||||
{
|
||||
var angleLine = Line.CreateBound(breakPoint1, offsetIntersectPoint);
|
||||
var angleMepCurve = mepCurveToBend.CopyAndSetLocationCurve(angleLine);
|
||||
|
||||
//拿到角度管的偏移交点处的连接件
|
||||
var angleMEPCurveIntersectPointConnector = angleMepCurve
|
||||
.GetConnectors(true)
|
||||
.GetNearestConnector(offsetIntersectPoint);
|
||||
//移动后的管线原有的连接件中,不用连接角度曲线的连接件,用来确定移动后管线的定位线
|
||||
Connector originOffsetConnector = null;
|
||||
|
||||
foreach (Connector conn in baseMepCurve2.GetConnectors(true))
|
||||
{
|
||||
//90度时,偏移管线的两个连接都是90度,但要选择偏移管原有的,非打断处的连接件
|
||||
if (
|
||||
conn.CoordinateSystem.BasisZ.DotProduct(
|
||||
angleMEPCurveIntersectPointConnector.CoordinateSystem.BasisZ
|
||||
) >= 0
|
||||
&& !offsetIntersectPoint.IsAlmostEqualTo(conn.Origin)
|
||||
) //锐角
|
||||
{
|
||||
originOffsetConnector = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
//if (originOffsetConnector != null && offsetIntersectPoint.DistanceTo(originOffsetConnector.Origin) > minLength)
|
||||
if (originOffsetConnector != null)
|
||||
{
|
||||
var finalOffsetLine = Line.CreateBound(
|
||||
offsetIntersectPoint,
|
||||
originOffsetConnector.Origin
|
||||
);
|
||||
baseMepCurve2.SetLocationCurve(finalOffsetLine);
|
||||
}
|
||||
|
||||
|
||||
var conn1 = ConnectorExtensions.GetNearestConnectors(
|
||||
baseMepCurve1,
|
||||
angleMepCurve
|
||||
);
|
||||
doc.Create.NewElbowFitting(conn1[0], conn1[1]);
|
||||
|
||||
var conn2 = ConnectorExtensions.GetNearestConnectors(
|
||||
angleMepCurve,
|
||||
baseMepCurve2
|
||||
);
|
||||
doc.Create.NewElbowFitting(conn2[0], conn2[1]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
ex.Message.ToLog();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AdjustType.TwoSide:
|
||||
|
||||
{
|
||||
MEPCurve baseMepCurve1;
|
||||
MEPCurve baseMepCurve2;
|
||||
//选择点的方向与原直线方向相反时,使得breakPoint1~breakPoint2始终与原直线同向
|
||||
if (breakLine.Direction.IsAlmostEqualTo(-baseLine.Direction))
|
||||
{
|
||||
//交换值
|
||||
(breakPoint1, breakPoint2) = (breakPoint2, breakPoint1);
|
||||
}
|
||||
|
||||
//doc.Regenerate();
|
||||
//偏移变换
|
||||
var translateTransform = Transform.CreateTranslation(
|
||||
translateDirection * Offset / 304.8
|
||||
);
|
||||
//偏移直线
|
||||
var offsetLine = baseLine.CreateTransformed(translateTransform) as Line;
|
||||
offsetLine!.MakeUnbound();
|
||||
//根据角度旋转的矩阵变换,创建变换后的直线
|
||||
//第一个交点
|
||||
var rotateTransform1 = Transform.CreateRotationAtPoint(
|
||||
direction.CrossProduct(translateDirection),
|
||||
Angle.ToRadian(),
|
||||
breakPoint1
|
||||
);
|
||||
var angleLine1 = baseLine.CreateTransformed(rotateTransform1) as Line;
|
||||
angleLine1!.MakeUnbound();
|
||||
var offsetPoint1 = offsetLine.IntersectionPoint(angleLine1);
|
||||
|
||||
//根据角度旋转的矩阵变换,创建变换后的直线
|
||||
//第二个交点
|
||||
var rotateTransform2 = Transform.CreateRotationAtPoint(
|
||||
direction.CrossProduct(translateDirection),
|
||||
(180 - Angle).ToRadian(),
|
||||
breakPoint2
|
||||
);
|
||||
var angleLine2 = baseLine.CreateTransformed(rotateTransform2) as Line;
|
||||
angleLine2!.MakeUnbound();
|
||||
var offsetPoint2 = offsetLine.IntersectionPoint(angleLine2);
|
||||
var b = Line.CreateBound(offsetPoint1, offsetPoint2);
|
||||
if (b.Direction.IsAlmostEqualTo(-baseLine.Direction))
|
||||
{
|
||||
Debug.WriteLine("翻弯的管线交叉");
|
||||
MessageBox.Show(
|
||||
"两点距离太近,无法翻弯",
|
||||
"提醒",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Information
|
||||
);
|
||||
ts.RollBack();
|
||||
break;
|
||||
}
|
||||
|
||||
var newMepCurveId = mepCurveToBend.BreakByPoint(breakPoint1);
|
||||
var newMepCurve = doc.GetElement(newMepCurveId) as MEPCurve;
|
||||
//判断打断生成的新管线的位置是原管线的前端还是后端
|
||||
if ((newMepCurve.GetCurve() as Line).IsInsideEx(breakPoint2)) //后端
|
||||
{
|
||||
baseMepCurve1 = mepCurveToBend;
|
||||
baseMepCurve2 = newMepCurve;
|
||||
}
|
||||
else
|
||||
{
|
||||
baseMepCurve1 = newMepCurve;
|
||||
baseMepCurve2 = mepCurveToBend;
|
||||
}
|
||||
|
||||
//第一条管线
|
||||
var newBaseLine1 = Line.CreateBound(startPoint, breakPoint1);
|
||||
//第二条管线
|
||||
var newBaseLine2 = Line.CreateBound(breakPoint2, endPoint);
|
||||
baseMepCurve1.SetLocationCurve(newBaseLine1);
|
||||
baseMepCurve2.SetLocationCurve(newBaseLine2);
|
||||
//生成的偏移线方向相反时,会导致两条翻弯的管线交叉
|
||||
|
||||
//第一根翻弯管
|
||||
var firstMepCurve = mepCurveToBend.CopyAndSetLocationCurve(
|
||||
Line.CreateBound(breakPoint1, offsetPoint1)
|
||||
);
|
||||
//偏移管
|
||||
var secondMepCurve = mepCurveToBend.CopyAndSetLocationCurve(
|
||||
Line.CreateBound(offsetPoint1, offsetPoint2)
|
||||
);
|
||||
//第二根翻弯管
|
||||
var thirdMepCurve = mepCurveToBend.CopyAndSetLocationCurve(
|
||||
Line.CreateBound(offsetPoint2, breakPoint2)
|
||||
);
|
||||
|
||||
doc.Regenerate();
|
||||
try
|
||||
{
|
||||
var connectors1 = ConnectorExtensions.GetNearestConnectors(
|
||||
baseMepCurve1,
|
||||
firstMepCurve
|
||||
);
|
||||
doc.Create.NewElbowFitting(connectors1[0], connectors1[1]);
|
||||
var connectors4 = ConnectorExtensions.GetNearestConnectors(
|
||||
thirdMepCurve,
|
||||
baseMepCurve2
|
||||
);
|
||||
doc.Create.NewElbowFitting(connectors4[0], connectors4[1]);
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.InvalidOperationException)
|
||||
{
|
||||
MessageBox.Show("角度过大或过小", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Message.ToLog();
|
||||
}
|
||||
try
|
||||
{
|
||||
var connectors2 = ConnectorExtensions.GetNearestConnectors(
|
||||
firstMepCurve,
|
||||
secondMepCurve
|
||||
);
|
||||
doc.Create.NewElbowFitting(connectors2[0], connectors2[1]);
|
||||
var connectors3 = ConnectorExtensions.GetNearestConnectors(
|
||||
secondMepCurve,
|
||||
thirdMepCurve
|
||||
);
|
||||
doc.Create.NewElbowFitting(connectors3[0], connectors3[1]);
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.InvalidOperationException)
|
||||
{
|
||||
MessageBox.Show("角度过大或过小", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Message.ToLog();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
CanRunning = true;
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CanRunning = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
"碰撞处理"
|
||||
);
|
||||
CanRunning = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public enum LocationType
|
||||
{
|
||||
Manual,
|
||||
Reference
|
||||
}
|
||||
|
||||
public enum AdjustType
|
||||
{
|
||||
TwoSide,
|
||||
OneSide
|
||||
}
|
||||
|
||||
public enum AdjustDirection
|
||||
{
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
Reference in New Issue
Block a user