Mercurial > octave
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); |