Revision: 55810
          http://sourceforge.net/p/brlcad/code/55810
Author:   phoenixyjll
Date:     2013-06-21 10:37:25 +0000 (Fri, 21 Jun 2013)
Log Message:
-----------
Add Newton-Raphson iteration in PCI to improve accuracy (use the one from 
subdivision and linear approximation as a starting point)

Modified Paths:
--------------
    brlcad/trunk/src/libbrep/intersect.cpp

Modified: brlcad/trunk/src/libbrep/intersect.cpp
===================================================================
--- brlcad/trunk/src/libbrep/intersect.cpp      2013-06-21 00:09:55 UTC (rev 
55809)
+++ brlcad/trunk/src/libbrep/intersect.cpp      2013-06-21 10:37:25 UTC (rev 
55810)
@@ -246,6 +246,11 @@
 // intersections defined by openNURBS (see other/openNURBS/opennurbs_curve.h)
 #define PCI_DEFAULT_TOLERANCE 0.001
 
+// Newton-Raphson iteration needs a good start. Although we can almost get
+// a good starting point every time, but in case of some unfortunate cases,
+// we define a maximum iteration, preventing from infinite loop.
+#define PCI_MAX_ITERATIONS 100
+
 bool
 ON_Intersect(const ON_3dPoint& pointA,
             const ON_Curve& curveB,
@@ -305,29 +310,60 @@
     }
 
     for (unsigned int i = 0; i < candidates.size(); i++) {
-       // Use linear approximation to get the intersection point
+       // Use linear approximation to get an estimated intersection point
        ON_Line line(candidates[i]->m_curve->PointAtStart(), 
candidates[i]->m_curve->PointAtEnd());
        double t, dis;
        line.ClosestPointTo(pointA, &t);
-       // Get the closest point on the line *segment* to the point
-       double closest_point_t;
+
+       // Make sure line_t belongs to [0, 1]
+       double line_t;
        if (t < 0)
-           closest_point_t = 0;
+           line_t = 0;
        else if (t > 1)
-           closest_point_t = 1;
+           line_t = 1;
        else
-           closest_point_t = t;
-       ON_3dPoint closest_point = line.PointAt(closest_point_t);
-       dis = pointA.DistanceTo(closest_point);
+           line_t = t;
 
+       double closest_point_t = candidates[i]->m_t.Min() + 
candidates[i]->m_t.Length()*line_t;
+       ON_3dPoint closest_point = curveB.PointAt(closest_point_t);
+       dis = closest_point.DistanceTo(pointA);
+
+       // Use Newton-Raphson method with the starting point from linear
+       // approximation.
+       // It's similar to point projection (or point inversion, or get
+       // closest point on curve). We calculate the root of:
+       //       (curve(t) - pointA) \dot tangent(t) = 0 (*)
+       // Then curve(t) may be the closest point on the curve to pointA.
+       //
+       // In some cases, the closest point (intersection point) is the
+       // endpoints of the curve, it does not satisfy (*), but that's
+       // OK because it already comes out with the linear approximation
+       // above.
+
+       double last_t = DBL_MAX;
+       int iterations = 0;
+       while (!ON_NearZero(last_t-closest_point_t)
+           && dis > tolerance
+           && iterations++ < PCI_MAX_ITERATIONS) {
+           ON_3dVector tangent, s_deriv;
+           last_t = closest_point_t;
+           curveB.Ev2Der(closest_point_t, closest_point, tangent, s_deriv);
+           double F = ON_DotProduct(closest_point-pointA, tangent);
+           double derivF = ON_DotProduct(closest_point-pointA, s_deriv) + 
ON_DotProduct(tangent, tangent);
+           if (!ON_NearZero(derivF))
+               closest_point_t -= F/derivF;
+           dis = closest_point.DistanceTo(pointA);
+       }
+       closest_point = curveB.PointAt(closest_point_t);
+
        if (dis <= tolerance) {
            ON_PX_EVENT *Event = new ON_PX_EVENT;
            Event->m_type = ON_PX_EVENT::pcx_point;
            Event->m_A = pointA;
            Event->m_B = closest_point;
-           Event->m_b[0] = 
candidates[i]->m_t.Min()+candidates[i]->m_t.Length()*closest_point_t;
+           Event->m_b[0] = closest_point_t;
            Event->m_Mid = (pointA + Event->m_B) * 0.5;
-           Event->m_radius = dis * 0.5;
+           Event->m_radius = closest_point.DistanceTo(pointA) * 0.5;
            x.Append(*Event);
            return true;
        }

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to