优化更新代码,添加界面功能并整合
This commit is contained in:
24
ShrlAlgo.RvKits/RvCivil/BricksFinishesCmd.cs
Normal file
24
ShrlAlgo.RvKits/RvCivil/BricksFinishesCmd.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class BricksFinishesCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
WinDialogHelper.ShowModeless<BricksFinishesView>(new BricksFinishesViewModel());
|
||||
//var fl = SingletonViewHelpers<BricksFinishesView>.GetInstance(out var isNewCreate);
|
||||
//if (isNewCreate)
|
||||
//{
|
||||
// fl.DataContext = new BricksFinishesViewModel();
|
||||
// fl.ShowAhead();
|
||||
//}
|
||||
//fl.Activate();
|
||||
}
|
||||
}
|
||||
68
ShrlAlgo.RvKits/RvCivil/BricksFinishesView.xaml
Normal file
68
ShrlAlgo.RvKits/RvCivil/BricksFinishesView.xaml
Normal file
@@ -0,0 +1,68 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvCivil.BricksFinishesView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:rvCivil="clr-namespace:ShrlAlgo.RvKits.RvCivil"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="铺贴"
|
||||
Width="180"
|
||||
Height="500"
|
||||
MinHeight="500"
|
||||
d:DataContext="{d:DesignInstance rvCivil:BricksFinishesViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:AutoGridEx ChildMargin="5" Columns="*">
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbPavementLength"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Prefix="砖长:"
|
||||
Suffix="mm"
|
||||
Text="{Binding PavementLength, StringFormat={}{0:F2}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbPavementWidth"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Prefix="砖宽:"
|
||||
Suffix="mm"
|
||||
Text="{Binding PavementWidth, StringFormat={}{0:F2}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbPavementGap"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Prefix="砖缝:"
|
||||
Suffix="mm"
|
||||
Text="{Binding PavementGap, StringFormat={}{0:F2}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbPavementThickness"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Prefix="砖厚:"
|
||||
Suffix="mm"
|
||||
Text="{Binding PavementThickness, StringFormat={}{0:F2}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbPavementBaseOffset"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Prefix="墙砖底标高:"
|
||||
Suffix="mm"
|
||||
Text="{Binding WallBaseOffset, StringFormat={}{0:F2}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbPavementName"
|
||||
Prefix="铺砖名(类型名):"
|
||||
Text="{Binding PanelName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<GroupBox Grid.Row="1" Header="铺设方式">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton Content="房间" IsChecked="{Binding ByRoom, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<RadioButton Content="平面" IsChecked="{Binding ByRoom, Converter={StaticResource InvertBooleanConverter}}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<CheckBox Content="边界留缝" IsChecked="{Binding IsEdgeExistGap, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Button
|
||||
x:Name="BtnByFace"
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding PlaceBricksCommand}"
|
||||
Content="铺设"
|
||||
IsEnabled="{Binding HasErrors, Mode=OneWay, Converter={StaticResource InvertBooleanConverter}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</ui:AutoGridEx>
|
||||
</ui:FluentWindowEx>
|
||||
15
ShrlAlgo.RvKits/RvCivil/BricksFinishesView.xaml.cs
Normal file
15
ShrlAlgo.RvKits/RvCivil/BricksFinishesView.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
/// <summary>
|
||||
/// BricksFinishesView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class BricksFinishesView
|
||||
{
|
||||
public BricksFinishesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
838
ShrlAlgo.RvKits/RvCivil/BricksFinishesViewModel.cs
Normal file
838
ShrlAlgo.RvKits/RvCivil/BricksFinishesViewModel.cs
Normal file
@@ -0,0 +1,838 @@
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Architecture;
|
||||
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
using ShrlAlgo.Toolkit.Mvvm.Attributes;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
public partial class BricksFinishesViewModel : ObservableValidator
|
||||
{
|
||||
public BricksFinishesViewModel()
|
||||
{
|
||||
finishesHandler = new ActionEventHandler();
|
||||
PavementLength = 600;
|
||||
PavementWidth = 600;
|
||||
PavementGap = 2;
|
||||
WallBaseOffset = 0;
|
||||
PavementThickness = 2;
|
||||
PanelName = "铺砖";
|
||||
}
|
||||
|
||||
private readonly ActionEventHandler finishesHandler;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool byRoom;
|
||||
|
||||
//边界限具有缝隙
|
||||
[ObservableProperty]
|
||||
private bool isEdgeExistGap;
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[Minimum(10.0)]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private double pavementWidth;
|
||||
|
||||
//public double PavementWidth
|
||||
//{
|
||||
// get => pavementWidth;
|
||||
// set => SetProperty(ref pavementWidth, value, true);
|
||||
//}
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private double wallBaseOffset;
|
||||
|
||||
// public double WallBaseOffset
|
||||
//{
|
||||
// get => wallBaseOffset;
|
||||
// set => SetProperty(ref wallBaseOffset, value, true);
|
||||
//}
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[Minimum(1.0)]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private double pavementThickness;
|
||||
|
||||
// public double PavementThickness
|
||||
//{
|
||||
// get => pavementThickness;
|
||||
// set => SetProperty(ref pavementThickness, value, true);
|
||||
//}
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[Minimum(10.0)]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private double pavementLength;
|
||||
|
||||
// public double PavementLength
|
||||
//{
|
||||
// get => pavementLength;
|
||||
// set => SetProperty(ref pavementLength, value, true);
|
||||
//}
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[IsNumeric]
|
||||
[Minimum(1.0)]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private double pavementGap;
|
||||
// public double PavementGap
|
||||
//{
|
||||
// get => pavementGap;
|
||||
// set => SetProperty(ref pavementGap, value, true);
|
||||
//}
|
||||
|
||||
[Required(ErrorMessage = "不可为空")]
|
||||
[MinLength(1)]
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
private string panelName;
|
||||
|
||||
// public string PanelName
|
||||
//{
|
||||
// get => panelName;
|
||||
// set
|
||||
// {
|
||||
// SetProperty(ref panelName, value, true);
|
||||
// PlaceBricksCommand.NotifyCanExecuteChanged();
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
private static CurtainSystemType SetCurtainSystemType(Document doc, double length, double width, double gap, double thickness, string panelName)
|
||||
{
|
||||
var curtainSystemTypeCollector = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(CurtainSystemType))
|
||||
.OfCategory(BuiltInCategory.OST_CurtaSystem)
|
||||
.Cast<CurtainSystemType>()
|
||||
.ToList();
|
||||
var panelTypeCollector = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(PanelType))
|
||||
.OfCategory(BuiltInCategory.OST_CurtainWallPanels)
|
||||
.Cast<PanelType>()
|
||||
.ToList();
|
||||
var curtainWallMullionsTypeCollector = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(MullionType))
|
||||
.OfCategory(BuiltInCategory.OST_CurtainWallMullions)
|
||||
.Cast<MullionType>()
|
||||
.ToList();
|
||||
|
||||
CurtainSystemType curtainSystemType = null;
|
||||
PanelType panelType = null;
|
||||
MullionType mullionType = null;
|
||||
|
||||
var curtainSystemTypeName = $"铺砖-{length}mm x {width}mm";
|
||||
var panelTypeName = panelName;
|
||||
var mullionTypeName = $"{gap}mm x {thickness}mm";
|
||||
|
||||
//创建嵌板类型
|
||||
try
|
||||
{
|
||||
var defaultPanelType = panelTypeCollector.FirstOrDefault();
|
||||
panelType = defaultPanelType.Duplicate(panelTypeName) as PanelType;
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.ArgumentException)
|
||||
{
|
||||
foreach (var t in panelTypeCollector)
|
||||
{
|
||||
if (t.Name == panelTypeName)
|
||||
{
|
||||
panelType = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panelType?.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_THICKNESS).Set(thickness / 304.8);
|
||||
//嵌板偏移
|
||||
panelType?.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_OFFSET).Set(0);
|
||||
//创建竖挺类型
|
||||
try
|
||||
{
|
||||
var defaultMullionType = curtainWallMullionsTypeCollector.FirstOrDefault(
|
||||
m => m.FamilyName.Contains("矩形") || m.FamilyName.Contains("Rectangular")
|
||||
);
|
||||
mullionType = defaultMullionType.Duplicate(mullionTypeName) as MullionType;
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.ArgumentException)
|
||||
{
|
||||
foreach (var t in curtainWallMullionsTypeCollector)
|
||||
{
|
||||
if (t.Name == mullionTypeName)
|
||||
{
|
||||
mullionType = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//设置参数
|
||||
|
||||
mullionType?.get_Parameter(BuiltInParameter.RECT_MULLION_WIDTH1).Set(gap / 304.8 / 2);
|
||||
mullionType?.get_Parameter(BuiltInParameter.RECT_MULLION_WIDTH2).Set(gap / 304.8 / 2);
|
||||
mullionType?.get_Parameter(BuiltInParameter.RECT_MULLION_THICK).Set(thickness / 304.8);
|
||||
|
||||
//创建幕墙系统类型
|
||||
try
|
||||
{
|
||||
var defaultCurtainSystemType = curtainSystemTypeCollector.FirstOrDefault();
|
||||
curtainSystemType = defaultCurtainSystemType.Duplicate(curtainSystemTypeName) as CurtainSystemType;
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.ArgumentException)
|
||||
{
|
||||
foreach (var t in curtainSystemTypeCollector)
|
||||
{
|
||||
if (t.Name == curtainSystemTypeName)
|
||||
{
|
||||
curtainSystemType = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//mullionType.get_Parameter(BuiltInParameter.MULLION_OFFSET).Set(0);
|
||||
//mullionType.get_Parameter(BuiltInParameter.MULLION_OFFSET).Set(thickness / 304.8 );
|
||||
|
||||
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.SPACING_LAYOUT_1).Set(1);
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.SPACING_LAYOUT_2).Set(1);
|
||||
|
||||
//panelType.get_Parameter(BuiltInParameter.CURTAIN_WALL_SYSPANEL_OFFSET).Set(-thickness / 304.8 / 2);
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.SPACING_LENGTH_1).Set((width + gap) / 304.8);
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.SPACING_LENGTH_2).Set((length + gap) / 304.8);
|
||||
if (mullionType != null && panelType != null)
|
||||
{
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.AUTO_PANEL).Set(panelType.Id);
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.AUTO_MULLION_INTERIOR_GRID1).Set(mullionType.Id);
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.AUTO_MULLION_INTERIOR_GRID2).Set(mullionType.Id);
|
||||
}
|
||||
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.CURTAINGRID_ADJUST_BORDER_1).Set(1);
|
||||
curtainSystemType?.get_Parameter(BuiltInParameter.CURTAINGRID_ADJUST_BORDER_2).Set(1);
|
||||
//curtainSystemType.get_Parameter(BuiltInParameter.AUTO_MULLION_BORDER1_GRID1).Set(mullionType.ViewId);
|
||||
//curtainSystemType.get_Parameter(BuiltInParameter.AUTO_MULLION_BORDER1_GRID2).Set(mullionType.ViewId);
|
||||
//curtainSystemType.get_Parameter(BuiltInParameter.AUTO_MULLION_BORDER2_GRID1).Set(mullionType.ViewId);
|
||||
//curtainSystemType.get_Parameter(BuiltInParameter.AUTO_MULLION_BORDER2_GRID2).Set(mullionType.ViewId);
|
||||
return curtainSystemType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取偏移量
|
||||
/// </summary>
|
||||
/// <param name="coord">UV平面坐标系</param>
|
||||
/// <param name="start">拾取的起铺点</param>
|
||||
/// <returns></returns>
|
||||
private static double[,] GetOffset(List<XYZ> coord, XYZ start)
|
||||
{
|
||||
var origin = coord[0];
|
||||
//var insterIntersectionResult = line.ProjectOf(origin);
|
||||
//var project = insterIntersectionResult?.XYZPoint;
|
||||
//var dis = insterIntersectionResult?.DistanceX;
|
||||
//var uDirection = XYZ.Zero;
|
||||
//var vDirection = XYZ.Zero;
|
||||
//bool lineIsU = false;
|
||||
double uoffest;
|
||||
double voffest;
|
||||
var p = start - origin;
|
||||
//u轴进行的偏移实际是v轴沿着u轴的偏移值,故应相反设置偏移值
|
||||
//因为轴的模长度为1,所以直接等于p在轴上的投影长度
|
||||
uoffest = p.DotProduct(coord[1]);
|
||||
//if (coord[1].CrossProduct(p).Z < 0)
|
||||
//{
|
||||
// uoffest = -uoffest;
|
||||
//}
|
||||
voffest = p.DotProduct(coord[2]);
|
||||
//if (coord[2].CrossProduct(p).Z < 0)
|
||||
//{
|
||||
// voffest = -voffest;
|
||||
//}
|
||||
//if (coord[1].CrossProduct(line.Direction).IsAlmostEqualTo(XYZ.Zero))
|
||||
//{
|
||||
// uoffest = coord[1].DotProduct(p) * coord[1];
|
||||
// voffest = coord[2].DotProduct(p) * coord[2];
|
||||
// ////得到起铺点相对幕墙系统原点的偏移量
|
||||
// //double offest = default;
|
||||
// //if ((start - origin).Normalize().IsAlmostEqualTo(coord[1]))
|
||||
// //{
|
||||
// // offest = (start - origin).GetLength();
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // offest = -(start - origin).GetLength();
|
||||
// //}
|
||||
// //result.Add(coord[1], offest);//u
|
||||
// //if ((project - origin).Normalize().IsAlmostEqualTo(coord[2]))
|
||||
// //{
|
||||
// // offest = (project - origin).GetLength();
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // offest = -(project - origin).GetLength();
|
||||
// //}
|
||||
// //result.Add(coord[2], offest);//v
|
||||
//}
|
||||
//else if (coord[2].CrossProduct(line.Direction).IsAlmostEqualTo(XYZ.Zero))
|
||||
//{
|
||||
// isInvert = true;
|
||||
// uoffest = coord[2].DotProduct(p) * coord[2];
|
||||
// voffest = coord[1].DotProduct(p) * coord[1];
|
||||
// //double offest = default;
|
||||
// //if ((project - origin).Normalize().IsAlmostEqualTo(coord[1]))
|
||||
// //{
|
||||
// // offest = (project - origin).GetLength();
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // offest = -(project - origin).GetLength();
|
||||
// //}
|
||||
// //result.Add(coord[1], offest);//v
|
||||
|
||||
|
||||
// //if ((start - origin).DotProduct(coord[1]) > 0)
|
||||
// //{
|
||||
// // offest = (start - origin).GetLength();
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // offest = -(start - origin).GetLength();
|
||||
// //}
|
||||
// //result.Add(coord[1], offest);//v
|
||||
//}
|
||||
////if (project != null)
|
||||
////{
|
||||
//// var offset = project.DistanceTo(start);
|
||||
//// //判断正方向还是反方向
|
||||
//// if ((start - project).Normalize().IsAlmostEqualTo(-coord[1]))
|
||||
//// {
|
||||
//// offset = -offset;
|
||||
//// }
|
||||
//// //var direction = XYZ.BasisZ.CrossProduct(pl.FaceNormal);
|
||||
|
||||
//// //if (direction.IsAlmostEqualTo(line.Direction))
|
||||
//// //{
|
||||
//// // offset = xyz.DistanceTo(startPoint) * 304.8;
|
||||
//// //}
|
||||
//// //else
|
||||
//// //{
|
||||
//// // offset = xyz.DistanceTo(endPoint) * 304.8;
|
||||
//// //}
|
||||
//// //offset = x;
|
||||
//// var n = Math.Floor(offset / interval);
|
||||
//// offset -= Math.Floor(n) * interval;
|
||||
//// return offset;
|
||||
////}
|
||||
//if (voffest == null || uoffest == null)
|
||||
//{
|
||||
// return null;
|
||||
//}
|
||||
return new[,]
|
||||
{
|
||||
{ uoffest, voffest }
|
||||
};
|
||||
}
|
||||
|
||||
private static FaceArray GetFaceArray(Document doc, List<CurveLoop> curveLoops, out DirectShape ds)
|
||||
{
|
||||
FaceArray array = new();
|
||||
|
||||
var solid = GeometryCreationUtilities.CreateExtrusionGeometry(curveLoops, -XYZ.BasisZ, 10.0);
|
||||
ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_Mass));
|
||||
|
||||
ds?.AppendShape(new List<GeometryObject> { solid });
|
||||
|
||||
foreach (Face face in solid.Faces)
|
||||
{
|
||||
var pf = face as PlanarFace;
|
||||
if (pf.FaceNormal.IsAlmostEqualTo(XYZ.BasisZ))
|
||||
{
|
||||
array.Append(face);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最终幕墙系统坐标
|
||||
/// </summary>
|
||||
/// <param name="doc"></param>
|
||||
/// <param name="array"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="rotation"></param>
|
||||
/// <returns></returns>
|
||||
private static List<XYZ> GetCoordinateSystem(Document doc, FaceArray array, Line line, out Rotation rotation)
|
||||
{
|
||||
var curtainSystemTypeCollector = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(CurtainSystemType))
|
||||
.OfCategory(BuiltInCategory.OST_CurtaSystem);
|
||||
XYZ origin = null;
|
||||
XYZ u = null;
|
||||
XYZ v = null;
|
||||
rotation = null;
|
||||
using (Transaction trans = new(doc, "获取坐标系"))
|
||||
{
|
||||
trans.Start();
|
||||
if (curtainSystemTypeCollector.FirstOrDefault() is CurtainSystemType defaultCurtainSystemType)
|
||||
{
|
||||
defaultCurtainSystemType.get_Parameter(BuiltInParameter.SPACING_LAYOUT_1).Set(2);
|
||||
defaultCurtainSystemType.get_Parameter(BuiltInParameter.SPACING_LAYOUT_2).Set(2);
|
||||
var curtainSystem = doc.Create.NewCurtainSystem(array, defaultCurtainSystemType);
|
||||
//编号
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_NUM_DIVISIONS_1).Set(1);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_NUM_DIVISIONS_2).Set(1);
|
||||
//对正
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_JUSTIFICATION_1).Set(2);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_JUSTIFICATION_2).Set(2);
|
||||
//
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ORIGIN_1).Set(0);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ORIGIN_2).Set(0);
|
||||
doc.Regenerate();
|
||||
origin = GetOrigin(doc, curtainSystem, out u, out v);
|
||||
var list = new List<XYZ> { origin, u, v };
|
||||
//获取旋转角度
|
||||
rotation = GetRotation(list, line);
|
||||
//设置旋转角
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ANGLE_1).Set(rotation.Radian);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ANGLE_2).Set(rotation.Radian);
|
||||
//得到转换后的角度
|
||||
doc.Regenerate();
|
||||
origin = GetOrigin(doc, curtainSystem, out u, out v);
|
||||
}
|
||||
|
||||
trans.RollBack();
|
||||
//trans.Commit();
|
||||
}
|
||||
|
||||
return [origin, u, v];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 得到旋转角度
|
||||
/// </summary>
|
||||
/// <param name="coordSystem"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static Rotation GetRotation(List<XYZ> coordSystem, Line line)
|
||||
{
|
||||
var radian1 = coordSystem[1].AngleTo(line.Direction);
|
||||
Rotation rotation1 =
|
||||
new()
|
||||
{
|
||||
Radian = radian1,
|
||||
Direction = line.Direction,
|
||||
Orientation = Orientation.U,
|
||||
CoordSystemAxis = coordSystem[1]
|
||||
};
|
||||
var radian2 = coordSystem[1].AngleTo(-line.Direction);
|
||||
Rotation rotation2 =
|
||||
new()
|
||||
{
|
||||
Radian = radian2,
|
||||
Direction = -line.Direction,
|
||||
Orientation = Orientation.U,
|
||||
CoordSystemAxis = coordSystem[1]
|
||||
};
|
||||
|
||||
var radian3 = coordSystem[2].AngleTo(line.Direction);
|
||||
Rotation rotation3 =
|
||||
new()
|
||||
{
|
||||
Radian = radian3,
|
||||
Direction = line.Direction,
|
||||
Orientation = Orientation.V,
|
||||
CoordSystemAxis = coordSystem[2]
|
||||
};
|
||||
var radian4 = coordSystem[2].AngleTo(-line.Direction);
|
||||
Rotation rotation4 =
|
||||
new()
|
||||
{
|
||||
Radian = radian4,
|
||||
Direction = -line.Direction,
|
||||
Orientation = Orientation.V,
|
||||
CoordSystemAxis = coordSystem[2]
|
||||
};
|
||||
List<Rotation> rotations = [rotation1, rotation2, rotation3, rotation4];
|
||||
var rotation = rotations.OrderBy(r => r.Radian).First();
|
||||
|
||||
if (rotation.CoordSystemAxis.CrossProduct(rotation.Direction).Z < 0)
|
||||
{
|
||||
rotation.Radian = -rotation.Radian;
|
||||
}
|
||||
|
||||
return rotation;
|
||||
//double radian;
|
||||
////grid2的轴向单位向量
|
||||
////在平面
|
||||
//if (pl.FaceNormal.IsAlmostEqualTo(XYZ.BasisZ))
|
||||
//{
|
||||
|
||||
// var perpendicularVector = line.Direction.CrossProduct(XYZ.BasisZ);
|
||||
// if (perpendicularVector.Y < 0)
|
||||
// {
|
||||
// perpendicularVector = -perpendicularVector;
|
||||
// }
|
||||
|
||||
// radian = perpendicularVector.X > 0 ? -perpendicularVector.AngleTo(XYZ.BasisY) : perpendicularVector.AngleTo(XYZ.BasisY);
|
||||
|
||||
// //angle = radian * 180 / Math.PI;
|
||||
|
||||
|
||||
// if (Math.Abs(Math.Round(radian, MidpointRounding.AwayFromZero) - Math.PI / 2) < 0.0001)
|
||||
// {
|
||||
// radian = 0;
|
||||
// }
|
||||
//}
|
||||
//else//在垂直面
|
||||
//{
|
||||
// radian = 0;
|
||||
//}
|
||||
|
||||
//return radian;
|
||||
}
|
||||
|
||||
private static void CreateCurtainSystemByFace(
|
||||
UIDocument uidoc,
|
||||
double length,
|
||||
double width,
|
||||
double gap,
|
||||
double thickness,
|
||||
double wallBaseOffset,
|
||||
string panelName,
|
||||
bool isEdgeExistGap
|
||||
)
|
||||
{
|
||||
var doc = uidoc.Document;
|
||||
var faceReference = uidoc.Selection.PickObject(ObjectType.Face, "请选择铺贴的面");
|
||||
var element = doc.GetElement(faceReference);
|
||||
double baseHeight = default;
|
||||
double height = default;
|
||||
doc.InvokeGroup(
|
||||
tg =>
|
||||
{
|
||||
if (element is Wall)
|
||||
{
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
//顶部约束
|
||||
var topConstraint = element.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();
|
||||
if (topConstraint == ElementId.InvalidElementId) //未连接
|
||||
{
|
||||
//无连接高度
|
||||
height = element.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
|
||||
element.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(height - (wallBaseOffset / 304.8));
|
||||
}
|
||||
|
||||
baseHeight = element.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
|
||||
element.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(baseHeight + (wallBaseOffset / 304.8));
|
||||
},
|
||||
"设置墙底部高度"
|
||||
);
|
||||
}
|
||||
|
||||
var face = element.GetGeometryObjectFromReference(faceReference) as Face;
|
||||
var pl = face as PlanarFace;
|
||||
if (pl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double radian = 0;
|
||||
double actualU = 0;
|
||||
double actualV = 0;
|
||||
FaceArray array = new();
|
||||
array.Append(face);
|
||||
|
||||
var referEdge = uidoc.Selection.PickObject(ObjectType.Edge, new EdgeFilter(element), "请选择对齐的边");
|
||||
var xyz = uidoc.Selection.PickPoint(
|
||||
ObjectSnapTypes.Intersections
|
||||
| ObjectSnapTypes.Endpoints
|
||||
| ObjectSnapTypes.Centers
|
||||
| ObjectSnapTypes.Midpoints
|
||||
| ObjectSnapTypes.Points
|
||||
| ObjectSnapTypes.Nearest
|
||||
| ObjectSnapTypes.Perpendicular
|
||||
| ObjectSnapTypes.WorkPlaneGrid
|
||||
| ObjectSnapTypes.Quadrants
|
||||
| ObjectSnapTypes.Tangents,
|
||||
"请选择起铺点"
|
||||
);
|
||||
var edgeObj = element.GetGeometryObjectFromReference(referEdge) as Edge;
|
||||
//var ourterEdgeArray = face.EdgeLoops.get_Item(0);
|
||||
|
||||
|
||||
if (edgeObj != null && edgeObj.AsCurve() is Line)
|
||||
{
|
||||
var line = edgeObj.AsCurve() as Line;
|
||||
var coordinateSystem = GetCoordinateSystem(doc, array, line, out var rotation);
|
||||
var startPoint = line!.GetEndPoint(0);
|
||||
var endPoint = line.GetEndPoint(1);
|
||||
var start = line.Project(xyz).XYZPoint;
|
||||
var totalLength = start.DistanceTo(startPoint) + start.DistanceTo(endPoint);
|
||||
//判断点是否在直线上
|
||||
if (totalLength - line.Length > 0.0001)
|
||||
{
|
||||
MessageBox.Show("选择点不在对齐的边上", "错误");
|
||||
return;
|
||||
}
|
||||
|
||||
radian = rotation.Radian;
|
||||
var uv = GetOffset(coordinateSystem, start);
|
||||
|
||||
if (uv != null)
|
||||
{
|
||||
//原始起铺点基于幕墙系统原点平面uv偏移量
|
||||
var intervalU = (length + gap) / 304.8;
|
||||
var intervalV = (width + gap) / 304.8;
|
||||
var n = Math.Floor(uv[0, 0] / intervalU);
|
||||
var m = Math.Floor(uv[0, 1] / intervalV);
|
||||
|
||||
if (isEdgeExistGap)
|
||||
{
|
||||
actualU = uv[0, 0] - (n * intervalU);
|
||||
actualV = uv[0, 1] - (m * intervalV);
|
||||
}
|
||||
else
|
||||
{
|
||||
actualU = uv[0, 0] - (n * intervalU) - (gap / 2 / 304.8);
|
||||
actualV = uv[0, 1] - (m * intervalV) - (gap / 2 / 304.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CurtainSystem curtainSystem = null;
|
||||
//doc.Regenerate();
|
||||
doc.Invoke(
|
||||
_ =>
|
||||
{
|
||||
var curtainSystemType = SetCurtainSystemType(doc, length, width, gap, thickness, panelName);
|
||||
curtainSystem = doc.Create.NewCurtainSystem(array, curtainSystemType);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ANGLE_1).Set(radian);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ANGLE_2).Set(radian);
|
||||
doc.Regenerate();
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ORIGIN_1).Set(actualU);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ORIGIN_2).Set(actualV);
|
||||
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_JUSTIFICATION_1).Set(2);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_JUSTIFICATION_2).Set(2);
|
||||
|
||||
ElementTransformUtils.MoveElement(doc, curtainSystem.Id, pl.FaceNormal * thickness / 304.8 / 2);
|
||||
},
|
||||
"创建幕墙系统"
|
||||
);
|
||||
if (element is Wall)
|
||||
{
|
||||
doc.Invoke(
|
||||
_ =>
|
||||
{
|
||||
element.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(baseHeight);
|
||||
var topConstraint = element.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();
|
||||
if (topConstraint == ElementId.InvalidElementId) //未连接
|
||||
{
|
||||
//无连接高度
|
||||
element.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(height);
|
||||
}
|
||||
},
|
||||
"设置墙偏移"
|
||||
);
|
||||
}
|
||||
|
||||
if (curtainSystem != null)
|
||||
{
|
||||
doc.Invoke(_ =>
|
||||
{
|
||||
var iterator = curtainSystem.CurtainGrids.ForwardIterator();
|
||||
iterator.MoveNext();
|
||||
var grid = iterator.Current as CurtainGrid;
|
||||
var panels = grid!.GetPanelIds().Select(id => doc.GetElement(id) as Panel);
|
||||
var area = width / 304.8 * length / 304.8;
|
||||
var errorPanels =
|
||||
from panel in panels
|
||||
where panel!.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED).AsDouble() < area / 4
|
||||
select panel;
|
||||
foreach (var panel in errorPanels)
|
||||
{
|
||||
var overrideGraphicSettings = doc.ActiveView.GetElementOverrides(panel.Id);
|
||||
overrideGraphicSettings.SetProjectionLineColor(new Color(255, 0, 0));
|
||||
//在当前视图下设置,其它视图保持原来的
|
||||
doc.ActiveView.SetElementOverrides(panel.Id, overrideGraphicSettings);
|
||||
doc.Regenerate();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
"创建饰面"
|
||||
);
|
||||
//CreateCurtainSystem(length, width, gap, thickness, angle, offset, doc, curveLoops, pl.FaceNormal);
|
||||
|
||||
|
||||
//var xyz = referEdge.GlobalPoint;
|
||||
|
||||
//if (angle > Math.PI / 2)
|
||||
//{
|
||||
// angle -= Math.PI;
|
||||
// if (perpendicularVector.Y>0)
|
||||
// {
|
||||
// angle -= Math.PI / 2 ;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// angle = Math.PI / 2 - angle;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
private static void CreateCurtainSystemByRoom(UIDocument uidoc, double length, double width, double gap, double thickness, string panelName)
|
||||
{
|
||||
var doc = uidoc.Document;
|
||||
|
||||
var rooms = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Rooms);
|
||||
if (!rooms.Any())
|
||||
{
|
||||
MessageBox.Show("项目中当前没有房间", "提示", MessageBoxButton.OK, MessageBoxImage.Stop);
|
||||
return;
|
||||
}
|
||||
|
||||
var refer = uidoc.Selection.PickObject(ObjectType.Element, new GenericFilter<Room>(), "请选择铺贴的房间");
|
||||
var room = doc.GetElement(refer) as Room;
|
||||
List<CurveLoop> curveLoops = [];
|
||||
var opts = new SpatialElementBoundaryOptions();
|
||||
var segmentsList = room!.GetBoundarySegments(opts);
|
||||
if (segmentsList != null)
|
||||
{
|
||||
foreach (var boundarySegments in segmentsList)
|
||||
{
|
||||
CurveLoop curveLoop = new();
|
||||
|
||||
foreach (var boundarySegment in boundarySegments)
|
||||
{
|
||||
curveLoop.Append(boundarySegment.GetCurve());
|
||||
}
|
||||
|
||||
curveLoops.Add(curveLoop);
|
||||
}
|
||||
}
|
||||
|
||||
doc.Invoke(
|
||||
_ =>
|
||||
{
|
||||
//double angle = 0;
|
||||
var array = GetFaceArray(doc, curveLoops, out var ds);
|
||||
var curtainSystemType = SetCurtainSystemType(doc, length, width, gap, thickness, panelName);
|
||||
|
||||
var curtainSystem = doc.Create.NewCurtainSystem(array, curtainSystemType);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ANGLE_1).Set(0);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ANGLE_2).Set(0);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_JUSTIFICATION_1).Set(2);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.SPACING_JUSTIFICATION_2).Set(2);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ORIGIN_1).Set(0);
|
||||
curtainSystem.get_Parameter(BuiltInParameter.CURTAINGRID_ORIGIN_2).Set(0);
|
||||
if (ds != null)
|
||||
{
|
||||
doc.Delete(ds.Id);
|
||||
}
|
||||
|
||||
ElementTransformUtils.MoveElement(doc, curtainSystem.Id, XYZ.BasisZ * thickness / 304.8 / 2);
|
||||
},
|
||||
"创建铺贴饰面"
|
||||
);
|
||||
//CreateCurtainSystem(length, width, gap, thickness, angle, offset, doc, curveLoops, XYZ.BasisZ);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void PlaceBricks()
|
||||
{
|
||||
finishesHandler.Raise(uiapp =>
|
||||
{
|
||||
var uidoc = uiapp.ActiveUIDocument;
|
||||
try
|
||||
{
|
||||
if (ByRoom)
|
||||
{
|
||||
CreateCurtainSystemByRoom(uidoc, PavementLength, PavementWidth, PavementGap, PavementThickness, PanelName);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateCurtainSystemByFace(
|
||||
uidoc,
|
||||
PavementLength,
|
||||
PavementWidth,
|
||||
PavementGap,
|
||||
PavementThickness,
|
||||
WallBaseOffset,
|
||||
PanelName,
|
||||
IsEdgeExistGap
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException) { }
|
||||
});
|
||||
}
|
||||
|
||||
private static XYZ GetOrigin(Document doc, CurtainSystem curtainSystem, out XYZ u, out XYZ v)
|
||||
{
|
||||
XYZ origin = null;
|
||||
var iterator = curtainSystem.CurtainGrids.ForwardIterator();
|
||||
iterator.MoveNext();
|
||||
var grid = iterator.Current as CurtainGrid;
|
||||
var uLineId = grid.GetUGridLineIds().FirstOrDefault();
|
||||
var vLineId = grid.GetVGridLineIds().FirstOrDefault();
|
||||
var uLine = doc.GetElement(uLineId) as CurtainGridLine;
|
||||
var vLine = doc.GetElement(vLineId) as CurtainGridLine;
|
||||
var l1 = uLine.FullCurve as Line;
|
||||
u = l1.Direction;
|
||||
var l2 = vLine.FullCurve as Line;
|
||||
v = l2.Direction;
|
||||
var result = l1.Intersect(l2, out var resultArray);
|
||||
if (result != SetComparisonResult.Disjoint)
|
||||
{
|
||||
if (!resultArray.IsEmpty)
|
||||
{
|
||||
origin = resultArray.get_Item(0).XYZPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
}
|
||||
|
||||
public class EdgeFilter : ISelectionFilter
|
||||
{
|
||||
public EdgeFilter(Element preElement)
|
||||
{
|
||||
element = preElement;
|
||||
}
|
||||
|
||||
private readonly Element element;
|
||||
|
||||
public bool AllowElement(Element elem)
|
||||
{
|
||||
return element.Id == elem.Id;
|
||||
}
|
||||
|
||||
public bool AllowReference(Reference reference, XYZ position)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
26
ShrlAlgo.RvKits/RvCivil/CivilConnectionCmd.cs
Normal file
26
ShrlAlgo.RvKits/RvCivil/CivilConnectionCmd.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Windows;
|
||||
using Autodesk.Revit.Attributes;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class CivilConnectionCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
WinDialogHelper.ShowModeless<ResolveCivilConnectView>(new ResolveCivilConnectViewModel(UiDocument));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
ex.StackTrace.ToLog();
|
||||
}
|
||||
}
|
||||
}
|
||||
26
ShrlAlgo.RvKits/RvCivil/CreateOpeningsCmd.cs
Normal file
26
ShrlAlgo.RvKits/RvCivil/CreateOpeningsCmd.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class CreateOpeningsCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
//CreateOpeningsViewModel viewModel = new();
|
||||
//CreateOpeningsView view = new(viewModel);
|
||||
//view.ShowDialog();
|
||||
SingletonChildWindowManager.ShowOrActivate<CreateOpeningsView, CreateOpeningsViewModel>();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
47
ShrlAlgo.RvKits/RvCivil/CreateOpeningsView.xaml
Normal file
47
ShrlAlgo.RvKits/RvCivil/CreateOpeningsView.xaml
Normal file
@@ -0,0 +1,47 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvCivil.CreateOpeningsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:rvCivil="clr-namespace:ShrlAlgo.RvKits.RvCivil"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="开洞设置"
|
||||
Width="200"
|
||||
Height="220"
|
||||
d:DataContext="{d:DesignInstance Type={x:Type rvCivil:CreateOpeningsViewModel}}"
|
||||
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
|
||||
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
|
||||
</Window.Resources>
|
||||
<ui:AutoGridEx
|
||||
ChildHorizontalAlignment="Stretch"
|
||||
ChildMargin="5"
|
||||
Columns="*"
|
||||
RowHeight="*"
|
||||
Rows="Auto,Auto,Auto">
|
||||
<ui:TextBoxEx
|
||||
Prefix="向外延伸距离:"
|
||||
Suffix="mm"
|
||||
Text="{Binding Distance, StringFormat={}{0:N2}}" />
|
||||
<CheckBox
|
||||
x:Name="CbAddCasing"
|
||||
Content="添加套管"
|
||||
IsChecked="{Binding AddCasing}" />
|
||||
<ComboBox
|
||||
DisplayMemberPath="Name"
|
||||
IsEnabled="{Binding IsChecked, ElementName=CbAddCasing}"
|
||||
ItemsSource="{Binding CasingFiles}"
|
||||
SelectedItem="{Binding SelectedCasing}" />
|
||||
<!-- Command="{Binding DataContext.CloseWinCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}" -->
|
||||
<Button
|
||||
HorizontalAlignment="Stretch"
|
||||
ui:AutoGridEx.RowHeightOverride="Auto"
|
||||
Command="{Binding CreateOpeningsCommand}"
|
||||
Content="开洞"
|
||||
ToolTip="选择添加套管则使用套管开洞" />
|
||||
</ui:AutoGridEx>
|
||||
</ui:FluentWindowEx>
|
||||
15
ShrlAlgo.RvKits/RvCivil/CreateOpeningsView.xaml.cs
Normal file
15
ShrlAlgo.RvKits/RvCivil/CreateOpeningsView.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
/// <summary>
|
||||
/// CreateOpeningsView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CreateOpeningsView
|
||||
{
|
||||
public CreateOpeningsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
277
ShrlAlgo.RvKits/RvCivil/CreateOpeningsViewModel.cs
Normal file
277
ShrlAlgo.RvKits/RvCivil/CreateOpeningsViewModel.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
public partial class CreateOpeningsViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty] private bool addCasing;
|
||||
|
||||
[ObservableProperty] private double distance;
|
||||
|
||||
private readonly string openingsFamilyFolder = $"{Variables.FamilyFolder}Opening";
|
||||
private readonly string casingsFamilyFolder = $"{Variables.FamilyFolder}Casing";
|
||||
private readonly ActionEventHandler handler = new();
|
||||
[ObservableProperty] private FileInfo selectedCasing;
|
||||
[ObservableProperty] private List<FileInfo> casingFiles = [];
|
||||
public CreateOpeningsViewModel()
|
||||
{
|
||||
var files = Directory.GetFiles(casingsFamilyFolder);
|
||||
foreach (var file in files)
|
||||
{
|
||||
CasingFiles.Add(new FileInfo(file));
|
||||
}
|
||||
}
|
||||
[RelayCommand]
|
||||
private void CreateOpenings()
|
||||
{
|
||||
try
|
||||
{
|
||||
handler.Raise(
|
||||
uiapp =>
|
||||
{
|
||||
var uidoc = uiapp.ActiveUIDocument;
|
||||
var doc = uidoc.Document;
|
||||
var reference = uidoc.Selection.PickObject(
|
||||
ObjectType.Element,
|
||||
new FuncFilter(e => e is Floor or ExtrusionRoof or FootPrintRoof or Ceiling or Wall or FamilyInstance),
|
||||
"请选择需要开洞的图元"
|
||||
);
|
||||
var elementToOpen = doc.GetElement(reference);
|
||||
|
||||
var intersectsElement = new ElementIntersectsElementFilter(elementToOpen);
|
||||
var mepCurves = doc.OfCollector().WherePasses(intersectsElement).Where(e => e is MEPCurve).Cast<MEPCurve>().ToList();
|
||||
|
||||
if (doc.ActiveView.ViewType != ViewType.ThreeD)
|
||||
{
|
||||
MessageBox.Show("请选择三维视图", "提示");
|
||||
}
|
||||
doc.InvokeGroup(
|
||||
_ =>
|
||||
{
|
||||
foreach (var mepCurve in mepCurves)
|
||||
{
|
||||
doc.Invoke(
|
||||
_ =>
|
||||
{
|
||||
//var level = new FilteredElementCollector(doc, doc.ActiveView.Id).OfCollector(BuiltInCategory.OST_Levels).OfClass(typeof(Level)).FirstElement();
|
||||
doc.ActiveView.SketchPlane = SketchPlane.Create(
|
||||
doc,
|
||||
elementToOpen.LevelId);
|
||||
},
|
||||
"设置工作平面");
|
||||
var curve = mepCurve.GetCurve();
|
||||
var conn = mepCurve.GetConnectors().OfType<Connector>().FirstOrDefault();
|
||||
double diameter = default;
|
||||
double width = default;
|
||||
double height = default;
|
||||
//double angle = default;
|
||||
Family openingFamily = null;
|
||||
var faceNormal = XYZ.Zero;
|
||||
faceNormal = conn.CoordinateSystem.BasisY;
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
switch (conn.Shape)
|
||||
{
|
||||
case ConnectorProfileType.Oval:
|
||||
break;
|
||||
case ConnectorProfileType.Rectangular:
|
||||
openingFamily = AddCasing
|
||||
? doc.GetOrLoadedFamily(
|
||||
$"{casingsFamilyFolder}\\矩形套管.rfa")
|
||||
: doc.GetOrLoadedFamily(
|
||||
$"{openingsFamilyFolder}\\矩形洞口.rfa");
|
||||
|
||||
width = conn.Width + (double)(Distance / 304.8);
|
||||
height = conn.Height + (double)(Distance / 304.8);
|
||||
|
||||
break;
|
||||
case ConnectorProfileType.Round:
|
||||
openingFamily = doc.GetOrLoadedFamily(
|
||||
AddCasing
|
||||
? $"{casingsFamilyFolder}\\圆形套管.rfa"
|
||||
: $"{openingsFamilyFolder}\\圆形洞口.rfa");
|
||||
|
||||
diameter = mepCurve.Diameter + (double)(Distance / 304.8);
|
||||
break;
|
||||
case ConnectorProfileType.Invalid:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//doc.ActiveView.SketchPlane = originSketch;
|
||||
if (openingFamily == null)
|
||||
{
|
||||
return Result.Failed;
|
||||
}
|
||||
var intersects = FindIntersects(elementToOpen, curve);
|
||||
|
||||
if (intersects.Count != 2)
|
||||
{
|
||||
return Result.Failed;
|
||||
}
|
||||
|
||||
var line = Line.CreateBound(intersects[0], intersects[1])
|
||||
.ExtendLine(0.5, true);
|
||||
|
||||
doc.ActiveView.ShowActiveWorkPlane();
|
||||
if (faceNormal == XYZ.Zero)
|
||||
{
|
||||
return Result.Failed;
|
||||
}
|
||||
|
||||
var plane = Plane.CreateByNormalAndOrigin(
|
||||
faceNormal,
|
||||
line.Evaluate(0.5, true));
|
||||
doc.ActiveView.SketchPlane = SketchPlane.Create(doc, plane);
|
||||
var workPlane = new FilteredElementCollector(
|
||||
doc,
|
||||
doc.ActiveView.Id)
|
||||
.OfCategory(BuiltInCategory.OST_IOSSketchGrid)
|
||||
.FirstElement();
|
||||
doc.Regenerate();
|
||||
var op = new Options
|
||||
{
|
||||
IncludeNonVisibleObjects = true,
|
||||
View = doc.ActiveView,
|
||||
//DetailLevel = ViewDetailLevel.Fine,
|
||||
ComputeReferences = true
|
||||
};
|
||||
var planeFace = workPlane
|
||||
.get_Geometry(op)
|
||||
.Where(obj => obj is Solid)
|
||||
.Cast<Solid>()
|
||||
.Select(s => s.Faces.get_Item(0))
|
||||
.FirstOrDefault();
|
||||
|
||||
var options = ts.GetFailureHandlingOptions();
|
||||
options.SetFailuresPreprocessor(new FailuresPreProcessor());
|
||||
ts.SetFailureHandlingOptions(options);
|
||||
|
||||
if (planeFace == null)
|
||||
{
|
||||
return Result.Failed;
|
||||
}
|
||||
|
||||
var symbolIds = openingFamily.GetFamilySymbolIds().FirstOrDefault();
|
||||
var symbol = doc.GetElement(symbolIds) as FamilySymbol;
|
||||
if (symbol != null && !symbol.IsActive)
|
||||
{
|
||||
symbol.Activate();
|
||||
}
|
||||
|
||||
var newFamilyInstance = doc.Create
|
||||
.NewFamilyInstance(planeFace, line, symbol);
|
||||
if (diameter != 0.0)
|
||||
{
|
||||
newFamilyInstance.GetParameters("洞口直径").FirstOrDefault()?.Set(
|
||||
diameter);
|
||||
}
|
||||
else if (width != 0.0 && height != 0.0)
|
||||
{
|
||||
newFamilyInstance.GetParameters("洞口宽度").FirstOrDefault()?.Set(width);
|
||||
newFamilyInstance.GetParameters("洞口高度").FirstOrDefault()?.Set(
|
||||
height);
|
||||
}
|
||||
|
||||
//ElementTransformUtils.RotateElement(doc, newFamilyInstance.ViewId, line, angle);
|
||||
doc.Regenerate();
|
||||
InstanceVoidCutUtils.AddInstanceVoidCut(
|
||||
doc,
|
||||
elementToOpen,
|
||||
newFamilyInstance);
|
||||
doc.Delete(doc.ActiveView.SketchPlane.Id);
|
||||
return Result.Succeeded;
|
||||
},
|
||||
"新建洞口");
|
||||
}
|
||||
},
|
||||
"开洞");
|
||||
});
|
||||
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException) { }
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Message.ToLog();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 找到宿主的面
|
||||
/// </summary>
|
||||
/// <param name="wall"></param>
|
||||
/// <returns></returns>
|
||||
private static Face FindCeilingAndFloorFace(Wall wall)
|
||||
{
|
||||
Options opt = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
|
||||
var geometryElement = wall.get_Geometry(opt);
|
||||
|
||||
Face normalFace = null;
|
||||
foreach (var geometryObject in geometryElement)
|
||||
{
|
||||
var solid = geometryObject as Solid;
|
||||
if (solid != null && solid.Faces.Size > 0)
|
||||
{
|
||||
foreach (Face face in solid.Faces)
|
||||
{
|
||||
var planarFace = face as PlanarFace;
|
||||
if (planarFace != null)
|
||||
{
|
||||
if (
|
||||
planarFace.FaceNormal.AngleTo(new XYZ(1, 1, 0)) == 0
|
||||
|| Math.Abs(planarFace.FaceNormal.AngleTo(new XYZ(1, 1, 0)) - Math.PI) < 0.0001
|
||||
)
|
||||
{
|
||||
normalFace = face;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return normalFace;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找所有管线定位线与元素面的碰撞点
|
||||
/// </summary>
|
||||
/// <param name="elementToOpen"></param>
|
||||
/// <param name="curve"></param>
|
||||
/// <returns></returns>
|
||||
private static List<XYZ> FindIntersects(Element elementToOpen, Curve curve)
|
||||
{
|
||||
var faces = elementToOpen.GetAllGeometryObjects<Face>();
|
||||
var intersects = new List<XYZ>();
|
||||
foreach (var face in faces)
|
||||
{
|
||||
//face = FindCeilingAndFloorFace(openingElement as Wall);
|
||||
var intersect = face.Intersect(curve, out var result);
|
||||
if (intersect == SetComparisonResult.Overlap)
|
||||
{
|
||||
//CurveArray curveArray = new CurveArray();
|
||||
var x = result.get_Item(0);
|
||||
var intersection = x.XYZPoint;
|
||||
intersects.Add(intersection);
|
||||
|
||||
//doc.Create.NewOpening(openingElement, curveArray, true);
|
||||
}
|
||||
}
|
||||
|
||||
return intersects;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
ShrlAlgo.RvKits/RvCivil/FloorFinishesCmd.cs
Normal file
18
ShrlAlgo.RvKits/RvCivil/FloorFinishesCmd.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class FloorFinishesCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
var floorTypes = Document.OfClass<FloorType>().Cast<FloorType>().ToList();
|
||||
WinDialogHelper.ShowModeless<FloorFinishesView>(new FloorFinishesViewModel(floorTypes));
|
||||
}
|
||||
}
|
||||
78
ShrlAlgo.RvKits/RvCivil/FloorFinishesView.xaml
Normal file
78
ShrlAlgo.RvKits/RvCivil/FloorFinishesView.xaml
Normal file
@@ -0,0 +1,78 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvCivil.FloorFinishesView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:rvCivil="clr-namespace:ShrlAlgo.RvKits.RvCivil"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="房间饰面"
|
||||
Width="200"
|
||||
Height="500"
|
||||
MinWidth="275"
|
||||
MinHeight="500"
|
||||
d:DataContext="{d:DesignInstance Type=rvCivil:FloorFinishesViewModel}"
|
||||
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
|
||||
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<ui:AutoGridEx
|
||||
ChildMargin="5"
|
||||
Columns="*"
|
||||
Rows="Auto,*,Auto,Auto">
|
||||
<GroupBox Header="范围">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton Content="所有房间" IsChecked="{Binding RbAllRooms}" />
|
||||
<RadioButton Content="选中房间" IsChecked="{Binding RbAllRooms, Converter={StaticResource InvertBooleanConverter}}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Stretch"
|
||||
Header="楼板类型">
|
||||
<ListBox
|
||||
x:Name="LbFloorType"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding FloorTypes}"
|
||||
SelectedValue="{Binding SelectedFloorType, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</GroupBox>
|
||||
<ui:TextBox
|
||||
Grid.Row="2"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
PlaceholderText="楼板偏移"
|
||||
Text="{Binding FloorOffset, StringFormat=\{0:N2\}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<!--<TextBox
|
||||
Grid.Row="2"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
md:HintAssist.Hint="楼板偏移"
|
||||
md:TextFieldAssist.SuffixText="mm">
|
||||
<TextBox.Text>
|
||||
<Binding
|
||||
Path="FloorOffset"
|
||||
StringFormat="{}{0:N2}"
|
||||
UpdateSourceTrigger="PropertyChanged">
|
||||
-->
|
||||
<!-- 可以修改值转换异常的提示“未能转换值”,前端验证 -->
|
||||
<!--
|
||||
<Binding.ValidationRules>
|
||||
<domain:RangeValidationRule Max="100" Min="0" xmlns:domain="clr-namespace:Sai.Toolkit.Mvvm.ValidationRules" ValidatesOnTargetUpdated = "True" />
|
||||
</Binding.ValidationRules>
|
||||
</Binding>
|
||||
</TextBox.Text>
|
||||
</TextBox>-->
|
||||
<ui:Button
|
||||
Grid.Row="3"
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding PlaceFloorCommand}"
|
||||
Content="布置"
|
||||
Icon="{ui:FontIcon Glyph=,
|
||||
FontFamily={StaticResource BoxIcons}}" />
|
||||
</ui:AutoGridEx>
|
||||
</ui:FluentWindowEx>
|
||||
15
ShrlAlgo.RvKits/RvCivil/FloorFinishesView.xaml.cs
Normal file
15
ShrlAlgo.RvKits/RvCivil/FloorFinishesView.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
/// <summary>
|
||||
/// FloorFinishesView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class FloorFinishesView
|
||||
{
|
||||
public FloorFinishesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
135
ShrlAlgo.RvKits/RvCivil/FloorFinishesViewModel.cs
Normal file
135
ShrlAlgo.RvKits/RvCivil/FloorFinishesViewModel.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Architecture;
|
||||
using Autodesk.Revit.UI;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
public partial class FloorFinishesViewModel : ObservableValidator
|
||||
{
|
||||
public FloorFinishesViewModel(IList<FloorType> floorTypes)
|
||||
{
|
||||
FloorTypes = floorTypes;
|
||||
|
||||
|
||||
finishesHandler = new ActionEventHandler();
|
||||
|
||||
}
|
||||
private readonly ActionEventHandler finishesHandler;
|
||||
|
||||
//private double floorOffset;
|
||||
|
||||
[Required]
|
||||
[Range(-6000, 6000, ErrorMessage = "输入偏移量值范围有误")]
|
||||
[NotifyCanExecuteChangedFor(nameof(PlaceFloorCommand))]
|
||||
[NotifyDataErrorInfo]
|
||||
[ObservableProperty]
|
||||
private double floorOffset;
|
||||
//[CustomValidation(typeof(FloorFinishesViewModel), nameof(ValidateFloorOffset))]
|
||||
//public double FloorOffset
|
||||
//{
|
||||
// get => floorOffset;
|
||||
// set
|
||||
// {
|
||||
// SetProperty(ref floorOffset, value, true);
|
||||
// PlaceFloorCommand.NotifyCanExecuteChanged();
|
||||
// }
|
||||
//}
|
||||
//自定义验证方法
|
||||
//public static ValidationResult ValidateFloorOffset(string floorOffset, ValidationContext context)
|
||||
//{
|
||||
// FloorFinishesViewModel instance = (FloorFinishesViewModel)context.ObjectInstance;
|
||||
// bool isValid = double.TryParse(floorOffset, out var _);
|
||||
// if (isValid)
|
||||
// {
|
||||
// return ValidationResult.Success;
|
||||
// }
|
||||
|
||||
// return new("输入内容不是数值。");
|
||||
//}
|
||||
|
||||
[ObservableProperty] private bool rbAllRooms;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(PlaceFloorCommand))]
|
||||
private FloorType selectedFloorType;
|
||||
|
||||
private bool CanPlace => SelectedFloorType != null && !HasErrors;
|
||||
|
||||
public IList<FloorType> FloorTypes { get; }
|
||||
|
||||
private IEnumerable<Room> selectedRooms;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanPlace))]
|
||||
private void PlaceFloor()
|
||||
{
|
||||
finishesHandler.Raise(app =>
|
||||
{
|
||||
var uidoc = app.ActiveUIDocument;
|
||||
GetRoomsToPlace(uidoc);
|
||||
CreateFloors(uidoc);
|
||||
});
|
||||
}
|
||||
public void CreateFloors(UIDocument uidoc)
|
||||
{
|
||||
var document = uidoc.Document;
|
||||
document.Invoke(_ =>
|
||||
{
|
||||
foreach (var room in selectedRooms)
|
||||
{
|
||||
if (room != null && room.UnboundedHeight != 0.0)
|
||||
{
|
||||
//UnitFormatUtils.TryParse(document.GetUnits(), UnitType.UT_Length, FloorOffset, out double value);
|
||||
|
||||
var option = new SpatialElementBoundaryOptions
|
||||
{
|
||||
SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish
|
||||
};
|
||||
var blists = room.GetBoundarySegments(option);
|
||||
CurveArray curveArray = new();
|
||||
var loops = new List<CurveLoop>();
|
||||
foreach (var bs in blists[0])
|
||||
{
|
||||
curveArray.Append(bs.GetCurve());
|
||||
|
||||
}
|
||||
foreach (var bsList in blists)
|
||||
{
|
||||
var curveList = new List<Curve>();
|
||||
foreach (var bs in bsList)
|
||||
{
|
||||
curveList.Add(bs.GetCurve());
|
||||
}
|
||||
loops.Add(CurveLoop.Create(curveList));
|
||||
}
|
||||
var level = document.GetElement(room.LevelId) as Level;
|
||||
if (curveArray.Size != 0)
|
||||
{
|
||||
#if REVIT2018 || REVIT2020
|
||||
document.Create.NewFloor(curveArray, SelectedFloorType, level, false)
|
||||
#elif REVIT2025
|
||||
Floor.Create(document, loops, SelectedFloorType.Id,level.Id,false,null,0.0)
|
||||
#endif
|
||||
.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(FloorOffset / 304.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, "房间饰面");
|
||||
}
|
||||
private void GetRoomsToPlace(UIDocument uidoc)
|
||||
{
|
||||
var doc = uidoc.Document;
|
||||
selectedRooms = RbAllRooms
|
||||
? (from elem in new FilteredElementCollector(doc, doc.ActiveView.Id).OfClass(typeof(SpatialElement))
|
||||
let room = elem as Room
|
||||
select room)
|
||||
: uidoc.SelectObjectsByRectangle<Room>("请框选以选择房间");
|
||||
}
|
||||
}
|
||||
164
ShrlAlgo.RvKits/RvCivil/ModelSplitterCmd.cs
Normal file
164
ShrlAlgo.RvKits/RvCivil/ModelSplitterCmd.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
/// <summary>
|
||||
/// 按标高拆分成多个模型
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class ModelSplitterCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
var result = MessageBox.Show("执行前请手动备份文件避免出现意外情况!", "模型拆分", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (result == MessageBoxResult.No)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#region FilterExecute
|
||||
|
||||
var levels = Document
|
||||
.OfClass<Level>()
|
||||
.Cast<Level>()
|
||||
.OrderBy(l => l.Elevation)
|
||||
.ToList();
|
||||
Dictionary<Level, Outline> levelOutlines = [];
|
||||
|
||||
//获取标高范围
|
||||
for (var i = 0; i < levels.Count; i++)
|
||||
{
|
||||
var baseLevel = levels[i];
|
||||
XYZ min = new(double.MinValue, double.MinValue, baseLevel.Elevation);
|
||||
XYZ max;
|
||||
Outline outline;
|
||||
if (i < levels.Count - 1)
|
||||
{
|
||||
var topLevel = levels[i + 1];
|
||||
max = new XYZ(double.MaxValue, double.MaxValue, topLevel.Elevation);
|
||||
outline = new Outline(min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
max = new XYZ(double.MaxValue, double.MaxValue, double.MaxValue);
|
||||
outline = new Outline(min, max);
|
||||
}
|
||||
|
||||
levelOutlines.Add(baseLevel, outline);
|
||||
}
|
||||
|
||||
StringBuilder sb = new();
|
||||
|
||||
//对比标高,得到实际分层位置
|
||||
foreach (var keyPair in levelOutlines)
|
||||
{
|
||||
//得到在标高范围内的元素
|
||||
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
|
||||
LogicalOrFilter logicalOr = new(new ElementClassFilter(typeof(HostObject)), new ElementClassFilter(typeof(FamilyInstance)));
|
||||
var insideCollector = Document.OfModelCollector()?.WherePasses(insideFilter).WherePasses(logicalOr).ToList();
|
||||
if (insideCollector == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var level = keyPair.Key;
|
||||
var elemIds = insideCollector.Where(elem => elem.get_BoundingBox(null) != null)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
foreach (var elementId in elemIds)
|
||||
{
|
||||
sb.AppendLine(elementId.ToString());
|
||||
}
|
||||
|
||||
if (elemIds.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var folder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + $"\\{Document.Title}";
|
||||
var fileName = $"{level.Name}.rvt";
|
||||
var filePath = $"{folder}\\{fileName}";
|
||||
var targetDocument = Application.NewProjectDocument(UnitSystem.Metric);
|
||||
using (Transaction trans = new(targetDocument, "创建标高"))
|
||||
{
|
||||
trans.Start();
|
||||
|
||||
try
|
||||
{
|
||||
var targetLevel = Level.Create(targetDocument, level.Elevation);
|
||||
ElementTransformUtils.CopyElements(Document, elemIds, targetDocument, null, new CopyPasteOptions());
|
||||
//targetLevel.Name = level.Name;
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message + sb;
|
||||
Result = Result.Failed;
|
||||
if (trans.GetStatus() == TransactionStatus.Started)
|
||||
{
|
||||
trans.RollBack();
|
||||
}
|
||||
|
||||
targetDocument.Close(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(folder))
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
|
||||
targetDocument.SaveAs($"{folder}\\{fileName}");
|
||||
targetDocument.Close(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorMessage = e.Message;
|
||||
Result = Result.Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
using (Transaction trans = new(Document, "按标高分割文件"))
|
||||
{
|
||||
trans.Start();
|
||||
try
|
||||
{
|
||||
Document.Delete(elemIds);
|
||||
var mp = ModelPathUtils.ConvertUserVisiblePathToModelPath(filePath);
|
||||
RevitLinkOptions options = new(true);
|
||||
var linkType = RevitLinkType.Create(Document, mp, options);
|
||||
var instance = RevitLinkInstance.Create(Document, linkType.ElementId, ImportPlacement.Origin);
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message + sb;
|
||||
Result = Result.Failed;
|
||||
if (trans.GetStatus() == TransactionStatus.Started)
|
||||
{
|
||||
trans.RollBack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion FilterExecute
|
||||
}
|
||||
}
|
||||
11
ShrlAlgo.RvKits/RvCivil/PlacementType.cs
Normal file
11
ShrlAlgo.RvKits/RvCivil/PlacementType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
public enum PlacementType
|
||||
{
|
||||
[Description("墙面")] ByFace,
|
||||
[Description("墙体")] ByWall,
|
||||
[Description("房间")] ByRoom
|
||||
}
|
||||
}
|
||||
91
ShrlAlgo.RvKits/RvCivil/ResolveCivilConnectView.xaml
Normal file
91
ShrlAlgo.RvKits/RvCivil/ResolveCivilConnectView.xaml
Normal file
@@ -0,0 +1,91 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvCivil.ResolveCivilConnectView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:rvCivil="clr-namespace:ShrlAlgo.RvKits.RvCivil"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="土建构件连接"
|
||||
Width="250"
|
||||
Height="600"
|
||||
MinHeight="600"
|
||||
d:DataContext="{d:DesignInstance Type=rvCivil:ResolveCivilConnectViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<ui:AutoGridEx
|
||||
ChildMargin="5"
|
||||
Columns="*"
|
||||
Rows="*,Auto,Auto">
|
||||
<GroupBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Header="扣减选项">
|
||||
<StackPanel>
|
||||
<CheckBox
|
||||
Content="结构柱剪切建筑墙"
|
||||
IsChecked="{Binding SColumnCutAWall}"
|
||||
ToolTip="保留原结构柱不变,建筑墙被剪切" />
|
||||
<CheckBox
|
||||
Content="结构柱剪切结构墙"
|
||||
IsChecked="{Binding SColumnCutSWall}"
|
||||
ToolTip="保留原结构柱不变,结构墙被剪切" />
|
||||
<CheckBox
|
||||
Content="结构柱剪切梁"
|
||||
IsChecked="{Binding SColumnCutFraming}"
|
||||
ToolTip="保留原结构柱不变,梁被剪切" />
|
||||
<CheckBox
|
||||
Content="结构柱剪切板"
|
||||
IsChecked="{Binding SColumnCutFloor}"
|
||||
ToolTip="保留原结构柱不变" />
|
||||
<CheckBox
|
||||
Content="梁剪切建筑墙"
|
||||
IsChecked="{Binding FramingCutAWall}"
|
||||
ToolTip="保留原结构梁,建筑墙被剪切" />
|
||||
<CheckBox
|
||||
Content="梁剪切结构墙"
|
||||
IsChecked="{Binding FramingCutSWall}"
|
||||
ToolTip="保留原结构梁,结构墙被剪切" />
|
||||
<CheckBox
|
||||
Content="梁剪切板"
|
||||
IsChecked="{Binding FramingCutFloor}"
|
||||
ToolTip="保留原梁,板被剪切" />
|
||||
<CheckBox
|
||||
Content="板剪切建筑墙"
|
||||
IsChecked="{Binding FloorCutAWall}"
|
||||
ToolTip="保留原板,建筑墙被剪切" />
|
||||
<CheckBox
|
||||
Content="主梁剪切次梁"
|
||||
IsChecked="{Binding MFramingCutSFraming}"
|
||||
ToolTip="保留主梁,次梁被剪切" />
|
||||
<CheckBox
|
||||
Content="板剪切结构墙"
|
||||
IsChecked="{Binding FloorCutSWall}"
|
||||
ToolTip="保留原板,结构墙被剪切" />
|
||||
<CheckBox
|
||||
Content="结构墙剪切建筑墙"
|
||||
IsChecked="{Binding SWallCutAWall}"
|
||||
ToolTip="保留原板,建筑墙被剪切" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="1" Header="修改范围">
|
||||
<UniformGrid Rows="1">
|
||||
<RadioButton Content="框选范围" IsChecked="True" />
|
||||
<RadioButton Content="整个模型" IsChecked="{Binding IsWholeModel}" />
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding ModifyModelCommand}"
|
||||
Content="修改"
|
||||
ToolTip="相交的图元才会被修改" />
|
||||
</ui:AutoGridEx>
|
||||
</ui:FluentWindowEx>
|
||||
17
ShrlAlgo.RvKits/RvCivil/ResolveCivilConnectView.xaml.cs
Normal file
17
ShrlAlgo.RvKits/RvCivil/ResolveCivilConnectView.xaml.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Windows;
|
||||
|
||||
using WPFluent.Controls;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
/// <summary>
|
||||
/// ResolveCivilConnectView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ResolveCivilConnectView : FluentWindowEx
|
||||
{
|
||||
public ResolveCivilConnectView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
481
ShrlAlgo.RvKits/RvCivil/ResolveCivilConnectViewModel.cs
Normal file
481
ShrlAlgo.RvKits/RvCivil/ResolveCivilConnectViewModel.cs
Normal file
@@ -0,0 +1,481 @@
|
||||
using System.Windows;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
|
||||
|
||||
using ShrlAlgo.RvKits.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
public partial class ResolveCivilConnectViewModel : ObservableObject
|
||||
{
|
||||
private readonly ActionEventHandler modifyHandler = new();
|
||||
|
||||
public ResolveCivilConnectViewModel(UIDocument uidoc)
|
||||
{
|
||||
doc = uidoc.Document;
|
||||
this.uidoc = uidoc;
|
||||
}
|
||||
|
||||
private readonly Document doc;
|
||||
private readonly UIDocument uidoc;
|
||||
|
||||
/// <summary>
|
||||
/// 楼板-建筑墙
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? floorCutAWall = false;
|
||||
/// <summary>
|
||||
/// 板-结构墙
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? floorCutSWall = false;
|
||||
/// <summary>
|
||||
/// 梁-建筑墙
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? framingCutAWall = false;
|
||||
|
||||
/// <summary>
|
||||
/// 梁-板
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? framingCutFloor = false;
|
||||
|
||||
/// <summary>
|
||||
/// 梁-结构墙
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? framingCutSWall = false;
|
||||
|
||||
/// <summary>
|
||||
/// 主梁-次梁
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? mFramingCutSFraming = false;
|
||||
|
||||
/// <summary>
|
||||
/// 结构柱子-建筑墙
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? sColumnCutAWall = false;
|
||||
/// <summary>
|
||||
/// 结构柱-板
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? sColumnCutFloor = false;
|
||||
/// <summary>
|
||||
/// 结构柱-梁
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? sColumnCutFraming = false;
|
||||
/// <summary>
|
||||
/// 结构柱-结构墙
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? sColumnCutSWall = false;
|
||||
/// <summary>
|
||||
/// 结构墙-建筑墙
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool? sWallCutAWall = false;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool? isWholeModel = false;
|
||||
|
||||
public static Options SetOptions()
|
||||
{
|
||||
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
|
||||
return option;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="elementsToSkip"></param>
|
||||
/// <param name="view3D"></param>
|
||||
/// <param name="tsName"></param>
|
||||
/// <param name="collectorReserve">保留的集合</param>
|
||||
/// <param name="collectorToCut">剪切的集合</param>
|
||||
private void ConnectCivilComponents(
|
||||
List<MessageModel> elementsToSkip,
|
||||
View3D view3D,
|
||||
string tsName,
|
||||
FilteredElementCollector collectorReserve,
|
||||
FilteredElementCollector collectorToCut
|
||||
)
|
||||
{
|
||||
if (collectorReserve == null || collectorToCut == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ids = collectorToCut.WhereElementIsNotElementType().ToElementIds();
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
var options = ts.GetFailureHandlingOptions();
|
||||
FailuresPreProcessor failuresProcessor = new();
|
||||
options.SetFailuresPreprocessor(failuresProcessor);
|
||||
ts.SetFailureHandlingOptions(options);
|
||||
var reserveElements = collectorReserve.WhereElementIsNotElementType().ToList();
|
||||
|
||||
foreach (var element in reserveElements)
|
||||
{
|
||||
try
|
||||
{
|
||||
//var filter = new ElementIntersectsElementFilter(wall, false);
|
||||
//var instances = collector.WherePasses(filter);
|
||||
//instance.get_BoundingBox(view3D)
|
||||
//BoundingBoxIntersectsFilter filter=new BoundingBoxIntersectsFilter(new Outline())
|
||||
|
||||
var box = element.get_BoundingBox(view3D);
|
||||
Outline outline = new(box.Min, box.Max);
|
||||
BoundingBoxIntersectsFilter intersectsFilter = new(outline);
|
||||
BoundingBoxIsInsideFilter boxIsInsideFilter = new(outline);
|
||||
var filter = new LogicalOrFilter(intersectsFilter, boxIsInsideFilter);
|
||||
//ElementIntersectsElementFilter filter = new ElementIntersectsElementFilter(structuralColumn, false);
|
||||
//执行一次后会修改集合,需修改
|
||||
|
||||
var newCollector = new FilteredElementCollector(doc, ids);
|
||||
|
||||
var intersectElements = newCollector.WherePasses(filter).ToList();
|
||||
|
||||
foreach (var intersectElem in intersectElements)
|
||||
{
|
||||
if (!JoinGeometryUtils.AreElementsJoined(doc, intersectElem, element))
|
||||
{
|
||||
JoinGeometryUtils.JoinGeometry(doc, element, intersectElem);
|
||||
}
|
||||
|
||||
if (!JoinGeometryUtils.IsCuttingElementInJoin(doc, element, intersectElem))
|
||||
{
|
||||
JoinGeometryUtils.SwitchJoinOrder(doc, element, intersectElem);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//避免重复添加
|
||||
if (!elementsToSkip.Exists(ele => ele.Element.Id == element.Id))
|
||||
{
|
||||
elementsToSkip.Add(new MessageModel(element, ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
tsName
|
||||
);
|
||||
}
|
||||
|
||||
private static List<Face> GetElementGeoList(Element elem)
|
||||
{
|
||||
List<Face> getElementGeoList = new();
|
||||
var geometry = elem.get_Geometry(SetOptions());
|
||||
|
||||
foreach (var geomObj in geometry)
|
||||
{
|
||||
if (geomObj is GeometryInstance geomInstance)
|
||||
{
|
||||
var usesSymbolGeometry = elem is FamilyInstance instance && !instance.HasModifiedGeometry();
|
||||
var instanceGeometry = usesSymbolGeometry ? geomInstance.GetSymbolGeometry() : geomInstance.GetInstanceGeometry();
|
||||
|
||||
foreach (var instObj in instanceGeometry)
|
||||
{
|
||||
getElementGeoList.AddRange(GetFaces(instObj));
|
||||
}
|
||||
}
|
||||
|
||||
getElementGeoList.AddRange(GetFaces(geomObj));
|
||||
}
|
||||
|
||||
return getElementGeoList;
|
||||
}
|
||||
|
||||
private static List<Face> GetFaces(GeometryObject geoObject)
|
||||
{
|
||||
List<Face> geometryObjects = new();
|
||||
if (geoObject is Solid instSolid)
|
||||
{
|
||||
if (instSolid.Faces.Size > 0)
|
||||
{
|
||||
geometryObjects.AddRange(instSolid.Faces.Cast<Face>());
|
||||
}
|
||||
//else if (typeof(Face) == typeof(Edge) && instSolid.Edges.Size > 0)
|
||||
//{
|
||||
// geometryObjects.AddRange(instSolid.Edges.Cast<Face>());
|
||||
//}
|
||||
}
|
||||
|
||||
return geometryObjects;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ModifyModel()
|
||||
{
|
||||
//if (obj is Windows view)
|
||||
//{
|
||||
// view.DialogResult = true;
|
||||
//}
|
||||
var result = MessageBox.Show("连接处理", "如果模型构件数量过多,存在崩溃风险。\n\r是否现在保存并继续?", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
doc.Save(new SaveOptions());
|
||||
}
|
||||
|
||||
if (result == MessageBoxResult.No)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
modifyHandler.Raise(_ =>
|
||||
{
|
||||
List<MessageModel> elementsToSkip = new();
|
||||
//墙和柱空间位置,连接时,墙在柱间要打断处理,不能“一条线延伸”建筑结构均如此。墙的顶部到梁底或者板底,等等其他具有构件之间空间连接视具体情况而定。要保证既不影响模型完整准确性,又不会对后期量的统计造成误差。建筑和结构要协调连接处的处理方式,做到统一。
|
||||
var view3D = doc.OfClass<View3D>().Cast<View3D>().FirstOrDefault(v => !v.IsTemplate);
|
||||
//构造收集器
|
||||
var floors = new FilteredElementCollector(doc).OfClass(typeof(Floor));
|
||||
|
||||
var columnCollector = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_Columns);
|
||||
var structColumns = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(FamilyInstance))
|
||||
.OfCategory(BuiltInCategory.OST_StructuralColumns);
|
||||
var beamsCollector = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_StructuralFraming);
|
||||
|
||||
var elemIds = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(Wall))
|
||||
.Where(wall => wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 0)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
var archiWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
|
||||
elemIds = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(Wall))
|
||||
.Where(wall => wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 1)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
|
||||
var structWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
//ElementCategoryFilter structuralColumns = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns);
|
||||
//ElementCategoryFilter columns = new ElementCategoryFilter(BuiltInCategory.OST_Columns);
|
||||
//ElementCategoryFilter beams = new ElementCategoryFilter(BuiltInCategory.OST_StructuralFraming);
|
||||
//List<ElementFilter> filters = new List<ElementFilter>
|
||||
//{
|
||||
// structuralColumns,
|
||||
// columns,
|
||||
// beams
|
||||
//};
|
||||
//LogicalOrFilter orFilter = new LogicalOrFilter(filters);
|
||||
try
|
||||
{
|
||||
if (IsWholeModel != true)
|
||||
{
|
||||
var elements = uidoc.Selection.PickElementsByRectangle(new FuncFilter(e => e is Wall or Floor or FamilyInstance));
|
||||
elemIds = elements.Where(elem => elem is Floor).Select(f => f.Id).ToList();
|
||||
floors = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
|
||||
elemIds = elements
|
||||
.Where(elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_StructuralColumns).Id)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
structColumns = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
|
||||
elemIds = elements
|
||||
.Where(elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_Columns).Id)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
columnCollector = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
|
||||
elemIds = elements
|
||||
.Where(elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_StructuralFraming).Id)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
beamsCollector = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
|
||||
elemIds = elements
|
||||
.Where(
|
||||
elem =>
|
||||
elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_Walls).Id
|
||||
&& elem.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 0
|
||||
)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
archiWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
|
||||
elemIds = elements
|
||||
.Where(
|
||||
elem =>
|
||||
elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_Walls).Id
|
||||
&& elem.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 1
|
||||
)
|
||||
.Select(elem => elem.Id)
|
||||
.ToList();
|
||||
structWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException) { }
|
||||
|
||||
using (TransactionGroup tg = new(doc, "模型连接处理"))
|
||||
{
|
||||
tg.Start();
|
||||
|
||||
if (SColumnCutSWall == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切结构墙", structColumns, structWalls);
|
||||
}
|
||||
|
||||
if (FloorCutAWall == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "板剪切建筑墙", floors, archiWalls);
|
||||
}
|
||||
|
||||
if (FramingCutFloor == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "梁剪切板", beamsCollector, floors);
|
||||
}
|
||||
|
||||
if (FramingCutSWall == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "梁剪切结构墙", beamsCollector, structWalls);
|
||||
}
|
||||
|
||||
if (SWallCutAWall == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "结构墙剪切建筑墙", structWalls, archiWalls);
|
||||
}
|
||||
|
||||
if (SColumnCutFloor == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切板", structColumns, floors);
|
||||
}
|
||||
|
||||
if (SColumnCutFraming == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切梁", structColumns, beamsCollector);
|
||||
}
|
||||
|
||||
if (SColumnCutAWall == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切建筑墙", structColumns, archiWalls);
|
||||
}
|
||||
|
||||
if (FramingCutAWall == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "梁剪切建筑墙", beamsCollector, archiWalls);
|
||||
}
|
||||
|
||||
if (FloorCutSWall == true)
|
||||
{
|
||||
ConnectCivilComponents(elementsToSkip, view3D, "板剪切结构墙", floors, structWalls);
|
||||
}
|
||||
|
||||
if (MFramingCutSFraming == true)
|
||||
{
|
||||
//ConnectCivilComponents(elementsToSkip, view3D, "主梁连接次梁", beamsCollector, beamsCollector);
|
||||
using Transaction trans = new(doc, "主梁连接次梁");
|
||||
trans.Start();
|
||||
var options = trans.GetFailureHandlingOptions();
|
||||
FailuresPreProcessor failuresProcessor = new();
|
||||
options.SetFailuresPreprocessor(failuresProcessor);
|
||||
trans.SetFailureHandlingOptions(options);
|
||||
|
||||
var beams = beamsCollector.WhereElementIsNotElementType().ToList();
|
||||
var ids = beamsCollector.WhereElementIsNotElementType().ToElementIds();
|
||||
foreach (var beam in beams)
|
||||
{
|
||||
try
|
||||
{
|
||||
//ElementIntersectsElementFilter filter = new ElementIntersectsElementFilter(structuralColumn, false);
|
||||
|
||||
var box = beam.get_BoundingBox(view3D);
|
||||
Outline outline = new(box.Min, box.Max);
|
||||
BoundingBoxIntersectsFilter intersectsFilter = new(outline);
|
||||
BoundingBoxIsInsideFilter boxIsInsideFilter = new(outline);
|
||||
var filter = new LogicalOrFilter(intersectsFilter, boxIsInsideFilter);
|
||||
//执行一次后会修改集合,需修改
|
||||
var newCollector = new FilteredElementCollector(doc, ids);
|
||||
|
||||
var intersectBeams = newCollector.WherePasses(filter);
|
||||
var firstBeam = beam as FamilyInstance;
|
||||
foreach (var intersectBeam in intersectBeams)
|
||||
{
|
||||
if (intersectBeam.Id == firstBeam.Id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var secondBeam = intersectBeam as FamilyInstance;
|
||||
var face1 = GetElementGeoList(firstBeam)
|
||||
.Find(face => face.ComputeNormal(new UV()).IsAlmostEqualTo(firstBeam.HandOrientation));
|
||||
var face2 = GetElementGeoList(intersectBeam)
|
||||
.Find(face => face.ComputeNormal(new UV()).IsAlmostEqualTo(secondBeam.HandOrientation));
|
||||
FamilyInstance mainBeam;
|
||||
FamilyInstance subBeam;
|
||||
if (face1 == null || face2 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (face1.Area > face2.Area)
|
||||
{
|
||||
mainBeam = firstBeam;
|
||||
subBeam = secondBeam;
|
||||
}
|
||||
else
|
||||
{
|
||||
mainBeam = secondBeam;
|
||||
subBeam = firstBeam;
|
||||
}
|
||||
|
||||
if (!JoinGeometryUtils.AreElementsJoined(doc, mainBeam, subBeam))
|
||||
{
|
||||
JoinGeometryUtils.JoinGeometry(doc, mainBeam, subBeam);
|
||||
}
|
||||
|
||||
if (!JoinGeometryUtils.IsCuttingElementInJoin(doc, mainBeam, subBeam))
|
||||
{
|
||||
JoinGeometryUtils.SwitchJoinOrder(doc, mainBeam, subBeam);
|
||||
}
|
||||
|
||||
//if (JoinGeometryUtils.AreElementsJoined(doc, mainBeam, subBeam))
|
||||
//{
|
||||
// //楼板被剪切了,第一个元素保持不变
|
||||
// if (!JoinGeometryUtils.IsCuttingElementInJoin(doc, mainBeam, subBeam))
|
||||
// {
|
||||
// JoinGeometryUtils.SwitchJoinOrder(doc, mainBeam, subBeam);
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// // 第一个元素保持不变
|
||||
// JoinGeometryUtils.SwitchJoinOrder(doc, beam, intersectBeam);
|
||||
//}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
elementsToSkip.Add(new MessageModel(beam, ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
|
||||
tg.Assimilate();
|
||||
}
|
||||
|
||||
if (elementsToSkip.Any())
|
||||
{
|
||||
WinDialogHelper.ShowModeless<MessageWin>(new MessageViewModel(uidoc, elementsToSkip, "未解决构件"));
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("处理完成", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
33
ShrlAlgo.RvKits/RvCivil/Rotation.cs
Normal file
33
ShrlAlgo.RvKits/RvCivil/Rotation.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
internal class Rotation
|
||||
{
|
||||
/// <summary>
|
||||
/// 旋转角度
|
||||
/// </summary>
|
||||
public double Radian { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对齐的轴
|
||||
/// </summary>
|
||||
public Orientation Orientation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对齐边与轴角度最小的对齐边的方向
|
||||
/// </summary>
|
||||
public XYZ Direction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对齐UV轴的方向
|
||||
/// </summary>
|
||||
public XYZ CoordSystemAxis { get; set; }
|
||||
}
|
||||
|
||||
public enum Orientation
|
||||
{
|
||||
U,
|
||||
V
|
||||
}
|
||||
}
|
||||
205
ShrlAlgo.RvKits/RvCivil/SlopedFloorCmd.cs
Normal file
205
ShrlAlgo.RvKits/RvCivil/SlopedFloorCmd.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class SlopedFloorCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
Document.Invoke(
|
||||
_ =>
|
||||
{
|
||||
Line line1 = null;
|
||||
Line line2 = null;
|
||||
HostObject obj1 = null;
|
||||
HostObject obj2 = null;
|
||||
var refer = UiDocument.Selection.PickObject(
|
||||
ObjectType.Edge,
|
||||
new FuncFilter(
|
||||
elem => elem is HostObject,
|
||||
(r, p) =>
|
||||
{
|
||||
obj1 = Document.GetElement(r) as HostObject;
|
||||
var edge = obj1?.GetGeometryObjectFromReference(r) as Edge;
|
||||
if (edge?.AsCurve() is Line l && l.Direction.Z < 0.0001)
|
||||
{
|
||||
line1 = l;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
),
|
||||
"请选择主体元素其中的一条水平边"
|
||||
);
|
||||
var elem = Document.GetElement(refer);
|
||||
UiDocument.Selection.PickObject(
|
||||
ObjectType.Edge,
|
||||
new FuncFilter(
|
||||
elem => elem is HostObject && elem.Id != obj1.Id,
|
||||
(r, _) =>
|
||||
{
|
||||
obj2 = Document.GetElement(r) as HostObject;
|
||||
|
||||
var edge1 = obj2?.GetGeometryObjectFromReference(r) as Edge;
|
||||
if (
|
||||
edge1?.AsCurve() is Line l
|
||||
&& l.Direction.Z < 0.0001
|
||||
&& l.Direction.CrossProduct(line1.Direction).IsAlmostEqualTo(XYZ.Zero)
|
||||
&& l.Distance(line1.Origin) > Application.ShortCurveTolerance / 304.8
|
||||
)
|
||||
{
|
||||
line2 = l;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
),
|
||||
"请选择与另一条平行的水平边"
|
||||
);
|
||||
var level1 = Document.GetElement(obj1.LevelId) as Level;
|
||||
var level2 = Document.GetElement(obj2.LevelId) as Level;
|
||||
var baseLevel = level1?.Elevation > level2?.Elevation ? level2 : level1;
|
||||
//基准边,低的边
|
||||
var lineBase = line1.Origin.Z < line2.Origin.Z ? line1 : line2;
|
||||
var lineAnother = line1.Origin.Z < line2.Origin.Z ? line2 : line1;
|
||||
//if (line1.Origin.Z < line2.Origin.Z)
|
||||
//{
|
||||
// lineBase = line1;
|
||||
// lineAnother = line2;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// lineBase = line2;
|
||||
// lineAnother = line1;
|
||||
//}
|
||||
|
||||
var curveArr = new CurveArray();
|
||||
var planeToProject = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, lineBase.Origin);
|
||||
var p1 = planeToProject.ProjectOf(lineBase.GetEndPoint(0));
|
||||
var p2 = planeToProject.ProjectOf(lineBase.GetEndPoint(1));
|
||||
var p3 = planeToProject.ProjectOf(lineAnother.GetEndPoint(0));
|
||||
var p4 = planeToProject.ProjectOf(lineAnother.GetEndPoint(1));
|
||||
Line l1;
|
||||
Line l2;
|
||||
Line l3;
|
||||
Line l4;
|
||||
|
||||
if (lineBase.Direction.IsAlmostEqualTo(lineAnother.Direction))
|
||||
{
|
||||
l1 = Line.CreateBound(p1, p2);
|
||||
l3 = Line.CreateBound(p4, p3);
|
||||
l4 = Line.CreateBound(p3, p1);
|
||||
l2 = Line.CreateBound(p2, p4);
|
||||
}
|
||||
else
|
||||
{
|
||||
l1 = Line.CreateBound(p1, p2);
|
||||
l3 = Line.CreateBound(p3, p4);
|
||||
l4 = Line.CreateBound(p4, p1);
|
||||
l2 = Line.CreateBound(p2, p3);
|
||||
}
|
||||
|
||||
curveArr.Append(l1);
|
||||
curveArr.Append(l2);
|
||||
curveArr.Append(l3);
|
||||
curveArr.Append(l4);
|
||||
|
||||
//var isStructure = obj1.get_Parameter(BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL).AsInteger();
|
||||
//选择线的中点连线
|
||||
var centerLine = Line.CreateBound(lineBase.Evaluate(0.5, true), lineAnother.Evaluate(0.5, true));
|
||||
//中线和边线叉乘,求出楼板面的法向量
|
||||
var floorNormal = lineBase.Direction.CrossProduct(centerLine.Direction);
|
||||
if (floorNormal.Z < 0)
|
||||
{
|
||||
floorNormal = floorNormal.Negate();
|
||||
}
|
||||
|
||||
//坡度角
|
||||
var radian = floorNormal.AngleTo(XYZ.BasisZ);
|
||||
|
||||
//另一条楼板边垂直xy的平面
|
||||
var normal = lineAnother.Direction.CrossProduct(XYZ.BasisZ);
|
||||
var plane = Plane.CreateByNormalAndOrigin(normal, lineAnother.Evaluate(0.5, true));
|
||||
//点与平面的距离
|
||||
var centerPoint = lineBase.Evaluate(0.5, true);
|
||||
var perpPoint = plane.ProjectOf(centerPoint);
|
||||
var slopedArrow = Line.CreateBound(centerPoint, new XYZ(perpPoint.X, perpPoint.Y, centerPoint.Z));
|
||||
//if (lineBase.Origin.Z > lineAnother.Origin.Z)
|
||||
//{
|
||||
// slopedArrow = slopedArrow.CreateReversed() as Line;
|
||||
//}
|
||||
//即板上表面法向量和Z轴正向之间
|
||||
//double radian = slopedArrow.Direction.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ);
|
||||
//double slope = Math.Abs(line1.Evaluate(0.5, true).Z - line2.Evaluate(0.5, true).Z);
|
||||
|
||||
//slopedArrow用以指定在XY平面上绘制的板轮廓,是沿着哪个方向进行坡度变化的。因此,这条线实际上是XY平面上,垂直于板上表面与XY平面交线的一条线。
|
||||
#if REVIT2018 || REVIT2020
|
||||
Document.Create.NewSlab(curveArr, baseLevel, slopedArrow, Math.Tan(radian), true);
|
||||
#elif REVIT2025
|
||||
var floorType = Floor.GetDefaultFloorType(Document, false);
|
||||
if (elem is Floor floor)
|
||||
{
|
||||
floorType = floor.GetTypeId();
|
||||
}
|
||||
var loops = new List<CurveLoop>() { CurveLoop.Create(new List<Curve>() { l1, l2, l3, l4 }) };
|
||||
Floor.Create(Document, loops, floorType, baseLevel.Id, true, slopedArrow, Math.Tan(radian));
|
||||
#endif
|
||||
},
|
||||
"坡度楼板"
|
||||
);
|
||||
}
|
||||
|
||||
private static bool IfSameHeight(List<double> vs)
|
||||
{
|
||||
//判断楼板中各端点标高是否相等
|
||||
List<double> list = new();
|
||||
foreach (var z in vs)
|
||||
{
|
||||
if (list.Contains(z) == false)
|
||||
{
|
||||
list.Add(z);
|
||||
}
|
||||
}
|
||||
|
||||
return list.Count == 1;
|
||||
}
|
||||
|
||||
//编辑子图元
|
||||
private void EditSubElements(Floor floor)
|
||||
{
|
||||
#if REVIT2018 || REVIT2020
|
||||
var slabShapeEditor = floor.SlabShapeEditor;
|
||||
#elif REVIT2025
|
||||
var slabShapeEditor = floor.GetSlabShapeEditor();
|
||||
#endif
|
||||
if (slabShapeEditor.IsEnabled)
|
||||
{
|
||||
var vertices = slabShapeEditor.SlabShapeVertices;
|
||||
var zList = new List<double>();
|
||||
foreach (SlabShapeVertex slabShapeVertex in vertices)
|
||||
{
|
||||
zList.Add(slabShapeVertex.Position.Z);
|
||||
}
|
||||
|
||||
//判断为水平板后重设形状
|
||||
if (IfSameHeight(zList))
|
||||
{
|
||||
var floorLevel = floor.Document.GetElement(floor.LevelId) as Level; //获取楼板所在标高
|
||||
var levelHeight = floorLevel.LookupParameter("立面").AsDouble(); //获取所在标高的标高
|
||||
var offsetHeight = zList.FirstOrDefault() - levelHeight;
|
||||
floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(offsetHeight);
|
||||
slabShapeEditor.ResetSlabShape();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
303
ShrlAlgo.RvKits/RvCivil/SplitComsByLevelCmd.cs
Normal file
303
ShrlAlgo.RvKits/RvCivil/SplitComsByLevelCmd.cs
Normal file
@@ -0,0 +1,303 @@
|
||||
using System.Windows;
|
||||
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.IFC;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
using ShrlAlgo.RvKits.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
|
||||
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
|
||||
public class SplitComsByLevelCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
var instances = Document.OfCollector().OfClass(typeof(FamilyInstance)).Cast<FamilyInstance>().ToList();
|
||||
var errors = new List<MessageModel>();
|
||||
using (TransactionGroup tg = new(Document, "按标高拆分墙、柱"))
|
||||
{
|
||||
tg.Start();
|
||||
//墙打断
|
||||
using (Transaction trans = new(Document, "楼层分割打断构件"))
|
||||
{
|
||||
trans.Start();
|
||||
|
||||
var walls = Document.OfCollector().OfClass(typeof(Wall)).Cast<Wall>().ToList();
|
||||
var structuralColumns = Document.OfCollector()
|
||||
.OfClass(typeof(FamilyInstance))
|
||||
.OfCategory(BuiltInCategory.OST_StructuralColumns)
|
||||
.Cast<FamilyInstance>()
|
||||
.ToList();
|
||||
var columns = Document.OfCollector()
|
||||
.OfClass(typeof(FamilyInstance))
|
||||
.OfCategory(BuiltInCategory.OST_Columns)
|
||||
.Cast<FamilyInstance>()
|
||||
.ToList();
|
||||
var elemToSplitIds = new List<ElementId>();
|
||||
foreach (var wall in walls)
|
||||
{
|
||||
//得到墙的包围框
|
||||
var canModify = true;
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
if (instance.Host != null && instance.Host.Id == wall.Id)
|
||||
{
|
||||
errors.Add(new MessageModel(wall, "有族基于当前墙无法拆分"));
|
||||
canModify = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ExporterIFCUtils.HasElevationProfile(wall))
|
||||
{
|
||||
canModify = false;
|
||||
errors.Add(new MessageModel(wall, "轮廓被修改无法拆分"));
|
||||
}
|
||||
|
||||
var needToDelete = false;
|
||||
if (canModify)
|
||||
{
|
||||
needToDelete = SplitWallByLevel(Document, wall, ActiveView);
|
||||
}
|
||||
|
||||
if (needToDelete)
|
||||
{
|
||||
elemToSplitIds.Add(wall.Id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var column in structuralColumns)
|
||||
{
|
||||
var canModify = true;
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
if (instance.Host != null && instance.Host.Id == column.Id)
|
||||
{
|
||||
errors.Add(new MessageModel(column, "有族基于当前结构柱,无法拆分"));
|
||||
canModify = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var needToDelete = false;
|
||||
if (canModify)
|
||||
{
|
||||
needToDelete = SplitColumnByLevel(Document, column, ActiveView);
|
||||
}
|
||||
|
||||
if (needToDelete)
|
||||
{
|
||||
elemToSplitIds.Add(column.Id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
var canModify = true;
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
if (instance.Host != null && instance.Host.Id == column.Id)
|
||||
{
|
||||
errors.Add(new MessageModel(column, "有族基于当前柱,无法拆分"));
|
||||
canModify = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var needToDelete = false;
|
||||
if (canModify)
|
||||
{
|
||||
needToDelete = SplitColumnByLevel(Document, column, ActiveView);
|
||||
}
|
||||
|
||||
if (needToDelete)
|
||||
{
|
||||
elemToSplitIds.Add(column.Id);
|
||||
}
|
||||
}
|
||||
|
||||
Document.Delete(elemToSplitIds);
|
||||
trans.Commit();
|
||||
}
|
||||
|
||||
tg.Assimilate();
|
||||
}
|
||||
|
||||
if (errors.Any())
|
||||
{
|
||||
WinDialogHelper.ShowModeless<MessageWin>(new MessageViewModel(UiDocument, errors, "未解决错误"));
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("处理完成", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool SplitColumnByLevel(Document document, FamilyInstance column, View view)
|
||||
{
|
||||
var wallBox = column.get_BoundingBox(view);
|
||||
var minZ = wallBox.Min.Z;
|
||||
var maxZ = wallBox.Max.Z;
|
||||
var allLevels = document
|
||||
.OfClass<Level>()
|
||||
.OfCategory(BuiltInCategory.OST_Levels)
|
||||
.Cast<Level>()
|
||||
.OrderBy(o => o.Elevation)
|
||||
.ToList();
|
||||
var toSplit = document
|
||||
.OfClass<Level>()
|
||||
.OfCategory(BuiltInCategory.OST_Levels)
|
||||
.Cast<Level>()
|
||||
.Where(l => l.Elevation - minZ > 0.0001 && maxZ - l.Elevation > 0.0001)
|
||||
.OrderBy(o => o.Elevation)
|
||||
.ToList();
|
||||
|
||||
if (toSplit.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var n = allLevels.FindIndex(l => l.Id == toSplit[0].Id);
|
||||
var minLevel = allLevels[0];
|
||||
if (n > 0)
|
||||
{
|
||||
minLevel = allLevels[n - 1]; //存在更低的标高时,取此标高作为底标高约束
|
||||
}
|
||||
|
||||
var translation = XYZ.BasisZ;
|
||||
|
||||
var bottomEleIds = ElementTransformUtils.CopyElement(document, column.Id, translation);
|
||||
var minWall = document.GetElement(bottomEleIds.FirstOrDefault()) as FamilyInstance;
|
||||
//底部约束
|
||||
minWall.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).Set(minLevel.Id);
|
||||
minWall.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(minZ - minLevel.Elevation);
|
||||
minWall.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).Set(toSplit[0].Id);
|
||||
minWall.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).Set(0);
|
||||
|
||||
var maxLevel = toSplit.Last();
|
||||
var m = allLevels.FindIndex(l => l.Id == toSplit.Last().Id);
|
||||
if (m < allLevels.Count - 1)
|
||||
{
|
||||
maxLevel = allLevels[m + 1]; //存在更高的标高
|
||||
}
|
||||
|
||||
var topEleIds = ElementTransformUtils.CopyElement(document, column.Id, translation);
|
||||
var maxWall = document.GetElement(topEleIds.FirstOrDefault()) as FamilyInstance;
|
||||
|
||||
maxWall.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).Set(toSplit.Last().Id);
|
||||
maxWall.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(0);
|
||||
maxWall.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).Set(maxLevel.Id);
|
||||
maxWall.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).Set(maxZ - maxLevel.Elevation);
|
||||
|
||||
for (var i = 0; i < toSplit.Count - 1; i++)
|
||||
{
|
||||
var baseLevel = toSplit[i];
|
||||
var topLevel = toSplit[i + 1];
|
||||
var eleIds = ElementTransformUtils.CopyElement(document, column.Id, translation);
|
||||
var wallCopy = document.GetElement(eleIds.FirstOrDefault()) as FamilyInstance;
|
||||
wallCopy.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).Set(baseLevel.Id);
|
||||
wallCopy.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(0);
|
||||
|
||||
wallCopy.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).Set(topLevel.Id);
|
||||
wallCopy.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).Set(0);
|
||||
//if (i == levelsToSplit.Count - 2 && maxZ < maxLevel.Bottom)
|
||||
//{
|
||||
// wallCopy.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(maxZ - maxLevel.Bottom);
|
||||
//}
|
||||
//Wall.Create(document, curve, wall.WallType.ViewId, levels[i].ViewId, 100, 100, false, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 切分墙体
|
||||
/// </summary>
|
||||
/// <param name="doc"></param>
|
||||
/// <param name="wall"></param>
|
||||
/// <param name="view">三维视图</param>
|
||||
/// <returns></returns>
|
||||
private static bool SplitWallByLevel(Document doc, Wall wall, View view)
|
||||
{
|
||||
var wallBox = wall.get_BoundingBox(view);
|
||||
var minZ = wallBox.Min.Z;
|
||||
var maxZ = wallBox.Max.Z;
|
||||
var allLevels = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(Level))
|
||||
.OfCategory(BuiltInCategory.OST_Levels)
|
||||
.Cast<Level>()
|
||||
.OrderBy(o => o.Elevation)
|
||||
.ToList();
|
||||
var toSplit = new FilteredElementCollector(doc)
|
||||
.OfClass(typeof(Level))
|
||||
.OfCategory(BuiltInCategory.OST_Levels)
|
||||
.Cast<Level>()
|
||||
.Where(l => l.Elevation - minZ > 0.0001 && maxZ - l.Elevation > 0.0001)
|
||||
.OrderBy(o => o.Elevation)
|
||||
.ToList();
|
||||
|
||||
if (toSplit.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var n = allLevels.FindIndex(l => l.Id == toSplit[0].Id);
|
||||
var minLevel = allLevels[0];
|
||||
if (n > 0)
|
||||
{
|
||||
minLevel = allLevels[n - 1]; //存在更低的标高时,取此标高作为底标高约束
|
||||
}
|
||||
|
||||
var translation = XYZ.BasisZ;
|
||||
var bottomEleIds = ElementTransformUtils.CopyElement(doc, wall.Id, translation);
|
||||
var minWall = doc.GetElement(bottomEleIds.FirstOrDefault()) as Wall;
|
||||
//底部约束
|
||||
minWall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).Set(minLevel.Id);
|
||||
minWall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(minZ - minLevel.Elevation);
|
||||
minWall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(toSplit[0].Id);
|
||||
minWall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(0);
|
||||
|
||||
//Wall.Create(doc, (wall.Location as LocationCurve).Curve, wall.WallType.Id, minLevel.Id, minLevel.Bottom - minZ, minZ - minLevel.Bottom, wall.Flipped, Convert.ToBoolean(wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger()));
|
||||
|
||||
var maxLevel = toSplit.Last();
|
||||
var m = allLevels.FindIndex(l => l.Id == toSplit.Last().Id);
|
||||
if (m < allLevels.Count - 1)
|
||||
{
|
||||
maxLevel = allLevels[m + 1]; //存在更高的标高
|
||||
}
|
||||
|
||||
var topEleIds = ElementTransformUtils.CopyElement(doc, wall.Id, translation);
|
||||
doc.Regenerate();
|
||||
var maxWall = doc.GetElement(topEleIds.FirstOrDefault()) as Wall;
|
||||
|
||||
maxWall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).Set(toSplit.Last().Id);
|
||||
maxWall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(0);
|
||||
maxWall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(maxLevel.Id);
|
||||
maxWall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(maxZ - maxLevel.Elevation);
|
||||
|
||||
for (var i = 0; i < toSplit.Count - 1; i++)
|
||||
{
|
||||
var baseLevel = toSplit[i];
|
||||
var topLevel = toSplit[i + 1];
|
||||
var eleIds = ElementTransformUtils.CopyElement(doc, wall.Id, translation);
|
||||
doc.Regenerate();
|
||||
var wallCopy = doc.GetElement(eleIds.FirstOrDefault()) as Wall;
|
||||
wallCopy.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).Set(baseLevel.Id);
|
||||
wallCopy.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(0);
|
||||
|
||||
wallCopy.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(topLevel.Id);
|
||||
wallCopy.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(0);
|
||||
//if (i == levelsToSplit.Count - 2 && maxZ < maxLevel.Bottom)
|
||||
//{
|
||||
// wallCopy.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(maxZ - maxLevel.Bottom);
|
||||
//}
|
||||
//Wall.Create(document, curve, wall.WallType.ViewId, levels[i].ViewId, 100, 100, false, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
20
ShrlAlgo.RvKits/RvCivil/SplitFloorCmd.cs
Normal file
20
ShrlAlgo.RvKits/RvCivil/SplitFloorCmd.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
/// <summary>
|
||||
/// Revit执行命令
|
||||
/// </summary>
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class SplitFloorCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
20
ShrlAlgo.RvKits/RvCivil/WallFinishesCmd.cs
Normal file
20
ShrlAlgo.RvKits/RvCivil/WallFinishesCmd.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
using Nice3point.Revit.Toolkit.External;
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
[Regeneration(RegenerationOption.Manual)]
|
||||
public class WallFinishesCmd : ExternalCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
var wallTypes = Document.OfCollector().OfClass(typeof(WallType)).Cast<WallType>().ToList();
|
||||
WinDialogHelper.ShowModeless<WallFinishesView>(new WallFinishesViewModel(wallTypes));
|
||||
}
|
||||
}
|
||||
}
|
||||
69
ShrlAlgo.RvKits/RvCivil/WallFinishesView.xaml
Normal file
69
ShrlAlgo.RvKits/RvCivil/WallFinishesView.xaml
Normal file
@@ -0,0 +1,69 @@
|
||||
<ui:FluentWindowEx
|
||||
x:Class="ShrlAlgo.RvKits.RvCivil.WallFinishesView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:rvCivil="clr-namespace:ShrlAlgo.RvKits.RvCivil"
|
||||
xmlns:ui="https://github.com/ShrlAlgo/WPFluent"
|
||||
Title="墙饰面"
|
||||
Width="250"
|
||||
Height="500"
|
||||
MinHeight="300"
|
||||
d:DataContext="{d:DesignInstance rvCivil:WallFinishesViewModel}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/ShrlAlgo.RvKits;component/WPFUI.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<ui:AutoGridEx
|
||||
ChildMargin="5"
|
||||
Columns="*"
|
||||
Rows="*,Auto,Auto,Auto,Auto">
|
||||
<GroupBox
|
||||
Height="300"
|
||||
VerticalAlignment="Stretch"
|
||||
Header="饰面类型">
|
||||
<ListBox
|
||||
x:Name="CbbWallTypes"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding WallTypes}"
|
||||
SelectedValue="{Binding SelectedWallType, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</GroupBox>
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbWallHeight"
|
||||
Grid.Row="1"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Prefix="饰面总高度:"
|
||||
Suffix="mm"
|
||||
Text="{Binding WallHeight, StringFormat=\{0:F2\}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:TextBoxEx
|
||||
x:Name="TbWallBase"
|
||||
Grid.Row="2"
|
||||
InputMethod.IsInputMethodEnabled="False"
|
||||
Prefix="饰面底部离地高度:"
|
||||
Suffix="mm"
|
||||
Text="{Binding WallBaseOffset, StringFormat=\{0:F2\}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ComboBox
|
||||
x:Name="CbbPlaceType"
|
||||
Grid.Row="3"
|
||||
IsSynchronizedWithCurrentItem="True"
|
||||
SelectedIndex="0"
|
||||
Text="布置方式">
|
||||
<ComboBoxItem Content="墙面" />
|
||||
<ComboBoxItem Content="房间" />
|
||||
<ComboBoxItem Content="整墙" />
|
||||
</ComboBox>
|
||||
<Button
|
||||
x:Name="BtnPlace"
|
||||
Grid.Row="4"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding PlaceWallCommand}"
|
||||
Content="布置" />
|
||||
</ui:AutoGridEx>
|
||||
</ui:FluentWindowEx>
|
||||
15
ShrlAlgo.RvKits/RvCivil/WallFinishesView.xaml.cs
Normal file
15
ShrlAlgo.RvKits/RvCivil/WallFinishesView.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil
|
||||
{
|
||||
/// <summary>
|
||||
/// WallFinishesView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class WallFinishesView
|
||||
{
|
||||
public WallFinishesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
315
ShrlAlgo.RvKits/RvCivil/WallFinishesViewModel.cs
Normal file
315
ShrlAlgo.RvKits/RvCivil/WallFinishesViewModel.cs
Normal file
@@ -0,0 +1,315 @@
|
||||
using System.Windows;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Architecture;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Selection;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Nice3point.Revit.Toolkit.External.Handlers;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ShrlAlgo.RvKits.RvCivil;
|
||||
|
||||
public partial class WallFinishesViewModel(List<WallType> wallTypes) : ObservableObject
|
||||
{
|
||||
private readonly ActionEventHandler wallFinishHandler = new ();
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(PlaceWallCommand))]
|
||||
private double wallBaseOffset;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(PlaceWallCommand))]
|
||||
private double wallHeight;
|
||||
|
||||
[ObservableProperty]
|
||||
private List<WallType> wallTypes = wallTypes;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(PlaceWallCommand))]
|
||||
private WallType selectedWallType;
|
||||
|
||||
public PlacementType PlaceType { get; set; }
|
||||
|
||||
private bool CanPlaceWallFinish()
|
||||
{
|
||||
return SelectedWallType != null && WallHeight > 0 && WallHeight > WallBaseOffset;
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanPlaceWallFinish))]
|
||||
private void PlaceWall()
|
||||
{
|
||||
wallFinishHandler.Raise(uiapp =>
|
||||
{
|
||||
var uidoc = uiapp.ActiveUIDocument;
|
||||
var doc = uidoc.Document;
|
||||
var wallWidth = SelectedWallType.Width;
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
switch (PlaceType)
|
||||
{
|
||||
case PlacementType.ByFace:
|
||||
|
||||
/* 项目“ShrlAlgo.RvKits (net48)”的未合并的更改
|
||||
在此之前:
|
||||
PlaceWallFinishesByFace(uiapp, SelectedWallType, wallWidth, WallHeight, WallBaseOffset);
|
||||
break;
|
||||
在此之后:
|
||||
PlaceWallFinishesByFace(uiapp, SelectedWallType, wallWidth, WallHeight, WallBaseOffset);
|
||||
break;
|
||||
*/
|
||||
WallFinishesViewModel.PlaceWallFinishesByFace(uidoc, SelectedWallType, wallWidth, WallHeight, WallBaseOffset);
|
||||
break;
|
||||
case PlacementType.ByWall:
|
||||
PlaceWallFinishesByWall(uidoc, SelectedWallType, wallWidth, WallHeight, WallBaseOffset);
|
||||
break;
|
||||
case PlacementType.ByRoom:
|
||||
var rooms = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Rooms);
|
||||
if (!rooms.Any())
|
||||
{
|
||||
MessageBox.Show("项目中当前没有房间", "温馨提示");
|
||||
//message = "项目中当前没有房间";
|
||||
}
|
||||
|
||||
PlaceWallFinishesByRoom(uidoc, SelectedWallType, wallWidth, WallHeight, WallBaseOffset);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.OperationCanceledException) { }
|
||||
});
|
||||
}
|
||||
|
||||
private static void PlaceWallFinishesByFace(UIDocument uidoc, WallType wallType, double wallWidth, double height, double baseOffset)
|
||||
{
|
||||
var doc = uidoc.Document;
|
||||
var referFace = uidoc.Selection.PickObject(ObjectType.Face, new GenericFilter<Wall>(), "请选择布置的墙面");
|
||||
var wall = doc.GetElement(referFace) as Wall;
|
||||
var face = wall.GetGeometryObjectFromReference(referFace) as Face;
|
||||
|
||||
var bottomFace = wall.GetAllGeometryObjects<Face>().FirstOrDefault(f => f.ComputeNormal(new UV()).IsAlmostEqualTo(-XYZ.BasisZ));
|
||||
if (bottomFace == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var baseLevel = doc.GetElement(wall.LevelId) as Level;
|
||||
|
||||
face.Intersect(bottomFace, out var intersectCurve);
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
var curve = intersectCurve.CreateOffset(wallWidth / 2, XYZ.BasisZ).CreateReversed();
|
||||
|
||||
var wallCreated = Wall.Create(doc, curve, wallType.Id, baseLevel.Id, height / 304.8, baseOffset / 304.8, false, false);
|
||||
doc.Regenerate();
|
||||
try
|
||||
{
|
||||
if (wallCreated.WallType.Kind == WallKind.Stacked)
|
||||
{
|
||||
foreach (var wallid in wallCreated.GetStackedWallMemberIds())
|
||||
{
|
||||
var stackedWall = doc.GetElement(wallid) as Wall;
|
||||
JoinGeometryUtils.JoinGeometry(doc, wall, stackedWall);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JoinGeometryUtils.JoinGeometry(doc, wall, wallCreated);
|
||||
}
|
||||
//JoinGeometryUtils.JoinGeometry(doc, wall, wallCreated);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.ToLog(ex.Message);
|
||||
}
|
||||
},
|
||||
"创建墙面饰面"
|
||||
);
|
||||
}
|
||||
|
||||
private static void PlaceWallFinishesByRoom(UIDocument uidoc, WallType wallType, double wallWidth, double wallHeight, double wallBaseOffset)
|
||||
{
|
||||
var doc = uidoc.Document;
|
||||
var refer = uidoc.Selection.PickObject(ObjectType.Element, new GenericFilter<Room>(), "请选择布置的房间");
|
||||
var room = uidoc.Document.GetElement(refer) as Room;
|
||||
var baseLevel = doc.GetElement(room.LevelId) as Level;
|
||||
List<CurveLoop> curveLoops =[];
|
||||
List<ElementId> walltojoin = [];
|
||||
List<List<ElementId>> wallToJoinList = [];
|
||||
var opts = new SpatialElementBoundaryOptions();
|
||||
//{
|
||||
// SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish
|
||||
//};
|
||||
|
||||
//BuiltInCategory builtInCategory = (BuiltInCategory)walltype.Category.ViewId.IntegerValue;
|
||||
//if (walltype.Kind == WallKind.Stacked)
|
||||
//{
|
||||
// var li = walltype.GetSubelements();
|
||||
// walltype.get
|
||||
//}
|
||||
//if (walltype.Kind == WallKind.Basic)
|
||||
//{
|
||||
// var compounds = walltype.GetCompoundStructure();
|
||||
// for (int i = 0; i < compounds.LayerCount; i++)
|
||||
// {
|
||||
// offest += compounds.GetWidth();
|
||||
// }
|
||||
//}
|
||||
|
||||
var segementsList = room.GetBoundarySegments(opts);
|
||||
|
||||
if (segementsList != null)
|
||||
{
|
||||
foreach (var boundarySegments in segementsList)
|
||||
{
|
||||
CurveLoop curveLoop = new();
|
||||
foreach (var boundarySegment in boundarySegments)
|
||||
{
|
||||
curveLoop.Append(boundarySegment.GetCurve());
|
||||
walltojoin.Add(boundarySegment.ElementId);
|
||||
}
|
||||
|
||||
wallToJoinList.Add(walltojoin);
|
||||
curveLoops.Add(curveLoop);
|
||||
}
|
||||
}
|
||||
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
var options = ts.GetFailureHandlingOptions();
|
||||
FailuresPreProcessor failuresProcessor = new();
|
||||
options.SetFailuresPreprocessor(failuresProcessor);
|
||||
ts.SetFailureHandlingOptions(options);
|
||||
//Plane plane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, new XYZ());
|
||||
//var mc = doc.Create.NewModelCurveArray(array, SketchPlane.Create(doc, plane));
|
||||
for (var i = 0; i < curveLoops.Count; i++)
|
||||
{
|
||||
//切线方向叉乘参数中的向量,内侧叉乘-z
|
||||
var curveLoopOffset = CurveLoop.CreateViaOffset(curveLoops[i], wallWidth / 2, -XYZ.BasisZ);
|
||||
for (var j = 0; j < curveLoopOffset.Count(); j++)
|
||||
{
|
||||
var curve = curveLoopOffset.ElementAt(j);
|
||||
////c的方向叉乘参数中的向量,内侧叉乘-z
|
||||
//var lc = c.CreateOffset(100 / 304.8, -XYZ.BasisZ);
|
||||
|
||||
//var x = curve.ComputeDerivatives(0.5, true).BasisX.CrossProduct(-XYZ.BasisZ).Normalize() * 100 / 304.8;
|
||||
//var mc = doc.Create.NewModelCurve(lc, SketchPlane.Create(doc, plane));
|
||||
//var mc = doc.Create.NewModelCurve(c, SketchPlane.Create(doc, plane));
|
||||
var wallCreated = Wall.Create(
|
||||
doc,
|
||||
curve,
|
||||
wallType.Id,
|
||||
baseLevel.Id,
|
||||
wallHeight / 304.8,
|
||||
wallBaseOffset / 304.8,
|
||||
false,
|
||||
false
|
||||
);
|
||||
wallCreated.get_Parameter(BuiltInParameter.WALL_ATTR_ROOM_BOUNDING).Set(1);
|
||||
doc.Regenerate();
|
||||
//连接墙体让门窗可以剪切出来
|
||||
#if REVIT2018 || REVIT2020
|
||||
if (wallToJoinList[i][j].IntegerValue > 0)
|
||||
#elif REVIT2025
|
||||
if (wallToJoinList[i][j].Value > 0)
|
||||
#endif
|
||||
{
|
||||
var elemToJoin = doc.GetElement(wallToJoinList[i][j]);
|
||||
try
|
||||
{
|
||||
if (wallCreated.WallType.Kind == WallKind.Stacked)
|
||||
{
|
||||
foreach (var wallid in wallCreated.GetStackedWallMemberIds())
|
||||
{
|
||||
var stackedWall = doc.GetElement(wallid) as Wall;
|
||||
JoinGeometryUtils.JoinGeometry(doc, elemToJoin, stackedWall);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JoinGeometryUtils.JoinGeometry(doc, elemToJoin, wallCreated);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.ToLog(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
//WallUtils.AllowWallJoinAtEnd(w, 0);
|
||||
//offsetCurves.Add(lc);
|
||||
}
|
||||
}
|
||||
},
|
||||
"创建房间墙饰面"
|
||||
);
|
||||
}
|
||||
|
||||
private static void PlaceWallFinishesByWall(UIDocument uidoc, WallType wallType, double wallWidth, double wallHeight, double wallBaseOffset)
|
||||
{
|
||||
var doc = uidoc.Document;
|
||||
var refer = uidoc.Selection.PickObject(ObjectType.Element, new GenericFilter<Wall>(), "请选择布置的墙体");
|
||||
var wall = uidoc.Document.GetElement(refer) as Wall;
|
||||
var baselevel = doc.GetElement(wall.LevelId) as Level;
|
||||
|
||||
var bottomFace = wall.GetAllGeometryObjects<Face>().FirstOrDefault(f => f.ComputeNormal(new UV()).IsAlmostEqualTo(-XYZ.BasisZ));
|
||||
var sideFaces = wall.GetAllGeometryObjects<Face>().Where(f => f.ComputeNormal(new UV()).DotProduct(XYZ.BasisZ) < 1.0e-09);
|
||||
//CurveLoop loop = new CurveLoop();
|
||||
List<Curve> curs = [];
|
||||
foreach (var sideFace in sideFaces)
|
||||
{
|
||||
bottomFace.Intersect(sideFace, out var intersectCurve);
|
||||
curs.Add(intersectCurve);
|
||||
//ModelCurve ml = doc.Create.NewModelCurve(cur, doc.ActiveView.SketchPlane);
|
||||
|
||||
//loop.Append(cur);
|
||||
}
|
||||
|
||||
//var loop = CurveLoop.Create(curs);
|
||||
//var offestcurveloop = CurveLoop.CreateViaOffset(loop, wallwidth / 2, XYZ.BasisZ);
|
||||
doc.Invoke(
|
||||
ts =>
|
||||
{
|
||||
for (var i = 0; i < curs.Count; i++)
|
||||
{
|
||||
var curve = curs.ElementAt(i).CreateOffset(wallWidth / 2, -XYZ.BasisZ);
|
||||
var wallCreated = Wall.Create(doc, curve, wallType.Id, baselevel.Id, wallHeight / 304.8, wallBaseOffset / 304.8, false, false);
|
||||
|
||||
doc.Regenerate();
|
||||
try
|
||||
{
|
||||
if (wallCreated.WallType.Kind == WallKind.Stacked)
|
||||
{
|
||||
foreach (var wallid in wallCreated.GetStackedWallMemberIds())
|
||||
{
|
||||
var stackedwall = doc.GetElement(wallid) as Wall;
|
||||
JoinGeometryUtils.JoinGeometry(doc, wall, stackedwall);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JoinGeometryUtils.JoinGeometry(doc, wall, wallCreated);
|
||||
}
|
||||
//JoinGeometryUtils.JoinGeometry(doc, wall, wallCreated);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.ToLog(ex.Message);
|
||||
}
|
||||
|
||||
//WallUtils.AllowWallJoinAtEnd(w, 0);
|
||||
//offestcurves.Add(lc);
|
||||
}
|
||||
},
|
||||
"创建墙体饰面"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user