462 lines
19 KiB
C#
462 lines
19 KiB
C#
|
||
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]
|
||
public partial string SearchText { get; set; }
|
||
|
||
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)
|
||
{
|
||
}
|
||
}
|
||
} |