整理代码
This commit is contained in:
20
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationCmd.cs
Normal file
20
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationCmd.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
public class AddInsulationCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<AddInsulationView>(new AddInsulationViewModel(Document));
|
||||
}
|
||||
}
|
||||
108
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationView.xaml
Normal file
108
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationView.xaml
Normal file
@@ -0,0 +1,108 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.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:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
xmlns:local="clr-namespace:ShrlAlgo.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:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ui:StackPanel
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
Margin="5"
|
||||
IsEnabled="{Binding AddToPipe, Mode=TwoWay}"
|
||||
Spacing="5">
|
||||
<ui:ComboBoxEx
|
||||
DisplayMemberPath="Name"
|
||||
Header="管道系统类型"
|
||||
ItemsSource="{Binding PipingSystemTypes}"
|
||||
SelectedItem="{Binding SelectedPipingSystemType}" />
|
||||
<DataGrid
|
||||
ui:StackPanel.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>
|
||||
</ui:StackPanel>
|
||||
<ui:StackPanel
|
||||
Grid.Column="1"
|
||||
Margin="5"
|
||||
IsEnabled="{Binding AddToDuct, Mode=TwoWay}"
|
||||
Spacing="5">
|
||||
<ui:ComboBoxEx
|
||||
DisplayMemberPath="Name"
|
||||
Header="风管系统类型:"
|
||||
ItemsSource="{Binding DuctSystemTypes}"
|
||||
SelectedItem="{Binding SelectedDuctSystem}" />
|
||||
<ui:ComboBoxEx
|
||||
DisplayMemberPath="Name"
|
||||
Header="保温层类型:"
|
||||
ItemsSource="{Binding DuctInsulationTypes}"
|
||||
SelectedItem="{Binding DuctInsulationItem.DuctInsulationType}" />
|
||||
<ui:TextBoxEx Header="保温层厚度:" Text="{Binding DuctInsulationItem.Thickness, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</ui:StackPanel>
|
||||
<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>
|
||||
</ui:FluentWindowEx>
|
||||
25
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationView.xaml.cs
Normal file
25
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationView.xaml.cs
Normal 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 ShrlAlgo.RvKits.RvMEP;
|
||||
/// <summary>
|
||||
/// AddInsulationView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class AddInsulationView
|
||||
{
|
||||
public AddInsulationView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
191
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationViewModel.cs
Normal file
191
ShrlAlgoToolkit.RevitAddins/RvMEP/AddInsulationViewModel.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
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 ShrlAlgo.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; }
|
||||
}
|
||||
}
|
||||
27
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectCmd.cs
Normal file
27
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectCmd.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
public class AnyConnectCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<AnyConnectView>(new AnyConnectViewModel());
|
||||
#if REVIT2018
|
||||
//WinDialogHelper.ShowModeless<AnyConnectView>(new AnyConnectViewModel());
|
||||
#elif REVIT2020
|
||||
//OptionsBarAssist.RegisterOptionsBar((AutoConnectOptionsView view, AnyConnectViewModel viewModel) =>
|
||||
//{
|
||||
// viewModel.ConnectCommand.Execute(null);
|
||||
//});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
116
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectView.xaml
Normal file
116
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectView.xaml
Normal file
@@ -0,0 +1,116 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.AnyConnectView"
|
||||
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:local="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="任意连接"
|
||||
Width="270"
|
||||
Height="350"
|
||||
MinHeight="350"
|
||||
d:DataContext="{d:DesignInstance Type=local:AnyConnectViewModel}"
|
||||
SizeToContent="Height"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:StackPanel Margin="5" Spacing="5">
|
||||
<ui:InfoBar
|
||||
VerticalAlignment="Top"
|
||||
IsOpen="{Binding ActiveSnackbar, Mode=OneWay}"
|
||||
Message="{Binding Message}" />
|
||||
<GroupBox Header="角度" ToolTip="平行或垂直连接时生效">
|
||||
<UniformGrid Columns="3">
|
||||
<RadioButton Content="默认" ToolTip="根据当前位置自动连接">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>0</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="15°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>15</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="22.5°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>22.5</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="30°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>30</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="45°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>45</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="60°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>60</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="90°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>90</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton x:Name="LbCustom" Content="自定义" />
|
||||
<TextBox
|
||||
VerticalAlignment="Center"
|
||||
IsEnabled="{Binding IsChecked, ElementName=LbCustom}"
|
||||
Text="{Binding Angle, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="选择方式">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton
|
||||
Content="多选"
|
||||
IsChecked="{Binding IsMultiSelect}"
|
||||
ToolTip="选择后完成" />
|
||||
<RadioButton
|
||||
Content="框选"
|
||||
IsChecked="{Binding IsMultiSelect, Converter={StaticResource InvertBooleanConverter}}"
|
||||
ToolTip="矩形框框选" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<ui:Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding ConnectCommand}"
|
||||
Content="连接管线"
|
||||
Icon="{ui:SymbolIcon Connector24}" />
|
||||
</ui:StackPanel>
|
||||
</ui:FluentWindowEx>
|
||||
28
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectView.xaml.cs
Normal file
28
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
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 ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
/// <summary>
|
||||
/// AnyConnectView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class AnyConnectView
|
||||
{
|
||||
public AnyConnectView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
1033
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectViewModel.cs
Normal file
1033
ShrlAlgoToolkit.RevitAddins/RvMEP/AnyConnectViewModel.cs
Normal file
File diff suppressed because it is too large
Load Diff
22
ShrlAlgoToolkit.RevitAddins/RvMEP/ArrangeMEPCurveCmd.cs
Normal file
22
ShrlAlgoToolkit.RevitAddins/RvMEP/ArrangeMEPCurveCmd.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
internal class ArrangeMEPCurveCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<ArrangeMEPCurveView>(new ArrangeMEPCurveViewModel());
|
||||
}
|
||||
}
|
||||
45
ShrlAlgoToolkit.RevitAddins/RvMEP/ArrangeMEPCurveView.xaml
Normal file
45
ShrlAlgoToolkit.RevitAddins/RvMEP/ArrangeMEPCurveView.xaml
Normal file
@@ -0,0 +1,45 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.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:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
|
||||
xmlns:local="clr-namespace:ShrlAlgo.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:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:StackPanel Margin="5" Spacing="5">
|
||||
<GroupBox Header="参考方向">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton Content="水平方向" IsChecked="{Binding IsHorizon}" />
|
||||
<RadioButton Content="垂直方向" IsChecked="{Binding IsHorizon, Converter={StaticResource InvertBooleanConverter}}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<ui: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="整理" />
|
||||
</ui:StackPanel>
|
||||
</ui:FluentWindowEx>
|
||||
@@ -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 ShrlAlgo.RvKits.RvMEP;
|
||||
/// <summary>
|
||||
/// ArrangeMEPCurveView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ArrangeMEPCurveView
|
||||
{
|
||||
public ArrangeMEPCurveView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
366
ShrlAlgoToolkit.RevitAddins/RvMEP/ArrangeMEPCurveViewModel.cs
Normal file
366
ShrlAlgoToolkit.RevitAddins/RvMEP/ArrangeMEPCurveViewModel.cs
Normal file
@@ -0,0 +1,366 @@
|
||||
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 ShrlAlgo.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.GetCurve() as Line).Direction.IsParallelTo(XYZ.BasisZ)),
|
||||
"请选择要整理的管线")
|
||||
.Select(e => e.Id)
|
||||
.ToList();
|
||||
if (ids.Count <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var baseId = uidoc.Selection
|
||||
.PickObject(
|
||||
Autodesk.Revit.UI.Selection.ObjectType.Element,
|
||||
new FuncFilter(e => ids.Contains(e.Id)),
|
||||
"请选择基准管线")
|
||||
.ElementId;
|
||||
|
||||
var baseElement = doc.GetElement(baseId);
|
||||
var baseLine = baseElement.GetCurve() 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.GetCurve() 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.GetCurve() 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]).GetCurve() 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.GetCurve() as Line).Origin.Z).GroupBy(e => (e.GetCurve() 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; }
|
||||
|
||||
}
|
||||
}
|
||||
111
ShrlAlgoToolkit.RevitAddins/RvMEP/AutoConnectOptionsView.xaml
Normal file
111
ShrlAlgoToolkit.RevitAddins/RvMEP/AutoConnectOptionsView.xaml
Normal file
@@ -0,0 +1,111 @@
|
||||
<StackPanel
|
||||
Background="#FFE5F0D7"
|
||||
Height="26"
|
||||
Orientation="Horizontal"
|
||||
d:DataContext="{d:DesignInstance Type=local:AnyConnectViewModel}"
|
||||
mc:Ignorable="d"
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.AutoConnectOptionsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="clr-namespace:ShrlAlgoToolkit.Mvvm.Converters;assembly=ShrlAlgoToolkit.Mvvm">
|
||||
<StackPanel.Resources>
|
||||
<converters:ComparisonConverter x:Key="ComparisonConverter" />
|
||||
<converters:InvertBooleanConverter x:Key="InvertBooleanConverter" />
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
</StackPanel.Resources>
|
||||
<TextBlock
|
||||
Padding="10,0,10,0"
|
||||
Text="任意管线 | 选项"
|
||||
VerticalAlignment="Center" />
|
||||
<Border
|
||||
Background="Gray"
|
||||
BorderBrush="Azure"
|
||||
BorderThickness="1,0"
|
||||
Width="3" />
|
||||
<TextBlock
|
||||
Margin="10,0,10,0"
|
||||
Text="连接角度:"
|
||||
ToolTip="平行或垂直连接时生效"
|
||||
VerticalAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<RadioButton
|
||||
Content="默认"
|
||||
ToolTip="根据当前位置自动连接"
|
||||
VerticalAlignment="Center">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>0</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="15°" VerticalAlignment="Center">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>15</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="22.5°" VerticalAlignment="Center">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>22.5</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="30°" VerticalAlignment="Center">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>30</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="45°" VerticalAlignment="Center">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>45</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="60°" VerticalAlignment="Center">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>60</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="90°" VerticalAlignment="Center">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<system:Double>90</system:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton
|
||||
Content="自定义:"
|
||||
VerticalAlignment="Center"
|
||||
x:Name="LbCustom" />
|
||||
<TextBox
|
||||
Text="{Binding Angle, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0}°}"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=LbCustom}"
|
||||
Width="80" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
@@ -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 ShrlAlgo.RvKits.RvMEP;
|
||||
/// <summary>
|
||||
/// AutoConnectOptionsView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class AutoConnectOptionsView
|
||||
{
|
||||
public AutoConnectOptionsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
564
ShrlAlgoToolkit.RevitAddins/RvMEP/BloomConnectorCmd.cs
Normal file
564
ShrlAlgoToolkit.RevitAddins/RvMEP/BloomConnectorCmd.cs
Normal file
@@ -0,0 +1,564 @@
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Electrical;
|
||||
|
||||
using Autodesk.Revit.DB.Mechanical;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
|
||||
|
||||
using System.Collections;
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
|
||||
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
|
||||
internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根短管
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
var elemIds = UiDocument.Selection.GetElementIds();
|
||||
if (elemIds.Count == 0)
|
||||
{
|
||||
var reference = UiDocument.Selection
|
||||
.PickObject(
|
||||
ObjectType.Element,
|
||||
new FuncFilter(e => e is FamilyInstance ins && ins.GetConnectors(true).Size > 0),
|
||||
"请选择族实例");
|
||||
elemIds.Add(Document.GetElement(reference).Id);
|
||||
}
|
||||
|
||||
foreach (var elemId in elemIds)
|
||||
{
|
||||
var pipeTypeId = Document.OfClass<PipeType>().FirstElementId();
|
||||
var cableTrayTypeId = Document.OfClass<CableTrayType>().FirstElementId();
|
||||
var conduitTypeId = Document.OfClass<ConduitType>().FirstElementId();
|
||||
|
||||
var ductTypeCollector = Document.OfClass<DuctType>().Cast<DuctType>();
|
||||
var roundDuctTypeId = ElementId.InvalidElementId;
|
||||
var rectangleDuctTypeId = ElementId.InvalidElementId;
|
||||
var ovalDuctTypeId = ElementId.InvalidElementId;
|
||||
//设置默认的风管类型
|
||||
foreach (var ductType in ductTypeCollector)
|
||||
{
|
||||
if (ductType.FamilyName == "圆形风管" || ductType.FamilyName.Contains("Round Duct"))
|
||||
{
|
||||
roundDuctTypeId = ductType.Id;
|
||||
}
|
||||
else if (ductType.FamilyName == "矩形风管" || ductType.FamilyName.Contains("Rectangular Duct"))
|
||||
{
|
||||
rectangleDuctTypeId = ductType.Id;
|
||||
}
|
||||
else if (ductType.FamilyName == "椭圆形风管" || ductType.FamilyName.Contains("Oval Duct"))
|
||||
{
|
||||
ovalDuctTypeId = ductType.Id;
|
||||
}
|
||||
}
|
||||
var fabricationConfiguration = FabricationConfiguration.GetFabricationConfiguration(Document);
|
||||
|
||||
var elem = Document.GetElement(elemId);
|
||||
if (elem.GetConnectors(true).IsEmpty && elem is not FamilyInstance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CableTray referCabTray = null;
|
||||
Conduit referConduit = null;
|
||||
//根据连接件拿到连接的管线的类型
|
||||
foreach (Connector conn in elem.GetConnectors())
|
||||
{
|
||||
if (conn.IsConnected)
|
||||
{
|
||||
var connector = conn.GetConnectedConnector();
|
||||
if (connector == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (conn.Domain == Domain.DomainPiping && connector.Owner is Pipe)
|
||||
{
|
||||
pipeTypeId = connector.Owner.GetTypeId();
|
||||
}
|
||||
else if (conn.Domain == Domain.DomainHvac)
|
||||
{
|
||||
switch (connector.Shape)
|
||||
{
|
||||
case ConnectorProfileType.Invalid:
|
||||
break;
|
||||
case ConnectorProfileType.Round:
|
||||
roundDuctTypeId = connector.Owner.GetTypeId();
|
||||
break;
|
||||
case ConnectorProfileType.Rectangular:
|
||||
rectangleDuctTypeId = connector.Owner.GetTypeId();
|
||||
break;
|
||||
case ConnectorProfileType.Oval:
|
||||
ovalDuctTypeId = connector.Owner.GetTypeId();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (conn.Domain == Domain.DomainCableTrayConduit)
|
||||
{
|
||||
if (connector.Owner is CableTray cableTray)
|
||||
{
|
||||
referCabTray = cableTray;
|
||||
cableTrayTypeId = cableTray.GetTypeId();
|
||||
}
|
||||
else if (connector.Owner is Conduit conduit)
|
||||
{
|
||||
referConduit = conduit;
|
||||
conduitTypeId = conduit.GetTypeId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Document.Invoke(
|
||||
_ =>
|
||||
{
|
||||
var connectors = elem.GetConnectors(true);
|
||||
foreach (Connector connector in connectors)
|
||||
{
|
||||
Element element = null;
|
||||
if (elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_FabricationPipework)
|
||||
{
|
||||
var serviceId = (elem as FabricationPart).ServiceId;
|
||||
var button = fabricationConfiguration.GetService(serviceId).GetButton(0, 0);
|
||||
var fabricationPart = FabricationPart.Create(Document, button, 0, elem.LevelId);
|
||||
var enumerator2 = fabricationPart.ConnectorManager.Connectors.GetEnumerator();
|
||||
if (enumerator2.MoveNext())
|
||||
{
|
||||
var connector2 = (Connector)enumerator2.Current;
|
||||
ElementTransformUtils.MoveElement(
|
||||
Document,
|
||||
fabricationPart.Id,
|
||||
connector.Origin - connector2.Origin
|
||||
);
|
||||
var basisZ = connector.CoordinateSystem.BasisZ;
|
||||
var basisZ2 = connector2.CoordinateSystem.BasisZ;
|
||||
var num = basisZ.DotProduct(basisZ2);
|
||||
if (Math.Abs(num - -1.0) < 0.0001)
|
||||
{
|
||||
connector2.ConnectTo(connector);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var xyz = basisZ.CrossProduct(basisZ2);
|
||||
|
||||
var line = Line.CreateBound(connector.Origin, connector.Origin + (10000000000000000.0 * xyz));
|
||||
var angleTo = basisZ.AngleTo(basisZ2);
|
||||
var angle = Math.PI - angleTo;
|
||||
ElementTransformUtils.RotateElement(Document, fabricationPart.Id, line, angle);
|
||||
if (connector2.Shape == ConnectorProfileType.Invalid)
|
||||
{
|
||||
connector2.Radius = connector.Radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
connector2.Width = connector.Width;
|
||||
connector2.Height = connector.Height;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
var extensionLength = connector.GetExtensionLength();
|
||||
var origin = connector.Origin;
|
||||
//延伸后的点
|
||||
var xyz2 = origin + (extensionLength * connector.CoordinateSystem.BasisZ);
|
||||
var levelId = elem.LevelId;
|
||||
if (levelId == ElementId.InvalidElementId)
|
||||
{
|
||||
var pa = elem.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM);
|
||||
if (pa != null)
|
||||
{
|
||||
levelId = pa.AsElementId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (levelId == ElementId.InvalidElementId)
|
||||
{
|
||||
if (elem is FamilyInstance { Host: Level } instance)
|
||||
{
|
||||
levelId = instance.Host.Id;
|
||||
}
|
||||
}
|
||||
|
||||
switch (connector.Domain)
|
||||
{
|
||||
//未定义
|
||||
case Domain.DomainUndefined:
|
||||
break;
|
||||
//风管
|
||||
case Domain.DomainHvac:
|
||||
//var mechanicalSystemTypes = new FilteredElementCollector(Document)
|
||||
// .OfClass(typeof(MechanicalSystemType))
|
||||
// .Cast<MechanicalSystemType>();
|
||||
////风管系统类型
|
||||
//var mechanicalSystem =
|
||||
// connector.MEPSystem == null
|
||||
// ? connector.DuctSystemType switch
|
||||
// {
|
||||
// //送风
|
||||
// DuctSystemType.SupplyAir
|
||||
// => mechanicalSystemTypes.FirstOrDefault(
|
||||
// pst =>
|
||||
// pst.SystemClassification
|
||||
// == Autodesk.Revit.DB.MEPSystemClassification.SupplyAir
|
||||
// ),
|
||||
// //回风
|
||||
// DuctSystemType.ReturnAir
|
||||
// => mechanicalSystemTypes.FirstOrDefault(
|
||||
// pst =>
|
||||
// pst.SystemClassification
|
||||
// == Autodesk.Revit.DB.MEPSystemClassification.ReturnAir
|
||||
// ),
|
||||
// //排风
|
||||
// DuctSystemType.ExhaustAir
|
||||
// => mechanicalSystemTypes.FirstOrDefault(
|
||||
// pst =>
|
||||
// pst.SystemClassification
|
||||
// == Autodesk.Revit.DB.MEPSystemClassification.ExhaustAir
|
||||
// ),
|
||||
// _
|
||||
// => mechanicalSystemTypes.FirstOrDefault(
|
||||
// pst =>
|
||||
// pst.SystemClassification
|
||||
// == Autodesk.Revit.DB.MEPSystemClassification.OtherAir
|
||||
// )
|
||||
// }
|
||||
// : Document.GetElement(connector.MEPSystem.GetTypeId()) as MechanicalSystemType;
|
||||
|
||||
//if (new FilteredElementCollector(Document).OfClass(typeof(DuctType)).FirstElement() is not DuctType)
|
||||
//{
|
||||
// break;
|
||||
//}
|
||||
|
||||
//风管形状
|
||||
switch (connector.Shape)
|
||||
{
|
||||
case ConnectorProfileType.Round:
|
||||
element = Duct.Create(
|
||||
Document,
|
||||
roundDuctTypeId,
|
||||
levelId,
|
||||
connector,
|
||||
xyz2
|
||||
);
|
||||
|
||||
Document.Regenerate();
|
||||
element.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).Set(connector.Radius * 2);
|
||||
break;
|
||||
|
||||
case ConnectorProfileType.Rectangular:
|
||||
element = Duct.Create(
|
||||
Document,
|
||||
rectangleDuctTypeId,
|
||||
levelId,
|
||||
connector,
|
||||
xyz2
|
||||
);
|
||||
Document.Regenerate();
|
||||
var width = Math.Max(connector.Width, connector.Height);
|
||||
var height = Math.Min(connector.Width, connector.Height);
|
||||
element.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(width);
|
||||
element.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(height);
|
||||
break;
|
||||
|
||||
case ConnectorProfileType.Oval:
|
||||
element = Duct.Create(Document, ovalDuctTypeId, levelId, connector, xyz2);
|
||||
Document.Regenerate();
|
||||
var w = Math.Max(connector.Width, connector.Height);
|
||||
var h = Math.Min(connector.Width, connector.Height);
|
||||
element.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(w);
|
||||
element.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(h);
|
||||
break;
|
||||
|
||||
default:
|
||||
element = Duct.Create(
|
||||
Document,
|
||||
roundDuctTypeId,
|
||||
levelId,
|
||||
connector,
|
||||
xyz2
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
//电气
|
||||
case Domain.DomainElectrical:
|
||||
break;
|
||||
//水管
|
||||
case Domain.DomainPiping:
|
||||
var pipingSystemTypes = new FilteredElementCollector(Document)
|
||||
.OfClass(typeof(PipingSystemType))
|
||||
.Cast<PipingSystemType>();
|
||||
if (pipeTypeId == ElementId.InvalidElementId)
|
||||
{
|
||||
pipeTypeId = Document.OfClass<PipeType>().FirstElementId();
|
||||
}
|
||||
var system = connector.MEPSystem;
|
||||
var pipingSystemType =
|
||||
system != null
|
||||
? Document.GetElement(system.GetTypeId()) as PipingSystemType
|
||||
: connector.PipeSystemType switch
|
||||
{
|
||||
//循环供水
|
||||
PipeSystemType.SupplyHydronic
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.SupplyHydronic
|
||||
),
|
||||
//循环回水
|
||||
PipeSystemType.ReturnHydronic
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.ReturnHydronic
|
||||
),
|
||||
//卫生设备
|
||||
PipeSystemType.Sanitary
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.Sanitary
|
||||
),
|
||||
//家用热水
|
||||
PipeSystemType.DomesticHotWater
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.DomesticHotWater
|
||||
),
|
||||
//家用冷水
|
||||
PipeSystemType.DomesticColdWater
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.DomesticColdWater
|
||||
),
|
||||
//其他
|
||||
PipeSystemType.OtherPipe
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.OtherPipe
|
||||
),
|
||||
//湿式消防系统
|
||||
PipeSystemType.FireProtectWet
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.FireProtectWet
|
||||
),
|
||||
//干式消防系统
|
||||
PipeSystemType.FireProtectDry
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.FireProtectDry
|
||||
),
|
||||
//预作用消防系统
|
||||
PipeSystemType.FireProtectPreaction
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.FireProtectPreaction
|
||||
),
|
||||
//其他消防系统
|
||||
PipeSystemType.FireProtectOther
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.FireProtectOther
|
||||
),
|
||||
//通风孔
|
||||
PipeSystemType.Vent
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.Vent
|
||||
),
|
||||
_
|
||||
=> pipingSystemTypes.FirstOrDefault(
|
||||
pst =>
|
||||
pst.SystemClassification
|
||||
== Autodesk.Revit.DB.MEPSystemClassification.OtherPipe
|
||||
)
|
||||
};
|
||||
|
||||
element = Pipe.Create(Document, pipingSystemType.Id, pipeTypeId, levelId, origin, xyz2);
|
||||
element.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(connector.Radius * 2);
|
||||
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();
|
||||
//}
|
||||
|
||||
|
||||
//switch (connector.ElectricalSystemType)
|
||||
//{
|
||||
// //电力
|
||||
// case ElectricalSystemType.PowerCircuit:
|
||||
|
||||
// break;
|
||||
//}
|
||||
|
||||
switch (connector.Shape)
|
||||
{
|
||||
case ConnectorProfileType.Invalid:
|
||||
break;
|
||||
|
||||
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:
|
||||
var width = Math.Max(connector.Width, connector.Height);
|
||||
var height = Math.Min(connector.Width, connector.Height);
|
||||
element = CableTray.Create(Document, cableTrayTypeId, origin, xyz2, levelId);
|
||||
element.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).Set(width);
|
||||
element.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).Set(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:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Document.Regenerate();
|
||||
//新建管线连接
|
||||
if (element == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var curve = element as MEPCurve;
|
||||
var conns = curve.ConnectorManager.UnusedConnectors.Cast<Connector>();
|
||||
foreach (var connect in conns)
|
||||
{
|
||||
if (connect.Origin.IsAlmostEqualTo(connector.Origin))
|
||||
{
|
||||
Debug.WriteLine("新建管线:");
|
||||
Debug.WriteLine(connect.CoordinateSystem.BasisX);
|
||||
Debug.WriteLine(connect.CoordinateSystem.BasisY);
|
||||
Debug.WriteLine(connect.CoordinateSystem.BasisZ);
|
||||
Debug.WriteLine("管件:");
|
||||
Debug.WriteLine(connector.CoordinateSystem.BasisX);
|
||||
Debug.WriteLine(connector.CoordinateSystem.BasisY);
|
||||
Debug.WriteLine(connector.CoordinateSystem.BasisZ);
|
||||
var isStandMEPCurve = connect.CoordinateSystem.BasisZ.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero);
|
||||
|
||||
if (isStandMEPCurve)
|
||||
{
|
||||
var angleX = Math.Acos(connect.CoordinateSystem.BasisX.DotProduct(connector.CoordinateSystem.BasisX));
|
||||
Debug.WriteLine(angleX);
|
||||
var crossProduct = connect.CoordinateSystem.BasisX
|
||||
.CrossProduct(connector.CoordinateSystem.BasisX).Normalize();
|
||||
var angle = Math.Acos(connect.CoordinateSystem.BasisX.DotProduct(connector.CoordinateSystem.BasisX));
|
||||
if (crossProduct.IsAlmostEqualTo(XYZ.Zero))
|
||||
{
|
||||
if (connect.CoordinateSystem.BasisX
|
||||
.IsAlmostEqualTo(connector.CoordinateSystem.BasisX))
|
||||
{
|
||||
ElementTransformUtils.RotateElement(
|
||||
Document,
|
||||
element.Id,
|
||||
Line.CreateUnbound(origin, XYZ.BasisZ),
|
||||
Math.PI / 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (angleX > Math.PI / 2)
|
||||
{
|
||||
ElementTransformUtils.RotateElement(
|
||||
Document,
|
||||
element.Id,
|
||||
Line.CreateUnbound(origin, XYZ.BasisZ),
|
||||
angleX - Math.PI / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ElementTransformUtils.RotateElement(
|
||||
Document,
|
||||
element.Id,
|
||||
Line.CreateUnbound(origin, XYZ.BasisZ),
|
||||
Math.PI / 2 - angleX);
|
||||
}
|
||||
}
|
||||
//if (Math.Abs(angleX - Math.PI / 2) > 0.001)
|
||||
//{
|
||||
// ElementTransformUtils.RotateElement(
|
||||
// Document,
|
||||
// element.Id,
|
||||
// Line.CreateUnbound(origin, crossProduct),
|
||||
// angleX - Math.PI / 2
|
||||
// );
|
||||
// Debug.WriteLine("旋转后新建管线:");
|
||||
// Debug.WriteLine(connect.CoordinateSystem.BasisX);
|
||||
// Debug.WriteLine(connect.CoordinateSystem.BasisY);
|
||||
// Debug.WriteLine(connect.CoordinateSystem.BasisZ);
|
||||
// Document.Regenerate();
|
||||
// angle = Math.Acos(connect.CoordinateSystem.BasisX.DotProduct(connector.CoordinateSystem.BasisX));
|
||||
// Debug.WriteLine(nameof(angle) + angle);
|
||||
//}
|
||||
}
|
||||
var conn = elem.GetConnectors(true).GetNearestConnector(connector.Origin);
|
||||
if (!connect.IsConnectedTo(connector))
|
||||
{
|
||||
connect.ConnectTo(connector);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"引出短管"
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
Result = Result.Cancelled;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
ShrlAlgoToolkit.RevitAddins/RvMEP/BreakMEPCurveCmd.cs
Normal file
81
ShrlAlgoToolkit.RevitAddins/RvMEP/BreakMEPCurveCmd.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Mechanical;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
/// <summary>
|
||||
/// Revit执行命令
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class BreakMEPCurveCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var filter1 = new FuncFilter(
|
||||
e => e is MEPCurve and not InsulationLiningBase and not FlexDuct and not FlexPipe);
|
||||
var refer1 = UiDocument.Selection.PickObject(
|
||||
ObjectType.PointOnElement, filter1
|
||||
, "拾取打断管线的位置");
|
||||
var pointPicked = refer1.GlobalPoint;
|
||||
|
||||
var mepCurve = UiDocument.Document.GetElement(refer1) as MEPCurve;
|
||||
var loc = mepCurve.GetCurve() as Line;
|
||||
var d = loc.Direction;
|
||||
var halfGap = 20 / 304.8;
|
||||
var point1 = pointPicked - d * halfGap;
|
||||
var point2 = pointPicked + d * halfGap;
|
||||
|
||||
var breakPoint1 = mepCurve.GetCurve().Project(point1).XYZPoint;
|
||||
var breakPoint2 = mepCurve.GetCurve().Project(point2).XYZPoint;
|
||||
if (!loc.IsInsideEx(breakPoint1, halfGap) || !loc.IsInsideEx(breakPoint2, halfGap))
|
||||
{
|
||||
MessageBox.Show("打断点距离管线端点太近");
|
||||
continue;
|
||||
}
|
||||
//var direction = breakPoint2 - breakPoint1;
|
||||
//var flag = direction.Normalize().IsAlmostEqualTo(loc.Direction);
|
||||
|
||||
Document.Invoke(_ =>
|
||||
{
|
||||
var second = mepCurve.BreakByPoint(breakPoint1);
|
||||
var third = mepCurve.BreakByPoint(breakPoint2);
|
||||
Document.Delete(third);
|
||||
|
||||
//if (flag)
|
||||
//{
|
||||
// var second = mepCurve.BreakByPoint(breakPoint1);
|
||||
// var third = mepCurve.BreakByPoint(breakPoint2);
|
||||
// Document.Delete(third);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// var second = mepCurve.BreakByPoint(breakPoint2);
|
||||
// //var mepCurve2 = Document.GetElement(second) as ElementToMove;
|
||||
// var third = mepCurve.BreakByPoint(breakPoint1);
|
||||
// Document.Delete(third);
|
||||
|
||||
//}
|
||||
|
||||
}, "打断管线");
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
110
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutCmd.cs
Normal file
110
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutCmd.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Electrical;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class CableLayoutCmd : ExternalCommand
|
||||
{
|
||||
private readonly List<Element> elems = new();
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
CableLayoutView view = new(Document);
|
||||
|
||||
if (view.ShowDialog() != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var count = view.ViewModel.Count;
|
||||
var conduitType = view.ViewModel.SelectedConduitType;
|
||||
var size = view.ViewModel.Size;
|
||||
Document.Invoke(
|
||||
_ =>
|
||||
{
|
||||
//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;
|
||||
var xyz = refer.GlobalPoint;
|
||||
//Curve curve = (ct.Location as LocationCurve).Curve;
|
||||
//XYZ project = curve.ProjectOf(xyz).XYZPoint;
|
||||
elems.Add(ct);
|
||||
var connector = ct.ConnectorManager.Connectors.GetNearestConnector(xyz);
|
||||
connector.GetAllRefsElements(elems);
|
||||
Dictionary<int, List<Conduit>> dictionary = new();
|
||||
List<Conduit> firstConduits = new();
|
||||
var interval = size.OuterDiameter;
|
||||
foreach (var elem in elems)
|
||||
{
|
||||
if (elem is MEPCurve mepCurve)
|
||||
{
|
||||
var conduit = Conduit.Create(
|
||||
Document,
|
||||
conduitType.Id,
|
||||
mepCurve.GetCurve().GetEndPoint(0),
|
||||
mepCurve.GetCurve().GetEndPoint(1),
|
||||
mepCurve.LevelId
|
||||
);
|
||||
firstConduits.Add(conduit);
|
||||
}
|
||||
}
|
||||
dictionary.Add(0, firstConduits);
|
||||
if (count > 2)
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
List<Conduit> conduits = new();
|
||||
var x = Math.Pow(-1, i);
|
||||
var y = Math.Ceiling(i / 2.0);
|
||||
var offest = x * y * interval;
|
||||
if (count % 2 == 0)
|
||||
{
|
||||
offest += interval / 2;
|
||||
}
|
||||
|
||||
foreach (var conduit in firstConduits)
|
||||
{
|
||||
var line = conduit.GetCurve() as Line;
|
||||
var direction = line!.Direction.CrossProduct(XYZ.BasisZ);
|
||||
var id = ElementTransformUtils.CopyElement(Document, conduit.Id, direction * offest).FirstOrDefault();
|
||||
var conduitCopied = Document.GetElement(id) as Conduit;
|
||||
conduits.Add(conduitCopied);
|
||||
}
|
||||
dictionary.Add(i + 1, conduits);
|
||||
}
|
||||
Document.Regenerate();
|
||||
}
|
||||
for (var i = 0; i < dictionary.Count; i++)
|
||||
{
|
||||
var conduits = dictionary[i];
|
||||
for (var j = 0; j < conduits.Count - 1; j++)
|
||||
{
|
||||
var conduit = conduits[j];
|
||||
var conduit1 = conduits[j + 1];
|
||||
|
||||
var list = ConnectorAssist.GetNearestConnectors(conduit, conduit1);
|
||||
if (list[0] != null && list[1] != null)
|
||||
{
|
||||
Document.Create.NewElbowFitting(list[0], list[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count % 2 == 0)
|
||||
{
|
||||
Document.Delete(firstConduits.Select(e => e.Id).ToList());
|
||||
}
|
||||
},
|
||||
"敷设电缆"
|
||||
);
|
||||
}
|
||||
}
|
||||
50
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutView.xaml
Normal file
50
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutView.xaml
Normal file
@@ -0,0 +1,50 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.CableLayoutView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:electricDesign="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="线缆布置"
|
||||
Width="220"
|
||||
Height="200"
|
||||
MinWidth="220"
|
||||
d:DataContext="{d:DesignInstance Type=electricDesign:CableLayoutViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:StackPanel Margin="5" Spacing="5">
|
||||
<ui:ComboBoxEx
|
||||
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
|
||||
ItemsSource="{Binding Specifications}"
|
||||
PlaceholderText="线缆型号"
|
||||
SelectedItem="{Binding SelectedConduitType, UpdateSourceTrigger=PropertyChanged}">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="SelectionChanged">
|
||||
<b:InvokeCommandAction Command="{Binding SelectionTypeCommand}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
</ui:ComboBoxEx>
|
||||
<ui:ComboBoxEx
|
||||
DisplayMemberPath="Key"
|
||||
ItemsSource="{Binding Sizes}"
|
||||
PlaceholderText="线缆线径"
|
||||
SelectedValue="{Binding Size, UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectedValuePath="Value" />
|
||||
<ui:TextBox
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
PlaceholderText="线缆数量"
|
||||
Text="{Binding Count, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Button HorizontalAlignment="Stretch" Content="布置">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="Click">
|
||||
<b:InvokeCommandAction Command="{Binding CloseWinCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
</Button>
|
||||
</ui:StackPanel>
|
||||
</ui:FluentWindowEx>
|
||||
20
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutView.xaml.cs
Normal file
20
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutView.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
/// <summary>
|
||||
/// CableLayoutView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CableLayoutView
|
||||
{
|
||||
public CableLayoutViewModel ViewModel = null;
|
||||
|
||||
public CableLayoutView(Document doc)
|
||||
{
|
||||
ViewModel = new CableLayoutViewModel(doc);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
83
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutViewModel.cs
Normal file
83
ShrlAlgoToolkit.RevitAddins/RvMEP/CableLayoutViewModel.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Electrical;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
public partial class CableLayoutViewModel : ObservableValidator
|
||||
{
|
||||
private readonly Document doc;
|
||||
public CableLayoutViewModel(Document doc)
|
||||
{
|
||||
this.doc = doc;
|
||||
specifications = new FilteredElementCollector(doc).OfClass(typeof(ConduitType)).Cast<ConduitType>().ToList();
|
||||
}
|
||||
[ObservableProperty]
|
||||
private ConduitType selectedConduitType;
|
||||
|
||||
[Range(1, 20, ErrorMessage = "输入值有误!")]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private int count;
|
||||
|
||||
//public int Count
|
||||
//{
|
||||
// get => count;
|
||||
// set => SetProperty(ref count, value, true);
|
||||
//}
|
||||
|
||||
[ObservableProperty]
|
||||
private List<ConduitType> specifications;
|
||||
[ObservableProperty]
|
||||
private ConduitSize size;
|
||||
[ObservableProperty]
|
||||
private Dictionary<string, ConduitSize> sizes;
|
||||
|
||||
[RelayCommand]
|
||||
private void CloseWin(object obj)
|
||||
{
|
||||
if (obj is System.Windows.Window window && Count > 0 && Size != null && SelectedConduitType != null)
|
||||
{
|
||||
window.DialogResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectionType()
|
||||
{
|
||||
var enumerator = ConduitSizeSettings.GetConduitSizeSettings(doc).GetEnumerator();
|
||||
var standardName = SelectedConduitType.get_Parameter(BuiltInParameter.CONDUIT_STANDARD_TYPE_PARAM).AsValueString();
|
||||
ConduitSizes sizes = null;
|
||||
Dictionary<string, ConduitSize> dictionary = new();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var current = enumerator.Current;
|
||||
if (current.Key == standardName)
|
||||
{
|
||||
sizes = current.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sizes != null)
|
||||
{
|
||||
foreach (var size in sizes)
|
||||
{
|
||||
var key = (size.NominalDiameter * 304.8).ToString();
|
||||
dictionary.Add(key, size);
|
||||
}
|
||||
}
|
||||
|
||||
Sizes = dictionary;
|
||||
}
|
||||
}
|
||||
20
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportCmd.cs
Normal file
20
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportCmd.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
/// <summary>
|
||||
/// Revit执行命令
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class ClashReportCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<ClashReportView>(new ClashReportViewModel(UiApplication));
|
||||
}
|
||||
}
|
||||
142
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportView.xaml
Normal file
142
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportView.xaml
Normal file
@@ -0,0 +1,142 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.ClashReportView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="碰撞报告"
|
||||
Width="700"
|
||||
Height="450"
|
||||
MinHeight="450"
|
||||
d:DataContext="{d:DesignInstance Type=local:ClashReportViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<ui:AutoGrid
|
||||
ChildMargin="5"
|
||||
Columns="*"
|
||||
Rows="*,Auto">
|
||||
<DataGrid
|
||||
AutoGenerateColumns="True"
|
||||
CanUserAddRows="True"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding CurrentViewItems.DefaultView}"
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="MouseDoubleClick">
|
||||
<b:InvokeCommandAction Command="{Binding LocationCommand}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}, Mode=FindAncestor}}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
<DataGrid.Template>
|
||||
<ControlTemplate>
|
||||
<Border
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
SnapsToDevicePixels="True">
|
||||
<ScrollViewer
|
||||
x:Name="DG_ScrollViewer"
|
||||
CanContentScroll="True"
|
||||
Focusable="false">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="ScrollChanged">
|
||||
<b:InvokeCommandAction Command="{Binding LvScrollCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ScrollViewer}, Mode=FindAncestor}}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
<ScrollViewer.Template>
|
||||
<ControlTemplate TargetType="{x:Type ScrollViewer}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Button
|
||||
Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
|
||||
Command="{x:Static DataGrid.SelectAllCommand}"
|
||||
Focusable="false"
|
||||
Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle,
|
||||
TypeInTargetAssembly={x:Type DataGrid}}}"
|
||||
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
|
||||
<DataGridColumnHeadersPresenter
|
||||
x:Name="PART_ColumnHeadersPresenter"
|
||||
Grid.Column="1"
|
||||
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
|
||||
<ScrollContentPresenter
|
||||
x:Name="PART_ScrollContentPresenter"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
CanContentScroll="{TemplateBinding CanContentScroll}" />
|
||||
<ScrollBar
|
||||
x:Name="PART_VerticalScrollBar"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Maximum="{TemplateBinding ScrollableHeight}"
|
||||
Orientation="Vertical"
|
||||
ViewportSize="{TemplateBinding ViewportHeight}"
|
||||
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
|
||||
Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
|
||||
<Grid Grid.Row="2" Grid.Column="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollBar
|
||||
x:Name="PART_HorizontalScrollBar"
|
||||
Grid.Column="1"
|
||||
Maximum="{TemplateBinding ScrollableWidth}"
|
||||
Orientation="Horizontal"
|
||||
ViewportSize="{TemplateBinding ViewportWidth}"
|
||||
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
|
||||
Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</ScrollViewer.Template>
|
||||
<StackPanel IsItemsHost="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</DataGrid.Template>
|
||||
</DataGrid>
|
||||
<ui:StackPanel
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal"
|
||||
Spacing="5">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox
|
||||
Content="当前视图"
|
||||
IsChecked="{Binding InCurrentView, UpdateSourceTrigger=PropertyChanged}"
|
||||
ToolTip="在当前视图中去定位" />
|
||||
<CheckBox
|
||||
Content="修改剖面框"
|
||||
IsChecked="{Binding IsSetSectionBox, UpdateSourceTrigger=PropertyChanged}"
|
||||
ToolTip="只选中构件,不修改剖面框" />
|
||||
</StackPanel>
|
||||
<Button
|
||||
Width="75"
|
||||
Command="{Binding OpenFileCommand}"
|
||||
Content="打开" />
|
||||
<Button
|
||||
Width="75"
|
||||
Command="{Binding RefreshCommand}"
|
||||
Content="刷新" />
|
||||
</ui:StackPanel>
|
||||
</ui:AutoGrid>
|
||||
</ui:FluentWindowEx>
|
||||
13
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportView.xaml.cs
Normal file
13
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportView.xaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
/// <summary>
|
||||
/// ClashReportView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ClashReportView
|
||||
{
|
||||
public ClashReportView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
}
|
||||
312
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportViewModel.cs
Normal file
312
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashReportViewModel.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using HtmlAgilityPack;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
public partial class ClashReportViewModel(UIApplication uiapp) : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(RefreshCommand))]
|
||||
private string filePathName;
|
||||
public UIApplication UiApp { get; set; } = uiapp;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool inCurrentView = true;
|
||||
[ObservableProperty]
|
||||
private bool isSetSectionBox;
|
||||
|
||||
public DataTable DataSource { get; set; } = new DataTable();
|
||||
[ObservableProperty]
|
||||
private DataTable currentViewItems = new();
|
||||
[RelayCommand]
|
||||
private void LvScroll(ScrollViewer scrollViewer)
|
||||
{
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
if (!isLoadingData && scrollViewer.VerticalOffset + scrollViewer.ViewportHeight == scrollViewer.ExtentHeight)//必须等于
|
||||
{
|
||||
LoadMoreData();
|
||||
}
|
||||
}
|
||||
|
||||
private const int VbBatchSize = 20;
|
||||
private bool isLoadingData;
|
||||
private void LoadInitialData()
|
||||
{
|
||||
isLoadingData = true;
|
||||
CurrentViewItems.Clear();
|
||||
var size = VbBatchSize;
|
||||
if (DataSource.Rows.Count < VbBatchSize)
|
||||
{
|
||||
size = DataSource.Rows.Count;
|
||||
}
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
CurrentViewItems.ImportRow(DataSource.Rows[i]);
|
||||
}
|
||||
|
||||
//CurrentViewItems = CurrentViewItems;
|
||||
isLoadingData = false;
|
||||
}
|
||||
private void LoadMoreData()
|
||||
{
|
||||
isLoadingData = true;
|
||||
var startIndex = CurrentViewItems.Rows.Count;
|
||||
var end = startIndex + VbBatchSize;
|
||||
if (end > DataSource.Rows.Count)
|
||||
{
|
||||
end = DataSource.Rows.Count;
|
||||
}
|
||||
if (startIndex < end + 1)
|
||||
{
|
||||
for (var i = startIndex; i < end; i++)
|
||||
{
|
||||
CurrentViewItems.ImportRow(DataSource.Rows[i]);
|
||||
}
|
||||
}
|
||||
|
||||
isLoadingData = false;
|
||||
}
|
||||
|
||||
private void LoadHtmlTableData(string filePath)
|
||||
{
|
||||
var htmlContent = ReadLocalHtmlFile(filePath);
|
||||
DataSource = ParseHtmlToPairs(htmlContent);
|
||||
LoadInitialData();
|
||||
}
|
||||
//private async Task<string> GetHtmlContent(string url)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// using (HttpClient httpClient = new HttpClient())
|
||||
// {
|
||||
// HttpResponseMessage response = await httpClient.GetAsync(url);
|
||||
// response.EnsureSuccessStatusCode();
|
||||
|
||||
// return await response.Content.ReadAsStringAsync();
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// MessageBox.Show("Error while fetching HTML content: " + ex.ViewMessage);
|
||||
// return null;
|
||||
// }
|
||||
//}
|
||||
private DataTable ParseHtmlToPairs(string html)
|
||||
{
|
||||
DataTable dataTable = new();
|
||||
try
|
||||
{
|
||||
HtmlDocument doc = new();
|
||||
doc.LoadHtml(html);
|
||||
|
||||
var tableNode = doc.DocumentNode.SelectSingleNode("//table");
|
||||
|
||||
if (tableNode != null)
|
||||
{
|
||||
var rows = tableNode.SelectNodes("tr");
|
||||
for (var i = 0; i < rows.Count; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
var row = rows[i].SelectNodes("td");
|
||||
foreach (var cell in row)
|
||||
{
|
||||
dataTable.Columns.Add(cell.InnerText == string.Empty ? WebUtility.HtmlDecode("序号") : WebUtility.HtmlDecode(cell.InnerText.Trim()));
|
||||
|
||||
CurrentViewItems = dataTable.Copy();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dataRow = dataTable.NewRow();
|
||||
var columnIndex = 0;
|
||||
foreach (var cell in rows[i].SelectNodes("td"))
|
||||
{
|
||||
dataRow[columnIndex] = WebUtility.HtmlDecode(cell.InnerText.Trim());
|
||||
columnIndex++;
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("html中未发现表格。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("解析html表格数据时出错:" + ex.Message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
private string ReadLocalHtmlFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
return File.ReadAllText(filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("读取本地html文件时出错:" + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private readonly ActionEventHandler handler = new();
|
||||
|
||||
[RelayCommand]
|
||||
private void Location(object obj)
|
||||
{
|
||||
var rowView = obj as DataRowView;
|
||||
var dr = rowView?.Row;
|
||||
var uidoc = UiApp.ActiveUIDocument;
|
||||
var doc = uidoc.Document;
|
||||
var ids = GetElementIds(dr);
|
||||
uidoc.Selection.SetElementIds(ids);
|
||||
var view = doc.ActiveView;
|
||||
if (!ids.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (view is View3D view3D)
|
||||
{
|
||||
handler.Raise(_ => doc.Invoke(ts =>
|
||||
{
|
||||
if (IsSetSectionBox)
|
||||
{
|
||||
view = view3D.SectionBoxElements(ids, InCurrentView);
|
||||
ts.Commit();
|
||||
if (UiApp.ActiveUIDocument.ActiveView.Id != view.Id)
|
||||
{
|
||||
UiApp.ActiveUIDocument.ActiveView = view;
|
||||
}
|
||||
//var box = elem.get_BoundingBox(UiDocument.ActiveGraphicalView);
|
||||
|
||||
var box = view3D.GetSectionBox();
|
||||
|
||||
var uiView = uidoc.GetOpenUIViews().FirstOrDefault(v => v.ViewId == uidoc.ActiveGraphicalView.Id);
|
||||
uiView.ZoomAndCenterRectangle(box.Min, box.Max);
|
||||
}
|
||||
else
|
||||
{
|
||||
view.ZoomElement(uidoc, ids.FirstOrDefault());
|
||||
}
|
||||
|
||||
}, "定位碰撞元素"));
|
||||
|
||||
|
||||
|
||||
}
|
||||
//RevitCommandId revitCommandId = RevitCommandId.LookupPostableCommandId(PostableCommand.SelectionBox);
|
||||
//try
|
||||
//{
|
||||
// uiapp.PostCommand(revitCommandId);
|
||||
//}
|
||||
//catch (Exception)
|
||||
//{
|
||||
|
||||
// throw;
|
||||
//}
|
||||
//RevitCommandId.LookupCommandId()
|
||||
//List<ElementId> ids = GetElementIds(dr);
|
||||
//ElementId id = null;
|
||||
//if (uiapp.ActiveUIDocument.Document.GetElement(ids[0]).IsValidObject)
|
||||
//{
|
||||
// id = ids[0];
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// ids.Remove(ids[0]);
|
||||
// if (uiapp.ActiveUIDocument.Document.GetElement(ids[1]).IsValidObject)
|
||||
// {
|
||||
// id = ids[1];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ids.Remove(ids[1]);
|
||||
// }
|
||||
//}
|
||||
//if (id != null)
|
||||
//{
|
||||
// uiapp.ActiveUIDocument.ShowElements(id);
|
||||
//}
|
||||
|
||||
//var index = str.IndexOf("ID ");
|
||||
//var elementId1 = str.Substring(index,)
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取当前文档的有效元素ID
|
||||
/// </summary>
|
||||
/// <param name="dr"></param>
|
||||
/// <returns></returns>
|
||||
private List<ElementId> GetElementIds(DataRow dr)
|
||||
{
|
||||
var list = new List<ElementId>();
|
||||
var str = dr[1].ToString();
|
||||
var idStr = str.Split(' ').Last();
|
||||
#if REVIT2018 || REVIT2020
|
||||
var id = new ElementId(int.Parse(idStr));
|
||||
#elif REVIT2025
|
||||
var id = new ElementId(long.Parse(idStr));
|
||||
#endif
|
||||
var str1 = dr[2].ToString();
|
||||
var idStr1 = str1.Split(' ').Last();
|
||||
#if REVIT2018 || REVIT2020
|
||||
var id1 = new ElementId(int.Parse(idStr1));
|
||||
#elif REVIT2025
|
||||
var id1 = new ElementId(long.Parse(idStr1));
|
||||
#endif
|
||||
var e = UiApp.ActiveUIDocument.Document.GetElement(id);
|
||||
var e1 = UiApp.ActiveUIDocument.Document.GetElement(id1);
|
||||
if (e is { IsValidObject: true } && !e.Document.IsLinked)
|
||||
{
|
||||
list.Add(id);
|
||||
}
|
||||
if (e1 is { IsValidObject: true } && !e1.Document.IsLinked)
|
||||
{
|
||||
list.Add(id1);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
[RelayCommand(CanExecute = nameof(CanRefresh))]
|
||||
private void Refresh()
|
||||
{
|
||||
CurrentViewItems.Clear();
|
||||
LoadHtmlTableData(FilePathName);
|
||||
}
|
||||
|
||||
private bool CanRefresh => !string.IsNullOrEmpty(FilePathName);
|
||||
[RelayCommand]
|
||||
private void OpenFile()
|
||||
{
|
||||
var fileOpenDialog = new OpenFileDialog()
|
||||
{
|
||||
Filter = "Html文件 (*.html)|*.html",
|
||||
Multiselect = false,
|
||||
};
|
||||
if (fileOpenDialog.ShowDialog() == true)
|
||||
{
|
||||
FilePathName = fileOpenDialog.FileName;
|
||||
LoadHtmlTableData(FilePathName);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveCmd.cs
Normal file
25
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveCmd.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class ClashResolveCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
WinDialogHelper.ShowModeless<ClashResolveView>(new ClashResolveViewModel());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
128
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveView.xaml
Normal file
128
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveView.xaml
Normal file
@@ -0,0 +1,128 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.ClashResolveView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="避让处理"
|
||||
Width="320"
|
||||
Height="450"
|
||||
MinWidth="320"
|
||||
MinHeight="480"
|
||||
d:DataContext="{d:DesignInstance Type=local:ClashResolveViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="Closing">
|
||||
<b:InvokeCommandAction Command="{Binding ClosingCommand}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:StackPanel Margin="5" Spacing="5">
|
||||
<GroupBox Header="角度">
|
||||
<UniformGrid Columns="3">
|
||||
<!--<ui:CardColor />-->
|
||||
<RadioButton Content="15°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<sys:Double>15</sys:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="22.5°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<sys:Double>22.5</sys:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="30°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<sys:Double>30</sys:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="45°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<sys:Double>45</sys:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="60°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<sys:Double>60</sys:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="90°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<sys:Double>90</sys:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton x:Name="LbCustom" Content="自定义" />
|
||||
<TextBox IsEnabled="{Binding IsChecked, ElementName=LbCustom}" Text="{Binding Angle, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<ui:StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<GroupBox ui:StackPanel.Fill="Fill" Header="参考方式">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton
|
||||
Content="手动"
|
||||
IsChecked="{Binding LocationType, ConverterParameter={x:Static local:LocationType.Manual}, Converter={StaticResource ComparisonConverter}}"
|
||||
ToolTip="手动选取两点" />
|
||||
<RadioButton
|
||||
Content="参考"
|
||||
IsChecked="{Binding LocationType, ConverterParameter={x:Static local:LocationType.Reference}, Converter={StaticResource ComparisonConverter}}"
|
||||
ToolTip="选择相交的两条管线,将翻弯管线偏移一定距离" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox ui:StackPanel.Fill="Fill" Header="调整方式">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton Content="单侧" IsChecked="{Binding AdjustType, ConverterParameter={x:Static local:AdjustType.OneSide}, Converter={StaticResource ComparisonConverter}}" />
|
||||
<RadioButton Content="双侧" IsChecked="{Binding AdjustType, ConverterParameter={x:Static local:AdjustType.TwoSide}, Converter={StaticResource ComparisonConverter}}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</ui:StackPanel>
|
||||
<GroupBox Grid.Row="2" Header="调整方向">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton Content="上" IsChecked="{Binding AdjustDirection, ConverterParameter={x:Static local:AdjustDirection.Up}, Converter={StaticResource ComparisonConverter}}" />
|
||||
<RadioButton Content="下" IsChecked="{Binding AdjustDirection, ConverterParameter={x:Static local:AdjustDirection.Down}, Converter={StaticResource ComparisonConverter}}" />
|
||||
<RadioButton Content="左" IsChecked="{Binding AdjustDirection, ConverterParameter={x:Static local:AdjustDirection.Left}, Converter={StaticResource ComparisonConverter}}" />
|
||||
<RadioButton Content="右" IsChecked="{Binding AdjustDirection, ConverterParameter={x:Static local:AdjustDirection.Right}, Converter={StaticResource ComparisonConverter}}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<ui:TextBoxEx
|
||||
ui:StackPanel.Fill="Fill"
|
||||
Prefix="偏移量:"
|
||||
Suffix="mm"
|
||||
Text="{Binding Offset, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
ui:StackPanel.Fill="Fill"
|
||||
Command="{Binding ResolveCommand}"
|
||||
Content="调整" />
|
||||
</ui:StackPanel>
|
||||
</ui:FluentWindowEx>
|
||||
36
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveView.xaml.cs
Normal file
36
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveView.xaml.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Windows;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
/// <summary>
|
||||
/// ClashResolveView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ClashResolveView
|
||||
{
|
||||
public ClashResolveView()
|
||||
{
|
||||
InitializeComponent();
|
||||
//ApplicationThemeManager.Apply(this);
|
||||
//ApplicationThemeManager.Changed -= ApplicationThemeManager_Changed;
|
||||
//ApplicationThemeManager.Changed += ApplicationThemeManager_Changed;
|
||||
}
|
||||
|
||||
//private void ApplicationThemeManager_Changed(ApplicationTheme currentApplicationTheme, Color systemAccent)
|
||||
//{
|
||||
// ApplicationThemeManager.Apply(this);
|
||||
//}
|
||||
|
||||
//private void Button_Click(object sender, RoutedEventArgs e)
|
||||
//{
|
||||
// if (ApplicationThemeManager.GetAppTheme()==ApplicationTheme.Light)
|
||||
// {
|
||||
// ApplicationThemeManager.Apply(ApplicationTheme.Dark);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ApplicationThemeManager.Apply(ApplicationTheme.Light);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
503
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveViewModel.cs
Normal file
503
ShrlAlgoToolkit.RevitAddins/RvMEP/ClashResolveViewModel.cs
Normal file
@@ -0,0 +1,503 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
using Autodesk.Windows;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
using ShrlAlgoToolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
public partial class ClashResolveViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private AdjustDirection adjustDirection;
|
||||
|
||||
[ObservableProperty]
|
||||
private AdjustType adjustType = AdjustType.OneSide;
|
||||
|
||||
/// <summary>
|
||||
/// 正在执行命令
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(ResolveCommand))]
|
||||
private bool canRunning = true;
|
||||
|
||||
[ObservableProperty]
|
||||
private double angle = 90.0;
|
||||
|
||||
[ObservableProperty]
|
||||
private double offset = 800;
|
||||
|
||||
[ObservableProperty]
|
||||
private LocationType locationType = LocationType.Manual;
|
||||
|
||||
public ActionEventHandler ActionEventHandler { get; } = new();
|
||||
partial void OnLocationTypeChanged(LocationType value)
|
||||
{
|
||||
KeyIntPtrHelper.RaiseEscTwice();
|
||||
}
|
||||
[RelayCommand]
|
||||
private static void Closing()
|
||||
{
|
||||
//关闭窗口退出选择
|
||||
KeyIntPtrHelper.RaiseEscTwice();
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(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 = ConnectorAssist.GetNearestConnectors(
|
||||
baseMepCurve1,
|
||||
angleMepCurve
|
||||
);
|
||||
doc.Create.NewElbowFitting(conn1[0], conn1[1]);
|
||||
|
||||
var conn2 = ConnectorAssist.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 = ConnectorAssist.GetNearestConnectors(
|
||||
baseMepCurve1,
|
||||
firstMepCurve
|
||||
);
|
||||
doc.Create.NewElbowFitting(connectors1[0], connectors1[1]);
|
||||
var connectors4 = ConnectorAssist.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 = ConnectorAssist.GetNearestConnectors(
|
||||
firstMepCurve,
|
||||
secondMepCurve
|
||||
);
|
||||
doc.Create.NewElbowFitting(connectors2[0], connectors2[1]);
|
||||
var connectors3 = ConnectorAssist.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
|
||||
}
|
||||
176
ShrlAlgoToolkit.RevitAddins/RvMEP/CorrectMEPCurveSlopeCmd.cs
Normal file
176
ShrlAlgoToolkit.RevitAddins/RvMEP/CorrectMEPCurveSlopeCmd.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Electrical;
|
||||
using Autodesk.Revit.DB.Mechanical;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
using Nice3point.Revit.Toolkit.Utils;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class CorrectMEPCurveSlopeCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
var mepCurves = UiDocument.SelectObjectsByRectangle<MEPCurve>();
|
||||
if (mepCurves == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Document.Invoke(_ =>
|
||||
{
|
||||
foreach (var mepCurve in mepCurves)
|
||||
{
|
||||
if (!IsErrorMEPCurve(mepCurve))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var loc = mepCurve.Location as LocationCurve;
|
||||
var line = loc.Curve as Line;
|
||||
var endPoint = line.GetEndPoint(0);
|
||||
var endPoint1 = line.GetEndPoint(1);
|
||||
Line unboundLine;
|
||||
Line l;
|
||||
var xoy1 = endPoint.Flatten();
|
||||
var xoy2 = endPoint1.Flatten();
|
||||
var tan = Math.Abs(endPoint.Z - endPoint1.Z) / xoy1.DistanceTo(xoy2);
|
||||
var dir = -XYZ.BasisZ;
|
||||
|
||||
if (endPoint.Z > endPoint1.Z)//以高点作为基准,修改低点
|
||||
{
|
||||
if (tan > 1)
|
||||
{
|
||||
unboundLine = Line.CreateUnbound(endPoint, dir);
|
||||
var startPoint = unboundLine.Project(endPoint1).XYZPoint;
|
||||
l = Line.CreateBound(endPoint, startPoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = xoy2 - xoy1;
|
||||
unboundLine = Line.CreateUnbound(endPoint, dir);
|
||||
var startPoint = unboundLine.Project(endPoint1).XYZPoint;
|
||||
l = Line.CreateBound(endPoint, startPoint);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tan > 1)
|
||||
{
|
||||
unboundLine = Line.CreateUnbound(endPoint1, dir);
|
||||
var startPoint = unboundLine.Project(endPoint).XYZPoint;
|
||||
l = Line.CreateBound(startPoint, endPoint1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = xoy2 - xoy1;
|
||||
unboundLine = Line.CreateUnbound(endPoint1, dir);
|
||||
var startPoint = unboundLine.Project(endPoint).XYZPoint;
|
||||
l = Line.CreateBound(startPoint, endPoint1);
|
||||
}
|
||||
}
|
||||
loc.Curve = l;
|
||||
}
|
||||
}, "修正坡度");
|
||||
}
|
||||
private void CorrectSlope()
|
||||
{
|
||||
var ids = UiDocument.Selection.GetElementIds();
|
||||
Document.Invoke(ts =>
|
||||
{
|
||||
foreach (var id in ids)
|
||||
{
|
||||
var elem = Document.GetElement(id);
|
||||
if (elem is MEPCurve mep)
|
||||
{
|
||||
var loc = mep.GetCurve() as Line;
|
||||
var x = Math.Round(loc.Direction.X);
|
||||
var y = Math.Round(loc.Direction.Y);
|
||||
var z = Math.Round(loc.Direction.Z);
|
||||
//if (Math.Abs(x) < 10E-5)
|
||||
//{
|
||||
// x = 0;
|
||||
//}
|
||||
//if (Math.Abs(y) < 10E-5)
|
||||
//{
|
||||
// y = 0;
|
||||
//}
|
||||
//if (Math.Abs(z) < 10E-5)
|
||||
//{
|
||||
// z = 0;
|
||||
//}
|
||||
var dir = new XYZ(x, y, z);
|
||||
var endPoint = loc.Origin + dir * loc.Length;
|
||||
var li = Line.CreateBound(loc.Origin, endPoint);
|
||||
var locx = mep.GetLocationCurve();
|
||||
locx.Curve = li;
|
||||
}
|
||||
}
|
||||
},"修正坡度");
|
||||
}
|
||||
private void ModifyMEPCurve(MEPCurve mepCurve)
|
||||
{
|
||||
var loc = mepCurve.Location as LocationCurve;
|
||||
var line = loc.Curve as Line;
|
||||
var dir = line.Direction;
|
||||
var newDir = new XYZ(dir.X.Rounding(), dir.Y.Rounding(), dir.Z.Rounding());
|
||||
var conns = mepCurve.ConnectorManager.Connectors.OfType<Connector>().ToList();
|
||||
//全部连接
|
||||
var allConnector = conns.All(conn => conn.IsConnected);
|
||||
//全部未连接
|
||||
var allNotConnector = conns.All(conn => !conn.IsConnected);
|
||||
Line newLine = null;
|
||||
if (allConnector || conns.ElementAt(0).IsConnected || allNotConnector)
|
||||
{
|
||||
var end = line.GetEndPoint(0) + newDir * line.Length;
|
||||
newLine = Line.CreateBound(line.GetEndPoint(0), end);
|
||||
}
|
||||
else
|
||||
{
|
||||
var start = line.GetEndPoint(1) - newDir * line.Length;
|
||||
newLine = Line.CreateBound(start, line.GetEndPoint(1));
|
||||
}
|
||||
Document.Invoke(
|
||||
_ =>
|
||||
{
|
||||
loc.Curve = newLine;
|
||||
}, "修正定位线");
|
||||
}
|
||||
private static bool IsErrorMEPCurve(MEPCurve mepCurve)
|
||||
{
|
||||
var isError = false;
|
||||
switch (mepCurve)
|
||||
{
|
||||
case Pipe:
|
||||
{
|
||||
var param = mepCurve.get_Parameter(BuiltInParameter.RBS_PIPE_SLOPE);
|
||||
isError = param.HasValue && ((param.AsDouble() < 0.025 && param.AsDouble() > 0) || param.AsDouble() > 0.055); //坡度过大或过小时
|
||||
break;
|
||||
}
|
||||
case Duct:
|
||||
{
|
||||
var param = mepCurve.get_Parameter(BuiltInParameter.RBS_DUCT_SLOPE);
|
||||
var loc = mepCurve.GetCurve() as Line;
|
||||
|
||||
isError = param.HasValue && ((param.AsDouble() < 0.025 && param.AsDouble() > 0) || param.AsDouble() > 0.055); //坡度过大或过小时
|
||||
break;
|
||||
}
|
||||
case Conduit or CableTray:
|
||||
{
|
||||
var p1 = mepCurve.get_Parameter(BuiltInParameter.RBS_START_OFFSET_PARAM).AsDouble();
|
||||
var p2 = mepCurve.get_Parameter(BuiltInParameter.RBS_END_OFFSET_PARAM).AsDouble();
|
||||
var l = mepCurve.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble();
|
||||
var sin = Math.Abs(p1 - p2) / l;
|
||||
var radian = Math.Asin(sin);
|
||||
var slope = Math.Tan(radian);
|
||||
isError = slope is (> 0 and < 0.025) or > 0.055;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
}
|
||||
45
ShrlAlgoToolkit.RevitAddins/RvMEP/DisconnectCmd.cs
Normal file
45
ShrlAlgoToolkit.RevitAddins/RvMEP/DisconnectCmd.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class DisconnectCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
var filter = new FuncFilter(e => e is MEPCurve || (e is FamilyInstance instance && instance.MEPModel.ConnectorManager != null));
|
||||
|
||||
var reference1 = UiDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, filter, "请选择需要断开连接的第一个设备或管线");
|
||||
var reference2 = UiDocument.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, filter, "请选择需要断开连接的第二个设备或管线");
|
||||
var element1 = Document.GetElement(reference1);
|
||||
var element2 = Document.GetElement(reference2);
|
||||
Document.Invoke(
|
||||
_ =>
|
||||
{
|
||||
if (element1.Id == element2.Id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (Connector conn in element1.GetConnectors(false))
|
||||
{
|
||||
var connectedConn = conn.GetConnectedConnector();
|
||||
if (connectedConn != null && connectedConn.Owner.Id == element2.Id)
|
||||
{
|
||||
conn.DisconnectFrom(connectedConn);
|
||||
}
|
||||
}
|
||||
},
|
||||
"取消连接"
|
||||
);
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException) { }
|
||||
}
|
||||
}
|
||||
47
ShrlAlgoToolkit.RevitAddins/RvMEP/FlipWorkplaneCmd.cs
Normal file
47
ShrlAlgoToolkit.RevitAddins/RvMEP/FlipWorkplaneCmd.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class FlipWorkplaneCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
ICollection<FamilyInstance> familyInstances;
|
||||
if (UiDocument.Selection.GetElementIds().Count > 0)
|
||||
{
|
||||
familyInstances = UiDocument.Selection.GetElementIds().Select(Document.GetElement).OfType<FamilyInstance>().ToList();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
familyInstances = UiDocument.SelectObjects<FamilyInstance>("请选择族实例");
|
||||
}
|
||||
Document.Invoke(
|
||||
ts =>
|
||||
{
|
||||
foreach (var ins in familyInstances)
|
||||
{
|
||||
if (ins.CanFlipWorkPlane)
|
||||
{
|
||||
ins.IsWorkPlaneFlipped = !ins.IsWorkPlaneFlipped;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
121
ShrlAlgoToolkit.RevitAddins/RvMEP/ForceConnectCmd.cs
Normal file
121
ShrlAlgoToolkit.RevitAddins/RvMEP/ForceConnectCmd.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class ForceConnectCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
using Transaction trans = new(Document, "强制连接系统");
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var pipeList = UiDocument.Selection.PickElementsByRectangle(new GenericFilter<Pipe>()).Cast<Pipe>().ToList();
|
||||
try
|
||||
{
|
||||
trans.Start();
|
||||
if (pipeList.Count == 2)
|
||||
{
|
||||
var pipe1 = pipeList[0];
|
||||
var pipe2 = pipeList[1];
|
||||
var l1 = (pipe1.Location as LocationCurve)?.Curve as Line;
|
||||
var l2 = (pipe2.Location as LocationCurve)?.Curve as Line;
|
||||
var l3 = l2.Clone();
|
||||
var p1 = l1.Origin;
|
||||
var projectPoint = l2.Project(p1).XYZPoint;
|
||||
|
||||
var collection1 = pipe1.ConnectorManager.UnusedConnectors;
|
||||
var collection2 = pipe2.ConnectorManager.UnusedConnectors;
|
||||
var di = double.MaxValue;
|
||||
var conns = new List<Connector>();
|
||||
|
||||
foreach (Connector connector in collection1)
|
||||
{
|
||||
foreach (Connector connector1 in collection2)
|
||||
{
|
||||
var temp = connector.Origin.DistanceTo(connector1.Origin);
|
||||
if (temp < di)
|
||||
{
|
||||
conns.Clear();
|
||||
di = temp;
|
||||
conns.Add(connector);
|
||||
conns.Add(connector1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Document.Create.NewElbowFitting(conns[0], conns[1]);
|
||||
//conns[0].ConnectTo(conns[1]);
|
||||
//var comparisonResult= l1.Intersect(l3, out var result);
|
||||
// if (comparisonResult == SetComparisonResult.Overlap)
|
||||
// {
|
||||
// var p = result.get_Item(0).XYZPoint;
|
||||
// }
|
||||
}
|
||||
|
||||
if (pipeList.Count == 3)
|
||||
{
|
||||
var pipe1 = pipeList[0];
|
||||
var pipe2 = pipeList[1];
|
||||
var pipe3 = pipeList[2];
|
||||
var l1 = (pipe1.Location as LocationCurve).Curve as Line;
|
||||
var l2 = (pipe2.Location as LocationCurve).Curve as Line;
|
||||
var l3 = (pipe3.Location as LocationCurve).Curve as Line;
|
||||
if (l1.Direction.IsAlmostEqualTo(l2.Direction))
|
||||
{
|
||||
var collection1 = pipe1.ConnectorManager.UnusedConnectors;
|
||||
var collection2 = pipe2.ConnectorManager.UnusedConnectors;
|
||||
|
||||
foreach (Connector connector in collection1)
|
||||
{
|
||||
foreach (Connector connector1 in collection2)
|
||||
{
|
||||
//var temp = connector.Origin.DistanceTo(connector1.Origin);
|
||||
//if (temp < di)
|
||||
//{
|
||||
// conns.Clear();
|
||||
// di = temp;
|
||||
// conns.Add(connector);
|
||||
// conns.Add(connector1);
|
||||
//}
|
||||
}
|
||||
}
|
||||
//doc.Create.NewTeeFitting();
|
||||
}
|
||||
}
|
||||
trans.Commit();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
trans.Commit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
if (trans.GetStatus() == TransactionStatus.Started)
|
||||
{
|
||||
trans.Commit();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message;
|
||||
if (trans.GetStatus() == TransactionStatus.Started)
|
||||
{
|
||||
trans.Commit();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckCmd.cs
Normal file
154
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckCmd.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Electrical;
|
||||
using Autodesk.Revit.DB.Mechanical;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
using ShrlAlgo.RvKits.Windows;
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
/// <summary>
|
||||
/// Revit执行命令
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class HeadroomCheckCmd : ExternalCommand
|
||||
{
|
||||
private void CheckHeadroom(IEnumerable<MEPCurve> elems, double compareMetric, double minValueMetric, double minLengthMetric)
|
||||
{
|
||||
var messages = new List<MessageModel>();
|
||||
var headroomValue = compareMetric / 304.8;
|
||||
var ignoreBelowValue = minValueMetric / 304.8;
|
||||
var minHeadroom = double.MaxValue;
|
||||
var minLength = minLengthMetric / 304.8;
|
||||
Element element = null;
|
||||
foreach (var item in elems)
|
||||
{
|
||||
if (item.GetCurve().Length < minLength)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var conns = item.ConnectorManager.Connectors.OfType<Connector>().ToList();
|
||||
var level = item.ReferenceLevel;
|
||||
#if REVIT2018 || REVIT2020
|
||||
if (conns.Any(conn => conn.GetConnectedConnector()?.Owner.Category.Id.IntegerValue == -2001140))
|
||||
#elif REVIT2025
|
||||
if (conns.Any(conn => conn.GetConnectedConnector()?.Owner.Category.Id.Value == -2001140))
|
||||
#endif
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var s = item.get_Parameter(BuiltInParameter.RBS_DUCT_SLOPE);
|
||||
if (item is Duct duct && s.HasValue && Math.Atan(s.AsDouble()) < Math.PI / 3)
|
||||
{
|
||||
var p1 = item.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM).AsDouble();
|
||||
var subtract = conns.FirstOrDefault()!.Shape switch
|
||||
{
|
||||
ConnectorProfileType.Round => duct.Diameter / 2,
|
||||
ConnectorProfileType.Rectangular => duct.Height / 2,
|
||||
ConnectorProfileType.Oval => duct.Height / 2,
|
||||
_ => default
|
||||
};
|
||||
|
||||
if (p1 - subtract < headroomValue && p1 - subtract > ignoreBelowValue)
|
||||
{
|
||||
var lowOffset = p1 - subtract;
|
||||
if (lowOffset < minHeadroom)
|
||||
{
|
||||
minHeadroom = lowOffset;
|
||||
element = item;
|
||||
}
|
||||
|
||||
MessageModel checkElement = new(item, $"底高程: {Math.Round(lowOffset * 304.8, 1)} mm\n\r参照标高:{level.Name}");
|
||||
messages.Add(checkElement);
|
||||
}
|
||||
}
|
||||
|
||||
var p = item.get_Parameter(BuiltInParameter.RBS_PIPE_SLOPE);
|
||||
if (item is Pipe pipe && p.HasValue && Math.Atan(p.AsDouble()) < Math.PI / 3)
|
||||
{
|
||||
var p1 = item.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM).AsDouble();
|
||||
if (p1 - (pipe.Diameter / 2) < headroomValue && p1 - (pipe.Diameter / 2) > ignoreBelowValue)
|
||||
{
|
||||
var lowOffset = p1 - (pipe.Diameter / 2);
|
||||
if (lowOffset < minHeadroom)
|
||||
{
|
||||
minHeadroom = lowOffset;
|
||||
element = item;
|
||||
}
|
||||
|
||||
MessageModel checkElement = new(item, $"底高程:{Math.Round(lowOffset * 304.8, 1)}mm\n\r参照标高:{level.Name}");
|
||||
messages.Add(checkElement);
|
||||
}
|
||||
}
|
||||
|
||||
if (item is Conduit or CableTray)
|
||||
{
|
||||
var p1 = item.get_Parameter(BuiltInParameter.RBS_START_OFFSET_PARAM).AsDouble();
|
||||
var p2 = item.get_Parameter(BuiltInParameter.RBS_END_OFFSET_PARAM).AsDouble();
|
||||
if (Math.Abs(p1 - p2) < 0.00001)
|
||||
{
|
||||
var p3 = item.get_Parameter(BuiltInParameter.RBS_CTC_BOTTOM_ELEVATION).AsDouble();
|
||||
if (p3 < minHeadroom)
|
||||
{
|
||||
minHeadroom = p3;
|
||||
element = item;
|
||||
}
|
||||
|
||||
if (p3 < headroomValue && p3 > ignoreBelowValue)
|
||||
{
|
||||
MessageModel checkElement = new(item, $"底高程:{Math.Round(p3 * 304.8)}mm\n\r参照标高:{level.Name}");
|
||||
messages.Add(checkElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageViewModel viewmodel = new(UiDocument, messages, "净高检查结果");
|
||||
if (element != null)
|
||||
{
|
||||
viewmodel.Footer = $"最低净高={Math.Round(minHeadroom * 304.8)}mm,元素:{element.Name},Id:{element.Id}";
|
||||
UiDocument.Selection.SetElementIds(new List<ElementId> { element.Id });
|
||||
}
|
||||
WinDialogHelper.ShowModeless<MessageWin>(viewmodel);
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<HeadroomCheckView>(new HeadroomCheckViewModel(UiApplication));
|
||||
//try
|
||||
//{
|
||||
// InputMessageBox inputMessage = new("净高限制", "请输出净高要求高度(mm)");
|
||||
// inputMessage.ShowDialog();
|
||||
// if (inputMessage.DialogResult == true)
|
||||
// {
|
||||
// var elems = UiDocument.Selection
|
||||
// .PickElementsByRectangle(new FuncFilter(e => e is ElementToMove, (_, _) => true))
|
||||
// .OfType<ElementToMove>();
|
||||
// if (double.TryParse(inputMessage.InputContent, out var headroomValue))
|
||||
// {
|
||||
// CheckHeadroom(elems, headroomValue, 1000, 300);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var elem = UiDocument.SelectObject<DirectShape>();
|
||||
// var clashFilter = new ElementIntersectsElementFilter(elem, false);
|
||||
// var elems = Document.OfCollector().WherePasses(clashFilter).OfType<ElementToMove>();
|
||||
// if (double.TryParse(inputMessage.InputContent, out var headroomValue))
|
||||
// {
|
||||
// CheckHeadroom(elems, headroomValue, 1000, 300);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
//{
|
||||
//}
|
||||
}
|
||||
}
|
||||
149
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckView.xaml
Normal file
149
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckView.xaml
Normal file
@@ -0,0 +1,149 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.HeadroomCheckView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="净空检查"
|
||||
Width="400"
|
||||
Height="800"
|
||||
d:DataContext="{d:DesignInstance local:HeadroomCheckViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<DataGrid
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Height="200"
|
||||
Margin="5"
|
||||
d:ItemsSource="{d:SampleData ItemCount=5}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
ItemsSource="{Binding Rooms}"
|
||||
SelectionMode="Extended">
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn
|
||||
Width="60"
|
||||
Binding="{Binding IsSelected}"
|
||||
ElementStyle="{StaticResource DataGridCheckBoxElementDefaultStyle}"
|
||||
Header="选择" />
|
||||
<DataGridTextColumn
|
||||
Binding="{Binding Name}"
|
||||
Header="房间名称"
|
||||
IsReadOnly="True" />
|
||||
<DataGridTemplateColumn Header="颜色" IsReadOnly="True">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{Binding Color, Converter={StaticResource Revit2MediaColorConverter}}" ToolTip="生成三维房间时的颜色" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" />
|
||||
<DataGrid
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Height="340"
|
||||
Margin="5"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding ErrorModels}"
|
||||
ToolTip="双击行可快速定位">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="MouseDoubleClick">
|
||||
<b:InvokeCommandAction Command="{Binding ShowElementCommand}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}, Mode=FindAncestor}}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Binding="{Binding Element.Category.Name}" Header="类别名称" />
|
||||
<DataGridTextColumn Binding="{Binding Element.Name}" Header="元素名称" />
|
||||
<DataGridTextColumn Binding="{Binding Level.Name}" Header="主体" />
|
||||
<DataGridTextColumn Binding="{Binding Element.Id}" Header="元素Id" />
|
||||
<DataGridTextColumn Binding="{Binding ErrorMessage}" Header="错误信息" />
|
||||
<DataGridTemplateColumn Header="操作">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<!-- 按钮参数绑定到当前行的绑定的Item -->
|
||||
<Button
|
||||
Command="{Binding DataContext.ShowElementCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}, Mode=FindAncestor}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="定位构件" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<!-- 树状结构,按楼层=>专业=>管线 -->
|
||||
<GridSplitter Grid.Row="3" HorizontalAlignment="Stretch" />
|
||||
<ui:StackPanel
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="5"
|
||||
Spacing="5">
|
||||
<!--<TextBlock
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="排除高度低的管线(mm):" />-->
|
||||
<ui:TextBoxEx
|
||||
MinWidth="120"
|
||||
Header="排除高度低的管线:"
|
||||
HeaderPlacement="Left"
|
||||
Suffix="mm"
|
||||
Text="1000" />
|
||||
<!--<TextBlock
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="排除长度短的管线(mm):" />-->
|
||||
<ui:TextBoxEx
|
||||
MinWidth="120"
|
||||
Header="排除长度短的管线:"
|
||||
HeaderPlacement="Left"
|
||||
Suffix="mm"
|
||||
Text="500" />
|
||||
<!--<TextBlock
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Text="净高要求高度(mm):" />-->
|
||||
<ui:TextBoxEx
|
||||
MinWidth="120"
|
||||
Header="净高要求高度:"
|
||||
HeaderPlacement="Left"
|
||||
Suffix="mm"
|
||||
Text="2600" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding AnalysisHeadroomCommand}"
|
||||
Content="净高分析"
|
||||
ToolTip="得到净高分析的平面以及不满足净高要求的管线" />
|
||||
<!--<Button
|
||||
Command="{Binding FindOverCommand}"
|
||||
Content="查询管线"
|
||||
ToolTip="根据净高要求查询" />-->
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding ResetRoomHeightCommand}"
|
||||
Content="重设高度"
|
||||
ToolTip="重新设置房间高度为4000mm,避免影响平面查看" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding GenerateRoom3DCommand}"
|
||||
Content="房间实体"
|
||||
ToolTip="生成三维房间实体" />
|
||||
</ui:StackPanel>
|
||||
</Grid>
|
||||
</ui:FluentWindowEx>
|
||||
17
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckView.xaml.cs
Normal file
17
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckView.xaml.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
/// <summary>
|
||||
/// HeadroomCheckView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class HeadroomCheckView
|
||||
{
|
||||
public HeadroomCheckView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
178
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckViewModel.cs
Normal file
178
ShrlAlgoToolkit.RevitAddins/RvMEP/HeadroomCheckViewModel.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Architecture;
|
||||
using Autodesk.Revit.UI;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
using RandomColorGenerator;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
public partial class HeadroomCheckViewModel : ObservableObject
|
||||
{
|
||||
private readonly UIApplication uiapp;
|
||||
|
||||
public HeadroomCheckViewModel(UIApplication uiapp)
|
||||
{
|
||||
this.uiapp = uiapp;
|
||||
document = uiapp.ActiveUIDocument.Document;
|
||||
Rooms = GetRoomItems();
|
||||
checkHeadroom = new ActionEventHandler();
|
||||
generateRoom3d = new ActionEventHandler();
|
||||
}
|
||||
private readonly ActionEventHandler checkHeadroom;
|
||||
private readonly ActionEventHandler generateRoom3d;
|
||||
private readonly Document document;
|
||||
|
||||
[ObservableProperty]
|
||||
private List<RoomCheckItem> rooms;
|
||||
private List<RoomCheckItem> GetRoomItems()
|
||||
{
|
||||
var roomItems = new List<RoomCheckItem>();
|
||||
var allRooms = uiapp.ActiveUIDocument.Document.OfClass<SpatialElement>().OfType<Room>();
|
||||
var groups = allRooms.GroupBy(r => r.Name);
|
||||
IEnumerable<IGrouping<string, Room>> enumerable = groups as IGrouping<string, Room>[] ?? groups.ToArray();
|
||||
var colors = GetRandomColors(enumerable.Count());
|
||||
for (int i = 0; i < enumerable.Count(); i++)
|
||||
{
|
||||
var group = enumerable.ElementAt(i);
|
||||
var color = colors.ElementAt(i);
|
||||
foreach (var room in group)
|
||||
{
|
||||
var r = new RoomCheckItem()
|
||||
{
|
||||
Room = room,
|
||||
Name = room.Name,
|
||||
Color = color,
|
||||
};
|
||||
roomItems.Add(r);
|
||||
}
|
||||
}
|
||||
return roomItems;
|
||||
}
|
||||
private static IEnumerable<Color> GetRandomColors(int count)
|
||||
{
|
||||
var colors = RandomColor.GetColors(ColorScheme.Random, Luminosity.Light, count);
|
||||
|
||||
return colors.Select(color => new Color(color.R, color.G, color.B));
|
||||
}
|
||||
private bool CanClick()
|
||||
{
|
||||
return Rooms.Any();
|
||||
}
|
||||
[RelayCommand(CanExecute = nameof(CanClick))]
|
||||
private void AnalysisHeadroom()
|
||||
{
|
||||
checkHeadroom.Raise(_ =>
|
||||
{
|
||||
var view = document.ActiveView;
|
||||
//var elev = view.GenLevel.Bottom;
|
||||
document.Invoke(_ =>
|
||||
{
|
||||
ElementClassFilter filter = new(typeof(Floor));
|
||||
foreach (var item in Rooms)
|
||||
{
|
||||
var room = item.Room;
|
||||
Level baseLevel = room.Level;
|
||||
var levels = document.OfClass<Level>().Cast<Level>();
|
||||
Level aboveLevel = null;
|
||||
double tempElev = double.MaxValue;
|
||||
foreach (var level in levels)
|
||||
{
|
||||
if (level.Elevation > baseLevel.Elevation && (level.Elevation - baseLevel.Elevation) < tempElev)
|
||||
{
|
||||
aboveLevel = level;
|
||||
tempElev = level.Elevation;
|
||||
}
|
||||
}
|
||||
|
||||
Element hitBottomElement = null;
|
||||
Element hitTopElement = null;
|
||||
document.XRayFindNearest(filter, FindReferenceTarget.Element, room.GetLocXYZ(), -XYZ.BasisZ, ref hitBottomElement);
|
||||
document.XRayFindNearest(filter, FindReferenceTarget.Element, room.GetLocXYZ(), XYZ.BasisZ, ref hitTopElement);
|
||||
if (hitBottomElement is Floor bottomFloor && bottomFloor.LevelId == baseLevel.Id)//击中的楼板是上层的楼板
|
||||
{
|
||||
//绝对标高
|
||||
var baseOffset = bottomFloor.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_BOTTOM).AsDouble();
|
||||
//底部偏移
|
||||
room.BaseOffset = baseOffset - baseLevel.Elevation;
|
||||
}
|
||||
else//找不到楼板则为0
|
||||
{
|
||||
room.BaseOffset = 0;
|
||||
}
|
||||
|
||||
if (hitTopElement is Floor topFloor && topFloor.LevelId == aboveLevel?.Id)//击中的楼板是当前的楼板
|
||||
{
|
||||
//绝对标高
|
||||
var limitOffset = topFloor.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble();
|
||||
//高度偏移
|
||||
room.LimitOffset = limitOffset - room.UpperLimit.Elevation;
|
||||
//全部高度
|
||||
//view.GetViewRange().GetLevelId(PlanViewPlane.TopClipPlane)
|
||||
//item.Room
|
||||
}
|
||||
else//找不到楼板则为上部标高
|
||||
{
|
||||
room.LimitOffset = aboveLevel.Elevation - room.UpperLimit.Elevation;
|
||||
}
|
||||
document.Regenerate();
|
||||
var elements = room.GetIntersectElements().Where(e => e is MEPCurve || e.Category.Id == new ElementId(BuiltInCategory.OST_StructuralFraming));
|
||||
foreach (var elem in elements)
|
||||
{
|
||||
var boundingBox = elem.get_BoundingBox(view);
|
||||
//最低绝对标高
|
||||
var roomTopOffset = boundingBox.Min.Z;
|
||||
room.LimitOffset = roomTopOffset - room.UpperLimit.Elevation;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
[RelayCommand(CanExecute = nameof(CanClick))]
|
||||
private void GenerateRoom3D()
|
||||
{
|
||||
document.Invoke(_ =>
|
||||
{
|
||||
var list = new List<GeometryObject>();
|
||||
DirectShape ds = DirectShape.CreateElement(document, new ElementId(BuiltInCategory.OST_GenericModel));
|
||||
FillPatternElement solidFillPattern = document
|
||||
.OfClass<FillPatternElement>()
|
||||
.Cast<FillPatternElement>()
|
||||
.FirstOrDefault(a => a.GetFillPattern().IsSolidFill);
|
||||
foreach (var item in Rooms)
|
||||
{
|
||||
list.Add(item.Room.GetSolid());
|
||||
Color color = item.Color;
|
||||
//TextNote.Create(document, viewId, position, text, options)
|
||||
OverrideGraphicSettings ogs = new();
|
||||
ogs.SetProjectionLineColor(color);
|
||||
#if REVIT2018
|
||||
ogs.SetSurfaceTransparency(50);
|
||||
ogs.SetProjectionFillColor(color);
|
||||
ogs.SetProjectionFillPatternId(solidFillPattern.Id);
|
||||
|
||||
ogs.SetCutFillColor(color);
|
||||
ogs.SetCutFillPatternId(solidFillPattern.Id);
|
||||
document.ActiveView.SetElementOverrides(ds.Id, ogs);
|
||||
#else
|
||||
ogs.SetSurfaceBackgroundPatternColor(color);
|
||||
ogs.SetSurfaceForegroundPatternId(solidFillPattern.Id);
|
||||
ogs.SetSurfaceForegroundPatternColor(color);
|
||||
|
||||
ogs.SetCutBackgroundPatternColor(color);
|
||||
ogs.SetCutForegroundPatternColor(color);
|
||||
ogs.SetCutForegroundPatternId(solidFillPattern.Id);
|
||||
ogs.SetSurfaceTransparency(50);
|
||||
document.ActiveView.SetElementOverrides(ds.Id, ogs);
|
||||
#endif
|
||||
}
|
||||
ds.AppendShape(list);
|
||||
}, "创建三维房间实体");
|
||||
}
|
||||
}
|
||||
57
ShrlAlgoToolkit.RevitAddins/RvMEP/InsulationItem.cs
Normal file
57
ShrlAlgoToolkit.RevitAddins/RvMEP/InsulationItem.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
using Autodesk.Revit.DB.Mechanical;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using System.Linq;
|
||||
using ShrlAlgoToolkit.Mvvm.Attributes;
|
||||
|
||||
namespace ShrlAlgo.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)]
|
||||
[NotifyDataErrorInfo]
|
||||
[ObservableProperty]
|
||||
private double thickness;
|
||||
//{
|
||||
// get => thickness;
|
||||
// set => SetProperty(ref thickness, value, true);
|
||||
//}
|
||||
//private double thickness;
|
||||
|
||||
[ObservableProperty]
|
||||
private PipeInsulationType pipeInsulationType;
|
||||
[ObservableProperty]
|
||||
private DuctInsulationType ductInsulationType;
|
||||
}
|
||||
180
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveConnectCmd.cs
Normal file
180
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveConnectCmd.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class MoveConnectCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
Reference baseReference;
|
||||
Reference moveReference;
|
||||
try
|
||||
{
|
||||
baseReference = UiDocument.Selection.PickObject(
|
||||
Autodesk.Revit.UI.Selection.ObjectType.Element,
|
||||
new FuncFilter(e => e.GetConnectors(true)?.Size > 0),
|
||||
"请选择基准的管线、管件、设备实例"
|
||||
);
|
||||
|
||||
moveReference = UiDocument.Selection.PickObject(
|
||||
Autodesk.Revit.UI.Selection.ObjectType.Element,
|
||||
new FuncFilter(
|
||||
e =>
|
||||
e.Id != baseReference.ElementId
|
||||
&& e.GetConnectors(true)?.Size > 0
|
||||
),
|
||||
"请选择需要移动连接的管线、管件、设备实例"
|
||||
);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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.GetCurve() 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;
|
||||
|
||||
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);
|
||||
|
||||
conn1.ConnectByFitting(conn2);
|
||||
}
|
||||
}
|
||||
},
|
||||
"移动连接"
|
||||
);
|
||||
}
|
||||
}
|
||||
20
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCmd.cs
Normal file
20
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCmd.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
/// <summary>
|
||||
/// Revit执行命令
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class MoveMEPCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<MoveMEPCurveView>(new MoveMEPCurveViewModel());
|
||||
}
|
||||
}
|
||||
59
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCurveView.xaml
Normal file
59
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCurveView.xaml
Normal file
@@ -0,0 +1,59 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.MoveMEPCurveView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="移动管线"
|
||||
Width="250"
|
||||
Height="310"
|
||||
MinWidth="250"
|
||||
MinHeight="310"
|
||||
d:DataContext="{d:DesignInstance Type=local:MoveMEPCurveViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="Closing">
|
||||
<b:InvokeCommandAction Command="{Binding ClosingCommand}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:StackPanel Margin="5" Spacing="5">
|
||||
<GroupBox Header="移动管线方式">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton
|
||||
Content="单独"
|
||||
IsChecked="{Binding IsSingle}"
|
||||
ToolTip="仅移动当前选择管线(与Revit默认修改逻辑一致)" />
|
||||
<RadioButton Content="整体" ToolTip="把与选择管线的所有连接管线整体移动" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Header="移动方式">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton Content="距离" IsChecked="{Binding ByDistance}" />
|
||||
<RadioButton Content="参考" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<ui:TextBoxEx
|
||||
Prefix="距离/间距:"
|
||||
Suffix="mm"
|
||||
Text="{Binding Distance}"
|
||||
ToolTip="上下移动的距离(需要区分正负)或与参考的间距" />
|
||||
<ui:StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
ui:StackPanel.Fill="Fill"
|
||||
Command="{Binding SelectCommand}"
|
||||
Content="选择" />
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
ui:StackPanel.Fill="Fill"
|
||||
Command="{Binding MoveCommand}"
|
||||
Content="移动" />
|
||||
</ui:StackPanel>
|
||||
</ui:StackPanel>
|
||||
</ui:FluentWindowEx>
|
||||
26
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCurveView.xaml.cs
Normal file
26
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCurveView.xaml.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
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 ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
/// <summary>
|
||||
/// MoveMEPCurveView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MoveMEPCurveView
|
||||
{
|
||||
public MoveMEPCurveView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
166
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCurveViewModel.cs
Normal file
166
ShrlAlgoToolkit.RevitAddins/RvMEP/MoveMEPCurveViewModel.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
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.Mvvm.Attributes;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
public partial class MoveMEPCurveViewModel : ObservableValidator
|
||||
{
|
||||
[ObservableProperty]
|
||||
private bool isSingle = true;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool byDistance = true;
|
||||
private readonly ActionEventHandler moveHandler = new();
|
||||
|
||||
[IsNumeric]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private double distance;
|
||||
|
||||
//public double Distance
|
||||
//{
|
||||
// get => distance;
|
||||
// set => SetProperty(ref distance, value, true);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 正在执行命令
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(MoveCommand))]
|
||||
private bool canRunning = true;
|
||||
|
||||
[RelayCommand]
|
||||
private void Closing()
|
||||
{
|
||||
#region 关闭窗口退出选择
|
||||
|
||||
if (!CanRunning)
|
||||
{
|
||||
KeyIntPtrHelper.RaiseEscTwice();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
[RelayCommand]
|
||||
private void Select()
|
||||
{
|
||||
moveHandler.Raise(uiapp =>
|
||||
{
|
||||
var uiDocument = uiapp.ActiveUIDocument;
|
||||
var doc = uiDocument.Document;
|
||||
try
|
||||
{
|
||||
var reference = uiDocument.Selection.PickObject(ObjectType.Element, new GenericFilter<MEPCurve>(), "请选择移动管线");
|
||||
var mepCurve = doc.GetElement(reference) as MEPCurve;
|
||||
var ids = new List<ElementId>();
|
||||
mepCurve.GetAllConnectedElements(ids);
|
||||
uiDocument.Selection.SetElementIds(ids);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CanRunning = true;
|
||||
});
|
||||
}
|
||||
[RelayCommand]
|
||||
private void Move()
|
||||
{
|
||||
CanRunning = false;
|
||||
moveHandler.Raise(uiapp =>
|
||||
{
|
||||
var uiDocument = uiapp.ActiveUIDocument;
|
||||
var doc = uiDocument.Document;
|
||||
|
||||
doc.Invoke(
|
||||
_ =>
|
||||
{
|
||||
double z;
|
||||
MEPCurve mepCurve;
|
||||
|
||||
try
|
||||
{
|
||||
var reference = uiDocument.Selection.PickObject(ObjectType.Element, new GenericFilter<MEPCurve>(), "请选择移动管线");
|
||||
mepCurve = doc.GetElement(reference) as MEPCurve;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CanRunning = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ByDistance)
|
||||
{
|
||||
z = Distance / 304.8;
|
||||
}
|
||||
else
|
||||
{
|
||||
Reference reference = null;
|
||||
ElementInLinkOrCurrentDocument linkOrCurrentDocument = new(doc);
|
||||
|
||||
try
|
||||
{
|
||||
reference = uiDocument.Selection.PickObject(ObjectType.PointOnElement, linkOrCurrentDocument, "请选择基准元素");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (reference == null)
|
||||
{
|
||||
CanRunning = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var referenceElem = linkOrCurrentDocument.LastCheckedWasFromLink
|
||||
? linkOrCurrentDocument.LinkedDocument.GetElement(reference.LinkedElementId)
|
||||
: doc.GetElement(reference);
|
||||
|
||||
var referMaxZ = referenceElem.get_BoundingBox(doc.ActiveView).Max.Z;
|
||||
var referMinZ = referenceElem.get_BoundingBox(doc.ActiveView).Min.Z;
|
||||
var maxZ = mepCurve.get_BoundingBox(doc.ActiveView).Max.Z;
|
||||
var minZ = mepCurve.get_BoundingBox(doc.ActiveView).Min.Z;
|
||||
//参考底部大于原管线顶部
|
||||
if (referMinZ > maxZ)
|
||||
{
|
||||
z = (referMinZ - Math.Abs(Distance) / 304.8) - maxZ;
|
||||
}
|
||||
//参考顶部大于原管线底部
|
||||
else if (referMaxZ < minZ)
|
||||
{
|
||||
z = (referMaxZ + Math.Abs(Distance) / 304.8) - minZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
CanRunning = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSingle)
|
||||
{
|
||||
ElementTransformUtils.MoveElement(doc, mepCurve.Id, XYZ.BasisZ * z);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ids = new List<ElementId>();
|
||||
mepCurve.GetAllConnectedElements(ids);
|
||||
ElementTransformUtils.MoveElements(doc, ids, XYZ.BasisZ * z);
|
||||
}
|
||||
},
|
||||
"移动管线"
|
||||
);
|
||||
CanRunning = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Events;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
public class RevitCommandEndedMonitor
|
||||
{
|
||||
private readonly UIApplication _revitUiApplication;
|
||||
|
||||
private bool _initializingCommandMonitor;
|
||||
|
||||
public event EventHandler CommandEnded;
|
||||
|
||||
public RevitCommandEndedMonitor(UIApplication revituiApplication)
|
||||
{
|
||||
_revitUiApplication = revituiApplication;
|
||||
|
||||
_initializingCommandMonitor = true;
|
||||
|
||||
_revitUiApplication.Idling += OnRevitUiApplicationIdling;
|
||||
}
|
||||
|
||||
private void OnRevitUiApplicationIdling(object sender, IdlingEventArgs idlingEventArgs)
|
||||
{
|
||||
if (_initializingCommandMonitor)
|
||||
{
|
||||
_initializingCommandMonitor = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_revitUiApplication.Idling -= OnRevitUiApplicationIdling;
|
||||
|
||||
OnCommandEnded();
|
||||
}
|
||||
|
||||
protected virtual void OnCommandEnded()
|
||||
{
|
||||
CommandEnded?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
23
ShrlAlgoToolkit.RevitAddins/RvMEP/RoomCheckItem.cs
Normal file
23
ShrlAlgoToolkit.RevitAddins/RvMEP/RoomCheckItem.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Autodesk.Revit.DB.Architecture;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
public partial class RoomCheckItem : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private bool isSelected;
|
||||
[ObservableProperty]
|
||||
private string name;
|
||||
[ObservableProperty]
|
||||
private Room room;
|
||||
[ObservableProperty]
|
||||
private Color color;
|
||||
}
|
||||
}
|
||||
24
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateInstanceCmd.cs
Normal file
24
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateInstanceCmd.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
class RotateInstanceCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<RotateMEPView>(new RotateMEPViewModel());
|
||||
}
|
||||
}
|
||||
}
|
||||
101
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateMEPView.xaml
Normal file
101
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateMEPView.xaml
Normal file
@@ -0,0 +1,101 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.RotateMEPView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:System="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
|
||||
xmlns:local="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
Title="旋转模型"
|
||||
Width="250"
|
||||
Height="280"
|
||||
MinWidth="250"
|
||||
MinHeight="280"
|
||||
d:DataContext="{d:DesignInstance Type={x:Type local:RotateMEPViewModel}}"
|
||||
SizeToContent="Height"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:StackPanel Margin="5" Spacing="5">
|
||||
<GroupBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Header="角度(°)">
|
||||
<UniformGrid Columns="3" Rows="3">
|
||||
<RadioButton Content="15°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<System:Double>15</System:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="22.5°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<System:Double>22.5</System:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="30°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<System:Double>30</System:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="45°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<System:Double>45</System:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="60°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<System:Double>60</System:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton Content="90°">
|
||||
<RadioButton.IsChecked>
|
||||
<Binding Converter="{StaticResource ComparisonConverter}" Path="Angle">
|
||||
<Binding.ConverterParameter>
|
||||
<System:Double>90</System:Double>
|
||||
</Binding.ConverterParameter>
|
||||
</Binding>
|
||||
</RadioButton.IsChecked>
|
||||
</RadioButton>
|
||||
<RadioButton x:Name="LbCustom" Content="自定义" />
|
||||
<TextBox Text="{Binding Angle, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=LbCustom}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<CheckBox
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Content="是否单选"
|
||||
IsChecked="{Binding IsSingleSelect}"
|
||||
ToolTip="单选构件,取消则可以多选构件" />
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding RotateInstanceCommand}"
|
||||
Content="旋转"
|
||||
ToolTip="当选中构件时,则直接旋转,未选中时,则根据选项决定是多选还是单选" />
|
||||
</ui:StackPanel>
|
||||
</ui:FluentWindowEx>
|
||||
27
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateMEPView.xaml.cs
Normal file
27
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateMEPView.xaml.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
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 ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
/// <summary>
|
||||
/// RotateMEPView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class RotateMEPView
|
||||
{
|
||||
public RotateMEPView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
108
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateMEPViewModel.cs
Normal file
108
ShrlAlgoToolkit.RevitAddins/RvMEP/RotateMEPViewModel.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
public partial class RotateMEPViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private double angle = 90;
|
||||
[ObservableProperty]
|
||||
private bool isSingleSelect = true;
|
||||
[RelayCommand]
|
||||
private void RotateInstance()
|
||||
{
|
||||
rotateHandler.Raise(
|
||||
uiapp =>
|
||||
{
|
||||
var uidoc = uiapp.ActiveUIDocument;
|
||||
var doc = uidoc.Document;
|
||||
ICollection<ElementId> elemIds = [];
|
||||
if (uidoc.Selection.GetElementIds().Any())
|
||||
{
|
||||
elemIds = uidoc.Selection.GetElementIds();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsSingleSelect)
|
||||
{
|
||||
var r = uidoc.Selection.PickObject(ObjectType.Element, new FuncFilter(e =>
|
||||
{
|
||||
return e is FamilyInstance && e.GetConnectors().OfType<Connector>().Any(c => c.IsConnected);
|
||||
}), "请选择已经连管的构件");
|
||||
|
||||
elemIds.Add(r.ElementId);
|
||||
}
|
||||
else
|
||||
{
|
||||
elemIds = uidoc.Selection.PickObjects(ObjectType.Element, new FuncFilter(e =>
|
||||
{
|
||||
return e is FamilyInstance && e.GetConnectors().OfType<Connector>().Any(c => c.IsConnected);
|
||||
}), "请选择已经连管的构件,并完成").Select(r => doc.GetElement(r).Id).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var id in elemIds)
|
||||
{
|
||||
var elem = uidoc.Document.GetElement(id);
|
||||
|
||||
var referConn = elem.GetConnectors().OfType<Connector>().FirstOrDefault(c =>
|
||||
{
|
||||
if (c.IsConnected)
|
||||
{
|
||||
if (c.CoordinateSystem.BasisZ.X > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.CoordinateSystem.BasisZ.Y > 0)
|
||||
{
|
||||
return true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.CoordinateSystem.BasisZ.Z > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (referConn != null)
|
||||
{
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
ElementTransformUtils.RotateElement(
|
||||
doc,
|
||||
elem.Id,
|
||||
Line.CreateUnbound(
|
||||
referConn.CoordinateSystem.Origin,
|
||||
referConn.CoordinateSystem.BasisZ),
|
||||
Angle.ToRadian());
|
||||
}, "旋转实例");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
readonly ActionEventHandler rotateHandler = new();
|
||||
}
|
||||
}
|
||||
18
ShrlAlgoToolkit.RevitAddins/RvMEP/RotationAngle.cs
Normal file
18
ShrlAlgoToolkit.RevitAddins/RvMEP/RotationAngle.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
public enum RotationAngle
|
||||
{
|
||||
[Description("22.5°")]
|
||||
TwentyTwoPointFive,
|
||||
[Description("30°")]
|
||||
Thirty,
|
||||
[Description("45°")]
|
||||
FortyFive,
|
||||
[Description("60°")]
|
||||
Sixty,
|
||||
[Description("90°")]
|
||||
Ninety
|
||||
}
|
||||
}
|
||||
15
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveCmd.cs
Normal file
15
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveCmd.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using ShrlAlgo.Toolkit.Core.Assist;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
|
||||
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
|
||||
public class StandMepCurveCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<StandMepCurveView>(new StandMepCurveViewModel(Document));
|
||||
}
|
||||
}
|
||||
97
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveView.xaml
Normal file
97
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveView.xaml
Normal file
@@ -0,0 +1,97 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvMEP.StandMepCurveView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:rvMep="clr-namespace:ShrlAlgo.RvKits.RvMEP"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="创建立管"
|
||||
Width="300"
|
||||
Height="320"
|
||||
MinWidth="300"
|
||||
MinHeight="320"
|
||||
d:DataContext="{d:DesignInstance Type=rvMep:StandMepCurveViewModel}"
|
||||
SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d">
|
||||
<b:Interaction.Triggers>
|
||||
<!--<b:EventTrigger EventName="Deactivated">
|
||||
<b:InvokeCommandAction Command="{Binding CreateMepCurveCommand}" />
|
||||
</b:EventTrigger>-->
|
||||
<b:EventTrigger EventName="Closing">
|
||||
<b:InvokeCommandAction Command="{Binding CancelCommand}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgoToolkit.RevitAddins;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:StackPanel Margin="5" Spacing="5">
|
||||
<ui:StackPanel Spacing="5">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton
|
||||
x:Name="RbPipe"
|
||||
Content="水管"
|
||||
IsChecked="{Binding IsPipe}" />
|
||||
<RadioButton
|
||||
x:Name="RbDuct"
|
||||
Content="风管"
|
||||
IsChecked="{Binding IsDuct}" />
|
||||
<RadioButton
|
||||
x:Name="RbCableTray"
|
||||
Content="桥架"
|
||||
IsChecked="{Binding IsCableTray}" />
|
||||
<RadioButton
|
||||
x:Name="RbConduit"
|
||||
Content="线管"
|
||||
IsChecked="{Binding IsConduit}" />
|
||||
</UniformGrid>
|
||||
<ui:StackPanel Spacing="5" Visibility="{Binding IsPipe, Converter={StaticResource BooleanToVisConverter}}">
|
||||
<ui:ComboBoxEx
|
||||
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
|
||||
ItemsSource="{Binding PipeTypes}"
|
||||
PlaceholderText="<管道类型>"
|
||||
SelectedItem="{Binding SelectedPipeType}" />
|
||||
<ui:ComboBoxEx
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding PipeSystemTypes}"
|
||||
PlaceholderText="<系统类型>"
|
||||
SelectedItem="{Binding SelectedPipeSystemType}" />
|
||||
</ui:StackPanel>
|
||||
|
||||
<ui:StackPanel Spacing="5" Visibility="{Binding IsDuct, Converter={StaticResource BooleanToVisConverter}}">
|
||||
<ui:ComboBoxEx
|
||||
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
|
||||
ItemsSource="{Binding DuctTypes}"
|
||||
PlaceholderText="<风管类型>"
|
||||
SelectedItem="{Binding SelectedDuctType}" />
|
||||
<ui:ComboBoxEx
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding DuctSystemTypes}"
|
||||
PlaceholderText="<系统类型>"
|
||||
SelectedItem="{Binding SelectedDuctSystemType}" />
|
||||
</ui:StackPanel>
|
||||
|
||||
<ui:ComboBoxEx
|
||||
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
|
||||
ItemsSource="{Binding ConduitTypes}"
|
||||
PlaceholderText="<线管类型>"
|
||||
SelectedItem="{Binding SelectedConduitType}"
|
||||
Visibility="{Binding IsConduit, Converter={StaticResource BooleanToVisConverter}}" />
|
||||
<ui:ComboBoxEx
|
||||
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
|
||||
ItemsSource="{Binding CableTrayTypes}"
|
||||
PlaceholderText="<桥架类型>"
|
||||
SelectedItem="{Binding SelectedCableTrayType}"
|
||||
Visibility="{Binding IsCableTray, Converter={StaticResource BooleanToVisConverter}}" />
|
||||
</ui:StackPanel>
|
||||
<Button
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
Command="{Binding CreateMepCurveCommand}"
|
||||
Content="创建立管" />
|
||||
</ui:StackPanel>
|
||||
</ui:FluentWindowEx>
|
||||
16
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveView.xaml.cs
Normal file
16
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveView.xaml.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Windows;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
/// <summary>
|
||||
/// StandMepCurveView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class StandMepCurveView
|
||||
{
|
||||
public StandMepCurveView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
177
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveViewModel.cs
Normal file
177
ShrlAlgoToolkit.RevitAddins/RvMEP/StandMepCurveViewModel.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Electrical;
|
||||
using Autodesk.Revit.DB.Mechanical;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
public partial class StandMepCurveViewModel : ObservableObject
|
||||
{
|
||||
public StandMepCurveViewModel(Document doc)
|
||||
{
|
||||
PipeTypes = doc.OfClass<PipeType>().Cast<PipeType>();
|
||||
DuctTypes = doc.OfClass<DuctType>().Cast<DuctType>();
|
||||
ConduitTypes = doc.OfClass<ConduitType>().Cast<ConduitType>();
|
||||
CableTrayTypes = doc.OfClass<CableTrayType>().Cast<CableTrayType>();
|
||||
PipeSystemTypes = doc.OfClass<PipingSystemType>().Cast<PipingSystemType>();
|
||||
DuctSystemTypes = doc.OfClass<MechanicalSystemType>().Cast<MechanicalSystemType>();
|
||||
}
|
||||
|
||||
private readonly ActionEventHandler standMepCurveEventHandler = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private IEnumerable<CableTrayType> cableTrayTypes;
|
||||
|
||||
[ObservableProperty]
|
||||
private IEnumerable<ConduitType> conduitTypes;
|
||||
|
||||
[ObservableProperty]
|
||||
private IEnumerable<MechanicalSystemType> ductSystemTypes;
|
||||
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private IEnumerable<DuctType> ductTypes;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private bool? isCableTray;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private bool? isConduit;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private bool? isDuct;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private bool? isPipe = true;
|
||||
|
||||
[ObservableProperty]
|
||||
private IEnumerable<PipingSystemType> pipeSystemTypes;
|
||||
|
||||
[ObservableProperty]
|
||||
private IEnumerable<PipeType> pipeTypes;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private CableTrayType selectedCableTrayType;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private ConduitType selectedConduitType;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private MechanicalSystemType selectedDuctSystemType;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private DuctType selectedDuctType;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private PipingSystemType selectedPipeSystemType;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateMepCurveCommand))]
|
||||
private PipeType selectedPipeType;
|
||||
partial void OnSelectedPipeTypeChanged(PipeType value)
|
||||
{
|
||||
var rule = value.RoutingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Segments, 0);
|
||||
var segment = value.Document.GetElement(rule.MEPPartId) as PipeSegment;
|
||||
PipeSizes = segment.GetSizes();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private ICollection<MEPSize> pipeSizes;
|
||||
|
||||
private bool isRunning;
|
||||
|
||||
private bool CanCreate()
|
||||
{
|
||||
return (IsPipe == true && SelectedPipeType != null && SelectedPipeSystemType != null)
|
||||
|| (IsDuct == true && SelectedDuctType != null && SelectedDuctSystemType != null)
|
||||
|| (IsConduit == true && SelectedConduitType != null)
|
||||
|| (IsCableTray == true && SelectedCableTrayType != null && !isRunning);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Cancel()
|
||||
{
|
||||
if (!isRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
KeyIntPtrHelper.RaiseEscTwice();
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanCreate))]
|
||||
private void CreateMepCurve()
|
||||
{
|
||||
isRunning = true;
|
||||
standMepCurveEventHandler.Raise(app =>
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var uidoc = app.ActiveUIDocument;
|
||||
var view = uidoc.ActiveView;
|
||||
var doc = uidoc.Document;
|
||||
const ObjectSnapTypes ss = ObjectSnapTypes.Points
|
||||
| ObjectSnapTypes.Endpoints
|
||||
| ObjectSnapTypes.Intersections
|
||||
| ObjectSnapTypes.Centers
|
||||
| ObjectSnapTypes.Midpoints
|
||||
| ObjectSnapTypes.Perpendicular
|
||||
| ObjectSnapTypes.Quadrants
|
||||
| ObjectSnapTypes.Tangents;
|
||||
var point = uidoc.Selection.PickPoint(ss, "选择创建立管的点");
|
||||
var startPoint = new XYZ(point.X, point.Y, view.GenLevel.Elevation);
|
||||
var endPoint = new XYZ(point.X, point.Y, view.GenLevel.Elevation + (2000 / 304.8));
|
||||
doc.Invoke(
|
||||
_ =>
|
||||
{
|
||||
if (IsPipe == true)
|
||||
{
|
||||
Pipe.Create(doc, SelectedPipeSystemType.Id, SelectedPipeType.Id, view.GenLevel.Id, startPoint, endPoint);
|
||||
}
|
||||
else if (IsDuct == true)
|
||||
{
|
||||
Duct.Create(doc, SelectedDuctSystemType.Id, SelectedDuctType.Id, view.GenLevel.Id, startPoint, endPoint);
|
||||
}
|
||||
else if (IsConduit == true)
|
||||
{
|
||||
Conduit.Create(doc, SelectedConduitType.Id, startPoint, endPoint, view.GenLevel.Id);
|
||||
}
|
||||
else if (IsCableTray == true)
|
||||
{
|
||||
CableTray.Create(doc, SelectedCableTrayType.Id, startPoint, endPoint, view.GenLevel.Id);
|
||||
}
|
||||
},
|
||||
"创建立管"
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
isRunning = false;
|
||||
}
|
||||
}
|
||||
65
ShrlAlgoToolkit.RevitAddins/RvMEP/SystemModel.cs
Normal file
65
ShrlAlgoToolkit.RevitAddins/RvMEP/SystemModel.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Plumbing;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP
|
||||
{
|
||||
public partial class SystemModel : ObservableObject
|
||||
{
|
||||
public SystemModel(MEPSystemType systemType)
|
||||
{
|
||||
//PipingSystemType;
|
||||
//MechanicalSystemType
|
||||
SystemType = systemType;
|
||||
Name = systemType.Name;
|
||||
MEPSystemClassification = (MEPSystemClassification)systemType.SystemClassification;
|
||||
FillColor = systemType.FillColor;
|
||||
Abbreviation = systemType.Abbreviation;
|
||||
}
|
||||
[ObservableProperty]
|
||||
private System.Windows.Media.Brush backgroundColor;
|
||||
|
||||
[ObservableProperty]
|
||||
private Color fillColor;
|
||||
|
||||
[ObservableProperty]
|
||||
private MEPSystemClassification mEPSystemClassification;
|
||||
|
||||
[ObservableProperty]
|
||||
private string name;
|
||||
[ObservableProperty]
|
||||
private PipeSystemType pipeSystemType;
|
||||
//系统类型
|
||||
[ObservableProperty]
|
||||
private MEPSystemType systemType;
|
||||
|
||||
[ObservableProperty]
|
||||
private Color lineColor;
|
||||
[ObservableProperty]
|
||||
private string abbreviation;
|
||||
|
||||
}
|
||||
|
||||
public enum MEPSystemClassification
|
||||
{
|
||||
[Description("送风")] SupplyAir = 1,
|
||||
[Description("回风")] ReturnAir = 2,
|
||||
[Description("排风")] ExhaustAir = 3,
|
||||
[Description("循环供水")] SupplyHydronic = 7,
|
||||
[Description("循环回水")] ReturnHydronic = 8,
|
||||
[Description("卫生设备")] Sanitary = 16,
|
||||
[Description("通风孔")] Vent = 17,
|
||||
[Description("雨水")] Storm = 18,
|
||||
[Description("家用热水")] DomesticHotWater = 19,
|
||||
[Description("家用冷水")] DomesticColdWater = 20,
|
||||
[Description("中水")] Recirculation = 21,
|
||||
[Description("其他")] OtherPipe = 22,
|
||||
[Description("湿式消防系统")] FireProtectWet = 23,
|
||||
[Description("干式消防系统")] FireProtectDry = 24,
|
||||
[Description("预作用消防系统")] FireProtectPreaction = 25,
|
||||
[Description("其他消防系统")] FireProtectOther = 26
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Mechanical;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvMEP;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class TerminalConnectToDuctCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
#if REVIT2018 || REVIT2020
|
||||
var terminalId = UiDocument.Selection
|
||||
.PickObject(
|
||||
Autodesk.Revit.UI.Selection.ObjectType.Element,
|
||||
new FuncFilter(e => e.Category.Id.IntegerValue == -2008013),
|
||||
"请选择风管末端"
|
||||
)
|
||||
.ElementId;
|
||||
#elif REVIT2025
|
||||
var terminalId = UiDocument.Selection
|
||||
.PickObject(
|
||||
Autodesk.Revit.UI.Selection.ObjectType.Element,
|
||||
new FuncFilter(e => e.Category.Id.Value == -2008013),
|
||||
"请选择风管末端"
|
||||
)
|
||||
.ElementId;
|
||||
#endif
|
||||
var ductId = UiDocument.Selection
|
||||
.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new GenericFilter<Duct>(), "请选择连接到的风管")
|
||||
.ElementId;
|
||||
Document.Invoke(_ =>
|
||||
{
|
||||
MechanicalUtils.ConnectAirTerminalOnDuct(Document, terminalId, ductId);
|
||||
});
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user