Revision: 74249
          http://sourceforge.net/p/brlcad/code/74249
Author:   starseeker
Date:     2019-10-26 19:42:49 +0000 (Sat, 26 Oct 2019)
Log Message:
-----------
Use the ON_FindLocalMinimum function from openNURBS to more properly implement 
the NURBS curve get closest point function.

Modified Paths:
--------------
    brlcad/trunk/src/libbrep/cdt_ovlps.cpp
    brlcad/trunk/src/libbrep/opennurbs_ext.cpp

Modified: brlcad/trunk/src/libbrep/cdt_ovlps.cpp
===================================================================
--- brlcad/trunk/src/libbrep/cdt_ovlps.cpp      2019-10-25 22:07:41 UTC (rev 
74248)
+++ brlcad/trunk/src/libbrep/cdt_ovlps.cpp      2019-10-26 19:42:49 UTC (rev 
74249)
@@ -1538,7 +1538,7 @@
        std::set<cdt_mesh::bedge_seg_t *> segs;
        segs.insert(ev_it->first);
 #if 0
-       ON_3dPoint problem(3.44525,7.67444,22.9198);
+       ON_3dPoint problem(3.06294,7.5,24.2775);
        std::set<overt_t *>::iterator v_it;
        for (v_it = verts.begin(); v_it != verts.end(); v_it++) {
            overt_t *v = *v_it;
@@ -1772,6 +1772,14 @@
                // If this point is also close to a brep face edge, list that 
edge/vert
                // combination for splitting
                ON_3dPoint vp = v->vpnt();
+
+#if 1
+               ON_3dPoint problem(3.06294,7.5,24.2775);
+               if (problem.DistanceTo(vp) < 0.01) {
+                   std::cout << "problem\n";
+               }
+#endif
+
                cdt_mesh::uedge_t closest_edge = 
omesh1->fmesh->closest_uedge(t1, vp);
                if (omesh1->fmesh->brep_edges.find(closest_edge) != 
omesh1->fmesh->brep_edges.end()) {
                    cdt_mesh::bedge_seg_t *bseg = 
omesh1->fmesh->ue2b_map[closest_edge];
@@ -1976,26 +1984,31 @@
            double dist = ov->bb.Diagonal().Length() * 10;
            closest_surf_pnt(spnt, sn, *omesh->fmesh, &ovpnt, 2*dist);
 
-           // TODO - check this point against the mesh vert tree - if we're
+           // Check this point against the mesh vert tree - if we're
            // extremely close to an existing vertex, we don't want to split
            // and create extremely tiny triangles - vertex adjustment should
            // handle super-close points...
            ON_BoundingBox pbb(spnt, spnt);
            std::set<overt_t *> cverts = omesh->vert_search(pbb);
-           std::cout << "Found " << cverts.size() << " close verts\n";
-           // Maybe try something like this - if we're close to a vertex, find
-           // the vertices from the other mesh that overlap with that vertex.
-           // If there are none (can that happen?) adjust the vertex.  If
-           // there are, if the surface point is closer than the closest vert
-           // from the other mesh, adjust, otherwise skip.
+
+           // If we're close to a vertex, find the vertices from the other
+           // mesh that overlap with that vertex.  If there are, and if the
+           // surface point is close to them per the vert bbox dimension,
+           // skip that point as a refinement point in this step.
            if (cverts.size()) {
                double spdist = ovpnt.DistanceTo(spnt);
+               
                if (spdist < ON_ZERO_TOLERANCE) {
+                   // If we're on the vertex point, we don't need to check
+                   // further - we're not splitting there.
                    omesh->refine_pnt_remove(ov);
                    continue;
                }
+
+               // Find the closest vertex, and use its bounding box size as a
+               // gauge for how close is too close for the surface point
                double vdist = DBL_MAX;
-               double bbdiag;
+               double bbdiag = DBL_MAX;
                std::set<overt_t *>::iterator v_it;
                for (v_it = cverts.begin(); v_it != cverts.end(); v_it++) {
                    ON_3dPoint cvpnt = (*v_it)->vpnt();
@@ -2010,11 +2023,9 @@
                    omesh->refine_pnt_remove(ov);
                    continue;
                }
-               std::cout << "spdist: " << spdist << "\n";
-               std::cout << "bbdiag: " << bbdiag << "\n";
            }
 
-           // Find the closest edges
+           // If we passed the above filter, find the closest edges
            std::set<cdt_mesh::uedge_t> close_edges = 
omesh->interior_uedges_search(ov->bb);
 
            double mindist = DBL_MAX; 

Modified: brlcad/trunk/src/libbrep/opennurbs_ext.cpp
===================================================================
--- brlcad/trunk/src/libbrep/opennurbs_ext.cpp  2019-10-25 22:07:41 UTC (rev 
74248)
+++ brlcad/trunk/src/libbrep/opennurbs_ext.cpp  2019-10-26 19:42:49 UTC (rev 
74249)
@@ -176,10 +176,37 @@
     return 0;
 }
 
-/* Implement the algorithm from https://github.com/pboyer/verb - specifically:
+
+/* Implement the closest point on curve algorithm from
+ * https://github.com/pboyer/verb - specifically:
+ *
  * verb/src/verb/eval/Tess.hx 
  * verb/src/verb/eval/Analyze.hx 
  */
+
+struct curve_search_args {
+    const ON_NurbsCurve *nc;
+    ON_3dPoint tp;
+};
+
+int
+curve_closest_search_func(void *farg, double t, double *ft, double *dft)
+{
+    struct curve_search_args *cargs = (struct curve_search_args *)farg;
+    const ON_NurbsCurve *nc = cargs->nc;
+    ON_3dPoint tp = cargs->tp;
+    ON_3dPoint crv_pnt;
+    ON_3dVector crv_d1;
+    ON_3dVector crv_d2;
+    if (!nc->Ev2Der(t, crv_pnt, crv_d1, crv_d2)) return -1;
+    ON_3dVector fparam2 = crv_pnt - tp;
+    *ft = ON_DotProduct(crv_d1, fparam2);
+    *dft = ON_DotProduct(crv_d2, fparam2) + ON_DotProduct(crv_d1, crv_d1);
+
+    if (*ft < ON_ZERO_TOLERANCE) return 1;
+    return 0;
+}
+
 bool
 ON_NurbsCurve_GetClosestPoint(
        double *t,
@@ -201,10 +228,9 @@
        pnts.push_back(nc->PointAt(st));
     }
 
-    // Find an initial guess based on the breakdown into segments
+    // Find an initial domain subset based on the breakdown into segments
     double d1 = domain.Min();
     double d2 = domain.Max();
-    double u = 0.0;
     double vmin = DBL_MAX;
     for (size_t i = 0; i < pnts.size() - 1; i++) {
        ON_Line l(pnts[i], pnts[i+1]);
@@ -211,37 +237,58 @@
        double lt;
        l.ClosestPointTo(p, &lt);
        ON_3dPoint pl = l.PointAt(lt);
+       if ((lt < 0 || NEAR_ZERO(lt, ON_ZERO_TOLERANCE))) {
+           pl = l.PointAt(0);
+       }
+       if ((lt > 1 || NEAR_EQUAL(lt, 1, ON_ZERO_TOLERANCE))) {
+           pl = l.PointAt(1);
+       }
        if (pl.DistanceTo(p) < vmin) {
            vmin = pl.DistanceTo(p);
            d1 = domain.ParameterAt(i*span);
            d2 = domain.ParameterAt((i+1)*span);
-           //u = d1 + (d2 - d1)*lt;
        }
     }
 
-    // TODO - verb uses Newton iteration, and so should we - for the moment,
-    // this is a quick and dirty (and undoubtedly slower) binary search
+    // Iterate to find the closest point
     double vdist = DBL_MAX;
-    double vmin_delta = DBL_MAX;
-    double vmin_prev = vmin;
-    ON_3dPoint p1 = nc->PointAt(d1);
-    ON_3dPoint p2 = nc->PointAt(d2);
-    while (vmin_delta > ON_ZERO_TOLERANCE) {
-       u = (d1 + d2) * 0.5;
-       if (p1.DistanceTo(p) < p2.DistanceTo(p)) {
-           d2 = u;
-           p2 = nc->PointAt(u);
-       } else {
-           d1 = u;
-           p1 = nc->PointAt(u);
+    double u = (d1 + d2) * 0.5;
+    struct curve_search_args cargs;
+    cargs.nc = nc;
+    cargs.tp = p;
+    double st;
+    int osearch = ON_FindLocalMinimum(curve_closest_search_func, &cargs, d1, 
u, d2, ON_EPSILON, 0.5*ON_ZERO_TOLERANCE, 100, &st);
+
+    if (osearch == 1) {
+
+       (*t) = st;
+       vdist = (p.DistanceTo(nc->PointAt(st)));
+
+    } else {
+
+       // ON_FindLocalMinimum failed, fall back on binary search
+       double vmin_delta = DBL_MAX;
+       double vmin_prev = vmin;
+       ON_3dPoint p1 = nc->PointAt(d1);
+       ON_3dPoint p2 = nc->PointAt(d2);
+       while (vmin_delta > ON_ZERO_TOLERANCE) {
+           u = (d1 + d2) * 0.5;
+           if (p1.DistanceTo(p) < p2.DistanceTo(p)) {
+               d2 = u;
+               p2 = nc->PointAt(u);
+           } else {
+               d1 = u;
+               p1 = nc->PointAt(u);
+           }
+           vdist = (p.DistanceTo(nc->PointAt(u)));
+           vmin_delta = fabs(vmin_prev - vmin);
+           vmin_prev = vmin;
        }
-       vdist = (p.DistanceTo(nc->PointAt(u)));
-       vmin_delta = fabs(vmin_prev - vmin);
-       vmin_prev = vmin;
+
+       (*t) = u;
+
     }
 
-    (*t) = u;
-
     if (maximum_distance > 0 && vdist > maximum_distance) return false;
 
     return true;

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



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to