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

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

View File

@@ -56,17 +56,11 @@
<setting name="DockPaneGuid" serializeAs="String">
<value>2ab776b4-b3fc-4810-8f44-ab5f1c9f5fa8</value>
</setting>
<setting name="AutoSave" serializeAs="String">
<value>True</value>
</setting>
<setting name="AutoSaveIntervalTime" serializeAs="String">
<value>10</value>
</setting>
<setting name="TimerSubscribed" serializeAs="String">
<value>False</value>
<value>5</value>
</setting>
<setting name="IsActiveAutoSave" serializeAs="String">
<value>False</value>
<value>True</value>
</setting>
</Sai.RvKits.Properties.Settings>
</userSettings>

View File

@@ -9,10 +9,8 @@ using CommunityToolkit.Diagnostics;
namespace Sai.RvKits;
public class CadSharperUtil(string path)
public static class DWGAssist
{
public ACadSharp.CadDocument CadDocument { get; private set; } = ACadSharp.IO.DwgReader.Read(path, OnNotification);
private static void OnNotification(object sender, ACadSharp.IO.NotificationEventArgs e) { }
/// <summary>
@@ -20,10 +18,8 @@ public class CadSharperUtil(string path)
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static CadObjectCollection<ACadSharp.Entities.Entity> GetAllEntitiesInModel(string file)
public static CadObjectCollection<ACadSharp.Entities.Entity> GetAllEntitiesInModel(this ACadSharp.CadDocument doc)
{
var doc = ACadSharp.IO.DwgReader.Read(file);
// 获取所有绘图实体所在的模型空间
var modelSpace = doc.BlockRecords["*Model_Space"];
@@ -31,25 +27,21 @@ public class CadSharperUtil(string path)
return modelSpace.Entities;
}
/// <summary>
/// 获取dwg所在的路径
/// 获取模型中的所有实体
/// </summary>
/// <param name="dwg"></param>
/// <param name="doc"></param>
/// <returns></returns>
public static string GetDwgPath(ImportInstance dwg)
public static CadObjectCollection<ACadSharp.Entities.Entity> GetAllEntitiesInCAD(this ACadSharp.CadDocument doc)
{
var cadLinkType = dwg.Document.GetElement(dwg.GetTypeId()) as CADLinkType;
Guard.IsNotNull(cadLinkType);
var filePath = cadLinkType.GetExternalFileReference().GetLinkedFileStatus() == LinkedFileStatus.Loaded
? ModelPathUtils.ConvertModelPathToUserVisiblePath(cadLinkType?.GetExternalFileReference().GetAbsolutePath())
: throw new InvalidOperationException("该dwg不是链接");
return !File.Exists(filePath) ? throw new InvalidOperationException("链接文件路径不存在") : filePath;
// 获取dwg中的所有实体
return doc.Entities;
}
public static List<KeyValuePair<string, XYZ>> GetTextByLayer(ImportInstance dwg, string textLayerName)
{
var keyValuePairs = new List<KeyValuePair<string, XYZ>>();
var dwgTransform = dwg!.GetTransform();
var path = CadSharperUtil.GetDwgPath(dwg);
var path = dwg.GetFilePath();
using ACadSharp.IO.DwgReader reader = new(path);
var cadDocument = reader.Read();
var entities = cadDocument.Entities.Where(entity => (entity is ACadSharp.Entities.MText || entity is ACadSharp.Entities.TextEntity) && entity.Layer.Name == textLayerName);
@@ -76,12 +68,11 @@ public class CadSharperUtil(string path)
}
return keyValuePairs;
}
public void DwgEntitiesToNewFile(string input, string output)
public static void DwgEntitiesToNewFile(this ACadSharp.CadDocument doc, string output)
{
/* --- ---
* ACadSharp无法写入已读的dwg/dxf文件dxf时文件结构有问题 *
*/
var doc = ACadSharp.IO.DwgReader.Read(input);
* ACadSharp无法写入已读的dwg/dxf文件dxf时文件结构有问题 *
*/
//转移实体的新文件
ACadSharp.CadDocument transfer = new();
@@ -96,71 +87,58 @@ public class CadSharperUtil(string path)
}
//保存文件
using ACadSharp.IO.DxfWriter writer = new(output, doc, false);
writer.OnNotification += Writer_OnNotification;
writer.Write();
ACadSharp.IO.DxfWriter.Write(output, doc, false, OnNotification);
}
private void Writer_OnNotification(object sender, ACadSharp.IO.NotificationEventArgs e) { }
/// <summary>
/// 读取dxf文件
/// </summary>
/// <param name="file">dxf file path</param>
/// <param name="file">dxf filePath path</param>
/// <param name="action"></param>
public static void ReadDxf(string file, Action<ACadSharp.CadDocument> action)
public static CadDocument ReadDxf(string file)
{
using ACadSharp.IO.DxfReader reader = new(file);
var doc = reader.Read();
action.Invoke(doc);
return new ACadSharp.IO.DxfReader(file, OnNotification).Read();
}
/// <summary>
/// Read a dwg file
/// 读取dxg文件
/// </summary>
/// <param name="file">dwg file path</param>
/// <param name="file">dwg filePath path</param>
/// <param name="action"></param>
public static void ReadDwg(string file, Action<ACadSharp.CadDocument> action)
public static CadDocument ReadDwg(string file)
{
using ACadSharp.IO.DwgReader reader = new(file);
var doc = reader.Read();
action.Invoke(doc);
return new ACadSharp.IO.DwgReader(file, OnNotification).Read();
}
/// <summary>
/// 写一个ascii dxf文件
/// </summary>
/// <param name="file"></param>
/// <param name="filePath"></param>
/// <param name="doc"></param>
public void WriteAsciiDxf(string file, ACadSharp.CadDocument doc)
public static void WriteAsciiDxf(this ACadSharp.CadDocument doc, string filePath)
{
using ACadSharp.IO.DxfWriter writer = new(file, doc, false);
writer.OnNotification += Writer_OnNotification;
writer.Write();
ACadSharp.IO.DxfWriter.Write(filePath, doc, false, OnNotification);
}
/// <summary>
/// 编写一个二进制的dxf文件
/// </summary>
/// <param name="file"></param>
/// <param name="filePath"></param>
/// <param name="doc"></param>
public void WriteBinaryDxf(string file, ACadSharp.CadDocument doc)
public static void WriteBinaryDxf(this ACadSharp.CadDocument doc, string filePath)
{
using ACadSharp.IO.DxfWriter writer = new(file, doc, true);
writer.OnNotification += Writer_OnNotification;
writer.Write();
ACadSharp.IO.DxfWriter.Write(filePath, doc, true, OnNotification);
}
/// <summary>
/// 获取模型中的所有块
/// 获取模型中的同名所有块
/// </summary>
/// <param name="file"></param>
/// <param name="blockName"></param>
/// <returns></returns>
public static IEnumerable<Insert> GetInsertEntities(string file, string blockName)
public static IEnumerable<Insert> GetInsertEntities(this ACadSharp.CadDocument doc, string blockName)
{
var doc = ACadSharp.IO.DwgReader.Read(file);
//获取正在使用你要找的块的插入实例
return doc.Entities.OfType<ACadSharp.Entities.Insert>().Where(e => e.Block.Name == blockName);
}

View File

@@ -600,7 +600,7 @@ public partial class ModelCheckViewModel : ObservableObject
}
List<ElementId> ids = [model.Element.Id];
//UiDocument.ActiveView.IsolateElementTemporary(model.Element.ViewId);
//UiDocument.ActiveView.IsolateElementTemporary(model.ElementToMove.ViewId);
showElementsSectionBox.Raise(_ =>
{
if (uidoc.ActiveView is not View3D view3d)

View File

@@ -60,6 +60,26 @@ namespace Sai.RvKits.Properties {
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap add_insulation_16px {
get {
object obj = ResourceManager.GetObject("add_insulation_16px", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap add_insulation_32px {
get {
object obj = ResourceManager.GetObject("add_insulation_32px", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
@@ -190,6 +210,46 @@ namespace Sai.RvKits.Properties {
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap arrange_mep_16px {
get {
object obj = ResourceManager.GetObject("arrange_mep_16px", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap arrange_mep_16px1 {
get {
object obj = ResourceManager.GetObject("arrange_mep_16px1", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap arrange_mep_32px {
get {
object obj = ResourceManager.GetObject("arrange_mep_32px", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap arrange_mep_32px1 {
get {
object obj = ResourceManager.GetObject("arrange_mep_32px1", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>

View File

@@ -280,6 +280,12 @@
<data name="rotate_instance_32px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\rotate_instance_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="arrange_mep_16px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\arrange_mep_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="arrange_mep_32px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\arrange_mep_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="flip_workplane_16px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\flip_workplane_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@@ -487,4 +493,16 @@
<data name="top_elev_32px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\top_elev_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="add_insulation_16px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\add_insulation_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="add_insulation_32px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\add_insulation_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="arrange_mep_16px1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\arrange_mep_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="arrange_mep_32px1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\arrange_mep_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@@ -133,19 +133,7 @@ namespace Sai.RvKits.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool AutoSave {
get {
return ((bool)(this["AutoSave"]));
}
set {
this["AutoSave"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
[global::System.Configuration.DefaultSettingValueAttribute("5")]
public int AutoSaveIntervalTime {
get {
return ((int)(this["AutoSaveIntervalTime"]));
@@ -157,19 +145,7 @@ namespace Sai.RvKits.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool TimerSubscribed {
get {
return ((bool)(this["TimerSubscribed"]));
}
set {
this["TimerSubscribed"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool IsActiveAutoSave {
get {
return ((bool)(this["IsActiveAutoSave"]));

View File

@@ -29,17 +29,11 @@
<Setting Name="DockPaneGuid" Type="System.String" Scope="User">
<Value Profile="(Default)">2ab776b4-b3fc-4810-8f44-ab5f1c9f5fa8</Value>
</Setting>
<Setting Name="AutoSave" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="AutoSaveIntervalTime" Type="System.Int32" Scope="User">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="TimerSubscribed" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
<Value Profile="(Default)">5</Value>
</Setting>
<Setting Name="IsActiveAutoSave" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

View File

@@ -10,7 +10,7 @@ namespace Sai.RvKits.RvCommon;
[Regeneration(RegenerationOption.Manual)]
public class AutoSaveCmd : ExternalCommand
{
private readonly System.Timers.Timer timer = Variables.Timer;
private readonly System.Timers.Timer timer = Variables.AutoSaveTimer;
public override void Execute()
{
if (string.IsNullOrEmpty(Document.PathName))
@@ -25,22 +25,20 @@ public class AutoSaveCmd : ExternalCommand
DataContext = viewModel
};
view.ShowDialog();
if (view.DialogResult == true)
if (Properties.Settings.Default.IsActiveAutoSave)
{
if (Properties.Settings.Default.AutoSave)
if (Properties.Settings.Default.AutoSaveIntervalTime >= 1)
{
if (Properties.Settings.Default.AutoSaveIntervalTime >= 1)
{
timer.Interval = Properties.Settings.Default.AutoSaveIntervalTime * 60 * 1000;
}
timer.Interval = Properties.Settings.Default.AutoSaveIntervalTime * 60 * 1000;
Properties.Settings.Default.Save();
//timer.Enabled = Properties.Settings.Default.AutoSave;
timer.Start();
}
else
{
timer.Stop();
}
//timer.Enabled = Properties.Settings.Default.AutoSave;
timer.Start();
}
else
{
timer.Stop();
}
Result = Result.Succeeded;
}

View File

@@ -1,5 +1,6 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@@ -7,27 +8,33 @@ namespace Sai.RvKits.RvCommon;
public partial class AutoSaveViewModel : ObservableValidator
{
public AutoSaveViewModel()
{
IsActiveAutoSave = Properties.Settings.Default.IsActiveAutoSave;
IntervalTime = Properties.Settings.Default.AutoSaveIntervalTime;
}
public AutoSaveViewModel()
{
IsActiveAutoSave = Properties.Settings.Default.IsActiveAutoSave;
IntervalTime = Properties.Settings.Default.AutoSaveIntervalTime;
}
[ObservableProperty]
private bool isActiveAutoSave;
private bool isActiveAutoSave;
//partial void OnIsActiveAutoSaveChanged(bool value)
//{
// throw new NotImplementedException();
//}
[Required(ErrorMessage = "不可为空")]
[DefaultValue(15)]
[DefaultValue(10)]
[NotifyDataErrorInfo]
[Range(5, 30, ErrorMessage = "输入值应在5~30分钟之间")]
[Range(1, 30, ErrorMessage = "输入值应在1~30分钟之间")]
[ObservableProperty]
private int intervalTime;
[RelayCommand]
private void Closing()
{
Properties.Settings.Default.IsActiveAutoSave = IsActiveAutoSave;
Properties.Settings.Default.AutoSaveIntervalTime = IntervalTime;
Properties.Settings.Default.Save();
}
[RelayCommand]
private void Closing()
{
Properties.Settings.Default.IsActiveAutoSave = IsActiveAutoSave;
Properties.Settings.Default.AutoSaveIntervalTime = IntervalTime;
Properties.Settings.Default.Save();
Variables.AutoSaveTimer.Interval = IntervalTime * 60 * 1000;
}
}

View File

@@ -249,7 +249,7 @@ public partial class InstanceCreatorViewModel : ObservableObject
// }
// var dwg = doc.GetElement(textRefer) as ImportInstance;
// var textLayerName = dwg.GetLayerName(textRefer);
// var path = dwg.GetDwgPath();
// var path = dwg.GetFilePath();
// var dwgTransform = dwg.GetTotalTransform();
// using ACadSharp.IO.DwgReader reader = new(path);

View File

@@ -26,7 +26,7 @@ public class ModifyModelParams : ExternalCommand
var textRefer = UiDocument.Selection.PickObject(ObjectType.PointOnElement, "请选择管线标注文字");
var dwg = Document.GetElement(textRefer) as ImportInstance;
var textLayerName = dwg.GetLayerName(textRefer);
var path = dwg.GetDwgPath();
var path = dwg.GetFilePath();
var dwgTransform = dwg!.GetTransform();
Document.Invoke(_ =>
{

View File

@@ -81,7 +81,7 @@ public partial class PipesCreatorViewModel : ObservableObject
doc.ActiveView.SetCategoryHidden(curve.GraphicsStyleId, false);
doc.ActiveView.SetCategoryHidden(text.GraphicsStyleId, false);
});
var path = dwg.GetDwgPath();
var path = dwg.GetFilePath();
using ACadSharp.IO.DwgReader reader = new(path);
var cadDocument = reader.Read();
//var blocks = cadDocument.Entities.OfType<ACadSharp.Entities.Insert>().Where(e => e.Layer.Name == layerName).ToList();

View File

@@ -111,7 +111,7 @@ public partial class FamilyProcessorViewModel : ObservableObject
// var familySymbolCollector = SourceDoc.OfClass<FamilySymbol>().Cast<FamilySymbol>().ToList();
// //ErrorModels<ElementId> dimensionTypeId = (from Element i in new FilteredElementCollector(sourceDoc).OfClass(typeof(DimensionType)) select i.ViewId).ToList();
// //ErrorModels<ElementId> dimensionTypeId = (from ElementToMove i in new FilteredElementCollector(sourceDoc).OfClass(typeof(DimensionType)) select i.ViewId).ToList();
// //var elementTypes = new FilteredElementCollector(sourceDoc).OfClass(typeof(ElementType));
// //ElementClassFilter familysymbolfilter = new ElementClassFilter(typeof(FamilySymbol));

View File

@@ -40,7 +40,7 @@ public partial class RenameTypeViewModel : ObservableObject
[ObservableProperty]
private bool isRunning;
/// <summary>
/// 选中正在使用中的条目
/// </summary>
@@ -161,11 +161,11 @@ public partial class RenameTypeViewModel : ObservableObject
foreach (var renameItem in selectedItems)
{
var tempName = renameItem.OldTypeName;
//手动修改的新名称不处理
if (!string.IsNullOrEmpty(renameItem.NewTypeName))
{
continue;
}
////手动修改的新名称不处理
//if (!string.IsNullOrEmpty(renameItem.NewTypeName))
//{
// continue;
//}
if (!string.IsNullOrEmpty(FoundText))
{
tempName = tempName.Replace(FoundText, string.IsNullOrEmpty(ReplaceText) ? string.Empty : ReplaceText);

View File

@@ -3,7 +3,7 @@ using System.Xml.Serialization;
namespace Sai.Toolkit.Core.LandXMLData;
[XmlType("Element")]
[XmlType("ElementToMove")]
[Serializable]
public class ElementModel : ShapeModel
{

View File

@@ -15,7 +15,7 @@ namespace Sai.Toolkit.Core.LandXMLData
[XmlAttribute("name")]
public string Name;
[XmlElement("Element")]
[XmlElement("ElementToMove")]
public List<SolidInstances> Solids;
}
}

View File

@@ -12,7 +12,7 @@ namespace Sai.Toolkit.Core.LandXMLData
Elements = new List<ElementModel>();
}
[XmlElement("Element")]
[XmlElement("ElementToMove")]
public List<ElementModel> Elements;
[XmlAttribute("name")]

View File

@@ -6,7 +6,7 @@ namespace Sai.RvKits.RvIndependent
{
public ExcelData(ExcelWorksheet sheet)
{
DataRows = new List<ExcelDataRow>();
DataRows = [];
var lastColumn = sheet.Dimension.End.Column;
var lastRow = sheet.Dimension.End.Row;
//不计算所有末行首列为空的行
@@ -23,13 +23,13 @@ namespace Sai.RvKits.RvIndependent
StartId = sheet.Cells[i, 1].Value?.ToString(), //起点节点号
Number = sheet.Cells[i, 2].Value?.ToString(), //管线点号
EndId = sheet.Cells[i, 3].Value?.ToString(), //连接点号
LayingMode = sheet.Cells[i, 4].Value?.ToString(), //埋设s方式
LayingMode = sheet.Cells[i, 4].Value?.ToString(), //埋设方式
Material = sheet.Cells[i, 5].Value?.ToString(), //管材
Size = sheet.Cells[i, 6].Value?.ToString(), //截面尺寸
Feature = sheet.Cells[i, 7].Value?.ToString(), //特征
AccessoryType = sheet.Cells[i, 8].Value?.ToString(), //节点类型
X = Convert.ToDouble(sheet.Cells[i, 9].Value),
Y = Convert.ToDouble(sheet.Cells[i, 10].Value),
X = Convert.ToDouble(sheet.Cells[i, 9].Value),//坐标Y
Y = Convert.ToDouble(sheet.Cells[i, 10].Value),//坐标X
GroundElev = Convert.ToDouble(sheet.Cells[i, 11].Value), //地面高程
Top = Convert.ToDouble(sheet.Cells[i, 12].Value), //管顶
InnerBottom = Convert.ToDouble(sheet.Cells[i, 13].Value), //管内底

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -62,108 +62,121 @@ public partial class ClashResolveViewModel : ObservableObject
doc.Invoke(
ts =>
{
switch (LocationType)
try
{
case LocationType.Manual:
switch (LocationType)
{
case LocationType.Manual:
{
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
),
"请选择翻弯的管线上的点"
);
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
var reference2 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(e => e.Id == mepCurveToBend!.Id),
"请选择另一个翻弯管线上的点或确定单侧翻弯的需要偏移一侧"
);
//两个断点,breakPoint1距离原直线起点近反向时交换值
breakPoint1 = mepCurveToBend.GetLocCurve().Project(reference1.GlobalPoint).XYZPoint;
breakPoint2 = mepCurveToBend.GetLocCurve().Project(reference2.GlobalPoint).XYZPoint;
}
break;
case LocationType.Reference:
{
var reference = uidoc.Selection.PickObject(
ObjectType.Element,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
),
"请选择参照的管线"
);
//参考的管线定位
var referenceMEPCurve = doc.GetElement(reference);
var referenceLine = referenceMEPCurve.GetLocCurve() as Line;
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
&& e.Id != referenceMEPCurve!.Id
),
"请选择翻弯的管线或确定单侧翻弯的需要偏移一侧"
);
//翻弯的管线定位
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
var bendLine = mepCurveToBend.GetLocCurve() as Line;
var result = bendLine!.Intersect(referenceLine, out var array);
XYZ intersectPoint = default;
switch (result)
{
case SetComparisonResult.Overlap:
intersectPoint = array.get_Item(0).XYZPoint;
break;
case SetComparisonResult.Disjoint:
{
IList<ClosestPointsPairBetweenTwoCurves> points =
[];
bendLine.ComputeClosestPoints(referenceLine, true, true, false, out points);
var point = points.FirstOrDefault()?.XYZPointOnFirstCurve;
if (bendLine.IsInsideEx(point, 0.2))
{
intersectPoint = point;
}
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
),
"请选择翻弯的管线上的点"
);
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
if (mepCurveToBend.Pinned)
{
MessageBox.Show("错误", "请解锁图元");
CanRunning = true;
return;
}
var reference2 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(e => e.Id == mepCurveToBend!.Id),
"请选择另一个翻弯管线上的点或确定单侧翻弯的需要偏移一侧"
);
//两个断点,breakPoint1距离原直线起点近反向时交换值
breakPoint1 = mepCurveToBend.GetLocCurve().Project(reference1.GlobalPoint).XYZPoint;
breakPoint2 = mepCurveToBend.GetLocCurve().Project(reference2.GlobalPoint).XYZPoint;
}
break;
case LocationType.Reference:
{
var reference = uidoc.Selection.PickObject(
ObjectType.Element,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
),
"请选择参照的管线"
);
//参考的管线定位
var referenceMEPCurve = doc.GetElement(reference);
var referenceLine = referenceMEPCurve.GetLocCurve() as Line;
var reference1 = uidoc.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(
e =>
e is MEPCurve mepCurve and not InsulationLiningBase
&& mepCurve.GetLocCurve() is Line line
&& !line.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero)
&& e.Id != referenceMEPCurve!.Id
),
"请选择翻弯的管线或确定单侧翻弯的需要偏移一侧"
);
//翻弯的管线定位
mepCurveToBend = doc.GetElement(reference1) as MEPCurve;
var bendLine = mepCurveToBend.GetLocCurve() as Line;
var result = bendLine!.Intersect(referenceLine, out var array);
XYZ intersectPoint = default;
switch (result)
{
case SetComparisonResult.Overlap:
intersectPoint = array.get_Item(0).XYZPoint;
break;
}
}
case SetComparisonResult.Disjoint:
{
IList<ClosestPointsPairBetweenTwoCurves> points =
[];
bendLine.ComputeClosestPoints(referenceLine, true, true, false, out points);
var point = points.FirstOrDefault()?.XYZPointOnFirstCurve;
if (bendLine.IsInsideEx(point, 0.2))
{
intersectPoint = point;
}
breakPoint1 = intersectPoint - (bendLine.Direction * Offset / 304.8);
breakPoint2 = intersectPoint + (bendLine.Direction * Offset / 304.8);
if (
reference1.GlobalPoint.DistanceTo(breakPoint1)
< reference1.GlobalPoint.DistanceTo(breakPoint2)
) //距离近的是breakpoint2
{
(breakPoint1, breakPoint2) = (breakPoint2, breakPoint1);
}
break;
}
}
if (
intersectPoint == default
|| !bendLine.IsInsideEx(breakPoint1, 0.2)
|| !bendLine.IsInsideEx(breakPoint2, 0.2)
)
{
return;
breakPoint1 = intersectPoint - (bendLine.Direction * Offset / 304.8);
breakPoint2 = intersectPoint + (bendLine.Direction * Offset / 304.8);
if (
reference1.GlobalPoint.DistanceTo(breakPoint1)
< reference1.GlobalPoint.DistanceTo(breakPoint2)
) //距离近的是breakpoint2
{
(breakPoint1, breakPoint2) = (breakPoint2, breakPoint1);
}
if (
intersectPoint == default
|| !bendLine.IsInsideEx(breakPoint1, 0.2)
|| !bendLine.IsInsideEx(breakPoint2, 0.2)
)
{
return;
}
}
}
break;
break;
}
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
CanRunning = true;
return;
}
var originBaseLine = mepCurveToBend.GetLocCurve() as Line;

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Windows;
using Autodesk.Revit.DB;
@@ -55,13 +56,35 @@ namespace Sai.RvKits.RvView
{
var uidoc = uiapp.ActiveUIDocument;
var element = uidoc.SelectObject(new FuncFilter(elem => elem.GetLocCurve() is Line));
#region
//var firstTip = "请选择第一个点以确定正交剖面的定位点";
//var lastTip = "请选择第二个点以确定拉抻的深度";
//if (IsParallel)
//{
// firstTip = "请选择第一个剖面范围水平的边界点";
// lastTip = "请选择第二个剖面范围水平的边界点";
//}
//var firstrefer = uidoc.Selection
// .PickObject(Autodesk.Revit.UI.Selection.ObjectType.PointOnElement, firstTip);
//var lastrefer = uidoc.Selection
// .PickObject(Autodesk.Revit.UI.Selection.ObjectType.PointOnElement, lastTip);
//var first = firstrefer.GlobalPoint;
//var last = firstrefer.GlobalPoint;
//var elementByCurve = uidoc.Document.GetElement(firstrefer);
//var firstPoint = elementByCurve.GetLocCurve().Project(first).XYZPoint;
//var lastPoint = elementByCurve.GetLocCurve().Project(last).XYZPoint;
#endregion
var lc = element.Location as LocationCurve;
var line = lc.Curve as Line;
var doc = uidoc.Document;
//获取剖面图类型
var viewfamilyType = doc.OfClass<ViewFamilyType>()
.Cast<ViewFamilyType>()
.Where(t => t.ViewFamily == ViewFamily.Section)
.FirstOrDefault();
var bb = element.get_BoundingBox(null);
var minZ = bb.Min.Z;
var maxZ = bb.Max.Z;
@@ -70,30 +93,33 @@ namespace Sai.RvKits.RvView
ViewSection viewSection = null;
BoundingBoxXYZ sectionBox;
var offset = 0.2 * baseLength;
//transform.xRightDirectiontransform.yUpDirection=Z轴transform.zViewDirection (r x u=v)
var t = Transform.Identity;
Debug.WriteLine($"Length{baseLength}");
Debug.WriteLine($"Offset{offset}");
Debug.WriteLine("拾取对象:");
Debug.WriteLine($"Min{bb.Min}");
Debug.WriteLine($"Max{bb.Max}");
//获得定位点
t.Origin = line.Evaluate(0.5, true).Flatten();
//t.Origin = line.GetEndPoint(0).Flatten();
Debug.WriteLine("定义剖面:");
Debug.WriteLine($"Transform.Origin{t.Origin}");
t.BasisY = XYZ.BasisZ;//UpDirection
t.BasisY = XYZ.BasisZ;//固定朝上UpDirection
var viewName = $"{element.Category.Name}({element.Id})";
if (IsParallel)
{
var min = new XYZ(-baseLength / 2, minZ - offset, -offset);
var max = new XYZ(baseLength / 2, maxZ + offset, offset);
//剖面视图中,裁剪框左下角的点
var min = new XYZ(-(baseLength + 1) / 2, minZ - 10, -2);
//剖面视图中,裁剪框右上角的点
var max = new XYZ((baseLength + 1) / 2, maxZ + 10, 2);
Debug.WriteLine($"Min{min}");
Debug.WriteLine($"Max{max}");
viewName = $"平行剖面-{viewName}";
t.BasisX = line.Direction;//与生成的最终剖面视图的RightDirection反向(定义Transform)
t.BasisZ = line.Direction.CrossProduct(XYZ.BasisZ);//与生成的最终剖面视图的ViewDirection反向(定义Transform)
Debug.WriteLine($"Transform.BasisX{t.BasisX}");
Debug.WriteLine($"Transform.BasisZ{t.BasisZ}");
@@ -110,22 +136,33 @@ namespace Sai.RvKits.RvView
viewName = $"正交剖面-{viewName}";
t.BasisX = XYZ.BasisZ.CrossProduct(line.Direction);
t.BasisZ = line.Direction;
var min = new XYZ(-3000 / 304.8 / 2, minZ - offset, -offset);
var max = new XYZ(3000 / 304.8 / 2, maxZ + offset, offset);
var min = new XYZ(-5, minZ - 5, -2);
var max = new XYZ(5, maxZ + 5, 2);
Debug.WriteLine($"Transform.BasisX{t.BasisX}");
Debug.WriteLine($"Transform.BasisZ{t.BasisZ}");
sectionBox = new BoundingBoxXYZ
try
{
Transform = t,
Min = min,
Max = max
};
sectionBox = new BoundingBoxXYZ
{
Transform = t,
Min = min,
Max = max
};
}
catch (Exception)
{
throw;
}
}
doc.Invoke(
ts =>
{
if (sectionBox == null)
{
return;
}
viewSection = ViewSection.CreateSection(uidoc.Document, viewfamilyType.Id, sectionBox);
viewSection.DisplayStyle = DisplayStyle.ShadingWithEdges;
viewSection.DetailLevel = ViewDetailLevel.Fine;

View File

@@ -84,11 +84,13 @@
<PackageReference Include="CommunityToolkit.Diagnostics" Version="8.3.2" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
<PackageReference Include="EPPlus.Core.Extensions" Version="2.4.0" />
<PackageReference Include="ACadSharp" Version="1.0.0" />
<PackageReference Include="ACadSharp" Version="1.0.1" />
<PackageReference Include="FuzzySharp" Version="2.0.2" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.65" />
<!--TreatAsUsed="true"标记为已使用-->
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" TreatAsUsed="true" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" TreatAsUsed="true">
<TreatAsUsed></TreatAsUsed>
</PackageReference>
<PackageReference Include="randomColorSharped.NetStandard" Version="1.0.2" />
</ItemGroup>
<!-- <ItemGroup Condition="$(DefineConstants.Contains('WINFORMS'))"> -->
@@ -144,6 +146,10 @@
</ItemGroup>
<ItemGroup>
<None Remove="Resources\add_insulation_16px.png" />
<None Remove="Resources\add_insulation_32px.png" />
<None Remove="Resources\arrange_mep_16px.png" />
<None Remove="Resources\arrange_mep_32px.png" />
<None Remove="Resources\flip_workplane_16px.png" />
<None Remove="Resources\flip_workplane_32px.png" />
<None Remove="Resources\rotate_instance_16px.png" />

View File

@@ -1,4 +1,4 @@
using System.Runtime.InteropServices;
using System.Windows;
using Autodesk.Revit.UI;
@@ -21,23 +21,31 @@ public class RvApp : ExternalApplication
{
private static readonly string TabName = Settings.Default.TabName;
private AsyncEventHandler saveHandler;
readonly System.Timers.Timer saveTimer = Variables.AutoSaveTimer;
private void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
{
saveHandler.RaiseAsync(app =>
{
{
#if REVIT2018
if (app.ActiveUIDocument.Document.IsModified)
{
app.ActiveUIDocument.Document.Save();
}
foreach (Autodesk.Revit.DB.Document doc in app.Application.Documents)
{
if (doc.IsModified && !string.IsNullOrEmpty(doc.PathName))
{
doc.Save();
}
}
#else
if (!app.ActiveUIDocument.Document.IsBackgroundCalculationInProgress() && app.ActiveUIDocument.Document.IsModified)
{
app.ActiveUIDocument.Document.Save();
}
foreach (Autodesk.Revit.DB.Document doc in app.Application.Documents)
{
if (!doc.IsBackgroundCalculationInProgress() && doc.IsModified&&!string.IsNullOrEmpty(doc.PathName))
{
doc.Save();
}
}
#endif
});
});
}
public override void OnStartup()
{
@@ -77,12 +85,13 @@ public class RvApp : ExternalApplication
_ = new TabManagerApp(Application);
_ = new FamilyApp(Application, UiApplication);
if (Properties.Settings.Default.AutoSave)
if (Properties.Settings.Default.IsActiveAutoSave)
{
Variables.Timer.Elapsed -= OnTimedEvent;
Variables.Timer.Elapsed += OnTimedEvent;
Variables.Timer.Interval = Properties.Settings.Default.AutoSaveIntervalTime * 60 * 1000;
Variables.Timer.Start();
var interval = Properties.Settings.Default.AutoSaveIntervalTime * 60 * 1000;
saveTimer.Interval = interval;
saveTimer.Elapsed -= OnTimedEvent;
saveTimer.Elapsed += OnTimedEvent;
saveTimer.Start();
}
}
@@ -213,16 +222,29 @@ public class RvApp : ExternalApplication
"将可以翻转工作平面的族实例,翻转其工作平面"
);
var rotateInstance = UIAssist.NewPushButtonData<RotateInstanceCmd>(
"旋转实例",
"旋转管件实例",
Resources.rotate_instance_32px,
Resources.rotate_instance_16px,
"将族实例根据已连接的情况进行旋转"
"将管件族实例根据已连接的情况进行旋转"
);
var addInsulation = UIAssist.NewPushButtonData<AddInsulationCmd>(
"保温层",
Resources.add_insulation_32px,
Resources.add_insulation_16px,
"对水管和风管添加保温层"
);
var arrangeMEPCurve = UIAssist.NewPushButtonData<ArrangeMEPCurveCmd>(
"整理管线",
Resources.arrange_mep_32px,
Resources.arrange_mep_16px,
"根据相对位置排布管线"
);
panel.AddStackedItems(standMepCurve, anyConnect, moveConnect);
panel.AddStackedItems(correctSlope, moveMEP, bloomConnector);
panel.AddStackedItems(breakMepCurveBtn, disConnect, terminalConnect);
panel.AddStackedItems(flipWorkplane, rotateInstance);
panel.AddStackedItems(addInsulation, arrangeMEPCurve);
panel.AddStackedItems(clashResolve, clashReport, headroomCheck);
}

View File

@@ -9,8 +9,7 @@ namespace Sai.RvKits;
public static class Variables
{
public static string AddInPath => Assembly.GetExecutingAssembly().Location;
public static string AddInPath { get; } = Assembly.GetExecutingAssembly().Location;
// public static IntPtr RevitWindowPtr
//{
// [DebuggerStepThrough]
@@ -18,9 +17,9 @@ public static class Variables
//}
//public static readonly string DllPath = typeof(Variables).Assembly.Location;
public static string DirAssembly => Path.GetDirectoryName(AddInPath);
public static string FamilyFolder => Path.Combine(DirAssembly, "Libraries");
public static DockablePaneId PaneId => new(new Guid(Properties.Settings.Default.DockPaneGuid));
public static System.Timers.Timer Timer => new();
public static string DirAssembly { get; } = Path.GetDirectoryName(AddInPath);
public static string FamilyFolder { get; } = Path.Combine(DirAssembly, "Libraries");
public static DockablePaneId PaneId { get; } = new(new Guid(Properties.Settings.Default.DockPaneGuid));
public static System.Timers.Timer AutoSaveTimer { get; } = new() { Enabled = true };
public static SnackbarPresenter SnackbarPresenter { get; set; }
}

View File

@@ -54,7 +54,7 @@ public partial class MessageViewModel : ObservableObject
}
var ids = new List<ElementId> { model.Element.Id };
//UiDocument.ActiveView.IsolateElementTemporary(model.Element.ViewId);
//UiDocument.ActiveView.IsolateElementTemporary(model.ElementToMove.ViewId);
showElementsSectionBox.Raise(
_ =>
{