添加项目文件。
This commit is contained in:
28
Szmedi.RvKits/Modeling/InstanceCreatorCmd.cs
Normal file
28
Szmedi.RvKits/Modeling/InstanceCreatorCmd.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
namespace Szmedi.RvKits.Modeling
|
||||
{
|
||||
/// <summary>
|
||||
/// Revit执行命令
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
|
||||
public class InstanceCreatorCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogAssists.ShowOrActivate<InstanceCreatorWin, InstanceCreatorViewModel>(UiApplication);
|
||||
|
||||
//InstanceCreatorWin win = WpfSingletonHelper<InstanceCreatorWin>.GetInstance(out bool isNewCreate);
|
||||
//if (isNewCreate)
|
||||
//{
|
||||
// win.DataContext = new InstanceCreatorViewModel(UiApplication);
|
||||
// win.ShowAhead();
|
||||
//}
|
||||
//win.Activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
461
Szmedi.RvKits/Modeling/InstanceCreatorViewModel.cs
Normal file
461
Szmedi.RvKits/Modeling/InstanceCreatorViewModel.cs
Normal file
@@ -0,0 +1,461 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
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 Microsoft.Win32;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
using SZMCToolkit.RevitAddins.Assists;
|
||||
|
||||
using Szmedi.RvKits.Assists;
|
||||
|
||||
namespace Szmedi.RvKits.Modeling;
|
||||
|
||||
public partial class InstanceCreatorViewModel : ObservableObject
|
||||
{
|
||||
public InstanceCreatorViewModel(UIApplication uiapp)
|
||||
{
|
||||
uiDocument = uiapp.ActiveUIDocument;
|
||||
document = uiDocument.Document;
|
||||
Families = new FilteredElementCollector(document)
|
||||
.OfClass(typeof(Family))
|
||||
.Cast<Family>()
|
||||
.Where(
|
||||
f =>
|
||||
f.IsEditable
|
||||
&& !f.IsInPlace
|
||||
&& f.GetFamilySymbolIds().Any()
|
||||
&& f.FamilyCategory.Id != BuiltInCategory.OST_PipeFitting.GetElementId(document)
|
||||
&& f.FamilyCategory.Id != BuiltInCategory.OST_DuctFitting.GetElementId(document)
|
||||
&& f.FamilyCategory.Id != BuiltInCategory.OST_CableTrayFitting.GetElementId(document)
|
||||
&& f.FamilyCategory.Id != BuiltInCategory.OST_ConduitFitting.GetElementId(document)
|
||||
&& f.FamilyCategory.GetHashCode() != -2000127 //过滤掉栏杆族
|
||||
&& f.FamilyPlacementType
|
||||
is FamilyPlacementType.OneLevelBased
|
||||
or FamilyPlacementType.TwoLevelsBased
|
||||
or FamilyPlacementType.WorkPlaneBased
|
||||
).OrderBy(f => f.Name);
|
||||
FamiliesView = CollectionViewSource.GetDefaultView(Families);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void PreviewTextInput(TextCompositionEventArgs args)
|
||||
{
|
||||
if (args != null && args.Source is System.Windows.Controls.ComboBox cb)
|
||||
{
|
||||
if (cb.Text == cb.SelectedItem?.ToString())
|
||||
{
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ActionEventHandler handler = new();
|
||||
private readonly Document document;
|
||||
private readonly UIDocument uiDocument;
|
||||
|
||||
[ObservableProperty]
|
||||
private BitmapSource image;
|
||||
|
||||
[ObservableProperty]
|
||||
private string searchText;
|
||||
partial void OnSearchTextChanged(string value)
|
||||
{
|
||||
if (Families != null)
|
||||
{
|
||||
FamiliesView.Filter = item =>
|
||||
{
|
||||
if (item is Family family)
|
||||
{
|
||||
return family.Name.Contains(value);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
FamiliesView.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CloseWinCommand))]
|
||||
private bool canPlace;
|
||||
|
||||
[ObservableProperty]
|
||||
private double offset;
|
||||
|
||||
[ObservableProperty]
|
||||
private Family selectedFamily;
|
||||
|
||||
[ObservableProperty]
|
||||
private FamilySymbol selectedFamilySymbol;
|
||||
|
||||
[ObservableProperty]
|
||||
private IEnumerable<Family> families;
|
||||
public ICollectionView FamiliesView { get; set; }
|
||||
[ObservableProperty]
|
||||
private IEnumerable<FamilySymbol> familySymbols;
|
||||
|
||||
[ObservableProperty]
|
||||
private List<RelatedProp> relatedProps;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanPlace))]
|
||||
private void CloseWin()
|
||||
{
|
||||
var d = Offset / 304.8;
|
||||
try
|
||||
{
|
||||
var reference = uiDocument.Selection.PickObject(
|
||||
ObjectType.PointOnElement,
|
||||
new DwgBlockSelection(),
|
||||
"请选择dwg块"
|
||||
);
|
||||
//图层ID;
|
||||
//doc.HideDwgLayer(reference, out ElementId columnGraphicStyleId, out GeometryElement columnGeoElem);
|
||||
var dwg = document.GetElement(reference) as ImportInstance;
|
||||
var geoInstances = dwg.GetBlockInstance(reference);
|
||||
if (geoInstances == null || !geoInstances.Any())
|
||||
{
|
||||
MessageBox.Show("选中块为嵌套子块或选中块的嵌套层级过深,请使用Tab来选择整体块", "识别错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
CanPlace = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var dwgTransform = dwg!.GetTotalTransform();
|
||||
handler.Raise(_ =>
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var instances = new List<FamilyInstance>();
|
||||
document.InvokeGroup(_ =>
|
||||
{
|
||||
document.Invoke(_ =>
|
||||
{
|
||||
if (!SelectedFamilySymbol.IsActive)
|
||||
{
|
||||
SelectedFamilySymbol.Activate();
|
||||
}
|
||||
|
||||
switch (SelectedFamily.FamilyPlacementType)
|
||||
{
|
||||
case FamilyPlacementType.OneLevelBased:
|
||||
foreach (var ins in geoInstances)
|
||||
{
|
||||
var level = uiDocument.ActiveView.GenLevel;
|
||||
|
||||
GetLocating(dwgTransform, ins, out var loc, out var rotation);
|
||||
var familyInstance =
|
||||
document.Create.NewFamilyInstance(loc, SelectedFamilySymbol, 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);
|
||||
instances.Add(familyInstance);
|
||||
}
|
||||
|
||||
break;
|
||||
case FamilyPlacementType.OneLevelBasedHosted:
|
||||
//foreach (var ins in geoInstances)
|
||||
//{
|
||||
// var level = uiDocument.ActiveView.GenLevel;
|
||||
|
||||
// GetLocating(dwgTransform, ins, out var loc, out var rotation);
|
||||
// var familyInstance =
|
||||
// doc.Create.NewFamilyInstance(loc, SelectedFamilySymbol, level, level, StructuralType.NonStructural);
|
||||
// doc.Regenerate();
|
||||
// ElementTransformUtils.RotateElement(
|
||||
// doc,
|
||||
// familyInstance.Id,
|
||||
// Line.CreateUnbound(loc, XYZ.BasisZ),
|
||||
// rotation
|
||||
// );
|
||||
// doc.Regenerate();
|
||||
// var translation = XYZ.BasisZ * d;
|
||||
// ElementTransformUtils.MoveElement(doc, familyInstance.Id, translation);
|
||||
// instances.Add(familyInstance);
|
||||
//}
|
||||
break;
|
||||
case FamilyPlacementType.TwoLevelsBased:
|
||||
foreach (var ins in geoInstances)
|
||||
{
|
||||
var level = uiDocument.ActiveView.GenLevel;
|
||||
GetLocating(dwgTransform, ins, out var loc, out var rotation);
|
||||
var familyInstance =
|
||||
document.Create.NewFamilyInstance(loc, SelectedFamilySymbol, 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);
|
||||
instances.Add(familyInstance);
|
||||
}
|
||||
|
||||
break;
|
||||
case FamilyPlacementType.WorkPlaneBased:
|
||||
foreach (var ins in geoInstances)
|
||||
{
|
||||
GetLocating(dwgTransform, ins, out var loc, out var rotation);
|
||||
var familyInstance = document.Create.NewFamilyInstance(
|
||||
loc,
|
||||
SelectedFamilySymbol,
|
||||
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);
|
||||
instances.Add(familyInstance);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
var propsModify = RelatedProps.Where(p => p.IsChecked && !string.IsNullOrEmpty(p.LayerName)).ToList();
|
||||
if (propsModify.Any())
|
||||
{
|
||||
document.Invoke(_ =>
|
||||
{
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
var box = instance.get_BoundingBox(document.ActiveView);
|
||||
var center = (box.Max + box.Min) / 2;
|
||||
var loc = center.Flatten();
|
||||
foreach (var prop in propsModify)
|
||||
{
|
||||
var param = instance.GetParameters(prop.Name).FirstOrDefault();
|
||||
if (param == null)
|
||||
{
|
||||
sb.AppendLine($"族实例:{instance.Name}不存在参数\"{prop.Name}\"");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (param.IsReadOnly)
|
||||
{
|
||||
sb.AppendLine($"族实例:{instance.Name}的\"{prop.Name}\"为只读参数:");
|
||||
continue;
|
||||
}
|
||||
|
||||
var texts = dwg.GetTextsByLayer(prop.LayerName);
|
||||
var keyValue = texts.OrderBy(text => text.Value.Flatten().DistanceTo(loc)).First();
|
||||
if (keyValue.Value.Flatten().DistanceTo(loc) > 10)
|
||||
{
|
||||
sb.AppendLine($"标注文字与族实例\"{instance.Name}-{instance.Id}\"距离过远,可能有误");
|
||||
}
|
||||
|
||||
param.SetValue(keyValue.Key);
|
||||
//param.Set(keyValue.Key);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
MessageBox.Show(sb.ToString(), "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
|
||||
var result = MessageBox.Show("布置完成,是否导出布置结果以供检查?", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.OK)
|
||||
{
|
||||
SaveFileDialog dialog = new()
|
||||
{
|
||||
Filter = WinDialogAssists.CreateFilter("Csv文件", "csv"),
|
||||
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
|
||||
};
|
||||
if (dialog.ShowDialog() != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var excel = dialog.FileName;
|
||||
//FileInfo fi = new(excel);
|
||||
//using ExcelPackage package = new(fi);
|
||||
//ExcelPackage excelPackage = Instances.ToWorksheet("< 1950")
|
||||
// .WithConfiguration(configuration => configuration.WithColumnConfiguration(x => x.AutoFit()))
|
||||
// .WithColumn(x => x.FirstName, "First Name")
|
||||
// .WithColumn(x => x.LastName, "Last Name")
|
||||
// .WithColumn(x => x.YearBorn, "Year of Birth")
|
||||
// .WithTitle("< 1950")
|
||||
// .NextWorksheet(post50, "> 1950")
|
||||
// .WithColumn(x => x.LastName, "Last Name")
|
||||
// .WithColumn(x => x.YearBorn, "Year of Birth")
|
||||
// .WithTitle("> 1950")
|
||||
// .ToExcelPackage();
|
||||
using (StreamWriter writer = new(excel, false, Encoding.UTF8))
|
||||
{
|
||||
writer.Write("族名称,族实例,元素Id");
|
||||
foreach (var prop in RelatedProps)
|
||||
{
|
||||
writer.Write($",{prop.Name}");
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
writer.Write($"{instance.Symbol.FamilyName},{instance.Name},{instance.Id.IntegerValue}");
|
||||
foreach (var prop in RelatedProps)
|
||||
{
|
||||
var param = instance.GetParameters(prop.Name).FirstOrDefault();
|
||||
if (param != null)
|
||||
{
|
||||
var value = param.GetValue();
|
||||
writer.Write($",{value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(",");
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteLine(); //换行
|
||||
}
|
||||
}
|
||||
|
||||
Process.Start(excel);
|
||||
}
|
||||
}, "族实例布置");
|
||||
});
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogAssists.WriteLog(ex.Message);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置元素几何变换
|
||||
/// </summary>
|
||||
/// <param name="dwgTransform"></param>
|
||||
/// <param name="ins"></param>
|
||||
/// <param name="loc"></param>
|
||||
/// <param name="rotation"></param>
|
||||
private static void GetLocating(Transform dwgTransform, GeometryInstance ins, out XYZ loc, out double rotation)
|
||||
{
|
||||
var blockLocation = ins.Transform.Origin;
|
||||
|
||||
if (ins.Transform.Origin.GetLength() is > 1000 or 0)
|
||||
{
|
||||
foreach (var geometryObject in ins.GetInstanceGeometry())
|
||||
{
|
||||
if (geometryObject is Arc arc)
|
||||
{
|
||||
blockLocation = arc.Center;
|
||||
break;
|
||||
}
|
||||
|
||||
if (geometryObject is PolyLine pl)
|
||||
{
|
||||
blockLocation = (pl.GetOutline().MaximumPoint + pl.GetOutline().MinimumPoint) / 2;
|
||||
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);
|
||||
}
|
||||
|
||||
//[RelayCommand]
|
||||
//private void AutoComplete(string searchText)
|
||||
//{
|
||||
// SelectedFamily = Families.FirstOrDefault(f => f.Name.Contains(searchText))!;
|
||||
//}
|
||||
partial void OnSelectedFamilyChanged(Family value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
FamilySymbols = value.GetFamilySymbolIds().Select(id => value.Document.GetElement(id)).OfType<FamilySymbol>();
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnSelectedFamilySymbolChanged(FamilySymbol value)
|
||||
{
|
||||
var map = FamilySymbols.FirstOrDefault()?.GetPreviewImage(new System.Drawing.Size(128, 128));
|
||||
if (map != null)
|
||||
{
|
||||
Image = map.ToBitmapSource();
|
||||
}
|
||||
|
||||
CanPlace = true;
|
||||
RelatedProps = new List<RelatedProp>();
|
||||
//var list = new List<RelatedProp>();
|
||||
//foreach (Parameter parameter in value.ParametersMap)
|
||||
//{
|
||||
// list.Add(new RelatedProp()
|
||||
// {
|
||||
// Id = parameter.Id.IntegerValue,
|
||||
// Name = parameter.Definition.Name,
|
||||
// PropertyType = "类型",
|
||||
// });
|
||||
//}
|
||||
//foreach (Parameter parameter in value.Parameters)
|
||||
//{
|
||||
// var found = list.Any(p => p.Id == parameter.Id.IntegerValue);
|
||||
// if (!found)
|
||||
// {
|
||||
// list.Add(new RelatedProp()
|
||||
// {
|
||||
// Id = parameter.Id.IntegerValue,
|
||||
// Name = parameter.Definition.Name,
|
||||
// PropertyType = "实例",
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
//RelatedProps = list;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void PickLayer(object prop)
|
||||
{
|
||||
try
|
||||
{
|
||||
var textRefer = uiDocument.Selection.PickObject(
|
||||
ObjectType.PointOnElement,
|
||||
new FuncFilter(e => e is ImportInstance import && import.IsLinked && document.GetElement(e.GetTypeId()) is CADLinkType),
|
||||
"请选择“链接(非导入)”的Cad文字图层");
|
||||
var dwg = document.GetElement(textRefer) as ImportInstance;
|
||||
var textLayerName = dwg.GetLayerName(textRefer);
|
||||
if (prop is RelatedProp relatedProp)
|
||||
{
|
||||
relatedProp.LayerName = textLayerName;
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Szmedi.RvKits/Modeling/InstanceCreatorWin.xaml
Normal file
110
Szmedi.RvKits/Modeling/InstanceCreatorWin.xaml
Normal file
@@ -0,0 +1,110 @@
|
||||
<controls:MaterialWindow
|
||||
x:Class="Szmedi.RvKits.Modeling.InstanceCreatorWin"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Szmedi.RvKits.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Szmedi.RvKits.Modeling"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
Title="族实例布置"
|
||||
Width="400"
|
||||
Height="400"
|
||||
MinHeight="300"
|
||||
d:DataContext="{d:DesignInstance local:InstanceCreatorViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<controls:MaterialWindow.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/Szmedi.RvKits;component/WPFUI.xaml" />
|
||||
</controls:MaterialWindow.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ComboBox
|
||||
Grid.Column="0"
|
||||
materialDesign:HintAssist.Hint="族名称"
|
||||
DisplayMemberPath="Name"
|
||||
Text="{Binding SearchText,UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEditable="True"
|
||||
ItemsSource="{Binding FamiliesView}"
|
||||
SelectedItem="{Binding SelectedFamily, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
|
||||
<!--<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="PreviewTextInput">
|
||||
<b:InvokeCommandAction Command="{Binding PreviewTextInputCommand}" PassEventArgsToCommand="True"/>
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>-->
|
||||
</ComboBox>
|
||||
<ComboBox
|
||||
Grid.Row="1"
|
||||
materialDesign:HintAssist.Hint="族类型"
|
||||
DisplayMemberPath="Name"
|
||||
IsSynchronizedWithCurrentItem="True"
|
||||
ItemsSource="{Binding FamilySymbols}"
|
||||
SelectedItem="{Binding SelectedFamilySymbol, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Width="64"
|
||||
Height="64"
|
||||
Margin="5"
|
||||
Source="{Binding Image}" />
|
||||
<TextBox Grid.Row="3" materialDesign:TextFieldAssist.PrefixText="偏移量:" materialDesign:TextFieldAssist.SuffixText="mm">
|
||||
<TextBox.Text>
|
||||
<Binding Path="Offset" UpdateSourceTrigger="PropertyChanged">
|
||||
<Binding.ValidationRules>
|
||||
<helper:DoubleValidationRule xmlns:helper="clr-namespace:Szmedi.Toolkit.Assists" ValidatesOnTargetUpdated="True" />
|
||||
</Binding.ValidationRules>
|
||||
</Binding>
|
||||
</TextBox.Text>
|
||||
</TextBox>
|
||||
<DataGrid
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
d:ItemsSource="{d:SampleData ItemCount=5}"
|
||||
AutoGenerateColumns="False"
|
||||
ItemsSource="{Binding RelatedProps}"
|
||||
ToolTip="根据提取的图层,就近将文字内容赋值给创建族实例的参数">
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn
|
||||
Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}"
|
||||
EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}"
|
||||
ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}"
|
||||
Header="是否赋值" />
|
||||
<DataGridTextColumn
|
||||
Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
|
||||
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"
|
||||
ElementStyle="{StaticResource MaterialDesignDataGridTextColumnStyle}"
|
||||
Header="参数名" />
|
||||
<DataGridTemplateColumn Header="选择图层">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button
|
||||
Command="{Binding DataContext.PickLayerCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
|
||||
CommandParameter="{Binding}"
|
||||
Content="{Binding LayerName, Mode=OneWay}"
|
||||
IsEnabled="{Binding IsChecked, Mode=OneWay}"
|
||||
Style="{StaticResource MaterialDesignPaperDarkButton}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<Button
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="85"
|
||||
Command="{Binding CloseWinCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
|
||||
Content="布置"
|
||||
ToolTip="选择dwg块并布置族实例" />
|
||||
</Grid>
|
||||
</controls:MaterialWindow>
|
||||
12
Szmedi.RvKits/Modeling/InstanceCreatorWin.xaml.cs
Normal file
12
Szmedi.RvKits/Modeling/InstanceCreatorWin.xaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Szmedi.RvKits.Modeling;
|
||||
|
||||
/// <summary>
|
||||
/// InstanceCreatorWin.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class InstanceCreatorWin
|
||||
{
|
||||
public InstanceCreatorWin()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
15
Szmedi.RvKits/Modeling/RelatedProp.cs
Normal file
15
Szmedi.RvKits/Modeling/RelatedProp.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
namespace Szmedi.RvKits.Modeling
|
||||
{
|
||||
public partial class RelatedProp : ObservableObject
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
[ObservableProperty]
|
||||
private string layerName;
|
||||
[ObservableProperty]
|
||||
private bool isChecked = false;
|
||||
public string PropertyType { get; set; }
|
||||
}
|
||||
}
|
||||
22
Szmedi.RvKits/Modeling/RelativeMoveCmd.cs
Normal file
22
Szmedi.RvKits/Modeling/RelativeMoveCmd.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
namespace Szmedi.RvKits.Modeling
|
||||
{
|
||||
/// <summary>
|
||||
/// Revit执行命令
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class RelativeMoveCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Szmedi.RvKits/Modeling/RoomNameAssignCmd.cs
Normal file
102
Szmedi.RvKits/Modeling/RoomNameAssignCmd.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Architecture;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
|
||||
|
||||
using Szmedi.RvKits.Assists;
|
||||
|
||||
namespace Szmedi.RvKits.Modeling
|
||||
{
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class RoomNameAssignCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
Document.Invoke(
|
||||
ts =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var reference = UiDocument.Selection.PickObject(ObjectType.PointOnElement, new GenericFilter<ImportInstance>(), "请选择CAD文字");
|
||||
var instance = Document.GetElement(reference) as ImportInstance;
|
||||
|
||||
var layerName = instance.GetLayerName(reference);
|
||||
List<KeyValuePair<string, XYZ>> layerTextPoints = instance.GetTextsByLayer(layerName);
|
||||
var rooms = ActiveView.OfCollector().OfCategory(BuiltInCategory.OST_Rooms).ToElements();
|
||||
var roomTags = ActiveView.OfCollector().OfCategory(BuiltInCategory.OST_RoomTags).Cast<RoomTag>();
|
||||
foreach (Room room in rooms)
|
||||
{
|
||||
var level = room.Level;
|
||||
var kv = layerTextPoints.FirstOrDefault(d => ContainsChinese(d.Key) && room.IsPointInRoom(d.Value.FlattenTo(level)));
|
||||
if (kv.Key != null)
|
||||
{
|
||||
//var flattenPoint = kv.Value.FlattenTo(level);
|
||||
|
||||
var tag = roomTags.FirstOrDefault(t => t.TaggedLocalRoomId == room.Id);
|
||||
if (tag == null)
|
||||
{
|
||||
var uv = new UV(kv.Value.X, kv.Value.Y);
|
||||
|
||||
Document.Create.NewRoomTag(new LinkElementId(room.Id), uv, ActiveView.Id);
|
||||
}
|
||||
|
||||
//var arc = Arc.Create(flattenPoint, 10, 0, 5, XYZ.BasisX, XYZ.BasisY);
|
||||
//Document.Create.NewModelCurve(arc, SketchPlane.Create(Document, level.Id));
|
||||
room.Name = kv.Key;
|
||||
}
|
||||
}
|
||||
//foreach (var kv in layerTextPoints)
|
||||
//{
|
||||
// var floor = ActiveView as ViewPlan;
|
||||
// var flattenPoint = kv.Value.FlattenTo(floor.GenLevel);
|
||||
|
||||
// var room = Document.GetRoomAtPoint(flattenPoint);
|
||||
|
||||
// if (room == null)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// var tag = roomTags.FirstOrDefault(t => t.TaggedLocalRoomId == room.Id);
|
||||
// if (tag == null)
|
||||
// {
|
||||
// var uv = new UV(kv.Value.X, kv.Value.Y);
|
||||
|
||||
// Document.Create.NewRoomTag(new LinkElementId(room.Id), uv, ActiveView.Id);
|
||||
// }
|
||||
|
||||
// var arc = Arc.Create(flattenPoint, 10, 0, 5, XYZ.BasisX, XYZ.BasisY);
|
||||
// Document.Create.NewModelCurve(arc, SketchPlane.Create(Document, floor.GenLevel.Id));
|
||||
// room.Name = kv.Key;
|
||||
//}
|
||||
}
|
||||
catch(Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
//用户取消操作
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
|
||||
}, "房间命名");
|
||||
}
|
||||
static bool ContainsChinese(string input)
|
||||
{
|
||||
// 正则表达式匹配汉字
|
||||
Regex regex = new Regex(@"[\u4e00-\u9fa5]");
|
||||
return regex.IsMatch(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Szmedi.RvKits/Modeling/TrackCreatorCmd.cs
Normal file
27
Szmedi.RvKits/Modeling/TrackCreatorCmd.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace Szmedi.RvKits.Modeling
|
||||
{
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
|
||||
internal class TrackCreatorCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogAssists.ShowOrActivate<TrackCreatorWin, TrackCreatorViewModel>(Document);
|
||||
|
||||
//var win = WpfSingletonHelper<TrackCreatorWin>.GetInstance(out var isNewCreate);
|
||||
//if (isNewCreate)
|
||||
//{
|
||||
// win.DataContext = new TrackCreatorViewModel(doc);
|
||||
// win.ShowAhead();
|
||||
//}
|
||||
//win.Activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
635
Szmedi.RvKits/Modeling/TrackCreatorViewModel.cs
Normal file
635
Szmedi.RvKits/Modeling/TrackCreatorViewModel.cs
Normal file
@@ -0,0 +1,635 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
using Szmedi.RvKits.Assists;
|
||||
using Szmedi.RvKits.Attributes;
|
||||
using Szmedi.RvKits.Properties;
|
||||
using Szmedi.Toolkit.Assists;
|
||||
|
||||
namespace Szmedi.RvKits.Modeling
|
||||
{
|
||||
public partial class TrackCreatorViewModel : ObservableValidator
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string searchProfileText;
|
||||
partial void OnSearchProfileTextChanged(string value)
|
||||
{
|
||||
if (ProfileFamilyTypes != null)
|
||||
{
|
||||
ProfileFamilyTypesView.Filter = obj =>
|
||||
{
|
||||
if (obj is FamilySymbol fs)
|
||||
{
|
||||
return fs.Name.Contains(value) || fs.FamilyName.Contains(value);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
ProfileFamilyTypesView.Refresh();
|
||||
}
|
||||
}
|
||||
[ObservableProperty]
|
||||
private string searchFamilyText;
|
||||
partial void OnSearchFamilyTextChanged(string value)
|
||||
{
|
||||
if (FamilyTypes != null)
|
||||
{
|
||||
FamilyTypesView.Filter = obj =>
|
||||
{
|
||||
if (obj is FamilySymbol fs)
|
||||
{
|
||||
return fs.Name.Contains(value) || fs.FamilyName.Contains(value);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
FamilyTypesView.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private CenterCurveType centerCurveType;
|
||||
|
||||
[ObservableProperty]
|
||||
private List<FamilySymbol> familyTypes;
|
||||
private readonly ActionEventHandler handler;
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[ObservableProperty]
|
||||
private double instanceOffsetX = 717.5;
|
||||
|
||||
[ObservableProperty]
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
private double instanceOffsetY = -216;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isModelCurve = true;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(CreateTrackCommand))]
|
||||
private bool isRunning;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isTwoSides = false;
|
||||
|
||||
[ObservableProperty]
|
||||
private List<Material> materials;
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[ObservableProperty]
|
||||
private double offsetX = 717.5;
|
||||
|
||||
[ObservableProperty]
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
private double offsetY = 0;
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[Minimum(0.5)]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private double precision = 1;
|
||||
|
||||
[ObservableProperty]
|
||||
private System.Windows.Media.ImageSource previewImage = Resources.TrackPic.ToBitmapSource();
|
||||
|
||||
[ObservableProperty]
|
||||
private List<FamilySymbol> profileFamilyTypes;
|
||||
|
||||
public ICollectionView ProfileFamilyTypesView { get; set; }
|
||||
public ICollectionView FamilyTypesView { get; set; }
|
||||
|
||||
[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 = 900;
|
||||
|
||||
public TrackCreatorViewModel(Document doc)
|
||||
{
|
||||
handler = new();
|
||||
profileFamilyTypes = doc.QueryElementsByTypeAndCategory<FamilySymbol>(BuiltInCategory.OST_ProfileFamilies)
|
||||
.Cast<FamilySymbol>()
|
||||
.OrderBy(n => n.FamilyName)
|
||||
.ToList();
|
||||
familyTypes = doc.QueryElementsByType<FamilySymbol>()
|
||||
.OfType<FamilySymbol>()
|
||||
.Where(
|
||||
s =>
|
||||
s.Category.Parent == null
|
||||
&& s.Family.IsEditable
|
||||
&& s.Family.IsUserCreated
|
||||
&& s.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBased
|
||||
)
|
||||
.OrderBy(n => n.FamilyName)
|
||||
.ToList();
|
||||
materials = doc.QueryElementsByType<Material>().OrderBy(n => n.Name).OfType<Material>().ToList();
|
||||
ProfileFamilyTypesView = CollectionViewSource.GetDefaultView(ProfileFamilyTypes);
|
||||
FamilyTypesView = CollectionViewSource.GetDefaultView(FamilyTypes);
|
||||
}
|
||||
|
||||
[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 = CurveUtils.GroupContinuousCurves(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;
|
||||
}
|
||||
|
||||
//if (IsModelCurve)
|
||||
//{
|
||||
// IList<Reference> refers = UiDocument.Selection.PickObjects(
|
||||
// ObjectType.Element,
|
||||
// new GenericFilter<ModelCurve>(),
|
||||
// "请选择模型线并完成选择"
|
||||
// );
|
||||
// curves = refers.Select(r => doc.GetElement(r)).OfType<ModelCurve>().Select(mc => mc.GeometryCurve).ToList();
|
||||
// List<List<Curve>> loops = new CurveUtils().GetCurvesOfLoops(curves);
|
||||
// if (loops.Count != 1)
|
||||
// {
|
||||
// MessageBox.Show("未选择路径或所选线条不止一条路径", "错误");
|
||||
// IsRunning = false;
|
||||
// return;
|
||||
// }
|
||||
// curves = loops.FirstOrDefault();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// Reference refer = UiDocument.Selection.PickObject(
|
||||
// ObjectType.Element,
|
||||
// new FuncFilter(e => e is ImportInstance importInstance && importInstance.Category.Name.EndsWith(".dwg")),
|
||||
// "请选择dwg实例"
|
||||
// );
|
||||
// ImportInstance importInstance = doc.GetElement(refer) as ImportInstance;
|
||||
// curves = importInstance.GetCurves();
|
||||
//}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||||
{
|
||||
IsRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ((curves != null) && (curves.Count > 1))
|
||||
{
|
||||
CurveUtils.SortCurvesContiguous(curves);
|
||||
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));
|
||||
}
|
||||
}
|
||||
//var li = curves[i].Tessellate();
|
||||
//li.Remove(li.Last());
|
||||
//points.AddRange(li);
|
||||
}
|
||||
|
||||
points.Add(curves[curves.Count - 1].GetEndPoint(1));
|
||||
var planePoints = points.Select(p => new XYZ(p.X, p.Y, 0)).ToList();
|
||||
var spline3D = HermiteSpline.Create(points, false);
|
||||
|
||||
doc.InvokeGroup(
|
||||
_ =>
|
||||
{
|
||||
//SketchPlane sketch = SketchPlane.Create(doc, Plane.CreateByNormalAndOrigin(XYZ.BasisZ, spline3D.GetEndPoint(0)));
|
||||
//var mc = doc.Create.NewModelCurve(spline3D, sketch);
|
||||
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);
|
||||
IsRunning = false;
|
||||
},
|
||||
"创建轨枕、扣件"
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogAssists.WriteLog(ex.StackTrace);
|
||||
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);
|
||||
XYZ tangent;
|
||||
XYZ rightBasis;
|
||||
XYZ topBasis;
|
||||
|
||||
tangent = transform.BasisX.Normalize();
|
||||
rightBasis = tangent.CrossProduct(XYZ.BasisZ).Normalize();
|
||||
topBasis = rightBasis.CrossProduct(tangent).Normalize();
|
||||
if (!XYZ.IsWithinLengthLimits(point))
|
||||
{
|
||||
MessageBox.Show("点不在Revit模型空间内,内部原点坐标与模型线相距太远", "错误");
|
||||
return;
|
||||
}
|
||||
//Plane plane = Plane.CreateByOriginAndBasis(point, rightBasis, topBasis);
|
||||
|
||||
//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 d = rightBasis.DotProduct(transform.BasisX);
|
||||
//if (!profileTransform.IsConformal)
|
||||
//{
|
||||
// MessageBox.Show($"起始段必须是直线", "创建失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
// IsRunning = false;
|
||||
// return;
|
||||
//}
|
||||
//偏移变换
|
||||
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
|
||||
.QueryElementsByType<CurveElement>()
|
||||
.OfType<CurveElement>()
|
||||
.Select(c => c.GeometryCurve)
|
||||
.ToList();
|
||||
#if DEBUG
|
||||
//doc.Invoke(_ =>
|
||||
//{
|
||||
// SketchPlane sketch = SketchPlane.Create(
|
||||
// doc,
|
||||
// Plane.CreateByNormalAndOrigin(XYZ.BasisZ, spline3D.GetEndPoint(0))
|
||||
// );
|
||||
// var mc = doc.Create.NewModelCurve(spline3D, sketch);
|
||||
//});
|
||||
#endif
|
||||
//doc.Invoke(
|
||||
// _ =>
|
||||
// {
|
||||
// SketchPlane sketch = SketchPlane.Create(doc, Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero));
|
||||
|
||||
// foreach (var item in profiles)
|
||||
// {
|
||||
// var mc = doc.Create.NewModelCurve(item, sketch);
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
|
||||
doc.Invoke(
|
||||
_ =>
|
||||
{
|
||||
//if (!SelectedProfileFamilyType.IsActiveZoom)
|
||||
//{
|
||||
// SelectedProfileFamilyType.Activate();
|
||||
//}
|
||||
//if (loop.IsOpen())
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
//familyDocument.FamilyCreate.NewSweep
|
||||
//材质处理
|
||||
Solid solidMirror = null;
|
||||
SolidOptions options = new(
|
||||
SelectedMaterial == null ? ElementId.InvalidElementId : SelectedMaterial.Id,
|
||||
ElementId.InvalidElementId
|
||||
);
|
||||
//获取截面的曲线集合
|
||||
var list = CurveUtils.GroupContinuousCurves(profiles);
|
||||
//生成线串
|
||||
var loops = list.Select(cs => CurveLoop.Create(cs)).ToList();
|
||||
|
||||
if (IsTwoSides)
|
||||
{
|
||||
List<CurveLoop> loopsAnother = [];
|
||||
var offsetTransformAnother = Transform.CreateTranslation(new XYZ(-OffsetX, OffsetY, 0) / 304.8);
|
||||
foreach (var item in loops)
|
||||
{
|
||||
loopsAnother.Add(CurveLoop.CreateViaCopy(item));
|
||||
}
|
||||
foreach (var item in loopsAnother)
|
||||
{
|
||||
item.Transform(offsetTransformAnother);
|
||||
item.Transform(profileTransform);
|
||||
}
|
||||
solidMirror = GeometryCreationUtilities.CreateFixedReferenceSweptGeometry(
|
||||
CurveLoop.Create([spline3D]),
|
||||
0,
|
||||
0,
|
||||
loopsAnother,
|
||||
XYZ.BasisZ,
|
||||
options
|
||||
);
|
||||
}
|
||||
foreach (var item in loops)
|
||||
{
|
||||
item.Transform(offsetTransform);
|
||||
item.Transform(profileTransform);
|
||||
}
|
||||
|
||||
var solid = GeometryCreationUtilities.CreateFixedReferenceSweptGeometry(
|
||||
CurveLoop.Create([spline3D]),
|
||||
0,
|
||||
0,
|
||||
loops,
|
||||
XYZ.BasisZ,
|
||||
options
|
||||
);
|
||||
List<GeometryObject> geos = [solid];
|
||||
if (IsTwoSides && solidMirror != null)
|
||||
{
|
||||
geos.Add(solidMirror);
|
||||
}
|
||||
doc.CreateDirectShapeInstance(
|
||||
"轨道",
|
||||
BuiltInCategory.OST_GenericModel,
|
||||
geos);
|
||||
//var shape = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
|
||||
//shape.SetShape(geos);
|
||||
},
|
||||
"创建钢轨"
|
||||
);
|
||||
IsRunning = false;
|
||||
familyDocument.Close(false);
|
||||
//spline3D.CreateOffset();
|
||||
//SketchPlane sketch = SketchPlane.Create(doc, Plane.CreateByNormalAndOrigin(p4, p1));
|
||||
//var mc = doc.Create.NewModelCurve(spline3D, sketch);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
familyDocument?.Close(false);
|
||||
LogAssists.WriteLog(ex.StackTrace);
|
||||
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,
|
||||
}
|
||||
}
|
||||
138
Szmedi.RvKits/Modeling/TrackCreatorWin.xaml
Normal file
138
Szmedi.RvKits/Modeling/TrackCreatorWin.xaml
Normal file
@@ -0,0 +1,138 @@
|
||||
<controls:MaterialWindow
|
||||
x:Class="Szmedi.RvKits.Modeling.TrackCreatorWin"
|
||||
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:controls="clr-namespace:Szmedi.RvKits.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Szmedi.RvKits.Modeling"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="轨道创建"
|
||||
Width="420"
|
||||
Height="720"
|
||||
SizeToContent="Height"
|
||||
d:DataContext="{d:DesignInstance Type=local:TrackCreatorViewModel}"
|
||||
|
||||
mc:Ignorable="d">
|
||||
<controls:MaterialWindow.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/Szmedi.RvKits;component/WPFUI.xaml" />
|
||||
</controls:MaterialWindow.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image Margin="5,5,5,5" Source="{Binding PreviewImage}" />
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<GroupBox Grid.Row="0" Grid.Column="0" Header="轨道">
|
||||
<StackPanel>
|
||||
<ComboBox
|
||||
materialDesign:HintAssist.Hint="轨道轮廓类型"
|
||||
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
|
||||
ItemsSource="{Binding ProfileFamilyTypesView}"
|
||||
IsEditable="True"
|
||||
Text="{Binding SearchProfileText,UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectedItem="{Binding SelectedProfileFamilyType, UpdateSourceTrigger=PropertyChanged}"
|
||||
ToolTip="未选择则不创建,
右键点击清除选择">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="MouseRightButtonUp">
|
||||
<b:InvokeCommandAction Command="{Binding ClearProfilesSelectionCommand}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
</ComboBox>
|
||||
<ComboBox
|
||||
materialDesign:HintAssist.Hint="轨道材质"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding Materials, Mode=OneWay}"
|
||||
SelectedItem="{Binding SelectedMaterial, UpdateSourceTrigger=PropertyChanged}"
|
||||
ToolTip="未选择无材质,
右键点击清除选择">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="MouseRightButtonUp">
|
||||
<b:InvokeCommandAction Command="{Binding ClearMaterialSelectionCommand}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
</ComboBox>
|
||||
<TextBox
|
||||
materialDesign:TextFieldAssist.PrefixText="偏移距离X:"
|
||||
materialDesign:TextFieldAssist.SuffixText="mm"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Text="{Binding OffsetX, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"
|
||||
ToolTip="向右偏移设置为正值,
向左偏移为负值" />
|
||||
<TextBox
|
||||
materialDesign:TextFieldAssist.PrefixText="偏移距离Y:"
|
||||
materialDesign:TextFieldAssist.SuffixText="mm"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Text="{Binding OffsetY, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"
|
||||
ToolTip="向上偏移设置为正值,
向下偏移为负值" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="0" Grid.Column="1" Header="扣件、轨枕">
|
||||
<StackPanel>
|
||||
<ComboBox
|
||||
materialDesign:HintAssist.Hint="扣件或轨枕类型"
|
||||
ItemTemplate="{StaticResource MultiDisplayMemberPath}"
|
||||
ItemsSource="{Binding FamilyTypesView}"
|
||||
IsEditable="True"
|
||||
Text="{Binding SearchFamilyText,UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectedItem="{Binding SelectedFamilyType, UpdateSourceTrigger=PropertyChanged}"
|
||||
ToolTip="未选择则不创建,
右键点击清除选择">
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="MouseRightButtonUp">
|
||||
<b:InvokeCommandAction Command="{Binding ClearFmailyTypeSelectionCommand}" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
</ComboBox>
|
||||
<TextBox
|
||||
materialDesign:TextFieldAssist.PrefixText="水平间距:"
|
||||
materialDesign:TextFieldAssist.SuffixText="mm"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Text="{Binding Spacing, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}" />
|
||||
<TextBox
|
||||
materialDesign:TextFieldAssist.PrefixText="偏移距离X:"
|
||||
materialDesign:TextFieldAssist.SuffixText="mm"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Text="{Binding InstanceOffsetX, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"
|
||||
ToolTip="向右偏移设置为正值,
向左偏移为负值" />
|
||||
<TextBox
|
||||
materialDesign:TextFieldAssist.PrefixText="偏移距离Y:"
|
||||
materialDesign:TextFieldAssist.SuffixText="mm"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Text="{Binding InstanceOffsetY, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"
|
||||
ToolTip="向上偏移设置为正值,
向下偏移为负值" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
<GroupBox Grid.Row="2" Header="中心线类型">
|
||||
<UniformGrid VerticalAlignment="Center" Rows="1">
|
||||
<RadioButton Content="模型线" IsChecked="{Binding CenterCurveType, ConverterParameter={x:Static local:CenterCurveType.ModelCurve}, Converter={StaticResource ComparisonConverter}}" ToolTip="框选连续、非闭合的模型线并在工具栏完成选择,
模型线的定位平面为绘制时的工作平面,
如在楼层楼层平面为该楼层高度" />
|
||||
<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="3" Rows="1">
|
||||
<TextBox
|
||||
materialDesign:TextFieldAssist.PrefixText="最小细分长度:"
|
||||
materialDesign:TextFieldAssist.SuffixText="m"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Text="{Binding Precision, UpdateSourceTrigger=PropertyChanged}"
|
||||
ToolTip="数值越小,越贴合原曲线,
建议模型线(由于单条曲线较长)取值小一些" />
|
||||
<CheckBox
|
||||
HorizontalAlignment="Center"
|
||||
Content="两侧布置"
|
||||
IsChecked="{Binding IsTwoSides}"
|
||||
ToolTip="截面或者实例是否在中心线另一侧创建或布置" />
|
||||
<Button Command="{Binding CreateTrackCommand}" Content="创建" ToolTip="选择合适的选项,创建模型。
注意:两根模型线之间若角度极小,
可作为一条直线时,使用一条直线代替" />
|
||||
</UniformGrid>
|
||||
</Grid>
|
||||
</controls:MaterialWindow>
|
||||
13
Szmedi.RvKits/Modeling/TrackCreatorWin.xaml.cs
Normal file
13
Szmedi.RvKits/Modeling/TrackCreatorWin.xaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Szmedi.RvKits.Modeling
|
||||
{
|
||||
/// <summary>
|
||||
/// TrackCreatorWin.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class TrackCreatorWin
|
||||
{
|
||||
public TrackCreatorWin()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user