Revision: 55833
          http://sourceforge.net/p/brlcad/code/55833
Author:   phoenixyjll
Date:     2013-06-25 06:48:22 +0000 (Tue, 25 Jun 2013)
Log Message:
-----------
Begin to implement curve-curve intersections. More tests and improvements are 
needed.

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

Modified: brlcad/trunk/include/brep.h
===================================================================
--- brlcad/trunk/include/brep.h 2013-06-24 20:51:29 UTC (rev 55832)
+++ brlcad/trunk/include/brep.h 2013-06-25 06:48:22 UTC (rev 55833)
@@ -1960,6 +1960,100 @@
             const ON_Interval* surfaceB_udomain = 0,
             const ON_Interval* surfaceB_vdomain = 0);
 
+/**
+ * An overload of ON_Intersect for curve-curve intersection.
+ *
+ * Description:
+ *   Intersect curveA with curveB.
+ *
+ * Parameters:
+ *   curveA - [in]
+ *
+ *   curveB - [in]
+ *
+ *   x - [out] Intersection events are appended to this array.
+ *
+ *   intersection_tolerance - [in]  If the distance from a point
+ *     on curveA to curveB is <= intersection tolerance,
+ *     then the point will be part of an intersection event.
+ *     If the input intersection_tolerance <= 0.0, then 0.001 is used.
+ *
+ *   overlap_tolerance - [in] If t1 and t2 are parameters of
+ *     curveA's intersection events and the distance from curveA(t) to
+ *     curveB is <= overlap_tolerance for every t1 <= t <= t2,
+ *     then the event will be returened as an overlap event.
+ *     If the input overlap_tolerance <= 0.0, then
+ *     intersection_tolerance*2.0 is used.
+ *
+ *   curveA_domain - [in] optional restriction on curveA domain
+ *
+ *   curveB_domain - [in] optional restriction on curveB domain
+ *
+ * Returns:
+ *    Number of intersection events appended to x.
+ */
+extern BREP_EXPORT int
+ON_Intersect(const ON_Curve* curveA,
+            const ON_Curve* curveB,
+            ON_SimpleArray<ON_X_EVENT>& x,
+            double intersection_tolerance = 0.0,
+            double overlap_tolerance = 0.0,
+            const ON_Interval* curveA_domain = 0,
+            const ON_Interval* curveB_domain = 0);
+
+/**
+ * An overload of ON_Intersect for curve-surface intersection.
+ *
+ * Description:
+ *   Intersect curveA with surfaceB.
+ *
+ * Parameters:
+ *   curveA - [in]
+ *
+ *   surfaceB - [in]
+ *
+ *   x - [out] Intersection events are appended to this array.
+ *
+ *   intersection_tolerance - [in]
+ *     If the distance from a point on curveA to the surface
+ *     is <= intersection tolerance, then the point will be part
+ *     of an intersection event, or there is an intersection event
+ *     the point leads to. If the input intersection_tolerance <= 0.0,
+ *     then 0.001 is used.
+ *
+ *   overlap_tolerance - [in]
+ *     If the input overlap_tolerance <= 0.0, then
+ *     2.0*intersection_tolerance is used.  Otherwise, overlap
+ *     tolerance must be >= intersection_tolerance.
+ *     In all cases, the intersection calculation is performed
+ *     with an overlap_tolerance that is >= intersection_tolerance.
+ *     If t1 and t2 are curve parameters of intersection events
+ *     and the distance from curve(t) to the surface
+ *     is <= overlap_tolerance for every t1 <= t <= t2, then the
+ *     event will be returned as an overlap event.
+ *
+ *   curveA_domain - [in]
+ *     optional restriction on curveA domain
+ *
+ *   surfaceB_udomain - [in]
+ *     optional restriction on surfaceB u domain
+ *
+ *   surfaceB_vdomain - [in]
+ *     optional restriction on surfaceB v domain
+ *
+ * Returns:
+ *    Number of intersection events appended to x.
+ */
+extern BREP_EXPORT int
+ON_Intersect(const ON_Curve* curveA,
+            const ON_Surface* surfaceB,
+            ON_SimpleArray<ON_X_EVENT>& x,
+            double intersection_tolerance = 0.0,
+            double overlap_tolerance = 0.0,
+            const ON_Interval* curveA_domain = 0,
+            const ON_Interval* surfaceB_udomain = 0,
+            const ON_Interval* surfaceB_vdomain = 0);
+
 } /* extern C++ */
 #endif
 

Modified: brlcad/trunk/src/libbrep/intersect.cpp
===================================================================
--- brlcad/trunk/src/libbrep/intersect.cpp      2013-06-24 20:51:29 UTC (rev 
55832)
+++ brlcad/trunk/src/libbrep/intersect.cpp      2013-06-25 06:48:22 UTC (rev 
55833)
@@ -102,6 +102,11 @@
        ON_BoundingBox new_bbox(m_node.m_min-vtol, m_node.m_max+vtol);
        return new_bbox.IsPointIn(pt);
     }
+    bool Intersect(const Subcurve& other) const
+    {
+       ON_BoundingBox intersection;
+       return intersection.Intersection(m_node, other.m_node);
+    }
 };
 
 
@@ -443,6 +448,253 @@
 
 
 /**
+ * Curve-curve intersection (CCI)
+ */
+
+// We make the default tolerance for CCI the same as that of curve-curve
+// intersections defined by openNURBS (see other/openNURBS/opennurbs_curve.h)
+#define CCI_DEFAULT_TOLERANCE 0.001
+
+// The maximal depth for subdivision - trade-off between accurancy and
+// performance
+#define MAX_CCI_DEPTH 8
+
+// 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 CCI_MAX_ITERATIONS 100
+
+// We can only test a finite number of points to determine overlap.
+// Here we test 16 points uniformly distributed.
+#define CCI_OVERLAP_TEST_POINTS 16
+
+// Build the curve tree root within a given domain
+bool
+build_root(const ON_Curve* curve, const ON_Interval* domain, Subcurve& root)
+{
+    if (domain == NULL || *domain == curve->Domain()) {
+       root.m_curve = curve->Duplicate();
+       root.m_t = curve->Domain();
+    } else {
+       // Use ON_Curve::Split() to get the sub-curve inside the domain
+       ON_Curve *temp_curve1 = NULL, *temp_curve2 = NULL, *temp_curve3 = NULL;
+       if (!curve->Split(domain->Min(), temp_curve1, temp_curve2))
+           return false;
+       delete temp_curve1;
+       temp_curve1 = NULL;
+       if (!temp_curve2->Split(domain->Max(), temp_curve1, temp_curve3))
+           return false;
+       delete temp_curve1;
+       delete temp_curve2;
+       root.m_curve = temp_curve3;
+       root.m_t = *domain;
+    }
+
+    root.SetBBox(root.m_curve->BoundingBox());
+    root.m_islinear = root.m_curve->IsLinear();
+    return true;
+}
+
+void
+newton_cci(double& t_a, double& t_b, const ON_Curve* curveA, const ON_Curve* 
curveB, double intersection_tolerance)
+{
+    // Equations:
+    //   x_a(t_a) - x_b(t_b) = 0
+    //   y_a(t_a) - y_b(t_b) = 0
+    //   z_a(t_a) - z_b(t_b) = 0
+    // It's an over-determined system.
+    // We use Newton-Raphson iterations to solve the first two equations,
+    // and use the third for checking.
+    double last_t_a = DBL_MAX*.5, last_t_b = DBL_MAX*.5;
+    ON_3dPoint pointA = curveA->PointAt(t_a);
+    ON_3dPoint pointB = curveB->PointAt(t_b);
+    double distance = pointA.DistanceTo(pointB);
+    int iteration = 0;
+    while (fabs(last_t_a - t_a) + fabs(last_t_b - t_b) > ON_ZERO_TOLERANCE
+       && distance > intersection_tolerance
+       && iteration++ < CCI_MAX_ITERATIONS) {
+       last_t_a = t_a, last_t_b = t_b;
+       ON_3dVector derivA, derivB;
+       curveA->Ev1Der(t_a, pointA, derivA);
+       curveB->Ev1Der(t_b, pointB, derivB);
+       ON_Matrix J(2, 2), F(2, 1);
+       J[0][0] = derivA.x;
+       J[0][1] = -derivB.x;
+       J[1][0] = derivA.y;
+       J[1][1] = -derivB.y;
+       F[0][0] = pointA.x - pointB.x;
+       F[1][0] = pointA.y - pointB.y;
+       if (J.Invert(0.0)) {
+           // FIXME: More elegant error handling.
+           bu_log("Inverse failed.\n");
+           continue;
+       }
+       ON_Matrix Delta;
+       Delta.Multiply(J, F);
+       t_a -= Delta[0][0];
+       t_b -= Delta[1][0];
+       distance = pointA.DistanceTo(pointB);
+    }
+}
+
+int
+ON_Intersect(const ON_Curve* curveA,
+            const ON_Curve* curveB,
+            ON_SimpleArray<ON_X_EVENT>& x,
+            double intersection_tolerance,
+            double UNUSED(overlap_tolerance),
+            const ON_Interval* curveA_domain,
+            const ON_Interval* curveB_domain)
+{
+    if (intersection_tolerance <= 0.0)
+       intersection_tolerance = 0.001;
+    if (overlap_tolerance <= 0.0)
+       overlap_tolerance = 2*intersection_tolerance;
+
+    Subcurve rootA, rootB;
+    if (!build_root(curveA, curveA_domain, rootA))
+       return 0;
+    if (!build_root(curveB, curveB_domain, rootB))
+       return 0;
+
+    typedef std::vector<std::pair<Subcurve*, Subcurve*> > NodePairs;
+    NodePairs candidates, next_candidates;
+    if (rootA.Intersect(rootB))
+       candidates.push_back(std::make_pair(&rootA, &rootB));
+
+    // Use sub-division and bounding box intersections first.
+    for (int h = 0; h <= MAX_CCI_DEPTH; h++) {
+       if (candidates.empty())
+           break;
+       next_candidates.clear();
+       for (NodePairs::iterator i = candidates.begin(); i != candidates.end(); 
i++) {
+           std::vector<Subcurve*> splittedA, splittedB;
+           if ((*i).first->m_islinear || (*i).first->Split() != 0) {
+               splittedA.push_back((*i).first);
+           } else {
+               splittedA.push_back((*i).first->m_children[0]);
+               splittedA.push_back((*i).first->m_children[1]);
+           }
+           if ((*i).second->m_islinear || (*i).second->Split() != 0) {
+               splittedA.push_back((*i).second);
+           } else {
+               splittedA.push_back((*i).second->m_children[0]);
+               splittedA.push_back((*i).second->m_children[1]);
+           }
+           for (unsigned int j = 0; j < splittedA.size(); j++)
+               for (unsigned int k = 0; k < splittedB.size(); k++)
+                   if (splittedA[j]->Intersect(*splittedB[k]))
+                       next_candidates.push_back(std::make_pair(splittedA[j], 
splittedB[k]));
+       }
+       candidates = next_candidates;
+    }
+
+    // For intersected bounding boxes, we calculate an accurate intersection
+    // point.
+    for (NodePairs::iterator i = candidates.begin(); i != candidates.end(); 
i++) {
+       /*
+       // First, use linear approximation to get a starting point
+       ON_Line lineA(curveA->PointAt(i->first->m_t.Min()), 
curveA->PointAt(i->first->m_t.Max()));
+       ON_Line lineB(curveB->PointAt(i->second->m_t.Min()), 
curveB->PointAt(i->second->m_t.Max()));
+       double t_lineA, t_lineB;
+       double t_a, t_b;
+       if (ON_IntersectLineLine(lineA, lineB, &t_lineA, &t_lineB, 
ON_ZERO_TOLERANCE, true)) {
+           // The line segments intersect
+           t_a = i->first->m_t.ParameterAt(t_lineA);
+           t_b = i->second->m_t.ParameterAt(t_lineB);
+       } else {
+           // Sometimes the approximated line segments do not intersect,
+           // but the curves DO intersect. We use the mid-points of the
+           // sub-curves as the starting point.
+           t_a = i->first->m_t.Mid();
+           t_b = i->second->m_t.Mid();
+       }*/
+
+       // Use two different start points - the two end-points of the interval
+       // If they converge to one point, it's considered an intersection
+       // point, otherwise it's considered an overlap event.
+       double t_a1 = i->first->m_t.Min(), t_b1 = i->second->m_t.Min();
+       newton_cci(t_a1, t_b1, curveA, curveB, intersection_tolerance);
+       double t_a2 = i->first->m_t.Max(), t_b2 = i->second->m_t.Max();
+       newton_cci(t_a2, t_b2, curveA, curveB, intersection_tolerance);
+
+       if (fabs(t_a1 - t_a2) + fabs(t_b1 - t_b2) < ON_ZERO_TOLERANCE*2) {
+           // the errors may double, so we use ON_ZERO_TOLERANCE*2
+           // it's considered the same point
+           ON_3dPoint pointA = curveA->PointAt(t_a1);
+           ON_3dPoint pointB = curveB->PointAt(t_b1);
+           double distance = pointA.DistanceTo(pointB);
+           // Check the validity of the solution
+           if (distance < intersection_tolerance) {
+               ON_X_EVENT Event;
+               Event.m_A[0] = pointA;
+               Event.m_B[0] = pointB;
+               Event.m_a[0] = t_a1;
+               Event.m_b[0] = t_b1;
+               Event.m_type = ON_X_EVENT::ccx_point;
+               x.Append(Event);
+           }
+       } else {
+           // Check overlap
+           bu_log("Maybe overlap.\n");
+           ON_3dPoint pointA1 = curveA->PointAt(t_a1);
+           ON_3dPoint pointB1 = curveB->PointAt(t_b1);
+           ON_3dPoint pointA2 = curveA->PointAt(t_a2);
+           ON_3dPoint pointB2 = curveB->PointAt(t_b2);
+           double distance1 = pointA1.DistanceTo(pointB1);
+           double distance2 = pointA2.DistanceTo(pointB2);
+           // Check the validity of the solution
+           if (distance1 < intersection_tolerance && distance2 < 
intersection_tolerance) {
+               ON_X_EVENT Event;
+               Event.m_A[0] = pointA1;
+               Event.m_A[1] = pointA2;
+               Event.m_B[0] = pointB1;
+               Event.m_B[1] = pointB2;
+               Event.m_a[0] = t_a1;
+               Event.m_a[1] = t_a2;
+               Event.m_b[0] = t_b1;
+               Event.m_b[1] = t_b2;
+               int j;
+               for (j = 1; j < CCI_OVERLAP_TEST_POINTS; j++) {
+                   double strike = 1.0/CCI_OVERLAP_TEST_POINTS;
+                   ON_3dPoint test_point = curveA->PointAt(t_a1 + 
(t_a2-t_a1)*j*strike);
+                   ON_ClassArray<ON_PX_EVENT> pci_x;
+                   // Use point-curve intersection
+                   if (!ON_Intersect(test_point, *curveA, pci_x, 
overlap_tolerance))
+                       break;
+               }
+               if (j != CCI_OVERLAP_TEST_POINTS)
+                   Event.m_type = ON_X_EVENT::ccx_point;
+               else
+                   Event.m_type = ON_X_EVENT::ccx_overlap;
+               x.Append(Event);
+           }
+       }
+    }
+
+    return x.Count();
+}
+
+
+/**
+ * Curve-surface intersection (CSI)
+ */
+int
+ON_Intersect(const ON_Curve*,
+            const ON_Surface*,
+            ON_SimpleArray<ON_X_EVENT>&,
+            double,
+            double,
+            const ON_Interval*,
+            const ON_Interval*,
+            const ON_Interval*)
+{
+    // Implement later.
+    return 0;
+}
+
+
+/**
  * Surface-surface intersections (SSI)
  *
  * approach:

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