添加项目文件。

This commit is contained in:
ShrlAlgo
2025-09-16 16:06:41 +08:00
parent 0e7807b826
commit 98c65ceb3d
922 changed files with 1009489 additions and 0 deletions

View 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();
}
}
}

View 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)
{
}
}
}

View 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>

View File

@@ -0,0 +1,12 @@
namespace Szmedi.RvKits.Modeling;
/// <summary>
/// InstanceCreatorWin.xaml 的交互逻辑
/// </summary>
public partial class InstanceCreatorWin
{
public InstanceCreatorWin()
{
InitializeComponent();
}
}

View 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; }
}
}

View 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()
{
}
}
}

View 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);
}
}
}

View 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();
}
}
}

View 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,
}
}

View 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="未选择则不创建,&#x0a;右键点击清除选择">
<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="未选择无材质,&#x0a;右键点击清除选择">
<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="向右偏移设置为正值,&#x0a;向左偏移为负值" />
<TextBox
materialDesign:TextFieldAssist.PrefixText="偏移距离Y"
materialDesign:TextFieldAssist.SuffixText="mm"
InputMethod.IsInputMethodEnabled="False"
Text="{Binding OffsetY, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"
ToolTip="向上偏移设置为正值,&#x0a;向下偏移为负值" />
</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="未选择则不创建,&#x0a;右键点击清除选择">
<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="向右偏移设置为正值,&#x0a;向左偏移为负值" />
<TextBox
materialDesign:TextFieldAssist.PrefixText="偏移距离Y"
materialDesign:TextFieldAssist.SuffixText="mm"
InputMethod.IsInputMethodEnabled="False"
Text="{Binding InstanceOffsetY, UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"
ToolTip="向上偏移设置为正值,&#x0a;向下偏移为负值" />
</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="框选连续、非闭合的模型线并在工具栏完成选择,&#x0a;模型线的定位平面为绘制时的工作平面,&#x0a;如在楼层楼层平面为该楼层高度" />
<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="数值越小,越贴合原曲线,&#x0a;建议模型线(由于单条曲线较长)取值小一些" />
<CheckBox
HorizontalAlignment="Center"
Content="两侧布置"
IsChecked="{Binding IsTwoSides}"
ToolTip="截面或者实例是否在中心线另一侧创建或布置" />
<Button Command="{Binding CreateTrackCommand}" Content="创建" ToolTip="选择合适的选项,创建模型。&#x0a;注意:两根模型线之间若角度极小,&#x0a;可作为一条直线时,使用一条直线代替" />
</UniformGrid>
</Grid>
</controls:MaterialWindow>

View File

@@ -0,0 +1,13 @@
namespace Szmedi.RvKits.Modeling
{
/// <summary>
/// TrackCreatorWin.xaml 的交互逻辑
/// </summary>
public partial class TrackCreatorWin
{
public TrackCreatorWin()
{
InitializeComponent();
}
}
}