Files
RookieStation/RookieStation/CmdPlaceShelves.cs
2021-06-04 16:43:37 +08:00

560 lines
28 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI;
using RookieStation.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Windows;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;
namespace RookieStation.PackAreaModule
{
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
internal class CmdPlaceShelves : IExternalCommand
{
/// <summary>
/// 当前编号
/// </summary>
private int currentnum = 1;
/// <summary>
/// 选择一次后停止
/// </summary>
//private static bool PlaceSingleInstanceAbort = true;
/// <summary>
/// revit窗口句柄
/// </summary>
private IntPtr revitWindow;
/// <summary>
/// 添加的元素
/// </summary>
private List<ElementId> eleIdsAdded = new List<ElementId>();
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Document doc = uidoc.Document;
revitWindow = uiapp.MainWindowHandle;
WpfShelvesLayout placement = CommonUtils.GenerateWindow<WpfShelvesLayout>();
if (placement.DialogResult != true)
{
return Result.Cancelled;
}
ShelvesPlacementViewModel vm = placement.vm;
ObservableCollection<Shelf> shelves = vm.Data;
Level level = uidoc.ActiveView.GenLevel;
return doc.InvokeGroup<Result>(tg =>
{
try
{
//定位线
FamilySymbol guide_Symbol = RsRevitUtils.GetGuideSymbol(doc);
eleIdsAdded.Clear();
uiapp.Application.DocumentChanged += Application_DocumentChanged;
uidoc.PromptForFamilyInstancePlacement(guide_Symbol);
uiapp.Application.DocumentChanged -= Application_DocumentChanged;
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
if (eleIdsAdded.Count == 0)
{
return Result.Cancelled;
}
Line refer_line = RsRevitUtils.GetGuideGeometryAndDeleteGuide(doc, eleIdsAdded);
uiapp.Application.DocumentChanged -= Application_DocumentChanged;
//始终位于左侧,Z轴朝上
var zaxis = XYZ.BasisZ;
Family shelf_family = null;
FamilySymbol shelf_symbol = null;
double shelf_spacing = vm.Spacing / 304.8;
//通道宽度
double passage_width = vm.PassageWidth / 304.8;
double parallel_referline_offest = vm.ParalelReferOffest / 304.8;
double vertical_referline_offest = vm.VerticalReferOffest / 304.8;
for (int i = 0; i < shelves.Count; i++)
{
//List<XYZ> all_points = new List<XYZ>();
List<XYZ> first_row_points = new List<XYZ>();
Shelf shelf = shelves[i];
double shelf_width = shelf.Width / 304.8;
double line_parameter = 0.0;
int n = 100;//循环次数
XYZ p = XYZ.Zero;
if (parallel_referline_offest < 0.001)//起点无间距
{
for (int j = 0; j < n; j++)
{
if (!refer_line.IsInside((line_parameter + shelf_width)))
{
break;
}
if (j % 2 == 0)
{
p = refer_line.Evaluate(line_parameter, false);
line_parameter += shelf_spacing + shelf_width;
}
else
{
p = refer_line.Evaluate(line_parameter, false);
line_parameter += shelf_width;
}
first_row_points.Add(p);
}
}
else//起点有距离
{
line_parameter = parallel_referline_offest;
for (int j = 0; j < n; j++)
{
if (!refer_line.IsInside(line_parameter + shelf_width))
{
break;
}
if (j % 2 == 0)
{
p = refer_line.Evaluate(line_parameter, false);
line_parameter += shelf_width;
}
else
{
p = refer_line.Evaluate(line_parameter, false);
line_parameter += shelf_spacing + shelf_width;
}
first_row_points.Add(p);
}
}
double l = shelf.Length / 304.8;
XYZ normal_vertical_offest_vector = zaxis.CrossProduct(refer_line.Direction).Normalize();
List<FamilyInstance> instances = new List<FamilyInstance>();
XYZ final_point = XYZ.Zero;
doc.Invoke(ts =>
{
shelf_family = RsRevitUtils.GetLoadedFamily(doc, UserConstant.LibraryPreDirectory + "Shelf\\单联货架.rfa");
var shelf_symbol_ids = shelf_family.GetFamilySymbolIds();
foreach (var id in shelf_symbol_ids)
{
FamilySymbol temp_symbol = doc.GetElement(id) as FamilySymbol;
if (temp_symbol.Name == shelf.SymbolName)
{
shelf_symbol = temp_symbol;
break;
}
}
shelf_symbol.Activate();
}, "加载货架,激活类型");
switch (shelf.NumOfGroup)
{
case NumOfGroup.Single:
for (int j = 0; j < first_row_points.Count; j++)
{
XYZ pt = first_row_points[j];
XYZ offest_direction = normal_vertical_offest_vector * (vertical_referline_offest + l / 2);
//垂直基准线平移 平行基准线平移
final_point = pt + offest_direction + refer_line.Direction * shelf_width / 2;
//附加通道和(单联、多联)货架长度的偏移
if (i > 0)
{
double total_length = GetTotalLength(shelves, i);
//附加排在前面通道和所有货架的长度
XYZ additional_dir = normal_vertical_offest_vector * (i * passage_width + total_length);
final_point += additional_dir;
}
FamilyInstance instance = null;
//all_points.Add(final_point);
doc.Invoke(ts =>
{
instance = doc.Create.NewFamilyInstance(final_point, shelf_symbol, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
instances.Add(instance);
}, "创建货架");
//位于直线右侧时,需要进行左右翻转
doc.Invoke(ts =>
{
if (parallel_referline_offest < 0.001)
{
if (j % 2 != 0 && instance.CanFlipHand)
{
instance.flipHand();
}
}
else
{
if (j % 2 == 0 && instance.CanFlipHand)
{
instance.flipHand();
}
}
}, "翻转货架");
}
break;
case NumOfGroup.Double:
for (int j = 0; j < first_row_points.Count; j++)
{
XYZ pt = first_row_points[j];
//偏移距离
XYZ offest_direction = normal_vertical_offest_vector * (vertical_referline_offest + l);
//基础偏移距离,移动半个长度到直线的一侧,垂直基准线平移 平行基准线平移
final_point = pt + offest_direction + refer_line.Direction * shelf_width / 2;
//附加通道和(单联、多联)货架长度的偏移
if (i > 0)
{
double totallength = GetTotalLength(shelves, i);
XYZ additionaldir = normal_vertical_offest_vector * (i * passage_width + totallength);
final_point += additionaldir;
}
FamilyInstance end_instance = null;
FamilyInstance start_instance = null;
doc.Invoke(ts =>
{
end_instance = doc.Create.NewFamilyInstance(final_point + l / 2 * normal_vertical_offest_vector, shelf_symbol, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
start_instance = doc.Create.NewFamilyInstance(final_point - l / 2 * normal_vertical_offest_vector, shelf_symbol, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
instances.Add(start_instance);
instances.Add(end_instance);
}, "创建货架");
doc.Invoke(ts =>
{
if (parallel_referline_offest < 0.001)
{
if (j % 2 != 0 && start_instance.CanFlipHand && end_instance.CanFlipHand)
{
start_instance.flipHand();
end_instance.flipHand();
}
}
else
{
if (j % 2 == 0 && start_instance.CanFlipHand && end_instance.CanFlipHand)
{
start_instance.flipHand();
end_instance.flipHand();
}
}
}, "翻转货架");
//all_points.Add(final_point + l / 2 * normal_vertical_offest_vector);
//all_points.Add(final_point - l / 2 * normal_vertical_offest_vector);
}
break;
case NumOfGroup.Three:
for (int j = 0; j < first_row_points.Count; j++)
{
XYZ pt = first_row_points[j];
XYZ offestdir = normal_vertical_offest_vector * (vertical_referline_offest + l * 3 / 2);
//垂直基准线平移 平行基准线平移
final_point = pt + offestdir + refer_line.Direction * shelf_width / 2;
//附加通道和(单联、多联)货架长度的偏移
if (i > 0)
{
double totallength = GetTotalLength(shelves, i);
XYZ additionaldir = normal_vertical_offest_vector * (i * passage_width + totallength);
final_point += additionaldir;
}
FamilyInstance end_instance = null;
FamilyInstance center_instance = null;
FamilyInstance start_instance = null;
doc.Invoke(ts =>
{
center_instance = doc.Create.NewFamilyInstance(final_point, shelf_symbol, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
end_instance = doc.Create.NewFamilyInstance(final_point + l * normal_vertical_offest_vector, shelf_symbol, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
start_instance = doc.Create.NewFamilyInstance(final_point - l * normal_vertical_offest_vector, shelf_symbol, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
instances.Add(center_instance);
instances.Add(end_instance);
instances.Add(start_instance);
}, "创建货架");
doc.Invoke(ts =>
{
if (parallel_referline_offest < 0.001)
{
if (j % 2 != 0 && start_instance.CanFlipHand && center_instance.CanFlipHand && end_instance.CanFlipHand)
{
start_instance.flipHand();
center_instance.flipHand();
end_instance.flipHand();
}
}
else
{
if (j % 2 == 0 && start_instance.CanFlipHand && center_instance.CanFlipHand && end_instance.CanFlipHand)
{
start_instance.flipHand();
center_instance.flipHand();
end_instance.flipHand();
}
}
}, "翻转货架");
}
break;
default:
break;
}
List<FamilyInstance> card_instances = new List<FamilyInstance>();
doc.Invoke(ts =>
{
XYZ veroffestdir = zaxis.CrossProduct(refer_line.Direction).Normalize();
//旋转角度
double angle = XYZ.BasisY.AngleTo(veroffestdir);
//判断相对于Y轴是正向角度逆时针还是逆向角度顺时针
var z = veroffestdir.CrossProduct(XYZ.BasisY).Normalize();
if (z.IsAlmostEqualTo(XYZ.BasisZ))
{
//逆向旋转,角度取负值
angle = -angle;
}
for (int j = 0; j < instances.Count; j++)
{
FamilyInstance instance = instances[j];
var location_XYZ = RsRevitUtils.GetXYZByElement(instance);
Line zline = Line.CreateUnbound(location_XYZ, XYZ.BasisZ);
//旋转,移动
ElementTransformUtils.RotateElement(doc, instance.Id, zline, angle);
//旋转后的
var hand_orientationd = instance.HandOrientation;
//货架左右切换时
if (instance.HandFlipped)
{
hand_orientationd = -hand_orientationd;
}
////垂直基准线平移
//ElementTransformUtils.MoveElement(doc, fi.Id, offestdir);
////平行基准线平移
//ElementTransformUtils.MoveElement(doc, fi.Id, line.Direction * w / 2);
//if (i >= 1)
//{
// XYZ additionaldir = zdir.CrossProduct(line.Direction).Normalize() * i * (passagewidth + l);
// ElementTransformUtils.MoveElement(doc, fi.Id, additionaldir);
//}
#region
FamilyInstance front_instance = null;
Reference front_face = instance.GetReferences(FamilyInstanceReferenceType.Front).FirstOrDefault();
PlaceCard(doc, location_XYZ, instance, hand_orientationd, front_face, out front_instance);
if (front_instance.CanFlipWorkPlane)
{
front_instance.IsWorkPlaneFlipped = true;
}
card_instances.Add(front_instance);
FamilyInstance back_instance = null;
Reference back_face = instance.GetReferences(FamilyInstanceReferenceType.Back).FirstOrDefault();
PlaceCard(doc, location_XYZ, instance, -hand_orientationd, back_face, out back_instance);
card_instances.Add(back_instance);
switch (shelf.NumOfGroup)
{
case NumOfGroup.Single:
front_instance.GetParameters("货架号").FirstOrDefault().Set(string.Format("{0}", currentnum));
back_instance.GetParameters("货架号").FirstOrDefault().Set(string.Format("{0}", currentnum));
currentnum += 1;
break;
case NumOfGroup.Double:
//根据组合加上组合数
if (j % 2 == 0 && j != 0)
{
currentnum += 2;
}
front_instance.GetParameters("货架号").FirstOrDefault().Set(string.Format("{0}{1}{2}", currentnum, "~", currentnum + 1));
back_instance.GetParameters("货架号").FirstOrDefault().Set(string.Format("{0}{1}{2}", currentnum, "~", currentnum + 1));
//最后一个需要加上组合数作为下一列的开始
if (j == instances.Count - 1)
{
currentnum += 2;
}
break;
case NumOfGroup.Three:
//根据组合加上组合数
if (j % 3 == 0 && j != 0)
{
currentnum += 3;
}
front_instance.GetParameters("货架号").FirstOrDefault().Set(string.Format("{0}{1}{2}", currentnum, "~", currentnum + 2));
back_instance.GetParameters("货架号").FirstOrDefault().Set(string.Format("{0}{1}{2}", currentnum, "~", currentnum + 2));
//最后一个需要加上组合数作为下一列的开始
if (j == instances.Count - 1)
{
currentnum += 3;
}
break;
default:
break;
}
#endregion
//Reference backface = fi.GetReferences(FamilyInstanceReferenceType.Back).FirstOrDefault();
//if (a.Contains("606:SURFACE"))
//{
// hand = -fi.HandOrientation;
//}
}
}, "调整货架角度及布置端牌");
DeleteCards(doc, card_instances);
}
}
return Result.Succeeded;
}, "布置货架及端牌");
}
/// <summary>
/// 删除多余端牌
/// </summary>
/// <param name="doc"></param>
/// <param name="card_instances"></param>
private void DeleteCards(Document doc, List<FamilyInstance> card_instances)
{
using (Transaction ts = new Transaction(doc, "删除多余端牌"))
{
ts.Start();
List<ElementId> ids_delete = new List<ElementId>();
foreach (var ins in card_instances)
{
var lp = RsRevitUtils.GetXYZByElement(ins);
foreach (var card in card_instances)
{
var lpt = RsRevitUtils.GetXYZByElement(card);
if (!card.Id.Equals(ins.Id) && lp.IsAlmostEqualTo(lpt))
{
ids_delete.Add(ins.Id);
ids_delete.Add(card.Id);
break;
}
}
}
doc.Delete(ids_delete);
ts.Commit();
}
}
private void Application_DocumentChanged(object sender, Autodesk.Revit.DB.Events.DocumentChangedEventArgs e)
{
ICollection<ElementId> idsAdded = e.GetAddedElementIds();
int n = idsAdded.Count;
//List<Element> eles = new List<Element>();
//foreach (var id in idsAdded)
//{
// eles.Add(e.GetDocument().GetElement(id));
//}
eleIdsAdded.AddRange(idsAdded);
//if (PlaceSingleInstanceAbort && n == 1)
if (n == 1)
{
KeyPress.PostMessage(revitWindow, (uint)KeyPress.KEYBOARD_MSG.WM_KEYDOWN, (uint)System.Windows.Forms.Keys.Escape, 0);
KeyPress.PostMessage(revitWindow, (uint)KeyPress.KEYBOARD_MSG.WM_KEYDOWN, (uint)System.Windows.Forms.Keys.Escape, 0);
//KeyPress.OneKey(revitWindow, (char)System.Windows.Forms.Keys.Escape);
}
}
/// <summary>
/// 布置端牌
/// </summary>
/// <param name="doc"></param>
/// <param name="p"></param>
/// <param name="fi"></param>
/// <param name="handOrientation">左右方向</param>
/// <param name="facereference"></param>
/// <param name="card_instance"></param>
private void PlaceCard(Document doc, XYZ p, FamilyInstance fi, XYZ handOrientation, Reference facereference, out FamilyInstance card_instance)
{
var shelfwidth = fi.Symbol.GetParameters("宽度").FirstOrDefault().AsDouble();
Family card = RsRevitUtils.GetLoadedFamily(doc, UserConstant.LibraryPreDirectory + "Shelf\\货架端牌.rfa");
var cardsymbolIds = card.GetFamilySymbolIds();
FamilySymbol cardsymbol = null;
foreach (ElementId syid in cardsymbolIds)
{
var sy = doc.GetElement(syid) as FamilySymbol;
var cardwidth = sy.GetParameters("宽度").FirstOrDefault().AsDouble();
if (cardwidth == shelfwidth)
{
cardsymbol = sy;
}
}
if (!cardsymbol.IsActive)
{
cardsymbol.Activate();
}
card_instance = doc.Create.NewFamilyInstance(facereference, p, handOrientation, cardsymbol);
}
/// <summary>
/// 获取该行之前的所有货架长度总和(英制)
/// </summary>
/// <param name="shelves"></param>
/// <param name="i">行数大于1即i>0</param>
/// <returns></returns>
private double GetTotalLength(ObservableCollection<Shelf> shelves, int i)
{
double totallength = 0.0;
for (int j = 0; j < i; j++)
{
switch (shelves[j].NumOfGroup)
{
case NumOfGroup.Single:
totallength += shelves[j].Length;
break;
case NumOfGroup.Double:
totallength += shelves[j].Length * 2;
break;
case NumOfGroup.Three:
totallength += shelves[j].Length * 3;
break;
default:
break;
}
}
return totallength / 304.8;
}
}
}