增加保温层和整理管线的功能,修复自动保存功能等修复多个bug

This commit is contained in:
GG Z
2024-10-27 00:19:48 +08:00
parent b6647218be
commit 77655c9ef5
67 changed files with 3159 additions and 731 deletions

View File

@@ -0,0 +1,18 @@
using System;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Nice3point.Revit.Toolkit.External;
namespace Sai.RvKits.RvMEP;
[Transaction(TransactionMode.Manual)]
public class AddInsulationCmd : ExternalCommand
{
public override void Execute()
{
WinDialogHelper.ShowModeless<AddInsulationView>(new AddInsulationViewModel(Document));
}
}

View File

@@ -0,0 +1,108 @@
<ex:FluentWindowEx
x:Class="Sai.RvKits.RvMEP.AddInsulationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
xmlns:local="clr-namespace:Sai.RvKits.RvMEP"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="保温层"
Width="620"
MinHeight="300"
d:DataContext="{d:DesignInstance Type=local:AddInsulationViewModel}"
SizeToContent="Height"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/Sai.RvKits;component/WPFUI.xaml" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ex:StackPanelEx
Grid.RowSpan="2"
Grid.Column="0"
Margin="5"
IsEnabled="{Binding AddToPipe, Mode=TwoWay}"
Spacing="5">
<ex:ComboBoxEx
DisplayMemberPath="Name"
Header="管道系统类型"
ItemsSource="{Binding PipingSystemTypes}"
SelectedItem="{Binding SelectedPipingSystemType}" />
<DataGrid
ex:StackPanelEx.Fill="Fill"
AutoGenerateColumns="False"
ItemsSource="{Binding PipeInsulationItems}"
SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding MinDiameter}" Header="最小管径" />
<DataGridTextColumn Binding="{Binding MaxDiameter}" Header="最大管径" />
<DataGridTextColumn Binding="{Binding Thickness}" Header="保温层厚度" />
<!--<DataGridTextColumn Binding="{Binding PipeInsulationType.Name}" Header="保温层材料" />-->
<!--<DataGridComboBoxColumn
DisplayMemberPath=""
Header="保温层材料"
ItemsSource="{Binding PipeInsulationTypes}"
SelectedItemBinding="{Binding PipeInsulationType, UpdateSourceTrigger=PropertyChanged}"
TextBinding="{Binding PipeInsulationType.Name}" />-->
<DataGridTemplateColumn Width="*" Header="保温层材料">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ComboBox
DisplayMemberPath="Name"
ItemsSource="{Binding DataContext.PipeInsulationTypes, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"
SelectedItem="{Binding PipeInsulationType, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ex:StackPanelEx>
<ex:StackPanelEx
Grid.Column="1"
Margin="5"
IsEnabled="{Binding AddToDuct, Mode=TwoWay}"
Spacing="5">
<ex:ComboBoxEx
DisplayMemberPath="Name"
Header="风管系统类型:"
ItemsSource="{Binding DuctSystemTypes}"
SelectedItem="{Binding SelectedDuctSystem}" />
<ex:ComboBoxEx
DisplayMemberPath="Name"
Header="保温层类型:"
ItemsSource="{Binding DuctInsulationTypes}"
SelectedItem="{Binding DuctInsulationItem.DuctInsulationType}" />
<ex:TextBoxEx Header="保温层厚度:" Text="{Binding DuctInsulationItem.Thickness, UpdateSourceTrigger=PropertyChanged}" />
</ex:StackPanelEx>
<StackPanel
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Right"
Orientation="Horizontal">
<CheckBox
MinWidth="50"
Margin="5"
Content="管道"
IsChecked="{Binding AddToPipe}" />
<CheckBox
MinWidth="50"
Margin="5"
Content="风管"
IsChecked="{Binding AddToDuct}" />
<Button
Grid.Row="1"
HorizontalAlignment="Right"
Command="{Binding AddInsulationCommand}"
Content="添加保温层" />
</StackPanel>
</Grid>
</ex:FluentWindowEx>

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Sai.RvKits.RvMEP;
/// <summary>
/// AddInsulationView.xaml 的交互逻辑
/// </summary>
public partial class AddInsulationView
{
public AddInsulationView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,190 @@
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
namespace Sai.RvKits.RvMEP
{
public partial class AddInsulationViewModel : ObservableObject
{
private readonly ActionEventHandler addInsulationHandler = new();
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(AddInsulationCommand))]
private bool addToDuct;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(AddInsulationCommand))]
private bool addToPipe;
/// <summary>
/// 定义的风管保温层
/// </summary>
[ObservableProperty]
private InsulationItem ductInsulationItem;
/// <summary>
/// 定义的管道保温层
/// </summary>
[ObservableProperty]
private List<InsulationItem> pipeInsulationItems;
/// <summary>
/// 选中的风管系统类型
/// </summary>
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(AddInsulationCommand))]
private MechanicalSystemType selectedDuctSystem;
/// <summary>
/// 选中的管道系统类型
/// </summary>
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(AddInsulationCommand))]
private PipingSystemType selectedPipingSystemType;
public AddInsulationViewModel(Document doc)
{
PipingSystemTypes = doc.OfClass<PipingSystemType>().Cast<PipingSystemType>().ToList();
DuctSystemTypes = doc.OfClass<MechanicalSystemType>().Cast<MechanicalSystemType>().ToList();
DuctInsulationTypes = doc.OfClass<DuctInsulationType>().Cast<DuctInsulationType>().ToList();
PipeInsulationTypes = doc.OfClass<PipeInsulationType>().Cast<PipeInsulationType>().ToList();
PipeInsulationItems = [
new InsulationItem(){MinDiameter=15,MaxDiameter=25, Thickness=25,PipeInsulationType=PipeInsulationTypes.FirstOrDefault()},
new InsulationItem(){MinDiameter=32,MaxDiameter=80, Thickness=30,PipeInsulationType=PipeInsulationTypes.FirstOrDefault()},
new InsulationItem(){MinDiameter=100,MaxDiameter=1000, Thickness=35,PipeInsulationType=PipeInsulationTypes.FirstOrDefault()},
];
DuctInsulationItem = new() { Thickness = 50, DuctInsulationType = DuctInsulationTypes.FirstOrDefault() };
}
[RelayCommand(CanExecute = nameof(CanAdd))]
private void AddInsulation()
{
addInsulationHandler.Raise(
uiapp =>
{
var uidoc = uiapp.ActiveUIDocument;
var doc = uidoc.Document;
doc.Invoke(
ts =>
{
if (AddToDuct)
{
var systems = doc.OfClass<MechanicalSystem>().Cast<MechanicalSystem>();
foreach (var system in systems)
{
var elems = system.DuctNetwork;
foreach (Element elem in elems)
{
var id = InsulationLiningBase.GetInsulationIds(doc, elem.Id).FirstOrDefault();
if (id == null)
{
//风管或风管管件
if (elem is Duct duct ||
(elem is FamilyInstance instance &&
instance.Category.Id.IntegerValue == -2008010))
{
Autodesk.Revit.DB.Mechanical.DuctInsulation
.Create(
doc,
elem.Id,
DuctInsulationItem.DuctInsulationType.Id,
DuctInsulationItem.Thickness / 304.8);
}
}
else
{
var insulation = doc.GetElement(id) as DuctInsulation;
insulation.ChangeTypeId(DuctInsulationItem.DuctInsulationType.Id);
insulation.Thickness = DuctInsulationItem.Thickness / 304.8;
}
}
}
}
if (AddToPipe)
{
var systems = doc.OfClass<PipingSystem>().Cast<PipingSystem>();
foreach (var system in systems)
{
var elems = system.PipingNetwork;
foreach (Element elem in elems)
{
//水管或水管管件
if (elem is Pipe pipe ||
(elem is FamilyInstance instance &&
instance.Category.Id.IntegerValue == -2008049))
{
InsulationItem pipeInsulation = default;
foreach (var item in PipeInsulationItems)
{
//直径
var str = elem.get_Parameter(BuiltInParameter.RBS_CALCULATED_SIZE)
.AsString()
.Split(' ')
.FirstOrDefault();
if (double.TryParse(str, out var d))
{
if (d >= item.MinDiameter && d <= item.MaxDiameter)
{
pipeInsulation = item;
break;
}
}
}
var id = InsulationLiningBase.GetInsulationIds(doc, elem.Id).FirstOrDefault();
if (id == null)
{
if (pipeInsulation != null)
{
Autodesk.Revit.DB.Plumbing.PipeInsulation
.Create(
doc,
elem.Id,
pipeInsulation.PipeInsulationType.Id,
pipeInsulation.Thickness / 304.8);
}
}
else
{
var insulation = doc.GetElement(id) as PipeInsulation;
insulation.ChangeTypeId(pipeInsulation.PipeInsulationType.Id);
insulation.Thickness = pipeInsulation.Thickness / 304.8;
}
}
}
}
}
}, "添加保温层");
});
}
//private bool CanAdd()
//{
// return (AddToDuct && SelectedDuctSystem != null) || (AddToPipe && SelectedPipingSystemType != null);
//}
private bool CanAdd => (AddToDuct && SelectedDuctSystem != null) ||
(AddToPipe && SelectedPipingSystemType != null);
/// <summary>
/// 所有风管保温层类型
/// </summary>
public List<DuctInsulationType> DuctInsulationTypes { get; set; }
/// <summary>
/// 所有风管系统类型
/// </summary>
public List<MechanicalSystemType> DuctSystemTypes { get; set; }
/// <summary>
/// 所有管道保温层类型
/// </summary>
public List<PipeInsulationType> PipeInsulationTypes { get; set; }
/// <summary>
/// 所有管道系统类型
/// </summary>
public List<PipingSystemType> PipingSystemTypes { get; set; }
}
}

View File

@@ -1,13 +1,13 @@
using System.Windows.Controls;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB.Plumbing;
using Nice3point.Revit.Toolkit.External;
namespace Sai.RvKits.RvMEP;
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class AnyConnectCmd : ExternalCommand
{
public override void Execute()

View File

@@ -310,7 +310,7 @@ public partial class AnyConnectViewModel : ObservableValidator
//var copyMepCurveId = ElementTransformUtils
// .CopyElement(doc, elementToCopy.Id, XYZ.Zero)
// .FirstOrDefault();
//var copyMepCurve = doc.GetElement(copyMepCurveId) as MEPCurve;
//var copyMepCurve = doc.GetElement(copyMepCurveId) as ElementToMove;
//取短的线作为旋转轴的基准点,保证能创建
var isFirstMEPCurveLengther = line1.Length < line2.Length;
var l = isFirstMEPCurveLengther ? Line.CreateBound(

View File

@@ -4,7 +4,17 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.Attributes;
using Nice3point.Revit.Toolkit.External;
namespace Sai.RvKits.RvMEP;
internal class ArrangeMEPCurveCmd
[Transaction(TransactionMode.Manual)]
internal class ArrangeMEPCurveCmd : ExternalCommand
{
public override void Execute()
{
WinDialogHelper.ShowModeless<ArrangeMEPCurveView>(new ArrangeMEPCurveViewModel());
}
}

View File

@@ -0,0 +1,44 @@
<ex:FluentWindowEx
x:Class="Sai.RvKits.RvMEP.ArrangeMEPCurveView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
xmlns:local="clr-namespace:Sai.RvKits.RvMEP"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="整理管线"
Width="270"
MinHeight="180"
d:DataContext="{d:DesignInstance Type=local:ArrangeMEPCurveViewModel}"
SizeToContent="Height"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/Sai.RvKits;component/WPFUI.xaml" />
</Window.Resources>
<ex:StackPanelEx Margin="5" Spacing="5">
<GroupBox Header="参考方向">
<UniformGrid Rows="1">
<RadioButton Content="水平方向" IsChecked="{Binding IsHorizon}" />
<RadioButton Content="垂直方向" IsChecked="{Binding IsHorizon, Converter={StaticResource InvertBooleanConverter}}" />
</UniformGrid>
</GroupBox>
<ex:TextBoxEx
Prefix="间距:"
Suffix="mm"
Text="{Binding Gap, UpdateSourceTrigger=PropertyChanged}" />
<UniformGrid Rows="1">
<RadioButton
MinWidth="50"
Content="管中心"
IsChecked="{Binding MEPCurveCenter}" />
<RadioButton
Content="管外壁/考虑保温层"
IsChecked="{Binding MEPCurveCenter, Converter={StaticResource InvertBooleanConverter}}"
ToolTip="若无保温,则仅考虑管外壁" />
</UniformGrid>
<Button
HorizontalAlignment="Stretch"
Command="{Binding ArrangeCommand}"
Content="整理" />
</ex:StackPanelEx>
</ex:FluentWindowEx>

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Sai.RvKits.RvMEP;
/// <summary>
/// ArrangeMEPCurveView.xaml 的交互逻辑
/// </summary>
public partial class ArrangeMEPCurveView
{
public ArrangeMEPCurveView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,364 @@
using System.Windows;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
namespace Sai.RvKits.RvMEP
{
public partial class ArrangeMEPCurveViewModel : ObservableObject
{
private readonly ActionEventHandler arrangeHandler = new();
[ObservableProperty]
private double gap = 250;
[ObservableProperty]
private bool mEPCurveCenter = true;
[ObservableProperty]
private bool isHorizon = true;
[RelayCommand]
private void Arrange()
{
arrangeHandler.Raise(
uiapp =>
{
var uidoc = uiapp.ActiveUIDocument;
var doc = uidoc.Document;
doc.Invoke(
ts =>
{
try
{
var ids = uidoc.Selection
.PickElementsByRectangle(
new FuncFilter(
e => e is MEPCurve &&
e is not InsulationLiningBase &&
e is not FlexDuct &&
e is not FlexPipe &&
!(e.GetLocCurve() as Line).Direction.IsParallelTo(XYZ.BasisZ)),
"请选择要整理的管线")
.Select(e => e.Id)
.ToList();
var baseId = uidoc.Selection
.PickObject(
Autodesk.Revit.UI.Selection.ObjectType.Element,
new FuncFilter(e => ids.Contains(e.Id)),
"请选择基准管线")
.ElementId;
if (ids.Count <= 1)
{
return;
}
var baseElement = doc.GetElement(baseId);
var baseLine = baseElement.GetLocCurve() as Line;
baseLine.MakeUnbound();
if (IsHorizon)
{
//移除基准
ids.Remove(baseId);
List<ArrangeElement> arranges = [];
foreach (var id in ids)
{
var elem = doc.GetElement(id);
var l = elem.GetLocCurve() as Line;
if (!l.Direction.IsParallelTo(baseLine.Direction))
{
MessageBox.Show("错误", "所选管线不平行");
return;
}
var d = baseLine.Distance(l.Origin);
var project = baseLine.Project(l.Origin).XYZPoint;
var vector = l.Origin.Flatten() - project.Flatten();
var ae = new ArrangeElement
{
ElementToMove = elem,
//用来确定与基准管线的位置和方向
HorizonDistanceVector = vector
};
arranges.Add(ae);
}
var groups = arranges.OrderBy(ar => ar.HorizonDistanceVector.GetLength())
.GroupBy(
ar => XYZ.BasisZ
.CrossProduct(baseLine.Direction)
.IsAlmostEqualTo(ar.HorizonDistanceVector.Normalize()));
if (groups.Count() > 2)
{
MessageBox.Show("管线定位线存在误差");
return;
}
//管中心距离
if (MEPCurveCenter)
{
foreach (var group in groups)
{
for (var i = 0; i < group.Count(); i++)
{
var arrange = group.ElementAt(i);
//当前的距离
var dis = arrange.HorizonDistanceVector.GetLength();
var moveUnitDir = arrange.HorizonDistanceVector.Normalize();
//最终的距离
var actualDis = (i + 1) * Gap / 304.8;
var translate = moveUnitDir * (actualDis - dis);
ElementTransformUtils.MoveElement(
doc,
arrange.ElementToMove.Id,
translate);
}
}
}
else
{
//遍历两个方向的分组
foreach (var group in groups)
{
double actualDis = 0;
double previousHalfSize = 0;
//基准半宽
if (baseElement is Pipe pipe)
{
previousHalfSize = pipe.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER).AsDouble() / 2;
}
else if (baseElement is Conduit conduit)
{
previousHalfSize = conduit.get_Parameter(BuiltInParameter.RBS_CONDUIT_OUTER_DIAM_PARAM).AsDouble() / 2;
}
else if (baseElement is CableTray tray || baseElement is Duct duct)
{
var baseConnector = baseElement.GetConnectors()
.OfType<Connector>()
.FirstOrDefault();
if (baseConnector.Shape == ConnectorProfileType.Oval || baseConnector.Shape == ConnectorProfileType.Rectangular)
{
previousHalfSize = baseConnector.Width / 2;
}
else if (baseConnector.Shape == ConnectorProfileType.Round)
{
previousHalfSize = baseConnector.Radius;
}
}
if (baseElement is Pipe or Duct)
{
//基准保温层厚度
var insulationId = InsulationLiningBase.GetInsulationIds(
doc,
baseElement.Id).FirstOrDefault();
if (insulationId != null)
{
var insulation = doc.GetElement(insulationId) as InsulationLiningBase;
previousHalfSize += insulation.Thickness;
}
}
for (var i = 0; i < group.Count(); i++)
{
var arrange = group.ElementAt(i);
//当前的距离
var dis = arrange.HorizonDistanceVector.GetLength();
var moveUnitDir = arrange.HorizonDistanceVector.Normalize();
double currentHalfSize = 0;
if (arrange.ElementToMove is Pipe p)
{
currentHalfSize = p.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER).AsDouble() / 2;
}
else if (arrange.ElementToMove is Conduit conduit)
{
currentHalfSize = conduit.get_Parameter(BuiltInParameter.RBS_CONDUIT_OUTER_DIAM_PARAM).AsDouble() / 2;
}
else if (arrange.ElementToMove is CableTray tray || arrange.ElementToMove is Duct duct)
{
var conn = arrange.ElementToMove.GetConnectors()
.OfType<Connector>()
.FirstOrDefault();
if (conn.Shape == ConnectorProfileType.Oval || conn.Shape == ConnectorProfileType.Rectangular)
{
currentHalfSize = conn.Width / 2;
}
else if (conn.Shape == ConnectorProfileType.Round)
{
currentHalfSize = conn.Radius;
}
}
//只有管道和风管有保温
if (arrange.ElementToMove is Pipe or Duct)
{
//考虑保温层
var currentInsulationId = InsulationLiningBase.GetInsulationIds(
doc,
arrange.ElementToMove.Id).FirstOrDefault();
if (currentInsulationId != null)
{
var currentInsulation = doc.GetElement(currentInsulationId) as InsulationLiningBase;
currentHalfSize += currentInsulation.Thickness;
}
}
//最终的距离叠加,附加上次的距离,使得每次只要增加一个上一个半宽+当前的半宽+间隙
actualDis += previousHalfSize + currentHalfSize + Gap / 304.8;
var translate = moveUnitDir * (actualDis - dis);
ElementTransformUtils.MoveElement(
doc,
arrange.ElementToMove.Id,
translate);
//修改上个半宽,用于当前分组里下一个元素循环
previousHalfSize = currentHalfSize;
}
}
}
}
//垂向
else
{
//通过LocationCurve确定相对位置关系
var orderIds = ids.Select(id => doc.GetElement(id) as MEPCurve)
.OrderBy(c => (c.GetLocCurve() as Line).Origin.Z).Select(e => e.Id).ToList();
//中心距
if (MEPCurveCenter)
{
var baseIndex = orderIds.IndexOf(baseId);
for (var i = 0; i < orderIds.Count; i++)
{
var currentZ = (doc.GetElement(orderIds[i]).GetLocCurve() as Line).Origin.Z;
var dis = Math.Abs(baseLine.Origin.Z - currentZ);
var actualDis = Math.Abs((baseIndex - i)) * Gap / 304.8;
//判断方向
var vector = i > baseIndex ? XYZ.BasisZ : -XYZ.BasisZ;
var translate = (actualDis - dis) * vector;
ElementTransformUtils.MoveElement(doc, orderIds[i], translate);
//if (i > baseIndex)
//{
// var dis = currentZ - baseLine.Origin.Z;//正的
// var actualDis = (i - baseIndex) * Gap / 304.8;//正的
// var translate = (actualDis - dis) * XYZ.BasisZ;
// ElementTransformUtils.MoveElement(doc, orderIds[i], translate);
//}
}
}
//外距
else
{
ids.Remove(baseId);
var groups = ids.Select(id => doc.GetElement(id) as MEPCurve)
.OrderBy(c => (c.GetLocCurve() as Line).Origin.Z).GroupBy(e => (e.GetLocCurve() as Line).Origin.Z > baseLine.Origin.Z);
var baseTop = baseElement.get_BoundingBox(null).Max.Z;
var baseBottom = baseElement.get_BoundingBox(null).Min.Z;
if (baseElement is Pipe or Duct)
{
//基准保温层厚度
var insulationId = InsulationLiningBase.GetInsulationIds(
doc,
baseElement.Id).FirstOrDefault();
if (insulationId != null)
{
var insulation = doc.GetElement(insulationId) as InsulationLiningBase;
baseTop = insulation.get_BoundingBox(null).Max.Z;
baseBottom = insulation.get_BoundingBox(null).Min.Z;
}
}
foreach (var group in groups)
{
if (group.Key)
{
var sumHeight = 0.0;
var vector = XYZ.BasisZ;
for (var i = 0; i < group.Count(); i++)
{
var mep = group.ElementAt(i);
var currentTop = mep.get_BoundingBox(null).Max.Z;
var currentBottom = mep.get_BoundingBox(null).Min.Z;
if (mep is Pipe or Duct)
{
//基准保温层厚度
var insulationId = InsulationLiningBase.GetInsulationIds(
doc,
mep.Id).FirstOrDefault();
if (insulationId != null)
{
var insulation = doc.GetElement(insulationId) as InsulationLiningBase;
currentTop = insulation.get_BoundingBox(null).Max.Z;
currentBottom = insulation.get_BoundingBox(null).Min.Z;
}
}
//当前间距
var dis = currentBottom - baseTop;
var actualDis = (i + 1) * Gap / 304.8 + sumHeight;
var translate = (actualDis - dis) * vector;
ElementTransformUtils.MoveElement(doc, mep.Id, translate);
//整体高度
sumHeight += currentTop - currentBottom;
}
}
else
{
var sumHeight = 0.0;
var vector = -XYZ.BasisZ;
for (var i = group.Count() - 1; i >= 0; i--)
{
var mep = group.ElementAt(i);
var currentTop = mep.get_BoundingBox(null).Max.Z;
var currentBottom = mep.get_BoundingBox(null).Min.Z;
if (mep is Pipe or Duct)
{
//基准保温层厚度
var insulationId = InsulationLiningBase.GetInsulationIds(
doc,
mep.Id).FirstOrDefault();
if (insulationId != null)
{
var insulation = doc.GetElement(insulationId) as InsulationLiningBase;
currentTop = insulation.get_BoundingBox(null).Max.Z;
currentBottom = insulation.get_BoundingBox(null).Min.Z;
}
}
//当前间距
var dis = baseBottom - currentTop;
var actualDis = (group.Count() - i) * Gap / 304.8 + sumHeight;
var translate = (actualDis - dis) * vector;
ElementTransformUtils.MoveElement(doc, mep.Id, translate);
//整体高度
sumHeight += currentTop - currentBottom;
}
}
}
}
}
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
}
},
"整理管线");
});
}
}
public class ArrangeElement
{
public double ElementHeight => ElementToMove.get_BoundingBox(null).Max.Z - ElementToMove.get_BoundingBox(null).Min.Z;
public Element ElementToMove { get; set; }
public BoundingBoxXYZ Box { get; set; }
/// <summary>
/// 与基准元素的间距及方向向量
/// </summary>
public XYZ HorizonDistanceVector { get; set; }
}
}

View File

@@ -24,7 +24,7 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
var elemIds = UiDocument.Selection.GetElementIds();
if (elemIds.Count == 0)
{
var reference = UiDocument.Selection.PickObject(ObjectType.Element, new GenericFilter<FamilyInstance>(), "请选择族实例");
var reference = UiDocument.Selection.PickObject(ObjectType.Element, new FuncFilter(e => e is FamilyInstance ins && ins.MEPModel.ConnectorManager != null), "请选择族实例");
elemIds.Add(Document.GetElement(reference).Id);
}
@@ -35,9 +35,9 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
var conduitTypeId = Document.OfClass<ConduitType>().FirstElementId();
var filteredElementCollector = Document.OfClass<DuctType>();
var roundTypeId = ElementId.InvalidElementId;
var rectangleTypeId = ElementId.InvalidElementId;
var ovalTypeId = ElementId.InvalidElementId;
var roundDuctTypeId = ElementId.InvalidElementId;
var rectangleDuctTypeId = ElementId.InvalidElementId;
var ovalDuctTypeId = ElementId.InvalidElementId;
foreach (var element2 in filteredElementCollector)
{
@@ -45,15 +45,15 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
if (ductType.FamilyName == "圆形风管" || ductType.FamilyName.Contains("Round Duct"))
{
roundTypeId = ductType.Id;
roundDuctTypeId = ductType.Id;
}
else if (ductType.FamilyName == "矩形风管" || ductType.FamilyName.Contains("Rectangular Duct"))
{
rectangleTypeId = ductType.Id;
rectangleDuctTypeId = ductType.Id;
}
else if (ductType.FamilyName == "椭圆形风管" || ductType.FamilyName.Contains("Oval Duct"))
{
ovalTypeId = ductType.Id;
ovalDuctTypeId = ductType.Id;
}
}
var fabricationConfiguration = FabricationConfiguration.GetFabricationConfiguration(Document);
@@ -63,6 +63,8 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
{
continue;
}
CableTray referCabTray = null;
Conduit referConduit = null;
//拿到连接的管线的类型
foreach (Connector conn in elem.GetConnectors())
{
@@ -84,13 +86,13 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
case ConnectorProfileType.Invalid:
break;
case ConnectorProfileType.Round:
roundTypeId = connector.Owner.GetTypeId();
roundDuctTypeId = connector.Owner.GetTypeId();
break;
case ConnectorProfileType.Rectangular:
rectangleTypeId = connector.Owner.GetTypeId();
rectangleDuctTypeId = connector.Owner.GetTypeId();
break;
case ConnectorProfileType.Oval:
ovalTypeId = connector.Owner.GetTypeId();
ovalDuctTypeId = connector.Owner.GetTypeId();
break;
default:
break;
@@ -100,10 +102,12 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
{
if (connector.Owner is CableTray cableTray)
{
referCabTray = cableTray;
cableTrayTypeId = cableTray.GetTypeId();
}
else if (connector.Owner is Conduit conduit)
{
referConduit = conduit;
conduitTypeId = conduit.GetTypeId();
}
}
@@ -239,7 +243,7 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
element = Duct.Create(
Document,
mechanicalSystem.Id,
roundTypeId,
roundDuctTypeId,
levelId,
origin,
xyz2
@@ -253,7 +257,7 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
element = Duct.Create(
Document,
mechanicalSystem.Id,
rectangleTypeId,
rectangleDuctTypeId,
levelId,
origin,
xyz2
@@ -264,7 +268,7 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
break;
case ConnectorProfileType.Oval:
element = Duct.Create(Document, mechanicalSystem.Id, ovalTypeId, levelId, origin, xyz2);
element = Duct.Create(Document, mechanicalSystem.Id, ovalDuctTypeId, levelId, origin, xyz2);
Document.Regenerate();
element.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(connector.Width);
element.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(connector.Height);
@@ -274,7 +278,7 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
element = Duct.Create(
Document,
mechanicalSystem.Id,
roundTypeId,
roundDuctTypeId,
levelId,
origin,
xyz2
@@ -391,18 +395,18 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
break;
//电力
case Domain.DomainCableTrayConduit:
if (cableTrayTypeId == ElementId.InvalidElementId)
{
cableTrayTypeId = new FilteredElementCollector(Document)
.OfClass(typeof(CableTrayType))
.FirstElementId();
}
if (conduitTypeId == ElementId.InvalidElementId)
{
conduitTypeId = new FilteredElementCollector(Document)
.OfClass(typeof(ConduitType))
.FirstElementId();
}
//if (cableTrayTypeId == ElementId.InvalidElementId)
//{
// cableTrayTypeId = new FilteredElementCollector(Document)
// .OfClass(typeof(CableTrayType))
// .FirstElementId();
//}
//if (conduitTypeId == ElementId.InvalidElementId)
//{
// conduitTypeId = new FilteredElementCollector(Document)
// .OfClass(typeof(ConduitType))
// .FirstElementId();
//}
//switch (connector.ElectricalSystemType)
@@ -420,11 +424,27 @@ internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根
case ConnectorProfileType.Round:
element = Conduit.Create(Document, conduitTypeId, origin, xyz2, levelId);
element.get_Parameter(BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM).Set(connector.Radius * 2);
if (referConduit != null)
{
var value = referConduit.get_Parameter(
BuiltInParameter.RBS_CTC_SERVICE_TYPE)
.AsString();
element.get_Parameter(BuiltInParameter.RBS_CTC_SERVICE_TYPE).Set(value);
}
break;
case ConnectorProfileType.Rectangular:
element = CableTray.Create(Document, cableTrayTypeId, origin, xyz2, levelId);
element.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).Set(connector.Width);
element.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).Set(connector.Height);
if (referCabTray != null)
{
var value = referCabTray.get_Parameter(
BuiltInParameter.RBS_CTC_SERVICE_TYPE)
.AsString();
element.get_Parameter(BuiltInParameter.RBS_CTC_SERVICE_TYPE).Set(value);
}
break;
case ConnectorProfileType.Oval:

View File

@@ -63,7 +63,7 @@ public class BreakMEPCurveCmd : ExternalCommand
//else
//{
// var second = mepCurve.BreakByPoint(breakPoint2);
// //var mepCurve2 = Document.GetElement(second) as MEPCurve;
// //var mepCurve2 = Document.GetElement(second) as ElementToMove;
// var third = mepCurve.BreakByPoint(breakPoint1);
// Document.Delete(third);

View File

@@ -28,7 +28,7 @@ public class CableLayoutCmd : ExternalCommand
Document.Invoke(
_ =>
{
//Reference refer = UiDocument.Selection.PickObject(ObjectType.Element, new TypeSelectionFilter<CableTray>(), "请选择桥架");
//Reference refer = UiDocument.Selection.PickObject(ObjectType.ElementToMove, new TypeSelectionFilter<CableTray>(), "请选择桥架");
//var ct = UiDocument.Document.GetElement(refer) as CableTray;
var refer = UiDocument.Selection.PickObject(ObjectType.Element, new GenericFilter<CableTray>(), "请选择需要敷设桥架");
var ct = UiDocument.Document.GetElement(refer) as MEPCurve;

View File

@@ -62,108 +62,121 @@ public partial class ClashResolveViewModel : ObservableObject
doc.Invoke(
ts =>
{
switch (LocationType)
try
{
case LocationType.Manual:
switch (LocationType)
{
case LocationType.Manual:
{
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
),
"请选择翻弯的管线上的点"
);
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
var reference2 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(e => e.Id == mepCurveToBend!.Id),
"请选择另一个翻弯管线上的点或确定单侧翻弯的需要偏移一侧"
);
//两个断点,breakPoint1距离原直线起点近反向时交换值
breakPoint1 = mepCurveToBend.GetLocCurve().Project(reference1.GlobalPoint).XYZPoint;
breakPoint2 = mepCurveToBend.GetLocCurve().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.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
),
"请选择参照的管线"
);
//参考的管线定位
var referenceMEPCurve = doc.GetElement(reference);
var referenceLine = referenceMEPCurve.GetLocCurve() as Line;
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
&& e.Id != referenceMEPCurve!.Id
),
"请选择翻弯的管线或确定单侧翻弯的需要偏移一侧"
);
//翻弯的管线定位
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
var bendLine = mepCurveToBend.GetLocCurve() 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;
}
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() 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.GetLocCurve().Project(reference1.GlobalPoint).XYZPoint;
breakPoint2 = mepCurveToBend.GetLocCurve().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.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
),
"请选择参照的管线"
);
//参考的管线定位
var referenceMEPCurve = doc.GetElement(reference);
var referenceLine = referenceMEPCurve.GetLocCurve() as Line;
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
&& e.Id != referenceMEPCurve!.Id
),
"请选择翻弯的管线或确定单侧翻弯的需要偏移一侧"
);
//翻弯的管线定位
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
var bendLine = mepCurveToBend.GetLocCurve() 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;
}
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);
}
break;
}
}
if (
intersectPoint == default
|| !bendLine.IsInsideEx(breakPoint1, 0.2)
|| !bendLine.IsInsideEx(breakPoint2, 0.2)
)
{
return;
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;
break;
}
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
CanRunning = true;
return;
}
var originBaseLine = mepCurveToBend.GetLocCurve() as Line;

View File

@@ -5,6 +5,7 @@ using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Nice3point.Revit.Toolkit.External;
@@ -118,6 +119,8 @@ public class CorrectMEPCurveSlopeCmd : ExternalCommand
case Duct:
{
var param = mepCurve.get_Parameter(BuiltInParameter.RBS_DUCT_SLOPE);
var loc = mepCurve.GetLocCurve() as Line;
isError = param.HasValue && ((param.AsDouble() < 0.025 && param.AsDouble() > 0) || param.AsDouble() > 0.055); //坡度过大或过小时
break;
}

View File

@@ -126,8 +126,8 @@ public class HeadroomCheckCmd : ExternalCommand
// if (inputMessage.DialogResult == true)
// {
// var elems = UiDocument.Selection
// .PickElementsByRectangle(new FuncFilter(e => e is MEPCurve, (_, _) => true))
// .OfType<MEPCurve>();
// .PickElementsByRectangle(new FuncFilter(e => e is ElementToMove, (_, _) => true))
// .OfType<ElementToMove>();
// if (double.TryParse(inputMessage.InputContent, out var headroomValue))
// {
// CheckHeadroom(elems, headroomValue, 1000, 300);
@@ -137,7 +137,7 @@ public class HeadroomCheckCmd : ExternalCommand
// {
// var elem = UiDocument.SelectObject<DirectShape>();
// var clashFilter = new ElementIntersectsElementFilter(elem, false);
// var elems = Document.OfCollector().WherePasses(clashFilter).OfType<MEPCurve>();
// var elems = Document.OfCollector().WherePasses(clashFilter).OfType<ElementToMove>();
// if (double.TryParse(inputMessage.InputContent, out var headroomValue))
// {
// CheckHeadroom(elems, headroomValue, 1000, 300);

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using CommunityToolkit.Mvvm.ComponentModel;
using Sai.Toolkit.Mvvm.Attributes;
namespace Sai.RvKits.RvMEP;
public partial class InsulationItem : ObservableValidator
{
[GreaterThan(nameof(MinDiameter))]
[Range(15, 1000)]
public double MaxDiameter
{
get => maxDiameter;
set
{
SetProperty(ref maxDiameter, value, true);
}
}
private double maxDiameter;
[Range(0, 1000)]
public double MinDiameter
{
get => minDiameter;
set
{
SetProperty(ref minDiameter, value, true);
ValidateProperty(MaxDiameter, nameof(MaxDiameter));
}
}
private double minDiameter;
[Required]
[Range(10, 1000)]
public double Thickness
{
get => thickness;
set => SetProperty(ref thickness, value, true);
}
private double thickness;
[ObservableProperty]
private PipeInsulationType pipeInsulationType;
[ObservableProperty]
private DuctInsulationType ductInsulationType;
}

View File

@@ -11,185 +11,186 @@ namespace Sai.RvKits.RvMEP;
[Regeneration(RegenerationOption.Manual)]
public class MoveConnectCmd : ExternalCommand
{
public override void Execute()
{
Reference baseReference;
Reference moveReference;
try
{
FuncFilter filter =
new(
e =>
((e is MEPCurve mep and not InsulationLiningBase) && mep.GetConnectors(true).Size > 0)
|| (
e is FamilyInstance instance
&& instance.MEPModel.ConnectorManager != null
&& instance.MEPModel.ConnectorManager.UnusedConnectors.Size > 0
)
);
public override void Execute()
{
Reference baseReference;
Reference moveReference;
try
{
FuncFilter filter =
new(
e =>
((e is MEPCurve mep and not InsulationLiningBase) && mep.GetConnectors(true).Size > 0)
|| (
e is FamilyInstance instance
&& instance.MEPModel.ConnectorManager != null
&& instance.MEPModel.ConnectorManager.UnusedConnectors.Size > 0
)
);
baseReference = UiDocument.Selection.PickObject(
Autodesk.Revit.UI.Selection.ObjectType.Element,
filter,
"请选择基准的管线、管件、设备实例"
);
FuncFilter filter1 =
new(
e =>
e.Id != baseReference.ElementId
&& ((e is MEPCurve mep and not InsulationLiningBase) && mep.GetConnectors(true).Size > 0)
|| (
e is FamilyInstance instance
&& instance.MEPModel.ConnectorManager != null
&& instance.MEPModel.ConnectorManager.UnusedConnectors.Size > 0
)
);
moveReference = UiDocument.Selection.PickObject(
Autodesk.Revit.UI.Selection.ObjectType.Element,
filter,
baseReference = UiDocument.Selection.PickObject(
Autodesk.Revit.UI.Selection.ObjectType.Element,
filter,
"请选择基准的管线、管件、设备实例"
);
FuncFilter filter1 =
new(
e =>
e.Id != baseReference.ElementId
&& ((e is MEPCurve mep and not InsulationLiningBase) && mep.GetConnectors(true).Size > 0)
|| (
e is FamilyInstance instance
&& instance.MEPModel.ConnectorManager != null
&& instance.MEPModel.ConnectorManager.UnusedConnectors.Size > 0
&& instance.Id != baseReference.ElementId
)
);
moveReference = UiDocument.Selection.PickObject(
Autodesk.Revit.UI.Selection.ObjectType.Element,
filter,
"请选择需要移动连接的管线、管件、设备实例"
);
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
return;
}
var baseElement = Document.GetElement(baseReference);
var elementToMove = Document.GetElement(moveReference);
var list = ConnectorAssist.GetNearestDomainConnectors(baseElement, elementToMove);
if (list.Count != 2)
{
MessageBox.Show("缺少可连接的连接件", "提示");
return;
}
Document.Invoke(
_ =>
{
var conn1 = list[0];
var conn2 = list.Last();
//if (conn1.Domain != conn2.Domain)//类型不一样不能连接
//{
// return;
//}
var origin1 = conn1.Origin;
var origin2 = conn2.Origin;
var direction1 = conn1.CoordinateSystem.BasisZ;
var direction2 = conn2.CoordinateSystem.BasisZ;
//夹角
var radian = Math.Acos(direction1.DotProduct(direction2));
//都是管线角度小于135,主次分支对齐连接,仅支持中心对齐
if (
baseElement is MEPCurve mainMEPCurve
&& elementToMove is MEPCurve branchMEPCurve
&& radian < 135.0.ToRadian()
)
{
//if ((conn2.Shape == ConnectorProfileType.Oval || conn2.Shape == ConnectorProfileType.Rectangular))
//{
// var verticalJustification = mainMEPCurve.get_Parameter(BuiltInParameter.RBS_CURVE_VERT_OFFSET_PARAM);
// var delta = XYZ.BasisZ * (branchMEPCurve.Height / 2 - mainMEPCurve.Height / 2);
// //底部
// if (verticalJustification.AsInteger() == 1)
// {
// origin2 -= delta;
// }
// //顶部
// if (verticalJustification.AsInteger() == 2)
// {
// origin2 += delta;
// }
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
return;
}
var baseElement = Document.GetElement(baseReference);
var elementToMove = Document.GetElement(moveReference);
var list = ConnectorAssist.GetNearestDomainConnectors(baseElement, elementToMove);
if (list.Count != 2)
{
MessageBox.Show("缺少可连接的连接件", "提示");
return;
}
Document.Invoke(
_ =>
{
var conn1 = list[0];
var conn2 = list.Last();
//if (conn1.Domain != conn2.Domain)//类型不一样不能连接
//{
// return;
//}
var origin1 = conn1.Origin;
var origin2 = conn2.Origin;
var direction1 = conn1.CoordinateSystem.BasisZ;
var direction2 = conn2.CoordinateSystem.BasisZ;
//夹角
var radian = Math.Acos(direction1.DotProduct(direction2));
//都是管线角度小于135,主次分支对齐连接,仅支持中心对齐
if (
baseElement is MEPCurve mainMEPCurve
&& elementToMove is MEPCurve branchMEPCurve
&& radian < 135.0.ToRadian()
)
{
//if ((conn2.Shape == ConnectorProfileType.Oval || conn2.Shape == ConnectorProfileType.Rectangular))
//{
// var verticalJustification = mainMEPCurve.get_Parameter(BuiltInParameter.RBS_CURVE_VERT_OFFSET_PARAM);
// var delta = XYZ.BasisZ * (branchMEPCurve.Height / 2 - mainMEPCurve.Height / 2);
// //底部
// if (verticalJustification.AsInteger() == 1)
// {
// origin2 -= delta;
// }
// //顶部
// if (verticalJustification.AsInteger() == 2)
// {
// origin2 += delta;
// }
//}
//管线所在的垂直于xoy平面的面法向
var normal = XYZ.BasisZ.CrossProduct(direction2);
//如果是立管,则取不移动的管线的方向,过移动管线做平面
if (normal.IsZeroLength())
{
normal = direction1;
}
//}
//管线所在的垂直于xoy平面的面法向
var normal = XYZ.BasisZ.CrossProduct(direction2);
//如果是立管,则取不移动的管线的方向,过移动管线做平面
if (normal.IsZeroLength())
{
normal = direction1;
}
var plane = Plane.CreateByNormalAndOrigin(normal, origin2);
//找到交点
var intersectPoint = plane.IntersectPoint(Line.CreateUnbound(origin1, direction1));
//不相交则直接移动
if (intersectPoint == null)
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, origin1 - origin2);
}
else
{
//避免交点在原管线外,导致反向连接
if ((mainMEPCurve.GetLocCurve() as Line).IsInsideEx(intersectPoint, 0.5))
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, intersectPoint - origin2);
}
else
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, origin1 - origin2);
}
}
mainMEPCurve.ConnectTo(branchMEPCurve);
}
else
{
if (baseElement is MEPCurve baseMEPCurve && elementToMove is MEPCurve moveMEPCurve)
{
if (
(
conn2.Shape == ConnectorProfileType.Oval
|| conn2.Shape == ConnectorProfileType.Rectangular
)
)
{
var verticalJustification = baseMEPCurve.get_Parameter(
BuiltInParameter.RBS_CURVE_VERT_OFFSET_PARAM
);
var plane = Plane.CreateByNormalAndOrigin(normal, origin2);
//找到交点
var intersectPoint = plane.IntersectPoint(Line.CreateUnbound(origin1, direction1));
//不相交则直接移动
if (intersectPoint == null)
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, origin1 - origin2);
}
else
{
//避免交点在原管线外,导致反向连接
if ((mainMEPCurve.GetLocCurve() as Line).IsInsideEx(intersectPoint, 0.5))
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, intersectPoint - origin2);
}
else
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, origin1 - origin2);
}
}
mainMEPCurve.ConnectTo(branchMEPCurve);
}
else
{
if (baseElement is MEPCurve baseMEPCurve && elementToMove is MEPCurve moveMEPCurve)
{
if (
(
conn2.Shape == ConnectorProfileType.Oval
|| conn2.Shape == ConnectorProfileType.Rectangular
)
)
{
var verticalJustification = baseMEPCurve.get_Parameter(
BuiltInParameter.RBS_CURVE_VERT_OFFSET_PARAM
);
var delta = XYZ.BasisZ * (baseMEPCurve.Height / 2 - moveMEPCurve.Height / 2);
//底部
if (verticalJustification.AsInteger() == 1)
{
origin2 += delta;
}
//顶部
if (verticalJustification.AsInteger() == 2)
{
origin2 -= delta;
}
}
}
var xyz = origin1 - origin2;
var delta = XYZ.BasisZ * (baseMEPCurve.Height / 2 - moveMEPCurve.Height / 2);
//底部
if (verticalJustification.AsInteger() == 1)
{
origin2 += delta;
}
//顶部
if (verticalJustification.AsInteger() == 2)
{
origin2 -= delta;
}
}
}
var xyz = origin1 - origin2;
Document.InvokeSub(_ =>
{
if (!xyz.IsZeroLength())
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, xyz);
}
});
if (direction1.IsAlmostEqualTo(direction2.Negate())) //对齐
{
conn1.ConnectByFitting(conn2);
}
else
{
var xyz2 = direction1.CrossProduct(direction2); //旋转轴方向
if (direction1.IsAlmostEqualTo(direction2))
{
xyz2 = conn1.CoordinateSystem.BasisY;
}
var line = Line.CreateUnbound(origin1, xyz2);
var angle = direction1.AngleTo(direction2);
//互补角
var complementaryAngle = Math.PI - angle;
Document.InvokeSub(_ =>
{
if (!xyz.IsZeroLength())
{
ElementTransformUtils.MoveElement(Document, elementToMove!.Id, xyz);
}
});
if (direction1.IsAlmostEqualTo(direction2.Negate())) //对齐
{
conn1.ConnectByFitting(conn2);
}
else
{
var xyz2 = direction1.CrossProduct(direction2); //旋转轴方向
if (direction1.IsAlmostEqualTo(direction2))
{
xyz2 = conn1.CoordinateSystem.BasisY;
}
var line = Line.CreateUnbound(origin1, xyz2);
var angle = direction1.AngleTo(direction2);
//互补角
var complementaryAngle = Math.PI - angle;
ElementTransformUtils.RotateElement(Document, elementToMove!.Id, line, complementaryAngle);
ElementTransformUtils.RotateElement(Document, elementToMove!.Id, line, complementaryAngle);
conn1.ConnectByFitting(conn2);
}
}
},
"移动连接"
);
}
conn1.ConnectByFitting(conn2);
}
}
},
"移动连接"
);
}
}