Client/Desktop/KMBIM3.0/KMBIM3.0_23.08.16_수정최종/Utils/FamilyInstanceCreator.cs

419 lines
14 KiB
C#

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using GeoInstance = Autodesk.Revit.DB.GeometryInstance;
using GeoElement = Autodesk.Revit.DB.GeometryElement;
using RevitElement = Autodesk.Revit.DB.Element;
namespace KMBIM.Revit.Tools.Utils
{
/// <summary>
/// This is main data class for creating family Instance by face
/// </summary>
public class FamilyInstanceCreator
{
#region Fields
// Revit document
private UIDocument m_revitDoc;
private Autodesk.Revit.Creation.Application m_appCreator;
// all face names
private List<String> m_faceNameList = new List<String>();
// all face instances
private List<Face> m_faceList = new List<Face>();
// all family symbols
private Dictionary<string, FamilySymbol> dictFamilySymbol = new Dictionary<string, FamilySymbol>();
// all family symbol names
private List<String> m_familySymbolNameList = new List<String>();
// the index default family symbol in family list
private FamilySymbol m_symbol;
#endregion
#region Properties
/// <summary>
/// Store the all face names, they will be displayed in a combo box
/// </summary>
public List<String> FaceNameList
{
get
{
return m_faceNameList;
}
}
/// <summary>
/// Store all face instances for convenience to create a face-based family instance
/// </summary>
public List<Face> FaceList
{
get
{
return m_faceList;
}
}
#endregion
#region Construtor
/// <summary>
/// Constructor, Store the Revit application
/// </summary>
/// <param name="app"></param>
public FamilyInstanceCreator(Autodesk.Revit.UI.UIApplication app)
{
m_revitDoc = app.ActiveUIDocument;
m_appCreator = app.Application.Create;
}
#endregion
#region Public methods
/// <summary>
/// 1. Find all family symbols in current Revit document and store them
/// 2. Find the index of default family symbol
/// Point("Point-based"); Line("Line-based")
/// </summary>
public void CheckFamilySymbol(FileInfo fiFamilypath, string defaultSymbolName)
{
Autodesk.Revit.DB.FilteredElementIterator familySymbolItor =
new FilteredElementCollector(m_revitDoc.Document).OfClass(typeof(FamilySymbol)).GetElementIterator();
bool hasDefaultSymbol = false;
int ii = 0;
while (familySymbolItor.MoveNext())
{
FamilySymbol symbol = (FamilySymbol)familySymbolItor.Current;
if (null == symbol)
{
continue;
}
if (!hasDefaultSymbol && 0 == String.Compare(defaultSymbolName, symbol.Name, true))
{
hasDefaultSymbol = true;
m_symbol = symbol;
break;
}
}
if (!hasDefaultSymbol)
{
FamilySymbol loadedfamilySymbol = null;
try
{
m_revitDoc.Document.LoadFamilySymbol(fiFamilypath.FullName, defaultSymbolName, out loadedfamilySymbol);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
if (null == loadedfamilySymbol)
{
return;
}
m_symbol = loadedfamilySymbol;
}
return;
}
public FamilyInstance CreatePipeAnnotation(XYZ origin, Autodesk.Revit.DB.View view)
{
FamilyInstance instance = m_revitDoc.Document.Create.NewFamilyInstance(origin, m_symbol, view);
m_revitDoc.Selection.GetElementIds().Clear();
m_revitDoc.Selection.GetElementIds().Add(instance.Id);
return instance;
}
public FamilyInstance CreateOpening(Reference linkedface, XYZ position, XYZ refDir)
{
Autodesk.Revit.DB.FamilyInstance instance = null;
if (!m_symbol.IsActive) m_symbol.Activate();
instance = m_revitDoc.Document.Create.NewFamilyInstance(linkedface, position, refDir, m_symbol);
return instance;
}
public FamilyInstance CreateOpening(Face face, Line position)
{
Autodesk.Revit.DB.FamilyInstance instance = null;
if (!m_symbol.IsActive) m_symbol.Activate();
instance = m_revitDoc.Document.Create.NewFamilyInstance(face, position, m_symbol);
return instance;
}
public FamilyInstance CreateWallOpening(XYZ origin, Wall wall)
{
Autodesk.Revit.DB.FamilyInstance instance = null;
instance = m_revitDoc.Document.Create.NewFamilyInstance(origin, m_symbol, wall, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
return instance;
}
public FamilyInstance CreateFloorOpening(XYZ origin, Floor floor)
{
Autodesk.Revit.DB.FamilyInstance instance = null;
instance = m_revitDoc.Document.Create.NewFamilyInstance(origin, m_symbol, floor, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
//m_revitDoc.Selection.Elements.Clear();
//m_revitDoc.Selection.Elements.Add(instance);
return instance;
}
/// <summary>
/// Create a based-point family instance by face
/// </summary>
/// <param name="locationP">the location point</param>
/// <param name="directionP">the direction</param>
/// <param name="faceIndex">the index of the selected face</param>
/// <param name="familySymbolIndex">the index of the selected family symbol</param>
/// <returns></returns>
public bool CreatePointFamilyInstance(Autodesk.Revit.DB.XYZ locationP, Autodesk.Revit.DB.XYZ directionP, int faceIndex
, int familySymbolIndex)
{
Face face = m_faceList[faceIndex];
FamilyInstance instance = m_revitDoc.Document.Create.NewFamilyInstance(face
, locationP, directionP, m_symbol);
m_revitDoc.Selection.GetElementIds().Clear();
m_revitDoc.Selection.GetElementIds().Add(instance.Id);
return true;
}
/// <summary>
/// Create a based-line family instance by face
/// </summary>
/// <param name="startP">the start point</param>
/// <param name="endP">the end point</param>
/// <param name="faceIndex">the index of the selected face</param>
/// <param name="familySymbolIndex">the index of the selected family symbol</param>
/// <returns></returns>
public bool CreateLineFamilyInstance(Autodesk.Revit.DB.XYZ startP, Autodesk.Revit.DB.XYZ endP, int faceIndex
, int familySymbolIndex)
{
Face face = m_faceList[faceIndex];
Autodesk.Revit.DB.XYZ projectedStartP = Project(face.Triangulate().Vertices as List<XYZ>, startP);
Autodesk.Revit.DB.XYZ projectedEndP = Project(face.Triangulate().Vertices as List<XYZ>, endP);
if (projectedStartP.IsAlmostEqualTo(projectedEndP))
{
return false;
}
Line line = Line.CreateBound(projectedStartP, projectedEndP);
FamilyInstance instance = m_revitDoc.Document.Create.NewFamilyInstance(face, line, m_symbol);
m_revitDoc.Selection.GetElementIds().Clear();
m_revitDoc.Selection.GetElementIds().Add(instance.Id);
return true;
}
/// <summary>
/// Judge whether the selected elementSet has face geometry
/// </summary>
/// <returns>true is having face geometry, false is having no face geometry</returns>
public bool CheckSelectedElementSet()
{
// judge whether an or more element is selected
if (1 != m_revitDoc.Selection.GetElementIds().Count)
{
return false;
}
m_faceList.Clear();
m_faceNameList.Clear();
// judge whether the selected element has face geometry
foreach (var elm_id in m_revitDoc.Selection.GetElementIds())
{
var elem = m_revitDoc.Document.GetElement(elm_id);
CheckSelectedElement(elem);
break;
}
if (0 >= m_faceList.Count)
{
return false;
}
return true;
}
#endregion
#region Private Methods
/// <summary>
/// Get the bounding box of a face, the BoundingBoxXYZ will be set in UI as default value
/// </summary>
/// <param name="indexFace">the index of face</param>
/// <returns>the bounding box</returns>
public BoundingBoxXYZ GetFaceBoundingBox(int indexFace)
{
Mesh mesh = m_faceList[indexFace].Triangulate();
Autodesk.Revit.DB.XYZ maxP = new Autodesk.Revit.DB.XYZ(double.MinValue, double.MinValue, double.MinValue);
Autodesk.Revit.DB.XYZ minP = new Autodesk.Revit.DB.XYZ(double.MaxValue, double.MaxValue, double.MaxValue);
foreach (Autodesk.Revit.DB.XYZ tempXYZ in mesh.Vertices)
{
minP = new XYZ(
Math.Min(minP.X, tempXYZ.X),
Math.Min(minP.Y, tempXYZ.Y),
Math.Min(minP.Z, tempXYZ.Z));
maxP = new XYZ(
Math.Max(maxP.X, tempXYZ.X),
Math.Max(maxP.Y, tempXYZ.Y),
Math.Max(maxP.Z, tempXYZ.Z));
}
BoundingBoxXYZ retBounding = new BoundingBoxXYZ();
retBounding.Max = maxP;
retBounding.Min = minP;
return retBounding;
}
/// <summary>
/// Judge whether an element has face geometry
/// </summary>
/// <param name="elem">the element to be checked</param>
/// <returns>true is having face geometry, false is having no face geometry</returns>
private bool CheckSelectedElement(RevitElement elem)
{
if (null == elem)
{
return false;
}
// Options opt = app.Application.Create.NewGeometryOptions();
Autodesk.Revit.DB.Options opts = new Autodesk.Revit.DB.Options();
opts.View = m_revitDoc.Document.ActiveView;
opts.ComputeReferences = true;
// Get geometry of the element
GeometryElement geoElement = elem.get_Geometry(opts);
InquireGeometry(geoElement, elem);
return true;
}
/// <summary>
/// Inquire an geometry element to get all face instances
/// </summary>
/// <param name="geoElement">the geometry element</param>
/// <param name="elem">the element, it provides the prefix of face name</param>
/// <returns></returns>
private bool InquireGeometry(GeometryElement geoElement, RevitElement elem)
{
if (null == geoElement || null == elem)
{
return false;
}
foreach (GeometryObject obj in geoElement)
{
if (obj is GeoInstance)
{
GeoInstance instance = (GeoInstance)obj;
InquireGeometry(instance.SymbolGeometry, elem);
}
else if (!(obj is Solid))
{
// is not Solid instance
continue;
}
// continue when obj is Solid instance
Solid solid = obj as Solid;
if (null == solid)
{
continue;
}
FaceArray faces = solid.Faces;
if (faces.IsEmpty)
{
continue;
}
// get the face name list
String category = String.Empty;
if (null != elem.Category && null != elem.Name)
{
category = elem.Category.Name;
}
int ii = 0;
foreach (Face tempFace in faces)
{
if (tempFace is PlanarFace)
{
m_faceNameList.Add(
String.Format("{0} : {1} ({2})", category, elem.Name, ii));
m_faceList.Add(tempFace);
ii++;
}
}
}
return true;
}
/// <summary>
/// Project a point on a face
/// </summary>
/// <param name="xyzArray">the face points, them fix a face </param>
/// <param name="point">the point</param>
/// <returns>the projected point on this face</returns>
static private Autodesk.Revit.DB.XYZ Project(List<XYZ> xyzArray, Autodesk.Revit.DB.XYZ point)
{
Autodesk.Revit.DB.XYZ a = xyzArray[0] - xyzArray[1];
Autodesk.Revit.DB.XYZ b = xyzArray[0] - xyzArray[2];
Autodesk.Revit.DB.XYZ c = point - xyzArray[0];
Autodesk.Revit.DB.XYZ normal = (a.CrossProduct(b));
try
{
normal = normal.Normalize();
}
catch (Exception)
{
normal = Autodesk.Revit.DB.XYZ.Zero;
}
Autodesk.Revit.DB.XYZ retProjectedPoint = point - (normal.DotProduct(c)) * normal;
return retProjectedPoint;
}
#endregion
}
}