507 lines
18 KiB
C#
507 lines
18 KiB
C#
|
||
using Autodesk.Revit.DB;
|
||
using Autodesk.Revit.DB.Visual;
|
||
using Autodesk.Revit.UI;
|
||
|
||
using CommunityToolkit.Mvvm.ComponentModel;
|
||
using CommunityToolkit.Mvvm.Input;
|
||
|
||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||
|
||
using System;
|
||
using System.Collections.ObjectModel;
|
||
|
||
using System.Linq;
|
||
using System.Runtime.InteropServices;
|
||
|
||
using System.Windows.Controls;
|
||
|
||
using Szmedi.RvKits.Assists;
|
||
|
||
namespace Szmedi.RvKits.ModelManager;
|
||
|
||
public partial class MaterialBatchViewModel : ObservableObject
|
||
{
|
||
public MaterialBatchViewModel(UIApplication uiapp)
|
||
{
|
||
doc = uiapp.ActiveUIDocument.Document;
|
||
var mats = new FilteredElementCollector(doc).OfClass(typeof(Material)).Cast<Material>();
|
||
materials = new ObservableCollection<Material>(mats);
|
||
this.uiapp = uiapp;
|
||
materialHandler = new();
|
||
}
|
||
|
||
private readonly ActionEventHandler materialHandler;
|
||
private readonly Document doc;
|
||
private readonly ObservableCollection<Material> materials;
|
||
private readonly UIApplication uiapp;
|
||
|
||
[ObservableProperty]
|
||
private bool isFloor = true;
|
||
|
||
[ObservableProperty]
|
||
private bool isStructuralColumn = true;
|
||
|
||
[ObservableProperty]
|
||
private bool isStructuralFraming = true;
|
||
|
||
[ObservableProperty]
|
||
private bool isWall = true;
|
||
|
||
[ObservableProperty]
|
||
[NotifyPropertyChangedFor(nameof(FilteredList))]
|
||
private string searchText;
|
||
|
||
[ObservableProperty]
|
||
[NotifyCanExecuteChangedFor(nameof(ApplyCustomMaterialCommand))]
|
||
private Material selectedMaterial;
|
||
|
||
//[RelayCommand]
|
||
//private void MaterialEdit()
|
||
//{
|
||
// RevitCommandId commandId = RevitCommandId.LookupPostableCommandId(PostableCommand.Materials);
|
||
// // var ptr = WinIntPtr.FindWindow(null, "材质浏览器");
|
||
// var mainWindowHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
|
||
// if (mainWindowHandle != IntPtr.Zero)
|
||
// {
|
||
// IntPtr materialDialog = WinIntPtr.FindWindowEx(mainWindowHandle, IntPtr.Zero, null, null);
|
||
// if (materialDialog != IntPtr.Zero)
|
||
// {
|
||
// if (uiapp.CanPostCommand(commandId))
|
||
// {
|
||
// Revit.Async.RevitTask.RunAsync(() =>
|
||
// {
|
||
// uiapp.PostCommand(commandId);
|
||
// }
|
||
// );
|
||
// }
|
||
// }
|
||
// }
|
||
//}
|
||
public IEnumerable<Material> FilteredList =>
|
||
IsIllumMaterial == true
|
||
? GetEmissiveMat(doc)
|
||
: string.IsNullOrEmpty(SearchText)
|
||
? materials
|
||
: materials.Where(x => x.Name.Contains(SearchText));
|
||
|
||
[ObservableProperty]
|
||
[NotifyPropertyChangedFor(nameof(FilteredList))]
|
||
private bool? isIllumMaterial = false;
|
||
|
||
[RelayCommand(CanExecute = nameof(StandardCanRun))]
|
||
private void ApplyStandardMaterial(ComboBoxItem item)
|
||
{
|
||
var materialName = item.Content.ToString();
|
||
materialHandler.Raise(uiapp =>
|
||
{
|
||
try
|
||
{
|
||
#if REVIT2018
|
||
var assetPropertyConcreteVersionGuid = "ACADGen-006";
|
||
var assetPropertyMetalVersionGuid = "Metal-047"; //缎光
|
||
// string assetPropertyMetalVersionGuid = "InvGen-028";//钢板
|
||
#elif REVIT2019 || REVIT2020
|
||
string assetPropertyConcreteVersionGuid = "Prism-1100"; //如果有贴图,前缀加上t_就是贴图的文件名
|
||
string assetPropertyMetalVersionGuid = "Metal-047";
|
||
#endif
|
||
Material material = null;
|
||
StandardCanRun = false;
|
||
using (var tg = new TransactionGroup(doc, $"应用标准{materialName}材质"))
|
||
{
|
||
tg.Start();
|
||
using (Transaction ts = new(doc, $"{materialName}材质创建"))
|
||
{
|
||
ts.Start();
|
||
if (materialName == "混凝土")
|
||
{
|
||
material = CreateConcreteMaterial(
|
||
uiapp,
|
||
"混凝土,现场浇注",
|
||
"混凝土",
|
||
"混凝土 - 现场浇注",
|
||
assetPropertyConcreteVersionGuid,
|
||
new Color(192, 192, 192)
|
||
);
|
||
}
|
||
else if (materialName == "钢")
|
||
{
|
||
material = CreateConcreteMaterial(uiapp, "金属,钢", "金属", "钢材", assetPropertyMetalVersionGuid, new Color(247, 247, 247));
|
||
}
|
||
else
|
||
{
|
||
ts.RollBack();
|
||
}
|
||
ts.Commit();
|
||
}
|
||
ApplyMaterial(material);
|
||
tg.Assimilate();
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
}
|
||
StandardCanRun = true;
|
||
});
|
||
}
|
||
|
||
[RelayCommand(CanExecute = nameof(CanApplyCustomMaterial))]
|
||
private void ApplyCustomMaterial(Material material)
|
||
{
|
||
materialHandler.Raise(_ =>
|
||
{
|
||
CustomCanRun = false;
|
||
try
|
||
{
|
||
ApplyMaterial(material);
|
||
}
|
||
catch (Exception)
|
||
{
|
||
|
||
}
|
||
CustomCanRun = true;
|
||
});
|
||
}
|
||
|
||
private void ApplyMaterial(Material material)
|
||
{
|
||
var framingCatId = Category.GetCategory(doc, BuiltInCategory.OST_StructuralFraming).Id;
|
||
var columnCatId = Category.GetCategory(doc, BuiltInCategory.OST_StructuralColumns).Id;
|
||
try
|
||
{
|
||
var elements = uiapp.ActiveUIDocument.Selection
|
||
.PickElementsByRectangle(
|
||
new FuncFilter(
|
||
elem =>
|
||
{
|
||
var flag1 = IsFloor && elem is Floor;
|
||
var flag2 = IsWall && elem is Wall wall && wall.WallType.Kind == WallKind.Basic;
|
||
var flag3 = IsStructuralColumn &&
|
||
elem is FamilyInstance &&
|
||
elem.Category.Id == columnCatId;
|
||
var flag4 = IsStructuralFraming &&
|
||
elem is FamilyInstance &&
|
||
elem.Category.Id == framingCatId;
|
||
return flag1 || flag2 || flag3 || flag4;
|
||
},
|
||
(_, _) => true),
|
||
"请框选元素");
|
||
|
||
using Transaction ts = new(doc, $"应用{material.Name}材质");
|
||
ts.Start();
|
||
foreach (var elem in elements)
|
||
{
|
||
if (elem is FamilyInstance framing && elem.Category.Id == framingCatId)
|
||
{
|
||
var param = framing.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM);
|
||
param?.Set(material.Id);
|
||
}
|
||
else if (elem is Wall wall)
|
||
{
|
||
var structure = wall.WallType.GetCompoundStructure();
|
||
structure.SetMaterialId(structure.StructuralMaterialIndex, material.Id);
|
||
wall.WallType.SetCompoundStructure(structure);
|
||
}
|
||
else if (elem is Floor floor)
|
||
{
|
||
var structure = floor.FloorType.GetCompoundStructure();
|
||
structure.SetMaterialId(structure.StructuralMaterialIndex, material.Id);
|
||
floor.FloorType.SetCompoundStructure(structure);
|
||
}
|
||
else if (elem is FamilyInstance column && elem.Category.Id == columnCatId)
|
||
{
|
||
var param = column.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM);
|
||
param?.Set(material.Id);
|
||
}
|
||
}
|
||
ts.Commit();
|
||
}
|
||
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
|
||
{
|
||
}
|
||
}
|
||
|
||
[ObservableProperty]
|
||
[NotifyCanExecuteChangedFor(nameof(ApplyStandardMaterialCommand))]
|
||
private bool standardCanRun = true;
|
||
|
||
[ObservableProperty]
|
||
[NotifyCanExecuteChangedFor(nameof(ApplyCustomMaterialCommand))]
|
||
private bool customCanRun = true;
|
||
private bool CanApplyCustomMaterial(Material material)
|
||
{
|
||
return material is not null && CustomCanRun;
|
||
}
|
||
|
||
private static List<Material> GetEmissiveMat(Document doc)
|
||
{
|
||
var materials = new FilteredElementCollector(doc).OfClass(typeof(Material)).ToElements().Cast<Material>();
|
||
List<Material> emissiveMat = [];
|
||
foreach (var material in materials)
|
||
{
|
||
if (doc.GetElement(material.AppearanceAssetId) is AppearanceAssetElement assetElem)
|
||
{
|
||
var asset = assetElem.GetRenderingAsset();
|
||
#if REVIT2018
|
||
var prop = asset["generic_self_illum_luminance"];
|
||
#elif REVIT2020 || REVIT2019
|
||
var prop = asset.FindByName("generic_self_illum_luminance");
|
||
#endif
|
||
var d = prop as AssetPropertyDouble;
|
||
if (d?.Value > 0)
|
||
{
|
||
emissiveMat.Add(material);
|
||
}
|
||
}
|
||
}
|
||
return emissiveMat;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置材质颜色
|
||
/// </summary>
|
||
/// <param name="uiapp"></param>
|
||
/// <param name="materialName"></param>
|
||
/// <param name="materialCategoryClass"></param>
|
||
/// <param name="appearanceAssetName"></param>
|
||
/// <param name="assetPropertyVersionGuid"></param>
|
||
/// <param name="shading">着色颜色</param>
|
||
/// <param name="color"></param>
|
||
/// <param name="cutPatternName"></param>
|
||
/// <param name="surfacePatternName"></param>
|
||
/// <returns></returns>
|
||
private static Material CreateConcreteMaterial(
|
||
UIApplication uiapp,
|
||
string materialName,
|
||
string materialCategoryClass,
|
||
string appearanceAssetName,
|
||
string assetPropertyVersionGuid,
|
||
Color shading,
|
||
Color color,
|
||
string cutPatternName,
|
||
string surfacePatternName
|
||
)
|
||
{
|
||
Material material;
|
||
var doc = uiapp.ActiveUIDocument.Document;
|
||
var materials = new FilteredElementCollector(doc)
|
||
.OfClass(typeof(Material))
|
||
.Cast<Material>()
|
||
.Where(m => m.Name == materialName);
|
||
var assets = uiapp.Application.GetAssets(AssetType.Appearance);
|
||
|
||
if (materials.Any())
|
||
{
|
||
material = materials.FirstOrDefault();
|
||
}
|
||
else
|
||
{
|
||
using Transaction ts = new(doc, $"新建{materialName}材质");
|
||
ts.Start();
|
||
var matId = Material.Create(doc, materialName);
|
||
material = doc.GetElement(matId) as Material;
|
||
ts.Commit();
|
||
}
|
||
|
||
using (Transaction name = new(doc, $"定义{materialCategoryClass}材质"))
|
||
{
|
||
name.Start();
|
||
if (material != null)
|
||
{
|
||
material.Color = shading;
|
||
material.MaterialClass = materialCategoryClass;
|
||
material.MaterialCategory = materialCategoryClass;
|
||
var asset = assets.FirstOrDefault(a =>
|
||
{
|
||
var propStr = a.FindByName("VersionGUID") as AssetPropertyString;
|
||
return propStr?.Value == assetPropertyVersionGuid;
|
||
});
|
||
AppearanceAssetElement appearanceAssetElement = null;
|
||
for (var i = 0; i < 100; i++)
|
||
{
|
||
appearanceAssetName = $"{appearanceAssetName}({i})";
|
||
if (AppearanceAssetElement.GetAppearanceAssetElementByName(doc, appearanceAssetName) == null)
|
||
{
|
||
appearanceAssetElement = AppearanceAssetElement.Create(doc, appearanceAssetName, asset);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (appearanceAssetElement != null)
|
||
{
|
||
material.AppearanceAssetId = appearanceAssetElement.Id;
|
||
}
|
||
|
||
var pattern1 = FillPatternElement.GetFillPatternElementByName(
|
||
doc,
|
||
FillPatternTarget.Drafting,
|
||
cutPatternName
|
||
);
|
||
var pattern2 = FillPatternElement.GetFillPatternElementByName(
|
||
doc,
|
||
FillPatternTarget.Drafting,
|
||
surfacePatternName
|
||
);
|
||
#if REVIT2018
|
||
|
||
material.CutPatternColor = color;
|
||
material.SurfacePatternColor = color;
|
||
if (pattern1 != null)
|
||
{
|
||
material.CutPatternId = pattern1.Id;
|
||
}
|
||
|
||
if (pattern2 != null)
|
||
{
|
||
material.SurfacePatternId = pattern2.Id;
|
||
}
|
||
#else
|
||
material.CutBackgroundPatternColor = color;
|
||
material.CutForegroundPatternColor = color;
|
||
material.SurfaceBackgroundPatternColor = color;
|
||
material.SurfaceForegroundPatternColor = color;
|
||
if (pattern1 != null)
|
||
{
|
||
material.CutBackgroundPatternId = pattern1.Id;
|
||
material.CutForegroundPatternId = pattern1.Id;
|
||
}
|
||
|
||
if (pattern2 != null)
|
||
{
|
||
material.SurfaceBackgroundPatternId = pattern2.Id;
|
||
material.SurfaceForegroundPatternId = pattern2.Id;
|
||
}
|
||
#endif
|
||
material.UseRenderAppearanceForShading = false;
|
||
}
|
||
|
||
name.Commit();
|
||
}
|
||
|
||
return material;
|
||
}
|
||
|
||
private static Material CreateConcreteMaterial(
|
||
UIApplication uiapp,
|
||
string materialName,
|
||
string materialCategoryClass,
|
||
string appearanceAssetName,
|
||
string assetPropertyVersionGuid,
|
||
Color shadingColor
|
||
)
|
||
{
|
||
Material material;
|
||
var doc = uiapp.ActiveUIDocument.Document;
|
||
var materials = new FilteredElementCollector(doc)
|
||
.OfClass(typeof(Material))
|
||
.Cast<Material>()
|
||
.Where(m => m.Name == materialName);
|
||
var assets = uiapp.Application.GetAssets(AssetType.Appearance);
|
||
//获取或创建材质
|
||
if (materials.Any())
|
||
{
|
||
material = materials.FirstOrDefault();
|
||
}
|
||
else
|
||
{
|
||
using SubTransaction ts = new(doc);
|
||
ts.Start();
|
||
var matId = Material.Create(doc, materialName);
|
||
material = doc.GetElement(matId) as Material;
|
||
ts.Commit();
|
||
}
|
||
//应用外观
|
||
using (SubTransaction name = new(doc))
|
||
{
|
||
name.Start();
|
||
if (material != null)
|
||
{
|
||
material.Color = shadingColor;
|
||
material.MaterialClass = materialCategoryClass;
|
||
material.MaterialCategory = materialCategoryClass;
|
||
var asset = assets.FirstOrDefault(a =>
|
||
{
|
||
var propStr = a.FindByName("VersionGUID") as AssetPropertyString;
|
||
return propStr?.Value == assetPropertyVersionGuid;
|
||
});
|
||
AppearanceAssetElement appearanceAssetElement = null;
|
||
for (var i = 0; i < 100; i++)
|
||
{
|
||
appearanceAssetName = $"{appearanceAssetName}({i})";
|
||
if (AppearanceAssetElement.GetAppearanceAssetElementByName(doc, appearanceAssetName) == null)
|
||
{
|
||
appearanceAssetElement = AppearanceAssetElement.Create(doc, appearanceAssetName, asset);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (appearanceAssetElement != null)
|
||
{
|
||
material.AppearanceAssetId = appearanceAssetElement.Id;
|
||
}
|
||
material.UseRenderAppearanceForShading = false;
|
||
}
|
||
|
||
name.Commit();
|
||
}
|
||
|
||
return material;
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void CloseWin()
|
||
{
|
||
SendESCToRevit();
|
||
}
|
||
|
||
private static void SendKeyToRevit(byte bVk, byte dwFlags)
|
||
{
|
||
var Revit = Autodesk.Windows.ComponentManager.ApplicationWindow;
|
||
WinIntPtr.SetForegroundWindow(Revit);
|
||
keybd_event(bVk, 0, dwFlags, 0);
|
||
}
|
||
|
||
[DllImport("user32.dll")]
|
||
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
|
||
|
||
public static void SendESCToRevit()
|
||
{
|
||
SendKeyToRevit(0x1B, 0);
|
||
SendKeyToRevit(0x1B, 2);
|
||
}
|
||
//private static void SetStructuralComponents(Material material)
|
||
//{
|
||
// var doc = material.doc;
|
||
// var columns = new FilteredElementCollector(doc).QueryElementsByType(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_StructuralColumns);
|
||
// var floors = new FilteredElementCollector(doc).QueryElementsByType(typeof(Floor)).OfCategory(BuiltInCategory.OST_Floors).Cast<Floor>().GroupBy(floor => floor.FloorType);
|
||
// var framings = new FilteredElementCollector(doc).QueryElementsByType(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_StructuralFraming);
|
||
// var walls = new FilteredElementCollector(doc).QueryElementsByType(typeof(Wall)).OfCategory(BuiltInCategory.OST_Walls).Cast<Wall>().Where(wall => wall.WallType.Kind == WallKind.Basic).GroupBy(wall => wall.WallType);
|
||
// foreach (var column in columns)
|
||
// {
|
||
// var param = column.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM);
|
||
// param?.Set(material.Id);
|
||
// }
|
||
|
||
// foreach (var framing in framings)
|
||
// {
|
||
// var param = framing.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM);
|
||
// param?.Set(material.Id);
|
||
// }
|
||
|
||
// foreach (var wall in walls)
|
||
// {
|
||
// var structure = wall.Key.GetCompoundStructure();
|
||
// structure.SetMaterialId(structure.StructuralMaterialIndex, material.Id);
|
||
|
||
// wall.Key.SetCompoundStructure(structure);
|
||
// }
|
||
|
||
// foreach (var floor in floors)
|
||
// {
|
||
// var structure = floor.Key.GetCompoundStructure();
|
||
// structure.SetMaterialId(structure.StructuralMaterialIndex, material.Id);
|
||
// floor.Key.SetCompoundStructure(structure);
|
||
// }
|
||
//}
|
||
}
|