添加项目文件。

This commit is contained in:
GG Z
2024-09-22 11:05:41 +08:00
parent fb5d55723a
commit 49ceaae6a8
764 changed files with 78850 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
using Autodesk.Revit.DB;
namespace Sai.RvKits.RvCommon;
internal class AlignModelElement
{
private readonly View ownerView;
public AlignModelElement(Element e)
{
Parent = e;
var doc = e.Document;
ownerView = doc.GetElement(e.OwnerViewId) != null ? doc.GetElement(e.OwnerViewId) as View : doc.ActiveView;
//var viewPlane = Plane.CreateByNormalAndOrigin(ownerView is View3D ? XYZ.BasisZ : ownerView!.ViewDirection, ownerView.Origin);
var elementBBox = e.get_BoundingBox(ownerView);
var max = elementBBox.Max;
var min = elementBBox.Min;
//var globalMax = elementBBox.Max;
//var globalMin = elementBBox.Min;
//var distanceProjected = ProjectedDistance(viewPlane, globalMax, globalMin);
//XYZ alternateMax = new(globalMax.X, globalMin.Y, globalMax.Z);
//XYZ alternateMin = new(globalMin.X, globalMax.Y, globalMin.Z);
//var alternateDistanceProjected = ProjectedDistance(viewPlane, alternateMax, alternateMin);
//if (alternateDistanceProjected > distanceProjected)
//{
// globalMax = alternateMax;
// globalMin = alternateMin;
//}
//var ownerViewTransform = ownerView.CropBox.Transform;
//var max = ownerViewTransform.Inverse.OfPoint(globalMax); //Max in the coordinate space of the view
//var min = ownerViewTransform.Inverse.OfPoint(globalMin); //Min in the coordinate space of the view
UpLeft = new XYZ(Math.Min(min.X, max.X), Math.Max(max.Y, min.Y), 0);
UpRight = new XYZ(Math.Max(min.X, max.X), Math.Max(max.Y, min.Y), 0);
DownLeft = new XYZ(Math.Min(min.X, max.X), Math.Min(max.Y, min.Y), 0);
DownRight = new XYZ(Math.Max(min.X, max.X), Math.Min(max.Y, min.Y), 0);
Center = (UpRight + DownLeft) / 2;
Bottom = min.Z;
Top = max.Z;
Middle = (max.Z + min.Z) / 2;
//if (ownerView is View3D)
//{
// Bottom = min.Z;
//}
//else
//{
// Bottom = Math.Min(max.Z, min.Z);
//}
}
//private static double ProjectedDistance(Plane plane, XYZ pointA, XYZ pointB)
//{
// //To be tested
// var uva = plane.ProjectOf(pointA);
// var uvb = plane.ProjectOf(pointB);
// return uva.DistanceTo(uvb);
//}
public void MoveTo(XYZ point, AlignType alignType)
{
if (!Parent.Pinned)
{
var displacementVector = alignType switch
{
AlignType.Left => point - UpLeft,
AlignType.Right => point - UpRight,
AlignType.Up => point - UpRight,
AlignType.Down => point - DownRight,
AlignType.HorizontallyCenter => point - Center,
AlignType.VerticallyCenter => point - Center,
AlignType.Bottom => XYZ.BasisZ * (point.Z - Bottom),
AlignType.Top => XYZ.BasisZ * (point.Z - Top),
AlignType.Middle => XYZ.BasisZ * (point.Z - Middle),
_ => throw new ArgumentOutOfRangeException(nameof(alignType), alignType, null)
};
//位置不一样,移动
if (!displacementVector.IsZeroLength())
{
//var translate = ownerView.CropBox.Transform.OfVector(displacementVector);
//Parent.Location.Move(translate);
ElementTransformUtils.MoveElement(Parent.Document, Parent.Id, displacementVector);
}
}
}
public double Bottom { get; }
/// <summary>
/// 水平面的中心
/// </summary>
public XYZ Center { get; }
public XYZ DownLeft { get; }
public XYZ DownRight { get; }
/// <summary>
/// 垂向的中心
/// </summary>
public double Middle { get; }
public Element Parent { get; }
public double Top { get; }
public XYZ UpLeft { get; }
public XYZ UpRight { get; }
}

View File

@@ -0,0 +1,32 @@
using System.ComponentModel;
namespace Sai.RvKits.RvCommon;
public enum AlignType
{
[Description("左对齐")]
Left,
[Description("右对齐")]
Right,
[Description("上对齐")]
Up,
[Description("下对齐")]
Down,
/// <summary>
/// Y轴中心对齐水平位置居中
/// </summary>
[Description("水平居中")]
HorizontallyCenter,
/// <summary>
/// X轴中心对齐垂直居中对齐
/// </summary>
[Description("垂直居中")]
VerticallyCenter,
[Description("底对齐")]
Bottom,
[Description("中对齐")]
Middle,
[Description("顶对齐")]
Top,
}

View File

@@ -0,0 +1,49 @@
using Autodesk.Revit.Attributes;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
using Nice3point.Revit.Toolkit.External.Handlers;
namespace Sai.RvKits.RvCommon;
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class AutoSaveCmd : ExternalCommand
{
private readonly System.Timers.Timer timer = Variables.Timer;
public override void Execute()
{
if (string.IsNullOrEmpty(Document.PathName))
{
ErrorMessage = "当前文件尚未保存,请先保存文件";
Result = Result.Failed;
return;
}
AutoSaveViewModel viewModel = new();
AutoSaveView view = new()
{
DataContext = viewModel
};
view.ShowDialog();
if (view.DialogResult == true)
{
if (Properties.Settings.Default.AutoSave)
{
if (Properties.Settings.Default.AutoSaveIntervalTime >= 1)
{
timer.Interval = Properties.Settings.Default.AutoSaveIntervalTime * 60 * 1000;
}
Properties.Settings.Default.Save();
//timer.Enabled = Properties.Settings.Default.AutoSave;
timer.Start();
}
else
{
timer.Stop();
}
}
Result = Result.Succeeded;
}
}

View File

@@ -0,0 +1,37 @@
<ex:FluentWindowEx
x:Class="Sai.RvKits.RvCommon.AutoSaveView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rvCommon="clr-namespace:Sai.RvKits.RvCommon"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="自动保存"
Width="300"
d:DataContext="{d:DesignInstance Type=rvCommon:AutoSaveViewModel}"
mc:Ignorable="d">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Closing">
<b:InvokeCommandAction Command="{Binding ClosingCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Sai.RvKits;component/WPFUI.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<ex:AutoGrid Margin="5" VerticalAlignment="Center">
<CheckBox x:Name="CbAutoSave" IsChecked="{Binding IsActiveAutoSave, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock VerticalAlignment="Center" Text="自动保存时间间隔(分钟)" />
<TextBox
x:Name="TbIntervalMinutes"
Width="80"
InputMethod.IsInputMethodEnabled="False"
IsEnabled="{Binding IsChecked, ElementName=CbAutoSave}"
Text="{Binding IntervalTime, UpdateSourceTrigger=PropertyChanged}" />
</ex:AutoGrid>
</ex:FluentWindowEx>

View File

@@ -0,0 +1,16 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Wpf.Ui.Extend.Controls;
namespace Sai.RvKits.RvCommon;
/// <summary>
/// AutoSaveView.xaml 的交互逻辑
/// </summary>
public partial class AutoSaveView : FluentWindowEx
{
public AutoSaveView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,33 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Sai.RvKits.RvCommon;
public partial class AutoSaveViewModel : ObservableValidator
{
public AutoSaveViewModel()
{
IsActiveAutoSave = Properties.Settings.Default.IsActiveAutoSave;
IntervalTime = Properties.Settings.Default.AutoSaveIntervalTime;
}
[ObservableProperty]
private bool isActiveAutoSave;
[Required(ErrorMessage = "不可为空")]
[DefaultValue(15)]
[NotifyDataErrorInfo]
[Range(5, 30, ErrorMessage = "输入值应在5~30分钟之间")]
[ObservableProperty]
private int intervalTime;
[RelayCommand]
private void Closing()
{
Properties.Settings.Default.IsActiveAutoSave = IsActiveAutoSave;
Properties.Settings.Default.AutoSaveIntervalTime = IntervalTime;
Properties.Settings.Default.Save();
}
}

View File

@@ -0,0 +1,28 @@
using Autodesk.Revit.DB;
namespace Sai.RvKits.RvCommon
{
internal class CustomLeader
{
public CustomLeader(Leader leader)
{
End = leader.End;
Elbow = leader.Elbow;
}
public CustomLeader()
{
End = new XYZ(0, 0, 0);
Elbow = new XYZ(0, 0, 0);
}
public CustomLeader(XYZ end, XYZ elbow)
{
End = end;
Elbow = elbow;
}
public XYZ End { get; set; }
public XYZ Elbow { get; set; }
}
}

View File

@@ -0,0 +1,96 @@
<ex:FluentWindowEx
x:Class="Sai.RvKits.RvCommon.DetailSelectFiltersView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
xmlns:local="clr-namespace:Sai.RvKits.RvCommon"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mvvm="clr-namespace:Sai.Toolkit.Mvvm"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="构件明细"
Width="800"
Height="450"
d:DataContext="{d:DesignInstance Type=local:DetailSelectFiltersViewModel}"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Sai.RvKits;component/WPFUI.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--<mvvm:BindingProxy x:Key="DocumentProxy" Data="{Binding Document}" />-->
</ResourceDictionary>
</Window.Resources>
<ex:AutoGrid
ChildMargin="5"
Columns="*"
Rows="*,Auto">
<DataGrid
AutoGenerateColumns="False"
CanUserAddRows="False"
ColumnWidth="Auto"
IsReadOnly="True"
ItemsSource="{Binding FilteredList}"
ToolTip="双击行可快速定位">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseDoubleClick">
<b:InvokeCommandAction Command="{Binding ShowElementCommand}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}, Mode=FindAncestor}}" />
</b:EventTrigger>
</b:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Id}" Header="元素ID" />
<DataGridTextColumn Binding="{Binding CategoryName}" Header="类别名称" />
<DataGridTextColumn
Width="Auto"
Binding="{Binding Name}"
Header="名称" />
<!--<DataGridTextColumn Binding="{Binding ReferenceLevel?.Name}" Header="参照标高" />-->
<DataGridTextColumn Binding="{Binding LevelName}" Header="标高" />
<DataGridTextColumn Binding="{Binding ReferenceLevel}" Header="参照标高" />
<DataGridTextColumn Binding="{Binding HostName}" Header="主体" />
<DataGridTextColumn Binding="{Binding Offset}" Header="偏移" />
<!--<DataGridTextColumn Binding="{Binding Path=LevelId, Converter={StaticResource IdToNameConverter}, ConverterParameter={StaticResource DocumentProxy}}" Header="标高" />-->
<!--<DataGridTextColumn Header="标高">
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource IdToNameConverter}">
<Binding Path="DataContext" RelativeSource="{RelativeSource Mode=Self}" />
<Binding Path="LevelId" />
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>-->
<DataGridTextColumn Binding="{Binding MEPSystemName}" Header="系统类型" />
<DataGridTextColumn Binding="{Binding RoomName}" Header="所属房间" />
<DataGridTextColumn Binding="{Binding Phase}" Header="创建阶段" />
<DataGridTextColumn Binding="{Binding Number}" Header="标记" />
<DataGridTextColumn Binding="{Binding Comment}" Header="注释" />
<!--<DataGridTextColumn Binding="{Binding ErrorMessage}" Header="错误信息" />-->
<!--<DataGridTemplateColumn Header="操作">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
-->
<!-- 按钮参数绑定到当前行的绑定的Item -->
<!--
<Button
Command="{Binding DataContext.ShowElementCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"
CommandParameter="{Binding}"
Content="定位构件" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>-->
</DataGrid.Columns>
</DataGrid>
<ex:StackPanelEx Grid.Row="1" Orientation="Horizontal">
<CheckBox
Margin="5"
Content="剖切"
IsChecked="{Binding IsCutting, UpdateSourceTrigger=PropertyChanged}"
ToolTip="仅三维视图可用" />
<ui:TextBox
Margin="5"
ex:StackPanelEx.Fill="Fill"
PlaceholderText="请输入检索属性条目"
Text="{Binding SearchProp, UpdateSourceTrigger=PropertyChanged}" />
</ex:StackPanelEx>
</ex:AutoGrid>
</ex:FluentWindowEx>

View File

@@ -0,0 +1,29 @@
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.Extend.Controls;
namespace Sai.RvKits.RvCommon
{
/// <summary>
/// DetailSelectFiltersView.xaml 的交互逻辑
/// </summary>
public partial class DetailSelectFiltersView : FluentWindowEx
{
public DetailSelectFiltersView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,162 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
namespace Sai.RvKits.RvCommon
{
public partial class DetailSelectFiltersViewModel : ObservableObject
{
private readonly ActionEventHandler handler;
[ObservableProperty]
ICollectionView filteredList;
[ObservableProperty]
private bool isCutting;
[ObservableProperty]
private ObservableCollection<SelectionElement> items;
[ObservableProperty]
private string searchProp;
private readonly UIApplication uiapp;
public DetailSelectFiltersViewModel(UIApplication uiapp, ActionEventHandler handler)
{
var elemIds = uiapp.ActiveUIDocument.Selection.GetElementIds();
Items = [];
this.uiapp = uiapp;
this.handler = handler;
var doc = uiapp.ActiveUIDocument.Document;
foreach (var elementId in elemIds)
{
//var elem = doc.GetElement(elementId);
//var param = elem.GetParameters("ID-100-编号").FirstOrDefault();
//if (param != null && param.AsString() == string.Empty)
//{
// Items.Add(doc.GetElement(elementId));
//}
var element = doc.GetElement(elementId);
if (element.IsValidObject)
{
Items.Add(new SelectionElement(element));
}
}
FilteredList = CollectionViewSource.GetDefaultView(Items);
}
partial void OnSearchPropChanged(string value)
{
FilteredList.Filter = o =>
{
if (string.IsNullOrEmpty(SearchProp))
{
return true;
}
var item = o as SelectionElement;
return (item?.Name != null && item.Name.Contains(SearchProp))
|| (item?.Number != null && item.Number.Contains(SearchProp))
|| (item?.Comment != null && item.Comment.Contains(SearchProp));
};
}
[RelayCommand]
private void ShowElement(object obj)
{
if (obj is not SelectionElement selection) return;
var model = selection.Element;
var uidoc = uiapp.ActiveUIDocument;
if (model.IsValidObject)
{
ZoomElement(model, uidoc);
}
else
{
Items.Remove(selection);
}
}
private void ZoomElement(Element model, UIDocument uidoc)
{
var views = uidoc.Document.OfClass<View>().OfType<View>().Where(v => !v.IsTemplate);
View targetView = null;
if (model.IsVisible(uidoc.ActiveView))
{
targetView = uidoc.ActiveView;
}
else
{
foreach (var v in views)
{
if (model.IsVisible(v))
{
targetView = v;
break;
}
}
}
if (targetView == null)
{
MessageBox.Show("未找到可见的视图", "错误");
return;
}
uidoc.ActiveView = targetView;
handler.Raise(
_ =>
{
uidoc.Document
.Invoke(
_ =>
{
if (targetView is View3D view3D && IsCutting)
{
view3D.SectionBoxElement(model.Id);
}
}, "剖切元素");
});
targetView.ZoomElement(uidoc, model.Id);
uidoc.Selection.SetElementIds([model.Id]);
}
}
public class SelectionElement(Element element)
{
public string CategoryName => element.Category?.Name;
public string Comment => element.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)?.AsString();
public Element Element => element;
public string HostName => element is FamilyInstance { Host: not null } instance ? instance.Host.Name : null;
public ElementId Id => element.Id;
public string LevelName => element.LevelId != ElementId.InvalidElementId ? (doc.GetElement(element.LevelId)?.Name) : null;
public string MEPSystemName => element is MEPCurve mep ? doc.GetElement(mep.MEPSystem.GetTypeId()).Name : null;
public string Name => element.Name;
public string Number => element.get_Parameter(BuiltInParameter.DOOR_NUMBER)?.AsString();
public string Offset =>
element is FamilyInstance instance
? (instance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM)?.AsValueString())
: null;
public string Phase => element.CreatedPhaseId == ElementId.InvalidElementId ? null : doc.GetElement(element.CreatedPhaseId).Name;
public string ReferenceLevel =>
element is MEPCurve mep
? mep.ReferenceLevel.Name
: (element.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM)?.AsValueString());
public string RoomName => element is FamilyInstance instance && instance.Room != null ? instance.Room.Name : null;
private readonly Document doc = element.Document;
}
}

View File

@@ -0,0 +1,19 @@
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Nice3point.Revit.Toolkit.External;
namespace Sai.RvKits.RvCommon;
/// <summary>
/// Revit执行命令
/// </summary>
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class InstanceCreatorCmd : ExternalCommand
{
public override void Execute()
{
WinDialogHelper.ShowModeless<InstanceCreatorView>(new InstanceCreatorViewModel(UiDocument));
}
}

View File

@@ -0,0 +1,61 @@
<ex:FluentWindowEx
x:Class="Sai.RvKits.RvCommon.InstanceCreatorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
xmlns:local="clr-namespace:Sai.RvKits.RvCommon"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="族实例布置"
Width="220"
Height="340"
MinHeight="300"
d:DataContext="{d:DesignInstance local:InstanceCreatorViewModel}"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Sai.RvKits;component/WPFUI.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<ex:StackPanelEx Margin="5" Spacing="5">
<ex:ComboBoxEx
DisplayMemberPath="Name"
ItemsSource="{Binding Families}"
PlaceholderText="选择族"
SelectedItem="{Binding SelectedFamily, UpdateSourceTrigger=PropertyChanged}" />
<ex:ComboBoxEx
DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding FamilySymbols, Mode=OneWay}"
PlaceholderText="选择族类型"
SelectedItem="{Binding SelectedFamilySymbol, UpdateSourceTrigger=PropertyChanged}"
ShowFilterBox="False" />
<Image
Grid.Row="2"
Width="128"
Height="128"
Source="{Binding Image}" />
<ex:TextBoxEx
Grid.Row="3"
Prefix="偏移量:"
Suffix="mm"
Text="{Binding Offset}">
<!--<TextBox.Text>
<Binding Path="Offset" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<rules:DoubleValidationRule xmlns:rules="clr-namespace:Sai.RvKits.ValidationRules" ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>-->
</ex:TextBoxEx>
<Button
Grid.Row="4"
HorizontalAlignment="Stretch"
Command="{Binding PlaceInstancesCommand}"
Content="布置"
ToolTip="选择dwg块并布置族实例" />
</ex:StackPanelEx>
</ex:FluentWindowEx>

View File

@@ -0,0 +1,16 @@
using System.Windows;
using Wpf.Ui.Controls;
namespace Sai.RvKits.RvCommon;
/// <summary>
/// InstanceCreatorView.xaml 的交互逻辑
/// </summary>
public partial class InstanceCreatorView
{
public InstanceCreatorView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,326 @@
using System.Windows;
using System.Windows.Media.Imaging;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
// ReSharper disable ConditionIsAlwaysTrueOrFalse
namespace Sai.RvKits.RvCommon;
public partial class InstanceCreatorViewModel : ObservableObject
{
public InstanceCreatorViewModel(UIDocument uiDocument)
{
this.uiDocument = uiDocument;
document = uiDocument.Document;
uiDocument.Application.Application.FamilyLoadedIntoDocument += Application_FamilyLoadedIntoDocument;
GetAvailableFamilies();
}
private readonly UIDocument uiDocument;
~InstanceCreatorViewModel()
{
uiDocument.Application.Application.FamilyLoadedIntoDocument -= Application_FamilyLoadedIntoDocument;
}
private void GetAvailableFamilies()
{
#if REVIT2018 || REVIT2020
//过滤掉栏杆族
var collector = document
.OfClass<Family>()
.Cast<Family>()
.Where(
f =>
f.IsEditable
&& !f.IsInPlace
&& f.GetFamilySymbolIds().Any()
&& f.FamilyCategory.Id.IntegerValue is not (-2000127 or -2009013 or -2005301 or -2009060)
&& f.FamilyPlacementType
is FamilyPlacementType.OneLevelBased
or FamilyPlacementType.TwoLevelsBased
or FamilyPlacementType.WorkPlaneBased
or FamilyPlacementType.OneLevelBasedHosted
)
.OrderBy(f => f.Name)
.ToList();
#elif REVIT2025
//过滤掉栏杆族
var collector = document
.OfClass<Family>()
.Cast<Family>()
.Where(
f =>
f.IsEditable
&& !f.IsInPlace
&& f.GetFamilySymbolIds().Any()
&& f.FamilyCategory.Id.Value is not (-2000127 or -2009013 or -2005301 or -2009060)
&& f.FamilyPlacementType
is FamilyPlacementType.OneLevelBased
or FamilyPlacementType.TwoLevelsBased
or FamilyPlacementType.WorkPlaneBased
or FamilyPlacementType.OneLevelBasedHosted
)
.OrderBy(f => f.Name)
.ToList();
#endif
Families = collector;
}
private void Application_FamilyLoadedIntoDocument(object sender, Autodesk.Revit.DB.Events.FamilyLoadedIntoDocumentEventArgs e)
{
GetAvailableFamilies();
}
private readonly ActionEventHandler handler = new();
[ObservableProperty]
private BitmapSource image;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(PlaceInstancesCommand))]
private bool canPlaceInstance = true;
private readonly Document document;
[ObservableProperty]
private double offset;
[ObservableProperty]
private Family selectedFamily;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(PlaceInstancesCommand))]
private FamilySymbol selectedFamilySymbol;
[ObservableProperty]
private List<Family> families;
[ObservableProperty]
private List<FamilySymbol> familySymbols;
private bool CanPlace()
{
return SelectedFamilySymbol != null && CanPlaceInstance;
}
[RelayCommand(CanExecute = nameof(CanPlace))]
private void PlaceInstances()
{
CanPlaceInstance = false;
handler.Raise(_ =>
{
var family = SelectedFamily;
var symbol = SelectedFamilySymbol;
var d = Offset / 304.8;
Reference reference;
try
{
reference = uiDocument.Selection.PickObject(ObjectType.PointOnElement, new DwgBlockSelection(), "请选择dwg块");
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
CanPlaceInstance = true;
return;
}
//图层ID
//Document.HideDwgLayer(referenceFunc, out ElementId columnGraphicStyleId, out GeometryElement columnGeoElem);
var dwg = document.GetElement(reference) as ImportInstance;
var geoInstances = dwg.GetBlocksByRef(reference);
var dwgTransform = dwg!.GetTotalTransform();
if (geoInstances == null || !geoInstances.Any())
{
MessageBox.Show("选中块为子块或选中块的嵌套层级过深请使用Tab来选择整体快", "识别失败", MessageBoxButton.OK, MessageBoxImage.Error);
CanPlaceInstance = true;
return;
}
document.Invoke(
_ =>
{
if (!symbol.IsActive)
{
symbol.Activate();
}
switch (family.FamilyPlacementType)
{
case FamilyPlacementType.OneLevelBased:
foreach (var ins in geoInstances)
{
var level = document.ActiveView.GenLevel;
GetPose(dwgTransform, ins, out var loc, out var rotation);
var familyInstance = document.Create.NewFamilyInstance(loc, symbol, level, StructuralType.NonStructural);
document.Regenerate();
ElementTransformUtils.RotateElement(document, familyInstance.Id, Line.CreateUnbound(loc, XYZ.BasisZ), rotation);
document.Regenerate();
var translation = XYZ.BasisZ * d;
ElementTransformUtils.MoveElement(document, familyInstance.Id, translation);
}
break;
case FamilyPlacementType.OneLevelBasedHosted:
#if REVIT2018 || REVIT2020
if (family.FamilyCategory.Id.IntegerValue is -2000023 or -2000014)
#elif REVIT2025
if (family.FamilyCategory.Id.Value is -2000023 or -2000014)
#endif
{
var level = document.ActiveView.GenLevel;
foreach (var ins in geoInstances)
{
GetPose(dwgTransform, ins, out var loc, out var rotation);
var minPoint = loc - new XYZ(0.4, 0.4, -level.Elevation);
var maxPoint = loc + new XYZ(0.4, 0.4, level.Elevation + 1);
var outline = new Outline(minPoint, maxPoint);
var intersectsFilter = new BoundingBoxIntersectsFilter(outline);
var intersect = document.OfClass<Wall>().WherePasses(intersectsFilter).FirstElement() as Wall;
var point = loc + (XYZ.BasisZ * level.Elevation);
document.Create.NewFamilyInstance(point, symbol, intersect, level, StructuralType.NonStructural);
}
}
break;
case FamilyPlacementType.TwoLevelsBased:
foreach (var ins in geoInstances)
{
var level = document.ActiveView.GenLevel;
GetPose(dwgTransform, ins, out var loc, out var rotation);
var familyInstance = document.Create.NewFamilyInstance(loc, symbol, level, StructuralType.NonStructural);
document.Regenerate();
ElementTransformUtils.RotateElement(document, familyInstance.Id, Line.CreateUnbound(loc, XYZ.BasisZ), rotation);
document.Regenerate();
var translation = XYZ.BasisZ * d;
ElementTransformUtils.MoveElement(document, familyInstance.Id, translation);
}
break;
case FamilyPlacementType.WorkPlaneBased:
foreach (var ins in geoInstances)
{
GetPose(dwgTransform, ins, out var loc, out var rotation);
var familyInstance = document.Create.NewFamilyInstance(
loc,
symbol,
document.ActiveView.SketchPlane,
StructuralType.NonStructural
);
document.Regenerate();
ElementTransformUtils.RotateElement(document, familyInstance.Id, Line.CreateUnbound(loc, XYZ.BasisZ), rotation);
document.Regenerate();
var translation = XYZ.BasisZ * d;
ElementTransformUtils.MoveElement(document, familyInstance.Id, translation);
}
break;
}
CanPlaceInstance = true;
},
"实例布置"
);
});
}
//private static Dictionary<XYZ, string> WriteCode(UIApplication uiapp)
//{
// var application = uiapp.Application;
// var uiDocument = uiapp.ActiveUIDocument;
// var doc = uiDocument.Document;
// Reference textRefer;
// try
// {
// //图层ID
// textRefer = uiDocument.Selection.PickObject(
// ObjectType.PointOnElement,
// new FuncFilter(e => e is ImportInstance import && import.IsLinked && doc.GetElement(e.GetTypeId()) is CADLinkType),
// "请选择“链接非导入”的Cad文字图层"
// );
// }
// catch (Autodesk.Revit.Exceptions.OperationCanceledException)
// {
// return null;
// }
// var dwg = doc.GetElement(textRefer) as ImportInstance;
// var textLayerName = dwg.GetLayerName(textRefer);
// var path = dwg.GetDwgPath();
// var dwgTransform = dwg.GetTotalTransform();
// using ACadSharp.IO.DwgReader reader = new(path);
// var cadDocument = reader.Read();
// return cadDocument.Entities
// .OfType<ACadSharp.Entities.TextEntity>()
// .Where(e => e.Layer.Name == textLayerName)
// .ToDictionary(
// v =>
// {
// var loc = dwgTransform.OfPoint(new XYZ(v.InsertPoint.X, v.InsertPoint.Y, v.InsertPoint.Z));
// return new XYZ(loc.X, loc.Y, 0);
// },
// e => e.Value
// );
//}
/// <summary>
/// 获取更加准确的位置
/// </summary>
/// <param name="dwgTransform"></param>
/// <param name="ins"></param>
/// <param name="loc"></param>
/// <param name="rotation"></param>
private static void GetPose(Transform dwgTransform, GeometryInstance ins, out XYZ loc, out double rotation)
{
var blockLocation = ins.Transform.Origin;
if (ins.Transform.Origin.GetLength() is > 1000 or 0) //块原点距离实际几何重心过远时
{
//存在标注的情况时,以多段线最准确
var b = ins.GetInstanceGeometry().Any(i => i is PolyLine);
foreach (var geometryObject in ins.GetInstanceGeometry())
{
if (b)
{
if (geometryObject is PolyLine pl)
{
blockLocation = (pl.GetOutline().MaximumPoint + pl.GetOutline().MinimumPoint) / 2;
break;
}
}
else
{
if (geometryObject is Line l)
{
blockLocation = l.Evaluate(0.5, true);
break;
}
if (geometryObject is Arc arc)
{
blockLocation = arc.Center;
break;
}
}
}
}
loc = dwgTransform.OfPoint(blockLocation);
loc = new XYZ(loc.X, loc.Y, 0);
rotation = Math.Abs(ins.Transform.BasisX.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ) - (2 * Math.PI));
}
partial void OnSelectedFamilyChanged(Family value)
{
var doc = value.Document;
FamilySymbols = value.GetFamilySymbolIds().Select(id => doc.GetElement(id)).OfType<FamilySymbol>().ToList();
}
partial void OnSelectedFamilySymbolChanged(FamilySymbol value)
{
Image = value.GetPreviewImage(new System.Drawing.Size(128, 128)).ToBitmapSource();
}
}

View File

@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External;
namespace Sai.RvKits.RvCommon
{
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
internal class ModelByCurveCreatorCmd : ExternalCommand
{
public override void Execute()
{
WinDialogHelper.ShowModeless<ModelByCurveCreatorView>(new ModelByCurveCreatorViewModel(Document));
}
}
}

View File

@@ -0,0 +1,146 @@
<ex:FluentWindowEx
x:Class="Sai.RvKits.RvCommon.ModelByCurveCreatorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
xmlns:local="clr-namespace:Sai.RvKits.RvCommon"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="曲线布置"
Width="500"
d:DataContext="{d:DesignInstance Type=local:ModelByCurveCreatorViewModel}"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/Sai.RvKits;component/WPFUI.xaml" />
</Window.Resources>
<ex:AutoGrid Columns="*" Rows="*,Auto,Auto">
<ex:AutoGrid
Grid.Row="0"
ChildMargin="5"
Columns="*,*"
Rows="*">
<GroupBox
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Stretch"
Header="沿线放样">
<ex:StackPanelEx Spacing="5">
<ex:ComboBoxEx
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
ItemsSource="{Binding ProfileFamilyTypes, Mode=OneWay}"
PlaceholderText="请选择轮廓类型"
SelectedItem="{Binding SelectedProfileFamilyType, UpdateSourceTrigger=PropertyChanged}"
ToolTip="选择轮廓类型,未选择则不创建,&#xA;右键点击清除选择">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseRightButtonUp">
<b:InvokeCommandAction Command="{Binding ClearProfilesSelectionCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ex:ComboBoxEx>
<ex:ComboBoxEx
DisplayMemberPath="Name"
ItemsSource="{Binding Materials, Mode=OneWay}"
PlaceholderText="请选择放样的材质"
SelectedItem="{Binding SelectedMaterial, UpdateSourceTrigger=PropertyChanged}"
ToolTip="选择放样模型材质,未选择则为默认材质,&#xA;右键点击清除选择">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseRightButtonUp">
<b:InvokeCommandAction Command="{Binding ClearMaterialSelectionCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ex:ComboBoxEx>
<ex:TextBoxEx
InputMethod.IsInputMethodEnabled="False"
Prefix="偏移距离X"
Suffix="mm"
Text="{Binding OffsetX, StringFormat={}{0:N2}, UpdateSourceTrigger=PropertyChanged}"
ToolTip="向右偏移设置为正值,&#xA;向左偏移为负值" />
<ex:TextBoxEx
InputMethod.IsInputMethodEnabled="False"
Prefix="偏移距离Y"
Suffix="mm"
Text="{Binding OffsetY, StringFormat={}{0:N2}, UpdateSourceTrigger=PropertyChanged}"
ToolTip="向上偏移设置为正值,&#xA;向下偏移为负值" />
</ex:StackPanelEx>
</GroupBox>
<GroupBox
Grid.Row="0"
Grid.Column="1"
VerticalAlignment="Stretch"
Header="沿线布置">
<ex:StackPanelEx Spacing="5">
<ex:ComboBoxEx
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
ItemsSource="{Binding FamilyTypes, Mode=OneWay}"
PlaceholderText="请选择实例类型"
SelectedItem="{Binding SelectedFamilyType, UpdateSourceTrigger=PropertyChanged}"
ToolTip="选择需要布置的族实例,未选择则不创建,&#xA;右键点击清除选择">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseRightButtonUp">
<b:InvokeCommandAction Command="{Binding ClearFmailyTypeSelectionCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ex:ComboBoxEx>
<ex:TextBoxEx
InputMethod.IsInputMethodEnabled="False"
Prefix="水平间距:"
Suffix="mm"
Text="{Binding Spacing, StringFormat={}{0:N2}, UpdateSourceTrigger=PropertyChanged}" />
<ex:TextBoxEx
InputMethod.IsInputMethodEnabled="False"
Prefix="偏移距离X"
Suffix="mm"
Text="{Binding InstanceOffsetX, StringFormat={}{0:N2}, UpdateSourceTrigger=PropertyChanged}"
ToolTip="向右偏移设置为正值,&#xA;向左偏移为负值" />
<ex:TextBoxEx
InputMethod.IsInputMethodEnabled="False"
Prefix="偏移距离Y"
Suffix="mm"
Text="{Binding InstanceOffsetY, StringFormat={}{0:N2}, UpdateSourceTrigger=PropertyChanged}"
ToolTip="向上偏移设置为正值,&#xA;向下偏移为负值" />
</ex:StackPanelEx>
</GroupBox>
</ex:AutoGrid>
<GroupBox
Grid.Row="1"
Margin="5"
Header="中心线类型">
<UniformGrid VerticalAlignment="Center" Rows="1">
<RadioButton
Content="模型线"
IsChecked="{Binding CenterCurveType, ConverterParameter={x:Static local:CenterCurveType.ModelCurve}, Converter={StaticResource ComparisonConverter}}"
ToolTip="模型线的定位平面为绘制时的工作平面,&#xA;如在楼层楼层平面为该楼层高度" />
<RadioButton
Content="体量族"
IsChecked="{Binding CenterCurveType, ConverterParameter={x:Static local:CenterCurveType.MassCurve}, Converter={StaticResource ComparisonConverter}}"
ToolTip="体量族中仅包含有一条连续的三维曲线" />
<RadioButton
Content="dwg链接"
IsChecked="{Binding CenterCurveType, ConverterParameter={x:Static local:CenterCurveType.DWGCurve}, Converter={StaticResource ComparisonConverter}}"
ToolTip="dwg中仅有一条连续的三维曲线" />
</UniformGrid>
</GroupBox>
<UniformGrid
Grid.Row="2"
Margin="5"
Rows="1">
<ex:TextBoxEx
InputMethod.IsInputMethodEnabled="False"
Prefix="最小细分长度:"
Suffix="m"
Text="{Binding Precision, UpdateSourceTrigger=PropertyChanged}"
ToolTip="数值越小,越拟合原曲线,&#xA;建议模型线由于单条曲线较长取值小一些dwg的曲线由于单条曲线较短取值大一些" />
<CheckBox
HorizontalAlignment="Center"
Content="两侧布置"
IsChecked="{Binding IsTwoSides}"
ToolTip="在中心线两侧布置放样(会合并)和实例" />
<Button
HorizontalAlignment="Stretch"
Command="{Binding CreateTrackCommand}"
Content="创建" />
</UniformGrid>
</ex:AutoGrid>
</ex:FluentWindowEx>

View File

@@ -0,0 +1,29 @@
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.Controls;
namespace Sai.RvKits.RvCommon
{
/// <summary>
/// ModelByCurveCreatorView.xaml 的交互逻辑
/// </summary>
public partial class ModelByCurveCreatorView
{
public ModelByCurveCreatorView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,551 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Windows;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
using Sai.RvKits.Converters;
using Sai.Toolkit.Mvvm.Attributes;
namespace Sai.RvKits.RvCommon
{
public partial class ModelByCurveCreatorViewModel : ObservableValidator
{
[ObservableProperty]
private CenterCurveType centerCurveType;
[ObservableProperty]
private List<FamilySymbol> familyTypes;
private readonly ActionEventHandler handler;
[Required(ErrorMessage = "不可为空")]
[IsNumeric]
[ObservableProperty]
private double instanceOffsetX = 0;
[ObservableProperty]
[Required(ErrorMessage = "不可为空")]
[IsNumeric]
private double instanceOffsetY = 0;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateTrackCommand))]
private bool isRunning;
[ObservableProperty]
private bool isTwoSides = false;
[ObservableProperty]
private List<Material> materials;
[Required(ErrorMessage = "不可为空")]
[IsNumeric]
[ObservableProperty]
private double offsetX = 0;
[ObservableProperty]
[Required(ErrorMessage = "不可为空")]
[IsNumeric]
private double offsetY = 0;
[Required(ErrorMessage = "不可为空")]
[IsNumeric]
[Minimum(0.5)]
[ObservableProperty]
[NotifyDataErrorInfo]
private double precision = 1.0;
//private List<ElementId> previewIds = [];
[ObservableProperty]
private List<FamilySymbol> profileFamilyTypes;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateTrackCommand))]
private FamilySymbol selectedFamilyType;
[ObservableProperty]
private Material selectedMaterial;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateTrackCommand))]
private FamilySymbol selectedProfileFamilyType;
[Required(ErrorMessage = "不可为空")]
[IsNumeric]
[Minimum(100)]
[NotifyDataErrorInfo]
[ObservableProperty]
private double spacing = 100;
public ModelByCurveCreatorViewModel(Document doc)
{
handler = new();
profileFamilyTypes = [.. doc.OfClass<FamilySymbol>()
.OfCategory(BuiltInCategory.OST_ProfileFamilies)
.Cast<FamilySymbol>()
.OrderBy(n => n.FamilyName)];
familyTypes = [.. doc.OfClass<FamilySymbol>()
.OfType<FamilySymbol>()
.Where(
s =>
s.Category.Parent == null
&& s.Family.IsEditable
&& s.Family.IsUserCreated
&& s.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBased
)
.OrderBy(n => n.FamilyName)];
materials = doc.OfClass<Material>().OrderBy(n => n.Name).OfType<Material>().ToList();
}
[RelayCommand]
private void ClearFmailyTypeSelection()
{
if (SelectedFamilyType != null)
SelectedFamilyType = null;
}
[RelayCommand]
private void ClearMaterialSelection()
{
if (SelectedMaterial != null)
SelectedMaterial = null;
}
[RelayCommand]
private void ClearProfilesSelection()
{
if (SelectedProfileFamilyType != null)
SelectedProfileFamilyType = null;
}
[RelayCommand(CanExecute = nameof(CanCreate))]
private void CreateTrack()
{
handler.Raise(uiapp =>
{
var UiDocument = uiapp.ActiveUIDocument;
var doc = UiDocument.Document;
List<Curve> curves = null;
try
{
IsRunning = true;
switch (CenterCurveType)
{
case CenterCurveType.ModelCurve:
{
var refers = UiDocument.Selection.PickObjects(
ObjectType.Element,
new GenericFilter<ModelCurve>(),
"请选择模型线并完成选择"
);
curves = refers.Select(r => doc.GetElement(r)).OfType<ModelCurve>().Select(mc => mc.GeometryCurve).ToList();
var loops = SpatialAssist.ToCurveLoops(curves);
if (loops.Count != 1)
{
MessageBox.Show("未选择路径或所选线条不止一条路径", "错误");
IsRunning = false;
return;
}
curves = loops.FirstOrDefault();
break;
}
case CenterCurveType.MassCurve:
{
var refer = UiDocument.Selection.PickObject(
ObjectType.Element,
new FuncFilter(e => e is FamilyInstance importInstance && importInstance.Category.ToBuiltInCategory() == BuiltInCategory.OST_Mass),
"请选择仅包含一条连续曲线的体量族"
);
var instance = doc.GetElement(refer) as FamilyInstance;
var geo = instance.GetGeometryObjects().FirstOrDefault();
if (geo is GeometryInstance geometryInstance)
{
curves = geometryInstance.GetInstanceGeometry().Where(g => g is Curve).Cast<Curve>().ToList();
}
break;
}
case CenterCurveType.DWGCurve:
{
var refer = UiDocument.Selection.PickObject(
ObjectType.Element,
new FuncFilter(e => e is ImportInstance importInstance && importInstance.Category.Name.EndsWith(".dwg")),
"请选择dwg实例"
);
var importInstance = doc.GetElement(refer) as ImportInstance;
//curves = importInstance.GetCurves();
var geo = importInstance.GetGeometryObjects().FirstOrDefault();
if (geo is GeometryInstance geometryInstance)
{
var polyLine = geometryInstance.GetInstanceGeometry().FirstOrDefault() as PolyLine;
curves = [polyLine.ConverToHermiteSpline()];
}
break;
}
default:
break;
}
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
IsRunning = false;
return;
}
try
{
if ((curves != null) && (curves.Count > 1))
{
var loop = CurveLoop.Create(curves);
if (!loop.IsOpen())
{
MessageBox.Show("选择的模型线是闭合的,无法使用", "提示");
IsRunning = false;
return;
}
var cs = loop.GetEnumerator();
curves = [];
while (cs.MoveNext())
{
curves.Add(cs.Current);
}
}
}
catch (Autodesk.Revit.Exceptions.ArgumentException)
{
MessageBox.Show("所选模型线不连续或包含螺旋线", "错误");
IsRunning = false;
return;
}
List<XYZ> points = [];
var imperial = Precision * 1000 / 304.8;
for (var i = 0; i < curves.Count; i++)
{
var curve = curves[i];
var divide = (int)Math.Floor(curve.Length / imperial);
//长度小于最小细分间距
//始终都会添加起始点
if (divide == 0)
{
points.Add(curve.Evaluate(0, true));
}
else
{
for (double j = 0; j < divide; j++)
{
var x = j / divide;
points.Add(curve.Evaluate(x, true));
}
}
}
points.Add(curves.Last().GetEndPoint(1));
var planePoints = points.Select(p => p.Flatten()).ToList();
var spline3D = HermiteSpline.Create(points, false);
doc.InvokeGroup(
_ =>
{
try
{
if (SelectedFamilyType != null)
{
doc.Invoke(
_ =>
{
var horizonSpline = HermiteSpline.Create(planePoints, false);
if (!SelectedFamilyType.IsActive)
{
SelectedFamilyType.Activate();
}
var level = new FilteredElementCollector(doc)
.OfClass(typeof(Level))
.Cast<Level>()
.FirstOrDefault(l => Math.Abs(l.Elevation) < 0.00001);
List<Autodesk.Revit.Creation.FamilyInstanceCreationData> dataList = [];
var spacing = Spacing / 304.8;
var x = InstanceOffsetX / 304.8;
var y = InstanceOffsetY / 304.8;
var n = Math.Floor(horizonSpline.Length / spacing);
for (var i = 0; i < n; i++)
{
//XYZ pointSplie = spline3D.Evaluate(spacing * i, false);
var pointxoy = horizonSpline.Evaluate(spacing * i, false);
var unboundLine = Line.CreateUnbound(pointxoy, XYZ.BasisZ);
var point = unboundLine.IntersectionPoint(spline3D);
var transform = spline3D.ComputeDerivatives(spacing * i, false);
//族的参考方向
var referVector = transform.BasisX.CrossProduct(XYZ.BasisZ);
if (IsTwoSides)
{
var locLeft = point.Add(-referVector.Normalize() * x) + y * XYZ.BasisZ;
Autodesk.Revit.Creation.FamilyInstanceCreationData data1 =
new(
locLeft,
SelectedFamilyType,
referVector,
level,
Autodesk.Revit.DB.Structure.StructuralType.Footing
);
dataList.Add(data1);
}
var loc = point.Add(referVector.Normalize() * x) + y * XYZ.BasisZ;
Autodesk.Revit.Creation.FamilyInstanceCreationData data =
new(
loc,
SelectedFamilyType,
referVector,
level,
Autodesk.Revit.DB.Structure.StructuralType.Footing
);
dataList.Add(data);
}
doc.Create.NewFamilyInstances2(dataList);
},
"创建轨枕"
);
}
}
catch (Exception ex)
{
ex.StackTrace.ToLog();
//曲线之间的过度可能不平滑,平面点在三维点交点point==null
MessageBox.Show(ex.Message, "实例布置失败", MessageBoxButton.OK, MessageBoxImage.Error);
IsRunning = false;
}
Document familyDocument = null;
try
{
if (SelectedProfileFamilyType == null)
{
IsRunning = false;
return;
}
var point = spline3D.GetEndPoint(0);
//非刚性变换,会改变原几何,此变换在曲线计算导数时为非刚性变换各个basis的模不等于1
var transform = spline3D.ComputeDerivatives(0, false);
familyDocument = doc.EditFamily(SelectedProfileFamilyType.Family);
var tangent = transform.BasisX.Normalize();
var rightBasis = tangent.CrossProduct(XYZ.BasisZ).Normalize();
var topBasis = rightBasis.CrossProduct(tangent).Normalize();
if (!XYZ.IsWithinLengthLimits(point))
{
MessageBox.Show("点不在Revit模型空间内,内部原点坐标与模型线相距太远", "错误");
return;
}
//var d0 = transform.BasisX.CrossProduct(XYZ.BasisZ).DotProduct(transform.BasisX);
//var translate = Transform.CreateTranslation(transform.Origin);
//var rotate = Transform.CreateRotationAtPoint(
// -rightBasis,
// XYZ.BasisZ.AngleTo(transform.BasisX),
// XYZ.Zero);
//double det = transform.Determinant;
//Transform profileTransform = rotate.Multiply(translate);
//构造放样截面的变换
var profileTransform = Transform.Identity;
profileTransform.Origin = point;
profileTransform.BasisX = rightBasis;
profileTransform.BasisY = topBasis;
profileTransform.BasisZ = tangent;
//偏移变换
var offsetTransform = Transform.CreateTranslation(new XYZ(OffsetX, OffsetY, 0) / 304.8);
//修改类型以适应选择的族类型,保证几何与族类型一致
familyDocument.Invoke(_ =>
{
var fm = familyDocument.FamilyManager;
foreach (FamilyType type in fm.Types)
{
if (type.Name == SelectedProfileFamilyType.Name)
{
fm.CurrentType = type;
break;
}
}
});
//获取截面
var profiles = familyDocument
.OfClass<CurveElement>()
.OfType<CurveElement>()
.Select(c => c.GeometryCurve)
.ToList();
#if DEBUG
//famdoc.Invoke(_ =>
//{
//var plane = Plane.CreateByOriginAndBasis(point, rightBasis, topBasis);
// SketchPlane sketch = SketchPlane.Create(
// famdoc,
// plane)
// );
// var mc = famdoc.Create.NewModelCurve(spline3D, sketch);
//});
#endif
//famdoc.Invoke(
// _ =>
// {
// SketchPlane sketch = SketchPlane.Create(famdoc, Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero));
// foreach (var item in profiles)
// {
// var mc = famdoc.Create.NewModelCurve(item, sketch);
// }
// });
doc.Invoke(
_ =>
{
//if (!SelectedProfileFamilyType.IsActive)
//{
// SelectedProfileFamilyType.Activate();
//}
//if (loop.IsOpen())
//{
// return;
//}
//familyDocument.FamilyCreate.NewSweep
Solid solidAnother = null;
var options = new SolidOptions(
SelectedMaterial == null ? ElementId.InvalidElementId : SelectedMaterial.Id,
ElementId.InvalidElementId
);
//获取截面的曲线集合
var list = SpatialAssist.ToCurveLoops(profiles);
//生成截面线串
var loops = list.Select(cs => CurveLoop.Create(cs)).ToList();
//两侧放在前面,先复制
if (IsTwoSides)
{
var loopsAnother = new List<CurveLoop>();
var offsetTransformAnother = Transform.CreateTranslation(new XYZ(-OffsetX, OffsetY, 0) / 304.8);
//var offsetTransformAnother = Transform.CreateReflection(Plane.CreateByNormalAndOrigin(XYZ.BasisX, XYZ.Zero));
foreach (var item in loops)
{
loopsAnother.Add(CurveLoop.CreateViaCopy(item));
}
foreach (var item in loopsAnother)
{
item.Transform(offsetTransformAnother);
item.Transform(profileTransform);
}
solidAnother = GeometryCreationUtilities.CreateFixedReferenceSweptGeometry(
CurveLoop.Create([spline3D]),
0,
0,
loopsAnother,
XYZ.BasisZ,
options
);
}
foreach (var item in loops)
{
item.Transform(offsetTransform);
item.Transform(profileTransform);
}
//foreach (var item in loops)
//{
// foreach (var curve in item)
// {
// previewIds.Add(DebugAssist.CreateTransientGeometries(doc, curve));
// }
//}
//var solid = GeometryCreationUtilities.CreateSweptGeometry(
// CurveLoop.Create([spline3D]),
// 0,
// 0,
// loops,
// options);
var solid = GeometryCreationUtilities.CreateFixedReferenceSweptGeometry(
CurveLoop.Create([spline3D]),
0,
0,
loops,
XYZ.BasisZ,
options
);
var geos = new List<GeometryObject>() { solid };
if (IsTwoSides && solidAnother != null)
{
geos.Add(solidAnother);
}
var shape = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
shape.SetShape(geos);
},
"曲线布置"
);
IsRunning = false;
familyDocument.Close(false);
//spline3D.CreateOffset();
//SketchPlane sketch = SketchPlane.Create(Document, Plane.CreateByNormalAndOrigin(p4, p1));
//var mc = Document.Create.NewModelCurve(spline3D, sketch);
}
catch (Exception ex)
{
familyDocument?.Close(false);
ex.StackTrace.ToLog();
MessageBox.Show(ex.Message, "轮廓放样失败", MessageBoxButton.OK, MessageBoxImage.Error);
IsRunning = false;
}
},
"基于曲线创建模型"
);
});
}
partial void OnCenterCurveTypeChanged(CenterCurveType value)
{
switch (value)
{
case CenterCurveType.ModelCurve:
Precision = 1;
break;
case CenterCurveType.MassCurve:
Precision = 1;
break;
case CenterCurveType.DWGCurve:
Precision = 2;
break;
default:
break;
}
}
private bool CanCreate => !IsRunning && !HasErrors && (SelectedProfileFamilyType != null || SelectedFamilyType != null);
//public double Precision
//{
// get { return precision; }
// set { SetProperty(ref precision, value, true); }
//}
//public double Spacing
//{
// get { return spacing; }
// set { SetProperty(ref spacing, value, true); }
//}
}
public enum CenterCurveType
{
ModelCurve,
MassCurve,
DWGCurve,
}
}

View File

@@ -0,0 +1,105 @@
using System.Diagnostics;
using ACadSharp.Entities;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using Nice3point.Revit.Toolkit.External;
namespace Sai.RvKits.RvCommon;
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class ModifyModelParams : ExternalCommand
{
public override void Execute()
{
var elems = UiDocument.SelectObjects<FamilyInstance>();
if (elems == null)
{
return;
}
var textRefer = UiDocument.Selection.PickObject(ObjectType.PointOnElement, "请选择管线标注文字");
var dwg = Document.GetElement(textRefer) as ImportInstance;
var textLayerName = dwg.GetLayerName(textRefer);
var path = dwg.GetDwgPath();
var dwgTransform = dwg!.GetTransform();
Document.Invoke(_ =>
{
using ACadSharp.IO.DwgReader reader = new(path);
var cadDocument = reader.Read();
var textEntities = cadDocument.Entities.OfType<TextEntity>().Where(e => e.Layer.Name == textLayerName).ToList();
double topOffset = default;
double bottomOffset = default;
foreach (var familyInstance in elems)
{
string str1 = default;
string str2 = default;
//XYZ p1 = default;
//XYZ p2 = default;
var loc = familyInstance.GetLocXYZ();
var smallest = double.MaxValue;
var secondSmallest = double.MaxValue;
foreach (var entity in textEntities)
{
if (!double.TryParse(entity.Value, out var _))
{
continue;
}
var xyz = new XYZ(entity.InsertPoint.X, entity.InsertPoint.Y, entity.InsertPoint.Z) / 304.8;
var ofPoint = dwgTransform.OfPoint(xyz);
//同一平面
var point = new XYZ(ofPoint.X, ofPoint.Y, loc.Z);
var temp = point.DistanceTo(loc);
if (temp < smallest)
{
str2 = str1;
str1 = entity.Value;
//p2 = p1;
//p1 = point;
secondSmallest = smallest;
smallest = temp;
}
else if (temp < secondSmallest)
{
//p2 = point;
str2 = entity.Value;
secondSmallest = temp;
}
}
var b1 = double.TryParse(str1, out var d1);
var b2 = double.TryParse(str2, out var d2);
if (b1 && b2)
{
if (d1 > d2)
{
topOffset = d1;
bottomOffset = d2;
}
else
{
topOffset = d2;
bottomOffset = d1;
}
}
//Debug.WriteLine(topOffset * 1000 / 304.8);
//Debug.WriteLine(bottomOffset * 1000 / 304.8);
if ((topOffset - bottomOffset) * 1000 / 304.8 < Application.ShortCurveTolerance)
{
Debug.WriteLine(familyInstance.Id);
}
else
{
familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).Set(topOffset * 1000 / 304.8);
familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(bottomOffset * 1000 / 304.8);
}
}
});
}
}

View File

@@ -0,0 +1,16 @@
using Autodesk.Revit.DB;
using Nice3point.Revit.Toolkit.External;
using Sai.Toolkit.Core.Helpers;
namespace Sai.RvKits.RvCommon;
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class PipesCreatorCmd : ExternalCommand
{
public override void Execute()
{
WinDialogHelper.ShowModeless<PipesCreatorView>(new PipesCreatorViewModel(Document));
}
}

View File

@@ -0,0 +1,43 @@
<ex:FluentWindowEx
x:Class="Sai.RvKits.RvCommon.PipesCreatorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="https://github.com/sherlockforrest/Wpf.Ui.Extend"
xmlns:local="clr-namespace:Sai.RvKits.RvCommon"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="管道翻模"
Width="250"
Height="180"
MinWidth="250"
MinHeight="180"
d:DataContext="{d:DesignInstance Type=local:PipesCreatorViewModel}"
SizeToContent="Height"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Sai.RvKits;component/WPFUI.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<ex:AutoGrid ChildMargin="5" Columns="*">
<ex:ComboBoxEx
Grid.Row="0"
DisplayMemberPath="Name"
ItemsSource="{Binding PipeTypes}"
PlaceholderText="管线类型"
SelectedItem="{Binding SelectedPipeType}" />
<ex:ComboBoxEx
Grid.Row="1"
DisplayMemberPath="Name"
ItemsSource="{Binding PipingSystemTypes}"
PlaceholderText="系统类型"
SelectedItem="{Binding SelectedPipingSystemType}" />
<Button
Grid.Row="2"
HorizontalAlignment="Stretch"
Command="{Binding CreateCommand}"
Content="创建" />
</ex:AutoGrid>
</ex:FluentWindowEx>

View File

@@ -0,0 +1,17 @@
using System.Windows;
using Wpf.Ui.Controls;
namespace Sai.RvKits.RvCommon
{
/// <summary>
/// PipesCreatorView.xaml 的交互逻辑
/// </summary>
public partial class PipesCreatorView
{
public PipesCreatorView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,272 @@
using System.IO;
using System.Text;
using ACadSharp.Entities;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI.Selection;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
namespace Sai.RvKits.RvCommon;
public partial class PipesCreatorViewModel : ObservableObject
{
public PipesCreatorViewModel(Document document)
{
this.document = document;
}
private readonly ActionEventHandler createHandler = new();
private readonly Document document;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateCommand))]
private PipeType selectedPipeType;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateCommand))]
private PipingSystemType selectedPipingSystemType;
public IList<PipeType> PipeTypes => document.OfClass<PipeType>().Cast<PipeType>().ToList();
public IList<PipingSystemType> PipingSystemTypes => document.OfClass<PipingSystemType>().Cast<PipingSystemType>().ToList();
private bool CanCreate()
{
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
return SelectedPipeType != null && SelectedPipingSystemType != null;
}
[RelayCommand(CanExecute = nameof(CanCreate))]
private void Create()
{
createHandler.Raise(uiapp =>
{
var application = uiapp.Application;
var uiDocument = uiapp.ActiveUIDocument;
var doc = uiDocument.Document;
Reference reference;
Reference textRefer;
try
{
reference = uiDocument.Selection.PickObject(
ObjectType.PointOnElement,
new FuncFilter(e => e is ImportInstance import && import.IsLinked && doc.GetElement(e.GetTypeId()) is CADLinkType),
"请选择dwg管线图层"
);
//图层ID
textRefer = uiDocument.Selection.PickObject(ObjectType.PointOnElement, new FuncFilter(e => e is ImportInstance import && import.IsLinked && doc.GetElement(e.GetTypeId()) is CADLinkType), "请选择管线标注文字");
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
return;
}
var dwg = doc.GetElement(reference) as ImportInstance;
var pipeLayerName = dwg.GetLayerName(reference);
var textLayerName = dwg.GetLayerName(textRefer);
//SketchPlane sketchPlane = SketchPlane.Create(Document, Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero));
doc.Invoke(_ =>
{
var curve = dwg!.GetGeometryObjectFromReference(reference);
var text = dwg.GetGeometryObjectFromReference(textRefer);
doc.ActiveView.SetCategoryHidden(curve.GraphicsStyleId, false);
doc.ActiveView.SetCategoryHidden(text.GraphicsStyleId, false);
});
var path = dwg.GetDwgPath();
using ACadSharp.IO.DwgReader reader = new(path);
var cadDocument = reader.Read();
//var blocks = cadDocument.Entities.OfType<ACadSharp.Entities.Insert>().Where(e => e.Layer.Name == layerName).ToList();
var textEntities = cadDocument.Entities.OfType<TextEntity>().Where(e => e.Layer.Name == textLayerName).ToList();
var lwPolyLines = cadDocument.Entities.OfType<LwPolyline>().Where(e => e.Layer.Name == pipeLayerName).ToList();
var dwgTransform = dwg!.GetTransform();
StringBuilder sb = new();
doc.InvokeGroup(_ =>
{
foreach (var lwPolyline in lwPolyLines)
{
//if (n % 500 == 0)
//{
// var result = TaskDialog.Show("提示", $"已创建{n},是否继续?", TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No);
// if (result == TaskDialogResult.No)
// {
// break;
// }
//}
var v = lwPolyline.Vertices;
if (v.Count == 2)
{
var p1 = new XYZ(v[0].Location.X, v[0].Location.Y, 0) / 304.8;
var p2 = new XYZ(v[1].Location.X, v[1].Location.Y, 0) / 304.8;
if (p1.DistanceTo(p2) < application.ShortCurveTolerance)
{
continue;
}
var di = double.MaxValue;
TextEntity text = null;
var l = Autodesk.Revit.DB.Line.CreateBound(p1, p2);
foreach (var entity in textEntities)
{
try
{
var transform = Transform.CreateRotation(XYZ.BasisZ, entity.Rotation);
var rotationVector = transform.OfPoint(XYZ.BasisX);
if (entity.Value.StartsWith("DN") || entity.Value.StartsWith("De"))
{
var crossProduct = l.Direction.CrossProduct(rotationVector);
if (crossProduct.GetLength() < 0.05)
{
var xyz = new XYZ(entity.InsertPoint.X, entity.InsertPoint.Y, entity.InsertPoint.Z) / 304.8;
var ofPoint = dwgTransform.OfPoint(xyz);
//同一平面
var point = new XYZ(ofPoint.X, ofPoint.Y, 0);
var d = l.Distance(point);
if (d < di)
{
di = d;
text = entity;
}
}
}
}
catch (Exception)
{
// ignored
}
}
doc.Invoke(
_ =>
{
//var pipeDiameter = Regex.Match(text.Value, @"(?<=DN)\d+");
//if (pipeDiameter.Length > 0)
//{
// var diameter = Convert.ToDouble(pipeDiameter.Value) / 304.8;
// pipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(diameter);
//}
//var elevation = Regex.Match(text.Value, @"(?<=\+)(\d|\.)+");
//if (elevation.Length > 0)
//{
// var h = Convert.ToDouble(elevation.Value) * 1000 / 304.8;
// pipe.get_Parameter(BuiltInParameter.RBS_OFFSET_PARAM).Set(h);
//}
p1 = dwgTransform.OfPoint(p1);
p2 = dwgTransform.OfPoint(p2);
var newPipe = Pipe.Create(doc, SelectedPipingSystemType.Id, SelectedPipeType.Id, doc.ActiveView.GenLevel.Id, p1, p2);
doc.Regenerate();
if (text != null)
{
var diameter = string.Empty;
//string slope = string.Empty;
//var splitStrings = text.Value.Split(' ');
//foreach (var str in splitStrings)
//{
// var str1 = str.Trim();
// if (str1.Contains("DN"))
// {
// diameter = str.TrimStart("DN".ToCharArray());
// }
// else if (str1.Contains("De"))
// {
// diameter = str.TrimStart("De".ToCharArray());
// }
// if (str1.Contains("i="))
// {
// slope = str.TrimStart("i=".ToCharArray());
// }
//}
if (double.TryParse(diameter, out var d))
{
newPipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(d / 304.8);
}
//if (double.TryParse(slope, out var s))
//{
// newPipe.get_Parameter(BuiltInParameter.RBS_PIPE_SLOPE).Set(s);
//}
}
else
{
sb.AppendLine($"{newPipe.Id}");
}
// ElementTransformUtils.MoveElement(Document, newPipe.Id, move);
//n++;
},
"创建管线"
);
doc.Invoke(_ =>
{
var mepCurves = doc.OfClass<MEPCurve>()
.Where(p => p is not InsulationLiningBase and not FlexPipe and not FlexDuct)
.ToList();
foreach (var mep in mepCurves)
{
foreach (var mep1 in mepCurves)
{
if (
mep.Id != mep1.Id
&& !mep.GetConnectors(true).IsEmpty
&& !mep1.GetConnectors(true).IsEmpty
&& mep.GetType() == mep1.GetType()
)
{
var connectors = ConnectorAssist.GetNearestConnectors(mep, mep1);
if (connectors.Count == 2 && connectors[0].Origin.IsAlmostEqualTo(connectors[1].Origin))
{
connectors[0].ConnectByFitting(connectors[1]);
}
}
}
}
});
}
}
});
if (sb.Length > 0)
{
var filePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\问题管线.txt";
File.WriteAllText(filePath, sb.ToString());
System.Diagnostics.Process.Start(filePath);
}
//UiDocument.Selection.SetElementIds(ids);
//using (Transaction name = new Transaction(Document, "tsname"))
//{
// name.Start();
// for (int i = 0; i < 20; i++)
// {
// var block = blocks[i];
// var loc = new XYZ(block.InsertPoint.X / 304.8, block.InsertPoint.Y / 304.8, 0);
// //var loc = dwg.GetTransform().Origin;
// if (!instance.Symbol.IsActive)
// {
// instance.Symbol.Activate();
// }
// var fi = Document.Create.NewFamilyInstance(loc, instance.Symbol, view.GenLevel, StructuralType.NonStructural);
// Document.Regenerate();
// ElementTransformUtils.MoveElement(Document,fi.Id,move);
// }
// name.Commit();
//}
});
}
}

View File

@@ -0,0 +1,51 @@
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using eTransmitForRevitDB;
using Nice3point.Revit.Toolkit.External;
namespace Sai.RvKits.RvCommon;
/// <summary>
/// Revit执行命令
/// </summary>
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class PureModelCmd : ExternalCommand
{
public override void Execute()
{
if (string.IsNullOrEmpty(Document.PathName))
{
System.Windows.MessageBox.Show("请先保存文件");
return;
}
var options = new SaveAsOptions()
{
Compact = true,
OverwriteExistingFile = true,
MaximumBackups = 3
};
for (var i = 0; i < 5; i++)
{
Purge(Document);
}
Document.SaveAs(Document.PathName, options);
System.Windows.MessageBox.Show("清理完成", "提示");
}
/// <summary>
/// 使用eTransmitForRevitDB清理文档未使用项
/// </summary>
/// <param name="doc"></param>
/// <returns></returns>
public static bool Purge(Document doc)
{
var eTransmitUpgradeOMatic = new eTransmitUpgradeOMatic(doc.Application);
var result = eTransmitUpgradeOMatic.purgeUnused(doc);
return result == UpgradeFailureType.UpgradeSucceeded;
}
}