comparison libinterp/corefcn/graphics.cc @ 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 10cc5bf3dbb1
comparison
equal deleted inserted replaced
26930:ead8f91c5556 26931:ef922c0631e7
9452 EIG eig (cov, false, false, true); 9452 EIG eig (cov, false, false, true);
9453 ColumnVector ev = real (eig.eigenvalues ()); 9453 ColumnVector ev = real (eig.eigenvalues ());
9454 return ev.min () <= tol * ev.max (); 9454 return ev.min () <= tol * ev.max ();
9455 } 9455 }
9456 9456
9457 std::list<octave_idx_type>
9458 coplanar_partition (const Matrix &vert, const Matrix &idx,
9459 octave_idx_type nc, octave_idx_type jj)
9460 {
9461 std::list<octave_idx_type> coplanar_ends;
9462
9463 Matrix plane_pivot = Matrix (1, 3, 0.0);
9464 for (octave_idx_type i = 0; i < 3; i++)
9465 plane_pivot(0,i) = vert(idx(0,jj)-1,i);
9466
9467 Matrix fc = Matrix (0, 3, 0.0); // face corner vertex coordinates
9468 Matrix fa = Matrix (1, 3, 0.0); // for append face corner
9469 Matrix coor_cov = Matrix (3, 3, 0.0);
9470
9471 if (nc >= 5)
9472 {
9473 // Coplanar test that involves all points.
9474 // For nc == 4, this initial test is not beneficial at all.
9475 // If the probability of coplanar input is more than half, for
9476 // the best average performance, we should use nc >= 5.
9477 // Higher threshold is meaningful only when input is known to be
9478 // non-coplanar and nc is small.
9479
9480 fc.resize (nc - 1, 3);
9481 for (octave_idx_type j = 1; j < nc; j++)
9482 for (octave_idx_type i = 0; i < 3; i++)
9483 fc(j-1,i) = vert(idx(j,jj)-1,i) - plane_pivot(i);
9484
9485 coor_cov = fc.transpose () * fc;
9486 if (is_coplanar (coor_cov))
9487 {
9488 coplanar_ends.push_back (nc - 1);
9489 return coplanar_ends;
9490 }
9491 }
9492
9493 fc.resize (3, 3);
9494 octave_idx_type i_start = 1;
9495 octave_idx_type i_end = 2;
9496
9497 // Split the polygon into coplanar segments.
9498 // The first point is common corner of all planes.
9499 while (i_start < nc - 1)
9500 {
9501 i_end = i_start + 2;
9502 if (i_end > nc - 1)
9503 {
9504 coplanar_ends.push_back (nc - 1);
9505 break;
9506 }
9507
9508 // Algorithm: Start from 3 points, keep adding points until the point set
9509 // is no more in a plane. Record the coplanar point set, then advance
9510 // i_start.
9511
9512 // Prepare 1+3 points for coplanar test.
9513 // The first point is implicitly included.
9514 for (octave_idx_type j = 0; j < 3; j++)
9515 for (octave_idx_type i = 0; i < 3; i++)
9516 fc(j,i) = vert(idx(j+i_start,jj)-1,i) - plane_pivot(i);
9517
9518 // covariance matrix between coordinates of vertices
9519 coor_cov = fc.transpose () * fc;
9520
9521 while (true)
9522 {
9523 // coplanar test
9524 if (! is_coplanar (coor_cov))
9525 break;
9526
9527 i_end++;
9528 if (i_end > nc - 1)
9529 break;
9530
9531 // add a point to plane
9532 for (octave_idx_type i = 0; i < 3; i++)
9533 fa(0,i) = vert(idx(i_end,jj)-1,i) - plane_pivot(i);
9534 coor_cov += fa.transpose () * fa;
9535 }
9536
9537 i_start = i_end - 1;
9538 coplanar_ends.push_back (i_start);
9539 }
9540 return coplanar_ends;
9541 }
9542
9457 void 9543 void
9458 patch::properties::update_data (void) 9544 patch::properties::update_data (void)
9459 { 9545 {
9460 if (updating_patch_data) 9546 if (updating_patch_data)
9461 return; 9547 return;
9508 // find first element that is NaN to get number of corners 9594 // find first element that is NaN to get number of corners
9509 octave_idx_type nc = 3; 9595 octave_idx_type nc = 3;
9510 while (nc < fcmax && ! octave::math::isnan (idx(nc,jj))) 9596 while (nc < fcmax && ! octave::math::isnan (idx(nc,jj)))
9511 nc++; 9597 nc++;
9512 9598
9513 std::list<octave_idx_type> coplanar_ends; 9599 // If any of the corners is NaN or Inf, skip coplanar test.
9514 9600 // FIXME: Add support for non-coplanar faces with unclosed contour.
9515 Matrix plane_pivot = Matrix (1, 3, 0.0); 9601 bool is_unclosed = false;
9516 for (octave_idx_type i = 0; i < 3; i++) 9602 for (octave_idx_type j = 0; j < nc; j++)
9517 plane_pivot(0,i) = vert(idx(0,jj)-1,i);
9518
9519 Matrix fc = Matrix (0, 3, 0.0); // face corner vertex coordinates
9520 Matrix fa = Matrix (1, 3, 0.0); // for append face corner
9521 Matrix coor_cov = Matrix (3, 3, 0.0);
9522
9523 if (nc >= 5)
9524 { 9603 {
9525 // Coplanar test that involves all points. 9604 const octave_idx_type k = idx(j, jj) - 1;
9526 // For nc == 4, this initial test is not beneficial at all. 9605 if (! (octave::math::isfinite (vert(k, 0))
9527 // If the probability of coplanar input is more than half, for 9606 && octave::math::isfinite (vert(k, 1))
9528 // the best average performance, we should use nc >= 5. 9607 && octave::math::isfinite (vert(k, 2))))
9529 // Higher threshold is meaningful only when input is known to be
9530 // non-coplanar and nc is small.
9531
9532 fc.resize (nc - 1, 3);
9533 for (octave_idx_type j = 1; j < nc; j++)
9534 for (octave_idx_type i = 0; i < 3; i++)
9535 fc(j-1,i) = vert(idx(j,jj)-1,i) - plane_pivot(i);
9536
9537 coor_cov = fc.transpose () * fc;
9538 if (is_coplanar (coor_cov))
9539 { 9608 {
9540 coplanar_ends.push_back (nc - 1); 9609 is_unclosed = true;
9541 coplanar_last_idx.push_back (coplanar_ends); 9610 break;
9542 continue;
9543 } 9611 }
9544 } 9612 }
9545 9613 if (is_unclosed)
9546 fc.resize (3, 3); 9614 continue;
9547 octave_idx_type i_start = 1; 9615
9548 octave_idx_type i_end = 2; 9616 coplanar_last_idx.push_back (coplanar_partition (vert, idx, nc, jj));
9549
9550 // Split the polygon into coplanar segments.
9551 // The first point is common corner of all planes.
9552 while (i_start < nc - 1)
9553 {
9554 i_end = i_start + 2;
9555 if (i_end > nc - 1)
9556 {
9557 coplanar_ends.push_back (nc - 1);
9558 break;
9559 }
9560
9561 // Algorithm: Start from 3 points, keep adding points until the
9562 // point set is no more in a plane. Record the coplanar point
9563 // set, then advance i_start.
9564
9565 // Prepare 1+3 points for coplanar test.
9566 // The first point is implicitly included.
9567 for (octave_idx_type j = 0; j < 3; j++)
9568 for (octave_idx_type i = 0; i < 3; i++)
9569 fc(j,i) = vert(idx(j+i_start,jj)-1,i) - plane_pivot(i);
9570
9571 // covariance matrix between coordinates of vertex
9572 coor_cov = fc.transpose () * fc;
9573
9574 while (true)
9575 {
9576 // coplanar test
9577 if (! is_coplanar (coor_cov))
9578 break;
9579
9580 i_end++;
9581 if (i_end > nc - 1)
9582 break;
9583
9584 // add a point to plane
9585 for (octave_idx_type i = 0; i < 3; i++)
9586 fa(0,i) = vert(idx(i_end,jj)-1,i) - plane_pivot(i);
9587 coor_cov += fa.transpose () * fa;
9588 }
9589
9590 i_start = i_end - 1;
9591 coplanar_ends.push_back (i_start);
9592 }
9593 coplanar_last_idx.push_back (coplanar_ends);
9594 } 9617 }
9595 } 9618 }
9596 9619
9597 // Build cdata 9620 // Build cdata
9598 dim_vector dv = dim_vector::alloc (3); 9621 dim_vector dv = dim_vector::alloc (3);