/// <summary> /// Resolve one obstruction of Pipe. /// </summary> /// <param name="pipe">Pipe to resolve</param> /// <param name="section">One pipe's obstruction</param> private void Resolve(Pipe pipe, Section section) { // Find out a parallel line of pipe centerline, which can avoid the obstruction. Line offset = FindRoute(pipe, section); // Construct a section line according to the given section. Line sectionLine = Line.get_Bound(section.Start, section.End); // Construct two side lines, which can avoid the obstruction too. Line side1 = Line.get_Bound(sectionLine.get_EndPoint(0), offset.get_EndPoint(0)); Line side2 = Line.get_Bound(offset.get_EndPoint(1), sectionLine.get_EndPoint(1)); // // Create an "U" shape, which connected with three pipes and two elbows, to round the obstruction. // PipeType pipeType = pipe.PipeType; Autodesk.Revit.DB.XYZ start = side1.get_EndPoint(0); Autodesk.Revit.DB.XYZ startOffset = offset.get_EndPoint(0); Autodesk.Revit.DB.XYZ endOffset = offset.get_EndPoint(1); Autodesk.Revit.DB.XYZ end = side2.get_EndPoint(1); // Create three side pipes of "U" shape. Pipe pipe1 = m_rvtDoc.Create.NewPipe(start, startOffset, pipeType); Pipe pipe2 = m_rvtDoc.Create.NewPipe(startOffset, endOffset, pipeType); Pipe pipe3 = m_rvtDoc.Create.NewPipe(endOffset, end, pipeType); // Copy parameters from pipe to other three created pipes. CopyParameters(pipe, pipe1); CopyParameters(pipe, pipe2); CopyParameters(pipe, pipe3); // Add the created three pipes to current section. section.Pipes.Add(pipe1); section.Pipes.Add(pipe2); section.Pipes.Add(pipe3); // Create the first elbow to connect two neighbor pipes of "U" shape. Connector conn1 = FindConnector(pipe1, startOffset); Connector conn2 = FindConnector(pipe2, startOffset); m_rvtDoc.Create.NewElbowFitting(conn1, conn2); // Create the second elbow to connect another two neighbor pipes of "U" shape. Connector conn3 = FindConnector(pipe2, endOffset); Connector conn4 = FindConnector(pipe3, endOffset); m_rvtDoc.Create.NewElbowFitting(conn3, conn4); }
/// <summary> /// This method will find out a route to avoid the obstruction. /// </summary> /// <param name="pipe">Pipe to resolve</param> /// <param name="section">Pipe's one obstruction</param> /// <returns>A route which can avoid the obstruction</returns> private Line FindRoute(Pipe pipe, Section section) { // Perpendicular direction minimal length. double minLength = pipe.Diameter * 2; // Parallel direction jump step. double jumpStep = pipe.Diameter; // Calculate the directions in which to find the solution. List<Autodesk.Revit.DB.XYZ > dirs = new List<Autodesk.Revit.DB.XYZ >(); Autodesk.Revit.DB.XYZ crossDir = null; foreach (ReferenceWithContext gref in section.Refs) { Element elem = m_rvtDoc.GetElement(gref.GetReference()); Line locationLine = (elem.Location as LocationCurve).Curve as Line; Autodesk.Revit.DB.XYZ refDir = locationLine.get_EndPoint(1) - locationLine.get_EndPoint(0); refDir = refDir.Normalize(); if (refDir.IsAlmostEqualTo(section.PipeCenterLineDirection) || refDir.IsAlmostEqualTo(-section.PipeCenterLineDirection)) { continue; } crossDir = refDir.CrossProduct(section.PipeCenterLineDirection); dirs.Add(crossDir.Normalize()); break; } // When all the obstruction are parallel with the centerline of the pipe, // We can't calculate the direction from the vector.Cross method. if (dirs.Count == 0) { // Calculate perpendicular directions with dir in four directions. List<Autodesk.Revit.DB.XYZ > perDirs = PerpendicularDirs(section.PipeCenterLineDirection, 4); dirs.Add(perDirs[0]); dirs.Add(perDirs[1]); } Line foundLine = null; while (null == foundLine) { // Extend the section interval by jumpStep. section.Inflate(0, jumpStep); section.Inflate(1, jumpStep); // Find solution in the given directions. for (int i = 0; null == foundLine && i < dirs.Count; i++) { // Calculate the intersections. List<ReferenceWithContext> obs1 = m_detector.Obstructions(section.Start, dirs[i]); List<ReferenceWithContext> obs2 = m_detector.Obstructions(section.End, dirs[i]); // Filter out the intersection result. Filter(pipe, obs1); Filter(pipe, obs2); // Find out the minimal intersections in two opposite direction. ReferenceWithContext[] mins1 = GetClosestSectionsToOrigin(obs1); ReferenceWithContext[] mins2 = GetClosestSectionsToOrigin(obs2); // Find solution in the given direction and its opposite direction. for (int j = 0; null == foundLine && j < 2; j++) { if (mins1[j] != null && Math.Abs(mins1[j].Proximity) < minLength || mins2[j] != null && Math.Abs(mins2[j].Proximity) < minLength) { continue; } // Calculate the maximal height that the parallel line can be reached. double maxHight = 1000 * pipe.Diameter; if (mins1[j] != null && mins2[j] != null) { maxHight = Math.Min(Math.Abs(mins1[j].Proximity), Math.Abs(mins2[j].Proximity)); } else if(mins1[j] != null) { maxHight = Math.Abs(mins1[j].Proximity); } else if (mins2[j] != null) { maxHight = Math.Abs(mins2[j].Proximity); } Autodesk.Revit.DB.XYZ dir = (j == 1) ? dirs[i] : -dirs[i]; // Calculate the parallel line which can avoid obstructions. foundLine = FindParallelLine(pipe, section, dir, maxHight); } } } return foundLine; }
/// <summary> /// Find a line Parallel to pipe's centerline to avoid the obstruction. /// </summary> /// <param name="pipe">Pipe who has obstructions</param> /// <param name="section">Pipe's one obstruction</param> /// <param name="dir">Offset Direction of the parallel line</param> /// <param name="maxLength">Maximum offset distance</param> /// <returns>Parallel line which can avoid the obstruction</returns> private Line FindParallelLine(Pipe pipe, Section section, Autodesk.Revit.DB.XYZ dir, double maxLength) { double step = pipe.Diameter; double hight = 2 * pipe.Diameter; while (hight <= maxLength) { Autodesk.Revit.DB.XYZ detal = dir * hight; Line line = Line.get_Bound(section.Start + detal, section.End + detal); List<ReferenceWithContext> refs = m_detector.Obstructions(line); Filter(pipe, refs); if (refs.Count == 0) { return line; } hight += step; } return null; }
/// <summary> /// Build sections for References, it's a factory method to build sections. /// A section contains several points through which the ray passes the obstruction(s). /// for example, a section may contain 2 points when the obstruction is stand alone, /// or contain 4 points if 2 obstructions are intersects with each other in the direction of the ray. /// </summary> /// <param name="allrefs">References</param> /// <param name="dir">Pipe's direction</param> /// <returns>List of Section</returns> public static List<Section> BuildSections(List<ReferenceWithContext> allrefs, Autodesk.Revit.DB.XYZ dir) { List<ReferenceWithContext> buildStack = new List<ReferenceWithContext>(); List<Section> sections = new List<Section>(); Section current = null; foreach (ReferenceWithContext geoRef in allrefs) { if (buildStack.Count == 0) { current = new Section(dir); sections.Add(current); } current.Refs.Add(geoRef); ReferenceWithContext tmp = Find(buildStack, geoRef); if (tmp != null) { buildStack.Remove(tmp); } else buildStack.Add(geoRef); } return sections; }
/// <summary> /// This method will find out a route to avoid the obstruction. /// </summary> /// <param name="pipe">Pipe to resolve</param> /// <param name="section">Pipe's one obstruction</param> /// <returns>A route which can avoid the obstruction</returns> private Line FindRoute(Pipe pipe, Section section) { // Perpendicular direction minimal length. double minLength = pipe.Diameter * 2; // Parallel direction jump step. double jumpStep = pipe.Diameter; // Calculate the directions in which to find the solution. List <Autodesk.Revit.DB.XYZ> dirs = new List <Autodesk.Revit.DB.XYZ>(); Autodesk.Revit.DB.XYZ crossDir = null; foreach (ReferenceWithContext gref in section.Refs) { Element elem = m_rvtDoc.GetElement(gref.GetReference()); Line locationLine = (elem.Location as LocationCurve).Curve as Line; Autodesk.Revit.DB.XYZ refDir = locationLine.GetEndPoint(1) - locationLine.GetEndPoint(0); refDir = refDir.Normalize(); if (refDir.IsAlmostEqualTo(section.PipeCenterLineDirection) || refDir.IsAlmostEqualTo(-section.PipeCenterLineDirection)) { continue; } crossDir = refDir.CrossProduct(section.PipeCenterLineDirection); dirs.Add(crossDir.Normalize()); break; } // When all the obstruction are parallel with the centerline of the pipe, // We can't calculate the direction from the vector.Cross method. if (dirs.Count == 0) { // Calculate perpendicular directions with dir in four directions. List <Autodesk.Revit.DB.XYZ> perDirs = PerpendicularDirs(section.PipeCenterLineDirection, 4); dirs.Add(perDirs[0]); dirs.Add(perDirs[1]); } Line foundLine = null; while (null == foundLine) { // Extend the section interval by jumpStep. section.Inflate(0, jumpStep); section.Inflate(1, jumpStep); // Find solution in the given directions. for (int i = 0; null == foundLine && i < dirs.Count; i++) { // Calculate the intersections. List <ReferenceWithContext> obs1 = m_detector.Obstructions(section.Start, dirs[i]); List <ReferenceWithContext> obs2 = m_detector.Obstructions(section.End, dirs[i]); // Filter out the intersection result. Filter(pipe, obs1); Filter(pipe, obs2); // Find out the minimal intersections in two opposite direction. ReferenceWithContext[] mins1 = GetClosestSectionsToOrigin(obs1); ReferenceWithContext[] mins2 = GetClosestSectionsToOrigin(obs2); // Find solution in the given direction and its opposite direction. for (int j = 0; null == foundLine && j < 2; j++) { if (mins1[j] != null && Math.Abs(mins1[j].Proximity) < minLength || mins2[j] != null && Math.Abs(mins2[j].Proximity) < minLength) { continue; } // Calculate the maximal height that the parallel line can be reached. double maxHight = 1000 * pipe.Diameter; if (mins1[j] != null && mins2[j] != null) { maxHight = Math.Min(Math.Abs(mins1[j].Proximity), Math.Abs(mins2[j].Proximity)); } else if (mins1[j] != null) { maxHight = Math.Abs(mins1[j].Proximity); } else if (mins2[j] != null) { maxHight = Math.Abs(mins2[j].Proximity); } Autodesk.Revit.DB.XYZ dir = (j == 1) ? dirs[i] : -dirs[i]; // Calculate the parallel line which can avoid obstructions. foundLine = FindParallelLine(pipe, section, dir, maxHight); } } } return(foundLine); }
/// <summary> /// Detect the obstructions of pipe and resolve them. /// </summary> /// <param name="pipe">Pipe to resolve</param> private void Resolve(Pipe pipe) { var parameter = pipe.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM); var levelId = parameter.AsElementId(); var systemTypeId = m_pipingSystemType.Id; // Get the centerline of pipe. Line pipeLine = (pipe.Location as LocationCurve).Curve as Line; // Calculate the intersection references with pipe's centerline. List <ReferenceWithContext> obstructionRefArr = m_detector.Obstructions(pipeLine); // Filter out the references, just allow Pipe, Beam, and Duct. Filter(pipe, obstructionRefArr); if (obstructionRefArr.Count == 0) { // There are no intersection found. return; } // Calculate the direction of pipe's centerline. Autodesk.Revit.DB.XYZ dir = pipeLine.GetEndPoint(1) - pipeLine.GetEndPoint(0); // Build the sections from the intersection references. List <Section> sections = Section.BuildSections(obstructionRefArr, dir.Normalize()); // Merge the neighbor sections if the distance of them is too close. for (int i = sections.Count - 2; i >= 0; i--) { Autodesk.Revit.DB.XYZ detal = sections[i].End - sections[i + 1].Start; if (detal.GetLength() < pipe.Diameter * 3) { sections[i].Refs.AddRange(sections[i + 1].Refs); sections.RemoveAt(i + 1); } } // Resolve the obstructions one by one. foreach (Section sec in sections) { Resolve(pipe, sec); } // Connect the neighbor sections with pipe and elbow fittings. // for (int i = 1; i < sections.Count; i++) { // Get the end point from the previous section. Autodesk.Revit.DB.XYZ start = sections[i - 1].End; // Get the start point from the current section. Autodesk.Revit.DB.XYZ end = sections[i].Start; // Create a pipe between two neighbor section. Pipe tmpPipe = Pipe.Create(m_rvtDoc, systemTypeId, pipe.PipeType.Id, levelId, start, end); // Copy pipe's parameters values to tmpPipe. CopyParameters(pipe, tmpPipe); // Create elbow fitting to connect previous section with tmpPipe. Connector conn1 = FindConnector(sections[i - 1].Pipes[2], start); Connector conn2 = FindConnector(tmpPipe, start); FamilyInstance fi = m_rvtDoc.Create.NewElbowFitting(conn1, conn2); // Create elbow fitting to connect current section with tmpPipe. Connector conn3 = FindConnector(sections[i].Pipes[0], end); Connector conn4 = FindConnector(tmpPipe, end); FamilyInstance f2 = m_rvtDoc.Create.NewElbowFitting(conn3, conn4); } // Find two connectors which pipe's two ends connector connected to. Connector startConn = FindConnectedTo(pipe, pipeLine.GetEndPoint(0)); Connector endConn = FindConnectedTo(pipe, pipeLine.GetEndPoint(1)); Pipe startPipe = null; if (null != startConn) { // Create a pipe between pipe's start connector and pipe's start section. startPipe = Pipe.Create(m_rvtDoc, pipe.PipeType.Id, levelId, startConn, sections[0].Start); } else { // Create a pipe between pipe's start point and pipe's start section. startPipe = Pipe.Create(m_rvtDoc, systemTypeId, pipe.PipeType.Id, levelId, sections[0].Start, pipeLine.GetEndPoint(0)); } // Copy parameters from pipe to startPipe. CopyParameters(pipe, startPipe); // Connect the startPipe and first section with elbow fitting. Connector connStart1 = FindConnector(startPipe, sections[0].Start); Connector connStart2 = FindConnector(sections[0].Pipes[0], sections[0].Start); FamilyInstance fii = m_rvtDoc.Create.NewElbowFitting(connStart1, connStart2); Pipe endPipe = null; int count = sections.Count; if (null != endConn) { // Create a pipe between pipe's end connector and pipe's end section. endPipe = Pipe.Create(m_rvtDoc, pipe.PipeType.Id, levelId, endConn, sections[count - 1].End); } else { // Create a pipe between pipe's end point and pipe's end section. endPipe = Pipe.Create(m_rvtDoc, systemTypeId, pipe.PipeType.Id, levelId, sections[count - 1].End, pipeLine.GetEndPoint(1)); } // Copy parameters from pipe to endPipe. CopyParameters(pipe, endPipe); // Connect the endPipe and last section with elbow fitting. Connector connEnd1 = FindConnector(endPipe, sections[count - 1].End); Connector connEnd2 = FindConnector(sections[count - 1].Pipes[2], sections[count - 1].End); FamilyInstance fiii = m_rvtDoc.Create.NewElbowFitting(connEnd1, connEnd2); // Delete the pipe after resolved. m_rvtDoc.Delete(pipe.Id); }