Example #1
0
        /* abandoned for now
         * public static Curve ExtendLineToBox(Curve line, List<Curve> box)
         * {
         *  Line result = null;
         *  foreach (Curve edge in box)
         *  {
         *      var test = ExtendLine(line, edge);
         *      if (null == test) { continue; }
         *      if (test.Length > line.Length)
         *      {
         *          return result;
         *      }
         *  }
         *  Debug.Print("Failure at line extension to box");
         *  return result;
         * }
         */

        /// <summary>
        /// Fuse two collinear segments if they are joined or almost joined.
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        public static List <Curve> CloseGapAtBreakpoint(List <Curve> lines)
        {
            List <List <Curve> > mergeGroups = new List <List <Curve> >();

            mergeGroups.Add(new List <Curve>()
            {
                lines[0]
            });
            lines.RemoveAt(0);

            while (lines.Count != 0)
            {
                foreach (Line element in lines)
                {
                    int iterCounter = 0;
                    foreach (List <Curve> sublist in mergeGroups)
                    {
                        iterCounter += 1;
                        if (Algorithm.IsLineAlmostSubsetLines(element, sublist))
                        {
                            sublist.Add(element);
                            lines.Remove(element);
                            goto a;
                        }
                        if (iterCounter == mergeGroups.Count)
                        {
                            mergeGroups.Add(new List <Curve>()
                            {
                                element
                            });
                            lines.Remove(element);
                            goto a;
                        }
                    }
                }
                a :;
            }
            Debug.Print("The resulting lines should be " + mergeGroups.Count.ToString());

            List <Curve> mergeLines = new List <Curve>();

            foreach (List <Curve> mergeGroup in mergeGroups)
            {
                if (mergeGroup.Count > 1)
                {
                    Debug.Print("Got lines to be merged " + mergeGroup.Count.ToString());
                    foreach (Line line in mergeGroup)
                    {
                        Debug.Print("Line{0} ({1}, {2}) -> ({3}, {4})", mergeGroup.IndexOf(line), line.GetEndPoint(0).X,
                                    line.GetEndPoint(0).Y, line.GetEndPoint(1).X, line.GetEndPoint(1).Y);
                    }
                    var merged = Algorithm.FuseLines(mergeGroup);
                    mergeLines.Add(merged);
                }
                else
                {
                    mergeLines.Add(mergeGroup[0]);
                }
            }
            return(mergeLines);
        }
Example #2
0
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            AppDomain currentDomain = AppDomain.CurrentDomain;

            currentDomain.AssemblyResolve += new ResolveEventHandler(Misc.LoadFromSameFolder);

            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            View active_view = doc.ActiveView;

            double tolerance = app.ShortCurveTolerance;

            ///////////////////////
            // Pick Import Instance
            ImportInstance import = null;

            try
            {
                Reference r = uidoc.Selection.PickObject(ObjectType.Element, new Util.ElementsOfClassSelectionFilter <ImportInstance>());
                import = doc.GetElement(r) as ImportInstance;
            }
            catch
            {
                return(Result.Cancelled);
            }
            if (import == null)
            {
                System.Windows.MessageBox.Show("CAD not found", "Tips");
                return(Result.Cancelled);
            }


            // Initiate the progress bar
            Views.ProgressBar pb = new Views.ProgressBar("Modeling entire building", "Initiation...", 100);
            if (pb.ProcessCancelled)
            {
                return(Result.Cancelled);
            }


            //////////////////////////////////
            // Check if the families are ready
            pb.CustomizeStatus("Checking families...", 2);
            if (pb.ProcessCancelled)
            {
                return(Result.Cancelled);
            }
            // Consider to add more customized families (in the Setting Panel)
            if (Properties.Settings.Default.name_door == null ||
                Properties.Settings.Default.name_window == null ||
                Properties.Settings.Default.name_columnRect == null ||
                Properties.Settings.Default.name_columnRound == null)
            {
                System.Windows.MessageBox.Show("Please select the column/door/window type in settings", "Tips");
                return(Result.Cancelled);
            }
            //if (!File.Exists(Properties.Settings.Default.url_door) && File.Exists(Properties.Settings.Default.url_window)
            //    && File.Exists(Properties.Settings.Default.url_column))
            //{
            //    System.Windows.MessageBox.Show("Please check the family path is solid", "Tips");
            //    return Result.Cancelled;
            //}
            //Family fColumn, fDoor, fWindow = null;
            //using (Transaction tx = new Transaction(doc, "Load necessary families"))
            //{
            //    tx.Start();
            //    if (!doc.LoadFamily(Properties.Settings.Default.url_column, out fColumn))
            //    {
            //        System.Windows.MessageBox.Show("Please check the column family path is solid", "Tips");
            //        return Result.Cancelled;
            //    }
            //    if (!doc.LoadFamily(Properties.Settings.Default.url_door, out fDoor) ||
            //        !doc.LoadFamily(Properties.Settings.Default.url_window, out fWindow))
            //    {
            //        System.Windows.MessageBox.Show("Please check the door/window family path is solid", "Tips");
            //        return Result.Cancelled;
            //    }
            //    tx.Commit();
            //}

            // Prepare a family for ViewPlan creation
            // It may be a coincidence that the 1st ViewFamilyType is for the FloorPlan
            // Uplift needed here (doomed if it happends to be a CeilingPlan)
            ViewFamilyType viewType = new FilteredElementCollector(doc)
                                      .OfClass(typeof(ViewFamilyType)).First() as ViewFamilyType;

            RoofType roofType = new FilteredElementCollector(doc)
                                .OfClass(typeof(RoofType)).FirstOrDefault <Element>() as RoofType;

            FloorType floorType = new FilteredElementCollector(doc)
                                  .OfClass(typeof(FloorType)).FirstOrDefault <Element>() as FloorType;


            ////////////////////
            // DATA PREPARATIONS
            pb.CustomizeStatus("Processing geometries...", 3);
            if (pb.ProcessCancelled)
            {
                return(Result.Cancelled);
            }
            // Prepare frames and levels
            // Cluster all geometry elements and texts into datatrees
            // Two procedures are intertwined
            List <GeometryObject> dwg_frames = Util.TeighaGeometry.ExtractElement(uidoc, import,
                                                                                  Properties.Settings.Default.layerFrame, "PolyLine"); // framework is polyline by default
            List <GeometryObject> dwg_geos = Util.TeighaGeometry.ExtractElement(uidoc, import);

            // Terminate if no geometry has been found
            if (dwg_geos == null)
            {
                System.Windows.MessageBox.Show("A drawing frame is mandantory", "Tips");
                return(Result.Failed);
            }

            List <PolyLine> closedPolys = new List <PolyLine>();
            List <PolyLine> parentPolys = new List <PolyLine>();

            Debug.Print("Number of geos acting as the framework is " + dwg_frames.Count().ToString());

            if (dwg_frames.Count > 0)
            {
                foreach (var obj in dwg_frames)
                {
                    PolyLine poly = obj as PolyLine;
                    // Draw shattered lines in case the object is a PolyLine
                    if (null != poly)
                    {
                        var vertices = poly.GetCoordinates();
                        if (vertices[0].IsAlmostEqualTo(vertices.Last()))
                        {
                            closedPolys.Add(poly);
                        }
                    }
                }

                for (int i = 0; i < closedPolys.Count(); i++)
                {
                    int judgement = 0;
                    int counter   = 0;
                    for (int j = 0; j < closedPolys.Count(); j++)
                    {
                        if (i != j)
                        {
                            if (!RegionDetect.PolyInPoly(closedPolys[i], RegionDetect.PolyLineToCurveArray(closedPolys[j], tolerance)))
                            {
                                //Debug.Print("Poly inside poly detected");
                                judgement += 1;
                            }
                            counter += 1;
                        }
                    }
                    if (judgement == counter)
                    {
                        parentPolys.Add(closedPolys[i]);
                    }
                }
            }
            else
            {
                Debug.Print("There is no returning of geometries");
            }
            Debug.Print("Got closedPolys: " + closedPolys.Count().ToString());
            Debug.Print("Got parentPolys: " + parentPolys.Count().ToString());


            string path = Util.TeighaText.GetCADPath(uidoc, import);

            Debug.Print("The path of linked CAD file is: " + path);
            List <Util.TeighaText.CADTextModel> texts = Util.TeighaText.GetCADText(path);


            int    level;
            int    levelCounter = 0;
            double floorHeight  = Misc.MmToFoot(Properties.Settings.Default.floorHeight);
            Dictionary <int, PolyLine> frameDict = new Dictionary <int, PolyLine>(); // cache drawing borders
            Dictionary <int, XYZ>      transDict = new Dictionary <int, XYZ>();
            // cache transform vector from the left-bottom corner of the drawing border to the Origin
            Dictionary <int, List <GeometryObject> > geoDict = new Dictionary <int, List <GeometryObject> >();
            // cache geometries of each floorplan
            Dictionary <int, List <Util.TeighaText.CADTextModel> > textDict = new Dictionary <int, List <Util.TeighaText.CADTextModel> >();

            // cache text info of each floorplan

            if (texts.Count > 0)
            {
                foreach (var textmodel in texts)
                {
                    level = Misc.GetLevel(textmodel.Text, "平面图");
                    Debug.Print("Got target label " + textmodel.Text);
                    if (level != -1)
                    {
                        foreach (PolyLine frame in parentPolys)
                        {
                            if (RegionDetect.PointInPoly(RegionDetect.PolyLineToCurveArray(frame, tolerance), textmodel.Location))
                            {
                                XYZ basePt   = Algorithm.BubbleSort(frame.GetCoordinates().ToList())[0];
                                XYZ transVec = XYZ.Zero - basePt;
                                Debug.Print("Add level " + level.ToString() + " with transaction (" +
                                            transVec.X.ToString() + ", " + transVec.Y.ToString() + ", " + transVec.Z.ToString() + ")");
                                if (!frameDict.Values.ToList().Contains(frame))
                                {
                                    frameDict.Add(level, frame);
                                    transDict.Add(level, transVec);
                                    levelCounter += 1;
                                }
                            }
                        }
                    }
                }
                // Too complicated using 2 iterations... uplift needed
                for (int i = 1; i <= levelCounter; i++)
                {
                    textDict.Add(i, new List <Util.TeighaText.CADTextModel>());
                    geoDict.Add(i, new List <GeometryObject>());
                    CurveArray tempPolyArray = RegionDetect.PolyLineToCurveArray(frameDict[i], tolerance);
                    foreach (var textmodel in texts)
                    {
                        if (RegionDetect.PointInPoly(tempPolyArray, textmodel.Location))
                        {
                            textDict[i].Add(textmodel);
                        }
                    }
                    foreach (GeometryObject go in dwg_geos)
                    {
                        XYZ centPt = XYZ.Zero;
                        if (go is Line)
                        {
                            //get the revit model coordinates.
                            Line go_line = go as Line;
                            centPt = (go_line.GetEndPoint(0) + go_line.GetEndPoint(1)).Divide(2);
                        }
                        else if (go is Arc)
                        {
                            Arc go_arc = go as Arc;
                            centPt = go_arc.Center;
                        }
                        else if (go is PolyLine)
                        {
                            PolyLine go_poly = go as PolyLine;
                            centPt = go_poly.GetCoordinate(0);
                        }
                        // Assignment
                        if (RegionDetect.PointInPoly(tempPolyArray, centPt) && centPt != XYZ.Zero)
                        {
                            geoDict[i].Add(go);
                        }
                    }
                }
            }
            Debug.Print("All levels: " + levelCounter.ToString());
            Debug.Print("frameDict: " + frameDict.Count().ToString());
            Debug.Print("transDict: " + transDict.Count().ToString());
            for (int i = 1; i <= levelCounter; i++)
            {
                Debug.Print("geoDict-{0}: {1}", i, geoDict[i].Count().ToString());
            }
            Debug.Print("textDict: " + textDict.Count().ToString() + " " + textDict[1].Count().ToString());


            ////////////////////
            // MAIN TRANSACTIONS

            // Prepare a family and configurations for TextNote (Put it inside transactions)

            /*
             * TextNoteType tnt = new FilteredElementCollector(doc)
             *  .OfClass(typeof(TextNoteType)).First() as TextNoteType;
             * TextNoteOptions options = new TextNoteOptions();
             * options.HorizontalAlignment = HorizontalTextAlignment.Center;
             * options.TypeId = doc.GetDefaultElementTypeId(ElementTypeGroup.TextNoteType);
             * BuiltInParameter paraIndex = BuiltInParameter.TEXT_SIZE;
             * Parameter textSize = tnt.get_Parameter(paraIndex);
             * textSize.Set(0.3); // in feet
             *
             * XYZ centPt = RegionDetect.PolyCentPt(frameDict[i]);
             * TextNoteOptions opts = new TextNoteOptions(tnt.Id);
             *
             * // The note may only show in the current view
             * // no matter we still need it anyway
             * TextNote txNote = TextNote.Create(doc, active_view.Id, centPt, floorView.Name, options);
             * txNote.ChangeTypeId(tnt.Id);
             *
             * // Draw model lines of frames as notation
             * Plane Geomplane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero + transDict[i] + XYZ.BasisZ * (i - 1) * floorHeight);
             * SketchPlane sketch = SketchPlane.Create(doc, Geomplane);
             * CurveArray shatters = RegionDetect.PolyLineToCurveArray(frameDict[i], tolerance);
             * Transform alignModelLine = Transform.CreateTranslation(transDict[i] + XYZ.BasisZ * (i - 1) * floorHeight);
             * foreach (Curve shatter in shatters)
             * {
             *  Curve alignedCrv = shatter.CreateTransformed(alignModelLine);
             *  ModelCurve modelline = doc.Create.NewModelCurve(alignedCrv, sketch) as ModelCurve;
             * }
             */


            // ITERATION FLAG
            for (int i = 1; i <= levelCounter; i++)
            {
                pb.CustomizeStatus("On Floor " + i.ToString() + "... with lines", 5);
                if (pb.ProcessCancelled)
                {
                    return(Result.Cancelled);
                }

                TransactionGroup tg = new TransactionGroup(doc, "Generate on floor-" + i.ToString());
                {
                    try
                    {
                        tg.Start();

                        // MILESTONE
                        // Align the labels to the origin
                        Transform alignment = Transform.CreateTranslation(transDict[i]);
                        foreach (Util.TeighaText.CADTextModel label in textDict[i])
                        {
                            label.Location = label.Location + transDict[i];
                        }

                        // MILESTONE
                        // Sort out lines
                        List <Curve> wallCrvs   = new List <Curve>();
                        List <Curve> columnCrvs = new List <Curve>();
                        List <Curve> doorCrvs   = new List <Curve>();
                        List <Curve> windowCrvs = new List <Curve>();
                        foreach (GeometryObject go in geoDict[i])
                        {
                            var gStyle = doc.GetElement(go.GraphicsStyleId) as GraphicsStyle;
                            if (gStyle.GraphicsStyleCategory.Name == Properties.Settings.Default.layerWall)
                            {
                                if (go.GetType().Name == "Line")
                                {
                                    Curve wallLine = go as Curve;
                                    wallCrvs.Add(wallLine.CreateTransformed(alignment) as Line);
                                }
                                if (go.GetType().Name == "PolyLine")
                                {
                                    CurveArray wallPolyLine_shattered = RegionDetect.PolyLineToCurveArray(go as PolyLine, tolerance);
                                    foreach (Curve crv in wallPolyLine_shattered)
                                    {
                                        wallCrvs.Add(crv.CreateTransformed(alignment) as Line);
                                    }
                                }
                            }
                            if (gStyle.GraphicsStyleCategory.Name == Properties.Settings.Default.layerColumn)
                            {
                                if (go.GetType().Name == "Line")
                                {
                                    Curve columnLine = go as Curve;
                                    columnCrvs.Add(columnLine.CreateTransformed(alignment));
                                }
                                if (go.GetType().Name == "PolyLine")
                                {
                                    CurveArray columnPolyLine_shattered = RegionDetect.PolyLineToCurveArray(go as PolyLine, tolerance);
                                    foreach (Curve crv in columnPolyLine_shattered)
                                    {
                                        columnCrvs.Add(crv.CreateTransformed(alignment));
                                    }
                                }
                            }
                            if (gStyle.GraphicsStyleCategory.Name == Properties.Settings.Default.layerDoor)
                            {
                                Curve    doorCrv = go as Curve;
                                PolyLine poly    = go as PolyLine;
                                if (null != doorCrv)
                                {
                                    doorCrvs.Add(doorCrv.CreateTransformed(alignment));
                                }
                                if (null != poly)
                                {
                                    CurveArray columnPolyLine_shattered = RegionDetect.PolyLineToCurveArray(poly, tolerance);
                                    foreach (Curve crv in columnPolyLine_shattered)
                                    {
                                        doorCrvs.Add(crv.CreateTransformed(alignment) as Line);
                                    }
                                }
                            }
                            if (gStyle.GraphicsStyleCategory.Name == Properties.Settings.Default.layerWindow)
                            {
                                Curve    windowCrv = go as Curve;
                                PolyLine poly      = go as PolyLine;
                                if (null != windowCrv)
                                {
                                    windowCrvs.Add(windowCrv.CreateTransformed(alignment));
                                }
                                if (null != poly)
                                {
                                    CurveArray columnPolyLine_shattered = RegionDetect.PolyLineToCurveArray(poly, tolerance);
                                    foreach (Curve crv in columnPolyLine_shattered)
                                    {
                                        windowCrvs.Add(crv.CreateTransformed(alignment) as Line);
                                    }
                                }
                            }
                        }

                        // MILESTONE
                        // Create additional levels (ignore what's present)
                        // Consider to use sub-transaction here
                        using (var t_level = new Transaction(doc))
                        {
                            t_level.Start("Create levels");
                            Level    floor     = Level.Create(doc, (i - 1) * floorHeight);
                            ViewPlan floorView = ViewPlan.Create(doc, viewType.Id, floor.Id);
                            floorView.Name = "F-" + i.ToString();
                            t_level.Commit();
                        }

                        // Grab the current building level
                        FilteredElementCollector colLevels = new FilteredElementCollector(doc)
                                                             .WhereElementIsNotElementType()
                                                             .OfCategory(BuiltInCategory.INVALID)
                                                             .OfClass(typeof(Level));
                        Level currentLevel = colLevels.LastOrDefault() as Level;
                        // The newly created level will append to the list,
                        // but this is not a safe choice

                        // Sub-transactions are packed within these functions.
                        // The family names should be defined by the user in WPF
                        // MILESTONE
                        pb.CustomizeStatus("On Floor " + i.ToString() + "... with Walls", 90 / levelCounter / 4);
                        if (pb.ProcessCancelled)
                        {
                            return(Result.Cancelled);
                        }
                        CreateWall.Execute(uiapp, wallCrvs, currentLevel, true);

                        // MILESTONE
                        pb.CustomizeStatus("On Floor " + i.ToString() + "... with Columns", 90 / levelCounter / 4);
                        if (pb.ProcessCancelled)
                        {
                            return(Result.Cancelled);
                        }
                        CreateColumn.Execute(app, doc, columnCrvs,
                                             Properties.Settings.Default.name_columnRect,
                                             Properties.Settings.Default.name_columnRound,
                                             currentLevel, true);

                        // MILESTONE
                        pb.CustomizeStatus("On Floor " + i.ToString() + "... with Openings", 90 / levelCounter / 4);
                        if (pb.ProcessCancelled)
                        {
                            return(Result.Cancelled);
                        }
                        CreateOpening.Execute(doc, doorCrvs, windowCrvs, wallCrvs, textDict[i],
                                              Properties.Settings.Default.name_door, Properties.Settings.Default.name_window, currentLevel, true);

                        // Create floor
                        // MILESTONE
                        var footprint = CreateRegion.Execute(doc, wallCrvs, columnCrvs, windowCrvs, doorCrvs);
                        using (var t_floor = new Transaction(doc))
                        {
                            t_floor.Start("Generate Floor");

                            Floor newFloor = doc.Create.NewFloor(footprint, floorType, currentLevel, false, XYZ.BasisZ);
                            newFloor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(0);

                            t_floor.Commit();
                        }

                        // Generate rooms after the topology is established
                        pb.CustomizeStatus("On Floor " + i.ToString() + "... with Rooms", 90 / levelCounter / 4);
                        if (pb.ProcessCancelled)
                        {
                            return(Result.Cancelled);
                        }
                        // MILESTONE
                        using (var t_space = new Transaction(doc))
                        {
                            t_space.Start("Create rooms");

                            doc.Regenerate();

                            PlanTopology planTopology = doc.get_PlanTopology(currentLevel);
                            if (doc.ActiveView.ViewType == ViewType.FloorPlan)
                            {
                                foreach (PlanCircuit circuit in planTopology.Circuits)
                                {
                                    if (null != circuit && !circuit.IsRoomLocated)
                                    {
                                        Room room = doc.Create.NewRoom(null, circuit);
                                        room.LimitOffset = floorHeight;
                                        room.BaseOffset  = 0;
                                        string roomName = "";
                                        foreach (Util.TeighaText.CADTextModel label in textDict[i])
                                        {
                                            if (label.Layer == Properties.Settings.Default.layerSpace)
                                            {
                                                if (room.IsPointInRoom(label.Location + XYZ.BasisZ * (i - 1) * floorHeight))
                                                {
                                                    roomName += label.Text;
                                                }
                                            }
                                        }
                                        if (roomName != "")
                                        {
                                            room.Name = roomName;
                                        }
                                    }
                                }
                            }
                            t_space.Commit();
                        }



                        // Create roof when iterating to the last level
                        // MILESTONE
                        if (i == levelCounter)
                        {
                            using (var t_roof = new Transaction(doc))
                            {
                                t_roof.Start("Create roof");
                                Level    roofLevel = Level.Create(doc, i * floorHeight);
                                ViewPlan floorView = ViewPlan.Create(doc, viewType.Id, roofLevel.Id);
                                floorView.Name = "Roof";

                                ModelCurveArray footPrintToModelCurveMapping = new ModelCurveArray();
                                FootPrintRoof   footprintRoof = doc.Create.NewFootPrintRoof(footprint, roofLevel, roofType,
                                                                                            out footPrintToModelCurveMapping);

                                //ModelCurveArrayIterator iterator = footPrintToModelCurveMapping.ForwardIterator();

                                /*
                                 * iterator.Reset();
                                 * while (iterator.MoveNext())
                                 * {
                                 *  ModelCurve modelCurve = iterator.Current as ModelCurve;
                                 *  footprintRoof.set_DefinesSlope(modelCurve, true);
                                 *  footprintRoof.set_SlopeAngle(modelCurve, 0.5);
                                 * }
                                 */
                                t_roof.Commit();
                            }
                        }
                        tg.Assimilate();
                    }
                    catch
                    {
                        System.Windows.MessageBox.Show("Error", "Tips");
                        tg.RollBack();
                    }
                }
                pb.JobCompleted();
            }

            return(Result.Succeeded);
        }
Example #3
0
        // Main thread
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            View view = doc.ActiveView;

            Selection sel = uidoc.Selection;

            double tolerance = app.ShortCurveTolerance;

            // Pick Import Instance
            ImportInstance import = null;

            try
            {
                Reference r = uidoc.Selection.PickObject(ObjectType.Element, new Util.ElementsOfClassSelectionFilter <ImportInstance>());
                import = doc.GetElement(r) as ImportInstance;
            }
            catch
            {
                return(Result.Cancelled);
            }
            if (import == null)
            {
                System.Windows.MessageBox.Show("CAD not found", "Tips");
                return(Result.Cancelled);
            }

            List <Curve> columnCrvs = Util.TeighaGeometry.ShatterCADGeometry(uidoc, import, "COLUMN", tolerance);
            List <Curve> wallCrvs   = Util.TeighaGeometry.ShatterCADGeometry(uidoc, import, "WALL", tolerance);
            List <Curve> doorCrvs   = Util.TeighaGeometry.ShatterCADGeometry(uidoc, import, "DOOR", tolerance);
            List <Curve> windowCrvs = Util.TeighaGeometry.ShatterCADGeometry(uidoc, import, "WINDOW", tolerance);

            //List<Line> columnLines = Util.CrvsToLines(columnCrvs);
            //List<Line> wallLines = Util.CrvsToLines(wallCrvs);

            // Merge the overlapped wall boundaries
            // Seal the wall boundary by column block
            // INPUT List<Line> wallLines, List<Line> columnLines
            #region PATCH wallLines
            List <Line> patchLines = new List <Line>();
            List <XYZ>  sectPts    = new List <XYZ>();

            // Seal the wall when encountered with column
            foreach (Curve columnCrv in columnCrvs)
            {
                sectPts.Clear();
                foreach (Line wallCrv in wallCrvs)
                {
                    if (!Algorithm.IsParallel(columnCrv, wallCrv))
                    {
                        SetComparisonResult result = wallCrv.Intersect(columnCrv, out IntersectionResultArray results);
                        if (result != SetComparisonResult.Disjoint)
                        {
                            XYZ sectPt = results.get_Item(0).XYZPoint;
                            sectPts.Add(sectPt);
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
                if (sectPts.Count() == 2)
                {
                    patchLines.Add(Line.CreateBound(sectPts[0], sectPts[1]));
                }
                if (sectPts.Count() > 2)  // not sure how to solve this
                {
                    Line minPatch = Line.CreateBound(XYZ.Zero, 10000 * XYZ.BasisX);
                    for (int i = 0; i < sectPts.Count(); i++)
                    {
                        for (int j = i + 1; j < sectPts.Count(); j++)
                        {
                            if (sectPts[i].DistanceTo(sectPts[j]) > 0.001)
                            {
                                Line testPatch = Line.CreateBound(sectPts[i], sectPts[j]);
                                if (testPatch.Length < minPatch.Length)
                                {
                                    minPatch = testPatch;
                                }
                            }
                        }
                    }
                    patchLines.Add(minPatch);
                }
            }

            // Patch for the wall lines
            wallCrvs.AddRange(patchLines);

            // Merge lines when they are parallel and almost intersected (knob)
            List <Curve> mergeLines = CloseGapAtBreakpoint(wallCrvs);

            //
            List <Curve> fixedLines = CloseGapAtCorner(mergeLines);

            #endregion
            // OUTPUT List<Line> fixedLines


            // INPUT List<Line> fixedLines
            #region Cluster the wallLines by hierarchy

            var wallClusters = Algorithm.ClusterByIntersect(fixedLines);
            Debug.Print("{0} clustered wall blocks in total", wallClusters.Count);

            // Generate boundingbox marker for the wall cluster
            List <List <Curve> > wallBlocks = new List <List <Curve> > {
            };
            foreach (List <Curve> cluster in wallClusters)
            {
                List <Curve> clusterCrv = cluster;
                if (null != Algorithm.CreateBoundingBox2D(clusterCrv))
                {
                    wallBlocks.Add(Algorithm.CreateBoundingBox2D(clusterCrv));
                }
            }
            Debug.Print("{0} clustered wall bounding boxes in total", wallBlocks.Count);

            #endregion
            // INPUT List<List< Curve >> wallClusters
            Debug.Print("WALL LINES PATCH & CLUSTERING COMPLETE!");


            // INPUT List<List<Curve>> wallClusters
            #region Iterate the generaion of axis

            // Wall axes
            List <Curve> axes = new List <Curve>();
            double       bias = Misc.MmToFoot(20);
            foreach (List <Curve> wallCluster in wallClusters)
            {
                List <Line> lines = Misc.CrvsToLines(wallCluster);
                for (int i = 0; i < lines.Count; i++)
                {
                    for (int j = 0; j < lines.Count - i; j++)
                    {
                        if (Algorithm.IsParallel(lines[i], lines[i + j]) &&
                            !Algorithm.IsIntersected(lines[i], lines[i + j]))
                        {
                            if (Algorithm.LineSpacing(lines[i], lines[i + j]) < Misc.MmToFoot(200) + bias &&
                                Algorithm.LineSpacing(lines[i], lines[i + j]) > Misc.MmToFoot(200) - bias &&
                                Algorithm.IsShadowing(lines[i], lines[i + j]))
                            {
                                if (Algorithm.GenerateAxis(lines[i], lines[i + j]) != null)
                                {
                                    axes.Add(Algorithm.GenerateAxis(lines[i], lines[i + j]));
                                    Debug.Print("got it!");
                                }
                            }
                        }
                    }
                }
            }
            #endregion
            // OUTPUT List<Line> axes
            Debug.Print("WALL AXIS ITERATION COMPLETE!");


            // INPUT List<Curve> doorCrvs
            // INPUT List<Curve> windowCrvs
            // INPUT List<Line> axes
            #region Merge axis joined/overlapped

            // Door axes
            var doorClusters = Algorithm.ClusterByIntersect(doorCrvs);
            List <List <Curve> > doorBlocks = new List <List <Curve> > {
            };
            foreach (List <Curve> cluster in doorClusters)
            {
                if (null != Algorithm.CreateBoundingBox2D(cluster))
                {
                    doorBlocks.Add(Algorithm.CreateBoundingBox2D(cluster));
                }
            }
            List <Curve> doorAxes = new List <Curve> {
            };
            foreach (List <Curve> doorBlock in doorBlocks)
            {
                List <Curve> doorFrame = new List <Curve> {
                };
                for (int i = 0; i < doorBlock.Count; i++)
                {
                    int         sectCount = 0;
                    List <Line> fenses    = new List <Line>();
                    foreach (Line line in fixedLines)
                    {
                        Curve testCrv = doorBlock[i].Clone();
                        SetComparisonResult result = RegionDetect.ExtendCrv(testCrv, 0.01).Intersect(line,
                                                                                                     out IntersectionResultArray results);
                        if (result == SetComparisonResult.Overlap)
                        {
                            sectCount += 1;
                            fenses.Add(line);
                        }
                    }
                    if (sectCount == 2)
                    {
                        XYZ projecting = fenses[0].Evaluate(0.5, true);
                        XYZ projected  = fenses[1].Project(projecting).XYZPoint;
                        if (fenses[0].Length > fenses[1].Length)
                        {
                            projecting = fenses[1].Evaluate(0.5, true);
                            projected  = fenses[0].Project(projecting).XYZPoint;
                        }
                        Line doorAxis = Line.CreateBound(projecting, projected);
                        doorAxes.Add(doorAxis);
                        //doorAxes.Add(doorBlock[i]);
                    }
                }
            }

            // Window axes
            var windowClusters = Algorithm.ClusterByIntersect(windowCrvs);

            List <List <Curve> > windowBlocks = new List <List <Curve> > {
            };
            foreach (List <Curve> cluster in windowClusters)
            {
                if (null != Algorithm.CreateBoundingBox2D(cluster))
                {
                    windowBlocks.Add(Algorithm.CreateBoundingBox2D(cluster));
                }
            }
            List <Curve> windowAxes = new List <Curve> {
            };
            foreach (List <Curve> windowBlock in windowBlocks)
            {
                Line axis1 = Line.CreateBound((windowBlock[0].GetEndPoint(0) + windowBlock[0].GetEndPoint(1)).Divide(2),
                                              (windowBlock[2].GetEndPoint(0) + windowBlock[2].GetEndPoint(1)).Divide(2));
                Line axis2 = Line.CreateBound((windowBlock[1].GetEndPoint(0) + windowBlock[1].GetEndPoint(1)).Divide(2),
                                              (windowBlock[3].GetEndPoint(0) + windowBlock[3].GetEndPoint(1)).Divide(2));
                if (axis1.Length > axis2.Length)
                {
                    windowAxes.Add(axis1);
                }
                else
                {
                    windowAxes.Add(axis2);
                }
            }


            axes.AddRange(windowAxes);
            axes.AddRange(doorAxes);
            Debug.Print("Checklist for axes: Door-{0}, Window-{1}, All-{2}", doorAxes.Count, windowAxes.Count,
                        axes.Count);
            List <Curve> axesExtended = new List <Curve>();
            foreach (Curve axis in axes)
            {
                axesExtended.Add(Algorithm.ExtendLine(axis, 200));
            }
            // Axis merge
            List <List <Curve> > axisGroups  = Algorithm.ClusterByOverlap(axesExtended);
            List <Curve>         centerLines = new List <Curve>();
            foreach (List <Curve> axisGroup in axisGroups)
            {
                var merged = Algorithm.FuseLines(axisGroup);
                centerLines.Add(merged);
            }

            #endregion
            // OUTPUT List<Line> centerLines
            Debug.Print("WINDOW / DOOR LINES JOINED!");


            // INPUT List<Curve> columnCrvs
            // INPUT List<Line> centerLines
            #region Extend and trim the axis (include column corner)

            List <List <Curve> > columnGroups = Algorithm.ClusterByIntersect(columnCrvs);
            foreach (List <Curve> columnGroup in columnGroups)
            {
                //List<Line> columnGrouplines = Util.CrvsToLines(columnGroup);
                List <Curve> nestLines = new List <Curve>();
                for (int i = 0; i < columnGroup.Count; i++)
                {
                    foreach (Line centerLine in centerLines)
                    {
                        SetComparisonResult result = columnGroup[i].Intersect(centerLine, out IntersectionResultArray results);
                        if (result == SetComparisonResult.Overlap)
                        {
                            for (int j = 0; j < columnGroup.Count; j++)
                            {
                                if (j != i)
                                {
                                    if (null != ExtendLine(centerLine, columnGroup[j]))
                                    {
                                        nestLines.Add(ExtendLine(centerLine, columnGroup[j]));
                                    }
                                }
                            }
                        }
                    }
                }
                Debug.Print("Got nested lines: " + nestLines.Count.ToString());
                if (nestLines.Count < 2)
                {
                    continue;
                }
                else
                {
                    centerLines.AddRange(nestLines);
                    int count = 0;
                    for (int i = 1; i < nestLines.Count; i++)
                    {
                        if (!Algorithm.IsParallel(nestLines[0], nestLines[i]))
                        {
                            count += 1;
                        }
                    }
                    if (count == 0)
                    {
                        var patches = Algorithm.CenterLinesOfBox(columnGroup);
                        foreach (Line patch in patches)
                        {
                            if (Algorithm.IsLineIntersectLines(patch, nestLines))
                            {
                                centerLines.Add(patch);
                            }
                        }
                    }
                }
            }

            #endregion
            // OUTPUT List<Line> centerLines
            Debug.Print("AXES JOINED AT COLUMN");


            // INPUT List<Line> centerLines
            //#The region detect function has fatal bug during boolean union operation
            #region Call region detection
            // Axis merge
            List <List <Curve> > tempStrays = Algorithm.ClusterByOverlap(centerLines);
            List <Curve>         strays     = new List <Curve>();
            foreach (List <Curve> tempStray in tempStrays)
            {
                Curve merged = Algorithm.FuseLines(tempStray);
                strays.Add(merged);
            }

            //var strayClusters = Algorithm.ClusterByIntersect(Util.LinesToCrvs(strays));
            //Debug.Print("Cluster of strays: " + strayClusters.Count.ToString());
            //Debug.Print("Cluster of strays[0]: " + strayClusters[0].Count.ToString());
            //Debug.Print("Cluster of strays[1]: " + strayClusters[1].Count.ToString());
            // The RegionCluster method should be applied to each cluster of the strays
            // It only works on a bunch of intersected line segments
            List <CurveArray> loops = RegionDetect.RegionCluster(strays);
            // The boolean union method of the loops needs to fix
            var perimeter      = RegionDetect.GetBoundary(loops);
            var recPerimeter   = CloseGapAtBreakpoint(perimeter);
            var arrayPerimeter = RegionDetect.AlignCrv(recPerimeter);
            for (int i = 0; i < arrayPerimeter.Size; i++)
            {
                Debug.Print("Line-{0} {1} {2}", i, Misc.PointString(arrayPerimeter.get_Item(i).GetEndPoint(0)),
                            Misc.PointString(arrayPerimeter.get_Item(i).GetEndPoint(1)));
            }
            #endregion
            // OUTPUT List<CurveArray> loops
            Debug.Print("REGION COMPLETE!");



            // Get the linestyle of "long-dashed"
            FilteredElementCollector fec = new FilteredElementCollector(doc)
                                           .OfClass(typeof(LinePatternElement));
            LinePatternElement linePatternElem = fec.FirstElement() as LinePatternElement;

            // Main visualization process
            using (Transaction tx = new Transaction(doc))
            {
                tx.Start("Generate Floor");

                // Draw wall patch lines

                /*
                 * foreach (Curve patchLine in patchLines)
                 * {
                 *  DetailLine axis = doc.Create.NewDetailCurve(view, patchLine) as DetailLine;
                 *  GraphicsStyle gs = axis.LineStyle as GraphicsStyle;
                 *  gs.GraphicsStyleCategory.LineColor = new Color(202, 51, 82);
                 *  gs.GraphicsStyleCategory.SetLineWeight(3, gs.GraphicsStyleType);
                 * }
                 */

                Plane       Geomplane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero);
                SketchPlane sketch    = SketchPlane.Create(doc, Geomplane);

                /*
                 * // Draw bounding boxes
                 * foreach (List<Curve> wallBlock in wallBlocks)
                 * {
                 *  foreach (Curve edge in wallBlock)
                 *  {
                 *      DetailLine axis = doc.Create.NewDetailCurve(view, edge) as DetailLine;
                 *      GraphicsStyle gs = axis.LineStyle as GraphicsStyle;
                 *      gs.GraphicsStyleCategory.LineColor = new Color(210, 208, 185);
                 *      gs.GraphicsStyleCategory.SetLineWeight(1, gs.GraphicsStyleType);
                 *      gs.GraphicsStyleCategory.SetLinePatternId(linePatternElem.Id, gs.GraphicsStyleType);
                 *  }
                 * }
                 */

                /*
                 * // Draw Axes
                 * Debug.Print("Axes all together: " + strays.Count.ToString());
                 * foreach (Line centerLine in strays)
                 * {
                 *  ModelCurve modelline = doc.Create.NewModelCurve(centerLine, sketch) as ModelCurve;
                 * }
                 */

                // Draw Regions

                foreach (CurveArray loop in loops)
                {
                    foreach (Curve edge in loop)
                    {
                        ModelCurve modelline = doc.Create.NewModelCurve(edge, sketch) as ModelCurve;
                    }
                }

                foreach (Curve edge in arrayPerimeter)
                {
                    DetailLine    axis = doc.Create.NewDetailCurve(view, edge) as DetailLine;
                    GraphicsStyle gs   = axis.LineStyle as GraphicsStyle;
                    gs.GraphicsStyleCategory.LineColor = new Color(202, 51, 82);
                    gs.GraphicsStyleCategory.SetLineWeight(8, gs.GraphicsStyleType);
                }


                tx.Commit();
            }

            return(Result.Succeeded);
        }