波导线拆分(基于Revit2019 API)
`using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using Form = System.Windows.Forms.Form;
namespace Boundary
{
[Transaction(TransactionMode.Manual)]
public class LoopBoundary : IExternalCommand
{
private UIDocument uidoc;
private Document currentDocument;
private Material currentMat;
private PartMaker partMaker;
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
uidoc = commandData.Application.ActiveUIDocument;
currentDocument = uidoc.Document;
partMaker = null;
currentMat = null;
message =
Trans("boundary",
() =>
{
var frm = new DataInput(GetMaterials());
var dr = frm.ShowDialog();
if (dr != System.Windows.Forms.DialogResult.OK) return null;
currentMat = frm.Material;
var floor = GetFloor();
if (floor == null) return null;
var face = GetFace(floor);
if (face == null) return "获取 波导线错误";
if (!PartUtils.AreElementsValidForCreateParts(currentDocument, new[] { floor.Id }))
return "无法为对象创建零件";
PartUtils.CreateParts(currentDocument, new[] { floor.Id });
currentDocument.Regenerate();
var parts = PartUtils.GetAssociatedParts(currentDocument, floor.Id, false, false);
if (!PartUtils.ArePartsValidForDivide(currentDocument, parts))
return "无法为对象拆分零件";
//拆分线
var cvs = GetCurves(face, MmToFt(frm.Length));
//拆分平面
var p = Plane.CreateByNormalAndOrigin(face.FaceNormal, face.Origin);
var sp = SketchPlane.Create(currentDocument, p);
partMaker = PartUtils.DivideParts(
currentDocument,
parts,
new List<ElementId>(0),
cvs,
sp.Id);
currentDocument.ActiveView.PartsVisibility = PartsVisibility.ShowPartsOnly;
return null;
});
if (!string.IsNullOrEmpty(message)) return Result.Failed;
SetPartsMat(partMaker);
return Result.Succeeded;
}
private void SetPartsMat(PartMaker pk)
{
var filter = new ElementClassFilter(typeof(Part));
var parts = new FilteredElementCollector(currentDocument)
.WherePasses(filter)
.OfType<Part>();
foreach (var part in parts)
{
if (part.PartMaker.Id != pk.Id) continue;
SetPartMatNoReadOnly(part);
SetPartMat(part);
}
}
private void SetPartMatNoReadOnly(Part part)
{
var original = part.get_Parameter(BuiltInParameter.DPART_MATERIAL_BY_ORIGINAL);
if (!original.IsReadOnly)
Trans("original", () => { original.Set(0); });
}
private void SetPartMat(Part part)
{
var mat = part.get_Parameter(BuiltInParameter.DPART_MATERIAL_ID_PARAM);
if (!mat.IsReadOnly)
Trans("mat set", () => { mat.Set(currentMat.Id); });
}
private XYZ PointProjectLine(XYZ pt, Line line)
{
line.MakeUnbound();
return line.Project(pt).XYZPoint;
}
private string Trans(string tranName, Func<string> func)
{
var r = "";
var trn = new Transaction(currentDocument, tranName);
using (trn)
{
trn.Start();
r = func();
trn.Commit();
}
return r;
}
private void Trans(string tranName, Action action)
{
var trn = new Transaction(currentDocument, tranName);
using (trn)
{
trn.Start();
action();
trn.Commit();
}
}
private List<Material> GetMaterials()
{
var filterByMaterial = new ElementCategoryFilter(BuiltInCategory.OST_Materials);
var col = new FilteredElementCollector(currentDocument);
var mats = col.WherePasses(filterByMaterial)
.OfType<Material>()
.ToList();
if (mats.Count > 0)
{
return mats;
}
throw new ArgumentNullException("无法获取材质!");
}
private Floor GetFloor()
{
try
{
var fid = uidoc.Selection.PickObject(ObjectType.Element, new FloorSelectionFilter());
var floor = currentDocument.GetElement(fid.ElementId) as Floor;
return floor;
}
catch
{
return null;
}
}
private PlanarFace GetFace(Floor floor)
{
var refer = HostObjectUtils.GetTopFaces(floor).FirstOrDefault();
var planer = floor.GetGeometryObjectFromReference(refer) as PlanarFace;
return planer;
}
private double MmToFt(double mm)
{
return UnitUtils.Convert(mm, DisplayUnitType.DUT_MILLIMETERS, DisplayUnitType.DUT_DECIMAL_FEET);
}
/// <summary>
///
/// </summary>
/// <param name="floor"></param>
public List<Curve> GetCurves(PlanarFace planer, double divLen)
{
var pts = planer.Triangulate().Vertices;
foreach (XYZ pt in pts)
{
Debug.Print(@"{0},{1}", pt.X, pt.Y);
}
var pts1 = pts.Take(pts.Count / 2);
var pts2 = pts.Skip(pts.Count / 2).Reverse();
var lst2 = pts2.ToList();
var lst1 = pts1.ToList();
var last = pts2.Last();
lst2.Insert(0, last);
lst2.RemoveAt(lst2.Count - 1);
last = lst2.Last();
lst2.Insert(0, last);
lst2.RemoveAt(lst2.Count - 1);
var outs = OrderXyzListByBottomLeft(lst1);
var inners = OrderXyzListByBottomLeft(lst2);
var loops = FenChai(inners, outs, divLen);
return Combine(loops, pts);
}
private List<XYZ> OrderXyzListByBottomLeft(List<XYZ> pts)
{
var r = new List<XYZ>();
Debug.Print("OrderXyzList");
var minY = pts.Min(p => p.Y);
var minX = pts.Where(p => p.Y == minY).Min(pt => pt.X);
var index = pts.FindIndex(p => p.X == minX && p.Y == minY);
r = pts.Skip(index).ToList();
r.AddRange(pts.Take(index));
return r;
}
private List<List<XYZ>> FenChai(List<XYZ> inners, List<XYZ> outers, double divlen)
{
var r_inner = new List<XYZ>();
var r_out = new List<XYZ>();
inners.Add(inners.First());
outers.Add(outers.First());
for (int i = 0; i < inners.Count - 1; i++)
{
var p1 = inners[i];
var p2 = inners[i + 1];
var outp1 = outers[i];
var outp2 = outers[i + 1];
var line_in = Line.CreateBound(p1, p2);
var line_out = Line.CreateBound(outp1, outp2);
var direction_in = line_in.Direction;
var direction_out = line_out.Direction;
var half = line_in.Length / 2.0;
var count = (int)(half / divlen);
count = count * 2;
var rem_in = half % divlen;
r_inner.Add(p1);
r_out.Add(outp1);
if (rem_in > 1e-9)
{
var pt = p1 + direction_in * rem_in;
r_inner.Add(pt);
r_out.Add(PointProjectLine(pt, line_out));
}
for (int j = 0; j < count; j++)
{
var pt = p1 + direction_in * (rem_in + (j + 1) * divlen);
r_inner.Add(pt);
r_out.Add(PointProjectLine(pt, line_out));
}
}
r_inner.Add(inners.First());
r_out.Add(outers.First());
return new List<List<XYZ>> { r_inner, r_out };
}
private List<Curve> Combine(List<List<XYZ>> loops, IList<XYZ> pts)
{
var r = new List<Curve>();
foreach (var loop in loops)
{
for (int i = 0; i < loop.Count - 1; i++)
{
r.Add(Line.CreateBound(loop[i], loop[i + 1]));
}
}
var loop1 = loops[0];
var loop2 = loops[1];
for (int i = 0; i < loop1.Count - 1; i++)
{
if (pts.Contains(loop1[i])) continue;
r.Add(Line.CreateBound(loop1[i], loop2[i]));
}
return r;
}
public class FloorSelectionFilter : ISelectionFilter
{
public bool AllowElement(Element element)
{
if (element.Category == null) return false;
if (element.Category.Id.IntegerValue != (int)BuiltInCategory.OST_Floors)
return false;
var floor = element as Floor;
if (floor == null) return false;
var openings = floor.GetDependentElements(new ElementClassFilter(typeof(Opening)));
return openings.Count > 0;
}
public bool AllowReference(Reference reference, XYZ position)
=> false;
}
public class DataInput : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.length_lab = new System.Windows.Forms.Label();
this.mat_lab = new System.Windows.Forms.Label();
this.btn_pickFloor = new System.Windows.Forms.Button();
this.btn_cancel = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.cbox_mats = new System.Windows.Forms.ComboBox();
this.SuspendLayout();
//
// length_lab
//
this.length_lab.AutoSize = true;
this.length_lab.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.length_lab.Location = new System.Drawing.Point(19, 39);
this.length_lab.Name = "length_lab";
this.length_lab.Size = new System.Drawing.Size(147, 14);
this.length_lab.TabIndex = 0;
this.length_lab.Text = "指定波导线长度(mm):";
//
// mat_lab
//
this.mat_lab.AutoSize = true;
this.mat_lab.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.mat_lab.Location = new System.Drawing.Point(43, 96);
this.mat_lab.Name = "mat_lab";
this.mat_lab.Size = new System.Drawing.Size(119, 14);
this.mat_lab.TabIndex = 0;
this.mat_lab.Text = "选择波导线材质:";
//
// btn_pickFloor
//
this.btn_pickFloor.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btn_pickFloor.Location = new System.Drawing.Point(146, 191);
this.btn_pickFloor.Name = "btn_pickFloor";
this.btn_pickFloor.Size = new System.Drawing.Size(108, 37);
this.btn_pickFloor.TabIndex = 1;
this.btn_pickFloor.Text = "选择楼板";
this.btn_pickFloor.UseVisualStyleBackColor = true;
this.btn_pickFloor.Click += new System.EventHandler(this.btn_pickFloor_Click);
//
// btn_cancel
//
this.btn_cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btn_cancel.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.btn_cancel.Location = new System.Drawing.Point(271, 191);
this.btn_cancel.Name = "btn_cancel";
this.btn_cancel.Size = new System.Drawing.Size(75, 37);
this.btn_cancel.TabIndex = 1;
this.btn_cancel.Text = "取消";
this.btn_cancel.UseVisualStyleBackColor = true;
//
// textBox1
//
this.textBox1.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.textBox1.Location = new System.Drawing.Point(166, 36);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(180, 23);
this.textBox1.TabIndex = 2;
this.textBox1.Text = "500";
this.textBox1.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);
//
// cbox_mats
//
this.cbox_mats.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cbox_mats.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.cbox_mats.FormattingEnabled = true;
this.cbox_mats.ItemHeight = 14;
this.cbox_mats.Location = new System.Drawing.Point(166, 93);
this.cbox_mats.Name = "cbox_mats";
this.cbox_mats.Size = new System.Drawing.Size(180, 22);
this.cbox_mats.TabIndex = 3;
//
// DataInput
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btn_cancel;
this.ClientSize = new System.Drawing.Size(383, 264);
this.Controls.Add(this.cbox_mats);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.btn_cancel);
this.Controls.Add(this.btn_pickFloor);
this.Controls.Add(this.mat_lab);
this.Controls.Add(this.length_lab);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "DataInput";
this.Text = "环形波导线";
this.Load += new System.EventHandler(this.DataInput_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label length_lab;
private System.Windows.Forms.Label mat_lab;
private System.Windows.Forms.Button btn_pickFloor;
private System.Windows.Forms.Button btn_cancel;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.ComboBox cbox_mats;
public int Length => string.IsNullOrEmpty(textBox1.Text) ? 0 : int.Parse(textBox1.Text);
public Material Material => cbox_mats.SelectedItem as Material;
public DataInput(List<Material> lists)
{
InitializeComponent();
cbox_mats.DataSource = lists;
cbox_mats.DisplayMember = "Name";
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !(char.IsDigit(e.KeyChar) || char.IsControl(e.KeyChar));
}
private void DataInput_Load(object sender, EventArgs e)
{
}
private void btn_pickFloor_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
this.Close();
}
}
}
}
`
原创代码,未经许可,请勿商用
本人有多年的CAD开发经验,独立完成多个CAD二次开发及Revit二次开发项目。熟悉.net及Asp.net开发技术,和Lisp开发技术。
现在成立了工作室,承接开发项目。结项后提供源码及开发文档,有需要的话可以提供发票.
有需求的可以 qilongliao@qq.com 联系开发事宜.