diff --git a/.idea/.idea.Sai.RvKits/.idea/vcs.xml b/.idea/.idea.Sai.RvKits/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.Sai.RvKits/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ConsoleApp/ConsoleApp.csproj b/ConsoleApp/ConsoleApp.csproj
index 21403a2..7aee2c3 100644
--- a/ConsoleApp/ConsoleApp.csproj
+++ b/ConsoleApp/ConsoleApp.csproj
@@ -1,15 +1,17 @@
- net472
+ net48
Exe
false
+
+
\ No newline at end of file
diff --git a/ConsoleApp/Program.cs b/ConsoleApp/Program.cs
index 87dd594..823dc63 100644
--- a/ConsoleApp/Program.cs
+++ b/ConsoleApp/Program.cs
@@ -1,26 +1,128 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using ACadSharp.Entities;
+
using CommunityToolkit.Diagnostics;
+using CSMath;
+
+using OpenAI.Chat;
+
namespace ConsoleApp
{
internal class Program
{
static void Main(string[] args)
{
- string str = "";
- double a = 10.0;
+ //TEST();
+
+ ChatClient client = new ChatClient("gpt-4o", Environment.GetEnvironmentVariable("OPEN_API_KEY"));
+ ChatCompletion completion = client.CompleteChat("say 'this is a test.'");
+ Console.WriteLine($"[ASSISTANT]:{completion.Content[0].Text}");
+ }
+
+ private static void TEST()
+ {
+ var str = "";
+ var a = 10.0;
double b = 100;
Debug.Assert(a == b);
//确保str满足条件才能继续执行,不满足即抛出异常
Guard.IsNotNullOrEmpty(str);//抛出异常
- Guard.IsLessThan(a,b);
+ Guard.IsLessThan(a, b);
+ }
+
+ public void ReadCAD()
+ {
+ var file = @"D:\Users\Zhanggg\Desktop\Drawing1.dwg";
+ var cad = new ACadSharp.IO.DwgReader(file).Read();
+ var polylines = cad.Entities.OfType().Where(l => l.Layer.Name == "RQ");
+ var sizes = cad.Entities.OfType().Where(t => t.Layer.Name == "RQ");
+ var entities = cad.Entities.OfType().Where(i => i.Layer.Name == "0" || i.Layer.Name == "RQ" || i.Layer.Name == "GAS" || i.Layer.Name == "燃具");
+ var sb = new StringBuilder();
+ sb.AppendLine("多段线");
+ foreach (var line in polylines)
+ {
+ var first = line.Vertices.First();
+ var last = line.Vertices.Last();
+ sb.AppendLine($"起点:{first.Location};终点:{last.Location}");
+ }
+ foreach (var insert in entities)
+ {
+ if (insert.Block.Name == "立管0")
+ {
+ var temp = double.MaxValue;
+ string t = default;
+ foreach (var item in sizes)
+ {
+ var current = item.InsertPoint.DistanceFrom(insert.InsertPoint);
+ if (current < temp)
+ {
+ temp = current;
+ t = item.Value;
+ }
+ }
+ }
+ //盲板
+ else if (insert.Block.Name == "盲板")
+ {
+
+ }
+ //旋塞阀
+ else if (insert.Block.Name.Contains("旋塞"))
+ {
+
+ }
+ //商业预留,法兰球阀
+ else if (insert.Block.Name.Contains("法兰球阀"))
+ {
+
+ }
+ //锁闭型螺纹铜球阀
+ else if (insert.Block.Name.Contains("户内阀"))
+ {
+
+ }
+ //燃气表
+ else if (insert.Block.Name == "计量表")
+ {
+
+ }
+ //自闭阀
+ else if (insert.Block.Name == "自闭阀")
+ {
+
+ }
+ //热水器
+ else if (insert.Block.Name == "RSQ")
+ {
+
+ }
+ //燃气灶
+ else if (insert.Block.Name == "燃气灶")
+ {
+
+ }
+ //球阀+丝堵
+ else if (insert.Block.Name.Contains("丝堵"))
+ {
+
+ }
+
+ sb.AppendLine($"图层名:{insert.Layer.Name};图块名:{insert.Block.Name};插入点:{insert.InsertPoint}");
+ }
+ File.WriteAllText(@"D:\Users\Zhanggg\Desktop\Drawing1.dwg" + ".txt", sb.ToString(), Encoding.UTF8);
+ //foreach (var insert in entities)
+ //{
+ // var blocks = insert.Block.Entities.OfType().Where(d=>d.Text.Contains("52D"));
+ //}
}
}
}
diff --git a/RvAddinTest/CorrectSlope.cs b/RvAddinTest/CorrectSlope.cs
new file mode 100644
index 0000000..3e3c8f3
--- /dev/null
+++ b/RvAddinTest/CorrectSlope.cs
@@ -0,0 +1,58 @@
+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 Nice3point.Revit.Toolkit.External;
+using Nice3point.Revit.Toolkit.Utils;
+
+using Sai.Toolkit.Revit.Assist;
+
+namespace RvAddinTest;
+[Transaction(TransactionMode.Manual)]
+[Regeneration(RegenerationOption.Manual)]
+internal class CorrectSlope : ExternalCommand
+{
+ public override void Execute()
+ {
+ var ids = UiDocument.Selection.GetElementIds();
+ Document.Modify(
+ set => set.Transaction).Commit((doc, t) =>
+ {
+ foreach (var id in ids)
+ {
+ var elem = Document.GetElement(id);
+ if (elem is MEPCurve mep)
+ {
+ var loc = mep.GetLocCurve() as Line;
+ var x = loc.Direction.X;
+ var y = loc.Direction.Y;
+ var z = loc.Direction.Z;
+ if (Math.Abs(loc.Direction.X) > 0 && Math.Abs(loc.Direction.X) < 10E-5)
+ {
+ x = 0;
+ }
+ if (Math.Abs(loc.Direction.Y) > 0 && Math.Abs(loc.Direction.Y) < 10E-5)
+ {
+ y = 0;
+ }
+ if (Math.Abs(loc.Direction.Z) > 0 && Math.Abs(loc.Direction.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;
+ }
+ }
+ });
+
+ }
+}
diff --git a/RvAddinTest/FluentWindow.xaml b/RvAddinTest/FluentWindow.xaml
new file mode 100644
index 0000000..934d29d
--- /dev/null
+++ b/RvAddinTest/FluentWindow.xaml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RvAddinTest/FluentWindow.xaml.cs b/RvAddinTest/FluentWindow.xaml.cs
new file mode 100644
index 0000000..ce99523
--- /dev/null
+++ b/RvAddinTest/FluentWindow.xaml.cs
@@ -0,0 +1,47 @@
+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;
+
+using Wpf.Ui;
+using Wpf.Ui.Appearance;
+
+namespace RvAddinTest;
+///
+/// FluentWindow.xaml 的交互逻辑
+///
+public partial class FluentWindow
+{
+ public FluentWindow()
+ {
+ 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);
+ }
+ }
+}
diff --git a/RvAddinTest/GASInstancesCreator.cs b/RvAddinTest/GASInstancesCreator.cs
new file mode 100644
index 0000000..326f7f1
--- /dev/null
+++ b/RvAddinTest/GASInstancesCreator.cs
@@ -0,0 +1,320 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Documents;
+
+using ACadSharp.Entities;
+
+using Autodesk.Revit.Attributes;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Selection;
+
+using CSMath;
+using XYZ = Autodesk.Revit.DB.XYZ;
+using Nice3point.Revit.Toolkit.External;
+using Nice3point.Revit.Toolkit.Options;
+using Nice3point.Revit.Toolkit.Utils;
+using Line = Autodesk.Revit.DB.Line;
+using Autodesk.Revit.DB.Plumbing;
+using System.IO;
+using System.Collections.ObjectModel;
+using Sai.Toolkit.Revit.Assist;
+using Microsoft.Win32;
+using Sai.Toolkit.Core.Helpers;
+
+namespace RvAddinTest
+{
+ [Transaction(TransactionMode.Manual)]
+ [Regeneration(RegenerationOption.Manual)]
+ public class GASInstancesCreator : ExternalCommand
+ {
+ private XYZ XYToRevitXYZ(CSMath.XY point)
+ {
+ return new XYZ(point.X, point.Y, 0) / 304.8;
+ }
+
+ private XYZ XYZToRevitXYZ(CSMath.XYZ point)
+ {
+ return new XYZ(point.X, point.Y, 0) / 304.8;
+ }
+
+ public override void Execute()
+ {
+ //var id = UiDocument.Selection.GetElementIds().First();
+ //var elem = Document.GetElement(id) as FamilyInstance;
+ //var point = elem.GetLocXYZ();
+
+ //var pipes = new FilteredElementCollector(Document).OfClass(typeof(Pipe)).Cast();
+ //Pipe p;
+ //foreach (var pipe in pipes)
+ //{
+ // var line = pipe.GetLocCurve() as Line;
+ // var lineOrigin = line.Origin.Flatten();
+ // var temp = double.MaxValue;
+ // if (line.Direction == XYZ.BasisZ)
+ // {
+ // var dis = point.DistanceTo(lineOrigin);
+ // if (dis < temp)
+ // {
+ // p = pipe;
+ // }
+ // }
+ //}
+ //var conns = elem.MEPModel.ConnectorManager.UnusedConnectors.OfType().FirstOrDefault();
+ var dialog = new OpenFileDialog
+ {
+ Filter = "dwg文件(*.dwg)|*.dwg"
+ };
+ if (dialog.ShowDialog()==true)
+ {
+ var file = dialog.FileName;
+ var cad = new ACadSharp.IO.DwgReader(file).Read();
+ var polylines = cad.Entities.OfType().Where(l => l.Layer.Name == "RQ" && l.Color.Equals(ACadSharp.Color.ByLayer));
+ var sizes = cad.Entities.OfType().Where(t => t.Layer.Name == "RQ" && t.Value.Contains("D"));
+ var entities = cad.Entities.OfType().Where(i => i.Layer.Name == "0" || i.Layer.Name == "RQ" || i.Layer.Name == "GAS" || i.Layer.Name == "燃具");
+ Create(polylines, sizes, entities);
+ }
+ }
+
+ private void Create(IEnumerable polylines, IEnumerable sizes, IEnumerable entities)
+ {
+ var pipeType = new FilteredElementCollector(Document).OfClass(typeof(PipeType))
+ .FirstOrDefault(pt => pt.Name == "低压燃气管道");
+ var systemType = new FilteredElementCollector(Document).OfClass(typeof(PipingSystemType))
+ .FirstOrDefault(pt => pt.Name == "低压燃气系统");
+
+ var mb = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+ .FirstOrDefault(pt => pt.Name.Contains("盲板")) as FamilySymbol;
+ var xs = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+ .FirstOrDefault(pt => pt.Name.Contains("旋塞")) as FamilySymbol;
+ var flqf = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name.Contains("法兰球阀")) as FamilySymbol;
+ var tqf = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name.Contains("铜制球阀")) as FamilySymbol;
+ var rqb = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name.Contains("燃气表")) as FamilySymbol;
+ var zbf = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name.Contains("自闭阀")) as FamilySymbol;
+ var rsq = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name.Contains("热水器")) as FamilySymbol;
+ var rqz = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name.Contains("燃气灶")) as FamilySymbol;
+ var qf = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name == "球阀") as FamilySymbol;
+ var sd = new FilteredElementCollector(Document).OfClass(typeof(FamilySymbol))
+.FirstOrDefault(pt => pt.Name == "丝堵") as FamilySymbol;
+ var sb = new StringBuilder();
+ using (var ts = new Transaction(Document, "翻模"))
+ {
+ ts.Start();
+
+ foreach (var line in polylines)
+ {
+ var tempDistance = double.MaxValue;
+ TextEntity textNoteNearest = null;
+ var vector = XYZ.BasisX;
+ var locXY = line.Vertices.FirstOrDefault().Location;
+ var firstPoint = XYToRevitXYZ(locXY);
+ var lastPoint = XYToRevitXYZ(line.Vertices.LastOrDefault().Location);
+ if (firstPoint.DistanceTo(lastPoint) 0)
+ {
+ File.WriteAllText(@"D:\Users\Zhanggg\Desktop\Errors.txt", sb.ToString(), Encoding.UTF8);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/RvAddinTest/InstancesCreator.cs b/RvAddinTest/InstancesCreator.cs
new file mode 100644
index 0000000..93b8762
--- /dev/null
+++ b/RvAddinTest/InstancesCreator.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+
+using Autodesk.Revit.Attributes;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Selection;
+
+using Nice3point.Revit.Toolkit.External;
+using Nice3point.Revit.Toolkit.Options;
+using Nice3point.Revit.Toolkit.Utils;
+
+namespace RvAddinTest
+{
+ [Transaction(TransactionMode.Manual)]
+ [Regeneration(RegenerationOption.Manual)]
+ public class InstancesCreator : ExternalCommand
+ {
+ public override void Execute()
+ {
+ var doc = Document;
+ var uidoc = UiDocument;
+ //var uidoc = uiApplication.ActiveUIDocument;
+ //var doc = uidoc.Document;
+ var ids = uidoc.Selection.GetElementIds();
+
+ using (Transaction ts = new(doc, "旋转"))
+ {
+ ts.Start();
+ var collector = new FilteredElementCollector(doc, doc.ActiveView.Id).OfClass(typeof(TextNote));
+ foreach (var id in ids)
+ {
+ var elem = doc.GetElement(id);
+ var loc = elem.Location as LocationPoint;
+ var point = loc.Point;
+ XYZ flattenXY = new(loc.Point.X, loc.Point.Y, 0);
+ var tempDistance = double.MaxValue;
+ TextNote textNoteNearest = null;
+ var vector = XYZ.BasisX;
+ foreach (var element in collector)
+ {
+ var textNote = element as TextNote;
+ XYZ flattenCoord = new(textNote.Coord.X, textNote.Coord.Y, 0);
+ var currentDistance = flattenCoord.DistanceTo(flattenXY);
+ if (currentDistance < tempDistance)
+ {
+ tempDistance = currentDistance;
+ textNoteNearest = textNote;
+ vector = textNote.BaseDirection;
+ }
+ }
+ if (textNoteNearest == null)
+ {
+ continue;
+ }
+ var radian = XYZ.BasisX.AngleTo(vector);
+
+ var crossProduct = XYZ.BasisX.CrossProduct(textNoteNearest.BaseDirection).Normalize();
+ if (Math.Abs(radian - Math.PI) < 10E-6)
+ {
+ ElementTransformUtils.RotateElement(doc, id, Line.CreateUnbound(point, XYZ.BasisZ), Math.PI);
+ }
+ if (crossProduct.IsAlmostEqualTo(XYZ.BasisZ))
+ {
+ ElementTransformUtils.RotateElement(doc, id, Line.CreateUnbound(point, XYZ.BasisZ), radian);
+ }
+ if (crossProduct.IsAlmostEqualTo(-XYZ.BasisZ))
+ {
+ ElementTransformUtils.RotateElement(doc, id, Line.CreateUnbound(point, XYZ.BasisZ), 2 * Math.PI - radian);
+ }
+ }
+ ts.Commit();
+ }
+
+ //MainWindow window = new MainWindow(Document);
+ //window.ShowDialog();
+ }
+ }
+ public class InsertInfo
+ {
+
+ public string Name { get; set; }
+ public XYZ InsertPoint { get; set; }
+ public double Radian { get; set; }
+ public double Length { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/RvAddinTest/RvAddinTest.csproj b/RvAddinTest/RvAddinTest.csproj
index 0cb33b5..5455bd1 100644
--- a/RvAddinTest/RvAddinTest.csproj
+++ b/RvAddinTest/RvAddinTest.csproj
@@ -20,11 +20,11 @@
$(DefineConstants);REVIT2018
-
-
-
+
+
+
-
+
@@ -36,6 +36,7 @@
+
diff --git a/RvAddinTest/TempCmd.cs b/RvAddinTest/TempCmd.cs
new file mode 100644
index 0000000..548f82a
--- /dev/null
+++ b/RvAddinTest/TempCmd.cs
@@ -0,0 +1,89 @@
+using System;
+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;
+using Autodesk.Revit.UI.Selection;
+
+using CommunityToolkit.Mvvm.DependencyInjection;
+
+using Nice3point.Revit.Toolkit.External;
+
+using Sai.Toolkit.Revit.Assist;
+using Sai.Toolkit.Revit.Helpers;
+
+namespace RvAddinTest;
+[Transaction(TransactionMode.Manual)]
+[Regeneration(RegenerationOption.Manual)]
+public class TempCmd : ExternalCommand
+{
+ public override void Execute()
+ {
+ var elemIds = Document.OfClass().Cast().Where(p => p.Diameter == 50 / 304.8 && !(p.GetLocCurve() as Line).Direction.IsParallelTo(XYZ.BasisZ)).Select(p => p.Id).ToList();
+ //var elementIds = uidoc.Selection.GetElementIds();
+ //var elementIds = new FilteredElementCollector(Document).OfClass(typeof(FamilyInstance)).Where(ins => ins.Name == "DN15").Select(ins => ins.Id).ToList();
+ //using (var ts = new Transaction(Document, "Temp"))
+ //{
+ // ts.Start();
+ //doc.Delete(elementIds);
+ //foreach (var id in elementIds)
+ //{
+ // var elem = Document.GetElement(id) as FamilyInstance;
+ // var p = elem.GetLocXYZ();
+ // //ElementTransformUtils.MoveElement(Document,id,-elem.HandOrientation*125/304.8);
+ // //Document.Regenerate();
+ // //ElementTransformUtils.MoveElement(Document, id,-elem.FacingOrientation*95/304.8);
+ // ElementTransformUtils.RotateElement(
+ // Document,
+ // id,
+ // Line.CreateUnbound(p, XYZ.BasisZ),
+ // Math.PI / 2);
+ //}
+ //内衬
+ //var e = InsulationLiningBase.GetLiningIds(doc, elem.Id);
+ //保温
+ //var p = InsulationLiningBase.GetInsulationIds(doc, elem.Id);
+ //var uidoc = UiApplication.ActiveUIDocument;
+ //var doc = uidoc.Document;
+ //var reference = uidoc.Selection.PickObject(ObjectType.Element);
+ //var elem = doc.GetElement(reference);
+ //var id = InsulationLiningBase.GetInsulationIds(Document, elem.Id).FirstOrDefault();
+ // ts.Commit();
+ //}
+ Document.Invoke(
+ ts =>
+ {
+ try
+ {
+ UiDocument.Selection.SetElementIds(elemIds);
+
+ //ElementTransformUtils.MoveElements(Document, elemIds, XYZ.BasisZ * 200 / 304.8);
+
+ //foreach (var elem in elems)
+ //{
+ // elem.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(50 / 304.8);
+ //}
+ }
+ catch (Autodesk.Revit.Exceptions.OperationCanceledException)
+ {
+ }
+ }, "CMD");
+ }
+ public class ArrangeElement
+ {
+ public XYZ Translation { get; set; }
+
+ public int Index { get; set; }
+
+ public Element ElementToMove { get; set; }
+
+ ///
+ /// 与基准元素的间距及方向向量
+ ///
+ public XYZ HorizonDistanceVector { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/Sai.RvKits.slnx b/Sai.RvKits.slnx
new file mode 100644
index 0000000..0f3ec46
--- /dev/null
+++ b/Sai.RvKits.slnx
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sai.RvKits/App.config b/Sai.RvKits/App.config
index 21c1b28..0618b6f 100644
--- a/Sai.RvKits/App.config
+++ b/Sai.RvKits/App.config
@@ -56,17 +56,11 @@
2ab776b4-b3fc-4810-8f44-ab5f1c9f5fa8
-
- True
-
- 10
-
-
- False
+ 5
- False
+ True
diff --git a/Sai.RvKits/CadSharperUtil.cs b/Sai.RvKits/DWGAssist.cs
similarity index 59%
rename from Sai.RvKits/CadSharperUtil.cs
rename to Sai.RvKits/DWGAssist.cs
index e2dc689..c69222c 100644
--- a/Sai.RvKits/CadSharperUtil.cs
+++ b/Sai.RvKits/DWGAssist.cs
@@ -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) { }
///
@@ -20,10 +18,8 @@ public class CadSharperUtil(string path)
///
///
///
- public static CadObjectCollection GetAllEntitiesInModel(string file)
+ public static CadObjectCollection 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;
}
///
- /// 获取dwg所在的路径
+ /// 获取模型中的所有实体
///
- ///
+ ///
///
- public static string GetDwgPath(ImportInstance dwg)
+ public static CadObjectCollection 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> GetTextByLayer(ImportInstance dwg, string textLayerName)
{
var keyValuePairs = new List>();
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) { }
///
/// 读取dxf文件
///
- /// dxf file path
+ /// dxf filePath path
///
- public static void ReadDxf(string file, Action 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();
}
///
- /// Read a dwg file
+ /// 读取dxg文件
///
- /// dwg file path
+ /// dwg filePath path
///
- public static void ReadDwg(string file, Action 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();
}
///
/// 写一个ascii dxf文件
///
- ///
+ ///
///
- 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);
}
///
/// 编写一个二进制的dxf文件
///
- ///
+ ///
///
- 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);
}
///
- /// 获取模型中的所有块
+ /// 获取模型中的同名所有块
///
///
///
///
- public static IEnumerable GetInsertEntities(string file, string blockName)
+ public static IEnumerable GetInsertEntities(this ACadSharp.CadDocument doc, string blockName)
{
- var doc = ACadSharp.IO.DwgReader.Read(file);
-
//获取正在使用你要找的块的插入实例
return doc.Entities.OfType().Where(e => e.Block.Name == blockName);
}
diff --git a/Sai.RvKits/ModelManager/ModelCheckViewModel.cs b/Sai.RvKits/ModelManager/ModelCheckViewModel.cs
index cb76368..da55694 100644
--- a/Sai.RvKits/ModelManager/ModelCheckViewModel.cs
+++ b/Sai.RvKits/ModelManager/ModelCheckViewModel.cs
@@ -600,7 +600,7 @@ public partial class ModelCheckViewModel : ObservableObject
}
List 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)
diff --git a/Sai.RvKits/Properties/Resources.Designer.cs b/Sai.RvKits/Properties/Resources.Designer.cs
index 8246498..1014542 100644
--- a/Sai.RvKits/Properties/Resources.Designer.cs
+++ b/Sai.RvKits/Properties/Resources.Designer.cs
@@ -60,6 +60,26 @@ namespace Sai.RvKits.Properties {
}
}
+ ///
+ /// 查找 System.Drawing.Bitmap 类型的本地化资源。
+ ///
+ internal static System.Drawing.Bitmap add_insulation_16px {
+ get {
+ object obj = ResourceManager.GetObject("add_insulation_16px", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// 查找 System.Drawing.Bitmap 类型的本地化资源。
+ ///
+ internal static System.Drawing.Bitmap add_insulation_32px {
+ get {
+ object obj = ResourceManager.GetObject("add_insulation_32px", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
///
@@ -190,6 +210,46 @@ namespace Sai.RvKits.Properties {
}
}
+ ///
+ /// 查找 System.Drawing.Bitmap 类型的本地化资源。
+ ///
+ internal static System.Drawing.Bitmap arrange_mep_16px {
+ get {
+ object obj = ResourceManager.GetObject("arrange_mep_16px", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// 查找 System.Drawing.Bitmap 类型的本地化资源。
+ ///
+ internal static System.Drawing.Bitmap arrange_mep_16px1 {
+ get {
+ object obj = ResourceManager.GetObject("arrange_mep_16px1", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// 查找 System.Drawing.Bitmap 类型的本地化资源。
+ ///
+ internal static System.Drawing.Bitmap arrange_mep_32px {
+ get {
+ object obj = ResourceManager.GetObject("arrange_mep_32px", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// 查找 System.Drawing.Bitmap 类型的本地化资源。
+ ///
+ internal static System.Drawing.Bitmap arrange_mep_32px1 {
+ get {
+ object obj = ResourceManager.GetObject("arrange_mep_32px1", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
///
diff --git a/Sai.RvKits/Properties/Resources.resx b/Sai.RvKits/Properties/Resources.resx
index b5770f4..6f2517d 100644
--- a/Sai.RvKits/Properties/Resources.resx
+++ b/Sai.RvKits/Properties/Resources.resx
@@ -280,6 +280,12 @@
..\Resources\rotate_instance_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\arrange_mep_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\arrange_mep_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\flip_workplane_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -487,4 +493,16 @@
..\Resources\top_elev_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\add_insulation_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\add_insulation_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\arrange_mep_16px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\arrange_mep_32px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
\ No newline at end of file
diff --git a/Sai.RvKits/Properties/Settings.Designer.cs b/Sai.RvKits/Properties/Settings.Designer.cs
index 0361e67..83e90e3 100644
--- a/Sai.RvKits/Properties/Settings.Designer.cs
+++ b/Sai.RvKits/Properties/Settings.Designer.cs
@@ -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"]));
diff --git a/Sai.RvKits/Properties/Settings.settings b/Sai.RvKits/Properties/Settings.settings
index 7e1c184..4e2e1aa 100644
--- a/Sai.RvKits/Properties/Settings.settings
+++ b/Sai.RvKits/Properties/Settings.settings
@@ -29,17 +29,11 @@
2ab776b4-b3fc-4810-8f44-ab5f1c9f5fa8
-
- True
-
- 10
-
-
- False
+ 5
- False
+ True
\ No newline at end of file
diff --git a/Sai.RvKits/Resources/add_insulation_16px.png b/Sai.RvKits/Resources/add_insulation_16px.png
new file mode 100644
index 0000000..147ded3
Binary files /dev/null and b/Sai.RvKits/Resources/add_insulation_16px.png differ
diff --git a/Sai.RvKits/Resources/add_insulation_32px.png b/Sai.RvKits/Resources/add_insulation_32px.png
new file mode 100644
index 0000000..10a8029
Binary files /dev/null and b/Sai.RvKits/Resources/add_insulation_32px.png differ
diff --git a/Sai.RvKits/Resources/arrange_mep_16px.png b/Sai.RvKits/Resources/arrange_mep_16px.png
new file mode 100644
index 0000000..28de526
Binary files /dev/null and b/Sai.RvKits/Resources/arrange_mep_16px.png differ
diff --git a/Sai.RvKits/Resources/arrange_mep_32px.png b/Sai.RvKits/Resources/arrange_mep_32px.png
new file mode 100644
index 0000000..6072d67
Binary files /dev/null and b/Sai.RvKits/Resources/arrange_mep_32px.png differ
diff --git a/Sai.RvKits/RvCommon/AutoSaveCmd.cs b/Sai.RvKits/RvCommon/AutoSaveCmd.cs
index 6abfd80..467b958 100644
--- a/Sai.RvKits/RvCommon/AutoSaveCmd.cs
+++ b/Sai.RvKits/RvCommon/AutoSaveCmd.cs
@@ -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;
}
diff --git a/Sai.RvKits/RvCommon/AutoSaveViewModel.cs b/Sai.RvKits/RvCommon/AutoSaveViewModel.cs
index 65c6543..7d12f39 100644
--- a/Sai.RvKits/RvCommon/AutoSaveViewModel.cs
+++ b/Sai.RvKits/RvCommon/AutoSaveViewModel.cs
@@ -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;
+ }
}
\ No newline at end of file
diff --git a/Sai.RvKits/RvCommon/InstanceCreatorViewModel.cs b/Sai.RvKits/RvCommon/InstanceCreatorViewModel.cs
index dc3a24c..f9d68dd 100644
--- a/Sai.RvKits/RvCommon/InstanceCreatorViewModel.cs
+++ b/Sai.RvKits/RvCommon/InstanceCreatorViewModel.cs
@@ -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);
diff --git a/Sai.RvKits/RvCommon/ModifyModelParams.cs b/Sai.RvKits/RvCommon/ModifyModelParams.cs
index e0a71ac..1de8519 100644
--- a/Sai.RvKits/RvCommon/ModifyModelParams.cs
+++ b/Sai.RvKits/RvCommon/ModifyModelParams.cs
@@ -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(_ =>
{
diff --git a/Sai.RvKits/RvCommon/PipesCreatorViewModel.cs b/Sai.RvKits/RvCommon/PipesCreatorViewModel.cs
index 596e25f..397d987 100644
--- a/Sai.RvKits/RvCommon/PipesCreatorViewModel.cs
+++ b/Sai.RvKits/RvCommon/PipesCreatorViewModel.cs
@@ -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().Where(e => e.Layer.Name == layerName).ToList();
diff --git a/Sai.RvKits/RvFamily/FamilyProcessorViewModel.cs b/Sai.RvKits/RvFamily/FamilyProcessorViewModel.cs
index 1cf5273..1c3a207 100644
--- a/Sai.RvKits/RvFamily/FamilyProcessorViewModel.cs
+++ b/Sai.RvKits/RvFamily/FamilyProcessorViewModel.cs
@@ -111,7 +111,7 @@ public partial class FamilyProcessorViewModel : ObservableObject
// var familySymbolCollector = SourceDoc.OfClass().Cast().ToList();
- // //ErrorModels dimensionTypeId = (from Element i in new FilteredElementCollector(sourceDoc).OfClass(typeof(DimensionType)) select i.ViewId).ToList();
+ // //ErrorModels 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));
diff --git a/Sai.RvKits/RvFamily/RenameTypeViewModel.cs b/Sai.RvKits/RvFamily/RenameTypeViewModel.cs
index 56929b1..c841939 100644
--- a/Sai.RvKits/RvFamily/RenameTypeViewModel.cs
+++ b/Sai.RvKits/RvFamily/RenameTypeViewModel.cs
@@ -40,7 +40,7 @@ public partial class RenameTypeViewModel : ObservableObject
[ObservableProperty]
private bool isRunning;
-
+
///
/// 选中正在使用中的条目
///
@@ -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);
diff --git a/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/ElementModel.cs b/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/ElementModel.cs
index 0a1c081..6d43f81 100644
--- a/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/ElementModel.cs
+++ b/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/ElementModel.cs
@@ -3,7 +3,7 @@ using System.Xml.Serialization;
namespace Sai.Toolkit.Core.LandXMLData;
-[XmlType("Element")]
+[XmlType("ElementToMove")]
[Serializable]
public class ElementModel : ShapeModel
{
diff --git a/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidCategory.cs b/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidCategory.cs
index a6b832f..7aa8eba 100644
--- a/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidCategory.cs
+++ b/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidCategory.cs
@@ -15,7 +15,7 @@ namespace Sai.Toolkit.Core.LandXMLData
[XmlAttribute("name")]
public string Name;
- [XmlElement("Element")]
+ [XmlElement("ElementToMove")]
public List Solids;
}
}
diff --git a/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidModel.cs b/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidModel.cs
index 0611364..8408997 100644
--- a/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidModel.cs
+++ b/Sai.RvKits/RvIndependent/MetroGauges/LandXMLData/SolidModel.cs
@@ -12,7 +12,7 @@ namespace Sai.Toolkit.Core.LandXMLData
Elements = new List();
}
- [XmlElement("Element")]
+ [XmlElement("ElementToMove")]
public List Elements;
[XmlAttribute("name")]
diff --git a/Sai.RvKits/RvIndependent/NetworkCreator/ExcelData.cs b/Sai.RvKits/RvIndependent/NetworkCreator/ExcelData.cs
index f08891d..bd6b12f 100644
--- a/Sai.RvKits/RvIndependent/NetworkCreator/ExcelData.cs
+++ b/Sai.RvKits/RvIndependent/NetworkCreator/ExcelData.cs
@@ -6,7 +6,7 @@ namespace Sai.RvKits.RvIndependent
{
public ExcelData(ExcelWorksheet sheet)
{
- DataRows = new List();
+ 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), //管内底
diff --git a/Sai.RvKits/RvMEP/AddInsulationCmd.cs b/Sai.RvKits/RvMEP/AddInsulationCmd.cs
new file mode 100644
index 0000000..4ef913b
--- /dev/null
+++ b/Sai.RvKits/RvMEP/AddInsulationCmd.cs
@@ -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(new AddInsulationViewModel(Document));
+ }
+}
\ No newline at end of file
diff --git a/Sai.RvKits/RvMEP/AddInsulationView.xaml b/Sai.RvKits/RvMEP/AddInsulationView.xaml
new file mode 100644
index 0000000..1843b7d
--- /dev/null
+++ b/Sai.RvKits/RvMEP/AddInsulationView.xaml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sai.RvKits/RvMEP/AddInsulationView.xaml.cs b/Sai.RvKits/RvMEP/AddInsulationView.xaml.cs
new file mode 100644
index 0000000..36ccca5
--- /dev/null
+++ b/Sai.RvKits/RvMEP/AddInsulationView.xaml.cs
@@ -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;
+///
+/// AddInsulationView.xaml 的交互逻辑
+///
+public partial class AddInsulationView
+{
+ public AddInsulationView()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/Sai.RvKits/RvMEP/AddInsulationViewModel.cs b/Sai.RvKits/RvMEP/AddInsulationViewModel.cs
new file mode 100644
index 0000000..b058673
--- /dev/null
+++ b/Sai.RvKits/RvMEP/AddInsulationViewModel.cs
@@ -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;
+ ///
+ /// 定义的风管保温层
+ ///
+ [ObservableProperty]
+ private InsulationItem ductInsulationItem;
+ ///
+ /// 定义的管道保温层
+ ///
+ [ObservableProperty]
+ private List pipeInsulationItems;
+ ///
+ /// 选中的风管系统类型
+ ///
+ [ObservableProperty]
+ [NotifyCanExecuteChangedFor(nameof(AddInsulationCommand))]
+
+ private MechanicalSystemType selectedDuctSystem;
+ ///
+ /// 选中的管道系统类型
+ ///
+ [ObservableProperty]
+ [NotifyCanExecuteChangedFor(nameof(AddInsulationCommand))]
+ private PipingSystemType selectedPipingSystemType;
+
+ public AddInsulationViewModel(Document doc)
+ {
+ PipingSystemTypes = doc.OfClass().Cast().ToList();
+ DuctSystemTypes = doc.OfClass().Cast().ToList();
+ DuctInsulationTypes = doc.OfClass().Cast().ToList();
+ PipeInsulationTypes = doc.OfClass().Cast().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().Cast();
+
+ 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().Cast();
+
+ 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);
+
+ ///
+ /// 所有风管保温层类型
+ ///
+ public List DuctInsulationTypes { get; set; }
+ ///
+ /// 所有风管系统类型
+ ///
+ public List DuctSystemTypes { get; set; }
+
+ ///
+ /// 所有管道保温层类型
+ ///
+ public List PipeInsulationTypes { get; set; }
+
+ ///
+ /// 所有管道系统类型
+ ///
+ public List PipingSystemTypes { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Sai.RvKits/RvMEP/AnyConnectCmd.cs b/Sai.RvKits/RvMEP/AnyConnectCmd.cs
index c02ea82..d7ce7eb 100644
--- a/Sai.RvKits/RvMEP/AnyConnectCmd.cs
+++ b/Sai.RvKits/RvMEP/AnyConnectCmd.cs
@@ -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()
diff --git a/Sai.RvKits/RvMEP/AnyConnectViewModel.cs b/Sai.RvKits/RvMEP/AnyConnectViewModel.cs
index 7df31e7..d6c2eff 100644
--- a/Sai.RvKits/RvMEP/AnyConnectViewModel.cs
+++ b/Sai.RvKits/RvMEP/AnyConnectViewModel.cs
@@ -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(
diff --git a/Sai.RvKits/RvMEP/ArrangeMEPCurveCmd.cs b/Sai.RvKits/RvMEP/ArrangeMEPCurveCmd.cs
index b31a86b..f4d64f6 100644
--- a/Sai.RvKits/RvMEP/ArrangeMEPCurveCmd.cs
+++ b/Sai.RvKits/RvMEP/ArrangeMEPCurveCmd.cs
@@ -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(new ArrangeMEPCurveViewModel());
+ }
}
diff --git a/Sai.RvKits/RvMEP/ArrangeMEPCurveView.xaml b/Sai.RvKits/RvMEP/ArrangeMEPCurveView.xaml
new file mode 100644
index 0000000..506cbab
--- /dev/null
+++ b/Sai.RvKits/RvMEP/ArrangeMEPCurveView.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sai.RvKits/RvMEP/ArrangeMEPCurveView.xaml.cs b/Sai.RvKits/RvMEP/ArrangeMEPCurveView.xaml.cs
new file mode 100644
index 0000000..8540e8a
--- /dev/null
+++ b/Sai.RvKits/RvMEP/ArrangeMEPCurveView.xaml.cs
@@ -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;
+///
+/// ArrangeMEPCurveView.xaml 的交互逻辑
+///
+public partial class ArrangeMEPCurveView
+{
+ public ArrangeMEPCurveView()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/Sai.RvKits/RvMEP/ArrangeMEPCurveViewModel.cs b/Sai.RvKits/RvMEP/ArrangeMEPCurveViewModel.cs
new file mode 100644
index 0000000..1081053
--- /dev/null
+++ b/Sai.RvKits/RvMEP/ArrangeMEPCurveViewModel.cs
@@ -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 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()
+ .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()
+ .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; }
+ ///
+ /// 与基准元素的间距及方向向量
+ ///
+ public XYZ HorizonDistanceVector { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/Sai.RvKits/RvMEP/BloomConnectorCmd.cs b/Sai.RvKits/RvMEP/BloomConnectorCmd.cs
index 5bef594..7e33b3a 100644
--- a/Sai.RvKits/RvMEP/BloomConnectorCmd.cs
+++ b/Sai.RvKits/RvMEP/BloomConnectorCmd.cs
@@ -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(), "请选择族实例");
+ 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().FirstElementId();
var filteredElementCollector = Document.OfClass();
- 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:
diff --git a/Sai.RvKits/RvMEP/BreakMEPCurveCmd.cs b/Sai.RvKits/RvMEP/BreakMEPCurveCmd.cs
index 92bd394..6f8a006 100644
--- a/Sai.RvKits/RvMEP/BreakMEPCurveCmd.cs
+++ b/Sai.RvKits/RvMEP/BreakMEPCurveCmd.cs
@@ -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);
diff --git a/Sai.RvKits/RvMEP/CableLayoutCmd.cs b/Sai.RvKits/RvMEP/CableLayoutCmd.cs
index 8df6ee6..1c23218 100644
--- a/Sai.RvKits/RvMEP/CableLayoutCmd.cs
+++ b/Sai.RvKits/RvMEP/CableLayoutCmd.cs
@@ -28,7 +28,7 @@ public class CableLayoutCmd : ExternalCommand
Document.Invoke(
_ =>
{
- //Reference refer = UiDocument.Selection.PickObject(ObjectType.Element, new TypeSelectionFilter(), "请选择桥架");
+ //Reference refer = UiDocument.Selection.PickObject(ObjectType.ElementToMove, new TypeSelectionFilter(), "请选择桥架");
//var ct = UiDocument.Document.GetElement(refer) as CableTray;
var refer = UiDocument.Selection.PickObject(ObjectType.Element, new GenericFilter(), "请选择需要敷设桥架");
var ct = UiDocument.Document.GetElement(refer) as MEPCurve;
diff --git a/Sai.RvKits/RvMEP/ClashResolveViewModel.cs b/Sai.RvKits/RvMEP/ClashResolveViewModel.cs
index b3d1f24..b491529 100644
--- a/Sai.RvKits/RvMEP/ClashResolveViewModel.cs
+++ b/Sai.RvKits/RvMEP/ClashResolveViewModel.cs
@@ -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 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 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;
diff --git a/Sai.RvKits/RvMEP/CorrectMEPCurveSlopeCmd.cs b/Sai.RvKits/RvMEP/CorrectMEPCurveSlopeCmd.cs
index b2c1051..70217c1 100644
--- a/Sai.RvKits/RvMEP/CorrectMEPCurveSlopeCmd.cs
+++ b/Sai.RvKits/RvMEP/CorrectMEPCurveSlopeCmd.cs
@@ -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;
}
diff --git a/Sai.RvKits/RvMEP/HeadroomCheckCmd.cs b/Sai.RvKits/RvMEP/HeadroomCheckCmd.cs
index 0ffb490..e30eb59 100644
--- a/Sai.RvKits/RvMEP/HeadroomCheckCmd.cs
+++ b/Sai.RvKits/RvMEP/HeadroomCheckCmd.cs
@@ -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();
+ // .PickElementsByRectangle(new FuncFilter(e => e is ElementToMove, (_, _) => true))
+ // .OfType();
// 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();
// var clashFilter = new ElementIntersectsElementFilter(elem, false);
- // var elems = Document.OfCollector().WherePasses(clashFilter).OfType();
+ // var elems = Document.OfCollector().WherePasses(clashFilter).OfType();
// if (double.TryParse(inputMessage.InputContent, out var headroomValue))
// {
// CheckHeadroom(elems, headroomValue, 1000, 300);
diff --git a/Sai.RvKits/RvMEP/InsulationItem.cs b/Sai.RvKits/RvMEP/InsulationItem.cs
new file mode 100644
index 0000000..0846a49
--- /dev/null
+++ b/Sai.RvKits/RvMEP/InsulationItem.cs
@@ -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;
+}
diff --git a/Sai.RvKits/RvMEP/MoveConnectCmd.cs b/Sai.RvKits/RvMEP/MoveConnectCmd.cs
index 738583f..97e4103 100644
--- a/Sai.RvKits/RvMEP/MoveConnectCmd.cs
+++ b/Sai.RvKits/RvMEP/MoveConnectCmd.cs
@@ -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);
+ }
+ }
+ },
+ "移动连接"
+ );
+ }
}
diff --git a/Sai.RvKits/RvView/QuickViewSectionViewModel.cs b/Sai.RvKits/RvView/QuickViewSectionViewModel.cs
index 680ebe4..0744abc 100644
--- a/Sai.RvKits/RvView/QuickViewSectionViewModel.cs
+++ b/Sai.RvKits/RvView/QuickViewSectionViewModel.cs
@@ -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()
.Cast()
.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.x:RightDirection,transform.y:UpDirection=Z轴,transform.z:ViewDirection (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;
diff --git a/Sai.RvKits/Sai.RvKits.csproj b/Sai.RvKits/Sai.RvKits.csproj
index 2a369dc..137fd22 100644
--- a/Sai.RvKits/Sai.RvKits.csproj
+++ b/Sai.RvKits/Sai.RvKits.csproj
@@ -84,11 +84,13 @@
-
+
-
+
+
+
@@ -144,6 +146,10 @@
+
+
+
+
diff --git a/Sai.RvKits/UIRibbon/RvApp.cs b/Sai.RvKits/UIRibbon/RvApp.cs
index 2ff354b..0fbb462 100644
--- a/Sai.RvKits/UIRibbon/RvApp.cs
+++ b/Sai.RvKits/UIRibbon/RvApp.cs
@@ -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(
- "旋转实例",
+ "旋转管件实例",
Resources.rotate_instance_32px,
Resources.rotate_instance_16px,
- "将族实例根据已连接的情况进行旋转"
+ "将管件族实例根据已连接的情况进行旋转"
+ );
+ var addInsulation = UIAssist.NewPushButtonData(
+ "保温层",
+ Resources.add_insulation_32px,
+ Resources.add_insulation_16px,
+ "对水管和风管添加保温层"
+ );
+ var arrangeMEPCurve = UIAssist.NewPushButtonData(
+ "整理管线",
+ 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);
}
diff --git a/Sai.RvKits/Variables.cs b/Sai.RvKits/Variables.cs
index b784530..af08fa9 100644
--- a/Sai.RvKits/Variables.cs
+++ b/Sai.RvKits/Variables.cs
@@ -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; }
}
diff --git a/Sai.RvKits/Windows/MessageViewModel.cs b/Sai.RvKits/Windows/MessageViewModel.cs
index 28889f3..b3eae93 100644
--- a/Sai.RvKits/Windows/MessageViewModel.cs
+++ b/Sai.RvKits/Windows/MessageViewModel.cs
@@ -54,7 +54,7 @@ public partial class MessageViewModel : ObservableObject
}
var ids = new List { model.Element.Id };
- //UiDocument.ActiveView.IsolateElementTemporary(model.Element.ViewId);
+ //UiDocument.ActiveView.IsolateElementTemporary(model.ElementToMove.ViewId);
showElementsSectionBox.Raise(
_ =>
{
diff --git a/Sai.Toolkit.Core/Heplers/WinDialogHelper.cs b/Sai.Toolkit.Core/Heplers/WinDialogHelper.cs
index a92976d..71f2171 100644
--- a/Sai.Toolkit.Core/Heplers/WinDialogHelper.cs
+++ b/Sai.Toolkit.Core/Heplers/WinDialogHelper.cs
@@ -2,121 +2,148 @@
using System.Reflection;
using System.Windows;
using System.Windows.Interop;
+
using CommunityToolkit.Mvvm.ComponentModel;
+
using Microsoft.Win32;
namespace Sai.Toolkit.Core.Helpers;
public static class WinDialogHelper
{
- ///
- /// 对话框过滤器
- ///
- /// 过滤器的名称
- /// 仅扩展名,*代表所有文件
- ///
- public static string CreateFilter(string filterName, params string[] extensions)
- {
- if (extensions[0] == "*")
- {
- return "所有文件(*)|*";
- }
+ ///
+ /// 对话框过滤器
+ ///
+ /// 过滤器的名称
+ /// 仅扩展名,*代表所有文件
+ ///
+ public static string CreateFilter(string filterName, params string[] extensions)
+ {
+ if (extensions[0] == "*")
+ {
+ return "所有文件(*)|*";
+ }
- var str = string.Empty;
- for (var i = 0; i < extensions.Length; i++)
- {
- var extension = extensions[i];
- str += $"*.{extension}";
- if (i < extensions.Length - 1)
- {
- str += ";";
- }
- }
+ var str = string.Empty;
+ for (var i = 0; i < extensions.Length; i++)
+ {
+ var extension = extensions[i];
+ str += $"*.{extension}";
+ if (i < extensions.Length - 1)
+ {
+ str += ";";
+ }
+ }
- return $"{filterName}({str})|{str}";
- }
+ return $"{filterName}({str})|{str}";
+ }
- ///
- /// 选择文件
- ///
- ///
- ///
- ///
- public static string GetSelectedFilePath(string title, params string[] extensions)
- {
- OpenFileDialog dialog =
- new()
- {
- CheckFileExists = true,
- Filter = CreateFilter(title, extensions),
- InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
- };
- return dialog.ShowDialog() == true ? dialog.FileName : null;
- }
+ ///
+ /// 选择文件
+ ///
+ ///
+ ///
+ ///
+ public static string GetSelectedFilePath(string title, params string[] extensions)
+ {
+ OpenFileDialog dialog =
+ new()
+ {
+ CheckFileExists = true,
+ Filter = CreateFilter(title, extensions),
+ InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
+ };
+ return dialog.ShowDialog() == true ? dialog.FileName : null;
+ }
- /////
- ///// 单选文件夹路径
- /////
- /////
- //public static string GetSelectedFolderPath()
- //{
- // var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog { Multiselect = false };
+ /////
+ ///// 单选文件夹路径
+ /////
+ /////
+ //public static string GetSelectedFolderPath()
+ //{
+ // var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog { Multiselect = false };
- // var folderPath = dialog.ShowDialog() == true ? dialog.SelectedPath : null;
+ // var folderPath = dialog.ShowDialog() == true ? dialog.SelectedPath : null;
- // return folderPath;
- //}
+ // return folderPath;
+ //}
- /////
- ///// 多选文件夹路径
- /////
- /////
- //public static string[] GetSelectedFolderPaths()
- //{
- // var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog { Multiselect = true };
+ /////
+ ///// 多选文件夹路径
+ /////
+ /////
+ //public static string[] GetSelectedFolderPaths()
+ //{
+ // var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog { Multiselect = true };
- // return dialog.ShowDialog() == true ? dialog.SelectedPaths : null;
- //}
+ // return dialog.ShowDialog() == true ? dialog.SelectedPaths : null;
+ //}
- ///
- /// 打开窗口,非模态窗口置顶显示,默认非模态
- ///
- ///
- private static void ShowAhead(this Window window)
- {
- _ = new WindowInteropHelper(window) { Owner = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle };
- window.Show();
- }
+ ///
+ /// 打开窗口,非模态窗口置顶显示,默认非模态
+ ///
+ ///
+ private static void ShowAhead(this Window window)
+ {
+ _ = new WindowInteropHelper(window) { Owner = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle };
+ window.Show();
+ }
- public static void ShowModeless(ObservableObject viewModel)
- where T : Window, new()
- {
- var view = SingletonViewHelper.GetInstance(out var isNewCreate);
- if (isNewCreate)
- {
- view.DataContext = viewModel;
- view.ShowAhead();
- }
- view.Activate();
- //AssemblyLoaderHelpers loaderUtil = new(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
- //loaderUtil.HookAssemblyResolve();
- //try
- //{
- // var view = SingletonViewHelper.GetInstance(out var isNewCreate);
- // if (isNewCreate)
- // {
- // view.DataContext = viewModel;
- // view.ShowAhead();
- // }
- // view.Activate();
- //}
- //catch (Exception ex)
- //{
- // LogHelper.ToLog($"{ex.Source}:{ex.StackTrace}");
- //}
- //finally
- //{
- // loaderUtil.UnhookAssemblyResolve();
- //}
- }
+ public static void ShowModeless(ObservableObject viewModel)
+ where T : Window, new()
+ {
+ var view = SingletonViewHelper.GetInstance(out var isNewCreate);
+ if (isNewCreate)
+ {
+ view.DataContext = viewModel;
+ view.ShowAhead();
+ }
+ view.Activate();
+ //AssemblyLoaderHelpers loaderUtil = new(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
+ //loaderUtil.HookAssemblyResolve();
+ //try
+ //{
+ // var view = SingletonViewHelper.GetInstance(out var isNewCreate);
+ // if (isNewCreate)
+ // {
+ // view.DataContext = viewModel;
+ // view.ShowAhead();
+ // }
+ // view.Activate();
+ //}
+ //catch (Exception ex)
+ //{
+ // LogHelper.ToLog($"{ex.Source}:{ex.StackTrace}");
+ //}
+ //finally
+ //{
+ // loaderUtil.UnhookAssemblyResolve();
+ //}
+ }
+ private static Dictionary _windows = [];
+ public static void ShowOrActivate(params object[] viewModelParams)
+ where TWindow : Window, new()
+ where TViewModel : class
+ {
+ var windowType = typeof(TWindow);
+ if (!_windows.ContainsKey(windowType) || _windows[windowType] == null)
+ {
+ //CloseAllWindowsExcept(windowType);
+ _windows[windowType] = new TWindow();
+ _windows[windowType].Closed += (sender, args) => _windows[windowType] = null;
+ if (_windows[windowType].DataContext == null || !(_windows[windowType].DataContext is TViewModel))
+ {
+ _windows[windowType].DataContext = viewModelParams.Length == 0
+ ? Activator.CreateInstance(typeof(TViewModel))
+ : Activator.CreateInstance(typeof(TViewModel), viewModelParams);
+ }
+ _ = new WindowInteropHelper(_windows[windowType]) { Owner = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle };
+ _windows[windowType].Show();
+ }
+ else
+ {
+ _windows[windowType].Activate();
+ }
+ }
}
diff --git a/Sai.Toolkit.Mvvm/BindingProxy.cs b/Sai.Toolkit.Mvvm/BindingProxy.cs
index c906367..e23ec0f 100644
--- a/Sai.Toolkit.Mvvm/BindingProxy.cs
+++ b/Sai.Toolkit.Mvvm/BindingProxy.cs
@@ -5,24 +5,24 @@ using System.Windows;
namespace Sai.Toolkit.Mvvm
{
- ///
- /// 绑定代理,用来传递绑定对象
- ///
- public class BindingProxy : Freezable
- {
- protected override Freezable CreateInstanceCore() => new BindingProxy();
+ ///
+ /// 绑定代理,用来传递绑定对象
+ ///
+ public class BindingProxy : Freezable
+ {
+ protected override Freezable CreateInstanceCore() => new BindingProxy();
- public object Data
- {
- get { return (object)GetValue(DataProperty); }
- set { SetValue(DataProperty, value); }
- }
+ public object Data
+ {
+ get { return GetValue(DataProperty); }
+ set { SetValue(DataProperty, value); }
+ }
- // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
- nameof(Data),
- typeof(object),
- typeof(BindingProxy)
- );
- }
+ // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
+ nameof(Data),
+ typeof(object),
+ typeof(BindingProxy)
+ );
+ }
}
diff --git a/Sai.Toolkit.Revit/Assist/ImportInstanceAssist.cs b/Sai.Toolkit.Revit/Assist/ImportInstanceAssist.cs
index c5066d9..225e997 100644
--- a/Sai.Toolkit.Revit/Assist/ImportInstanceAssist.cs
+++ b/Sai.Toolkit.Revit/Assist/ImportInstanceAssist.cs
@@ -165,7 +165,7 @@ public static class ImportInstanceAssist
///
///
///
- public static string GetDwgPath(this ImportInstance dwg)
+ public static string GetFilePath(this ImportInstance dwg)
{
var cadLinkType = dwg.Document.GetElement(dwg.GetTypeId()) as CADLinkType;
var filePath = cadLinkType?.GetExternalFileReference().GetLinkedFileStatus() == LinkedFileStatus.Loaded
diff --git a/Sai.Toolkit.Revit/Assist/SpatialAssist.cs b/Sai.Toolkit.Revit/Assist/SpatialAssist.cs
index b5fa882..e7656a9 100644
--- a/Sai.Toolkit.Revit/Assist/SpatialAssist.cs
+++ b/Sai.Toolkit.Revit/Assist/SpatialAssist.cs
@@ -713,7 +713,24 @@ public static class SpatialAssist
{
return instance.Location is LocationCurve lc ? lc.Curve : null;
}
-
+ ///
+ /// 获取元素定位线
+ ///
+ /// 以点定位的实例
+ ///
+ public static LocationCurve GetLocationCurve(this Element instance)
+ {
+ return instance.Location is LocationCurve lc ? lc : null;
+ }
+ ///
+ /// 获取元素定位线
+ ///
+ /// 以点定位的实例
+ ///
+ public static LocationPoint GetLocationPoint(this Element instance)
+ {
+ return instance.Location is LocationPoint lp ? lp : null;
+ }
///
/// 获取元素定位点
///
diff --git a/Sai.Toolkit.Revit/Assist/UIAssist.cs b/Sai.Toolkit.Revit/Assist/UIAssist.cs
index f2791d3..3164bbe 100644
--- a/Sai.Toolkit.Revit/Assist/UIAssist.cs
+++ b/Sai.Toolkit.Revit/Assist/UIAssist.cs
@@ -2,6 +2,7 @@
using System.Drawing;
using System.IO;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
@@ -10,16 +11,14 @@ using System.Windows.Media.Imaging;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
-using adWin = Autodesk.Windows;
using CommunityToolkit.Diagnostics;
using UIFramework;
using UIFrameworkServices;
-using System.Runtime.CompilerServices;
-using Sai.Toolkit.Mvvm.Attributes;
+using adWin = Autodesk.Windows;
namespace Sai.Toolkit.Revit.Assist;
diff --git a/Sai.Toolkit.Revit/Assist/ViewAssist.cs b/Sai.Toolkit.Revit/Assist/ViewAssist.cs
index c7e6ac9..89c748c 100644
--- a/Sai.Toolkit.Revit/Assist/ViewAssist.cs
+++ b/Sai.Toolkit.Revit/Assist/ViewAssist.cs
@@ -6,6 +6,10 @@ using Autodesk.Revit.UI;
namespace Sai.Toolkit.Revit.Assist;
+/// SectionView:
+/// RightDirection = CropBox.Transform.BasisX;
+/// ViewDirection = CropBox.Transform.BasisZ;
+/// UpDirection = XYZ.BasisZ =CropBox.Transform.BasisY
public static class ViewAssist
{
///
diff --git a/Wpf.Ui.Extend/Controls/TreeComboBox/ExtendedTreeView.cs b/Wpf.Ui.Extend/Controls/TreeComboBox/ExtendedTreeView.cs
new file mode 100644
index 0000000..b1215f4
--- /dev/null
+++ b/Wpf.Ui.Extend/Controls/TreeComboBox/ExtendedTreeView.cs
@@ -0,0 +1,247 @@
+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.Input;
+
+namespace Wpf.Ui.Extend.Controls;
+public class ExtendedTreeView : TreeView
+{
+ public event MouseEventHandler? OnHierarchyMouseUp;
+ public event RoutedEventHandler? OnChecked;
+
+ public static readonly DependencyProperty IsExpandedPathProperty = DependencyProperty.Register("IsExpandedPath", typeof(string), typeof(ExtendedTreeView), new PropertyMetadata());
+ public static readonly DependencyProperty IsSelectedPathProperty = DependencyProperty.Register("IsSelectedPath", typeof(string), typeof(ExtendedTreeView), new PropertyMetadata());
+ public static readonly DependencyProperty IsCheckedPathProperty = DependencyProperty.Register("IsCheckedPath", typeof(string), typeof(ExtendedTreeView), new PropertyMetadata());
+
+ public string IsSelectedPath
+ {
+ get { return (string)GetValue(IsSelectedPathProperty); }
+ set { SetValue(IsSelectedPathProperty, value); }
+ }
+
+ public string IsExpandedPath
+ {
+ get { return (string)GetValue(IsExpandedPathProperty); }
+ set { SetValue(IsExpandedPathProperty, value); }
+ }
+
+ public string IsCheckedPath
+ {
+ get { return (string)GetValue(IsCheckedPathProperty); }
+ set { SetValue(IsCheckedPathProperty, value); }
+ }
+
+ protected override DependencyObject GetContainerForItemOverride()
+ {
+ ExtendedTreeViewItem treeViewItem = null;
+ if (IsCheckedPath == null)
+ {
+ treeViewItem = ExtendedTreeViewItem.CreateItemWithBinding(IsExpandedPath, IsSelectedPath);
+ }
+ else
+ {
+ var xtreeViewItem = CheckableTreeViewItem.CreateItemWithBinding(IsExpandedPath, IsSelectedPath, IsCheckedPath);
+ xtreeViewItem.IsCheckedHandler += XtreeViewItem_IsCheckedHandler;
+ treeViewItem = xtreeViewItem;
+ }
+
+ treeViewItem.OnHierarchyMouseUp += OnChildItemMouseLeftButtonUp;
+
+
+ return treeViewItem;
+ }
+
+ private void XtreeViewItem_IsCheckedHandler(object sender, RoutedEventArgs e)
+ {
+ if (this.OnChecked != null)
+ {
+ this.OnChecked(sender, e);
+ e.Handled = true;
+ }
+ }
+
+ private void OnChildItemMouseLeftButtonUp(object sender, MouseEventArgs e)
+ {
+ if (this.OnHierarchyMouseUp != null)
+ {
+ this.OnHierarchyMouseUp(this, e);
+ e.Handled = true;
+ }
+ }
+
+}
+
+public class ExtendedTreeViewItem : TreeViewItem
+{
+ private string isExpandedPath;
+ private string isSelectedPath;
+
+ public ExtendedTreeViewItem()
+ {
+ this.MouseLeftButtonUp += OnMouseLeftButtonUp;
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ }
+
+ public ExtendedTreeViewItem(string isExpandedPath, string isSelectedPath)
+ {
+ this.isExpandedPath = isExpandedPath;
+ this.isSelectedPath = isSelectedPath;
+ }
+
+ void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ HierarchyMouseUp(e);
+ }
+
+ protected override DependencyObject GetContainerForItemOverride()
+ {
+ var childItem = CreateItemWithBinding(isExpandedPath, isSelectedPath);
+
+ childItem.MouseLeftButtonUp += OnMouseLeftButtonUp;
+
+ return childItem;
+ }
+
+ public static ExtendedTreeViewItem CreateItemWithBinding(string isExpandedPath, string isSelectedPath)
+ {
+ var tvi = new ExtendedTreeViewItem(isExpandedPath, isSelectedPath);
+
+ var expandedBinding = new Binding(isExpandedPath)
+ {
+ Mode = BindingMode.TwoWay
+ };
+ tvi.SetBinding(TreeViewItem.IsExpandedProperty, expandedBinding);
+
+ var selectedBinding = new Binding(isSelectedPath)
+ {
+ Mode = BindingMode.TwoWay
+ };
+ tvi.SetBinding(TreeViewItem.IsSelectedProperty, selectedBinding);
+
+ return tvi;
+ }
+
+ public event MouseEventHandler OnHierarchyMouseUp;
+
+ protected void HierarchyMouseUp(MouseButtonEventArgs e)
+ {
+ if (this.OnHierarchyMouseUp != null)
+ {
+ this.OnHierarchyMouseUp?.Invoke(this, e);
+ e.Handled = true;
+ }
+ }
+}
+
+
+
+public class CheckableTreeViewItem : ExtendedTreeViewItem
+{
+ private string isExpandedPath;
+ private string isSelectedPath;
+ private string isCheckedPath;
+ private CheckBox? checkBox;
+
+ public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(CheckableTreeViewItem), new PropertyMetadata(false));
+
+ static CheckableTreeViewItem()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckableTreeViewItem), new FrameworkPropertyMetadata(typeof(CheckableTreeViewItem)));
+ }
+
+ public CheckableTreeViewItem()
+ {
+ }
+
+ public override void OnApplyTemplate()
+ {
+ checkBox = this.GetTemplateChild("PART_CheckBox") as CheckBox;
+ checkBox.Checked += CheckBox_Checked;
+ checkBox.Unchecked += CheckBox_Unchecked;
+ base.OnApplyTemplate();
+ }
+
+ private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
+ {
+ if (IsCheckedHandler != null)
+ {
+ IsCheckedHandler?.Invoke(this, e);
+ e.Handled = true;
+ }
+ }
+
+ private void CheckBox_Checked(object sender, RoutedEventArgs e)
+ {
+ if (IsCheckedHandler != null)
+ {
+ IsCheckedHandler?.Invoke(this, e);
+ e.Handled = true;
+ }
+ }
+
+ public CheckableTreeViewItem(string isExpandedPath, string isSelectedPath, string isCheckedPath)
+ {
+ this.isExpandedPath = isExpandedPath;
+ this.isSelectedPath = isSelectedPath;
+ this.isCheckedPath = isCheckedPath;
+ }
+
+ public bool IsChecked
+ {
+ get { return (bool)GetValue(IsCheckedProperty); }
+ set { SetValue(IsCheckedProperty, value); }
+ }
+
+
+ protected override DependencyObject GetContainerForItemOverride()
+ {
+ var childItem = CreateItemWithBinding(isExpandedPath, isSelectedPath, isCheckedPath);
+ childItem.IsCheckedHandler += ChildItem_IsCheckedHandler;
+ return childItem;
+ }
+
+ private void ChildItem_IsCheckedHandler(object sender, RoutedEventArgs e)
+ {
+ if (IsCheckedHandler != null)
+ {
+ IsCheckedHandler?.Invoke(sender, e);
+ e.Handled = true;
+ }
+ }
+
+ public static CheckableTreeViewItem CreateItemWithBinding(string isExpandedPath, string isSelectedPath, string isCheckedPath)
+ {
+ var tvi = new CheckableTreeViewItem(isExpandedPath, isSelectedPath, isCheckedPath);
+
+ var expandedBinding = new Binding(isExpandedPath)
+ {
+ Mode = BindingMode.TwoWay
+ };
+ tvi.SetBinding(TreeViewItem.IsExpandedProperty, expandedBinding);
+
+ var selectedBinding = new Binding(isSelectedPath)
+ {
+ Mode = BindingMode.TwoWay
+ };
+ tvi.SetBinding(TreeViewItem.IsSelectedProperty, selectedBinding);
+
+ var isCheckedBinding = new Binding(isCheckedPath)
+ {
+ Mode = BindingMode.TwoWay
+ };
+ tvi.SetBinding(CheckableTreeViewItem.IsCheckedProperty, isCheckedBinding);
+
+ return tvi;
+ }
+
+ public event RoutedEventHandler IsCheckedHandler;
+}
diff --git a/Wpf.Ui.Extend/Controls/TreeComboBox/TreeComboBox.cs b/Wpf.Ui.Extend/Controls/TreeComboBox/TreeComboBox.cs
new file mode 100644
index 0000000..13f9f10
--- /dev/null
+++ b/Wpf.Ui.Extend/Controls/TreeComboBox/TreeComboBox.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace Wpf.Ui.Extend.Controls;
+public class TreeComboBox : ComboBox
+{
+ public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IEnumerable), typeof(TreeComboBox), new PropertyMetadata(null));
+ public static readonly DependencyProperty ParentPathProperty = DependencyProperty.Register("ParentPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata());
+ public static readonly DependencyProperty SelectedNodeProperty = DependencyProperty.Register("SelectedNode", typeof(object), typeof(TreeComboBox), new FrameworkPropertyMetadata(default));
+ public static readonly DependencyProperty IsCheckedPathProperty = DependencyProperty.Register("IsCheckedPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata());
+ public static readonly DependencyProperty IsExpandedPathProperty = DependencyProperty.Register("IsExpandedPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata("IsExpanded"));
+ public static readonly DependencyProperty IsSelectedPathProperty = DependencyProperty.Register("IsSelectedPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata("IsSelected"));
+
+ private ExtendedTreeView _treeView;
+ private ObservableCollection