Buckets:
kuklev9797/revit-ckpts / assets /samples /Samples /FindReferencesByDirection /RaytraceBounce /CS /RayTraceBounceForm.cs
| // | |
| // (C) Copyright 2003-2023 by Autodesk, Inc. | |
| // | |
| // Permission to use, copy, modify, and distribute this software in | |
| // object code form for any purpose and without fee is hereby granted, | |
| // provided that the above copyright notice appears in all copies and | |
| // that both that copyright notice and the limited warranty and | |
| // restricted rights notice below appear in all supporting | |
| // documentation. | |
| // | |
| // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. | |
| // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF | |
| // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. | |
| // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE | |
| // UNINTERRUPTED OR ERROR FREE. | |
| // | |
| // Use, duplication, or disclosure by the U.S. Government is subject to | |
| // restrictions set forth in FAR 52.227-19 (Commercial Computer | |
| // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) | |
| // (Rights in Technical Data and Computer Software), as applicable. | |
| // | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Diagnostics; | |
| using System.IO; | |
| using Autodesk.Revit.DB; | |
| using Autodesk.Revit.UI; | |
| using TaskDialog = Autodesk.Revit.UI.TaskDialog; | |
| namespace Revit.SDK.Samples.RayTraceBounce.CS | |
| { | |
| /// <summary> | |
| /// 1. This form allowing entry of a coordinate location (X, Y, Z) within the model and a coordinate direction (i, j, k). | |
| /// 2. Launch a ray from this location in this direction to find the first intersection with a face | |
| /// 3. Calculate the reflection angle of the ray from the face and launch another ray to find the next intersection | |
| /// 4. For each ray/intersection, create a model line connecting the two points. The end result should be a series of model lines bouncing from item to item. | |
| /// 5. Provide a hard limit of say, 100 intersections, to prevent endless reflections within an enclosed space. | |
| /// 6. Write a log file of the intersection containing: the element type, id, and material of the intersected face. | |
| /// </summary> | |
| public partial class RayTraceBounceForm : System.Windows.Forms.Form | |
| { | |
| /// <summary> | |
| /// current assembly name | |
| /// </summary> | |
| private static string AssemblyName = System.Reflection.Assembly.GetExecutingAssembly().Location; | |
| /// <summary> | |
| /// current assembly directory | |
| /// </summary> | |
| private static string AssemblyDirectory = Path.GetDirectoryName(AssemblyName); | |
| /// <summary> | |
| /// epsilon limit | |
| /// </summary> | |
| private static double epsilon = 0.00000001; | |
| /// <summary> | |
| /// how many bounces to run | |
| /// </summary> | |
| private static int rayLimit = 100; | |
| /// <summary> | |
| /// revit application | |
| /// </summary> | |
| private Autodesk.Revit.UI.UIApplication m_app; | |
| /// <summary> | |
| /// current document | |
| /// </summary> | |
| private Document m_doc; | |
| /// <summary> | |
| /// closet geometry reference between origin/intersection and ray/intersection | |
| /// </summary> | |
| private Autodesk.Revit.DB.ReferenceWithContext m_rClosest = null; | |
| /// <summary> | |
| /// 3D view | |
| /// </summary> | |
| private Autodesk.Revit.DB.View3D m_view = null; | |
| /// <summary> | |
| /// the count of line between origin/intersection and ray/intersection | |
| /// </summary> | |
| private int m_LineCount = 0; | |
| /// <summary> | |
| /// the count of ray between origin/intersection and ray/intersection | |
| /// </summary> | |
| private int m_RayCount = 0; | |
| /// <summary> | |
| /// the face which the ray intersect with | |
| /// </summary> | |
| private Face m_face = null; | |
| /// <summary> | |
| /// ray start from here | |
| /// </summary> | |
| private Autodesk.Revit.DB.XYZ m_origin = new Autodesk.Revit.DB.XYZ(0, 0, 0); | |
| /// <summary> | |
| /// ray direction | |
| /// </summary> | |
| private Autodesk.Revit.DB.XYZ m_direction = new Autodesk.Revit.DB.XYZ(0, 0, 0); | |
| /// <summary> | |
| /// for time calculation | |
| /// </summary> | |
| private Stopwatch m_stopWatch = new Stopwatch(); | |
| /// <summary> | |
| /// output string list | |
| /// </summary> | |
| private List<string> m_outputInfo = new List<string>(); | |
| /// <summary> | |
| /// trace listener | |
| /// </summary> | |
| private TraceListener m_txtListener = null; | |
| /// <summary> | |
| /// Constructor | |
| /// </summary> | |
| /// <param name="commandData">Revit application</param> | |
| /// <param name="v">3D View</param> | |
| public RayTraceBounceForm(ExternalCommandData commandData, Autodesk.Revit.DB.View3D v) | |
| { | |
| InitializeComponent(); | |
| string logFile = AssemblyName.Replace(".dll", DateTime.Now.ToString("yyyyMMddhhmmss") + ".log"); | |
| if (File.Exists(logFile)) File.Delete(logFile); | |
| m_txtListener = new TextWriterTraceListener(logFile); | |
| Trace.Listeners.Add(m_txtListener); | |
| m_app = commandData.Application; | |
| m_doc = commandData.Application.ActiveUIDocument.Document; | |
| m_view = v; | |
| UpdateData(true); | |
| // Delete lines it created | |
| DeleteLines(); | |
| } | |
| /// <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.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> | |
| /// Cancel button click event | |
| /// </summary> | |
| /// <param name="sender"></param> | |
| /// <param name="e"></param> | |
| private void buttonCancel_Click(object sender, EventArgs e) | |
| { | |
| Close(); | |
| } | |
| /// <summary> | |
| /// Clean up any resources being used. | |
| /// </summary> | |
| /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |
| protected override void Dispose(bool disposing) | |
| { | |
| Trace.Flush(); | |
| m_txtListener.Close(); | |
| Trace.Close(); | |
| Trace.Listeners.Remove(m_txtListener); | |
| if (disposing && (components != null)) | |
| { | |
| components.Dispose(); | |
| } | |
| base.Dispose(disposing); | |
| } | |
| /// <summary> | |
| /// Update textbox data with member variable | |
| /// </summary> | |
| /// <param name="updateControl">if get/set date from control</param> | |
| public bool UpdateData(bool updateControl) | |
| { | |
| try | |
| { | |
| if (updateControl) | |
| { | |
| textBoxLocationX.Text = Convert.ToString(0.0); | |
| textBoxLocationY.Text = Convert.ToString(0.0); | |
| textBoxLocationZ.Text = Convert.ToString(0.0); | |
| textBoxDirectionI.Text = Convert.ToString(Math.Cos(0)); | |
| textBoxDirectionJ.Text = Convert.ToString(Math.Sin(0)); | |
| textBoxDirectionK.Text = Convert.ToString(0.0); | |
| } | |
| else | |
| { | |
| if (string.IsNullOrEmpty(textBoxLocationX.Text) || string.IsNullOrEmpty(textBoxLocationY.Text) || | |
| string.IsNullOrEmpty(textBoxLocationZ.Text) || string.IsNullOrEmpty(textBoxDirectionI.Text) || | |
| string.IsNullOrEmpty(textBoxDirectionJ.Text) || string.IsNullOrEmpty(textBoxDirectionK.Text)) | |
| { | |
| TaskDialog.Show("Revit", "Value cannot be empty."); | |
| return false; | |
| } | |
| m_origin = new XYZ( | |
| Convert.ToDouble(textBoxLocationX.Text), | |
| Convert.ToDouble(textBoxLocationY.Text), | |
| Convert.ToDouble(textBoxLocationZ.Text)); | |
| m_direction = new XYZ( | |
| Convert.ToDouble(textBoxDirectionI.Text), | |
| Convert.ToDouble(textBoxDirectionJ.Text), | |
| Convert.ToDouble(textBoxDirectionK.Text)); | |
| } | |
| return true; | |
| } | |
| catch (System.Exception) | |
| { | |
| return false; | |
| } | |
| } | |
| /// <summary> | |
| /// Find the first intersection with a face | |
| /// </summary> | |
| /// <param name="references"></param> | |
| /// <returns></returns> | |
| public Autodesk.Revit.DB.ReferenceWithContext FindClosestReference(IList<ReferenceWithContext> references) | |
| { | |
| double face_prox = Double.PositiveInfinity; | |
| double edge_prox = Double.PositiveInfinity; | |
| foreach (ReferenceWithContext r in references) | |
| { | |
| Reference reference = r.GetReference(); | |
| Element referenceElement = m_doc.GetElement(reference); | |
| GeometryObject referenceGeometryObject = referenceElement.GetGeometryObjectFromReference(reference); | |
| m_face = null; | |
| m_face = referenceGeometryObject as Face; | |
| Edge edge = null; | |
| edge = referenceGeometryObject as Edge; | |
| if (m_face != null) | |
| { | |
| if ((r.Proximity < face_prox) && (r.Proximity > epsilon)) | |
| { | |
| m_rClosest = r; | |
| face_prox = Math.Abs(r.Proximity); | |
| } | |
| } | |
| else if (edge != null) | |
| { | |
| if ((r.Proximity < edge_prox) && (r.Proximity > epsilon)) | |
| { | |
| edge_prox = Math.Abs(r.Proximity); | |
| } | |
| } | |
| } | |
| if (edge_prox <= face_prox) | |
| { | |
| // stop bouncing if there is an edge at least as close as the nearest face - there is no single angle of reflection for a ray striking a line | |
| m_outputInfo.Add("there is an edge at least as close as the nearest face - there is no single angle of reflection for a ray striking a line"); | |
| m_rClosest = null; | |
| } | |
| return m_rClosest; | |
| } | |
| /// <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 = Line.CreateBound(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 = Plane.CreateByOriginAndBasis(direction, rotatedDirection, startpt); | |
| SketchPlane skplane = SketchPlane.Create(m_app.ActiveUIDocument.Document, geometryPlane); | |
| ModelCurve mcurve = m_app.ActiveUIDocument.Document.Create.NewModelCurve(line, skplane); | |
| m_app.ActiveUIDocument.Document.Regenerate(); | |
| //ElementArray lsArr = mcurve.LineStyles; | |
| ICollection<ElementId> lsArr = mcurve.GetLineStyleIds(); | |
| foreach (Autodesk.Revit.DB.ElementId eid in lsArr) | |
| { | |
| Element e = m_app.ActiveUIDocument.Document.GetElement(eid); | |
| 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> | |
| /// Delete all unnecessary lines | |
| /// </summary> | |
| public void DeleteLines() | |
| { | |
| int delLineNum = 0; | |
| try | |
| { | |
| SubTransaction transaction = new SubTransaction(m_app.ActiveUIDocument.Document); | |
| transaction.Start(); | |
| List<Autodesk.Revit.DB.Element> list = new List<Autodesk.Revit.DB.Element>(); | |
| ElementClassFilter filter = new ElementClassFilter(typeof(Autodesk.Revit.DB.CurveElement)); | |
| FilteredElementCollector collector = new FilteredElementCollector(m_app.ActiveUIDocument.Document); | |
| list.AddRange(collector.WherePasses(filter).ToElements()); | |
| foreach (Autodesk.Revit.DB.Element e in list) | |
| { | |
| ModelCurve mc = e as ModelCurve; | |
| if (mc != null) | |
| { | |
| if (mc.LineStyle.Name == "bounce" || mc.LineStyle.Name == "normal") | |
| { | |
| m_app.ActiveUIDocument.Document.Delete(e.Id); | |
| delLineNum++; | |
| } | |
| } | |
| } | |
| transaction.Commit(); | |
| } | |
| catch (System.Exception) | |
| { | |
| } | |
| } | |
| /// <summary> | |
| /// Output the information to log file | |
| /// </summary> | |
| protected void OutputInformation() | |
| { | |
| foreach (string item in m_outputInfo) | |
| { | |
| Trace.WriteLine(item); | |
| } | |
| Trace.Flush(); | |
| } | |
| } | |
| } | |
Xet Storage Details
- Size:
- 17.7 kB
- Xet hash:
- d894a86968561b05efb8749d1aa8d1e5fc6ff1f5a145414ad278235e64bf65a2
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.