using System.ComponentModel; using System.Windows.Controls; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Windows; using CommunityToolkit.Mvvm.Input; using Nice3point.Revit.Toolkit.External.Handlers; using ShrlAlgoToolkit.Core.Assists; using ShrlAlgoToolkit.RevitAddins.Assists; using ShrlAlgoToolkit.RevitAddins.Properties; using ShrlAlgoToolkit.RevitAddins.RvCommon; namespace ShrlAlgoToolkit.RevitAddins.UIRibbon; public class ModifyTabApp { public ModifyTabApp(UIApplication uiapp) { handler = new ActionEventHandler(); this.uiapp = uiapp; var tab = ComponentManager.Ribbon.Tabs.FirstOrDefault(ribbonTab => ribbonTab.Id == "Modify"); SelectionPanel(tab); //FilterPanel(tab); AlignPanel(tab); } private readonly ActionEventHandler handler; private readonly UIApplication uiapp; private Document Document => UIDocument.Document; private UIDocument UIDocument => uiapp.ActiveUIDocument; /// /// 对齐元素 /// /// 需对齐的元素集合 /// 对齐的类型 private static void AlignByType(List alignElements, AlignType alignType) { switch (alignType) { case AlignType.Left: { //最左的元素 var leftAlignElement = alignElements.OrderBy(x => x.UpLeft.X).FirstOrDefault(); foreach (var alignElement in alignElements) { XYZ resultingPoint = new(leftAlignElement.UpLeft.X, alignElement.UpLeft.Y, 0); alignElement.MoveTo(resultingPoint, AlignType.Left); } break; } case AlignType.Right: { var rightAlignElement = alignElements.OrderByDescending(x => x.UpRight.X).FirstOrDefault(); foreach (var alignElement in alignElements) { XYZ resultingPoint = new(rightAlignElement.UpRight.X, alignElement.UpRight.Y, 0); alignElement.MoveTo(resultingPoint, AlignType.Right); } break; } case AlignType.Up: { var upAlignElement = alignElements.OrderByDescending(x => x.UpRight.Y).FirstOrDefault(); foreach (var alignElement in alignElements) { XYZ resultingPoint = new(alignElement.UpRight.X, upAlignElement.UpRight.Y, 0); alignElement.MoveTo(resultingPoint, AlignType.Up); } break; } case AlignType.Down: { var farthestAlign = alignElements.OrderBy(x => x.DownRight.Y).FirstOrDefault(); foreach (var alignElement in alignElements) { XYZ resultingPoint = new(alignElement.DownRight.X, farthestAlign.DownRight.Y, 0); alignElement.MoveTo(resultingPoint, AlignType.Down); } break; } case AlignType.HorizontallyCenter: //同一条垂直轴 { var sortedElements = alignElements.OrderBy(x => x.UpRight.X).ToList(); var rightElement = sortedElements.LastOrDefault(); var leftElement = sortedElements.FirstOrDefault(); var xCoord = (rightElement.Center.X + leftElement.Center.X) / 2; foreach (var alignElement in sortedElements) { XYZ resultingPoint = new(xCoord, alignElement.Center.Y, 0); alignElement.MoveTo(resultingPoint, AlignType.HorizontallyCenter); } break; } case AlignType.VerticallyCenter: //同一条水平轴 { var sortedElements = alignElements.OrderBy(x => x.UpRight.Y).ToList(); var upperAlignAnnotation = sortedElements.LastOrDefault(); var lowerAlignAnnotation = sortedElements.FirstOrDefault(); var yCoord = (upperAlignAnnotation.Center.Y + lowerAlignAnnotation.Center.Y) / 2; foreach (var alignElement in sortedElements) { XYZ resultingPoint = new(alignElement.Center.X, yCoord, 0); alignElement.MoveTo(resultingPoint, AlignType.VerticallyCenter); } break; } case AlignType.Bottom: { var sortedElements = alignElements.OrderBy(z => z.Bottom).ToList(); var elevation = sortedElements.FirstOrDefault(); foreach (var alignElement in sortedElements) { XYZ resultingPoint = new(0, 0, elevation.Bottom); alignElement.MoveTo(resultingPoint, AlignType.Bottom); } break; } case AlignType.Middle: { var sortedElements = alignElements.OrderBy(z => z.Middle).ToList(); //var middle = sortedElements.FirstOrDefault(); var topAlign = sortedElements.LastOrDefault(); var botAlign = sortedElements.FirstOrDefault(); var middle = (topAlign.Middle + botAlign.Middle) / 2; foreach (var alignElement in sortedElements) { XYZ resultingPoint = new(0, 0, middle); alignElement.MoveTo(resultingPoint, AlignType.Middle); } break; } case AlignType.Top: { var sortedElements = alignElements.OrderByDescending(z => z.Top).ToList(); var top = sortedElements.FirstOrDefault(); foreach (var alignElement in sortedElements) { XYZ resultingPoint = new(0, 0, top.Top); alignElement.MoveTo(resultingPoint, AlignType.Top); } break; } } } /// /// 对齐命令 /// /// private void AlignCommand(object obj) { if (obj is not Autodesk.Windows.RibbonButton rb) { return; } var alignType = (AlignType)rb.CommandParameter; handler.Raise(_ => { Document.Invoke( _ => { var selectedIds = UIDocument.Selection.GetElementIds(); var alignElements = (from id in selectedIds let e = new AlignModelElement(Document.GetElement(id)) select e).ToList(); //List alignElements = new(); //foreach (var id in selectedIds) //{ // var e = Document.GetElement(id); // alignElements.Add(new AlignModelElement(e)); //} AlignByType(alignElements, alignType); }, alignType.GetAttribute().Description); }); } /// /// 是否能进行对齐操作 /// /// private bool CanAlign() { return UIDocument?.Selection .GetElementIds() .Count(id => Document.GetElement(id) is GenericForm || Document.GetElement(id).Category?.CategoryType == CategoryType.Model) > 1; } /// /// 对齐面板 /// /// private void AlignPanel(RibbonTab tab) { //新建面板 Autodesk.Windows.RibbonPanel alignElemsPanel = new() { FloatingOrientation = System.Windows.Controls.Orientation.Vertical }; //面板资源 RibbonPanelSource alignSource = new() { Id = "ID_Layout_Panel", Title = "布局" }; alignElemsPanel.Source = alignSource; //面板按钮 var alignLeftBtn = new Autodesk.Windows.RibbonButton { Image = Resources.align_left_16px.ToBitmapSource(), //LargeImage = Properties.Resources.align_left_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_ALL_BTN", Name = "左对齐", ToolTip = "根据几何元素范围,元素左侧对齐", Text = "左对齐", IsCheckable = true, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.Left //Orientation = System.Windows.Controls.Orientation.Vertical }; var alignRightBtn = new Autodesk.Windows.RibbonButton { Image = Resources.align_right_16px.ToBitmapSource(), //LargeImage = Properties.Resources.align_right_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_ALR_BTN", Name = "右对齐", ToolTip = "根据几何元素范围,元素右侧对齐", Text = "右对齐", IsCheckable = true, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.Right //Orientation = System.Windows.Controls.Orientation.Vertical }; var alignDownBtn = new Autodesk.Windows.RibbonButton { Image = Resources.align_down_16px.ToBitmapSource(), //LargeImage = Properties.Resources.align_down_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_ALD_BTN", Name = "下对齐", ToolTip = "根据几何元素范围,元素底部对齐", Text = "下对齐", IsCheckable = true, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.Down //Orientation = System.Windows.Controls.Orientation.Vertical }; var alignUpBtn = new Autodesk.Windows.RibbonButton { Image = Resources.align_top_16px.ToBitmapSource(), //LargeImage = Properties.Resources.align_top_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_ALU_BTN", Name = "上对齐", ToolTip = "根据几何元素范围,元素顶部对齐", Text = "上对齐", IsCheckable = true, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.Up //Orientation = System.Windows.Controls.Orientation.Vertical }; var alignHCBtn = new Autodesk.Windows.RibbonButton { Image = Resources.align_center_16px.ToBitmapSource(), //LargeImage = Properties.Resources.align_center_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_ALHC_BTN", Name = "水平中", ToolTip = "根据几何元素范围,水平居中", Text = "水平中", IsCheckable = true, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.HorizontallyCenter //Orientation = System.Windows.Controls.Orientation.Vertical }; var alignVCBtn = new Autodesk.Windows.RibbonButton { Image = Resources.align_middle_16px.ToBitmapSource(), //LargeImage = Properties.Resources.align_middle_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_ALVC_BTN", Name = "垂直中", ToolTip = "根据几何元素范围,垂直居中", Text = "垂直中", IsCheckable = true, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.VerticallyCenter //Orientation = System.Windows.Controls.Orientation.Vertical }; var alignTopBtn = new Autodesk.Windows.RibbonButton { Image = Resources.top_elev_16px.ToBitmapSource(), LargeImage = Resources.top_elev_32px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, ToolTip = "几何元素顶部高程对齐", Id = "ID_ALT_BTN", Name = "顶对齐", Text = "顶对齐", IsCheckable = true, //默认水平,文字与图标 //Orientation = Orientation.Vertical, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.Top }; var alignMiddleBtn = new Autodesk.Windows.RibbonButton { Image = Resources.middle_elev_16px.ToBitmapSource(), LargeImage = Resources.middle_elev_32px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, ToolTip = "几何元素中心高程对齐", Id = "ID_ALM_BTN", Name = "中对齐", Text = "中对齐", IsCheckable = true, //Orientation = Orientation.Vertical, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.Middle }; var alignBottomBtn = new Autodesk.Windows.RibbonButton { Image = Resources.bottom_elev_16px.ToBitmapSource(), LargeImage = Resources.bottom_elev_32px.ToBitmapSource(), //Standard为16px,Large为32px Size = RibbonItemSize.Standard, ShowText = true, ToolTip = "几何元素底部高程对齐", Id = "ID_ALB_BTN", Name = "底对齐", Text = "底对齐", IsCheckable = true, //Orientation = Orientation.Vertical, CommandHandler = new RelayCommand(AlignCommand, _ => CanAlign()), CommandParameter = AlignType.Bottom }; //面板行布局 RibbonRowPanel ribbonRowPanel = new(); ribbonRowPanel.Items.Add(alignLeftBtn); ribbonRowPanel.Items.Add(alignRightBtn); //换行 ribbonRowPanel.Items.Add(new RibbonRowBreak()); ribbonRowPanel.Items.Add(alignUpBtn); ribbonRowPanel.Items.Add(alignDownBtn); ribbonRowPanel.Items.Add(new RibbonRowBreak()); ribbonRowPanel.Items.Add(alignHCBtn); ribbonRowPanel.Items.Add(alignVCBtn); //第二个面板行布局 RibbonRowPanel ribbonRowPanel1 = new(); ribbonRowPanel1.Items.Add(alignTopBtn); ribbonRowPanel1.Items.Add(new RibbonRowBreak()); ribbonRowPanel1.Items.Add(alignMiddleBtn); ribbonRowPanel1.Items.Add(new RibbonRowBreak()); ribbonRowPanel1.Items.Add(alignBottomBtn); //布局添加到面板数据源 alignSource.Items.Add(ribbonRowPanel); alignSource.Items.Add(ribbonRowPanel1); tab.Panels.Add(alignElemsPanel); } /// /// 选择元素面板 /// /// private void SelectionPanel(RibbonTab tab) { //新建面板 Autodesk.Windows.RibbonPanel ribbonPanel = new() { FloatingOrientation = System.Windows.Controls.Orientation.Vertical }; //面板资源 RibbonPanelSource selSource = new() { Id = "ID_SSI_Panel", Title = "选择元素" }; ribbonPanel.Source = selSource; //面板按钮 Autodesk.Windows.RibbonButton iavBtn = new() { //Image = new System.Windows.Media.Imaging.BitmapImage(new Uri(icopath)), Image = Resources.select_on_view_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_IAV_BTN", Name = "视图类似实例", ToolTip = "选择视图中的同类型实例", Text = "视图类似实例", IsCheckable = true, CommandHandler = new RelayCommand( () => { //var selectedIds = UIDocument.Selection.GetElementIds(); //var groups = selectedIds.GroupBy(id => Document.GetElement(id).GetTypeId()); var col = new FilteredElementCollector(Document, UIDocument.ActiveView.Id); var typeIds = UIDocument.Selection .GetElementIds() .Where(id => Document.GetElement(id).GetTypeId() != null) .Select(id => Document.GetElement(id).GetTypeId()) .Distinct() .ToList(); //ICollection setSelIds = (from t in types // select Document.GetElement(t.Id) into selectedElement // from item in col // where selectedElement.Id == item.GetTypeId() && item.Category != null // select item.Id) var setSelIds = ( from typeId in typeIds from elem in col where typeId == elem.GetTypeId() && elem.Category != null select elem.Id ).ToList(); UIDocument.Selection.SetElementIds(setSelIds); }, () => UIDocument?.Selection .GetElementIds() .Any(id => Document.GetElement(id).GetTypeId() != ElementId.InvalidElementId && Document.GetElement(id).Category != null) == true ) //Orientation = System.Windows.Controls.Orientation.Vertical }; Autodesk.Windows.RibbonButton iipBtn = new() { Image = Resources.select_on_project_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_IIP_BTN", //下拉显示名 Name = "项目类似实例", ToolTip = "选择项目中的同类型实例", //选中显示名 Text = "项目类似实例", IsCheckable = true, CommandHandler = new RelayCommand( () => { //var selectedIds = UIDocument.Selection.GetElementIds(); var typeIds = UIDocument.Selection .GetElementIds() .Where(id => Document.GetElement(id).GetTypeId() != null) .Select(id => Document.GetElement(id).GetTypeId()) .Distinct() .ToList(); var col = Document.OfCollector().WhereElementIsNotElementType(); //var groups = selectedIds.GroupBy(id => Document.GetElement(id).GetTypeId()); var setSelIds = ( from typeId in typeIds from elem in col where typeId == elem.GetTypeId() && elem.Category != null select elem.Id ).ToList(); UIDocument.Selection.SetElementIds(setSelIds); }, () => UIDocument?.Selection .GetElementIds() .Any(id => Document.GetElement(id).Category != null && Document.GetElement(id).GetTypeId() != ElementId.InvalidElementId) == true ) //Orientation = System.Windows.Controls.Orientation.Vertical }; Autodesk.Windows.RibbonButton rSelBtn = new() { Image = Resources.select_3d_object_16px.ToBitmapSource(), Size = RibbonItemSize.Standard, ShowText = true, Id = "ID_BS_BTN", //下拉显示名 Name = "框选类似实例", ToolTip = "框选与当前选择实例同类型的实例", //选中显示名 Text = "框选类似实例", IsCheckable = true, CommandHandler = new RelayCommand( () => { try { var typeIds = UIDocument.Selection .GetElementIds() .Where(id => Document.GetElement(id).GetTypeId() != null) .Select(id => Document.GetElement(id).GetTypeId()) .Distinct() .ToList(); var setSelectedElemIds = new List(); var sameTypesFilter = new FuncFilter(elem => { return typeIds.Any(id => id.Equals(elem.GetTypeId())); }); var elements = UIDocument.Selection.PickElementsByRectangle(sameTypesFilter, "请框选与当前选择元素相同的实例"); setSelectedElemIds.AddRange(elements.Select(e => e.Id)); UIDocument.Selection.SetElementIds(setSelectedElemIds); } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { } }, () => { return UIDocument?.Selection .GetElementIds() .Any(id => { var elem = Document.GetElement(id); return elem.Category != null && elem.GetTypeId() != ElementId.InvalidElementId; }) == true; } ) //Orientation = System.Windows.Controls.Orientation.Vertical }; //面板按钮 Autodesk.Windows.RibbonButton selFilterBtn = new() { //Image = new System.Windows.Media.Imaging.BitmapImage(new Uri(icopath)), Image = Resources.select_filter_16px.ToBitmapSource(), LargeImage = Resources.select_filter_32px.ToBitmapSource(), Size = RibbonItemSize.Large, ShowText = true, Id = "ID_Filter_BTN", Name = "构件明细", ToolTip = "查看选中的元素", Text = "构件明细", IsCheckable = true, Orientation = Orientation.Vertical, CommandHandler = new RelayCommand( () => WinDialogHelper.ShowModeless(new DetailSelectFiltersViewModel(uiapp, handler)), () => UIDocument?.Selection .GetElementIds() .Any(id => Document.GetElement(id).GetTypeId() != ElementId.InvalidElementId && Document.GetElement(id).Category != null) == true ) }; //面板行布局 RibbonRowPanel ribbonRowPanel = new(); ribbonRowPanel.AddAwStackItems(iavBtn, iipBtn, rSelBtn); //ribbonRowPanel.Items.Add(iavBtn); ////行打断=新建行 //ribbonRowPanel.Items.Add(new RibbonRowBreak()); //ribbonRowPanel.Items.Add(iipBtn); //ribbonRowPanel.Items.Add(new RibbonRowBreak()); //ribbonRowPanel.Items.Add(rSelBtn); RibbonRowPanel ribbonRowPanel1 = new(); ribbonRowPanel1.Items.Add(selFilterBtn); //ribbonPanel.Source.Items.Add(selFilterBtn); //布局添加到面板数据源 selSource.Items.Add(ribbonRowPanel); selSource.Items.Add(ribbonRowPanel1); ////分隔条 //RibbonSeparator rsP = new RibbonSeparator(); //rsP.SeparatorStyle = RibbonSeparatorStyle.Invisible; tab.Panels.Add(ribbonPanel); } private void FilterPanel(RibbonTab tab) { Autodesk.Windows.RibbonPanel ribbonPanel = new(); //面板资源 RibbonPanelSource filterSource = new() { Id = "ID_Filter_Panel", Title = "选择过滤" }; ribbonPanel.Source = filterSource; //面板按钮 Autodesk.Windows.RibbonButton btn = new() { //Image = new System.Windows.Media.Imaging.BitmapImage(new Uri(icopath)), Image = Resources.select_filter_16px.ToBitmapSource(), LargeImage = Resources.select_filter_32px.ToBitmapSource(), Size = RibbonItemSize.Large, ShowText = true, Id = "ID_Filter_BTN", Name = "选择过滤", ToolTip = "查看选中的元素", Text = "选择过滤", IsCheckable = true, Orientation = Orientation.Vertical, CommandHandler = new RelayCommand( () => WinDialogHelper.ShowModeless(new DetailSelectFiltersViewModel(uiapp, handler)), () => UIDocument?.Selection .GetElementIds() .Any(id => Document.GetElement(id).GetTypeId() != ElementId.InvalidElementId && Document.GetElement(id).Category != null) == true ) }; ribbonPanel.Source.Items.Add(btn); tab.Panels.Add(ribbonPanel); } }