changeset 26931:ef922c0631e7

Skip coplanar test for faces with NaN vertex (bug #55895). * graphics.cc (patch::properties::update_data, coplanar_partition): Skip the coplanar test when any of the face corners is NaN or Inf. Move the coplanar test into new function "coplanar_partition".
author Eddy Xiao <bewantbe@gmail.com>
date Sun, 17 Mar 2019 19:13:30 +0800
parents ead8f91c5556
children b6ac4615214f
files libinterp/corefcn/graphics.cc
diffstat 1 files changed, 101 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/graphics.cc	Sat Mar 16 22:21:26 2019 +0100
+++ b/libinterp/corefcn/graphics.cc	Sun Mar 17 19:13:30 2019 +0800
@@ -9454,6 +9454,92 @@
   return ev.min () <= tol * ev.max ();
 }
 
+std::list<octave_idx_type>
+coplanar_partition (const Matrix &vert, const Matrix &idx,
+                    octave_idx_type nc, octave_idx_type jj)
+{
+  std::list<octave_idx_type> coplanar_ends;
+  
+  Matrix plane_pivot = Matrix (1, 3, 0.0);
+  for (octave_idx_type i = 0; i < 3; i++)
+    plane_pivot(0,i) = vert(idx(0,jj)-1,i);
+
+  Matrix fc = Matrix (0, 3, 0.0);  // face corner vertex coordinates
+  Matrix fa = Matrix (1, 3, 0.0);  // for append face corner
+  Matrix coor_cov = Matrix (3, 3, 0.0);
+
+  if (nc >= 5)
+    {
+      // Coplanar test that involves all points.
+      // For nc == 4, this initial test is not beneficial at all.
+      // If the probability of coplanar input is more than half, for
+      // the best average performance, we should use nc >= 5.
+      // Higher threshold is meaningful only when input is known to be
+      // non-coplanar and nc is small.
+
+      fc.resize (nc - 1, 3);
+      for (octave_idx_type j = 1; j < nc; j++)
+        for (octave_idx_type i = 0; i < 3; i++)
+          fc(j-1,i) = vert(idx(j,jj)-1,i) - plane_pivot(i);
+
+      coor_cov = fc.transpose () * fc;
+      if (is_coplanar (coor_cov))
+        {
+          coplanar_ends.push_back (nc - 1);
+          return coplanar_ends;
+        }
+    }
+
+  fc.resize (3, 3);
+  octave_idx_type i_start = 1;
+  octave_idx_type i_end = 2;
+
+  // Split the polygon into coplanar segments.
+  // The first point is common corner of all planes.
+  while (i_start < nc - 1)
+    {
+      i_end = i_start + 2;
+      if (i_end > nc - 1)
+        {
+          coplanar_ends.push_back (nc - 1);
+          break;
+        }
+
+      // Algorithm: Start from 3 points, keep adding points until the point set
+      // is no more in a plane. Record the coplanar point set, then advance
+      // i_start.
+
+      // Prepare 1+3 points for coplanar test.
+      // The first point is implicitly included.
+      for (octave_idx_type j = 0; j < 3; j++)
+        for (octave_idx_type i = 0; i < 3; i++)
+          fc(j,i) = vert(idx(j+i_start,jj)-1,i) - plane_pivot(i);
+
+      // covariance matrix between coordinates of vertices
+      coor_cov = fc.transpose () * fc;
+
+      while (true)
+        {
+          // coplanar test
+          if (! is_coplanar (coor_cov))
+            break;
+
+          i_end++;
+          if (i_end > nc - 1)
+            break;
+
+          // add a point to plane
+          for (octave_idx_type i = 0; i < 3; i++)
+            fa(0,i) = vert(idx(i_end,jj)-1,i) - plane_pivot(i);
+          coor_cov += fa.transpose () * fa;
+        }
+
+      i_start = i_end - 1;
+      coplanar_ends.push_back (i_start);
+    }
+  return coplanar_ends;
+}
+
 void
 patch::properties::update_data (void)
 {
@@ -9510,87 +9596,24 @@
           while (nc < fcmax && ! octave::math::isnan (idx(nc,jj)))
             nc++;
 
-          std::list<octave_idx_type> coplanar_ends;
-
-          Matrix plane_pivot = Matrix (1, 3, 0.0);
-          for (octave_idx_type i = 0; i < 3; i++)
-            plane_pivot(0,i) = vert(idx(0,jj)-1,i);
-
-          Matrix fc = Matrix (0, 3, 0.0);  // face corner vertex coordinates
-          Matrix fa = Matrix (1, 3, 0.0);  // for append face corner
-          Matrix coor_cov = Matrix (3, 3, 0.0);
-
-          if (nc >= 5)
-            {
-              // Coplanar test that involves all points.
-              // For nc == 4, this initial test is not beneficial at all.
-              // If the probability of coplanar input is more than half, for
-              // the best average performance, we should use nc >= 5.
-              // Higher threshold is meaningful only when input is known to be
-              // non-coplanar and nc is small.
-
-              fc.resize (nc - 1, 3);
-              for (octave_idx_type j = 1; j < nc; j++)
-                for (octave_idx_type i = 0; i < 3; i++)
-                  fc(j-1,i) = vert(idx(j,jj)-1,i) - plane_pivot(i);
-
-              coor_cov = fc.transpose () * fc;
-              if (is_coplanar (coor_cov))
+          // If any of the corners is NaN or Inf, skip coplanar test.
+          // FIXME: Add support for non-coplanar faces with unclosed contour.
+          bool is_unclosed = false;
+          for (octave_idx_type j = 0; j < nc; j++)
+            {
+              const octave_idx_type k = idx(j, jj) - 1;
+              if (! (octave::math::isfinite (vert(k, 0))
+                  && octave::math::isfinite (vert(k, 1))
+                  && octave::math::isfinite (vert(k, 2))))
                 {
-                  coplanar_ends.push_back (nc - 1);
-                  coplanar_last_idx.push_back (coplanar_ends);
-                  continue;
-                }
-            }
-
-          fc.resize (3, 3);
-          octave_idx_type i_start = 1;
-          octave_idx_type i_end = 2;
-
-          // Split the polygon into coplanar segments.
-          // The first point is common corner of all planes.
-          while (i_start < nc - 1)
-            {
-              i_end = i_start + 2;
-              if (i_end > nc - 1)
-                {
-                  coplanar_ends.push_back (nc - 1);
+                  is_unclosed = true;
                   break;
                 }
-
-              // Algorithm: Start from 3 points, keep adding points until the
-              // point set is no more in a plane. Record the coplanar point
-              // set, then advance i_start.
-
-              // Prepare 1+3 points for coplanar test.
-              // The first point is implicitly included.
-              for (octave_idx_type j = 0; j < 3; j++)
-                for (octave_idx_type i = 0; i < 3; i++)
-                  fc(j,i) = vert(idx(j+i_start,jj)-1,i) - plane_pivot(i);
-
-              // covariance matrix between coordinates of vertex
-              coor_cov = fc.transpose () * fc;
-
-              while (true)
-                {
-                  // coplanar test
-                  if (! is_coplanar (coor_cov))
-                    break;
-
-                  i_end++;
-                  if (i_end > nc - 1)
-                    break;
-
-                  // add a point to plane
-                  for (octave_idx_type i = 0; i < 3; i++)
-                    fa(0,i) = vert(idx(i_end,jj)-1,i) - plane_pivot(i);
-                  coor_cov += fa.transpose () * fa;
-                }
-
-              i_start = i_end - 1;
-              coplanar_ends.push_back (i_start);
-            }
-          coplanar_last_idx.push_back (coplanar_ends);
+            }
+          if (is_unclosed)
+            continue;
+
+          coplanar_last_idx.push_back (coplanar_partition (vert, idx, nc, jj));
         }
     }