Ray Intersection - Getting the hit geometry

Hi all,
I have a scene with many surfaces and I want to do some ray intersections (no reflexion, just direct). In order to solve the untrimmed geometry problem, I was about to use the pointOnFace method proposed on many other posts.

But I couldn’t find how to get the hit geometry from the RayShoot method. The function only outputs the hit point but do not give any reference to the surface that has been hit. Actually for other purposes I would really need to have this information (which surface has been hit by the ray).

Does someone have an idea on how to do it in C# (I’m doing this for a plugin) ?

So far, I could momentarily solve my problem by writing the following function.
The principle is the following :

  • for each ray, the program go through all the input geometry to see on which one arrived the ray.

  • then it checks if the ray arrived inside the trimmed geometry.

      public Point3d FullRayShoot(Ray3d ray, IEnumerable<BrepFace> brepFaces, out int hitFace, out bool success)
          {
              var endPoint = Intersection.RayShoot(ray, _brepFaces, 1);
              double u_closest = 0.0;
              double v_closest = 0.0;
              hitFace = 0;
              int i = 0;
              success = false;
    
              if (endPoint != null)
              {
                  foreach (BrepFace bf in brepFaces)
                  {
                      bf.ClosestPoint(endPoint[0], out u_closest, out v_closest);
                      if (bf.PointAt(u_closest, v_closest).DistanceTo(endPoint[0]) <= _doc.ModelAbsoluteTolerance)
                      {
                          if (bf.IsPointOnFace(u_closest, v_closest) == PointFaceRelation.Interior)
                          {
                              hitFace = i;
                              success = true;
                              return endPoint[0];
                          }
                      }
                      i++;
                  }
              }
              return new Point3d();
          }
    

But I believe this is completely inefficient way to proceed. Going through all the geometry for each rays doesn’t sounds a good practice for me. Especially for further developement where I might have hundreds of surfaces and hundreds of rays lunched from every one. This code might slow down the plugin.

Does someone have a solution for this ?

Hi @TomTom, I do not understand what do you mean by “selecting” the object before ray shooting. Can you please attach some code ? Eventually just the command line.
So far I couldn’t find any way to get the hit geometry directly from the rayshooting option. Althought it is the most obvious way to proceed. The solution that I proposed works good but is especially inefficient.

The only thing that I could find in the API is the following description of the output, but I couldn’t use it (the output array is never the size of the input geometry) :

Return Value

Type:Point3d[ ]
An array of points: one for each face that was passed by the faceIds out reference.

Hi @em.rudelle,

Internally, we know which Brep face was hit. RhinoCommon just needs to return this. I’ve created an issue so we can provide this in the future.

https://mcneel.myjetbrains.com/youtrack/issue/RH-57098

– Dale

2 Likes

Sorry but I’m very confused with what I should do with this ObjectTable. According to Dale’s answer, it looks like the rayshoot method doesn’t output the hit geometry in any way. I’m not sure you can get it by “selecting the object before doing a rayshoot”, I’m not even sure if that makes any sense. Please attach some code, it would be very helpful.

RH-57098 is fixed in the latest WIP

Thanks for the update !
Although we cannot expect our users to run on the last WIP version. As a matter of fact I finally wrote a code that computes this RayShoot very fast, and it is compatible with Rhino6. I’m sharing it here, in case someone read this and has the same problem later on.

public Point3d FullRayShoot(Ray3d ray, IEnumerable<Brep> breps, out int hitFace, out bool success)
    {
        success = false;
        hitFace = 0;
        var rayCrv = new Line(ray.Position, ray.Direction, 999999999999).ToNurbsCurve();
        var returnPoint = new Point3d();

        double minDist = 9999999999;
        int i = 0;
        foreach (Brep bp in breps)
        {
            bool interResult = Intersection.CurveBrepFace(rayCrv, bp.Faces[0],_doc.ModelAbsoluteTolerance,out Curve[] curves,out Point3d[] points);
            if(interResult)
            {
                if (points.Length != 0)
                {
                    double dist = points[0].DistanceTo(ray.Position);
                    if (dist < minDist && dist > _doc.ModelAbsoluteTolerance)
                    {
                        hitFace = i;
                        success = true;
                        returnPoint = points[0];
                        minDist = dist;
                    }
                }
            }
            i++;
        }

        return returnPoint;
    }

The structure of inputs/outputs is not very logical but fitted my needs and the rest of my program at that point. Modification are more than welcome :slight_smile:

Where exactly did you optimise something? Don’t get me wrong, I really like to know, but I don’t understand where any optimisation was applyied here. The same confusion I had with your PM.

Hi again @TomTom,

The algorithm is not the same since I’m doing intersection on geometry myself instead of using the rayshoot method.
On the first algorithm I was checking (among all surfaces) to which surface belonged the result point.
Whereas now I have it straight away.

If we assume that in the original rayshoot method, the program had to go through all geometry. It made two times through all the geometry for first methode. Only once for second.

I’m not trying to fool anyone, and positive critics are welcome. If you’re not interested in, it’s completely ok for me. Also I guess everything here is getting a bit confused for new observers since you delete all your messages.

I mean a simple optimisation is to filter out the physical intersections by using mathematical ones at first, so that you reduce computation time. In my example you see how I created 30001 objects. I simply added a bounding box intersection before doing the physical one, because I don’t need to do them on all.

In my previous posts (which I deleted) I was thinking that you are directly refering to RhinoObjects, so that a preselection (which might work similar) can be exploited. There are a couple of other optimisations possible, but this simple trick reduces computation already drastically:

ptest.gh (10.8 KB)

public Point3d FullRayShoot(Ray3d ray, IEnumerable<Brep> breps, out int hitFace, out bool success)
{
    success = false;
    hitFace = 0;
    Line rayLine = new Line(ray.Position, ray.Direction, 999999999999);
    var returnPoint = new Point3d();

    double minDist = 9999999999;
    int i = 0;
    foreach (Brep bp in breps)
    {
      // Get Bounding-Box
      BoundingBox bb = bp.GetBoundingBox(false);
      Interval linePM; // irrelevant
      // Filter by using mathematical intersection
      if (Rhino.Geometry.Intersect.Intersection.LineBox(rayLine, bb, 0.1, out linePM))
      {
        NurbsCurve rayCrv = rayLine.ToNurbsCurve();
        Curve[] curves;
        Point3d[] points;
        bool interResult = Rhino.Geometry.Intersect.Intersection.CurveBrepFace(rayCrv, bp.Faces[0], 0.001, out curves, out  points);
        if(interResult)
        {
          if (points.Length != 0)
          {
            double dist = points[0].DistanceTo(ray.Position);
            if (dist < minDist && dist > 0.001)
            {
              hitFace = i;
              success = true;
              returnPoint = points[0];
              minDist = dist;
            }
          }
        }
      }
      i++;
    }

    return returnPoint;
}

1 Like

Hi @TomTom,
Your help is much appreciated, thank you. I don’t have so many Breps to intersect with, but it already halved the computation time for my whole recognition process.
Yes I’m not very familiar with computation and optimization, so I’m glad you proposed your kind help.