From:                                         Harry Mattison

Sent:                                           Wednesday, December 23, 2009 04:26

To:                                               Anthony Hauck; Jeremy Tammik; Scott Conover

Subject:                                     playing pool with FindReferencesByDirection

Attachments:                          PoolTable.rvt; ClassLibraryC.dll

 

Hi,

 

Here's the modification we discussed to make the ray shooting SDK example a bit more fun. Some code cleanup might be in order before publishing it, but it works and can amuse a 6 year old, if nothing else.

 

Harry

 

 

 

 

                   public class RaytraceBouncePool : IExternalCommand {

            // have a line style "bounce" created in the document before running this

 

            ExternalCommandData cdata;

            Autodesk.Revit.Application app;

            Document doc;

            Face face = null;

            Autodesk.Revit.Geometry.Reference rClosest = null;

            Autodesk.Revit.Elements.View3D view = null;

            static double epsilon = 0.00000001;

            int LineCount = 0;

            int RayCount = 0;

 

            public IExternalCommand.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) {

                cdata = commandData;

                app = commandData.Application;

                doc = app.ActiveDocument;

                Get3DView();

                DeleteLines();

 

               // find the cue

               XYZ direction = null;

               XYZ startpt = null;

               List<Autodesk.Revit.Element> list = new List<Autodesk.Revit.Element>();

                Filter filter = app.Create.Filter.NewTypeFilter(typeof(Autodesk.Revit.Elements.FamilyInstance));

                int num = app.ActiveDocument.get_Elements(filter, list);

                foreach (Autodesk.Revit.Element e in list) {

                    if (e.Name == "cue") {

                       LocationCurve lc = e.Location as LocationCurve;

                       direction = lc.Curve.ComputeDerivatives(0,true).BasisX;

                       startpt = lc.Curve.get_EndPoint(1);

                        break;

                    }

                }

                if (view == null) MessageBox.Show("A default 3D view (named {3D}) must exist before running this command");

                else {                       

                        for (int ctr = 1; ctr <= 100; ctr++) // how many bounces to run

                    {

                            Autodesk.Revit.Geometry.ReferenceArray references = doc.FindReferencesByDirection(startpt, direction, view);

                            rClosest = null;

                            FindClosestReference(references);

                            if (rClosest == null) {

                                MessageBox.Show("Ray " + ctr + " aborted. No closest face reference found.");

                                return IExternalCommand.Result.Succeeded;

                            }

                            else {

                                XYZ endpt = new XYZ(rClosest.GlobalPoint.X, rClosest.GlobalPoint.Y, rClosest.GlobalPoint.Z);

                                if (startpt.AlmostEqual(endpt)) {

                                    MessageBox.Show("Start and end points are equal. Ray " + ctr + " aborted\n" + startpt.X + ", " + startpt.Y + ", " + startpt.Z);

                                    break;

                                }

                                else {

                                    MakeLine(startpt, endpt, direction, "bounce");

                                    RayCount = RayCount + 1;

                                    face = rClosest.GeometryObject as Face;

                                    if (rClosest.Element.Category.Name == "Doors")

                                    {

                                       MessageBox.Show("You sank the ball with " + ctr + " shots.");

                                       return IExternalCommand.Result.Succeeded;

                                    }

                                    UV endptUV = rClosest.UVPoint;

                                    XYZ FaceNormal = face.ComputeDerivatives(endptUV).BasisZ// face normal where ray hits

                                    FaceNormal = rClosest.Transform.OfVector(FaceNormal); // transformation to get it in terms of document coordinates instead of the parent symbol

                                    XYZ directionMirrored = direction - 2 * direction.Dot(FaceNormal) * FaceNormal; //http://www.fvastro.org/presentations/ray_tracing.htm

                                    direction = directionMirrored; // get ready to shoot the next ray

                                    startpt = endpt;

                                }

                            }

                        }

                   

                }

                return IExternalCommand.Result.Succeeded;

            }

 

            public Autodesk.Revit.Geometry.Reference FindClosestReference(ReferenceArray references) {

                double face_prox = Double.PositiveInfinity;

                double edge_prox = Double.PositiveInfinity;

                //string refs = "";

                foreach (Autodesk.Revit.Geometry.Reference r in references) {

                   if (r.Element.Category.Name != "Generic Models")

                   {

                      face = null;

                      face = r.GeometryObject as Face;

                      Edge edge = null;

                      edge = r.GeometryObject as Edge;

                      if (face != null)

                      {

                         //refs = refs + r.ProximityParameter + "\n";

                         if (Math.Abs(r.ProximityParameter) < face_prox && r.ProximityParameter > epsilon) //when startpoint is on a surface, should FindReferencesByDirection find that surface?

                         {

                            rClosest = r;

                            face_prox = Math.Abs(r.ProximityParameter);

                         }

                      }

                      if (edge != null)

                      {

                         if (Math.Abs(r.ProximityParameter) < edge_prox && r.ProximityParameter > epsilon) //when startpoint is on a surface, should FindReferencesByDirection find that surface?

                         {

                            edge_prox = Math.Abs(r.ProximityParameter);

                         }

                      }

                   }

                }

                //MessageBox.Show("Distance to references found:\n" + refs);

                if (edge_prox <= face_prox) rClosest = null; // stop bouncing if there is an edge at least as close as the neareast face - there is no single angle of reflection for a ray striking a line

                return rClosest;

            }

 

            public void MakeLine(XYZ startpt, XYZ endpt, XYZ direction, string style) {

                LineCount = LineCount + 1;

                Line line = app.Create.NewLineBound(startpt, endpt);

                Plane geometryPlane = app.Create.NewPlane(direction, startpt);

                SketchPlane skplane = app.ActiveDocument.Create.NewSketchPlane(geometryPlane);

                ModelCurve mcurve = app.ActiveDocument.Create.NewModelCurve(line, skplane);

                ElementArray lsArr = mcurve.LineStyles;

                foreach (Autodesk.Revit.Element e in lsArr) {

                    if (e.Name == style) {

                        mcurve.LineStyle = e;

                        break;

                    }

                }

            }

 

            public void Get3DView() {

                List<Autodesk.Revit.Element> list = new List<Autodesk.Revit.Element>();

                Filter filter = app.Create.Filter.NewTypeFilter(typeof(Autodesk.Revit.Elements.View3D));

                Int64 num = app.ActiveDocument.get_Elements(filter, list);

                foreach (Autodesk.Revit.Element v in list) {

                    if (v.Name == "{3D}") {

                        view = v as Autodesk.Revit.Elements.View3D;

                        break;

                    }

                }

            }

 

            public void DeleteLines() {

                List<Autodesk.Revit.Element> list = new List<Autodesk.Revit.Element>();

                Filter filter = app.Create.Filter.NewTypeFilter(typeof(Autodesk.Revit.Elements.CurveElement), true);

                Int64 num = app.ActiveDocument.get_Elements(filter, list);

                foreach (Autodesk.Revit.Element e in list) {

                    ModelCurve mc = e as ModelCurve;

                    if (mc != null) {

                        if (mc.LineStyle.Name == "bounce" || mc.LineStyle.Name == "normal") app.ActiveDocument.Delete(e);

                    }

                }

            }

        }