using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.Creation;
using System.Reflection;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using System.IO;
using System.Collections;

namespace uBIMBasicCode
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    public class BasicCode
    {
        // Revit 中获取族名称
        public void GetFamilyAndTypeInfo(Element element, ref string familyName, ref string typeName, ref string familyTypeName)
        {
            if (element is FamilyInstance)
            {
                FamilyInstance instance = element as FamilyInstance;
                Element objectTypeAsElement = GetObjectTypeAsElement(instance, null);
                familyName = instance.Symbol.Family.Name;
                typeName = objectTypeAsElement.Name;
                Parameter parameter = objectTypeAsElement.get_Parameter(BuiltInParameter.SYMBOL_FAMILY_AND_TYPE_NAMES_PARAM);
                if (parameter != null)
                {
                    familyTypeName = parameter.AsString();
                }
            }
            else
            {
                Parameter parameter2 = element.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM);
                if (parameter2 != null)
                {
                    Parameter parameter3 = null;
                    ElementId elementId = parameter2.AsElementId();
                    Element element3 = GetElement(element.Document, elementId);
                    if (element3 != null)
                    {
                        parameter3 = element3.get_Parameter(BuiltInParameter.ALL_MODEL_FAMILY_NAME);
                        if (parameter3 != null)
                        {
                            familyName = parameter3.AsString();
                        }
                        parameter3 = element3.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME);
                        if (parameter3 != null)
                        {
                            typeName = parameter3.AsString();
                        }
                        if (!string.IsNullOrEmpty(typeName) && !string.IsNullOrEmpty(familyName))
                        {
                            familyTypeName = familyName + " : " + typeName;
                        }
                    }
                    else
                    {
                        try
                        {
                            parameter3 = element.get_Parameter(BuiltInParameter.ALL_MODEL_FAMILY_NAME);
                            if (parameter3 != null)
                            {
                                familyName = parameter3.AsString();
                            }
                        }
                        catch
                        {
                        }
                        try
                        {
                            parameter3 = element.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME);
                            if (parameter3 != null)
                            {
                                typeName = parameter3.AsString();
                            }
                        }
                        catch
                        {
                        }
                        try
                        {
                            if (!string.IsNullOrEmpty(typeName) && !string.IsNullOrEmpty(familyName))
                            {
                                familyTypeName = familyName + " : " + typeName;
                            }
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }
        public static Element GetObjectTypeAsElement(Element element, Autodesk.Revit.DB.Document doc = null)
        {
            try
            {
                ElementId typeId = element.GetTypeId();
                if (doc == null)
                {
                    return GetElement(element.Document, typeId);
                }
                return GetElement(element.Document, typeId);
            }
            catch
            {
            }
            return null;
        }
        public static Element GetElement(Autodesk.Revit.DB.Document oDocument, ElementId elementId)
        {
            try
            {
                return oDocument.GetElement(elementId);
            }
            catch
            {
                return null;
            }
        }

        //记录窗口信息 举例：filename = "uBIM设置"，sectionname = "拾线生MEP"，注意是control的name，不是text
        public void WriteFormSetting(System.Windows.Forms.Form form, string filename, string sectionname)
        {
            string appdatapath = Environment.GetEnvironmentVariable("LocalAppData") + "\\uBIMTools";
            if (!Directory.Exists(appdatapath))
                Directory.CreateDirectory(appdatapath);
            string sName = appdatapath + "\\" + filename + ".txt";
            List<string> string_formcontrol = new List<string>();
            string_formcontrol.Add("【" + sectionname + "】");

            List<System.Windows.Forms.Control> control_list = new List<System.Windows.Forms.Control>();

            foreach (System.Windows.Forms.Control control in form.Controls)
            {
                if (control.GetType().ToString() == "System.Windows.Forms.TabControl")
                {
                    System.Windows.Forms.TabControl tabcontrol = control as System.Windows.Forms.TabControl;
                    foreach (System.Windows.Forms.TabPage page in tabcontrol.TabPages)
                    {
                        foreach (System.Windows.Forms.Control control2 in page.Controls)
                            control_list.Add(control2);
                    }
                }
                else
                {
                    if (control.GetType().ToString() != "System.Windows.Forms.GroupBox")
                        control_list.Add(control);
                    else
                    {
                        System.Windows.Forms.GroupBox gb = control as System.Windows.Forms.GroupBox;
                        foreach (System.Windows.Forms.Control control2 in gb.Controls)
                            control_list.Add(control2);
                    }
                }
            }

            foreach (System.Windows.Forms.Control control in control_list)
            {
                if (control.GetType().ToString() == "System.Windows.Forms.Label")
                    continue;
                if (control.GetType().ToString() == "System.Windows.Forms.TextBox")
                {
                    System.Windows.Forms.TextBox tb = control as System.Windows.Forms.TextBox;
                    string_formcontrol.Add(control.Name + "=" + tb.Text);
                }
                if (control.GetType().ToString() == "System.Windows.Forms.RadioButton")
                {
                    System.Windows.Forms.RadioButton rb = control as System.Windows.Forms.RadioButton;
                    if (rb.Checked)
                        string_formcontrol.Add(control.Name + "=True");
                    else
                        string_formcontrol.Add(control.Name + "=False");
                }
                if (control.GetType().ToString() == "System.Windows.Forms.ComboBox")
                {
                    System.Windows.Forms.ComboBox cb = control as System.Windows.Forms.ComboBox;
                    string_formcontrol.Add(control.Name + "=" + cb.Text);
                }
                if (control.GetType().ToString() == "System.Windows.Forms.CheckBox")
                {
                    System.Windows.Forms.CheckBox cb = control as System.Windows.Forms.CheckBox;
                    if (cb.Checked)
                        string_formcontrol.Add(control.Name + "=True");
                    else
                        string_formcontrol.Add(control.Name + "=False");
                }
            }

            int rows_begin = -1;
            int rows_end = -1;

            if (File.Exists(sName))
            {
                string[] rows = File.ReadAllLines(sName, System.Text.Encoding.Default);
                for (int i = 0; i <= rows.Count() - 1; i++)
                {
                    try
                    {
                        if (rows[i] == "【" + sectionname + "】")
                        {
                            rows_begin = i;
                            break;
                        }
                    }
                    catch
                    { }
                }
                for (int i = rows_begin + 1; i <= rows.Count() - 1; i++)
                {
                    if (rows[i].Contains("【"))
                    {
                        rows_end = i;
                        break;
                    }
                }
                if (rows_end == -1)
                    rows_end = rows.Count();

                //分段记录
                List<string> newrow_list = new List<string>();
                for (int i = 0; i <= rows_begin - 1; i++)
                {
                    newrow_list.Add(rows[i]);
                }
                for (int i = 0; i <= string_formcontrol.Count - 1; i++)
                {
                    newrow_list.Add(string_formcontrol[i]);
                }
                for (int i = rows_end; i <= rows.Count() - 1; i++)
                {
                    newrow_list.Add(rows[i]);
                }
                //写入数组
                string[] newrows = new string[newrow_list.Count];
                for (int i = 0; i <= newrow_list.Count - 1; i++)
                {
                    newrows[i] = newrow_list[i];
                }
                File.WriteAllLines(sName, newrows, Encoding.Default);
            }
            else
            {
                //写入数组
                string[] newrows = new string[string_formcontrol.Count];
                for (int i = 0; i <= string_formcontrol.Count - 1; i++)
                {
                    newrows[i] = string_formcontrol[i];
                }
                File.WriteAllLines(sName, newrows, Encoding.Default);
            }
        }

        //读取窗口信息 举例：filename = "uBIM设置"，sectionname = "拾线生MEP"，注意是control的name，不是text
        public void ReadFormSetting(System.Windows.Forms.Form form, string filename, string sectionname)
        {
            string appdatapath = Environment.GetEnvironmentVariable("LocalAppData") + "\\uBIMTools";
            if (!Directory.Exists(appdatapath))
                Directory.CreateDirectory(appdatapath);
            //Assembly myAssembly = Assembly.GetAssembly(this.GetType());
            //string sName = myAssembly.Location;
            //sName = sName.Substring(0, sName.LastIndexOf("\\")) + "\\" + filename + ".txt";
            string sName = appdatapath + "\\" + filename + ".txt";

            List<System.Windows.Forms.Control> control_list = new List<System.Windows.Forms.Control>();
            foreach (System.Windows.Forms.Control control in form.Controls)
            {
                if (control.GetType().ToString() == "System.Windows.Forms.TabControl")
                {
                    System.Windows.Forms.TabControl tabcontrol = control as System.Windows.Forms.TabControl;
                    foreach (System.Windows.Forms.TabPage page in tabcontrol.TabPages)
                    {
                        foreach (System.Windows.Forms.Control control2 in page.Controls)
                            control_list.Add(control2);
                    }
                }
                else
                {
                    if (control.GetType().ToString() != "System.Windows.Forms.GroupBox")
                        control_list.Add(control);
                    else
                    {
                        System.Windows.Forms.GroupBox gb = control as System.Windows.Forms.GroupBox;
                        foreach (System.Windows.Forms.Control control2 in gb.Controls)
                            control_list.Add(control2);
                    }
                }
            }
            if (File.Exists(sName))
            {
                string[] rows = File.ReadAllLines(sName, System.Text.Encoding.Default);
                int begin = -1;
                for (int i = 0; i <= rows.Count() - 1; i++)
                {
                    try
                    {
                        if (rows[i] == "【" + sectionname + "】")
                        {
                            begin = i;
                            break;
                        }
                    }
                    catch
                    { }
                }
                if (begin != -1)
                {
                    for (int i = begin + 1; i <= rows.Count() - 1; i++)
                    {
                        if (rows[i].Contains("【"))
                            break;

                        foreach (System.Windows.Forms.Control control in control_list)
                        {
                            if (control.GetType().ToString() == "System.Windows.Forms.Label")
                                continue;
                            //if (control.Name != rows[i].Split('=')[0])
                            //    continue;
                            if (control.GetType().ToString() == "System.Windows.Forms.TextBox" && control.Name == rows[i].Split('=')[0])
                            {
                                System.Windows.Forms.TextBox tb = control as System.Windows.Forms.TextBox;
                                try
                                {
                                    tb.Text = rows[i].Split('=')[1];
                                }
                                catch { }
                            }
                            if (control.GetType().ToString() == "System.Windows.Forms.RadioButton" && control.Name == rows[i].Split('=')[0])
                            {
                                System.Windows.Forms.RadioButton rb = control as System.Windows.Forms.RadioButton;
                                try
                                {
                                    if (rows[i].Split('=')[1] == "True")
                                        rb.Checked = true;
                                    else
                                        rb.Checked = false;
                                }
                                catch { }
                            }
                            if (control.GetType().ToString() == "System.Windows.Forms.ComboBox" && control.Name == rows[i].Split('=')[0])
                            {
                                System.Windows.Forms.ComboBox cb = control as System.Windows.Forms.ComboBox;
                                try
                                {
                                    int index = cb.FindString(rows[i].Split('=')[1]);
                                    cb.SelectedIndex = index;
                                }
                                catch
                                { }
                            }
                            if (control.GetType().ToString() == "System.Windows.Forms.CheckBox" && control.Name == rows[i].Split('=')[0])
                            {
                                System.Windows.Forms.CheckBox cb = control as System.Windows.Forms.CheckBox;
                                try
                                {
                                    if (rows[i].Split('=')[1] == "True")
                                        cb.Checked = true;
                                    else
                                        cb.Checked = false;
                                }
                                catch { }
                            }
                        }
                    }
                }
            }
        }

        //判断是否有物体表面经过点
        public Boolean Something_Cross_Point(Autodesk.Revit.DB.Document doc, XYZ checkpoint, double tor)
        {
            Outline myOutLn = new Outline(checkpoint - new XYZ(tor, tor, tor), checkpoint + new XYZ(tor, tor, tor));
            BoundingBoxIntersectsFilter filter = new BoundingBoxIntersectsFilter(myOutLn);
            IList<Element> intersect_elements = (new FilteredElementCollector(doc)).WherePasses(filter).ToElements();
            if (intersect_elements.Count > 0)
            {
                foreach (Element e in intersect_elements)
                {
                    IList<Face> face_list = AllFace_Of_Element(e, ViewDetailLevel.Fine);
                    foreach (Face f in face_list)
                    {
                        if (Distance_Point_To_Face(f, checkpoint) < tor / 10)
                            return true;
                    }
                }
            }
            return false;
        }

        //对double取整到小数点后2位
        public double doubleround(double a)
        {
            double b = Math.Round(a * 304.8, 0) / 304.8;
            return b;
        }

        //求family
        public Family fm_by_name(Autodesk.Revit.UI.ExternalCommandData CommandData, string name)
        {
            Family fm = null;
            IList<Element> familylist = (new FilteredElementCollector(CommandData.Application.ActiveUIDocument.Document)).OfClass(typeof(Family)).ToElements();
            foreach (Element e in familylist)
            {
                Family tmp = e as Family;
                if (tmp.Name == name)
                {
                    fm = tmp;
                    break;
                }
            }
            return fm;
        }

        //求familysymbol
        public FamilySymbol fs_by_name(Autodesk.Revit.UI.ExternalCommandData CommandData, string name, Family fm)
        {
            FamilySymbol fs = null;
            foreach (ElementId eid in fm.GetFamilySymbolIds())
            {
                FamilySymbol tmp = CommandData.Application.ActiveUIDocument.Document.GetElement(eid) as FamilySymbol;
                if (tmp.Name == name)
                {
                    fs = tmp;
                    break;
                }
            }
            return fs;
        }

        //求b点相对于a点的角度（从aX转到ab的角度），从0到360。
        public double Angle_AX_to_AB(XYZ a, XYZ b)
        {
            Double angle = 0;
            if (a.X == b.X)
            {
                if (a.Y > b.Y)
                    angle = 270;
                else
                    angle = 90;
            }
            if (a.Y == b.Y)
            {
                if (a.X > b.X)
                    angle = 180;
                else
                    angle = 0;
            }
            if (a.X != b.X && a.Y != b.Y)
            {
                double atan = Math.Atan((b.Y - a.Y) / (b.X - a.X)) * 180 / Math.PI;
                if (b.X > a.X && b.Y > a.Y)
                    angle = atan;
                if (b.X < a.X)
                    angle = atan + 180;
                if (b.X > a.X && b.Y < a.Y)
                    angle = atan + 360;
            }
            return angle;
        }

        //求圆弧中点
        public XYZ Midpoint_Of_Arc(XYZ p1, XYZ p2, XYZ cen)
        {
            double r = p1.DistanceTo(cen);
            double a = Math.Acos((p1.X - cen.X) / r);
            double b = Math.Acos((p2.X - cen.X) / r);
            XYZ m = cen + new XYZ(Math.Cos((a + b) / 2) * r, Math.Sin((a + b) / 2) * r, (p1.Z + p2.Z) / 2 - cen.Z);
            return m;
        }

        // 求线段p1p2与线段p3p4的平面交点坐标（其中包含根据已知两点坐标，求过这两点的直线解析方程： a*x+b*y+c = 0  (a >= 0)  ）
        public XYZ IntersectPoint_Of_Curves(XYZ p1, XYZ p2, XYZ p3, XYZ p4)
        {
            Double sign = 1;
            Double a1 = p2.Y - p1.Y;
            if (p2.Y - p1.Y < 0)
            {
                sign = -1;
                a1 = sign * (p2.Y - p1.Y);
            }
            Double b1 = sign * (p1.X - p2.X);
            Double c1 = sign * (p1.Y * p2.X - p1.X * p2.Y);

            Double sign2 = 1;
            Double a2 = p4.Y - p3.Y;
            if (p4.Y - p3.Y < 0)
            {
                sign2 = -1;
                a2 = sign2 * (p4.Y - p3.Y);
            }
            Double b2 = sign2 * (p3.X - p4.X);
            Double c2 = sign2 * (p3.Y * p4.X - p3.X * p4.Y);
            double d = a1 * b2 - b1 * a2;

            if (Math.Abs(d) < 0.001) // 不相交
                return null;
            XYZ insect = new XYZ((c2 * b1 - c1 * b2) / d, (a2 * c1 - a1 * c2) / d, 0);
            XYZ p1_tmp = new XYZ(p1.X, p1.Y, 0);
            XYZ p2_tmp = new XYZ(p2.X, p2.Y, 0);
            XYZ p3_tmp = new XYZ(p3.X, p3.Y, 0);
            XYZ p4_tmp = new XYZ(p4.X, p4.Y, 0);
            if (Math.Abs(p1_tmp.DistanceTo(insect) + p2_tmp.DistanceTo(insect) - p1_tmp.DistanceTo(p2_tmp)) > 0.01)
                return null;
            if (Math.Abs(p3_tmp.DistanceTo(insect) + p4_tmp.DistanceTo(insect) - p3_tmp.DistanceTo(p4_tmp)) > 0.01)
                return null;
            return insect;
        }

        // 求线段C1与线段C2的平面交点坐标（不一定在线段内，可能是延伸交点）
        public XYZ IntersectPoint_Of_ExtendCurves(Curve curve1, Curve curve2)
        {
            XYZ p1 = curve1.GetEndPoint(0);
            XYZ p2 = curve1.GetEndPoint(1);
            XYZ p3 = curve2.GetEndPoint(0);
            XYZ p4 = curve2.GetEndPoint(1);
            Double sign = 1;
            Double a1 = p2.Y - p1.Y;
            if (p2.Y - p1.Y < 0)
            {
                sign = -1;
                a1 = sign * (p2.Y - p1.Y);
            }
            Double b1 = sign * (p1.X - p2.X);
            Double c1 = sign * (p1.Y * p2.X - p1.X * p2.Y);

            Double sign2 = 1;
            Double a2 = p4.Y - p3.Y;
            if (p4.Y - p3.Y < 0)
            {
                sign2 = -1;
                a2 = sign2 * (p4.Y - p3.Y);
            }
            Double b2 = sign2 * (p3.X - p4.X);
            Double c2 = sign2 * (p3.Y * p4.X - p3.X * p4.Y);
            double d = a1 * b2 - b1 * a2;

            if (Math.Abs(d) < 0.001) // 不相交
                return null;
            XYZ insect = new XYZ((c2 * b1 - c1 * b2) / d, (a2 * c1 - a1 * c2) / d, p1.Z);
            return insect;
        }

        //求构件分类名称
        public string CategoryOrType_name(Element e)
        {
            string str = e.GetType().Name;
            try
            {
                str = e.Category.Name;

            }
            catch
            {
                if (e.GetType().Name == "Element")
                    str = "其他";
            }
            return str;
        }

        //求楼板底面
        public Face Bottomface_Of_Floor(ExternalCommandData CommandData, Floor floor)
        {
            Face face = null;
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Options options = Revit.Create.NewGeometryOptions();
            options.ComputeReferences = true;
            GeometryElement geoElement_floor = floor.get_Geometry(options);
            Solid solid_floor = null;
            IEnumerator enumerator = geoElement_floor.GetEnumerator();
            {
                while (enumerator.MoveNext())
                {
                    GeometryObject geoObj = enumerator.Current as GeometryObject;
                    if (geoObj is Solid)
                        solid_floor = geoObj as Solid;
                    if (solid_floor == null)
                        continue;
                    if (solid_floor.Faces.Size <= 1)
                        continue;
                    foreach (Face facetmp in solid_floor.Faces)
                    {
                        XYZ normal = facetmp.ComputeNormal(new UV(0, 0));
                        if (Math.Abs(normal.Z + 1) < 0.01)  //求板底面
                            face = facetmp;
                    }
                }
            }
            return face;
        }

        //求楼板顶面
        public Face Topface_Of_Floor(ExternalCommandData CommandData, Floor floor)
        {
            Face face = null;
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Options options = Revit.Create.NewGeometryOptions();
            options.ComputeReferences = true;
            GeometryElement geoElement_floor = floor.get_Geometry(options);
            Solid solid_floor = null;
            IEnumerator enumerator = geoElement_floor.GetEnumerator();
            {
                while (enumerator.MoveNext())
                {
                    GeometryObject geoObj = enumerator.Current as GeometryObject;
                    if (geoObj is Solid)
                        solid_floor = geoObj as Solid;
                    if (solid_floor == null)
                        continue;
                    if (solid_floor.Faces.Size <= 1)
                        continue;
                    foreach (Face facetmp in solid_floor.Faces)
                    {
                        XYZ normal = facetmp.ComputeNormal(new UV(0, 0));
                        if (Math.Abs(normal.Z - 1) < 0.01)  //求板顶面
                            face = facetmp;
                    }
                }
            }
            return face;
        }

        //求梁的基础数据（长，宽，高，梁定位线）梁定位线为边1→1；边2→-1；居中→0
        public List<Double> Beam_Data_Origin(Autodesk.Revit.UI.ExternalCommandData CommandData, FamilyInstance beam)
        {
            List<Double> bdata_origin = new List<double>();
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            if (beam.StructuralType != Autodesk.Revit.DB.Structure.StructuralType.Beam)
                return null;
            LocationCurve lc = beam.Location as LocationCurve;
            GeometryElement geoElement_beam_origin = beam.GetOriginalGeometry(Revit.Create.NewGeometryOptions());
            BoundingBoxXYZ bb = geoElement_beam_origin.GetBoundingBox();
            Double lenth = bb.Max.X - bb.Min.X;
            Double width = bb.Max.Y - bb.Min.Y;
            Double height = bb.Max.Z - bb.Min.Z;
            Double p = 0;
            if (beam.get_Parameter(BuiltInParameter.BEAM_H_JUSTIFICATION).AsInteger() == 1)
                p = 1;
            if (beam.get_Parameter(BuiltInParameter.BEAM_H_JUSTIFICATION).AsInteger() == 2)
                p = -1;
            bdata_origin.Add(lenth);
            bdata_origin.Add(width);
            bdata_origin.Add(height);
            bdata_origin.Add(p);
            return bdata_origin;
        }

        //求梁面中心线（for梁定位线忽左忽右忽中）
        public Line Beam_Eenterline(ExternalCommandData CommandData, FamilyInstance beam)
        {
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            if (beam.StructuralType != Autodesk.Revit.DB.Structure.StructuralType.Beam)
                return null;
            Double p = 0;
            if (beam.get_Parameter(BuiltInParameter.BEAM_H_JUSTIFICATION).AsInteger() == 1)
                p = 1;
            if (beam.get_Parameter(BuiltInParameter.BEAM_H_JUSTIFICATION).AsInteger() == 2)
                p = -1;
            LocationCurve lc = beam.Location as LocationCurve;
            XYZ start = lc.Curve.GetEndPoint(0);
            XYZ end = lc.Curve.GetEndPoint(1);
            XYZ direction0 = end - start;
            Double dd0 = end.DistanceTo(start);
            Double beamwidth = Beam_Data_Origin(CommandData, beam)[1];
            start = start + beamwidth / 2 * (new XYZ(-direction0.Y / dd0, direction0.X / dd0, 0)) * p;
            end = end + beamwidth / 2 * (new XYZ(-direction0.Y / dd0, direction0.X / dd0, 0)) * p;
            Line line = Line.CreateBound(start, end);
            return line;
        }

        //求族实例旋转角度（弧度）
        public double RotateAngle_Familyinstance(FamilyInstance fi)
        {
            Transform trans = fi.GetTransform();
            double ang = Math.Atan(trans.BasisX.Y / trans.BasisX.X);
            return ang;
        }

        //求族实例的在位boundingbox平面四角点（已旋转）（左下，右下，左上，右上）Z坐标按最低点————————不对，求出来的边界包含族里面的参照线
        public List<XYZ> Points_Of_FI_Boundingbox(ExternalCommandData CommandData, FamilyInstance fi)
        {
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Transform tf = fi.GetTransform();
            GeometryElement geoElement_origin = fi.GetOriginalGeometry(Revit.Create.NewGeometryOptions());
            if (geoElement_origin == null)
                return null;
            BoundingBoxXYZ bb = geoElement_origin.GetBoundingBox();
            XYZ p1 = bb.Min;  //左下
            XYZ p4 = new XYZ(bb.Max.X, bb.Max.Y, p1.Z);  //右上
            XYZ p2 = new XYZ(p4.X, p1.Y, p1.Z);     //右下
            XYZ p3 = new XYZ(p1.X, p4.Y, p1.Z);     //左上
            List<XYZ> point_list = new List<XYZ>();
            point_list.Add(tf.OfPoint(p1));
            point_list.Add(tf.OfPoint(p2));
            point_list.Add(tf.OfPoint(p3));
            point_list.Add(tf.OfPoint(p4));
            return point_list;
        }

        //求点面距离（≥0）
        public double Distance_Point_To_Face(Face face, XYZ p)
        {
            Transform tran = Transform.Identity;
            tran.Origin = face.Evaluate(new UV(0, 0));
            tran.BasisX = face.Evaluate(new UV(1, 0)) - face.Evaluate(new UV(0, 0));
            tran.BasisY = face.Evaluate(new UV(0, 1)) - face.Evaluate(new UV(0, 0));
            tran.BasisZ = face.ComputeNormal(new UV(0, 0));
            double b = Math.Abs(tran.Inverse.OfPoint(p).Z);   //线面的垂直距离 
            return b;
        }

        //求点到面的z坐标（不一定≥0）
        public double ZFDistance_Point_To_Face(Face face, XYZ p)
        {
            Transform tran = null;
            tran = Transform.Identity;
            tran.Origin = face.Evaluate(new UV(0, 0));
            tran.BasisX = face.Evaluate(new UV(1, 0)) - face.Evaluate(new UV(0, 0));
            tran.BasisY = face.Evaluate(new UV(0, 1)) - face.Evaluate(new UV(0, 0));
            tran.BasisZ = face.ComputeNormal(new UV(0, 0));
            double b = tran.Inverse.OfPoint(p).Z;
            return b;
        }

        //求点在面上的UV坐标（不管点是否在面上）
        public UV UV_On_Face(Face face, XYZ p)
        {
            Transform tran = null;
            tran = Transform.Identity;
            tran.Origin = face.Evaluate(new UV(0, 0));
            tran.BasisX = face.Evaluate(new UV(1, 0)) - face.Evaluate(new UV(0, 0));
            tran.BasisY = face.Evaluate(new UV(0, 1)) - face.Evaluate(new UV(0, 0));
            tran.BasisZ = face.ComputeNormal(new UV(0, 0));
            double x = tran.Inverse.OfPoint(p).X;
            double y = tran.Inverse.OfPoint(p).Y;
            UV uv = new UV(x, y);
            return uv;
        }

        //判断三点顺逆时针（仅考虑水平面）
        public int Clockwise(XYZ p1, XYZ p2, XYZ p3)
        {
            int k = 1;
            double d = (p2.X - p1.X) * (p3.Y - p2.Y) - (p2.Y - p1.Y) * (p3.X - p2.X);
            if (Math.Abs(d) < 0.000001)
                k = 0;
            else if (d < 0)  //顺时针
                k = -1;
            return k;
        }

        //将点按顺序插入点列（首尾不变，需保证新点位于原两端点之间），距离tor以内忽略
        public List<XYZ> Insert_Point_Into_Pointlist(List<XYZ> pointlist, XYZ newpoint, double tor)
        {
            XYZ p0 = pointlist[0];
            XYZ plast = pointlist[pointlist.Count - 1];
            if (newpoint.DistanceTo(p0) < 0.01)
                return pointlist;
            if (newpoint.DistanceTo(plast) < 0.01)
                return pointlist;
            if (newpoint.DistanceTo(p0) > p0.DistanceTo(plast) || newpoint.DistanceTo(plast) > p0.DistanceTo(plast))
                return pointlist;
            for (int i = 1; i <= pointlist.Count - 1; i++)
            {
                XYZ pi = pointlist[i];
                if (newpoint.DistanceTo(pi) < tor)
                    return pointlist;
                if (pi.DistanceTo(p0) > newpoint.DistanceTo(pointlist[0]))
                {
                    pointlist.Insert(i, newpoint);
                    break;
                }
            }
            return pointlist;
        }

        //求点集里点的索引
        public int Index_Of_Pointlist(List<XYZ> pointlist, XYZ p)
        {
            int index = -1;
            for (int k = 0; k <= pointlist.Count - 1; k++)
            {
                if (pointlist[k].DistanceTo(p) < 0.01)
                {
                    index = k;
                    break;
                }
            }
            return index;
        }

        //curvelist偏移 任意段从起点往左偏移
        public List<Curve> Curvelist_Offset(Autodesk.Revit.UI.ExternalCommandData CommandData, IList<Curve> curvelist, List<double> distance_list)
        {
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            List<Curve> cl_offset = new List<Curve>();
            for (int n = 0; n <= curvelist.Count - 1; n++)
            {
                Curve c = curvelist[n];
                XYZ start = c.GetEndPoint(0);
                XYZ end = c.GetEndPoint(1);
                XYZ delta1 = end - start;
                XYZ delta2 = start - end;
                XYZ start_new = new XYZ(-delta1.Y, delta1.X, 0) * distance_list[n] / c.Length + start;
                XYZ end_new = new XYZ(delta2.Y, -delta2.X, 0) * distance_list[n] / c.Length + end;
                Curve c_offset = Line.CreateBound(start_new, end_new);
                if (c_offset == null)
                    return null;
                cl_offset.Add(c_offset);
            }
            List<Curve> cl_new = new List<Curve>();
            for (int n = 0; n <= cl_offset.Count - 1; n++)
            {
                Curve c1 = cl_offset[n];
                Curve c2 = cl_offset[0];
                Curve c3 = cl_offset[cl_offset.Count - 1];
                if (n < cl_offset.Count - 1)
                    c2 = cl_offset[n + 1];
                if (n > 0)
                    c3 = cl_offset[n - 1];
                XYZ p1 = IntersectPoint_Of_ExtendCurves(c1, c3);
                XYZ p2 = IntersectPoint_Of_ExtendCurves(c1, c2);
                if (p1 == null)
                    p1 = c1.GetEndPoint(0);

                if (p2 == null)
                    p2 = c1.GetEndPoint(1);
                //if (p1 == null || p2 == null)
                //    continue;
                if (p1.DistanceTo(p2) < 0.001)
                    return cl_new;
                Curve c_new = Line.CreateBound(p1, p2);
                cl_new.Add(c_new);
            }
            return cl_new;
        }

        //求点B绕点A逆时针转90°后的坐标
        public XYZ Rotate90_Around_XYZ(XYZ b, XYZ a)
        {
            XYZ delta = b - a;
            XYZ end = new XYZ(-delta.Y, delta.X, 0) + a;
            return end;
        }

        //求点B绕点A顺时针转90°后的坐标
        public XYZ AntiRotate90_Around_XYZ(XYZ b, XYZ a)
        {
            XYZ delta = b - a;
            XYZ end = new XYZ(delta.Y, -delta.X, 0) + a;
            return end;
        }

        //两条线的交点
        public XYZ IntersectPointOfTowCurve(Curve curve1, Curve curve2)
        {
            XYZ intersectionResult = null;
            IntersectionResultArray result = new IntersectionResultArray();
            SetComparisonResult comparisonR;
            comparisonR = curve1.Intersect(curve2, out result);
            if (SetComparisonResult.Disjoint != comparisonR)
            {
                if (!result.IsEmpty)
                    intersectionResult = result.get_Item(0).XYZPoint;
            }
            return intersectionResult;
        }

        //求当前层上面的那一层(1米以内的忽略，最顶层的即为自己)
        public Level Level_Above_Level(Autodesk.Revit.DB.Document doc, Level level1)
        {
            Level level2 = level1;
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            collector.OfClass(typeof(Level));
            FilteredElementIterator iterator = collector.GetElementIterator();
            int yy = 0; //0为最上一层
            while (iterator.MoveNext())
            {
                Level levelit = iterator.Current as Level;
                if ((levelit.Elevation - level1.Elevation) > 999 / 304.8)
                {
                    level2 = levelit;
                    yy = 1;
                    break;
                }
            }
            if (yy == 1)
            {
                iterator.Reset();
                while (iterator.MoveNext())
                {
                    Level levelit = iterator.Current as Level;
                    if ((levelit.Elevation - level1.Elevation) > 999 / 304.8 && (level2.Elevation - levelit.Elevation) > 999 / 304.8)
                        level2 = levelit;
                }
            }
            if (yy == 0)
                level2 = level1;
            return level2;
        }

        //求平面视图中点附近的管道(点的z坐标未知)
        public List<Pipe> PipeList_NearPoint_IgnorZ(Autodesk.Revit.DB.Document doc, Level l, XYZ p, Double tor)
        {
            List<Pipe> pipe_list = new List<Pipe>();
            double lz = Level_Above_Level(doc, l).Elevation;
            if (Level_Above_Level(doc, l).Id.IntegerValue == l.Id.IntegerValue)
                lz += 10000 / 304.8;    //最上层，按10米范围计算
            XYZ max = new XYZ(p.X + tor, p.Y + tor, lz);
            XYZ min = new XYZ(p.X - tor, p.Y - tor, l.Elevation);
            Outline myOutLn = new Outline(min, max);
            BoundingBoxIntersectsFilter boxfilter = new BoundingBoxIntersectsFilter(myOutLn);
            ElementClassFilter pipeClassfilter = new ElementClassFilter(typeof(Pipe));
            LogicalAndFilter Filter = new LogicalAndFilter(boxfilter, pipeClassfilter);
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            IList<Element> pipeset = collector.WherePasses(Filter).ToElements();

            foreach (Element e in pipeset)
            {
                try
                {
                    double outersize = 0;
                    Pipe pp = e as Pipe;
                    PipeType pipetype = pp.PipeType;
                    RoutingPreferenceRule rule_temp = pipetype.RoutingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Segments, 0);
                    Segment ss = doc.GetElement(rule_temp.MEPPartId) as Segment;
                    Double insulationsize = pp.get_Parameter(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS).AsDouble();
                    for (int ii = 0; ii < ss.GetSizes().Count; ii++)
                    {
                        if (ss.GetSizes().ElementAt(ii).NominalDiameter == pp.Diameter)
                            outersize = ss.GetSizes().ElementAt(ii).OuterDiameter;
                    }
                    LocationCurve lc = (e as Pipe).Location as LocationCurve;
                    XYZ projectpoint = lc.Curve.Project(p).XYZPoint;
                    XYZ pz = new XYZ(p.X, p.Y, projectpoint.Z);
                    if (pz.DistanceTo(projectpoint) <= (outersize + insulationsize) * 0.5 + tor)
                        pipe_list.Add(e as Pipe);
                }
                catch
                { }
            }
            return pipe_list;
        }

        //求平面视图中点附近的风管(点的z坐标未知)，tor以内，求距离最近的那根
        public Duct Duct_NearPoint_IgnorZ(Autodesk.Revit.DB.Document doc, Level l, XYZ p, Double tor)
        {
            Duct duct = null;
            double lz = Level_Above_Level(doc, l).Elevation;
            if (Level_Above_Level(doc, l).Id.IntegerValue == l.Id.IntegerValue)
                lz += 10000 / 304.8;    //最上层，按10米范围计算
            XYZ max = new XYZ(p.X + tor, p.Y + tor, lz);
            XYZ min = new XYZ(p.X - tor, p.Y - tor, l.Elevation);
            Outline myOutLn = new Outline(min, max);
            BoundingBoxIntersectsFilter boxfilter = new BoundingBoxIntersectsFilter(myOutLn);
            ElementClassFilter ductClassfilter = new ElementClassFilter(typeof(Duct));
            LogicalAndFilter Filter = new LogicalAndFilter(boxfilter, ductClassfilter);
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            IList<Element> ductset = collector.WherePasses(Filter).ToElements();
            double min_distance = tor * 2;
            foreach (Element e in ductset)
            {
                try
                {
                    Duct ducttmp = e as Duct;
                    LocationCurve lc = ducttmp.Location as LocationCurve;
                    XYZ projectpoint = lc.Curve.Project(p).XYZPoint;
                    XYZ pz = new XYZ(p.X, p.Y, projectpoint.Z);
                    if (pz.DistanceTo(projectpoint) > ducttmp.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).AsDouble() * 0.5 + tor)
                        continue;
                    if (pz.DistanceTo(projectpoint) <= min_distance)
                    {
                        min_distance = pz.DistanceTo(projectpoint);
                        duct = ducttmp;
                    }
                }
                catch
                { }
            }
            return duct;
        }

        //求点附近的风管
        public List<Duct> DuctList_NearPoint(Autodesk.Revit.DB.Document doc, XYZ p, Double tolerance)
        {
            List<Duct> ductlist = new List<Duct>();
            XYZ max = new XYZ(p.X + tolerance, p.Y + tolerance, p.Z + tolerance);
            XYZ min = new XYZ(p.X - tolerance, p.Y - tolerance, p.Z - tolerance);
            Outline myOutLn = new Outline(min, max);
            BoundingBoxIntersectsFilter boxfilter = new BoundingBoxIntersectsFilter(myOutLn);
            ElementClassFilter ductClassfilter = new ElementClassFilter(typeof(Duct));
            LogicalAndFilter Filter = new LogicalAndFilter(boxfilter, ductClassfilter);
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            IList<Element> ductset = collector.WherePasses(Filter).ToElements();
            foreach (Element e in ductset)
            {
                ductlist.Add(e as Duct);
            }

            return ductlist;
        }

        //求点附近的管道(考虑点的z坐标)
        public List<Pipe> PipeList_NearPoint(Autodesk.Revit.DB.Document doc, XYZ p, Double tolerance)
        {
            List<Pipe> pipelist = new List<Pipe>();
            XYZ max = new XYZ(p.X + tolerance, p.Y + tolerance, p.Z + tolerance);
            XYZ min = new XYZ(p.X - tolerance, p.Y - tolerance, p.Z - tolerance);
            Outline myOutLn = new Outline(min, max);
            BoundingBoxIntersectsFilter boxfilter = new BoundingBoxIntersectsFilter(myOutLn);
            ElementClassFilter pipeClassfilter = new ElementClassFilter(typeof(Pipe));
            LogicalAndFilter Filter = new LogicalAndFilter(boxfilter, pipeClassfilter);
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            IList<Element> pipeset = collector.WherePasses(Filter).ToElements();
            foreach (Element e in pipeset)
            {
                pipelist.Add(e as Pipe);
            }
            return pipelist;
        }

        //求点附近的桥架
        public List<CableTray> CableList_NearPoint(Autodesk.Revit.DB.Document doc, XYZ p, Double tolerance)
        {
            List<CableTray> cablelist = new List<CableTray>();
            XYZ max = new XYZ(p.X + tolerance, p.Y + tolerance, p.Z + tolerance);
            XYZ min = new XYZ(p.X - tolerance, p.Y - tolerance, p.Z - tolerance);
            Outline myOutLn = new Outline(min, max);
            BoundingBoxIntersectsFilter boxfilter = new BoundingBoxIntersectsFilter(myOutLn);
            ElementClassFilter cableClassfilter = new ElementClassFilter(typeof(CableTray));
            LogicalAndFilter Filter = new LogicalAndFilter(boxfilter, cableClassfilter);
            IList<Element> cableset = new FilteredElementCollector(doc).WherePasses(Filter).ToElements();
            foreach (Element e in cableset)
            {
                cablelist.Add(e as CableTray);
            }
            return cablelist;
        }


        //求靠近点p的管道某端connector
        public Connector PipeConnector_Near_Point(Pipe pipe, XYZ p)
        {
            Connector c = null;
            LocationCurve lc = pipe.Location as LocationCurve;
            double d = Math.Min(p.DistanceTo(lc.Curve.GetEndPoint(0)), p.DistanceTo(lc.Curve.GetEndPoint(1)));
            ConnectorSetIterator csi = pipe.ConnectorManager.Connectors.ForwardIterator();
            while (csi.MoveNext())
            {
                Connector contmp = csi.Current as Connector;
                if (Math.Abs(contmp.Origin.DistanceTo(p) - d) < 0.1)
                    c = contmp;
            }
            return c;
        }

        //求靠近点p的管道某端connector
        public Connector DuctConnector_Near_Point(Duct duct, XYZ p)
        {
            Connector c = null;
            LocationCurve lc = duct.Location as LocationCurve;
            double d = Math.Min(p.DistanceTo(lc.Curve.GetEndPoint(0)), p.DistanceTo(lc.Curve.GetEndPoint(1)));
            ConnectorSetIterator csi = duct.ConnectorManager.Connectors.ForwardIterator();
            while (csi.MoveNext())
            {
                Connector contmp = csi.Current as Connector;
                if (Math.Abs(contmp.Origin.DistanceTo(p) - d) < 0.1)
                    c = contmp;
            }
            return c;
        }

        //取得与管件fm直接连接的管件集合
        public ElementSet Fm_LinkToFm_Set(FamilyInstance fm)
        {
            ElementSet fmlinkset = new ElementSet();
            ConnectorSetIterator csi = fm.MEPModel.ConnectorManager.Connectors.ForwardIterator();
            while (csi.MoveNext())
            {
                ConnectorSet connectorSet = (csi.Current as Connector).AllRefs;
                foreach (Connector ctmp in connectorSet)
                {
                    if (ctmp.Owner == null)
                        continue;
                    if (fmlinkset.Contains(ctmp.Owner) || ctmp.Owner.GetType().Name != "FamilyInstance")
                        continue;
                    if ((ctmp.Owner as FamilyInstance).Symbol.Family.FamilyCategory.Name == "管件")
                        fmlinkset.Insert(ctmp.Owner);
                }
            }
            return fmlinkset;
        }

        //取得与管件fm直接或间接连接的所有管件集合
        public ElementSet AllFm_LinkToFm_Set(FamilyInstance fm)
        {
            ElementSet fmset = Fm_LinkToFm_Set(fm);
            int cal = fmset.Size;
            while (cal < 100)
            {
                ElementSet add = new ElementSet();
                foreach (Element e in fmset)
                {
                    FamilyInstance fitmp = e as FamilyInstance;
                    ElementSet fmsettmp = Fm_LinkToFm_Set(fitmp);
                    foreach (Element ee in fmsettmp)
                    {
                        if (!fmset.Contains(ee))
                            add.Insert(ee);
                    }
                }
                if (add.Size == 0)
                    break;
                foreach (Element e in add)
                    fmset.Insert(e);
            }

            return fmset;
        }

        //取得与管件fm直接连接的管道集合
        public ElementSet Pipe_LinkToFm_Set(FamilyInstance fm)
        {
            ElementSet pipelinkset = new ElementSet();
            ConnectorSetIterator csi = fm.MEPModel.ConnectorManager.Connectors.ForwardIterator();
            while (csi.MoveNext())
            {
                ConnectorSet connectorSet = (csi.Current as Connector).AllRefs;
                foreach (Connector ctmp in connectorSet)
                {
                    if (ctmp.Owner == null)
                        continue;
                    if (ctmp.Owner.GetType().Name == "Pipe" && !pipelinkset.Contains(ctmp.Owner))
                        pipelinkset.Insert(ctmp.Owner);
                    //if (ctmp.ConnectorType == ConnectorType.Logical)   //连向系统（很奇怪），用AllRefs找不到管，先另想办法
                }
            }
            return pipelinkset;
        }

        //取得与管件fm直接或间接连接的管道集合
        public ElementSet AllPipe_LinkToFm_Set(FamilyInstance fm)
        {
            ElementSet allpipelinkset = Pipe_LinkToFm_Set(fm);  //直接连接的管道
            ElementSet fmlinkset = Fm_LinkToFm_Set(fm);         //直接连接的管件
            foreach (Element e in fmlinkset)
            {
                FamilyInstance fm_tmp = e as FamilyInstance;
                foreach (Element e2 in Fm_LinkToFm_Set(fm_tmp))
                {
                    if (!fmlinkset.Contains(e2))
                        fmlinkset.Insert(e2);
                }
            }
            foreach (Element e in fmlinkset)
            {
                FamilyInstance fm_tmp = e as FamilyInstance;
                foreach (Element e2 in Pipe_LinkToFm_Set(fm_tmp))
                {
                    if (!allpipelinkset.Contains(e2))
                        allpipelinkset.Insert(e2);
                }
            }
            return allpipelinkset;
        }

        //取得管道某端所连接的管件集合
        public ElementSet FamilyInstance_LinkSet(Pipe p, int i)
        {
            ElementSet filinkset = new ElementSet();
            ConnectorSetIterator csi = p.ConnectorManager.Connectors.ForwardIterator();
            while (csi.MoveNext())
            {
                LocationCurve lc = p.Location as LocationCurve;
                if ((csi.Current as Connector).Origin.DistanceTo(lc.Curve.GetEndPoint(i)) > 0.05)
                    continue;
                ConnectorSet connectorSet = (csi.Current as Connector).AllRefs;    //csi.Current as Connector为所需的管端connector
                foreach (Connector cc in connectorSet)    //cc.owner为管件
                {
                    if (cc.Owner == null)
                        continue;
                    if (cc.Owner is FamilyInstance)
                    {
                        FamilyInstance fm = cc.Owner as FamilyInstance;
                        if (fm == null)
                            continue;
                        if (fm.Symbol.Family.FamilyCategory.Name != "管件")
                            continue;
                        filinkset.Insert(fm);
                        foreach (Element e in AllFm_LinkToFm_Set(fm))
                        {
                            if (!filinkset.Contains(e))
                                filinkset.Insert(e);
                        }
                    }
                }
            }
            return filinkset;
        }

        //取得管道某端所连接的管道集合
        public ElementSet PipeLinkSet(Pipe p, int i)
        {
            ElementSet pipelinkset = new ElementSet();
            ConnectorSetIterator csi = p.ConnectorManager.Connectors.ForwardIterator();
            while (csi.MoveNext())
            {
                LocationCurve lc = p.Location as LocationCurve;
                if ((csi.Current as Connector).Origin.DistanceTo(lc.Curve.GetEndPoint(i)) > 0.05)
                    continue;
                ConnectorSet connectorSet = (csi.Current as Connector).AllRefs;    //csi.Current as Connector为所需的管端connector
                foreach (Connector cc in connectorSet)    //cc.owner为管件
                {
                    if (cc.Owner == null)
                        continue;
                    if (cc.Owner is Pipe)
                    {
                        Pipe pipe = cc.Owner as Pipe;
                        if (pipe.Id == p.Id)
                            continue;
                        if (pipe != null)
                            pipelinkset.Insert(pipe);
                    }
                    if (cc.Owner is FamilyInstance)
                    {
                        FamilyInstance fm = cc.Owner as FamilyInstance;
                        if (fm == null)
                            continue;
                        if (fm.Symbol.Family.FamilyCategory.Name != "管件")
                            continue;
                        foreach (Element e in AllPipe_LinkToFm_Set(fm))
                        {
                            if (e.Id != p.Id && !pipelinkset.Contains(e))
                                pipelinkset.Insert(e);
                        }
                    }
                }
            }
            return pipelinkset;
        }

        //与Connector c相连的Connector集合，自己除外，管道系统等东西除外
        public List<Connector> Connectors_To_Connector(Connector c)
        {
            List<Connector> connectorRefs = new List<Connector>();
            foreach (Connector cc in c.AllRefs)
            {
                if (cc.Owner == null)
                    continue;
                if (cc.Owner is FamilyInstance)
                {
                    FamilyInstance fm = cc.Owner as FamilyInstance;
                    if (fm == null)
                        continue;
                    if (fm.Symbol.Family.FamilyCategory.Name != "管件")
                        continue;
                    connectorRefs.Add(cc);
                }
                if (cc.Owner is Pipe)
                {
                    if (c.Owner.Id.IntegerValue == cc.Owner.Id.IntegerValue)
                        continue;
                    connectorRefs.Add(cc);
                }
            }
            return connectorRefs;
        }

        //求doc里有没有加载族family。
        public Boolean BooleanFamily(Autodesk.Revit.DB.Document doc, string familyname)
        {
            int zz = 0;
            FamilySymbol familySymbol = null;
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            ICollection<Element> collection = collector.OfClass(typeof(FamilySymbol)).ToElements();
            foreach (Element e in collection)
            {
                familySymbol = e as FamilySymbol;
                if (familySymbol.Family.Name == familyname)
                {
                    zz = 1;
                    break;
                }
            }
            if (zz == 1)
                return true;
            else
                return false;
        }

        //求某族里的某类型
        public FamilySymbol Find_FamilySymbol(Autodesk.Revit.DB.Document doc, Family family, string symbolname)
        {
            FamilySymbol fs = null;
            IEnumerator<ElementId> symbolsItor = family.GetFamilySymbolIds().GetEnumerator();
            symbolsItor.Reset();
            while (symbolsItor.MoveNext())
            {
                FamilySymbol familySymboltmp = doc.GetElement(symbolsItor.Current) as FamilySymbol;
                if (symbolname == familySymboltmp.Name)
                {
                    fs = familySymboltmp;
                    break;
                }
            }
            return fs;
        }

        //复制族类型。
        public FamilySymbol Dublicate_Symbol(Autodesk.Revit.DB.Document doc, FamilySymbol oldsymbol, string newsymbolname)
        {

            int fb = 1;   //拿来计算有多少个副本用
            int had = 0;
            IEnumerator<ElementId> symbolItor = oldsymbol.Family.GetFamilySymbolIds().GetEnumerator();
            FamilySymbol newsymbol = null;
            FamilySymbol fbsymbol = null;
            while (symbolItor.MoveNext())
            {
                FamilySymbol symbol = doc.GetElement(symbolItor.Current) as FamilySymbol;
                if (symbol.Name == newsymbolname)
                {
                    had = 1;
                }
                if (symbol.Name != newsymbolname && symbol.Name.Contains(newsymbolname + " 副本"))
                {
                    fb = fb + 1;
                    fbsymbol = symbol;
                }
            }
            if (fb > 1)
            {
                newsymbol = fbsymbol.Duplicate(fbsymbol.Name.Substring(0, fbsymbol.Name.IndexOf("副本") + 2) + fb.ToString()) as FamilySymbol;
            }
            else
            {
                if (had == 1)
                {
                    newsymbol = oldsymbol.Duplicate(newsymbolname + " 副本1") as FamilySymbol;
                }
                else
                {
                    newsymbol = oldsymbol.Duplicate(newsymbolname) as FamilySymbol;
                }
            }
            return newsymbol;
        }

        //查找材质
        public Material GetMaterial(Autodesk.Revit.DB.Document doc, string name)
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            collector.WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_Materials));
            var MaterialElement = from element in collector
                                  where element.Name == name
                                  select element;

            if (MaterialElement.Count() == 0)
                return null;
            return MaterialElement.First<Element>() as Material;
        }

        //尽可能把原FamilyInstance的各项参数赋值到新建FailyInstance，注意偏移量是忽略的
        public void Old_To_New(Element old_Element, Element new_Element)
        {
            ParameterSetIterator parait_old = old_Element.Parameters.ForwardIterator();
            parait_old.Reset();
            while (parait_old.MoveNext())
            {
                Parameter para_old = parait_old.Current as Parameter;
                if (para_old.Definition.Name == "偏移量")
                    continue;
                try
                {
                    ParameterSetIterator parait_new = new_Element.Parameters.ForwardIterator();
                    parait_new.Reset();
                    while (parait_new.MoveNext())
                    {
                        Parameter para_new = parait_new.Current as Parameter;
                        if (para_old.Definition.Name == para_new.Definition.Name)
                        {
                            BuiltInParameter biParam = (BuiltInParameter)para_new.Id.IntegerValue;
                            BuiltInParameter biParam_old = (BuiltInParameter)para_old.Id.IntegerValue;

                            if (old_Element.get_Parameter(biParam).StorageType == StorageType.Double)
                            {
                                try
                                {
                                    Double tmp = old_Element.get_Parameter(biParam).AsDouble();
                                    new_Element.get_Parameter(biParam).Set(tmp);
                                }
                                catch { }
                            }
                            else if (old_Element.get_Parameter(biParam).StorageType == StorageType.ElementId)
                            {
                                try
                                {
                                    ElementId tmp = old_Element.get_Parameter(biParam).AsElementId();
                                    new_Element.get_Parameter(biParam).Set(tmp);
                                }
                                catch { }
                            }
                            else if (old_Element.get_Parameter(biParam).StorageType == StorageType.Integer)
                            {
                                try
                                {
                                    int tmp = old_Element.get_Parameter(biParam).AsInteger();
                                    new_Element.get_Parameter(biParam).Set(tmp);
                                }
                                catch { }
                            }
                            else if (old_Element.get_Parameter(biParam).StorageType == StorageType.String)
                            {
                                try
                                {
                                    String tmp = old_Element.get_Parameter(biParam).AsString();
                                    new_Element.get_Parameter(biParam).Set(tmp);
                                }
                                catch { }
                            }
                        }
                    }
                }
                catch
                { }
            }
        }
        
        /// <summary>
        /// Transaction前面一大段的东西
        /// </summary>
        /// <param name="trans"></param>
        public void SetTransaction(Transaction trans)
        {
            FailureHandlingOptions failureHandlingOptions = trans.GetFailureHandlingOptions();
            FailureHandler failureHandler = new FailureHandler();
            failureHandlingOptions.SetFailuresPreprocessor(failureHandler);
            failureHandlingOptions.SetClearAfterRollback(true);
            trans.SetFailureHandlingOptions(failureHandlingOptions);
        }

        //Transaction前面一大段的东西，点击弹窗的“删除”
        public void SetTransaction_DeleteElement(Transaction trans)
        {
            FailureHandlingOptions failureHandlingOptions = trans.GetFailureHandlingOptions();
            FailureHandler_DeleteElement failureHandler = new FailureHandler_DeleteElement();
            failureHandlingOptions.SetFailuresPreprocessor(failureHandler);
            failureHandlingOptions.SetClearAfterRollback(true);
            trans.SetFailureHandlingOptions(failureHandlingOptions);
        }

        //BoundingBoxXYZ确保在各个视图都是完整的
        public BoundingBoxXYZ Entire_BoundingBoxXYZ(Autodesk.Revit.UI.ExternalCommandData CommandData, Element e)
        {
            //创建3D视图
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            Transaction transaction0 = new Transaction(doc, "Create3DView");
            transaction0.Start();
            XYZ viewDirection = new XYZ(10, 10, -10);
            IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
                                                          let type = elem as ViewFamilyType
                                                          where type.ViewFamily == ViewFamily.ThreeDimensional
                                                          select type;
            View3D view3D = View3D.CreateIsometric(doc, viewFamilyTypes.First().Id);
            transaction0.Commit();
            BoundingBoxXYZ bbbox = e.get_BoundingBox(view3D);
            Transaction transaction1 = new Transaction(doc, "Create3DView"); transaction1.Start();
            doc.Delete(view3D.Id);
            transaction1.Commit();
            return bbbox;
        }

        //求curve集里最长的curve索引
        public int index_of_maxcurve(IList<Curve> curvelist)
        {
            double length = 0;
            int index = -1;
            for (int k = 0; k <= curvelist.Count - 1; k++)
            {
                if (curvelist[k].Length > length)
                {
                    index = k;
                    length = curvelist[k].Length;
                }
            }
            return index;
        }

        //求curve集里最短的curve索引
        public int index_of_mincurve(IList<Curve> curvelist)
        {
            double length = curvelist[0].Length;
            int index = 0;
            for (int k = 1; k <= curvelist.Count - 1; k++)
            {
                if (curvelist[k].Length < length)
                {
                    index = k;
                    length = curvelist[k].Length;
                }
            }
            return index;
        }

        // 求线段p1p2与线段p3p4的平面交点坐标（要求交点距离P1P2大于delta，否则返回null）
        public XYZ insect_delta(XYZ p1, XYZ p2, XYZ p3, XYZ p4, double delta)
        {
            XYZ p1_delta = (p2 - p1) * delta / p2.DistanceTo(p1) + p1;
            XYZ p2_delta = (p1 - p2) * delta / p2.DistanceTo(p1) + p2;
            return IntersectPoint_Of_Curves(p1_delta, p2_delta, p3, p4);
        }

        //求物体的所有Face
        public IList<Face> AllFace_Of_Element(Element e, ViewDetailLevel vdl)
        {
            IList<Face> face_list = new List<Face>();
            try
            {
                Options options = new Options();
                options.IncludeNonVisibleObjects = false;
                options.DetailLevel = vdl;
                options.ComputeReferences = true;

                GeometryElement geoElement = e.get_Geometry(options);
                IEnumerator enumerator = geoElement.GetEnumerator();
                {
                    while (enumerator.MoveNext())
                    {
                        List<Solid> solid_list = new List<Solid>();
                        GeometryObject geoObj = enumerator.Current as GeometryObject;
                        if (geoObj is GeometryInstance)
                        {
                            GeometryInstance geoinstance = geoObj as GeometryInstance;
                            GeometryElement geoObjtmp = geoinstance.GetInstanceGeometry();
                            //GeometryElement geoObjtmp = geoinstance.GetSymbolGeometry();
                            IEnumerator enumeratorobj = geoObjtmp.GetEnumerator();
                            {
                                while (enumeratorobj.MoveNext())
                                {
                                    GeometryObject obj2 = enumeratorobj.Current as GeometryObject;
                                    if (obj2 is Solid)
                                    {
                                        solid_list.Add(obj2 as Solid);
                                    }
                                }
                            }
                        }
                        else if (geoObj is Solid)
                        {
                            solid_list.Add(geoObj as Solid);
                        }
                        foreach (Solid solid in solid_list)
                        {
                            if (solid == null)
                                continue;
                            if (solid.Faces.Size <= 1)
                                continue;
                            foreach (Face face in solid.Faces)
                            {
                                face_list.Add(face);
                            }
                        }
                    }
                }
            }
            catch
            { }
            return face_list;
        }

        //求物体的所有Solid
        public List<Solid> AllSolid_Of_Element(Element e, ViewDetailLevel vdl)
        {
            List<Solid> solid_list = new List<Solid>();
            try
            {
                Options options = new Options();
                options.IncludeNonVisibleObjects = false;
                options.DetailLevel = vdl;
                options.ComputeReferences = true;

                GeometryElement geoElement = e.get_Geometry(options);
                IEnumerator enumerator = geoElement.GetEnumerator();
                {
                    while (enumerator.MoveNext())
                    {
                        GeometryObject geoObj = enumerator.Current as GeometryObject;
                        if (geoObj is GeometryInstance)
                        {
                            GeometryInstance geoinstance = geoObj as GeometryInstance;
                            GeometryElement geoObjtmp = geoinstance.GetInstanceGeometry();
                            //GeometryElement geoObjtmp = geoinstance.GetSymbolGeometry();
                            IEnumerator enumeratorobj = geoObjtmp.GetEnumerator();
                            {
                                while (enumeratorobj.MoveNext())
                                {
                                    GeometryObject obj2 = enumeratorobj.Current as GeometryObject;
                                    if (obj2 is Solid)
                                    {
                                        solid_list.Add(obj2 as Solid);
                                    }
                                }
                            }
                        }
                        else if (geoObj is Solid)
                        {
                            solid_list.Add(geoObj as Solid);
                        }
                    }
                }
            }
            catch
            { }
            return solid_list;
        }

        //求face的Transform，要求X轴为水平，Y轴向上，Z轴为法线
        public Transform Tf_Of_Face_X(ExternalCommandData CommandData, Face face)
        {
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            UV uvpoint = (face.GetBoundingBox().Max + face.GetBoundingBox().Min) / 2;
            //XYZ origin = face.Evaluate(uvpoint);
            XYZ origin = face.Evaluate(face.GetBoundingBox().Min);
            Plane geometryPlane = Revit.Create.NewPlane(face.ComputeNormal(uvpoint), origin);
            //geometryPlane的X单位向量不是水平的。用geometryPlane上面的半径为1的圆，与水平面半径为1的圆相交，得到水平的单位向量。
            //相应的得到竖直的单位向量，再重新建立Transform坐标系

            Arc arc11 = Arc.Create(geometryPlane, 1, 0, Math.PI);//画圆，注意0.0001是角度，Math.PI * 2是360度
            Arc arc12 = Arc.Create(geometryPlane, 1, Math.PI, Math.PI * 2);//画圆，注意0.0001是角度，Math.PI * 2是360度

            Plane basicZPlane = Revit.Create.NewPlane(XYZ.BasisZ, origin);
            if (face.ComputeNormal(uvpoint).Z > 0.9999 || face.ComputeNormal(uvpoint).Z < -0.9999)
            {
                //这种情况不能通过XY平面圆相交来求，要通过XZ平面圆相交来求
                basicZPlane = Revit.Create.NewPlane(XYZ.BasisY, origin);
            }

            Arc arc21 = Arc.Create(basicZPlane, 1, 0, Math.PI);
            Arc arc22 = Arc.Create(basicZPlane, 1, Math.PI, Math.PI * 2);

            List<XYZ> intersect_list_x = new List<XYZ>();
            List<XYZ> intersect_list_y = new List<XYZ>();
            IntersectionResultArray irax1 = new IntersectionResultArray();
            arc11.Intersect(arc21, out irax1);
            IntersectionResultArray irax2 = new IntersectionResultArray();
            arc11.Intersect(arc22, out irax2);
            IntersectionResultArray irax3 = new IntersectionResultArray();
            arc12.Intersect(arc21, out irax3);
            IntersectionResultArray irax4 = new IntersectionResultArray();
            arc12.Intersect(arc22, out irax4);
            if (irax1 != null)
            {
                foreach (IntersectionResult ir in irax1)
                    intersect_list_x.Add(ir.XYZPoint);
            }
            if (irax2 != null)
            {
                foreach (IntersectionResult ir in irax2)
                    intersect_list_x.Add(ir.XYZPoint);
            }
            if (irax3 != null)
            {
                foreach (IntersectionResult ir in irax3)
                    intersect_list_x.Add(ir.XYZPoint);
            }
            if (irax4 != null)
            {
                foreach (IntersectionResult ir in irax4)
                    intersect_list_x.Add(ir.XYZPoint);
            }

            Plane basicYPlane = Revit.Create.NewPlane(XYZ.BasisY, origin);
            if (Math.Abs(face.ComputeNormal(uvpoint).X) < 0.0001)  //这种情况不能通过XZ平面圆相交来求，要通过YZ平面圆相交来求
            {
                basicYPlane = Revit.Create.NewPlane(XYZ.BasisX, origin);
            }

            Arc arc31 = Arc.Create(basicYPlane, 1, 0, Math.PI);
            Arc arc32 = Arc.Create(basicYPlane, 1, Math.PI, Math.PI * 2);

            IntersectionResultArray iray1 = new IntersectionResultArray();
            arc11.Intersect(arc31, out iray1);
            IntersectionResultArray iray2 = new IntersectionResultArray();
            arc11.Intersect(arc32, out iray2);
            IntersectionResultArray iray3 = new IntersectionResultArray();
            arc12.Intersect(arc31, out iray3);
            IntersectionResultArray iray4 = new IntersectionResultArray();
            arc12.Intersect(arc32, out iray4);

            if (iray1 != null)
            {
                foreach (IntersectionResult ir in iray1)
                    intersect_list_y.Add(ir.XYZPoint);
            }
            if (iray2 != null)
            {
                foreach (IntersectionResult ir in iray2)
                    intersect_list_y.Add(ir.XYZPoint);
            }
            if (iray3 != null)
            {
                foreach (IntersectionResult ir in iray3)
                    intersect_list_y.Add(ir.XYZPoint);
            }
            if (iray4 != null)
            {
                foreach (IntersectionResult ir in iray4)
                    intersect_list_y.Add(ir.XYZPoint);
            }
            XYZ px = intersect_list_x[0];
            if (px.Y < origin.Y)
                px = intersect_list_x[1];

            XYZ py = intersect_list_y[0];
            if (py.Z < origin.Z)
                py = intersect_list_y[1];


            //Transform tf = Transform.Identity;
            //tf.Origin = origin;
            //tf.BasisX = px - origin;
            //tf.BasisY = py - origin;
            //tf.BasisZ = geometryPlane.Normal;

            //——————————————————————————————2017-8-28修改——————————————————————
            Transform tf = Transform.Identity;
            tf.Origin = origin;
            tf.BasisY = py - origin;
            tf.BasisZ = -geometryPlane.Normal;
            tf.BasisX = -tf.BasisZ.CrossProduct(tf.BasisY);

            return tf;
        }

        //求face的Transform
        public Transform Tf_Of_Face(ExternalCommandData CommandData, Face face)
        {
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            UV uvpoint = (face.GetBoundingBox().Max + face.GetBoundingBox().Min) / 2;
            XYZ origin = face.Evaluate(uvpoint);
            Plane geometryPlane = Revit.Create.NewPlane(face.ComputeNormal(uvpoint), origin);
            //geometryPlane的X单位向量不是水平的。

            Transform tf = Transform.Identity;
            tf.Origin = origin;
            tf.BasisX = geometryPlane.XVec;
            tf.BasisY = geometryPlane.YVec;
            tf.BasisZ = geometryPlane.Normal;

            return tf;

        }

        //求点在面坐标系上的坐标（不管点是否在面上）
        public XYZ XYZ_On_Face(Face face, XYZ p)
        {
            Transform tran = null;
            tran = Transform.Identity;
            tran.Origin = face.Evaluate(new UV(0, 0));
            tran.BasisX = face.Evaluate(new UV(1, 0)) - face.Evaluate(new UV(0, 0));
            tran.BasisY = face.Evaluate(new UV(0, 1)) - face.Evaluate(new UV(0, 0));
            tran.BasisZ = face.ComputeNormal(new UV(0, 0));
            return tran.Inverse.OfPoint(p);
        }

        //将curve投射到face上。暂时只考虑line和arc
        public Curve CurveProjectToFace(Face face, Curve c)
        {
            Curve newcurve = c;
            if (c is Arc)
            {
                XYZ p1 = face.Evaluate(UV_On_Face(face, c.GetEndPoint(0)));
                XYZ p2 = face.Evaluate(UV_On_Face(face, c.GetEndPoint(1)));
                XYZ p3 = face.Evaluate(UV_On_Face(face, c.Evaluate(0.5, true)));
                newcurve = Arc.Create(p1, p2, p3);
            }
            else
            {
                XYZ p1 = face.Evaluate(UV_On_Face(face, c.GetEndPoint(0)));
                XYZ p2 = face.Evaluate(UV_On_Face(face, c.GetEndPoint(1)));
                newcurve = Line.CreateBound(p1, p2);
            }

            return newcurve;
        }

        //将curve投射到trasform上。暂时只考虑line和arc
        public Curve CurveProjectToTransform(Transform tf, Curve c)
        {
            Curve newcurve = null;
            try
            {
                if (c is Arc)
                {
                    XYZ p1 = tf.Inverse.OfPoint(c.GetEndPoint(0));
                    p1 = new XYZ(p1.X, p1.Y, 0);
                    p1 = tf.OfPoint(p1);
                    XYZ p2 = tf.Inverse.OfPoint(c.GetEndPoint(1));
                    p2 = new XYZ(p2.X, p2.Y, 0);
                    p2 = tf.OfPoint(p2);
                    XYZ p3 = tf.Inverse.OfPoint(c.Evaluate(0.5, true));
                    p3 = new XYZ(p3.X, p3.Y, 0);
                    p3 = tf.OfPoint(p3);
                    newcurve = Arc.Create(p1, p2, p3);
                }
                else
                {
                    XYZ p1 = tf.Inverse.OfPoint(c.GetEndPoint(0));
                    p1 = new XYZ(p1.X, p1.Y, 0);
                    p1 = tf.OfPoint(p1);
                    XYZ p2 = tf.Inverse.OfPoint(c.GetEndPoint(1));
                    p2 = new XYZ(p2.X, p2.Y, 0);
                    p2 = tf.OfPoint(p2);
                    newcurve = Line.CreateBound(p1, p2);
                }
            }
            catch
            { }
            //MessageBox.Show(distance_point_to_face(face, newcurve.GetEndPoint(0)) + "\n" + distance_point_to_face(face, newcurve.GetEndPoint(1)) + "\n"  + "OKbbb", "uBIM", MessageBoxButtons.OK);

            return newcurve;
        }

        /// <summary>  
        /// 判断点是否在多边形内，注意没有考虑Z坐标，仅考虑水平面的点和多边形
        /// ----------原理----------  
        /// 注意到如果从P作水平向左的射线的话，如果P在多边形内部，那么这条射线与多边形的交点必为奇数，  
        /// 如果P在多边形外部，则交点个数必为偶数(0也在内)。  
        /// </summary>  
        /// <param name="checkPoint">要判断的点</param>  
        /// <param name="polygonPoints">多边形的顶点</param>  
        /// <returns></returns>  
        public bool IsInPolygon(XYZ checkPoint, List<XYZ> polygonPoints)
        {
            bool inside = false;
            int pointCount = polygonPoints.Count;
            XYZ p1, p2;
            for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)//第一个点和最后一个点作为第一条线，之后是第一个点和第二个点作为第二条线，之后是第二个点与第三个点，第三个点与第四个点...  
            {
                p1 = polygonPoints[i];
                p2 = polygonPoints[j];
                if (checkPoint.Y < p2.Y)
                {//p2在射线之上  
                    if (p1.Y <= checkPoint.Y)
                    {//p1正好在射线中或者射线下方  
                        if ((checkPoint.Y - p1.Y) * (p2.X - p1.X) > (checkPoint.X - p1.X) * (p2.Y - p1.Y))//斜率判断,在P1和P2之间且在P1P2右侧  
                        {
                            //射线与多边形交点为奇数时则在多边形之内，若为偶数个交点时则在多边形之外。  
                            //由于inside初始值为false，即交点数为零。所以当有第一个交点时，则必为奇数，则在内部，此时为inside=(!inside)  
                            //所以当有第二个交点时，则必为偶数，则在外部，此时为inside=(!inside)  
                            inside = (!inside);
                        }
                    }
                }
                else if (checkPoint.Y < p1.Y)
                {
                    //p2正好在射线中或者在射线下方，p1在射线上  
                    if ((checkPoint.Y - p1.Y) * (p2.X - p1.X) < (checkPoint.X - p1.X) * (p2.Y - p1.Y))//斜率判断,在P1和P2之间且在P1P2右侧  
                    {
                        inside = (!inside);
                    }
                }
            }
            return inside;
        }

        //判断点是否在面积内部，注意没有考虑Z坐标，自动忽略点的Z坐标
        public Boolean IsInsideArea(Area area, XYZ p)
        {
            Boolean isinside = false;
            List<Curve> curve_list = new List<Curve>();
            foreach (IList<BoundarySegment> bs_tmp in area.GetBoundarySegments(new SpatialElementBoundaryOptions()))
            {
                foreach (BoundarySegment boundarySegment in bs_tmp)
                {
                    curve_list.Add(boundarySegment.GetCurve());
                }
            }
            p = new XYZ(p.X, p.Y, area.Level.Elevation);
            Line line = Line.CreateBound(p, p + XYZ.BasisX * 100);
            int k = 0;
            foreach (Curve c in curve_list)
            {
                SetComparisonResult scr = line.Intersect(c);
                if (scr == SetComparisonResult.Subset)
                {
                    isinside = true;
                    break;
                }
                if (scr == SetComparisonResult.Overlap)
                    k += 1;
            }
            //奇数为里；偶数为外
            if (k / 2 == (k + 1) / 2)   //偶数
                isinside = false;
            else
                isinside = true;

            return isinside;
        }

        //求element相交的element
        public IList<ElementId> Element_Intersect_Element(Autodesk.Revit.DB.Document doc, Element e)
        {
            IList<ElementId> elementid_list = new List<ElementId>();
            //原来有连接关系的，用ElementIntersectsElementFilter找不到
            try
            {
                ICollection<ElementId> joined_idlist = JoinGeometryUtils.GetJoinedElements(doc, e);
                foreach (ElementId id in joined_idlist)
                {
                    if (!elementid_list.Contains(id))
                        elementid_list.Add(id);
                }
            }
            catch
            { }
            try
            {
                FilteredElementCollector collector = new FilteredElementCollector(doc);
                ElementIntersectsElementFilter elementFilter = new ElementIntersectsElementFilter(e);
                IList<Element> tmp_list = collector.WherePasses(elementFilter).ToElements();
                foreach (Element etmp in tmp_list)
                {
                    if (etmp.Id.IntegerValue != e.Id.IntegerValue)
                        elementid_list.Add(etmp.Id);
                }
            }
            catch
            { }
            //两个物体并排，上面代码找不到
            //BoundingBoxXYZ bb = e.get_BoundingBox(view);
            //Outline myOutLn = new Outline(bb.Min - new XYZ(0.01, 0.01, 0.01), bb.Max + new XYZ(0.01, 0.01, 0.01));
            //BoundingBoxIntersectsFilter boxfilter = new BoundingBoxIntersectsFilter(myOutLn);
            //FilteredElementCollector collector2 = new FilteredElementCollector(doc);
            //IList<Element> interset = collector2.WherePasses(boxfilter).ToElements();
            //foreach (Element etmp in interset)
            //    elementid_list.Add(etmp.Id);
            return elementid_list;
        }

        //join两个物体，e1为主剪切，e2为被剪切
        public void Join_Two_Element(Autodesk.Revit.DB.Document doc, Element e1, Element e2)
        {
            ICollection<ElementId> joined_idlist = JoinGeometryUtils.GetJoinedElements(doc, e1);
            if (joined_idlist.Contains(e2.Id))
            {
                try
                {
                    Boolean cut = JoinGeometryUtils.IsCuttingElementInJoin(doc, e1, e2);
                    //True if e1保全, false if e1被剪
                    if (cut == false)
                    {
                        JoinGeometryUtils.SwitchJoinOrder(doc, e1, e2);
                    }
                }
                catch
                { }
            }
            else
            {
                try
                {
                    JoinGeometryUtils.JoinGeometry(doc, e1, e2);
                    Boolean cut = JoinGeometryUtils.IsCuttingElementInJoin(doc, e1, e2);
                    //True if e1保全, false if e1被剪
                    if (cut == false)
                    {
                        JoinGeometryUtils.SwitchJoinOrder(doc, e1, e2);
                    }
                }
                catch
                { }
            }
        }

        //求点附近的构件（包含该点）
        public ICollection<ElementId> Element_Contain_Point(Autodesk.Revit.DB.Document doc, XYZ p)
        {
            Outline myOutLn = new Outline(p - new XYZ(0.01, 0.01, 0.01), p + new XYZ(0.01, 0.01, 0.01));
            BoundingBoxIntersectsFilter filter = new BoundingBoxIntersectsFilter(myOutLn);
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            ICollection<ElementId> intersect_elements = collector.WherePasses(filter).ToElementIds();
            return intersect_elements;
        }

        //求element BoundingBoxXYZ相交的element（链接文件中），每一个Element对应一个其所属的RevitLinkInstance
        public IList<LinkElementId> Element_Intersect_ElementInLink(ExternalCommandData CommandData, Element e, out IList<RevitLinkInstance> revitlinklist)
        {
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            BoundingBoxXYZ bb = Entire_BoundingBoxXYZ(CommandData, e);

            IList<LinkElementId> linkelementid_list = new List<LinkElementId>();

            //获取当前项目中全部链接文件
            IList<Element> linkdoc_list = Searcher.LinkDocList(doc);
            revitlinklist = new List<RevitLinkInstance>();
            foreach (Element ee in linkdoc_list)
            {
                try
                {
                    RevitLinkInstance revitInstance = ee as RevitLinkInstance;
                    Autodesk.Revit.DB.Document linkdoc = revitInstance.GetLinkDocument() as Autodesk.Revit.DB.Document;
                    Transform tf = revitInstance.GetTotalTransform();
                    XYZ p1 = tf.Inverse.OfPoint(bb.Min);
                    XYZ p2 = tf.Inverse.OfPoint(bb.Max);
                    double minx = Math.Min(p1.X, p2.X);
                    double miny = Math.Min(p1.Y, p2.Y);
                    double minz = Math.Min(p1.Z, p2.Z);
                    double maxx = Math.Max(p1.X, p2.X);
                    double maxy = Math.Max(p1.Y, p2.Y);
                    double maxz = Math.Max(p1.Z, p2.Z);

                    Outline myOutLn = new Outline(new XYZ(minx, miny, minz), new XYZ(maxx, maxy, maxz));
                    BoundingBoxIntersectsFilter boxfilter = new BoundingBoxIntersectsFilter(myOutLn);
                    IList<Element> interset_link = (new FilteredElementCollector(linkdoc)).WherePasses(boxfilter).ToElements();
                    foreach (Element etmp in interset_link)
                    {
                        linkelementid_list.Add(new LinkElementId(revitInstance.Id, etmp.Id));
                        revitlinklist.Add(revitInstance);
                    }
                }
                catch
                { }
            }
            return linkelementid_list;
        }

        //求点所属楼层
        public Level LevelContainsPoint(Autodesk.Revit.DB.Document doc, XYZ p)
        {
            List<Level> levellist = new List<Level>();
            List<double> evlist = new List<double>();
            ICollection<ElementId> levelid_list = (new FilteredElementCollector(doc)).
                WherePasses(new ElementClassFilter(typeof(Level))).ToElementIds();
            Level level = doc.GetElement(levelid_list.ElementAt(0)) as Level;
            foreach (ElementId eid in levelid_list)
            {
                Level leveltmp = doc.GetElement(eid) as Level;
                levellist.Add(leveltmp);
                evlist.Add(leveltmp.Elevation);
            }
            evlist.Sort();
            evlist.Reverse();
            foreach (ElementId eid in levelid_list)
            {
                Level leveltmp = doc.GetElement(eid) as Level;
                levellist[evlist.IndexOf(leveltmp.Elevation)] = leveltmp;
            }
            for (int t = 0; t <= levellist.Count - 1; t++)
            {
                if (p.Z >= evlist[t])
                {
                    level = levellist[t];
                    break;
                }
            }
            return level;
        }
                
        //楼层排序，从高到低
        public List<ElementId> LevelIDList(Autodesk.Revit.DB.Document doc)
        {
            List<ElementId> levelid_orderlist = new List<ElementId>();
            List<double> evlist = new List<double>();
            ICollection<ElementId> levelid_list = (new FilteredElementCollector(doc)).
                WherePasses(new ElementClassFilter(typeof(Level))).ToElementIds();
            foreach (ElementId eid in levelid_list)
            {
                Level level = doc.GetElement(eid) as Level;
                levelid_orderlist.Add(eid);
                evlist.Add(level.Elevation);
            }
            evlist.Sort();
            evlist.Reverse();
            foreach (ElementId eid in levelid_list)
            {
                Level level = doc.GetElement(eid) as Level;
                levelid_orderlist[evlist.IndexOf(level.Elevation)] = eid;
            }
            return levelid_orderlist;
        }

        //在一堆curvelist里面，点击pickpoint求边界，Z为0，已区分不同的loop
        public List<Curve> BounaryCurveList(ExternalCommandData CommandData, List<Curve> curvelist, XYZ pickpoint, out Area area, out List<ElementId> del_list)
        {
            area = null;
            del_list = new List<ElementId>();
            List<Curve> bounarycurvelist = new List<Curve>();
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            //新建面积平面
            FilteredElementCollector collector_areascheme = new FilteredElementCollector(doc);
            IList<Element> intersect_areascheme = collector_areascheme.OfClass(typeof(AreaScheme)).ToElements();
            Transaction transaction0 = new Transaction(doc, "yy"); transaction0.Start();
            Level level = LevelContainsPoint(doc, new XYZ(0, 0, 0.1));
            ViewPlan vp = ViewPlan.CreateAreaPlan(doc, (intersect_areascheme[0] as AreaScheme).Id, level.Id);
            transaction0.Commit();
            del_list.Add(vp.Id);

            Transaction transaction = new Transaction(doc, "yy"); transaction.Start();
            XYZ origin = new XYZ(0, 0, 0);
            XYZ normal = new XYZ(0, 0, 1);
            Plane plane = CommandData.Application.Application.Create.NewPlane(normal, origin);
            SketchPlane sp = SketchPlane.Create(doc, plane);
            transaction.Commit();

            IList<ElementId> modelcurve_id = new List<ElementId>();  //临时生成的面积边界
            IList<XYZ> points_of_mc = new List<XYZ>();  //记录modelcurve的端点
            foreach (Curve curve in curvelist)
            {
                XYZ p0 = curve.GetEndPoint(0);
                XYZ p1 = curve.GetEndPoint(1);

                ModelCurve mc = null;
                Transaction transaction7 = new Transaction(doc, "yy");
                FailureHandlingOptions failureHandlingOptions7 = transaction7.GetFailureHandlingOptions();
                FailureHandler failureHandler7 = new FailureHandler();
                failureHandlingOptions7.SetFailuresPreprocessor(failureHandler7);
                failureHandlingOptions7.SetClearAfterRollback(true);
                transaction7.SetFailureHandlingOptions(failureHandlingOptions7);
                transaction7.Start();
                try
                {
                    mc = doc.Create.NewAreaBoundaryLine(sp, curve, vp);
                }
                catch
                { }
                transaction7.Commit();
                try
                {
                    modelcurve_id.Add(mc.Id);
                    points_of_mc.Add(p0);
                    points_of_mc.Add(p1);
                    del_list.Add(mc.Id);
                }
                catch
                { }
            }

            //利用面积功能求边界
            Transaction transaction3 = new Transaction(doc, "yy");
            FailureHandlingOptions failureHandlingOptions3 = transaction3.GetFailureHandlingOptions();
            FailureHandler failureHandler3 = new FailureHandler();
            failureHandlingOptions3.SetFailuresPreprocessor(failureHandler3);
            failureHandlingOptions3.SetClearAfterRollback(true);
            transaction3.SetFailureHandlingOptions(failureHandlingOptions3);
            transaction3.Start();
            try
            {
                area = doc.Create.NewArea(vp, new UV(pickpoint.X, pickpoint.Y));
                del_list.Add(area.Id);
            }
            catch
            { }
            transaction3.Commit();

            if (area == null)
            {
                return bounarycurvelist;
            }

            IList<XYZ> bounarypointlist = new List<XYZ>();
            IList<Curve> bc_nsz_list = new List<Curve>();   //重整边界后逆时针排列的边界

            //区分不同的loop
            IList<IList<XYZ>> pointlistlist = new List<IList<XYZ>>();

            foreach (IList<BoundarySegment> bs_tmp in area.GetBoundarySegments(new SpatialElementBoundaryOptions()))
            {
                IList<XYZ> pointlist = new List<XYZ>();
                foreach (BoundarySegment boundarySegment in bs_tmp)
                {
                    XYZ addpoint = boundarySegment.GetCurve().GetEndPoint(0);
                    //有时边界点明明显示是对的，但数据有几毫米误差，一般出现在几根梁墙交于同一点处，原因不明，
                    //没找到更好的办法，只好遍历modelcurve的端点，如果有接近的，就以这个为准。
                    foreach (XYZ p in points_of_mc)
                    {
                        if (p.DistanceTo(addpoint) < 10 / 304.8)
                        {
                            addpoint = p;
                            break;
                        }
                    }
                    Boolean add = true;

                    foreach (XYZ p in pointlist)
                    {
                        if (p.DistanceTo(addpoint) < 10 / 304.8)
                        {
                            add = false;
                            break;
                        }
                    }
                    if (add == true)
                        pointlist.Add(addpoint);
                }
                pointlistlist.Add(pointlist);
            }

            for (int j = 0; j <= pointlistlist.Count - 1; j++)
            {
                IList<XYZ> pointlist = pointlistlist[j];
                for (int i = 0; i <= pointlist.Count - 1; i++)
                {
                    Curve c = null;
                    try
                    {
                        if (i < pointlist.Count - 1)
                        {
                            XYZ p0 = pointlist[i];
                            XYZ p1 = pointlist[i + 1];
                            p0 = new XYZ(p0.X, p0.Y, 0);
                            p1 = new XYZ(p1.X, p1.Y, 0);
                            c = Line.CreateBound(p0, p1) as Curve;
                        }
                        else
                        {
                            XYZ p0 = pointlist[i];
                            XYZ p1 = pointlist[0];
                            p0 = new XYZ(p0.X, p0.Y, 0);
                            p1 = new XYZ(p1.X, p1.Y, 0);
                            c = Line.CreateBound(p0, p1) as Curve;
                        }
                        bounarycurvelist.Add(c);
                    }
                    catch
                    { }
                }
            }

            //将共线边界合并
            Boolean gx = false;
            do
            {
                gx = false;
                for (int i = 0; i <= bounarycurvelist.Count - 1; i++)
                {
                    Boolean gxi = false;
                    for (int j = i + 1; j <= bounarycurvelist.Count; j++)
                    {
                        Curve ci = bounarycurvelist[i];
                        Curve cj = null;
                        if (j == bounarycurvelist.Count)
                            cj = bounarycurvelist[0];
                        else
                            cj = bounarycurvelist[j];
                        if (ci.GetEndPoint(0).DistanceTo(cj.GetEndPoint(0)) < 10 / 304.8)
                        {
                            if (ci.Length + cj.Length - ci.GetEndPoint(1).DistanceTo(cj.GetEndPoint(1)) < 0.01)
                            {
                                Curve newcurve = Line.CreateBound(ci.GetEndPoint(1), cj.GetEndPoint(1)) as Curve;
                                bounarycurvelist[i] = newcurve;
                                bounarycurvelist.RemoveAt(j);
                                gxi = true;
                                break;
                            }
                        }
                        if (ci.GetEndPoint(0).DistanceTo(cj.GetEndPoint(1)) < 10 / 304.8)
                        {
                            if (ci.Length + cj.Length - ci.GetEndPoint(1).DistanceTo(cj.GetEndPoint(0)) < 0.01)
                            {
                                Curve newcurve = Line.CreateBound(ci.GetEndPoint(1), cj.GetEndPoint(0)) as Curve;
                                bounarycurvelist[i] = newcurve;
                                bounarycurvelist.RemoveAt(j);
                                gxi = true;
                                break;
                            }
                        }
                        if (ci.GetEndPoint(1).DistanceTo(cj.GetEndPoint(0)) < 10 / 304.8)
                        {
                            if (ci.Length + cj.Length - ci.GetEndPoint(0).DistanceTo(cj.GetEndPoint(1)) < 0.01)
                            {
                                Curve newcurve = Line.CreateBound(ci.GetEndPoint(0), cj.GetEndPoint(1)) as Curve;
                                bounarycurvelist[i] = newcurve;
                                bounarycurvelist.RemoveAt(j);
                                gxi = true;
                                break;
                            }
                        }
                        if (ci.GetEndPoint(1).DistanceTo(cj.GetEndPoint(1)) < 10 / 304.8)
                        {
                            if (ci.Length + cj.Length - ci.GetEndPoint(0).DistanceTo(cj.GetEndPoint(0)) < 0.01)
                            {
                                Curve newcurve = Line.CreateBound(ci.GetEndPoint(0), cj.GetEndPoint(0)) as Curve;
                                bounarycurvelist[i] = newcurve;
                                bounarycurvelist.RemoveAt(j);
                                gxi = true;
                                break;
                            }
                        }
                    }
                    if (gxi == true)
                    {
                        gx = true;
                        break;
                    }
                }
            }
            while (gx == true);

            //将各边界按顺序重整
            Boolean nx = false;
            do
            {
                nx = false;
                for (int i = 0; i <= bounarycurvelist.Count - 1; i++)
                {
                    Boolean nxi = false;
                    Curve c = bounarycurvelist[i];
                    XYZ p0 = c.GetEndPoint(0);
                    XYZ p1 = c.GetEndPoint(1);
                    foreach (Curve d in bounarycurvelist)
                    {
                        if (d.GetEndPoint(0).IsAlmostEqualTo(c.GetEndPoint(0)) && !d.GetEndPoint(1).IsAlmostEqualTo(c.GetEndPoint(1)))
                        {
                            Curve newcurve = Line.CreateBound(p1, p0) as Curve;
                            bounarycurvelist[i] = newcurve;
                            nxi = true;
                            break;
                        }
                    }
                    if (nxi == true)
                    {
                        nx = true;
                        break;
                    }
                }
            }
            while (nx == true);

            //极小误差校正
            double tormax = 0.01;
            double tormin = 0.0000000000000001;
            Boolean correctcontinue = false;
            int cal = 0;
            do
            {
                cal++;
                correctcontinue = false;
                List<int> delcurve_index_list = new List<int>();
                List<Curve> newcurve_list = new List<Curve>();
                for (int i = 0; i <= bounarycurvelist.Count - 2; i++)
                {
                    Curve c = bounarycurvelist[i];
                    if (!(c is Line))
                        continue;
                    XYZ newpoint = c.GetEndPoint(1);
                    double delta_x = Math.Abs(c.GetEndPoint(0).X - c.GetEndPoint(1).X);
                    double delta_y = Math.Abs(c.GetEndPoint(0).Y - c.GetEndPoint(1).Y);
                    if (delta_x < tormax && delta_x > tormin)
                    {
                        newpoint = new XYZ(c.GetEndPoint(0).X, c.GetEndPoint(1).Y, c.GetEndPoint(1).Z);
                        Curve newcurve_x = Line.CreateBound(c.GetEndPoint(0), newpoint);
                        bounarycurvelist[i] = newcurve_x;
                        Curve newcurve_next = Line.CreateBound(newpoint, bounarycurvelist[i + 1].GetEndPoint(1));
                        bounarycurvelist[i + 1] = newcurve_next;
                        correctcontinue = true;
                    }
                    if (delta_y < tormax && delta_y > tormin)
                    {
                        newpoint = new XYZ(c.GetEndPoint(1).X, c.GetEndPoint(0).Y, c.GetEndPoint(1).Z);
                        Curve newcurve_x = Line.CreateBound(c.GetEndPoint(0), newpoint);
                        bounarycurvelist[i] = newcurve_x;
                        Curve newcurve_next = Line.CreateBound(newpoint, bounarycurvelist[i + 1].GetEndPoint(1));
                        bounarycurvelist[i + 1] = newcurve_next;
                        correctcontinue = true;
                    }
                }
            }
            while (correctcontinue == true || cal <= bounarycurvelist.Count);

            //清理临时数据
            //Transaction transaction542 = new Transaction(doc, "yy"); transaction542.Start();
            //doc.Delete(area.Id);  //主程序后面要用到，在主程序里删
            //transaction542.Commit();

            return bounarycurvelist;
        }

        //求链接底图中，pick的线条（如果是PolyLine 输出的是离拾取点最近的那段线）
        public Curve CurvefromPick_noPolyLine(ExternalCommandData CommandData, Reference pickReference)
        {
            Curve curve = null;
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            XYZ pickpoint = pickReference.GlobalPoint;
            pickpoint = new XYZ(pickpoint.X, pickpoint.Y, doc.ActiveView.GenLevel.Elevation);
            if (doc.GetElement(pickReference) is ImportInstance)
            {
                ImportInstance importInstance = doc.GetElement(pickReference) as ImportInstance;
                Transform tf = importInstance.GetTotalTransform();
                Options options = Revit.Create.NewGeometryOptions();
                options.ComputeReferences = true;
                //由于涉及到嵌套图块，直接点选取得的线条可能不对，所以直接全部遍历。
                foreach (GeometryObject geometryObj in importInstance.get_Geometry(options))
                {
                    if (geometryObj is GeometryInstance)
                    {
                        GeometryInstance geometryInstance = geometryObj as GeometryInstance;
                        foreach (GeometryObject symbolObject in geometryInstance.SymbolGeometry)
                        {
                            if (symbolObject is GeometryInstance)
                            {
                                GeometryInstance symbolInstance = symbolObject as GeometryInstance;
                                GeometryElement geoObjtmp = symbolInstance.GetInstanceGeometry();
                                IEnumerator enumeratorobj = geoObjtmp.GetEnumerator();
                                {
                                    while (enumeratorobj.MoveNext())
                                    {
                                        GeometryObject obj2 = enumeratorobj.Current as GeometryObject;
                                        if (obj2 is Line)
                                        {
                                            Line newLinetmp = obj2 as Line;
                                            Curve curvetmp = newLinetmp.CreateTransformed(tf);
                                            XYZ p1 = new XYZ(curvetmp.GetEndPoint(0).X, curvetmp.GetEndPoint(0).Y, pickpoint.Z);
                                            XYZ p2 = new XYZ(curvetmp.GetEndPoint(1).X, curvetmp.GetEndPoint(1).Y, pickpoint.Z);
                                            if (p1.DistanceTo(p2) < 0.001)
                                                continue;
                                            curvetmp = Line.CreateBound(p1, p2);
                                            if (curvetmp.Distance(pickpoint) <= 0.1)
                                            {
                                                curve = curvetmp;
                                                break;
                                            }
                                        }
                                        if (obj2 is Arc)
                                        {
                                            Arc arctmp = (obj2 as Arc).CreateTransformed(tf) as Arc;
                                            XYZ center = new XYZ(arctmp.Center.X, arctmp.Center.Y, pickpoint.Z);

                                            if (Math.Abs(center.DistanceTo(pickpoint) - arctmp.Radius) < 0.1)
                                            {
                                                curve = arctmp;
                                                break;
                                            }
                                        }
                                        if (obj2 is PolyLine)
                                        {
                                            PolyLine pline = obj2 as PolyLine;
                                            for (int i = 0; i <= pline.NumberOfCoordinates - 2; i++)
                                            {
                                                Line newLinetmp = Line.CreateBound(pline.GetCoordinate(i), pline.GetCoordinate(i + 1));
                                                Curve curvetmp = newLinetmp.CreateTransformed(tf);  //链接底图可能被移动旋转过，要用tf转换
                                                XYZ p1 = curvetmp.GetEndPoint(0);
                                                XYZ p2 = curvetmp.GetEndPoint(1);
                                                p1 = new XYZ(p1.X, p1.Y, pickpoint.Z);
                                                p2 = new XYZ(p2.X, p2.Y, pickpoint.Z);
                                                if (p1.DistanceTo(p2) < 0.001)
                                                    continue;
                                                curvetmp = Line.CreateBound(p1, p2);

                                                if (curvetmp.Distance(pickpoint) <= 0.1)
                                                {
                                                    curve = curvetmp;
                                                    break;
                                                }
                                            }
                                        }
                                        if (curve != null)
                                            break;
                                    }
                                }
                            }
                            if (curve != null)
                                break;
                        }
                    }
                    if (curve != null)
                        break;
                }

            }
            return curve;
        }

        //求链接底图中，pick的线条（如果是PolyLine 输出的是线段list）
        public List<Curve> CurvelistfromPick_yesPolyLine(ExternalCommandData CommandData, Reference pickReference)
        {
            List<Curve> curvelist = new List<Curve>();
            //Curve curve = null;
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            XYZ pickpoint = pickReference.GlobalPoint;
            pickpoint = new XYZ(pickpoint.X, pickpoint.Y, doc.ActiveView.GenLevel.Elevation);

            if (doc.GetElement(pickReference) is ImportInstance)
            {
                ImportInstance importInstance = doc.GetElement(pickReference) as ImportInstance;
                Transform tf = importInstance.GetTotalTransform();
                foreach (GeometryObject geometryObj in importInstance.get_Geometry(new Options()))
                {
                    if (!(geometryObj is GeometryInstance))
                        continue;
                    GeometryInstance geometryInstance = geometryObj as GeometryInstance;
                    foreach (GeometryObject symbolObject in geometryInstance.SymbolGeometry)
                    {
                        if (!(symbolObject is GeometryInstance))
                            continue;
                        GeometryInstance symbolInstance = symbolObject as GeometryInstance;
                        GeometryElement geoObjtmp = symbolInstance.GetInstanceGeometry();
                        IEnumerator enumeratorobj = geoObjtmp.GetEnumerator();
                        {
                            while (enumeratorobj.MoveNext())
                            {
                                GeometryObject obj2 = enumeratorobj.Current as GeometryObject;
                                if (obj2 is Line)
                                {
                                    Line newLinetmp = obj2 as Line;
                                    Curve curvetmp = newLinetmp.CreateTransformed(tf);
                                    XYZ p1 = new XYZ(curvetmp.GetEndPoint(0).X, curvetmp.GetEndPoint(0).Y, pickpoint.Z);
                                    XYZ p2 = new XYZ(curvetmp.GetEndPoint(1).X, curvetmp.GetEndPoint(1).Y, pickpoint.Z);

                                    if (curvetmp.Distance(pickpoint) <= 0.1)
                                    {
                                        curvelist.Add(curvetmp);
                                        break;
                                    }
                                }
                                if (obj2 is Arc)
                                {
                                    Arc arctmp = (obj2 as Arc).CreateTransformed(tf) as Arc;
                                    XYZ center = new XYZ(arctmp.Center.X, arctmp.Center.Y, pickpoint.Z);

                                    if (Math.Abs(center.DistanceTo(pickpoint) - arctmp.Radius) < 0.1)
                                    {
                                        curvelist.Add(arctmp);
                                        break;
                                    }
                                }
                                if (obj2 is PolyLine)
                                {
                                    PolyLine pline = obj2 as PolyLine;
                                    Boolean pick_pline = false;
                                    for (int i = 0; i <= pline.NumberOfCoordinates - 2; i++)
                                    {
                                        Line newLinetmp = Line.CreateBound(pline.GetCoordinate(i), pline.GetCoordinate(i + 1));
                                        Curve curvetmp = newLinetmp.CreateTransformed(tf);  //链接底图可能被移动旋转过，要用tf转换
                                        XYZ p1 = curvetmp.GetEndPoint(0);
                                        XYZ p2 = curvetmp.GetEndPoint(1);
                                        p1 = new XYZ(p1.X, p1.Y, pickpoint.Z);
                                        p2 = new XYZ(p2.X, p2.Y, pickpoint.Z);
                                        curvetmp = Line.CreateBound(p1, p2);

                                        if (curvetmp.Distance(pickpoint) <= 0.1)
                                        {
                                            pick_pline = true;
                                            break;
                                        }
                                    }
                                    if (pick_pline)
                                    {
                                        for (int i = 0; i <= pline.NumberOfCoordinates - 2; i++)
                                        {
                                            Line newLinetmp = null;
                                            Curve curvetmp = null;
                                            try
                                            {
                                                newLinetmp = Line.CreateBound(pline.GetCoordinate(i), pline.GetCoordinate(i + 1));
                                                curvetmp = newLinetmp.CreateTransformed(tf);  //链接底图可能被移动旋转过，要用tf转换
                                                XYZ p1 = curvetmp.GetEndPoint(0);
                                                XYZ p2 = curvetmp.GetEndPoint(1);
                                                p1 = new XYZ(p1.X, p1.Y, pickpoint.Z);
                                                p2 = new XYZ(p2.X, p2.Y, pickpoint.Z);
                                                curvetmp = Line.CreateBound(p1, p2);
                                            }
                                            catch
                                            { }
                                            if (newLinetmp == null)
                                                continue;
                                            curvelist.Add(curvetmp);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return curvelist;
        }

        //求链接底图中，pick的线条所在的CurveLoop，out是否矩形
        public List<Curve> CurveLoop_In_Link(ExternalCommandData CommandData, ImportInstance importInstance, XYZ pickpoint, out Boolean isRectangle)
        {
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            List<Curve> curveloop = new List<Curve>();
            List<Curve> allcurvelist = new List<Curve>();
            Curve curve_pick = null;
            isRectangle = true;
            pickpoint = new XYZ(pickpoint.X, pickpoint.Y, doc.ActiveView.GenLevel.Elevation);

            //记录所有线allcurvelist，拾取线curve_pick
            Options options = CommandData.Application.Application.Create.NewGeometryOptions();
            options.ComputeReferences = true;
            GeometryElement geoElement = importInstance.get_Geometry(options);
            IEnumerator enumeratorObj = geoElement.GetEnumerator();
            {
                while (enumeratorObj.MoveNext())
                {
                    GeometryObject geoObj = enumeratorObj.Current as GeometryObject;
                    if (!(geoObj is GeometryInstance))
                        continue;
                    GeometryInstance gi = geoObj as GeometryInstance;
                    GeometryElement geoObjtmp = (geoObj as GeometryInstance).GetInstanceGeometry();
                    IEnumerator enumeratorObj2 = geoObjtmp.GetEnumerator();
                    {
                        while (enumeratorObj2.MoveNext())
                        {
                            GeometryObject obj2 = enumeratorObj2.Current as GeometryObject;
                            if (obj2 is Line)
                            {
                                Line newLinetmp = null;
                                try
                                {
                                    Line geomLine = obj2 as Line;
                                    XYZ p1 = new XYZ(geomLine.GetEndPoint(0).X, geomLine.GetEndPoint(0).Y, doc.ActiveView.GenLevel.Elevation);
                                    XYZ p2 = new XYZ(geomLine.GetEndPoint(1).X, geomLine.GetEndPoint(1).Y, doc.ActiveView.GenLevel.Elevation);
                                    newLinetmp = Line.CreateBound(p1, p2);
                                }
                                catch { }
                                if (newLinetmp == null)
                                    continue;

                                allcurvelist.Add(newLinetmp);

                                if (newLinetmp.Distance(pickpoint) <= 0.01)
                                    curve_pick = newLinetmp;
                            }

                            if (obj2 is Arc)
                            {
                                Arc arctmp = obj2 as Arc;
                                allcurvelist.Add(arctmp);
                                XYZ checkpoint = new XYZ(pickpoint.X, pickpoint.Y, arctmp.Center.Z);
                                if (Math.Abs(checkpoint.DistanceTo(arctmp.Center) - arctmp.Radius) < 0.1)
                                {
                                    curve_pick = obj2 as Arc;
                                    isRectangle = false;
                                }
                            }

                            if (obj2 is PolyLine)
                            {
                                PolyLine pline = obj2 as PolyLine;
                                for (int i = 0; i <= pline.NumberOfCoordinates - 2; i++)
                                {
                                    Line newLinetmp = null;
                                    try
                                    {
                                        Line geomLine = Line.CreateBound(pline.GetCoordinate(i), pline.GetCoordinate(i + 1));
                                        XYZ p1 = new XYZ(geomLine.GetEndPoint(0).X, geomLine.GetEndPoint(0).Y, doc.ActiveView.GenLevel.Elevation);
                                        XYZ p2 = new XYZ(geomLine.GetEndPoint(1).X, geomLine.GetEndPoint(1).Y, doc.ActiveView.GenLevel.Elevation);
                                        newLinetmp = Line.CreateBound(p1, p2);
                                    }
                                    catch { }
                                    if (newLinetmp == null)
                                        continue;
                                    allcurvelist.Add(newLinetmp);
                                    if (newLinetmp.Distance(pickpoint) <= 0.01)
                                        curve_pick = newLinetmp;
                                }
                            }
                        }
                    }
                }
            }

            //求与curve_pick首尾相连，连成矩形的curvelist
            if (curve_pick == null)
                return new List<Curve>();
            curveloop.Add(curve_pick);
            if (isRectangle)
            {
                for (int r = 0; r <= 2; r++)
                {
                    for (int i = 0; i <= allcurvelist.Count - 1; i++)
                    {
                        Curve curve = allcurvelist[i];

                        if (curve.Intersect(curveloop[r]) != SetComparisonResult.Overlap)  //相交就是Overlap
                            continue;

                        if (curve.GetEndPoint(0).DistanceTo(curveloop[r].GetEndPoint(1)) < 0.001)
                        {
                            double d = curve.GetEndPoint(1).DistanceTo(curveloop[r].GetEndPoint(0));
                            if (Math.Abs(curve.Length * curve.Length + curveloop[r].Length * curveloop[r].Length - d * d) < 0.001)
                            {
                                curveloop.Add(curve);
                                break;
                            }
                        }
                        if (curve.GetEndPoint(1).DistanceTo(curveloop[r].GetEndPoint(1)) < 0.001)
                        {
                            double d = curve.GetEndPoint(0).DistanceTo(curveloop[r].GetEndPoint(0));
                            if (Math.Abs(curve.Length * curve.Length + curveloop[r].Length * curveloop[r].Length - d * d) < 0.001)
                            {
                                curveloop.Add(curve);
                                break;
                            }
                        }
                    }
                    if (curveloop.Count == r + 1)  //没有新增
                    {
                        break;
                    }
                }

                if (curveloop.Count < 4)
                    return new List<Curve>();

                double d1 = curveloop[3].GetEndPoint(0).DistanceTo(curveloop[0].GetEndPoint(0));
                double d2 = curveloop[3].GetEndPoint(0).DistanceTo(curveloop[1].GetEndPoint(0));
                double d3 = curveloop[3].GetEndPoint(1).DistanceTo(curveloop[0].GetEndPoint(0));
                double d4 = curveloop[3].GetEndPoint(1).DistanceTo(curveloop[1].GetEndPoint(0));

                if (Math.Min(Math.Min(d1, d2), Math.Min(d3, d4)) < 0.001)
                    return curveloop;
                else
                    return new List<Curve>();
            }
            else
            {
                return curveloop;
            }
        }

        //求链接底图中，指定名称的图层所有连成矩形或单个圆的CurveLoop
        public List<List<Curve>> CurveLoopList_Rec_In_Link(ExternalCommandData CommandData, ImportInstance importInstance, string layername)
        {
            Autodesk.Revit.DB.Document doc = CommandData.Application.ActiveUIDocument.Document;
            List<List<Curve>> curveloop_list = new List<List<Curve>>();
            List<Curve> allcurvelist = new List<Curve>();

            //记录所有线allcurvelist，拾取线curve_pick
            Options options = CommandData.Application.Application.Create.NewGeometryOptions();
            options.ComputeReferences = true;
            GeometryElement geoElement = importInstance.get_Geometry(options);
            IEnumerator enumeratorObj = geoElement.GetEnumerator();
            {
                while (enumeratorObj.MoveNext())
                {
                    GeometryObject geoObj = enumeratorObj.Current as GeometryObject;
                    //try
                    //{
                    //    GraphicsStyle gs = doc.GetElement(geoObj.GraphicsStyleId) as GraphicsStyle;
                    //    MessageBox.Show("gs.GraphicsStyleCategory.Name" + "\n" + gs.GraphicsStyleCategory.Name, "向日葵", MessageBoxButtons.OK);
                    //    if (layername != gs.GraphicsStyleCategory.Name)  //判断图层
                    //        continue;
                    //}
                    //catch
                    //{
                    //    MessageBox.Show("没有图层" + "\n" + "OK", "向日葵", MessageBoxButtons.OK);
                    //    continue;
                    //}
                    if (!(geoObj is GeometryInstance))
                        continue;
                    GeometryInstance gi = geoObj as GeometryInstance;
                    GeometryElement geoObjtmp = (geoObj as GeometryInstance).GetInstanceGeometry();
                    IEnumerator enumeratorObj2 = geoObjtmp.GetEnumerator();
                    {
                        while (enumeratorObj2.MoveNext())
                        {
                            GeometryObject obj2 = enumeratorObj2.Current as GeometryObject;
                            try
                            {
                                GraphicsStyle gs2 = doc.GetElement(obj2.GraphicsStyleId) as GraphicsStyle;
                                //MessageBox.Show("gs2.GraphicsStyleCategory.Name" + "\n" + gs2.GraphicsStyleCategory.Name, "向日葵", MessageBoxButtons.OK);
                                if (layername != gs2.GraphicsStyleCategory.Name)  //判断图层
                                    continue;
                            }
                            catch
                            {
                                //MessageBox.Show("没有图层" + "\n" + "OK2", "向日葵", MessageBoxButtons.OK);
                                continue;
                            }
                            if (obj2 is Line)
                            {
                                Line newLinetmp = null;
                                try
                                {
                                    Line geomLine = obj2 as Line;
                                    XYZ p1 = new XYZ(geomLine.GetEndPoint(0).X, geomLine.GetEndPoint(0).Y, doc.ActiveView.GenLevel.Elevation);
                                    XYZ p2 = new XYZ(geomLine.GetEndPoint(1).X, geomLine.GetEndPoint(1).Y, doc.ActiveView.GenLevel.Elevation);
                                    newLinetmp = Line.CreateBound(p1, p2);
                                }
                                catch { }
                                if (newLinetmp == null)
                                    continue;
                                allcurvelist.Add(newLinetmp);
                            }

                            if (obj2 is Arc)   //判断是否圆，是的话直接放入curveloop
                            {
                                Arc arctmp = obj2 as Arc;
                                if (arctmp.IsCyclic)
                                {
                                    List<Curve> curveloop = new List<Curve>();
                                    curveloop.Add(arctmp);
                                    curveloop_list.Add(curveloop);
                                }
                            }

                            if (obj2 is PolyLine)
                            {
                                PolyLine pline = obj2 as PolyLine;
                                for (int i = 0; i <= pline.NumberOfCoordinates - 2; i++)
                                {
                                    Line newLinetmp = null;
                                    try
                                    {
                                        Line geomLine = Line.CreateBound(pline.GetCoordinate(i), pline.GetCoordinate(i + 1));
                                        XYZ p1 = new XYZ(geomLine.GetEndPoint(0).X, geomLine.GetEndPoint(0).Y, doc.ActiveView.GenLevel.Elevation);
                                        XYZ p2 = new XYZ(geomLine.GetEndPoint(1).X, geomLine.GetEndPoint(1).Y, doc.ActiveView.GenLevel.Elevation);
                                        newLinetmp = Line.CreateBound(p1, p2);
                                    }
                                    catch { }
                                    if (newLinetmp == null)
                                        continue;
                                    allcurvelist.Add(newLinetmp);
                                }
                            }
                        }
                    }
                }
            }

            //求首尾相连，连成矩形的curvelist
            List<int> done_list = new List<int>();//记录已check的curve索引
            for (int i = 0; i <= allcurvelist.Count - 2; i++)
            {
                if (done_list.Contains(i))
                    continue;
                Curve curve_pick = allcurvelist[i];
                List<Curve> curveloop = new List<Curve>();
                curveloop.Add(curve_pick);
                List<int> done_tmp_list = new List<int>();
                done_tmp_list.Add(i);
                for (int r = 0; r <= 2; r++)
                {
                    for (int j = i + 1; j <= allcurvelist.Count - 1; j++)
                    {
                        if (done_list.Contains(j))
                            continue;
                        Curve curve = allcurvelist[j];
                        if (curve.Intersect(curveloop[r]) != SetComparisonResult.Overlap)  //相交就是Overlap
                            continue;

                        if (curve.GetEndPoint(0).DistanceTo(curveloop[r].GetEndPoint(1)) < 0.001)
                        {
                            double d = curve.GetEndPoint(1).DistanceTo(curveloop[r].GetEndPoint(0));
                            if (Math.Abs(curve.Length * curve.Length + curveloop[r].Length * curveloop[r].Length - d * d) < 0.001)
                            {
                                curveloop.Add(curve);
                                done_tmp_list.Add(j);
                                break;
                            }
                        }
                        if (curve.GetEndPoint(1).DistanceTo(curveloop[r].GetEndPoint(1)) < 0.001)
                        {
                            double d = curve.GetEndPoint(0).DistanceTo(curveloop[r].GetEndPoint(0));
                            if (Math.Abs(curve.Length * curve.Length + curveloop[r].Length * curveloop[r].Length - d * d) < 0.001)
                            {
                                curveloop.Add(curve);
                                done_tmp_list.Add(j);
                                break;
                            }
                        }
                    }
                    if (curveloop.Count == r + 1)  //没有新增
                        break;
                }
                if (curveloop.Count == 4)
                {
                    double d1 = curveloop[3].GetEndPoint(0).DistanceTo(curveloop[0].GetEndPoint(0));
                    double d2 = curveloop[3].GetEndPoint(0).DistanceTo(curveloop[1].GetEndPoint(0));
                    double d3 = curveloop[3].GetEndPoint(1).DistanceTo(curveloop[0].GetEndPoint(0));
                    double d4 = curveloop[3].GetEndPoint(1).DistanceTo(curveloop[1].GetEndPoint(0));

                    if (Math.Min(Math.Min(d1, d2), Math.Min(d3, d4)) < 0.001)
                    {
                        curveloop_list.Add(curveloop);
                        foreach (int r in done_tmp_list)
                            done_list.Add(r);
                    }
                }
            }
            return curveloop_list;
        }

        //求链接底图中，拾取的图块名称，如果不是图块则返回""。输出该图块的transform。
        public string BlockName_PickIn_Link(ImportInstance importInstance, XYZ pickpoint, out Transform tf_block)
        {
            string blockname = "";
            tf_block = null;
            Transform tf = importInstance.GetTotalTransform();
            foreach (GeometryObject geometryObj in importInstance.get_Geometry(new Options()))
            {
                if (geometryObj is GeometryInstance)
                {
                    GeometryInstance geometryInstance = geometryObj as GeometryInstance;
                    foreach (GeometryObject symbolObject in geometryInstance.SymbolGeometry)
                    {
                        if (symbolObject is GeometryInstance)
                        {
                            GeometryInstance symbolInstance = symbolObject as GeometryInstance;
                            GeometryElement geoObjtmp = symbolInstance.GetInstanceGeometry();
                            IEnumerator enumeratorobj = geoObjtmp.GetEnumerator();
                            {
                                while (enumeratorobj.MoveNext())
                                {
                                    GeometryObject obj = enumeratorobj.Current as GeometryObject;
                                    if (obj is Line)
                                    {
                                        Line newLinetmp = obj as Line;
                                        Curve curvetmp = newLinetmp.CreateTransformed(tf);
                                        XYZ p1 = new XYZ(curvetmp.GetEndPoint(0).X, curvetmp.GetEndPoint(0).Y, pickpoint.Z);
                                        XYZ p2 = new XYZ(curvetmp.GetEndPoint(1).X, curvetmp.GetEndPoint(1).Y, pickpoint.Z);
                                        if (p1.DistanceTo(p2) > 0.001)
                                        {
                                            curvetmp = Line.CreateBound(p1, p2);
                                        }
                                        if (curvetmp.Distance(pickpoint) <= 0.1)
                                        {
                                            blockname = symbolInstance.Symbol.Name;   //图块名
                                            tf_block = symbolInstance.Transform;
                                            break;
                                        }
                                    }
                                    if (obj is Arc)
                                    {
                                        Arc arctmp = (obj as Arc).CreateTransformed(tf) as Arc;
                                        XYZ center = new XYZ(arctmp.Center.X, arctmp.Center.Y, pickpoint.Z);

                                        if (Math.Abs(center.DistanceTo(pickpoint) - arctmp.Radius) < 0.1)
                                        {
                                            blockname = symbolInstance.Symbol.Name;   //图块名
                                            tf_block = symbolInstance.Transform;
                                            break;
                                        }
                                    }
                                    if (obj is PolyLine)
                                    {
                                        PolyLine pline = obj as PolyLine;
                                        for (int i = 0; i <= pline.NumberOfCoordinates - 2; i++)
                                        {
                                            Line newLinetmp = Line.CreateBound(pline.GetCoordinate(i), pline.GetCoordinate(i + 1));
                                            Curve curvetmp = newLinetmp.CreateTransformed(tf);  //链接底图可能被移动旋转过，要用tf转换
                                            XYZ p1 = curvetmp.GetEndPoint(0);
                                            XYZ p2 = curvetmp.GetEndPoint(1);
                                            p1 = new XYZ(p1.X, p1.Y, pickpoint.Z);
                                            p2 = new XYZ(p2.X, p2.Y, pickpoint.Z);
                                            if (p1.DistanceTo(p2) > 0.001)
                                            {
                                                curvetmp = Line.CreateBound(p1, p2);
                                            }

                                            if (curvetmp.Distance(pickpoint) <= 0.1)
                                            {
                                                blockname = symbolInstance.Symbol.Name;   //图块名
                                                tf_block = symbolInstance.Transform;
                                                break;
                                            }
                                        }
                                    }
                                    if (blockname != "")
                                        break;
                                }
                            }
                        }
                        if (blockname != "")
                            break;
                    }
                }
                if (blockname != "")
                    break;
            }
            return blockname;
        }

        //求链接底图中，指定名称的所有图块，其transform的list
        public List<Transform> Transform_BlockIn_Link(ImportInstance importInstance, string blockname)
        {
            List<Transform> tf_list = new List<Transform>();
            //Transform tf = importInstance.GetTotalTransform();
            //不考虑importInstance的整体transform
            foreach (GeometryObject geometryObj in importInstance.get_Geometry(new Options()))
            {
                if (geometryObj is GeometryInstance)
                {
                    GeometryInstance geometryInstance = geometryObj as GeometryInstance;
                    foreach (GeometryObject symbolObject in geometryInstance.SymbolGeometry)
                    {
                        if (symbolObject is GeometryInstance)
                        {
                            GeometryInstance symbolInstance = symbolObject as GeometryInstance;
                            //GeometryElement geoObjtmp = symbolInstance.GetInstanceGeometry();
                            if (symbolInstance.Symbol.Name == blockname)
                            {
                                tf_list.Add(symbolInstance.Transform);
                                //MessageBox.Show((symbolInstance.SymbolGeometry as GeometryInstance).Transform.Origin + "\n" + geometryInstance.Transform.Origin, "uBIM", MessageBoxButtons.OK);
                            }
                        }
                    }
                }
            }
            return tf_list;
        }

        //求内建参数string
        public string BuildinParameterName(Element e, string pname)
        {
            string str = "";
            foreach (BuiltInParameter bip in Enum.GetValues(typeof(BuiltInParameter)))
            {
                Parameter p = e.get_Parameter(bip);
                if (null != p)
                {
                    if (p.Definition.Name == pname)
                        str = bip.ToString();
                }
            }
            return str;
        }
    }

    /// <summary>
    /// 构件过滤器
    /// </summary>
    public class Searcher
    {
        /// <summary>
        /// 收集所有标高构件并排序
        /// </summary>
        /// <param name="docc"></param>
        /// <returns></returns>
        public static IList<Element> SortLevel(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> LevelList = new FilteredElementCollector(docc).OfClass(typeof(Level)).ToElements();
            if (LevelList.Count > 1)
            {
                double[] levelValue = new double[LevelList.Count];
                for (int i = 0; i < LevelList.Count; i++)
                    levelValue.SetValue((LevelList[i] as Level).Elevation, i);
                SortList(levelValue, LevelList);
            }
            return LevelList;
        }
        public static IEnumerable<T> SortList<T>(double[] key, IEnumerable<T> list)
        {
            if (key.Length != list.Count())
            {
                throw new Exception("Key and List have different lengths.");
            }
            else
            {
                double[] destinationArray = new double[key.Length];
                Array.Copy(key, destinationArray, key.Length);
                T[] items = list.ToArray();
                Array.Sort<double, T>(destinationArray, items);
                return items.AsEnumerable();
            }
        }

        public static IList<Element> ImportInstance(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> importList = new FilteredElementCollector(docc, docc.ActiveView.Id).OfClass(typeof(ImportInstance)).ToElements();
            return importList;
        }

        public static IList<Element> Material(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> materialList = new FilteredElementCollector(docc).OfClass(typeof(Material)).ToElements();
            return materialList;
        }

        public static IList<Element> PipeType(Autodesk.Revit.DB.Document docc)
        {
            FilteredElementCollector collectorPT = new FilteredElementCollector(docc);
            ElementClassFilter pipetypefilter = new ElementClassFilter(typeof(PipeType));
            IList<Element> ptset = collectorPT.WherePasses(pipetypefilter).ToElements();
            return ptset;
        }

        public static IList<Element> PipeSystemType(Autodesk.Revit.DB.Document docc)
        {
            FilteredElementCollector collectorpst = new FilteredElementCollector(docc);
            ElementClassFilter pipesystemtypefilter = new ElementClassFilter(typeof(PipingSystemType));
            IList<Element> pstset = collectorpst.WherePasses(pipesystemtypefilter).ToElements();
            return pstset;
        }

        //仅限矩形风管
        public static IList<Element> DuctType_Rec(Autodesk.Revit.DB.Document docc)
        {
            FilteredElementCollector collectorDT = new FilteredElementCollector(docc);
            ElementClassFilter ducttypefilter = new ElementClassFilter(typeof(DuctType));
            IList<Element> dtset = collectorDT.WherePasses(ducttypefilter).ToElements();
            IList<Element> jxdtset = new List<Element>();

            foreach (Element e in dtset)
            {
                DuctType dt = e as DuctType;
                string shape = dt.get_Parameter(BuiltInParameter.ALL_MODEL_FAMILY_NAME).AsString();
                if (shape == "矩形风管")
                    jxdtset.Add(e);
            }
            return jxdtset;
        }

        public static IList<Element> CableType(Autodesk.Revit.DB.Document docc)
        {
            FilteredElementCollector collectorCT = new FilteredElementCollector(docc);
            ElementClassFilter cabletypefilter = new ElementClassFilter(typeof(CableTrayType));
            IList<Element> cableset = collectorCT.WherePasses(cabletypefilter).ToElements();
            return cableset;
        }

        public static IList<Element> LinkDocList(Autodesk.Revit.DB.Document docc)
        {
            FilteredElementCollector link_collector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            link_collector.OfClass(typeof(RevitLinkInstance));
            IList<Element> linkdoc_list = link_collector.ToList();
            return linkdoc_list;
        }

        public static IList<Element> MechanicalSystemtType(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> mechanicalsystemtype_list = new FilteredElementCollector(docc).OfClass(typeof(MechanicalSystemType)).ToElements();
            return mechanicalsystemtype_list;
        }

        public static IList<Element> BeamInstance(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            if (findincurrentview)
            {
                FilteredElementCollector BCollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
                BCollector.OfCategory(BuiltInCategory.OST_StructuralFraming).OfClass(typeof(FamilyInstance));
                IList<Element> BInstanceList = BCollector.ToElements();
                return BInstanceList;
            }
            else
            {
                FilteredElementCollector BCollector = new FilteredElementCollector(docc);
                BCollector.OfCategory(BuiltInCategory.OST_StructuralFraming).OfClass(typeof(FamilyInstance));
                IList<Element> BInstanceList = BCollector.ToElements();
                return BInstanceList;
            }
        }

        public static IList<Element> ColumnInstance(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            if (findincurrentview)
            {
                FilteredElementCollector CCollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
                CCollector.OfCategory(BuiltInCategory.OST_StructuralColumns).OfClass(typeof(FamilyInstance));
                IList<Element> CInstanceList = CCollector.ToElements();
                return CInstanceList;
            }
            else
            {
                FilteredElementCollector CCollector = new FilteredElementCollector(docc);
                CCollector.OfCategory(BuiltInCategory.OST_StructuralColumns).OfClass(typeof(FamilyInstance));
                IList<Element> CInstanceList = CCollector.ToElements();
                return CInstanceList;
            }
        }

        public static IList<Element> WallInstance(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            if (findincurrentview)
            {
                FilteredElementCollector Wallcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
                Wallcollector.OfCategory(BuiltInCategory.OST_Walls).OfClass(typeof(Wall));
                IList<Element> WallList = Wallcollector.ToElements();
                return WallList;
            }
            else
            {
                FilteredElementCollector Wallcollector = new FilteredElementCollector(docc);
                Wallcollector.OfCategory(BuiltInCategory.OST_Walls).OfClass(typeof(Wall));
                IList<Element> WallList = Wallcollector.ToElements();
                return WallList;
            }
        }

        public static IList<Element> FloorInstance(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            if (findincurrentview)
            {
                FilteredElementCollector Floorcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
                Floorcollector.OfCategory(BuiltInCategory.OST_Floors);
                IList<Element> FloorList = Floorcollector.ToElements();
                return FloorList;
            }
            else
            {
                FilteredElementCollector Floorcollector = new FilteredElementCollector(docc);
                Floorcollector.OfCategory(BuiltInCategory.OST_Floors);
                IList<Element> FloorList = Floorcollector.ToElements();
                return FloorList;
            }

        }

        public static IList<Element> FindBeamFamily(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> BCollection = new List<Element>();
            FilteredElementCollector FilterFamily = new FilteredElementCollector(docc);
            FilterFamily.OfClass(typeof(Family));
            IList<Element> FamilyCollection = FilterFamily.ToElements();
            for (int i = 0; i < FamilyCollection.Count; i++)
            {
                Family familytmp = FamilyCollection[i] as Family;
                if (familytmp.FamilyCategory.Name == "结构框架")
                    BCollection.Add(FamilyCollection[i]);
            }
            return BCollection;
        }

        public static IList<Element> FindColumnFamily(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> CCollection = new List<Element>();
            FilteredElementCollector FilterFamily = new FilteredElementCollector(docc);
            FilterFamily.OfClass(typeof(Family));
            IList<Element> FamilyCollection = FilterFamily.ToElements();
            for (int i = 0; i < FamilyCollection.Count; i++)
            {
                Family familytmp = FamilyCollection[i] as Family;
                if (familytmp.FamilyCategory.Name == "结构柱")
                    CCollection.Add(FamilyCollection[i]);
            }
            return CCollection;
        }

        //找风口族
        public static IList<Element> FindAirTerminalFamily(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> CCollection = new List<Element>();
            FilteredElementCollector FilterFamily = new FilteredElementCollector(docc);
            FilterFamily.OfClass(typeof(Family));
            IList<Element> FamilyCollection = FilterFamily.ToElements();
            for (int i = 0; i < FamilyCollection.Count; i++)
            {
                Family familytmp = FamilyCollection[i] as Family;
                if (familytmp.FamilyCategory.Name == "风道末端")
                    CCollection.Add(FamilyCollection[i]);
            }
            return CCollection;
        }

        public static IList<Element> FindGeneralFamily(Autodesk.Revit.DB.Document docc)
        {
            IList<Element> GCollection = new List<Element>();
            IList<Element> FamilyCollection = (new FilteredElementCollector(docc)).OfClass(typeof(Family)).ToElements();
            for (int i = 0; i < FamilyCollection.Count; i++)
            {
                Family familytmp = FamilyCollection[i] as Family;
                if (familytmp.FamilyCategory.Name == "常规模型")
                    GCollection.Add(FamilyCollection[i]);
            }
            return GCollection;
        }

        public static IList<Element> FindDoorInstance(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            if (findincurrentview)
            {
                FilteredElementCollector Doorcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
                Doorcollector.OfCategory(BuiltInCategory.OST_Doors);
                IList<Element> DoorList = Doorcollector.ToElements();
                return DoorList;
            }
            else
            {
                FilteredElementCollector Doorcollector = new FilteredElementCollector(docc);
                Doorcollector.OfCategory(BuiltInCategory.OST_Doors);
                IList<Element> DoorList = Doorcollector.ToElements();
                return DoorList;
            }
        }

        public static IList<Element> FindWindowInstance(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            if (findincurrentview)
            {
                FilteredElementCollector Windowcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
                Windowcollector.OfCategory(BuiltInCategory.OST_Windows);
                IList<Element> WindowList = Windowcollector.ToElements();
                return WindowList;
            }
            else
            {
                FilteredElementCollector Windowcollector = new FilteredElementCollector(docc);
                Windowcollector.OfCategory(BuiltInCategory.OST_Windows);
                IList<Element> WindowList = Windowcollector.ToElements();
                return WindowList;
            }
        }

        public static IList<Element> FindPipe(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            FilteredElementCollector Pipecollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                Pipecollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            Pipecollector.OfClass(typeof(Pipe));
            IList<Element> PipeList = Pipecollector.ToElements();
            return PipeList;
        }

        //管件、管道附件、喷头、管道保温
        public static IList<Element> FindPipeXG(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            FilteredElementCollector PipeFittingcollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                PipeFittingcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            PipeFittingcollector.OfCategory(BuiltInCategory.OST_PipeFitting).OfClass(typeof(FamilyInstance));
            IList<Element> PipeFittingList = PipeFittingcollector.ToElements();

            FilteredElementCollector PipeInsulationcollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                PipeInsulationcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            PipeInsulationcollector.OfCategory(BuiltInCategory.OST_PipeInsulations);
            IList<Element> PipeInsulationList = PipeInsulationcollector.ToElements();
            IList<Element> PipeInsulationList_NotType = new List<Element>();
            foreach (Element e in PipeInsulationList)
            {
                if (e.GetType().Name != "PipeInsulationType")
                    PipeInsulationList_NotType.Add(e);
            }

            FilteredElementCollector PipeAccessorycollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                PipeAccessorycollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            PipeAccessorycollector.OfCategory(BuiltInCategory.OST_PipeAccessory).OfClass(typeof(FamilyInstance));
            IList<Element> PipeAccessoryList = PipeAccessorycollector.ToElements();

            FilteredElementCollector PipeSprinklerscollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                PipeSprinklerscollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            PipeSprinklerscollector.OfCategory(BuiltInCategory.OST_Sprinklers).OfClass(typeof(FamilyInstance));
            IList<Element> PipeSprinklersList = PipeSprinklerscollector.ToElements();

            IList<Element> all_list = new List<Element>();
            foreach (Element e in PipeFittingList)
                all_list.Add(e);
            foreach (Element e in PipeInsulationList_NotType)
                all_list.Add(e);
            foreach (Element e in PipeAccessoryList)
                all_list.Add(e);
            foreach (Element e in PipeSprinklersList)
                all_list.Add(e);

            return all_list;
        }

        //pipe保温层
        public static IList<Element> PipeinsulationType(Autodesk.Revit.DB.Document docc)
        {
            FilteredElementCollector pinsulation_collector = new FilteredElementCollector(docc);
            ElementClassFilter pinsulation_typefilter = new ElementClassFilter(typeof(PipeInsulationType));
            IList<Element> pinsulationset = pinsulation_collector.WherePasses(pinsulation_typefilter).ToElements();
            return pinsulationset;
        }

        public static IList<Element> FindDuct(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            FilteredElementCollector Ductcollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                Ductcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            Ductcollector.OfClass(typeof(Duct));
            IList<Element> DuctList = Ductcollector.ToElements();
            return DuctList;
        }

        //风管管件、风管附件、末端、风管保温
        public static IList<Element> FindDuctXG(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            FilteredElementCollector DuctFittingcollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                DuctFittingcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            DuctFittingcollector.OfCategory(BuiltInCategory.OST_DuctFitting).OfClass(typeof(FamilyInstance));
            IList<Element> DuctFittingList = DuctFittingcollector.ToElements();

            FilteredElementCollector DuctInsulationcollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                DuctInsulationcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            DuctInsulationcollector.OfCategory(BuiltInCategory.OST_DuctInsulations);
            IList<Element> DuctInsulationList = DuctInsulationcollector.ToElements();
            IList<Element> DuctInsulationList_NotType = new List<Element>();
            foreach (Element e in DuctInsulationList)
            {
                if (e.GetType().Name != "DuctInsulationType")
                    DuctInsulationList_NotType.Add(e);
            }

            FilteredElementCollector DuctAccessorycollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                DuctAccessorycollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            DuctAccessorycollector.OfCategory(BuiltInCategory.OST_DuctAccessory).OfClass(typeof(FamilyInstance));
            IList<Element> DuctAccessoryList = DuctAccessorycollector.ToElements();

            FilteredElementCollector DuctTerminalcollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                DuctTerminalcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            DuctTerminalcollector.OfCategory(BuiltInCategory.OST_DuctTerminal).OfClass(typeof(FamilyInstance));
            IList<Element> DuctTerminalList = DuctTerminalcollector.ToElements();

            IList<Element> all_list = new List<Element>();
            foreach (Element e in DuctFittingList)
                all_list.Add(e);
            foreach (Element e in DuctInsulationList_NotType)
                all_list.Add(e);
            foreach (Element e in DuctAccessoryList)
                all_list.Add(e);
            foreach (Element e in DuctTerminalList)
                all_list.Add(e);

            return all_list;
        }

        //duct保温层
        public static IList<Element> DuctinsulationType(Autodesk.Revit.DB.Document docc)
        {
            FilteredElementCollector dinsulation_collector = new FilteredElementCollector(docc);
            ElementClassFilter dinsulation_typefilter = new ElementClassFilter(typeof(DuctInsulationType));
            IList<Element> dinsulationset = dinsulation_collector.WherePasses(dinsulation_typefilter).ToElements();
            return dinsulationset;
        }

        public static IList<Element> FindCableTray(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            FilteredElementCollector CableTrayXGcollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                CableTrayXGcollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            CableTrayXGcollector.OfCategory(BuiltInCategory.OST_CableTrayFitting).OfClass(typeof(FamilyInstance));
            IList<Element> CableTrayXGList = CableTrayXGcollector.ToElements();
            return CableTrayXGList;
        }

        //桥架配件
        public static IList<Element> FindCableTrayXG(Autodesk.Revit.DB.Document docc, Boolean findincurrentview)
        {
            FilteredElementCollector CableTraycollector = new FilteredElementCollector(docc);
            if (findincurrentview)
                CableTraycollector = new FilteredElementCollector(docc, docc.ActiveView.Id);
            CableTraycollector.OfClass(typeof(CableTray));
            IList<Element> CableTrayList = CableTraycollector.ToElements();
            return CableTrayList;
        }

        //这是啥东西
        public static IList<FamilySymbol> FindFamilysymbol(Autodesk.Revit.DB.Document docc, IList<Element> ElementCollection)
        {
            IList<FamilySymbol> FSCollction = new List<FamilySymbol>();
            for (int i = 0; i < ElementCollection.Count; i++)
            {
                Family familytmp = ElementCollection[i] as Family;
                IEnumerator<ElementId> symbolsItor = familytmp.GetFamilySymbolIds().GetEnumerator();
                symbolsItor.Reset();
                while (symbolsItor.MoveNext())
                {
                    FamilySymbol familysymbol = docc.GetElement(symbolsItor.Current) as FamilySymbol;
                    FSCollction.Add(familysymbol);
                }
            }
            return FSCollction;
        }

        //a Family----its Symbols这又是啥东西
        public static IList<IList> Family_symbolList(Autodesk.Revit.DB.Document docc, IList<Element> ElementCollection)
        {
            IList<IList> FSCollction = new List<IList>();
            for (int i = 0; i < ElementCollection.Count; i++)
            {
                Family familytmp = ElementCollection[i] as Family;
                IList<FamilySymbol> symbolList = new List<FamilySymbol>();
                IEnumerator<ElementId> symbolsItor = familytmp.GetFamilySymbolIds().GetEnumerator();
                symbolsItor.Reset();
                while (symbolsItor.MoveNext())
                {
                    FamilySymbol familysymbol = docc.GetElement(symbolsItor.Current) as FamilySymbol;
                    symbolList.Add(familysymbol);
                }
                FSCollction.Add(symbolList.ToList());
            }
            return FSCollction;
        }

        public static IList<string> FindFamilyName(Autodesk.Revit.DB.Document docc, IList<Element> ElementCollection)
        {
            IList<string> familyName = new List<string>();
            for (int i = 0; i < ElementCollection.Count; i++)
            {
                Family familytmp = ElementCollection[i] as Family;
                if (!familyName.Contains(familytmp.Name))
                    familyName.Add(familytmp.Name);
            }
            return familyName;
        }

        //Find symbols' name which have the same family(return string)
        public static IList<string> TypeName_ofSameFamily(Autodesk.Revit.DB.Document docc, string str, IList<Element> ElementCollection)
        {
            IList<string> typeName = new List<string>();
            for (int i = 0; i < ElementCollection.Count; i++)
            {
                Family familytmp = ElementCollection[i] as Family;
                if (familytmp.Name == str)
                {
                    IEnumerator<ElementId> symbolsItor = familytmp.GetFamilySymbolIds().GetEnumerator();
                    symbolsItor.Reset();
                    while (symbolsItor.MoveNext())
                    {
                        FamilySymbol familysymbol = docc.GetElement(symbolsItor.Current) as FamilySymbol;
                        typeName.Add(familysymbol.Name);
                    }
                }
            }
            return typeName;
        }

        //Find symbols which have the same family(return familysymbol)
        public static IList<FamilySymbol> Familysymbol_ofSameFamily(Autodesk.Revit.DB.Document docc, string str, IList<Element> ElementCollection)
        {
            IList<FamilySymbol> familysymbolList = new List<FamilySymbol>();
            for (int i = 0; i < ElementCollection.Count; i++)
            {
                Family familytmp = ElementCollection[i] as Family;
                if (familytmp.Name == str)
                {
                    IEnumerator<ElementId> symbolsItor = familytmp.GetFamilySymbolIds().GetEnumerator();
                    symbolsItor.Reset();
                    while (symbolsItor.MoveNext())
                    {
                        FamilySymbol familysymbol = docc.GetElement(symbolsItor.Current) as FamilySymbol;
                        familysymbolList.Add(familysymbol);
                    }
                }
            }
            return familysymbolList;
        }
    }

    /// <summary>
    /// 通用Revit异常处理
    /// </summary>
    public class FailureHandler : IFailuresPreprocessor
    {
        public string ErrorMessage { set; get; }
        public string ErrorSeverity { set; get; }

        public FailureHandler()
        {
            ErrorMessage = "";
            ErrorSeverity = "";
        }

        public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
        {
            IList<FailureMessageAccessor> failureMessages = failuresAccessor.GetFailureMessages();
            foreach (FailureMessageAccessor failureMessageAccessor in failureMessages)
            {
                FailureDefinitionId id = failureMessageAccessor.GetFailureDefinitionId();
                try
                {
                    ErrorMessage = failureMessageAccessor.GetDescriptionText();
                }
                catch
                {
                    ErrorMessage = "Unknown Error";
                }

                try
                {
                    FailureSeverity failureSeverity = failureMessageAccessor.GetSeverity();
                    ErrorSeverity = failureSeverity.ToString();

                    if (failureSeverity == FailureSeverity.Warning)
                    {
                        //if (ErrorMessage == "已删除所有关联的零件，并使原始图元在视图中不可见。")    //饰面层命令
                        //{
                        //    failuresAccessor.DeleteWarning(failureMessageAccessor);
                        //    return FailureProcessingResult.ProceedWithCommit;
                        //}
                        if (ErrorMessage == "高亮显示的墙要附着到高亮显示的目标上，但未与此目标接触。")
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage == "线稍微偏离了轴，可能会导致不精确。")
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage.Contains("高亮显示的墙重叠"))
                        {
                            failuresAccessor.DeleteWarning(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }
                        else
                            failuresAccessor.DeleteWarning(failureMessageAccessor);
                    }
                    else
                    {
                        if (ErrorMessage == "无法剪切连接的图元。")
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage.Contains("连接无效的反方向"))
                        {
                            return FailureProcessingResult.ProceedWithRollBack;
                        }

                        if (ErrorMessage.Contains("不能剪切任何对象"))
                        {
                            //墙上如果有门，断开墙体后会弹出上述提示，应点击“删除”，以删除多余的门窗。
                            IList<ElementId> id_list = failureMessageAccessor.GetFailingElementIds().ToList();
                            foreach (ElementId idd in failureMessageAccessor.GetFailingElementIds().ToList())
                            {
                                if (failuresAccessor.GetDocument().GetElement(idd) is Wall)
                                    id_list.Remove(idd);
                            }

                            failuresAccessor.DeleteElements(id_list);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage == "此零件无法与其他零件进行合并。") //饰面层命令
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage == "编辑模型将导致删除某些零件。") //饰面层命令
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage.Contains("无法使图元保持连接"))
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage == "不能进行拉伸。" || ErrorMessage == "线太短。" || ErrorMessage == "立面轮廓草图无效。")
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithRollBack;
                        }

                        if (ErrorMessage.Contains("不满足限制条件"))
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage.Contains("不能满足定义高亮显示的图元的绘制限制条件"))
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage.Contains("不能生成墙"))
                        {
                            return FailureProcessingResult.ProceedWithCommit;
                        }

                        if (ErrorMessage.Contains("无法生成类型"))
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.Continue;
                        }
                        else
                        {
                            failuresAccessor.ResolveFailure(failureMessageAccessor);
                            return FailureProcessingResult.Continue;
                        }
                    }
                }
                catch
                {

                }
            }
            return FailureProcessingResult.Continue;
        }
    }

    /// <summary>
    /// Revit异常处理
    /// 专为“风管/管道已修改为位于导致连接无效的反方向上。”点击删除按钮
    /// </summary>
    public class FailureHandler_DeleteElement : IFailuresPreprocessor
    {
        public string ErrorMessage { set; get; }
        public string ErrorSeverity { set; get; }

        public FailureHandler_DeleteElement()
        {
            ErrorMessage = "";
            ErrorSeverity = "";
        }
        
        public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
        {
            IList<FailureMessageAccessor> failureMessages = failuresAccessor.GetFailureMessages();
            foreach (FailureMessageAccessor failureMessageAccessor in failureMessages)
            {
                FailureDefinitionId id = failureMessageAccessor.GetFailureDefinitionId();
                try
                {
                    ErrorMessage = failureMessageAccessor.GetDescriptionText();
                    if (ErrorMessage == "风管/管道已修改为位于导致连接无效的反方向上。")
                    {
                        IList<ElementId> idlist = new List<ElementId>();
                        foreach (ElementId idtmp in failureMessageAccessor.GetFailingElementIds())
                            idlist.Add(idtmp);
                        failuresAccessor.DeleteElements(idlist);
                        return FailureProcessingResult.ProceedWithCommit;
                    }
                }
                catch
                { }
            }
            return FailureProcessingResult.Continue;
        }
    }

    /// <summary>
    /// 选择过滤器
    /// </summary>
    public class uBIMSelectionFilter
    {
        /// <summary>
        /// 填充区域 
        /// </summary>
        public class HatchSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element.GetType().Name == "FilledRegion")
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }
        
        /// <summary>
        /// 线性构件
        /// </summary>
        public class LinearSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                LocationCurve lc = element.Location as LocationCurve;
                if (lc != null)
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }
        
        /// <summary>
        /// 管线及保温，未加线管
        /// </summary>
        public class MEPSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element is Pipe || element is Duct || element is CableTray || element is PipeInsulation || element is DuctInsulation)
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }

        /// <summary>
        /// FamilyInstance过滤器
        /// </summary>
        public class FamilyInstanceSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element.GetType().Name == "FamilyInstance")
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }

        /// <summary>
        /// 梁过滤器
        /// </summary>
        public class BeamSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element.GetType().Name == "FamilyInstance")
                {
                    if ((element as FamilyInstance).Symbol.Family.FamilyCategory.Name == "结构框架")
                        return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }
        
        /// <summary>
        /// Pipe过滤器
        /// </summary>
        public class PipeSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element.GetType().Name == "Pipe")
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }

        /// <summary>
        /// Pipe及保温过滤器
        /// </summary>
        public class PipeAndInsulationSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element is Pipe || element is PipeInsulation)
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }

        /// <summary>
        /// 墙
        /// </summary>
        public class WallSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element is Wall)
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }

        /// <summary>
        /// 墙、板、FamilyInstance
        /// </summary>
        public class HoleElementSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element is Wall || element is Floor || element is FamilyInstance)
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return false;
            }
        }

        /// <summary>
        /// dwg链接底图
        /// </summary>
        public class DwgLinkSF : ISelectionFilter
        {
            public bool AllowElement(Element element)
            {
                if (element.GetType().Name == "ImportInstance")
                {
                    return true;
                }
                return false;
            }
            public bool AllowReference(Reference refer, XYZ point)
            {
                return true;
            }
        }

    }

    /// <summary>
    /// 生成管连接件
    /// </summary>
    public class CreateFitting
    {
        private int zz;
        private int zz0;
        private double tol;
        BasicCode bc = new BasicCode();

        public double Tol
        {
            get
            {
                return tol;
            }
            set
            {
                tol = value;
            }
        }

        public Connector[] recordConnector(IList<Element> eleList)
        {
            zz = eleList.Count;
            zz0 = 1;
            Connector[] conns = new Connector[2 * zz + 1];
            if (eleList[0] is Pipe)
            {
                foreach (Element ele in eleList)
                {
                    Pipe pipe = ele as Pipe;
                    try
                    {
                        ConnectorSetIterator csi = pipe.ConnectorManager.Connectors.ForwardIterator();
                        while (csi.MoveNext())
                        {
                            if ((csi.Current as Connector).IsConnected == true)
                                continue;
                            conns[zz0] = csi.Current as Connector;
                            zz0 += 1;
                        }
                    }
                    catch { }
                }
            }
            if (eleList[0] is Duct)
            {
                foreach (Element ele in eleList)
                {
                    Duct duct = ele as Duct;
                    try
                    {
                        ConnectorSetIterator csi = duct.ConnectorManager.Connectors.ForwardIterator();
                        while (csi.MoveNext())
                        {
                            if ((csi.Current as Connector).IsConnected == true)
                                continue;
                            conns[zz0] = csi.Current as Connector;
                            zz0 += 1;
                        }
                    }
                    catch { }
                }
            }
            if (eleList[0] is CableTray)
            {
                foreach (Element ele in eleList)
                {
                    CableTray cable = ele as CableTray;
                    try
                    {
                        ConnectorSetIterator csi = cable.ConnectorManager.Connectors.ForwardIterator();
                        while (csi.MoveNext())
                        {
                            if ((csi.Current as Connector).IsConnected == true)
                                continue;
                            conns[zz0] = csi.Current as Connector;
                            zz0 += 1;
                        }
                    }
                    catch { }
                }
            }

            return conns;
        }
        public List<XYZ> recordSamePoint(Connector[] conns, double tolerance)
        {
            tol = tolerance;
            List<XYZ> samePoint = new List<XYZ>();
            int yn = 0;
            for (int i = 1; i <= zz0 - 2; i++)
            {
                XYZ point_i = conns[i].Origin;
                for (int j = i + 1; j < zz0 - 1; j++)
                {
                    XYZ point_j = conns[j].Origin;

                    if (point_i.DistanceTo(point_j) < tolerance)
                    {
                        if (samePoint.Count == 0)
                            samePoint.Add(point_i);
                        else
                        {
                            yn = 0;
                            foreach (XYZ point in samePoint)
                            {
                                if (point.DistanceTo(point_i) < tolerance)
                                {
                                    yn = 1;
                                }
                            }
                            if (yn == 0)
                                samePoint.Add(point_i);
                        }
                    }
                }
            }
            return samePoint;
        }

        //遍历每个点，看这些点附近有几个Connector，根据个数生成管件
        public List<FamilyInstance> createNewFitting(Autodesk.Revit.DB.Document doc, List<XYZ> samePoint, Connector[] conns)
        {
            List<FamilyInstance> newfitting_list = new List<FamilyInstance>();
            for (int i = 0; i < samePoint.Count; i++)
            {
                FamilyInstance newfitting = null;

                List<Connector> connspt = new List<Connector>();
                #region 求connector数量
                for (int j = 1; j <= zz0 - 1; j++)
                {
                    if (conns[j].Origin.DistanceTo(samePoint[i]) > tol)
                        continue;
                    Boolean same_owner = false;
                    Connector same1 = null;
                    Connector same2 = null;
                    int same_int = -1;
                    for (int k = 0; k < connspt.Count; k++)
                    {
                        Connector ctmp = connspt[k];
                        if (ctmp.Owner.Id == (conns[j].Owner.Id))
                        {
                            same_owner = true;
                            same1 = ctmp;
                            same2 = conns[j];
                            same_int = k;
                            break;
                        }
                    }
                    if (same_owner == true)
                    {
                        if (same1.Origin.DistanceTo(samePoint[i]) > same2.Origin.DistanceTo(samePoint[i]))
                        {
                            connspt.RemoveAt(same_int);
                            connspt.Add(same2);
                        }
                    }
                    else
                        connspt.Add(conns[j]);
                }
                #endregion

                Transaction transaction = new Transaction(doc, "yy"); transaction.Start();
                #region 2 connectors
                if (connspt.Count == 2)
                {
                    Connector cc1 = connspt[0];
                    Connector cc2 = connspt[1];

                    //要判断两个connector是否反向、不共线
                    string test = "";
                    Curve curve1 = null;
                    Curve curve2 = null;
                    if (cc1.Owner is Pipe || cc1.Owner is Duct || cc1.Owner is CableTray)
                    {
                        MEPCurve mc = cc1.Owner as MEPCurve;
                        curve1 = (mc.Location as LocationCurve).Curve;
                    }
                    if (cc2.Owner is Pipe || cc2.Owner is Duct || cc2.Owner is CableTray)
                    {
                        MEPCurve mc = cc2.Owner as MEPCurve;
                        curve2 = (mc.Location as LocationCurve).Curve;
                    }

                    if (curve1 != null && curve2 != null)
                    {
                        XYZ start1 = cc1.Origin;
                        XYZ end1 = curve1.GetEndPoint(0);
                        if (start1.DistanceTo(end1) < 0.001)
                            end1 = curve1.GetEndPoint(1);

                        XYZ start2 = cc2.Origin;
                        XYZ end2 = curve2.GetEndPoint(0);
                        if (start2.DistanceTo(end2) < 0.001)
                            end2 = curve2.GetEndPoint(1);

                        XYZ d1 = (end1 - start1) / curve1.Length;
                        XYZ d2 = (end2 - start2) / curve2.Length;
                        if (d1.DistanceTo(d2) < 0.001)  //同向，平行线，跳过
                            test = "同向";
                        else if (d1.DistanceTo(d2) > 1.999)  //反向，考虑共线
                            test = "反向";
                        else
                            test = "成角度";
                    }

                    if (test != "同向")
                    {
                        int m = 0;
                        try
                        {
                            newfitting = doc.Create.NewTransitionFitting(connspt[0], connspt[1]);
                        }
                        catch
                        {
                            m = 1;
                        }
                        if (m == 1)
                        {
                            try
                            {
                                newfitting = doc.Create.NewElbowFitting(connspt[0], connspt[1]);
                            }
                            catch
                            {
                                m = 3;
                            }
                        }
                        if (m == 3)
                        {
                            MessageBox.Show("无法生成弯头。", "uBIM", MessageBoxButtons.OK);
                        }
                    }
                }
                #endregion
                #region 3 connectors
                if (connspt.Count == 3)
                {

                    double dd1 = Math.Max(connspt[0].Radius, connspt[1].Radius);
                    double dd = Math.Max(connspt[2].Radius, dd1);
                    int m = 0;
                    try
                    {
                        newfitting = doc.Create.NewTeeFitting(connspt[0], connspt[1], connspt[2]);
                        newfitting.LookupParameter("公称半径").Set(dd);
                    }
                    catch { m = 1; }

                    if (m == 1)
                    {
                        try
                        {
                            newfitting = doc.Create.NewTeeFitting(connspt[2], connspt[1], connspt[0]);
                            newfitting.LookupParameter("公称半径").Set(dd);
                        }
                        catch { m = 2; }
                    }
                    if (m == 2)
                    {
                        try
                        {
                            newfitting = doc.Create.NewTeeFitting(connspt[0], connspt[2], connspt[1]);
                            newfitting.LookupParameter("公称半径").Set(dd);
                        }
                        catch { m = 3; }
                    }
                    if (m == 3)
                    {
                        MessageBox.Show("无法生成三通。", "uBIM", MessageBoxButtons.OK);
                    }
                }
                #endregion
                #region 4 connectors
                if (connspt.Count == 4)
                {
                    double dd1 = Math.Max((connspt[0] as Connector).Radius, (connspt[1] as Connector).Radius);
                    double dd2 = Math.Max((connspt[2] as Connector).Radius, (connspt[3] as Connector).Radius);
                    double dd = Math.Max(dd1, dd2);
                    int m = 0;
                    try
                    {
                        newfitting = doc.Create.NewCrossFitting(connspt[0] as Connector, connspt[1] as Connector, connspt[2] as Connector, connspt[3] as Connector);
                        newfitting.LookupParameter("公称半径").Set(dd);
                    }
                    catch { m = 1; }
                    if (m == 1)
                    {
                        try
                        {
                            newfitting = doc.Create.NewCrossFitting(connspt[0] as Connector, connspt[2] as Connector, connspt[1] as Connector, connspt[3] as Connector);
                            newfitting.LookupParameter("公称半径").Set(dd);
                        }
                        catch { m = 2; }
                    }
                    if (m == 2)
                    {
                        try
                        {
                            newfitting = doc.Create.NewCrossFitting(connspt[0] as Connector, connspt[3] as Connector, connspt[1] as Connector, connspt[2] as Connector);
                            newfitting.LookupParameter("公称半径").Set(dd);
                        }
                        catch { m = 3; }
                    }
                    if (m == 3)
                    {
                        MessageBox.Show("无法生成四通。", "uBIM", MessageBoxButtons.OK);
                    }
                }
                #endregion
                transaction.Commit();

                if (newfitting != null)
                    newfitting_list.Add(newfitting);
            }
            return newfitting_list;
        }

        //遍历每个点，看这些点附近有几个Connector，根据个数生成管件——变高专用，delta为变高值，返回最小变高值
        public List<FamilyInstance> createNewFitting_BG(Autodesk.Revit.DB.Document doc, List<XYZ> samePoint, Connector[] conns, double delta, out double min)
        {
            List<FamilyInstance> newfitting_list = new List<FamilyInstance>();
            min = 0;
            for (int i = 0; i < samePoint.Count; i++)
            {
                FamilyInstance newfitting = null;
                List<Connector> connspt = new List<Connector>();
                #region 求connector数量
                for (int j = 1; j <= zz0 - 1; j++)
                {
                    if (conns[j].Origin.DistanceTo(samePoint[i]) > tol)
                        continue;
                    Boolean same_owner = false;
                    Connector same1 = null;
                    Connector same2 = null;
                    int same_int = -1;
                    for (int k = 0; k < connspt.Count; k++)
                    {
                        Connector ctmp = connspt[k];
                        if (ctmp.Owner.Id == (conns[j].Owner.Id))
                        {
                            same_owner = true;
                            same1 = ctmp;
                            same2 = conns[j];
                            same_int = k;
                            break;
                        }
                    }
                    if (same_owner == true)
                    {
                        if (same1.Origin.DistanceTo(samePoint[i]) > same2.Origin.DistanceTo(samePoint[i]))
                        {
                            connspt.RemoveAt(same_int);
                            connspt.Add(same2);
                        }
                    }
                    else
                        connspt.Add(conns[j]);
                }
                #endregion
                Transaction transaction = new Transaction(doc, "yy");
                bc.SetTransaction(transaction);
                transaction.Start();
                #region 2 connectors
                if (connspt.Count == 2)
                {
                    int m = 0;
                    try
                    {
                        newfitting = doc.Create.NewTransitionFitting(connspt[0], connspt[1]);
                    }
                    catch
                    {
                        m = 1;
                    }

                    if (m == 1)
                    {
                        try
                        {
                            newfitting = doc.Create.NewElbowFitting(connspt[0], connspt[1]);
                        }
                        catch
                        {
                            m = 3;
                        }
                        if (newfitting != null)
                        {
                            ConnectorSetIterator Elbowconcsi = newfitting.MEPModel.ConnectorManager.Connectors.ForwardIterator();
                            XYZ[] conxyz = new XYZ[2];
                            int ii = 0;
                            while (Elbowconcsi.MoveNext())
                            {
                                conxyz[ii] = (Elbowconcsi.Current as Connector).Origin;
                                ii += 1;
                            }
                            Double deltatmp = Math.Abs(conxyz[1].Z - conxyz[0].Z);
                            if (Math.Abs(delta) < deltatmp * 2 + 0.03)
                            {
                                min = Math.Ceiling((deltatmp * 2 * 304.8 + 10) / 10) * 10 / 304.8;
                                MessageBox.Show("管件要求至少变高：" + (Math.Ceiling((deltatmp * 2 * 304.8 + 10) / 10) * 10).ToString("0") + "。", "创筑", MessageBoxButtons.OK);
                                transaction.RollBack();
                                return new List<FamilyInstance>();
                            }
                        }
                    }
                    if (m == 3)
                    {
                        MessageBox.Show("无法生成弯头。", "uBIM", MessageBoxButtons.OK);
                    }
                }
                #endregion

                transaction.Commit();

                if (newfitting != null)
                    newfitting_list.Add(newfitting);
            }
            return newfitting_list;
        }

        //风管生大小头
        public void createNewFitting_doubleLine(Autodesk.Revit.DB.Document doc, Connector[] conns, double tolerance)
        {
            List<Connector> twoConnector = new List<Connector>();
            //int yn = 0;
            //for (int i = 1; i <= zz0 - 2; i++)
            //{
            //    XYZ point_i = conns[i].Origin;
            //    for (int j = i + 1; j < zz0 - 1; j++)
            //    {
            //        XYZ point_j = conns[j].Origin;
            //        if (point_i.DistanceTo(point_j) < tolerance)
            //        {
            //            twoConnector.Add(conns[i]);
            //            twoConnector.Add(conns[j]);
            //            yn = 1;
            //            break;
            //        }
            //    }
            //    if (yn == 1)
            //        break;
            //}
            double MinDistance = double.MaxValue;
            for (int i = 1; i <= zz0 - 2; i++)
            {
                XYZ point_i = conns[i].Origin;
                for (int j = i + 1; j <= zz0 - 1; j++)
                {
                    XYZ point_j = conns[j].Origin;
                    double distmp = point_i.DistanceTo(point_j);
                    if (distmp < MinDistance)
                    {
                        MinDistance = distmp;
                    }
                }
            }

            for (int i = 1; i <= zz0 - 2; i++)
            {
                XYZ point_i = conns[i].Origin;
                for (int j = i + 1; j <= zz0 - 1; j++)
                {
                    XYZ point_j = conns[j].Origin;
                    double distmp = point_i.DistanceTo(point_j);
                    if (distmp == MinDistance)
                    {
                        twoConnector.Add(conns[i]);
                        twoConnector.Add(conns[j]);
                    }
                }
            }

            if (twoConnector.Count == 2)
            {
                Transaction transaction = new Transaction(doc, "yy"); transaction.Start();
                try
                {
                    doc.Create.NewTransitionFitting(twoConnector[0], twoConnector[1]);

                }
                catch
                {
                    MessageBox.Show("无法生成大小头。", "uBIM", MessageBoxButtons.OK);
                }
                transaction.Commit();
            }
        }
    }

    /// <summary>
    /// 点的计算
    /// </summary>
    public class XYZMath
    {
        /// <summary>
        /// 精确度
        /// </summary>
        const double PRECISION = 0.0000000001;

        /// <summary>
        /// 计算两点的中点
        /// </summary>
        /// <param name="first">第一个点</param>
        /// <param name="second">第二个点</param>
        /// <returns></returns>
        public static Autodesk.Revit.DB.XYZ FindMidPoint(Autodesk.Revit.DB.XYZ first, Autodesk.Revit.DB.XYZ second)
        {
            double x = (first.X + second.X) / 2;
            double y = (first.Y + second.Y) / 2;
            double z = (first.Z + second.Z) / 2;
            Autodesk.Revit.DB.XYZ midPoint = new Autodesk.Revit.DB.XYZ(x, y, z);
            return midPoint;
        }

        /// <summary>
        /// 计算两点的距离
        /// </summary>
        /// <param name="first">第一个点</param>
        /// <param name="second">第二个点</param>
        /// <returns></returns>
        public static double FindDistance(Autodesk.Revit.DB.XYZ first, Autodesk.Revit.DB.XYZ second)
        {
            double x = first.X - second.X;
            double y = first.Y - second.Y;
            double z = first.Z - second.Z;
            return Math.Sqrt(x * x + y * y + z * z);
        }

        /// <summary>
        /// 计算第一个点至第二个点的方向单位向量
        /// </summary>
        /// <param name="first">第一个点</param>
        /// <param name="second">第二个点</param>
        /// <returns></returns>
        public static Autodesk.Revit.DB.XYZ FindDirection(Autodesk.Revit.DB.XYZ first, Autodesk.Revit.DB.XYZ second)
        {
            double x = second.X - first.X;
            double y = second.Y - first.Y;
            double z = second.Z - first.Z;
            double distance = FindDistance(first, second);
            Autodesk.Revit.DB.XYZ direction = new Autodesk.Revit.DB.XYZ(x / distance, y / distance, z / distance);
            return direction;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="viewDirection"></param>
        /// <returns></returns>
        public static Autodesk.Revit.DB.XYZ FindRightDirection(Autodesk.Revit.DB.XYZ viewDirection)
        {

            double x = -viewDirection.Y;
            double y = viewDirection.X;
            double z = viewDirection.Z;
            Autodesk.Revit.DB.XYZ direction = new Autodesk.Revit.DB.XYZ(x, y, z);
            return direction;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="viewDirection"></param>
        /// <returns></returns>
        public static Autodesk.Revit.DB.XYZ FindUpDirection(Autodesk.Revit.DB.XYZ viewDirection)
        {
            Autodesk.Revit.DB.XYZ direction = new Autodesk.Revit.DB.XYZ(0, 0, 1);
            return direction;
        }
    }
}
