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);
}
}
}
}