/// <summary> /// Make a line from start point to end point with the direction and style /// </summary> /// <param name="startpt">start point</param> /// <param name="endpt">end point</param> /// <param name="direction">the direction which decide the plane</param> /// <param name="style">line style name</param> public void MakeLine(Autodesk.Revit.DB.XYZ startpt, Autodesk.Revit.DB.XYZ endpt, Autodesk.Revit.DB.XYZ direction, string style) { try { m_LineCount = m_LineCount + 1; Line line = m_app.Application.Create.NewLineBound(startpt, endpt); // Line must lie in the sketch plane. Use the direction of the line to construct a plane that hosts the target line. XYZ rotatedDirection = XYZ.BasisX; // If the direction is not vertical, cross the direction vector with Z to get a vector rotated ninety degrees. That vector, // plus the original vector, form the axes of the sketch plane. if (!direction.IsAlmostEqualTo(XYZ.BasisZ) && !direction.IsAlmostEqualTo(-XYZ.BasisZ)) { rotatedDirection = direction.Normalize().CrossProduct(XYZ.BasisZ); } Plane geometryPlane = m_app.Application.Create.NewPlane(direction, rotatedDirection, startpt); SketchPlane skplane = m_app.ActiveUIDocument.Document.Create.NewSketchPlane(geometryPlane); ModelCurve mcurve = m_app.ActiveUIDocument.Document.Create.NewModelCurve(line, skplane); m_app.ActiveUIDocument.Document.Regenerate(); ElementArray lsArr = mcurve.LineStyles; foreach (Autodesk.Revit.DB.Element e in lsArr) { if (e.Name == style) { mcurve.LineStyle = e; break; } } m_app.ActiveUIDocument.Document.Regenerate(); } catch (System.Exception ex) { m_outputInfo.Add("Failed to create lines: " + ex.ToString()); } }
/// <summary> /// Get an edge from the form by its endpoints /// </summary> /// <param name="form">The form contains the edge</param> /// <param name="startPoint">Start point of the edge</param> /// <param name="endPoint">End point of the edge</param> /// <returns>The edge found</returns> private Edge GetEdgeByEndPoints(Form form, Autodesk.Revit.DB.XYZ startPoint, Autodesk.Revit.DB.XYZ endPoint) { Edge edge = null; // Get all edges of the form EdgeArray edges = null; Options geoOptions = m_revitApp.Create.NewGeometryOptions(); geoOptions.ComputeReferences = true; Autodesk.Revit.DB.GeometryElement geoElement = form.get_Geometry(geoOptions); foreach (GeometryObject geoObject in geoElement.Objects) { Solid solid = geoObject as Solid; if (null == solid) { continue; } edges = solid.Edges; } // Traverse the edges and look for the edge with the right endpoints foreach (Edge ed in edges) { Autodesk.Revit.DB.XYZ rpPos1 = ed.Evaluate(0); Autodesk.Revit.DB.XYZ rpPos2 = ed.Evaluate(1); if ((startPoint.IsAlmostEqualTo(rpPos1) && endPoint.IsAlmostEqualTo(rpPos2)) || (startPoint.IsAlmostEqualTo(rpPos2) && endPoint.IsAlmostEqualTo(rpPos1))) { edge = ed; break; } } return(edge); }
/// <summary> /// Create a based-line family instance by face /// </summary> /// <param name="startP">the start point</param> /// <param name="endP">the end point</param> /// <param name="faceIndex">the index of the selected face</param> /// <param name="familySymbolIndex">the index of the selected family symbol</param> /// <returns></returns> public bool CreateLineFamilyInstance(Autodesk.Revit.DB.XYZ startP, Autodesk.Revit.DB.XYZ endP, int faceIndex , int familySymbolIndex) { Face face = m_faceList[faceIndex]; Autodesk.Revit.DB.XYZ projectedStartP = Project(face.Triangulate().Vertices as List <XYZ>, startP); Autodesk.Revit.DB.XYZ projectedEndP = Project(face.Triangulate().Vertices as List <XYZ>, endP); if (projectedStartP.IsAlmostEqualTo(projectedEndP)) { return(false); } Line line = Line.CreateBound(projectedStartP, projectedEndP); if (!m_familySymbolList[familySymbolIndex].IsActive) { m_familySymbolList[familySymbolIndex].Activate(); } FamilyInstance instance = m_revitDoc.Document.Create.NewFamilyInstance(face, line , m_familySymbolList[familySymbolIndex]); List <ElementId> instanceId = new List <ElementId>(); instanceId.Add(instance.Id); m_revitDoc.Selection.SetElementIds(instanceId); return(true); }
/// <summary> /// Compute the angle between two edges /// </summary> /// <param name="edgeA">The 1st edge</param> /// <param name="edgeB">The 2nd edge</param> /// <returns>The angle of the 2 edges</returns> private double AngleBetweenEdges(Edge edgeA, Edge edgeB) { Autodesk.Revit.DB.XYZ vectorA = null; Autodesk.Revit.DB.XYZ vectorB = null; // find coincident vertices Autodesk.Revit.DB.XYZ A_0 = edgeA.Evaluate(0); Autodesk.Revit.DB.XYZ A_1 = edgeA.Evaluate(1); Autodesk.Revit.DB.XYZ B_0 = edgeB.Evaluate(0); Autodesk.Revit.DB.XYZ B_1 = edgeB.Evaluate(1); if (A_0.IsAlmostEqualTo(B_0)) { vectorA = edgeA.ComputeDerivatives(0).BasisX.Normalize(); vectorB = edgeA.ComputeDerivatives(0).BasisX.Normalize(); } else if (A_0.IsAlmostEqualTo(B_1)) { vectorA = edgeA.ComputeDerivatives(0).BasisX.Normalize(); vectorB = edgeB.ComputeDerivatives(1).BasisX.Normalize(); } else if (A_1.IsAlmostEqualTo(B_0)) { vectorA = edgeA.ComputeDerivatives(1).BasisX.Normalize(); vectorB = edgeB.ComputeDerivatives(0).BasisX.Normalize(); } else if (A_1.IsAlmostEqualTo(B_1)) { vectorA = edgeA.ComputeDerivatives(1).BasisX.Normalize(); vectorB = edgeB.ComputeDerivatives(1).BasisX.Normalize(); } if (A_1.IsAlmostEqualTo(B_0) || A_0.IsAlmostEqualTo(B_1)) { vectorA = vectorA.Negate(); } if (null == vectorA || null == vectorB) { return(0d); } double angle = Math.Acos(vectorA.DotProduct(vectorB)); return(angle); }
/// <summary> /// Create a based-line family instance by face /// </summary> /// <param name="startP">the start point</param> /// <param name="endP">the end point</param> /// <param name="faceIndex">the index of the selected face</param> /// <param name="familySymbolIndex">the index of the selected family symbol</param> /// <returns></returns> public bool CreateLineFamilyInstance(Autodesk.Revit.DB.XYZ startP, Autodesk.Revit.DB.XYZ endP, int faceIndex , int familySymbolIndex) { Face face = m_faceList[faceIndex]; Autodesk.Revit.DB.XYZ projectedStartP = Project(face.Triangulate().Vertices as List <XYZ>, startP); Autodesk.Revit.DB.XYZ projectedEndP = Project(face.Triangulate().Vertices as List <XYZ>, endP); if (projectedStartP.IsAlmostEqualTo(projectedEndP)) { return(false); } Line line = m_appCreator.NewLine(projectedStartP, projectedEndP, true); FamilyInstance instance = m_revitDoc.Document.Create.NewFamilyInstance(face, line , m_familySymbolList[familySymbolIndex]); m_revitDoc.Selection.Elements.Clear(); m_revitDoc.Selection.Elements.Add(instance); return(true); }
/// <summary> /// OK button click event /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonOK_Click(object sender, EventArgs e) { DeleteLines(); if (!UpdateData(false)) { return; } m_outputInfo.Clear(); m_stopWatch.Start(); Transaction transaction = new Transaction(m_doc, "RayTraceBounce"); transaction.Start(); m_LineCount = 0; m_RayCount = 0; // Start Find References By Direction Autodesk.Revit.DB.XYZ startpt = m_origin; m_outputInfo.Add("Start Find References By Direction: "); for (int ctr = 1; ctr <= rayLimit; ctr++) { ReferenceIntersector referenceIntersector = new ReferenceIntersector(m_view); IList <ReferenceWithContext> references = referenceIntersector.Find(startpt, m_direction); m_rClosest = null; FindClosestReference(references); if (m_rClosest == null) { string info = "Ray " + ctr + " aborted. No closest face reference found. "; m_outputInfo.Add(info); if (ctr == 1) { TaskDialog.Show("Revit", info); } break; } else { Reference reference = m_rClosest.GetReference(); Element referenceElement = m_doc.GetElement(reference); GeometryObject referenceObject = referenceElement.GetGeometryObjectFromReference(reference); Autodesk.Revit.DB.XYZ endpt = reference.GlobalPoint; if (startpt.IsAlmostEqualTo(endpt)) { m_outputInfo.Add("Start and end points are equal. Ray " + ctr + " aborted\n" + startpt.X + ", " + startpt.Y + ", " + startpt.Z); break; } else { MakeLine(startpt, endpt, m_direction, "bounce"); m_RayCount = m_RayCount + 1; string info = "Intersected Element Type: [" + referenceElement.GetType().ToString() + "] ElementId: [" + referenceElement.Id.IntegerValue.ToString(); m_face = referenceObject as Face; if (m_face.MaterialElementId != ElementId.InvalidElementId) { Material materialElement = m_doc.GetElement(m_face.MaterialElementId) as Material; info += "] Face MaterialElement Name: [" + materialElement.Name + "] Shininess: [" + materialElement.Shininess; } else { info += "] Face.MaterialElement is null [" + referenceElement.Category.Name; } info += "]"; m_outputInfo.Add(info); Autodesk.Revit.DB.UV endptUV = reference.UVPoint; Autodesk.Revit.DB.XYZ FaceNormal = m_face.ComputeDerivatives(endptUV).BasisZ; // face normal where ray hits FaceNormal = m_rClosest.GetInstanceTransform().OfVector(FaceNormal); // transformation to get it in terms of document coordinates instead of the parent symbol Autodesk.Revit.DB.XYZ directionMirrored = m_direction - 2 * m_direction.DotProduct(FaceNormal) * FaceNormal; //http://www.fvastro.org/presentations/ray_tracing.htm m_direction = directionMirrored; // get ready to shoot the next ray startpt = endpt; } } } transaction.Commit(); m_stopWatch.Stop(); TimeSpan ts = m_stopWatch.Elapsed; string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); m_outputInfo.Add(elapsedTime + "\n" + "Lines = " + m_LineCount + "\n" + "Rays = " + m_RayCount); m_stopWatch.Reset(); OutputInformation(); }
/// <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); }