/// <summary> /// Extend a line segment with certain extension(mm) on both ends. /// </summary> /// <param name="line"></param> /// <param name="extension"></param> /// <returns></returns> public static Curve ExtendLine(Curve line, double extension) { XYZ ptStart = line.GetEndPoint(0); XYZ ptEnd = line.GetEndPoint(1); XYZ vec = (ptEnd - ptStart).Normalize(); return(Line.CreateBound(ptStart - vec * Misc.MmToFoot(extension), ptEnd + vec * Misc.MmToFoot(extension))); }
// add new type of a family instance if not exist public static FamilySymbol NewRectColumnType(Document doc, string familyName, double width, double depth) { Family f = Misc.GetFirstElementOfTypeNamed(doc, typeof(Family), familyName) as Family; if (null == f) { // add default path and error handling here if (!doc.LoadFamily(Properties.Settings.Default.url_columnRect, out f)) { Debug.Print("Unable to load the default column"); } } if (null != f) { Debug.Print("Family name={0}", f.Name); // Pick any symbol for duplication (for iteration convenient choose the last): FamilySymbol s = null; foreach (ElementId id in f.GetFamilySymbolIds()) { s = doc.GetElement(id) as FamilySymbol; if (s.Name == width.ToString() + " x " + depth.ToString() + "mm") { return(s); } } Debug.Assert(null != s, "expected at least one symbol to be defined in family"); // Duplicate the existing symbol: s = s.Duplicate(width.ToString() + " x " + depth.ToString() + "mm") as FamilySymbol; // Analyse the symbol parameters: foreach (Parameter param in s.Parameters) { Debug.Print("Parameter name={0}, value={1}", param.Definition.Name, param.AsValueString()); } // Define new dimensions for our new type; // the specified parameter name is case sensitive: s.LookupParameter("Width").Set(Misc.MmToFoot(width)); s.LookupParameter("Depth").Set(Misc.MmToFoot(depth)); return(s); } else { return(null); } }
/// <summary> /// Check if two lines are almost joined. /// </summary> /// <param name="crv1"></param> /// <param name="crv2"></param> /// <returns></returns> public static bool IsAlmostJoined(Curve line1, Curve line2) { double radius = Misc.MmToFoot(Properties.Settings.Default.jointRadius); XYZ ptStart = line1.GetEndPoint(0); XYZ ptEnd = line1.GetEndPoint(1); XYZ xAxis = new XYZ(1, 0, 0); // The x axis to define the arc plane. Must be normalized XYZ yAxis = new XYZ(0, 1, 0); // The y axis to define the arc plane. Must be normalized Curve knob1 = Arc.Create(ptStart, radius, 0, 2 * Math.PI, xAxis, yAxis); Curve knob2 = Arc.Create(ptEnd, radius, 0, 2 * Math.PI, xAxis, yAxis); SetComparisonResult result1 = knob1.Intersect(line2, out IntersectionResultArray results1); SetComparisonResult result2 = knob2.Intersect(line2, out IntersectionResultArray results2); if (result1 == SetComparisonResult.Overlap || result2 == SetComparisonResult.Overlap) { return(true); } else { return(false); } }
public static FamilySymbol NewSpecialShapedColumnType(Application app, Document doc, CurveArray boundary) { Document familyDoc = app.NewFamilyDocument(Properties.Settings.Default.url_columnFamily); using (Transaction tx_createFamily = new Transaction(familyDoc, "Create family")) { tx_createFamily.Start(); Plane familyGeomplane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero); SketchPlane sketch = SketchPlane.Create(familyDoc, familyGeomplane); CurveArrArray curveArrArray = new CurveArrArray(); curveArrArray.Append(boundary); // The end has to be 4000mm in metric which is in align with the Metric Column.rft Extrusion extrusion = familyDoc.FamilyCreate.NewExtrusion(true, curveArrArray, sketch, Misc.MmToFoot(4000)); familyDoc.FamilyManager.NewType("Type 0"); familyDoc.Regenerate(); Reference topFaceRef = null; Options opt = new Options(); opt.ComputeReferences = true; opt.DetailLevel = ViewDetailLevel.Fine; GeometryElement gelm = extrusion.get_Geometry(opt); foreach (GeometryObject gobj in gelm) { if (gobj is Solid) { Solid solid = gobj as Solid; foreach (Face face in solid.Faces) { if (face.ComputeNormal(UV.Zero).IsAlmostEqualTo(XYZ.BasisZ)) { topFaceRef = face.Reference; } } } } View v = GetView(familyDoc); Reference r = GetUpperRefLevel(familyDoc); Dimension d = familyDoc.FamilyCreate.NewAlignment(v, r, topFaceRef); d.IsLocked = true; tx_createFamily.Commit(); } //familyDoc.SaveAs("Special Shaped Column - " + boundary.Size.ToString() + ".rfa"); //familyDoc.Close(); Family f = familyDoc.LoadFamily(doc) as Family; FamilySymbol s = null; foreach (ElementId id in f.GetFamilySymbolIds()) { s = doc.GetElement(id) as FamilySymbol; } return(s); }
// Main thread public static CurveArray Execute(Document doc, List <Curve> wallCrvs, List <Curve> columnCrvs, List <Curve> windowCrvs, List <Curve> doorCrvs) { View view = doc.ActiveView; List <Line> columnLines = Misc.CrvsToLines(columnCrvs); // 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 = CmdPatchBoundary.CloseGapAtBreakpoint(wallCrvs); // List <Curve> fixedLines = CmdPatchBoundary.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 <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 != CmdPatchBoundary.ExtendLine(centerLine, columnGroup[j])) { nestLines.Add(CmdPatchBoundary.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) { var merged = Algorithm.FuseLines(tempStray); strays.Add(merged); } // 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 = CmdPatchBoundary.CloseGapAtBreakpoint(perimeter); #endregion // OUTPUT List<CurveArray> loops Debug.Print("REGION COMPLETE!"); return(RegionDetect.AlignCrv(recPerimeter)); }
public static void Execute(UIApplication uiapp, List <Curve> wallCrvs, Level level, bool IsSilent) { UIDocument uidoc = uiapp.ActiveUIDocument; Application app = uiapp.Application; Document doc = uidoc.Document; // Bundle double lines and generate their axes List <Curve> axes = new List <Curve>(); double bias = Misc.MmToFoot(20); var doubleLines = Misc.CrvsToLines(wallCrvs); for (int i = 0; i < doubleLines.Count; i++) { for (int j = 0; j < doubleLines.Count - i; j++) { if (Algorithm.IsParallel(doubleLines[i], doubleLines[i + j]) && !Algorithm.IsIntersected(doubleLines[i], doubleLines[i + j])) { // Imperical Units within Revit API if (Algorithm.LineSpacing(doubleLines[i], doubleLines[i + j]) < Misc.MmToFoot(200) + bias && Algorithm.LineSpacing(doubleLines[i], doubleLines[i + j]) > Misc.MmToFoot(200) - bias && Algorithm.IsShadowing(doubleLines[i], doubleLines[i + j])) { if (Algorithm.GenerateAxis(doubleLines[i], doubleLines[i + j]) != null) { axes.Add(Algorithm.GenerateAxis(doubleLines[i], doubleLines[i + j])); } Debug.Print(doubleLines[i].Length.ToString() + " | " + doubleLines[i + j].Length.ToString()); } } } } // Axis merge / List <Curve> mergedAxes = Algorithm.MergeAxes(axes); Debug.Print("The merged axes number " + mergedAxes.Count.ToString()); string task = "Creating Walls..."; string caption = "Extrude Walls"; int n = mergedAxes.Count; /*using (Transaction tx = new Transaction(doc, "Generate walls")) * { * tx.Start(); * * // Wall generation * foreach (Curve axis in mergedAxes) * { * Wall.Create(doc, axis, level.Id, true); * } * * tx.Commit(); * }*/ if (IsSilent == true) { using (Transaction tx = new Transaction(doc, "Generate a wall")) { FailureHandlingOptions options = tx.GetFailureHandlingOptions(); options.SetFailuresPreprocessor(new Util.FailureSwallower(false, false)); tx.SetFailureHandlingOptions(options); tx.Start(); foreach (Curve axis in mergedAxes) { Wall.Create(doc, axis, level.Id, true); } tx.Commit(); } } else { Views.ProgressBar pb = new Views.ProgressBar(caption, task, n); foreach (Curve axis in mergedAxes) { using (Transaction tx = new Transaction(doc, "Generate a wall")) { tx.Start(); Wall.Create(doc, axis, level.Id, true); tx.Commit(); } pb.Increment(); if (pb.ProcessCancelled) { break; } } pb.JobCompleted(); } }
// Main execution 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; // Grab the current building level FilteredElementCollector colLevels = new FilteredElementCollector(doc) .WhereElementIsNotElementType() .OfCategory(BuiltInCategory.INVALID) .OfClass(typeof(Level)); Level firstLevel = colLevels.FirstElement() as Level; // LineStyle filter CurveElementFilter filter = new CurveElementFilter(CurveElementType.ModelCurve); FilteredElementCollector collector = new FilteredElementCollector(doc); ICollection <Element> founds = collector.WherePasses(filter).ToElements(); List <CurveElement> importCurves = new List <CurveElement>(); foreach (CurveElement ce in founds) { importCurves.Add(ce); } var wallCurves = importCurves.Where(x => x.LineStyle.Name == "WALL").ToList(); List <Curve> wallLines = new List <Curve>(); // Algorithm only support walls of line type foreach (CurveElement ce in wallCurves) { wallLines.Add(ce.GeometryCurve as Curve); } //double parasStart = wallLines[0].GetEndParameter(0); //double parasEnd = wallLines[0].GetEndParameter(1); //wallLines[0].MakeUnbound(); //double _parasStart = wallLines[1].GetEndParameter(0); //double _parasEnd = wallLines[1].GetEndParameter(1); //wallLines[1].MakeUnbound(); SetComparisonResult result = wallLines[0].Intersect(wallLines[1], out IntersectionResultArray results); Debug.Assert(result != SetComparisonResult.Overlap, "Overlap"); Debug.Assert(result != SetComparisonResult.BothEmpty, "BothEmpty"); Debug.Assert(result != SetComparisonResult.Disjoint, "Disjoint"); Debug.Assert(result != SetComparisonResult.Equal, "Equal"); Debug.Assert(result != SetComparisonResult.LeftEmpty, "LeftEmpty"); Debug.Assert(result != SetComparisonResult.RightEmpty, "RightEmpty"); Debug.Assert(result != SetComparisonResult.Subset, "Subset"); Debug.Assert(result != SetComparisonResult.Superset, "Superset"); double radius = Misc.MmToFoot(50); XYZ ptStart = wallLines[0].GetEndPoint(0); XYZ ptEnd = wallLines[0].GetEndPoint(1); XYZ xAxis = new XYZ(1, 0, 0); // The x axis to define the arc plane. Must be normalized XYZ yAxis = new XYZ(0, 1, 0); // The y axis to define the arc plane. Must be normalized Curve knob1 = Arc.Create(ptStart, radius, 0, 2 * Math.PI, xAxis, yAxis); Curve knob2 = Arc.Create(ptEnd, radius, 0, 2 * Math.PI, xAxis, yAxis); SetComparisonResult result1 = knob1.Intersect(wallLines[1], out IntersectionResultArray results1); SetComparisonResult result2 = knob2.Intersect(wallLines[1], out IntersectionResultArray results2); // if (result1 == SetComparisonResult.Disjoint && result2 == SetComparisonResult.Disjoint) if ((result1 == SetComparisonResult.Overlap || result1 == SetComparisonResult.Subset || result1 == SetComparisonResult.Superset || result1 == SetComparisonResult.Equal) || (result2 == SetComparisonResult.Overlap || result2 == SetComparisonResult.Subset || result2 == SetComparisonResult.Superset || result2 == SetComparisonResult.Equal)) { Debug.Print("INTERSECTED!"); } else { Debug.Print("DISJOINT!"); } XYZ ptStart1 = wallLines[0].GetEndPoint(0); XYZ ptEnd1 = wallLines[0].GetEndPoint(1); XYZ ptStart2 = wallLines[1].GetEndPoint(0); XYZ ptEnd2 = wallLines[1].GetEndPoint(1); Line baseline = wallLines[1].Clone() as Line; baseline.MakeUnbound(); XYZ _ptStart = baseline.Project(ptStart1).XYZPoint; XYZ _ptEnd = baseline.Project(ptEnd1).XYZPoint; Debug.Print("_start: " + Misc.PointString(_ptStart)); Debug.Print("_end: " + Misc.PointString(_ptEnd)); Line checkline = Line.CreateBound(_ptStart, _ptEnd); SetComparisonResult projection = checkline.Intersect(wallLines[1] as Line, out IntersectionResultArray projections); Debug.Print("Shadowing?" + projection.ToString()); if (projection == SetComparisonResult.Equal) { Debug.Print("Shadowing"); } { Debug.Print("Departed"); } Curve proj1 = Arc.Create(_ptStart, radius, 0, 2 * Math.PI, xAxis, yAxis); Curve proj2 = Arc.Create(_ptEnd, radius, 0, 2 * Math.PI, xAxis, yAxis); using (Transaction tx = new Transaction(doc)) { tx.Start("Generate sub-surface and its mark"); Plane Geomplane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero); SketchPlane sketch = SketchPlane.Create(doc, Geomplane); ModelCurve modelline1 = doc.Create.NewModelCurve(proj1, sketch) as ModelCurve; ModelCurve modelline2 = doc.Create.NewModelCurve(proj2, sketch) as ModelCurve; tx.Commit(); } return(Result.Succeeded); }
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(); } }
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); }
// 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); }