560 lines
28 KiB
C#
560 lines
28 KiB
C#
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;
|
||
}
|
||
}
|
||
} |