// Retrieve the width and depth of a rectangle public static Tuple <double, double, double> GetSizeOfRectangle(List <Line> lines) { List <double> rotations = new List <double> { }; // in radian List <double> lengths = new List <double> { }; // in milimeter foreach (Line line in lines) { XYZ vec = line.GetEndPoint(1) - line.GetEndPoint(0); double angle = AngleTo2PI(vec, XYZ.BasisX); //Debug.Print("Iteration angle is " + angle.ToString()); rotations.Add(angle); lengths.Add(Misc.FootToMm(line.Length)); } int baseEdgeId = rotations.IndexOf(rotations.Min()); double width = lengths[baseEdgeId]; double depth = width; if (width == lengths.Min()) { depth = lengths.Max(); } else { depth = lengths.Min(); } return(Tuple.Create(Math.Round(width, 2), Math.Round(depth, 2), rotations.Min())); // clockwise rotation in radian measure // x pointing right and y down as is common for computer graphics // this will mean you get a positive sign for clockwise angles }
// Main transaction public static void Execute(Application app, Document doc, List <Curve> columnLines, string nameRectColumn, string nameRoundColumn, Level level, bool IsSilent) { // Sort out column boundary // Consider using CurveArray to store the data List <List <Curve> > columnRect = new List <List <Curve> >(); List <Arc> columnRound = new List <Arc>(); List <List <Curve> > columnSpecialShaped = new List <List <Curve> >(); List <int> delIndex = new List <int>(); List <Curve> sortedLines = new List <Curve>(); foreach (Curve columnLine in columnLines) { if (columnLine.GetType().ToString() == "Autodesk.Revit.DB.Arc") { columnRound.Add(columnLine as Arc); delIndex.Add(columnLines.IndexOf(columnLine)); } else { sortedLines.Add(columnLine); } } // this is the temperal method List <List <Curve> > columnGroups = Algorithm.ClusterByIntersect(sortedLines); Debug.Print("Baselines are sorted well"); foreach (List <Curve> columnGroup in columnGroups) { if (Algorithm.GetPtsOfCrvs(columnGroup).Count == columnGroup.Count) { if (Algorithm.IsRectangle(columnGroup)) { columnRect.Add(columnGroup); } else { columnSpecialShaped.Add(columnGroup); } } } Debug.Print("Got rectangle {0}, round {1}, and unique shape {2}", columnRect.Count, columnRound.Count, columnSpecialShaped.Count); // Grab the columntype FilteredElementCollector colColumns = new FilteredElementCollector(doc) .OfClass(typeof(FamilySymbol)); // .OfCategory(BuiltInCategory.OST_Columns); // OST handles the internal family types, maybe? FamilySymbol rectangularColumn = colColumns.FirstElement() as FamilySymbol; // Use default setting to avoid error handling, which is a lack of the line below //FamilySymbol column_demo = columnTypes.Find((FamilySymbol fs) => { return fs.Name == "Column_demo"}); foreach (FamilySymbol columnType in colColumns) { if (columnType.Name == nameRectColumn) { rectangularColumn = columnType as FamilySymbol; break; } } // I don't know if there's a better way to split this... // Column generation if (IsSilent == true) { using (Transaction tx = new Transaction(doc, "Generate rectangular columns")) { FailureHandlingOptions options = tx.GetFailureHandlingOptions(); options.SetFailuresPreprocessor(new Util.FailureSwallower(false, false)); tx.SetFailureHandlingOptions(options); tx.Start(); foreach (List <Curve> baselines in columnRect) { double width = Algorithm.GetSizeOfRectangle(Misc.CrvsToLines(baselines)).Item1; double depth = Algorithm.GetSizeOfRectangle(Misc.CrvsToLines(baselines)).Item2; double angle = Algorithm.GetSizeOfRectangle(Misc.CrvsToLines(baselines)).Item3; FamilySymbol fs = NewRectColumnType(doc, nameRectColumn, width, depth); if (!fs.IsActive) { fs.Activate(); } XYZ columnCenterPt = Algorithm.GetCenterPt(baselines); Line columnCenterAxis = Line.CreateBound(columnCenterPt, columnCenterPt.Add(-XYZ.BasisZ)); // z pointing down to apply a clockwise rotation FamilyInstance fi = doc.Create.NewFamilyInstance(columnCenterPt, fs, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); ElementTransformUtils.RotateElement(doc, fi.Id, columnCenterAxis, angle); //Autodesk.Revit.DB.Structure.StructuralType.Column } tx.Commit(); } // To generate the special shaped column you have to do it transaction by transaction // due to the family document reload operation must be out of one. foreach (List <Curve> baselines in columnSpecialShaped) { var boundary = Algorithm.RectifyPolygon(Misc.CrvsToLines(baselines)); FamilySymbol fs = NewSpecialShapedColumnType(app, doc, boundary); if (null == fs) { Debug.Print("Generic Model Family returns no symbol"); continue; } using (Transaction tx = new Transaction(doc, "Generate a special shaped column")) { tx.Start(); if (!fs.IsActive) { fs.Activate(); } XYZ basePt = XYZ.Zero; Line columnBaseAxis = Line.CreateBound(basePt, basePt.Add(-XYZ.BasisZ)); FamilyInstance fi = doc.Create.NewFamilyInstance(basePt, fs, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); // DANGEROUS! the coordination transformation should be added here tx.Commit(); } } } else { string caption = "Extrude columns"; string task = "Creating rectangular columns..."; Views.ProgressBar pb1 = new Views.ProgressBar(caption, task, columnRect.Count); foreach (List <Curve> baselines in columnRect) { using (Transaction tx = new Transaction(doc, "Generate a rectangular column")) { tx.Start(); double width = Algorithm.GetSizeOfRectangle(Misc.CrvsToLines(baselines)).Item1; double depth = Algorithm.GetSizeOfRectangle(Misc.CrvsToLines(baselines)).Item2; double angle = Algorithm.GetSizeOfRectangle(Misc.CrvsToLines(baselines)).Item3; FamilySymbol fs = NewRectColumnType(doc, nameRectColumn, width, depth); if (!fs.IsActive) { fs.Activate(); } XYZ columnCenterPt = Algorithm.GetCenterPt(baselines); Line columnCenterAxis = Line.CreateBound(columnCenterPt, columnCenterPt.Add(-XYZ.BasisZ)); // z pointing down to apply a clockwise rotation FamilyInstance fi = doc.Create.NewFamilyInstance(columnCenterPt, fs, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); ElementTransformUtils.RotateElement(doc, fi.Id, columnCenterAxis, angle); //Autodesk.Revit.DB.Structure.StructuralType.Column tx.Commit(); } pb1.Increment(); if (pb1.ProcessCancelled) { break; } } pb1.Close(); task = "Creating round columns..."; Views.ProgressBar pb2 = new Views.ProgressBar(caption, task, columnRound.Count); foreach (Arc baseline in columnRound) { using (Transaction tx = new Transaction(doc, "Generate a rounded column")) { tx.Start(); XYZ basePt = baseline.Center; double diameter = Misc.FootToMm(Math.Round(2 * baseline.Radius, 2)); FamilySymbol fs = NewRoundColumnType(doc, nameRoundColumn, diameter); if (!fs.IsActive) { fs.Activate(); } Line columnCenterAxis = Line.CreateBound(basePt, basePt.Add(-XYZ.BasisZ)); // z pointing down to apply a clockwise rotation FamilyInstance fi = doc.Create.NewFamilyInstance(basePt, fs, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); tx.Commit(); } pb2.Increment(); if (pb2.ProcessCancelled) { break; } } pb2.Close(); task = "Creating special shaped columns..."; Views.ProgressBar pb3 = new Views.ProgressBar(caption, task, columnSpecialShaped.Count); foreach (List <Curve> baselines in columnSpecialShaped) { var boundary = Algorithm.RectifyPolygon(Misc.CrvsToLines(baselines)); FamilySymbol fs = NewSpecialShapedColumnType(app, doc, boundary); if (null == fs) { Debug.Print("Generic Model Family returns no symbol"); continue; } using (Transaction tx = new Transaction(doc, "Generate a special shaped column")) { tx.Start(); if (!fs.IsActive) { fs.Activate(); } XYZ basePt = XYZ.Zero; Line columnBaseAxis = Line.CreateBound(basePt, basePt.Add(-XYZ.BasisZ)); FamilyInstance fi = doc.Create.NewFamilyInstance(basePt, fs, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); // DANGEROUS! the coordination transformation should be added here tx.Commit(); } pb3.Increment(); if (pb3.ProcessCancelled) { break; } } pb3.JobCompleted(); } }
public static void Execute(Document doc, List <Curve> doorCrvs, List <Curve> windowCrvs, List <Curve> wallCrvs, List <Util.TeighaText.CADTextModel> labels, string nameDoor, string nameWindow, Level level, bool IsSilent) { View view = doc.ActiveView; var doorClusters = Algorithm.ClusterByIntersect(doorCrvs); // Sometimes ClusterByIntersect will not return ideal result // because the intersected lines are not detected by the program for no reason // sometimes it goes well // iterate the bounding box generation 2 times may gurantee this but lacking efficiency List <List <Curve> > doorBlocks = new List <List <Curve> > { }; foreach (List <Curve> cluster in doorClusters) { if (null != Algorithm.CreateBoundingBox2D(cluster)) { doorBlocks.Add(Algorithm.CreateBoundingBox2D(cluster)); } } //Debug.Print("{0} clustered door blocks in total", doorBlocks.Count); 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 <Curve> fenses = new List <Curve>(); foreach (Curve line in wallCrvs) { 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]); } } //Debug.Print("Curves adjoning the box: " + doorFrame.Count.ToString()); } Debug.Print("We got {0} door axes. ", doorAxes.Count); // Collect window blocks 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)); } } //Debug.Print("{0} clustered window blocks in total", windowBlocks.Count); 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); } } Debug.Print("We got {0} window axes. ", windowAxes.Count); if (IsSilent) { // Main transaction // Plot axis of doors/windows and create the instance using (Transaction tx = new Transaction(doc, "Generate sub-surfaces & marks")) { FailureHandlingOptions options = tx.GetFailureHandlingOptions(); options.SetFailuresPreprocessor(new Util.FailureSwallower(false, false)); // Switch this for the failure list test // Util.FailureCollector fc = new Util.FailureCollector(); // options.SetFailuresPreprocessor(fc); tx.SetFailureHandlingOptions(options); tx.Start(); /* * Plane Geomplane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero); * SketchPlane sketch = SketchPlane.Create(doc, Geomplane); * * // Create door & window blocks * * foreach (List<Curve> doorBlock in doorBlocks) * { * //Debug.Print("Creating new bounding box"); * foreach (Curve edge in doorBlock) * { * ModelCurve modelline = doc.Create.NewModelCurve(edge, sketch) as ModelCurve; * } * } * foreach (List<Curve> windowBlock in windowBlocks) * { * //Debug.Print("Creating new bounding box"); * foreach (Curve edge in windowBlock) * { * ModelCurve modelline = doc.Create.NewModelCurve(edge, sketch) as ModelCurve; * } * } */ // Create door axis & instance foreach (Curve doorAxis in doorAxes) { /* * DetailLine axis = doc.Create.NewDetailCurve(view, doorAxis) as DetailLine; * GraphicsStyle gs = axis.LineStyle as GraphicsStyle; * gs.GraphicsStyleCategory.LineColor = new Color(202, 51, 82); * gs.GraphicsStyleCategory.SetLineWeight(7, gs.GraphicsStyleType); */ Wall hostWall = Wall.Create(doc, doorAxis, level.Id, true); double width = Math.Round(Misc.FootToMm(doorAxis.Length), 0); double height = 2000; XYZ basePt = (doorAxis.GetEndPoint(0) + doorAxis.GetEndPoint(1)).Divide(2); XYZ insertPt = basePt + XYZ.BasisZ * level.Elevation; // Absolute height double span = Double.PositiveInfinity; int labelId = -1; foreach (Util.TeighaText.CADTextModel text in labels) { double distance = basePt.DistanceTo(text.Location); if (distance < span) { span = distance; labelId = labels.IndexOf(text); } } if (labelId > -1) { width = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item1; height = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item2; //Debug.Print("Raw window label: {0}", labels[labelId].Text); } Debug.Print("Create new door with dimension {0}x{1}", width.ToString(), height.ToString()); FamilySymbol fs = NewOpeningType(doc, nameDoor, width, height, "Door"); if (null == fs) { continue; } if (!fs.IsActive) { fs.Activate(); } FamilyInstance fi = doc.Create.NewFamilyInstance(insertPt, fs, hostWall, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); } // Create window axis & instance foreach (Curve windowAxis in windowAxes) { /* * DetailLine axis = doc.Create.NewDetailCurve(view, windowAxis) as DetailLine; * GraphicsStyle gs = axis.LineStyle as GraphicsStyle; * gs.GraphicsStyleCategory.LineColor = new Color(202, 51, 82); * gs.GraphicsStyleCategory.SetLineWeight(7, gs.GraphicsStyleType); */ Wall hostWall = Wall.Create(doc, windowAxis, level.Id, true); double width = Math.Round(Misc.FootToMm(windowAxis.Length), 0); double height = 2500; XYZ basePt = (windowAxis.GetEndPoint(0) + windowAxis.GetEndPoint(1)).Divide(2); // On world plane XYZ insertPt = basePt + XYZ.BasisZ * (Misc.MmToFoot(Properties.Settings.Default.sillHeight) + level.Elevation); // Absolute height double span = Misc.MmToFoot(2000); int labelId = -1; foreach (Util.TeighaText.CADTextModel text in labels) { double distance = basePt.DistanceTo(text.Location); //Debug.Print("Compare the two pts: " + Util.PrintXYZ(basePt) + " " + Util.PrintXYZ(text.Location)); if (distance < span) { span = distance; labelId = labels.IndexOf(text); } } if (labelId > -1) { width = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item1; height = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item2; if (height + Properties.Settings.Default.sillHeight > Properties.Settings.Default.floorHeight) { height = Properties.Settings.Default.floorHeight - Properties.Settings.Default.sillHeight; } //Debug.Print("Raw window label: {0}", labels[labelId].Text); } Debug.Print("Create new window with dimension {0}x{1}", width.ToString(), height.ToString()); FamilySymbol fs = NewOpeningType(doc, nameWindow, width, height, "Window"); if (null == fs) { continue; } if (!fs.IsActive) { fs.Activate(); } FamilyInstance fi = doc.Create.NewFamilyInstance(insertPt, fs, hostWall, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); } tx.Commit(); } // Switch this for the failure list test // fc.ShowDialogue(); } ///////////////////////////// // UNDER PRESENTATION MODE // else { string caption = "Create openings"; string task = "Creating doors..."; Views.ProgressBar pb1 = new Views.ProgressBar(caption, task, doorAxes.Count); foreach (Curve doorAxis in doorAxes) { using (Transaction tx = new Transaction(doc, "Generate doors & adherences")) { //FailureHandlingOptions failOpt = tx.GetFailureHandlingOptions(); //failOpt.SetFailuresPreprocessor(new Util.WarningSwallower(false, false)); //tx.SetFailureHandlingOptions(failOpt);] tx.Start(); Wall hostWall = Wall.Create(doc, doorAxis, level.Id, true); double width = Math.Round(Misc.FootToMm(doorAxis.Length), 0); double height = 2000; XYZ basePt = (doorAxis.GetEndPoint(0) + doorAxis.GetEndPoint(1)).Divide(2); XYZ insertPt = basePt + XYZ.BasisZ * level.Elevation; // Absolute height double span = Double.PositiveInfinity; int labelId = -1; foreach (Util.TeighaText.CADTextModel text in labels) { double distance = basePt.DistanceTo(text.Location); if (distance < span) { span = distance; labelId = labels.IndexOf(text); } } if (labelId > -1) { width = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item1; height = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item2; //Debug.Print("Raw window label: {0}", labels[labelId].Text); } Debug.Print("Create new door with dimension {0}x{1}", width.ToString(), height.ToString()); FamilySymbol fs = NewOpeningType(doc, nameDoor, width, height, "Door"); if (null == fs) { continue; } if (!fs.IsActive) { fs.Activate(); } FamilyInstance fi = doc.Create.NewFamilyInstance(insertPt, fs, hostWall, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); tx.Commit(); } pb1.Increment(); if (pb1.ProcessCancelled) { break; } } pb1.Close(); task = "Creating windows..."; Views.ProgressBar pb2 = new Views.ProgressBar(caption, task, windowAxes.Count); // Create window axis & instance foreach (Curve windowAxis in windowAxes) { using (Transaction tx = new Transaction(doc, "Generate windows & adherences")) { tx.Start(); Wall hostWall = Wall.Create(doc, windowAxis, level.Id, true); double width = Math.Round(Misc.FootToMm(windowAxis.Length), 0); double height = 2500; XYZ basePt = (windowAxis.GetEndPoint(0) + windowAxis.GetEndPoint(1)).Divide(2); // On world plane XYZ insertPt = basePt + XYZ.BasisZ * (Misc.MmToFoot(Properties.Settings.Default.sillHeight) + level.Elevation); // Absolute height double span = Misc.MmToFoot(2000); int labelId = -1; foreach (Util.TeighaText.CADTextModel text in labels) { double distance = basePt.DistanceTo(text.Location); //Debug.Print("Compare the two pts: " + Util.PrintXYZ(basePt) + " " + Util.PrintXYZ(text.Location)); if (distance < span) { span = distance; labelId = labels.IndexOf(text); } } if (labelId > -1) { width = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item1; height = Util.TeighaText.DecodeLabel(labels[labelId].Text, width, height).Item2; if (height + Properties.Settings.Default.sillHeight > Properties.Settings.Default.floorHeight) { height = Properties.Settings.Default.floorHeight - Properties.Settings.Default.sillHeight; } //Debug.Print("Raw window label: {0}", labels[labelId].Text); } Debug.Print("Create new window with dimension {0}x{1}", width.ToString(), height.ToString()); FamilySymbol fs = NewOpeningType(doc, nameWindow, width, height, "Window"); if (null == fs) { continue; } if (!fs.IsActive) { fs.Activate(); } FamilyInstance fi = doc.Create.NewFamilyInstance(insertPt, fs, hostWall, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); tx.Commit(); } pb2.Increment(); if (pb2.ProcessCancelled) { break; } } pb2.JobCompleted(); } }