Revision: 55715
          http://sourceforge.net/p/brlcad/code/55715
Author:   phoenixyjll
Date:     2013-06-12 07:12:47 +0000 (Wed, 12 Jun 2013)
Log Message:
-----------
Calculate point-curve intersection using sub-division.

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

Modified: brlcad/trunk/src/libbrep/intersect.cpp
===================================================================
--- brlcad/trunk/src/libbrep/intersect.cpp      2013-06-11 21:55:33 UTC (rev 
55714)
+++ brlcad/trunk/src/libbrep/intersect.cpp      2013-06-12 07:12:47 UTC (rev 
55715)
@@ -36,6 +36,168 @@
 #include "brep.h"
 
 
+/* Sub-division support for a curve.
+ * It's similar to generating the bounding box tree, when the Split()
+ * method is called, the curve is splitted into two parts, whose bounding
+ * boxes become the children of the original curve's bbox.
+ */
+struct Subcurve {
+private:
+    ON_BoundingBox m_node;
+public:
+    ON_Curve *m_curve;
+    ON_Interval m_t;
+    Subcurve *m_children[2];
+    ON_BOOL32 m_islinear;
+
+    Subcurve() : m_curve(NULL), m_islinear(false)
+    {
+       m_children[0] = m_children[1] = NULL;
+    }
+    Subcurve(const Subcurve &_scurve)
+    {
+       m_islinear = _scurve.m_islinear;
+       m_curve = _scurve.m_curve->Duplicate();
+       m_t = _scurve.m_t;
+       m_children[0] = m_children[1] = NULL;
+       SetBBox(_scurve.m_node);
+    }
+    ~Subcurve()
+    {
+       for (int i = 0; i < 2; i++) {
+           if (m_children[i])
+               delete m_children[i];
+       }
+       delete m_curve;
+    }
+    int Split()
+    {
+       for (int i = 0; i < 2; i++)
+           m_children[i] = new Subcurve();
+
+       if (m_curve->Split(m_t.Mid(), m_children[0]->m_curve, 
m_children[1]->m_curve) == false)
+           return -1;
+
+       m_children[0]->m_t = ON_Interval(m_t.Min(), m_t.Mid());
+       m_children[0]->SetBBox(m_children[0]->m_curve->BoundingBox());
+       m_children[0]->m_islinear = m_children[0]->m_curve->IsLinear();
+       m_children[1]->m_t = ON_Interval(m_t.Mid(), m_t.Max());
+       m_children[1]->SetBBox(m_children[1]->m_curve->BoundingBox());
+       m_children[1]->m_islinear = m_children[1]->m_curve->IsLinear();
+
+       return 0;
+    }
+    void GetBBox(ON_3dPoint &min, ON_3dPoint &max)
+    {
+       min = m_node.m_min;
+       max = m_node.m_max;
+    }
+    void SetBBox(const ON_BoundingBox &bbox)
+    {
+       m_node = bbox;
+    }
+    bool IsPointIn(const ON_3dPoint &pt)
+    {
+       return m_node.IsPointIn(pt);
+    }
+};
+
+
+/* Sub-division support for a surface.
+ * It's similar to generating the bounding box tree, when the Split()
+ * method is called, the surface is splitted into two parts, whose bounding
+ * boxes become the children of the original surface's bbox.
+ */
+struct Subsurface {
+private:
+    ON_BoundingBox m_node;
+public:
+    ON_Surface *m_surf;
+    ON_Interval m_u, m_v;
+    Subsurface *m_children[4];
+
+    Subsurface() : m_surf(NULL)
+    {
+       m_children[0] = m_children[1] = m_children[2] = m_children[3] = NULL;
+    }
+    Subsurface(const Subsurface &_ssurf)
+    {
+       m_surf = _ssurf.m_surf->Duplicate();
+       m_u = _ssurf.m_u;
+       m_v = _ssurf.m_v;
+       m_children[0] = m_children[1] = m_children[2] = m_children[3] = NULL;
+       SetBBox(_ssurf.m_node);
+    }
+    ~Subsurface()
+    {
+       for (int i = 0; i < 4; i++) {
+           if (m_children[i])
+               delete m_children[i];
+       }
+       delete m_surf;
+    }
+    int Split()
+    {
+       for (int i = 0; i < 4; i++)
+           m_children[i] = new Subsurface();
+       ON_Surface *temp_surf1 = NULL, *temp_surf2 = NULL;
+       ON_BOOL32 ret = true;
+       ret = m_surf->Split(0, m_u.Mid(), temp_surf1, temp_surf2);
+       if (!ret) {
+           delete temp_surf1;
+           delete temp_surf2;
+           return -1;
+       }
+
+       ret = temp_surf1->Split(1, m_v.Mid(), m_children[0]->m_surf, 
m_children[1]->m_surf);
+       delete temp_surf1;
+       if (!ret) {
+           delete temp_surf2;
+           return -1;
+       }
+       m_children[0]->m_u = ON_Interval(m_u.Min(), m_u.Mid());
+       m_children[0]->m_v = ON_Interval(m_v.Min(), m_v.Mid());
+       m_children[0]->SetBBox(m_children[0]->m_surf->BoundingBox());
+       m_children[1]->m_u = ON_Interval(m_u.Min(), m_u.Mid());
+       m_children[1]->m_v = ON_Interval(m_v.Mid(), m_v.Max());
+       m_children[1]->SetBBox(m_children[1]->m_surf->BoundingBox());
+
+       ret = temp_surf2->Split(1, m_v.Mid(), m_children[2]->m_surf, 
m_children[3]->m_surf);
+       delete temp_surf2;
+       if (!ret)
+           return -1;
+       m_children[2]->m_u = ON_Interval(m_u.Mid(), m_u.Max());
+       m_children[2]->m_v = ON_Interval(m_v.Min(), m_v.Mid());
+       m_children[2]->SetBBox(m_children[2]->m_surf->BoundingBox());
+       m_children[3]->m_u = ON_Interval(m_u.Mid(), m_u.Max());
+       m_children[3]->m_v = ON_Interval(m_v.Mid(), m_v.Max());
+       m_children[3]->SetBBox(m_children[3]->m_surf->BoundingBox());
+
+       return 0;
+    }
+    void GetBBox(ON_3dPoint &min, ON_3dPoint &max)
+    {
+       min = m_node.m_min;
+       max = m_node.m_max;
+    }
+    void SetBBox(const ON_BoundingBox &bbox)
+    {
+       m_node = bbox;
+       /* Make sure that each dimension of the bounding box is greater than
+        * ON_ZERO_TOLERANCE.
+        * It does the same work as building the surface tree when ray tracing
+        */
+       for (int i = 0; i < 3; i++) {
+           double d = m_node.m_max[i] - m_node.m_min[i];
+           if (ON_NearZero(d, ON_ZERO_TOLERANCE)) {
+               m_node.m_min[i] -= 0.001;
+               m_node.m_max[i] += 0.001;
+           }
+       }
+    }
+};
+
+
 /**
  * Point-point intersections (PPI)
  *
@@ -69,20 +231,100 @@
     return false;
 }
 
+
+#define MAX_PCI_DEPTH 8
 /**
  * Point-curve intersections (PCI)
  */
 bool
-ON_Intersect(const ON_3dPoint&,
-            const ON_Curve&,
-            ON_ClassArray<ON_PX_EVENT>&,
-            double,
-            const ON_Interval*)
+ON_Intersect(const ON_3dPoint& pointA,
+            const ON_Curve& curveB,
+            ON_ClassArray<ON_PX_EVENT>& x,
+            double tolerance,
+            const ON_Interval* curveB_domain)
 {
-    // Implement later.
+    bu_log("PCI called.\n");
+    Subcurve root;
+    if (curveB_domain == NULL) {
+       root.m_curve = curveB.Duplicate();
+       root.m_t = curveB.Domain();
+    }
+    else {
+       // Use ON_Curve::Split() to get the sub-curve inside curveB_domain
+       ON_Curve *temp_curve1 = NULL, *temp_curve2 = NULL, *temp_curve3 = NULL;
+       if (!curveB.Split(curveB_domain->Min(), temp_curve1, temp_curve2))
+           return false;
+       delete temp_curve1;
+       temp_curve1 = NULL;
+       if (!temp_curve2->Split(curveB_domain->Max(), temp_curve1, temp_curve3))
+           return false;
+       delete temp_curve1;
+       delete temp_curve2;
+       root.m_curve = temp_curve3;
+       root.m_t = *curveB_domain;
+    }
+
+    root.SetBBox(root.m_curve->BoundingBox());
+    root.m_islinear = root.m_curve->IsLinear();
+
+    if (!root.IsPointIn(pointA))
+       return false;
+
+    std::vector<Subcurve*> candidates, next_candidates;
+    candidates.push_back(&root);
+
+    // Find the sub-curves that are possibly intersected with the point.
+    for (int i = 0; i < MAX_PCI_DEPTH; i++) {
+       next_candidates.clear();
+       for (unsigned int j = 0; j < candidates.size(); j++) {
+           if (candidates[j]->m_islinear) {
+               next_candidates.push_back(candidates[j]);
+           } else {
+               if (candidates[j]->Split() == 0) {
+                   if (candidates[j]->m_children[0]->IsPointIn(pointA))
+                       next_candidates.push_back(candidates[j]->m_children[0]);
+                   if (candidates[j]->m_children[1]->IsPointIn(pointA))
+                       next_candidates.push_back(candidates[j]->m_children[1]);
+               } else
+                   next_candidates.push_back(candidates[j]);
+           }
+       }
+       candidates = next_candidates;
+    }
+
+    for (unsigned int i = 0; i < candidates.size(); i++) {
+       // Use linear approximation to get the 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;
+       if (t < 0)
+           closest_point_t = 0;
+       else if (t > 1)
+           closest_point_t = 1;
+       else
+           closest_point_t = t;
+       ON_3dPoint closest_point = line.PointAt(closest_point_t);
+       dis = pointA.DistanceTo(closest_point);
+       
+       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_Mid = (pointA + Event->m_B) * 0.5;
+           Event->m_radius = dis * 0.5;
+           x.Append(*Event);
+           return true;
+       }
+    }
+    // All candidates have no intersection
     return false;
 }
 
+
 /**
  * Point-surface intersections (PSI)
  */
@@ -296,97 +538,7 @@
 };
 
 
-struct Subsurface {
-private:
-    ON_BoundingBox m_node;
-public:
-    ON_Surface *m_surf;
-    ON_Interval m_u, m_v;
-    Subsurface *m_children[4];
-
-    Subsurface() : m_surf(NULL)
-    {
-       m_children[0] = m_children[1] = m_children[2] = m_children[3] = NULL;
-    }
-    Subsurface(const Subsurface &_ssurf)
-    {
-       m_surf = _ssurf.m_surf->Duplicate();
-       m_u = _ssurf.m_u;
-       m_v = _ssurf.m_v;
-       m_children[0] = m_children[1] = m_children[2] = m_children[3] = NULL;
-       SetBBox(_ssurf.m_node);
-    }
-    ~Subsurface()
-    {
-       for (int i = 0; i < 4; i++) {
-           if (m_children[i])
-               delete m_children[i];
-       }
-       delete m_surf;
-    }
-    int Split()
-    {
-       for (int i = 0; i < 4; i++)
-           m_children[i] = new Subsurface();
-       ON_Surface *temp_surf1 = NULL, *temp_surf2 = NULL;
-       ON_BOOL32 ret = true;
-       ret = m_surf->Split(0, m_u.Mid(), temp_surf1, temp_surf2);
-       if (!ret) {
-           delete temp_surf1;
-           delete temp_surf2;
-           return -1;
-       }
-
-       ret = temp_surf1->Split(1, m_v.Mid(), m_children[0]->m_surf, 
m_children[1]->m_surf);
-       delete temp_surf1;
-       if (!ret) {
-           delete temp_surf2;
-           return -1;
-       }
-       m_children[0]->m_u = ON_Interval(m_u.Min(), m_u.Mid());
-       m_children[0]->m_v = ON_Interval(m_v.Min(), m_v.Mid());
-       m_children[0]->SetBBox(m_children[0]->m_surf->BoundingBox());
-       m_children[1]->m_u = ON_Interval(m_u.Min(), m_u.Mid());
-       m_children[1]->m_v = ON_Interval(m_v.Mid(), m_v.Max());
-       m_children[1]->SetBBox(m_children[1]->m_surf->BoundingBox());
-
-       ret = temp_surf2->Split(1, m_v.Mid(), m_children[2]->m_surf, 
m_children[3]->m_surf);
-       delete temp_surf2;
-       if (!ret)
-           return -1;
-       m_children[2]->m_u = ON_Interval(m_u.Mid(), m_u.Max());
-       m_children[2]->m_v = ON_Interval(m_v.Min(), m_v.Mid());
-       m_children[2]->SetBBox(m_children[2]->m_surf->BoundingBox());
-       m_children[3]->m_u = ON_Interval(m_u.Mid(), m_u.Max());
-       m_children[3]->m_v = ON_Interval(m_v.Mid(), m_v.Max());
-       m_children[3]->SetBBox(m_children[3]->m_surf->BoundingBox());
-
-       return 0;
-    }
-    void GetBBox(ON_3dPoint &min, ON_3dPoint &max)
-    {
-       min = m_node.m_min;
-       max = m_node.m_max;
-    }
-    void SetBBox(const ON_BoundingBox &bbox)
-    {
-       m_node = bbox;
-       /* Make sure that each dimension of the bounding box is greater than
-        * ON_ZERO_TOLERANCE.
-        * It does the same work as building the surface tree when ray tracing
-        */
-       for (int i = 0; i < 3; i++) {
-           double d = m_node.m_max[i] - m_node.m_min[i];
-           if (ON_NearZero(d, ON_ZERO_TOLERANCE)) {
-               m_node.m_min[i] -= 0.001;
-               m_node.m_max[i] += 0.001;
-           }
-       }
-    }
-};
-
-
-#define INTERSECT_MAX_DEPTH 8
+#define MAX_SSI_DEPTH 8
 int
 ON_Intersect(const ON_Surface* surfA,
             const ON_Surface* surfB,
@@ -429,7 +581,7 @@
      * method of splitting a NURBS surface.
      * So finally only a small subset of the surface tree is created.
      */
-    for (int h = 0; h <= INTERSECT_MAX_DEPTH; h++) {
+    for (int h = 0; h <= MAX_SSI_DEPTH; h++) {
        if (nodepairs.empty())
            break;
        NodePairs tmp_pairs;
@@ -444,7 +596,7 @@
                if (ret1) {
                    if (ret2) { /* both splits failed */
                        tmp_pairs.push_back(*i);
-                       h = INTERSECT_MAX_DEPTH;
+                       h = MAX_SSI_DEPTH;
                    } else { /* the first failed */
                        for (int j = 0; j < 4; j++)
                            tmp_pairs.push_back(std::make_pair((*i).first, 
(*i).second->m_children[j]));
@@ -469,7 +621,7 @@
            (*i).first->GetBBox(box_a.m_min, box_a.m_max);
            (*i).second->GetBBox(box_b.m_min, box_b.m_max);
            if (box_intersect.Intersection(box_a, box_b)) {
-               if (h == INTERSECT_MAX_DEPTH) {
+               if (h == MAX_SSI_DEPTH) {
                    // We have arrived at the bottom of the trees.
                    // Get an estimate of the intersection point lying on the 
intersection curve
 

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