36#ifndef MJR_INCLUDE_MR_cell_cplx
50#include <unordered_map>
200 template <
bool chk_point_unique,
201 bool chk_cell_unique,
202 bool chk_cell_vertexes,
203 bool chk_cell_dimension,
209 requires ((std::is_floating_point<flt_type>::value) &&
210 (eps > std::numeric_limits<flt_type>::epsilon()))
335 bool operator()(
const fvec3_t& a,
const fvec3_t& b)
const {
return (((std::abs(a[0]-b[0]) > eps) ||
336 (std::abs(a[1]-b[1]) > eps) ||
337 (std::abs(a[2]-b[2]) > eps)) &&
341 ((a[1] == b[1]) && (a[2] < b[2])))))); }
442 if constexpr (chk_point_unique) {
474 for(
int i=0; i<3; ++i)
475 if (data_idx_lst[i].index() == 0)
476 v[i] = node_data[std::get<int>(data_idx_lst.at(i))];
478 v[i] = std::get<uft_t>(data_idx_lst.at(i));
487 for(
decltype(data_idx_lst.size()) i=0; i<data_idx_lst.size(); ++i)
488 if (data_idx_lst[i].index() == 0)
489 v.push_back(node_data[std::get<int>(data_idx_lst.at(i))]);
491 v.push_back(std::get<uft_t>(data_idx_lst.at(i)));
499 if (data_idx.index() == 0)
500 return (node_data[std::get<int>(data_idx)]);
502 return (std::get<int>(data_idx));
508 std::ostringstream convert;
512 convert << std::setprecision(5) <<
static_cast<uft_t>(c) <<
" ";
515 convert <<
"[ DNE ]";
517 return(convert.str());
551 for(
int i=0; i<static_cast<int>(scalar_name_strings.size()); ++i)
560 for(
int i=0; i<static_cast<int>(scalar_name_strings.size()); ++i)
589 for(
int i=0; i<3; ++i)
590 tmp += pnt[i]*pnt[i];
597 for(
int i=0; i<3; ++i)
598 tmp += pnt1[i]*pnt2[i];
605 tmp[0] = pnt1[1]*pnt2[2]-pnt1[2]*pnt2[1];
606 tmp[1] = pnt1[2]*pnt2[0]-pnt1[0]*pnt2[2];
607 tmp[2] = pnt1[0]*pnt2[1]-pnt1[1]*pnt2[0];
614 for(
int i=0; i<3; ++i)
615 tmp[i] = pnt1[i] - pnt2[i];
627 if (std::abs(length) > eps) {
628 for(
int i=0; i<3; ++i)
629 pnt[i] = pnt[i]/length;
639 for(
int i=0; i<3; ++i)
640 tmp[i] = scl1 * pnt1[i] + scl2 * pnt2[i];
647 static_assert(
false,
"vec3_det3: Under active development. Untested!");
648 return (pnt1[0] * pnt2[1] * pnt3[2] -
649 pnt1[0] * pnt2[2] * pnt3[1] -
650 pnt1[1] * pnt2[0] * pnt3[2] +
651 pnt1[1] * pnt2[2] * pnt3[0] +
652 pnt1[2] * pnt2[0] * pnt3[1] -
653 pnt1[2] * pnt2[1] * pnt3[0]);
684 return std::string(
"");
692 if (ilin1pnt1 == ilin1pnt2)
694 if (ilin2pnt1 == ilin2pnt2)
697 std::set<node_idx_t> points_sorted;
698 points_sorted.insert(ilin1pnt1);
699 points_sorted.insert(ilin1pnt2);
700 points_sorted.insert(ilin2pnt1);
701 points_sorted.insert(ilin2pnt2);
702 if (points_sorted.size() == 4) {
720 }
else if (points_sorted.size() == 3) {
722 if (ilin1pnt1 == ilin2pnt1) {
723 ipntc = ilin1pnt1; ipnt1 = ilin1pnt2; ipnt2 = ilin2pnt2;
724 }
else if (ilin1pnt1 == ilin2pnt2) {
725 ipntc = ilin1pnt1; ipnt1 = ilin1pnt2; ipnt2 = ilin2pnt1;
726 }
else if (ilin1pnt2 == ilin2pnt1) {
727 ipntc = ilin1pnt2; ipnt1 = ilin1pnt1; ipnt2 = ilin2pnt2;
728 }
else if (ilin1pnt2 == ilin2pnt2) {
729 ipntc = ilin1pnt2; ipnt1 = ilin1pnt1; ipnt2 = ilin2pnt1;
731 ipntc = 0; ipnt1 = 0; ipnt2 = 0;
743 }
else if (points_sorted.size() == 2) {
759 lin1pnt1[0] * lin2pnt1[1] - lin1pnt1[0] * lin2pnt2[1] - lin1pnt1[1] * lin2pnt1[0] + lin1pnt1[1] * lin2pnt2[0] -
760 lin1pnt2[0] * lin2pnt1[1] + lin1pnt2[0] * lin2pnt2[1] + lin1pnt2[1] * lin2pnt1[0] - lin1pnt2[1] * lin2pnt2[0];
761 if (std::abs(denom) < eps)
764 lin1pnt1[0]*lin2pnt1[1] - lin1pnt1[0]*lin2pnt2[1] -
765 lin1pnt1[1]*lin2pnt1[0] + lin1pnt1[1]*lin2pnt2[0] +
766 lin2pnt1[0]*lin2pnt2[1] - lin2pnt1[1]*lin2pnt2[0];
768 -(lin1pnt1[0]*lin1pnt2[1] - lin1pnt1[0]*lin2pnt1[1] -
769 lin1pnt1[1]*lin1pnt2[0] + lin1pnt1[1]*lin2pnt1[0] +
770 lin1pnt2[0]*lin2pnt1[1] - lin1pnt2[1]*lin2pnt1[0]);
771 uft_t ua = numera/denom;
772 uft_t ub = numerb/denom;
773 if ( (ua < 0) || (ub < 0) || (ua > 1) || (ub > 1) )
775 uft_t eq3 = numera/denom * (lin1pnt2[2] - lin1pnt1[2]) - numerb/denom * (lin2pnt2[2] - lin2pnt1[2]) + lin2pnt1[2] + lin1pnt1[2];
776 if (std::abs(eq3) < eps)
796 for(
int i=0; i<3; i++) {
797 d[i] = (linpnt2[i] - linpnt1[i]) / segd;
798 t += (pnt[i] - linpnt1[i])*d[i];
800 for(
int i=0; i<3; i++) {
801 p[i] = linpnt1[i] + t * d[i];
808 if (std::abs((dp1+dp2)-segd) > eps)
845 uft_t denom = basisv1[0] * basisv2[1] - basisv2[0] * basisv1[1];
846 uft_t u = (q[0] * basisv2[1] - basisv2[0] * q[1]) / denom;
847 uft_t v = (basisv1[0] * q[1] - q[0] * basisv1[1]) / denom;
848 uft_t dd = std::abs(u*basisv1[2] + v*basisv2[2] - q[2]);
849 if ( (u>=0) && (v>=0) && ((u+v)<=1) && (dd<eps) ) {
850 return std::abs(lambda);
855 return std::min(std::min(d1, d2), d3);
862 return ((std::abs(p1[0]) < eps) &&
863 (std::abs(p1[1]) < eps) &&
864 (std::abs(p1[2]) < eps));
885 if (pnt_list.size() > 3) {
888 for(
decltype(pnt_list.size()) i=4; i<pnt_list.size(); i++)
909 static_assert(
false,
"geomr_seg_tri_intersection: Not yet implemented!");
910 return (tp1[0]+tp2[0]+tp3[0]+sp1[0]+sp2[0]>1.0);
940 return static_cast<int>(
cell_lst.size());
947 if ( (dimension < 0) || (dimension > logical_dim) )
948 dimension = logical_dim;
949 if (logical_dim > 3) {
950 std::cerr <<
"MR_cell_cplx API USAGE ERROR: Maximum supported dimension is 3" << std::endl;
962 static std::vector<std::vector<cell_structure_t>> cst = {{{{0}},
973 {{0,1},{1,2},{2,3},{3,0}},
974 {{0,1},{1,2},{2,3},{3,0},
975 {0,4},{1,4},{2,4},{3,4}},
976 {{0,1},{1,2},{2,3},{3,0},
977 {4,5},{5,6},{6,7},{7,4},
978 {0,4},{1,5},{2,6},{3,7}}},
999 {{0,1,2,3,4,5,6,7}}}};
1000 return (cst[dimension][idx]);
1096 return std::string(
"ERROR");
1105 std::vector<int>::size_type num_verts = cell_verts.size();
1107 if (num_verts < req_num_pts)
1109 if (num_verts > req_num_pts)
1112 if (std::any_of(cell_verts.cbegin(), cell_verts.cend(), [](
node_idx_t i) { return (i < 0); }))
1115 if (std::any_of(cell_verts.cbegin(), cell_verts.cend(), [
this](
node_idx_t i) { return (i >= node_count()); }))
1118 if (num_verts > 1) {
1119 std::set<node_idx_t> cell_verts_sorted;
1121 if (cell_verts_sorted.contains(pnt_idx))
1123 cell_verts_sorted.insert(pnt_idx);
1170 if ( !(segs.empty())) {
1171 for(
decltype(segs.size()) i=0; i<segs.size()-1; i++) {
1172 for(
decltype(segs.size()) j=i+1; j<segs.size(); j++) {
1173 std::set<node_idx_t> points_sorted;
1174 points_sorted.insert(segs[i][0]);
1175 points_sorted.insert(segs[i][1]);
1176 points_sorted.insert(segs[j][0]);
1177 points_sorted.insert(segs[j][1]);
1178 auto it =
geomi_seg_isect_type(cell_verts[segs[i][0]], cell_verts[segs[i][1]], cell_verts[segs[j][0]], cell_verts[segs[j][1]]);
1179 if(points_sorted.size() == 4) {
1182 }
else if(points_sorted.size() == 3) {
1223 for(
auto face_structure: face_structures) {
1225 for(
auto idx: face_structure)
1226 face.push_back(cell_verts[idx]);
1248 if (
add_cell(new_cell_kind, new_cell_verts))
1252 for(
auto cell_part: cell_parts) {
1254 for(
auto idx: cell_part)
1255 newer_cell_verts.push_back(new_cell_verts[idx]);
1271 if constexpr (chk_cell_vertexes) {
1277 if constexpr (chk_cell_dimension) {
1283 if constexpr (chk_cell_edges) {
1289 if constexpr (chk_cell_unique) {
1291 std::sort(new_cell_sorted_verts.begin(), new_cell_sorted_verts.end());
1296 cell_lst.push_back(new_cell_verts);
1300 cell_lst.push_back(new_cell_verts);
1336 std::cout <<
"ERROR(write_xml_vtk): No points!" << std::endl;
1340 std::cout <<
"ERROR(write_xml_vtk): No cells!" << std::endl;
1344 std::ofstream out_stream;
1345 out_stream.open(file_name, std::ios::out | std::ios::binary | std::ios::trunc);
1346 if (out_stream.is_open()) {
1347 out_stream.imbue(std::locale::classic());
1349 std::cout <<
"ERROR(write_xml_vtk): Could not open file!" << std::endl;
1352 out_stream <<
"<VTKFile type='UnstructuredGrid' version='0.1' byte_order='LittleEndian'>" << std::endl;
1353 out_stream <<
"<!-- " << description <<
" -->" << std::endl;
1354 out_stream <<
" <UnstructuredGrid>" << std::endl;
1355 out_stream <<
" <Piece NumberOfPoints='" <<
node_count() <<
"' NumberOfCells='" <<
num_cells() <<
"'>" << std::endl;
1357 std::string scalars_attr_value, vectors_attr_value, normals_attr_value;
1359 if (kv.second.size()==1)
1360 scalars_attr_value += (scalars_attr_value.empty() ?
"" :
" ") + kv.first;
1362 if (kv.first ==
"NORMALS")
1363 normals_attr_value =
"NORMALS";
1365 vectors_attr_value += (vectors_attr_value.empty() ?
"" :
" ") + kv.first;
1366 out_stream <<
" <PointData";
1367 if ( !(scalars_attr_value.empty()))
1368 out_stream <<
" Scalars='" << scalars_attr_value <<
"'";
1369 if ( !(normals_attr_value.empty()))
1370 out_stream <<
" Normals='" << normals_attr_value <<
"'";
1371 if ( !(vectors_attr_value.empty()))
1372 out_stream <<
" Vectors='" << vectors_attr_value <<
"'";
1373 out_stream <<
">" << std::endl;
1375 out_stream <<
" <DataArray Name='" << kv.first <<
"' type='Float64' format='ascii' NumberOfComponents='" << kv.second.size() <<
"'>" << std::endl;
1378 for (
auto& idx : kv.second)
1381 out_stream << std::endl <<
" </DataArray>" << std::endl;
1383 out_stream <<
" </PointData>" << std::endl;
1385 out_stream <<
" <Points>" << std::endl;
1386 out_stream <<
" <DataArray Name='Points' type='Float64' format='ascii' NumberOfComponents='3'>" << std::endl;
1389 out_stream <<
" " << std::setprecision(10) << pnt[0] <<
" " << pnt[1] <<
" " << pnt[2] << std::endl;
1391 out_stream <<
" </DataArray>" << std::endl;
1392 out_stream <<
" </Points>" << std::endl;
1393 out_stream <<
" <Cells>" << std::endl;
1394 out_stream <<
" <DataArray type='Int32' Name='connectivity' format='ascii'>" << std::endl;
1397 for(
auto& vert: poly)
1398 out_stream << vert <<
" ";
1399 out_stream << std::endl;
1401 out_stream <<
" </DataArray>" << std::endl;
1402 out_stream <<
" <DataArray type='Int32' Name='offsets' format='ascii'>" << std::endl;
1404 std::vector<int>::size_type j = 0;
1407 out_stream << j <<
" ";
1409 out_stream << std::endl;
1410 out_stream <<
" </DataArray>" << std::endl;
1411 out_stream <<
" <DataArray type='Int8' Name='types' format='ascii'>" << std::endl;
1415 out_stream << std::endl;
1416 out_stream <<
" </DataArray>" << std::endl;
1417 out_stream <<
" </Cells>" << std::endl;
1418 out_stream <<
" </Piece>" << std::endl;
1419 out_stream <<
" </UnstructuredGrid>" << std::endl;
1420 out_stream <<
"</VTKFile>" << std::endl;
1423 out_stream << std::endl;
1439 std::cout <<
"ERROR(write_legacy_vtk): No points!" << std::endl;
1443 std::cout <<
"ERROR(write_legacy_vtk): No cells!" << std::endl;
1447 std::ofstream out_stream;
1448 out_stream.open(file_name, std::ios::out | std::ios::binary | std::ios::trunc);
1449 if (out_stream.is_open()) {
1450 out_stream.imbue(std::locale::classic());
1452 std::cout <<
"ERROR(write_legacy_vtk): Could not open file!" << std::endl;
1456 out_stream <<
"# vtk DataFile Version 3.0" << std::endl;
1457 out_stream << description << std::endl;
1458 out_stream <<
"ASCII" << std::endl;
1459 out_stream <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
1461 out_stream <<
"POINTS " <<
node_count() <<
" double" << std::endl;
1465 out_stream << std::setprecision(10) << pnt[0] <<
" " << pnt[1] <<
" " << pnt[2] << std::endl;
1468 std::vector<int>::size_type total_cells_ints = 0;
1470 total_cells_ints += (1+cell.size());
1471 out_stream <<
"CELLS " <<
num_cells() <<
" " << total_cells_ints << std::endl;
1473 out_stream << poly.size() <<
" ";
1474 for(
auto& vert: poly) {
1475 out_stream << vert <<
" ";
1477 out_stream << std::endl;
1479 out_stream <<
"CELL_KINDS " <<
num_cells() << std::endl;
1484 out_stream <<
"POINT_DATA " <<
node_count() << std::endl;
1487 if (kv.second.size() == 1) {
1488 out_stream <<
"SCALARS " << kv.first <<
" double 1" << std::endl;
1489 out_stream <<
"LOOKUP_TABLE default" << std::endl;
1492 out_stream << std::setprecision(10) << v << std::endl;
1499 if (kv.second.size() == 3) {
1500 if (
"NORMALS" == kv.first) {
1501 out_stream <<
"NORMALS " << kv.first <<
" double" << std::endl;
1502 }
else if (
"COLORS" == kv.first) {
1503 out_stream <<
"COLOR_SCALARS " << kv.first <<
" 3" << std::endl;
1505 out_stream <<
"VECTORS " << kv.first <<
" double" << std::endl;
1509 out_stream << std::setprecision(10) << v[0] <<
" " << v[1] <<
" " << v[2] << std::endl;
1516 out_stream << std::endl;
1525 std::cout <<
"Meta Data" << std::endl;
1526 std::cout <<
" Points .................. " <<
node_count() << std::endl;
1531 std::cout <<
" Cells ................... " <<
num_cells() << std::endl;
1533 int num_nodes_printed = 0;
1534 std::cout <<
"NODES BEGIN (" <<
node_count() <<
")" << std::endl;
1536 std::cout <<
" " << pnt_idx <<
": " <<
node_to_string(pnt_idx) << std::endl;
1537 num_nodes_printed++;
1538 if ((max_num_print > 0) && (num_nodes_printed >= max_num_print)) {
1539 std::cout <<
" Maximum number of nodes reached. Halting tree dump." << std::endl;
1543 std::cout <<
"NODES END" << std::endl;
1546 int num_cells_printed = 0;
1547 std::cout <<
"CELLS BEGIN (" <<
num_cells() <<
")" << std::endl;
1551 std::cout << vert <<
" ";
1553 num_cells_printed++;
1554 if ((max_num_print > 0) && (num_cells_printed >= max_num_print)) {
1555 std::cout <<
" Maximum number of cells reached. Halting tree dump." << std::endl;
1559 std::cout <<
"CELLS END" << std::endl;
1574 std::cout <<
"ERROR(write_ply): No points!" << std::endl;
1578 std::cout <<
"ERROR(write_ply): No cells!" << std::endl;
1584 std::cout <<
"ERROR(write_ply): Cells must all be 2D (triangles or quads)!" << std::endl;
1589 std::ofstream out_stream;
1590 out_stream.open(file_name, std::ios::out | std::ios::binary | std::ios::trunc);
1591 if (out_stream.is_open()) {
1592 out_stream.imbue(std::locale::classic());
1594 std::cout <<
"ERROR(write_ply): Could not open file!" << std::endl;
1599 out_stream <<
"ply" << std::endl;
1600 out_stream <<
"format ascii 1.0" << std::endl;
1601 out_stream <<
"comment software: Mitch Richling's MR_rect_tree package" << std::endl;
1602 out_stream <<
"comment note: " << description << std::endl;
1603 out_stream <<
"element vertex " <<
node_count() << std::endl;
1604 out_stream <<
"property float x" << std::endl;
1605 out_stream <<
"property float y" << std::endl;
1606 out_stream <<
"property float z" << std::endl;
1607 if (have_colors_data) {
1608 out_stream <<
"property uchar red" << std::endl;
1609 out_stream <<
"property uchar green" << std::endl;
1610 out_stream <<
"property uchar blue" << std::endl;
1612 if (have_normal_data) {
1613 out_stream <<
"property float nx" << std::endl;
1614 out_stream <<
"property float ny" << std::endl;
1615 out_stream <<
"property float nz" << std::endl;
1617 out_stream <<
"element face " <<
num_cells() << std::endl;
1618 out_stream <<
"property list uchar int vertex_index" << std::endl;
1619 out_stream <<
"end_header" << std::endl;
1623 out_stream << std::setprecision(10) << pnt[0] <<
" " << pnt[1] <<
" " << pnt[2];
1624 if (have_colors_data) {
1626 out_stream <<
" " <<
static_cast<int>(255*clr[0]) <<
" " <<
static_cast<int>(255*clr[1]) <<
" " <<
static_cast<int>(255*clr[2]);
1628 if (have_normal_data) {
1631 out_stream <<
" " << std::setprecision(10) << nml[0] <<
" " << nml[1] <<
" " << nml[2];
1633 out_stream << std::endl;
1637 out_stream << poly.size() <<
" ";
1638 for(
auto& vert: poly) {
1639 out_stream << vert <<
" ";
1641 out_stream << std::endl;
1644 out_stream << std::endl;
1657 return (std::isnan(test_pnt[0]) || std::isnan(test_pnt[1]) || std::isnan(test_pnt[2]));
1666 if (std::abs(test_pnt[axis_index]-level) < close_epsilon)
1668 else if(test_pnt[axis_index] < level)
1693 int idx_last_good = -1;
1695 for(
int i=0; i<start_size; i++)
1698 if (idx_last_good != i)
1716 void mirror(std::vector<int> flip_list,
uft_t zero_epsilon=
epsilon*1000,
bool reverse_vertex_order=
true) {
1718 for(
int cell_idx=0; cell_idx<num_start_cells; ++cell_idx) {
1720 for(
auto pidx:
cell_lst[cell_idx]) {
1722 for(
int flip_list_idx=0; flip_list_idx<static_cast<int>(flip_list.size()); ++flip_list_idx)
1723 if ((flip_list[flip_list_idx]) && (std::abs(od[flip_list_idx]) < zero_epsilon))
1724 od[flip_list_idx] = 0;
1727 if constexpr (chk_point_unique) {
1730 std::cout <<
"ERROR(mirror): Collapse caused collision!" << std::endl;
1734 for(
int flip_list_idx=0; flip_list_idx<static_cast<int>(flip_list.size()); ++flip_list_idx)
1735 if (flip_list[flip_list_idx])
1736 nd[flip_list_idx] = -nd[flip_list_idx];
1738 new_cell.push_back(p);
1740 if (reverse_vertex_order)
1741 std::reverse(new_cell.begin(), new_cell.end());
1768 static std::unordered_map<node_idx_t, std::unordered_map<node_idx_t, node_idx_t>> edge_solver_cache;
1769 if (sdf_func ==
nullptr) {
1770 edge_solver_cache.clear();
1773 node_idx_t cache_key1 = std::min(pnt_idx1, pnt_idx2);
1774 node_idx_t cache_key2 = std::max(pnt_idx1, pnt_idx2);
1776 if (edge_solver_cache.contains(cache_key1))
1777 if (edge_solver_cache[cache_key1].contains(cache_key2))
1778 return edge_solver_cache[cache_key1][cache_key2];
1784 uft_t pos_pnt_sdfv = sdf_func(pos_node_data);
1785 if (pos_pnt_sdfv > 0) {
1787 neg_pnt_sdfv = sdf_func(neg_node_data);
1789 neg_node_data = pos_node_data;
1790 neg_pnt_sdfv = pos_pnt_sdfv;
1792 pos_pnt_sdfv = sdf_func(pos_node_data);
1797 if (std::abs(pos_pnt_sdfv) < std::abs(neg_pnt_sdfv)) {
1798 sol_node_data = pos_node_data;
1799 sol_pnt_sdfv = pos_pnt_sdfv;
1801 sol_node_data = neg_node_data;
1802 sol_pnt_sdfv = neg_pnt_sdfv;
1804 if (neg_pnt_sdfv < 0) {
1805 while ((std::abs(sol_pnt_sdfv) > solve_epsilon) && (pos_pnt_sdfv-neg_pnt_sdfv) > solve_epsilon) {
1806 for(
decltype(pos_node_data.size()) i=0; i<pos_node_data.size(); i++)
1807 sol_node_data[i] = (pos_node_data[i] + neg_node_data[i])/
static_cast<uft_t>(2.0);
1808 sol_pnt_sdfv = sdf_func(sol_node_data);
1809 if (sol_pnt_sdfv > 0) {
1810 pos_node_data = sol_node_data;
1811 pos_pnt_sdfv = sol_pnt_sdfv;
1813 neg_node_data = sol_node_data;
1814 neg_pnt_sdfv = sol_pnt_sdfv;
1820 edge_solver_cache[cache_key1][cache_key2] = sol_pnt_idx;
1831 for(
int cell_idx=0; cell_idx<num_start_cells; ++cell_idx) {
1833 auto& cur_cell =
cell_lst[cell_idx];
1835 int zero_cnt= 0, plus_cnt= 0, negv_cnt= 0;
1836 int zero_loc=-1, plus_loc=-1, negv_loc=-1;
1837 for(
int i=0; i<3; i++) {
1839 if (std::abs(sdf_val) <= solve_epsilon) {
1843 if (sdf_val <
static_cast<uft_t>(0.0)) {
1852 const std::vector<std::array<int, 3>> pmat { {0, 1, 2}, {1, 2, 0}, {2, 0, 1}};
1853 std::array<int, 3> p;
1854 if ((zero_cnt == 0) && (plus_cnt > 0) && (negv_cnt >0)) {
1859 auto orgv0 = cur_cell[p[0]];
1860 auto orgv1 = cur_cell[p[1]];
1861 auto orgv2 = cur_cell[p[2]];
1862 auto newv1 =
edge_solver_sdf(data_func, orgv0, orgv1, sdf_func, solve_epsilon);
1863 auto newv2 =
edge_solver_sdf(data_func, orgv0, orgv2, sdf_func, solve_epsilon);
1864 if ((newv1 != orgv0) && (newv1 != orgv1) && (newv2 != orgv0) && (newv2 != orgv2)) {
1865 cur_cell[p[1]] = newv1;
1866 cur_cell[p[2]] = newv2;
1870 }
else if ((zero_cnt == 1) && (plus_cnt == 1) && (negv_cnt == 1)) {
1872 auto orgv0 = cur_cell[p[0]];
1873 auto orgv1 = cur_cell[p[1]];
1874 auto orgv2 = cur_cell[p[2]];
1875 auto newv0 =
edge_solver_sdf(data_func, orgv1, orgv2, sdf_func, solve_epsilon);
1876 if ((newv0 != orgv1) && (newv0 != orgv2)) {
1877 cur_cell[2] = newv0;
1892 for(
int cell_idx=0; cell_idx<num_start_cells; ++cell_idx) {
1894 auto& cur_cell =
cell_lst[cell_idx];
1895 int plus_cnt=0, negv_cnt=0;
1896 for(
int i=0; i<2; i++) {
1898 if (sdf_val <
static_cast<uft_t>(0.0))
1900 else if (sdf_val >
static_cast<uft_t>(0.0))
1903 if ((plus_cnt == 1) && (negv_cnt == 1)) {
1904 auto orgv0 = cur_cell[0];
1905 auto orgv1 = cur_cell[1];
1906 auto newv =
edge_solver_sdf(data_func, orgv0, orgv1, sdf_func, solve_epsilon);
1907 if ((newv != orgv0) && (newv != orgv1)) {
1923 return std::all_of(cell_verts.cbegin(), cell_verts.cend(), [
this, level_index, level, level_epsilon](
int v) { return (node_idx_to_node_data[v][level_index] > level+level_epsilon); });
1927 return std::all_of(cell_verts.cbegin(), cell_verts.cend(), [
this, level_index, level, level_epsilon](
int v) { return (node_idx_to_node_data[v][level_index] < level+level_epsilon); });
1931 int pos_cnt=0, neg_cnt=0;
1932 for(
auto v: cell_verts) {
1934 if (mjr::math::fnear_zero(sv, sdf_epsilon))
1941 if ((neg_cnt > 0) && (pos_cnt > 0))
1960#define MJR_INCLUDE_MR_cell_cplx
Template class used to store and transform cell complexes (mesh/triangluation/etc....
std::vector< fvec3_t > fvec3_list_t
Hold a list of MR_cell_cplx::fvec3_t objects.
std::function< node_data_t(const node_data_t &)> p2data_func_t
Function that takes and returns a node_data_t (Node Data Transform)
uft_t vec3_scalar_triple_product(const fvec3_t &pnt1, const fvec3_t &pnt2, const fvec3_t &pnt3) const
Compute the vector diffrence.
std::set< cell_verts_t > uniq_cell_lst_t
Used to uniquify cells.
cell_stat_t check_cell_vertexes(cell_kind_t cell_kind, cell_verts_t cell_verts) const
Perform cell vertex checks.
void create_named_datasets(named_data_name_list_t scalar_name_strings, data_name_to_node_data_idx_lst_t names)
This is an overloaded member function, provided for convenience. It differs from the above function o...
node_idx_t idx_of_last_point_added() const
Retruns the index of the last point given to the add_node() method.
fvec3_t vec3_linear_combination(uft_t scl1, const fvec3_t &pnt1, uft_t scl2, const fvec3_t &pnt2) const
Compute the linear combination.
node_idx_list_t cell_verts_t
Type to hold the vertexes of a poly cell.
cell_stat_t check_cell_dimension(cell_kind_t cell_kind, cell_verts_t cell_verts) const
Perform cell dimension (2D cells must not be colinear & 3D cells must not be coplainer)
std::string seg_isect_to_string(seg_isect_t seg_isect) const
Convert an seg_isect_t to a string.
fvec3_t vec3_cross_product(const fvec3_t &pnt1, const fvec3_t &pnt2) const
Compute the cross prodcut.
std::string node_to_string(node_idx_t pnt_idx) const
Convert a fvec3_t to a string representation.
bool cell_stat_is_good(cell_stat_t cell_stat) const
Convert cell_stat_t to a bool (true if GOOD).
cell_structure_t & cell_kind_to_structure(cell_kind_t cell_kind, int dimension) const
Convert cell_kind_t value to a list of vertexes.
bool geomr_pts_coplanar(fvec3_t p1, fvec3_t p2, fvec3_t p3, fvec3_t p4) const
Check if points are coplanar.
std::function< bool(const cell_verts_t &)> c2bool_func_t
Function that takes a cell and returns a bool (Cell Predicate)
bool cell_near_sdf_boundry(const cell_verts_t cell_verts, p2real_func_t sdf_function, uft_t sdf_epsilon=epsilon)
Return true if cell is near SDF boundry.
std::array< uft_t, 3 > fvec3_t
Hold a tuple of real values defining a point/vector in R^3 (also see MR_cell_cplx::vdat_t).
cell_stat_t status_of_last_cell_added() const
Retruns the status of the last cell given to the add_cell() method.
std::string cell_stat_to_string(cell_stat_t cell_stat) const
Convert cell_stat_t enum value to a string.
void set_data_name_to_data_idx_lst(data_name_to_node_data_idx_lst_t names)
Create named data sets by setting raw member.
bool last_cell_added_was_new() const
Retruns true if the last cell given to the add_cell() was new and the return value of status_of_last_...
uft_t geomr_pnt_pln_distance(const fvec3_t &plnpnt1, const fvec3_t &plnpnt2, const fvec3_t &plnpnt3, const fvec3_t &pnt) const
Compute the distance between a point and a plane.
std::vector< node_idx_t > node_idx_list_t
list of node indexes.
node_data_idx_lst_t node_data_to_pnt
How to construct a point from a node dataset.
int io_result
Type returned by I/O functions.
bool cell_below_level(const cell_verts_t cell_verts, int level_index, uft_t level, uft_t level_epsilon=epsilon)
Return true if ALL vertexes are below the level by more than epsilon.
std::vector< uft_t > node_data_t
Type to hold a data for a single node.
void dump_cplx(int max_num_print) const
Dump object to STDOUT.
std::vector< cell_verts_t > cell_lst_t
Type for a list of poly cells.
node_data_t vdat_t
Type to hold a list values extracted from node data via a MR_cell_cplx::node_data_idx_lst_t (also see...
int num_cells() const
Number of cells.
bool geomi_pts_colinear(node_idx_t pi1, node_idx_t pi2, node_idx_t pi3, node_idx_t pi4) const
Check if points are colinear.
bool geomr_pts_colinear(fvec3_t p1, fvec3_t p2, fvec3_t p3) const
Check if points are colinear.
uft_t scalar_from_node_data(node_data_idx_t data_idx, node_data_t node_data) const
Extract a uft_t from a node_data_t and a node_data_idx_t.
cell_stat_t last_cell_stat
Status of the last cell added via add_cell() method.
uft_t vec3_dot_product(const fvec3_t &pnt1, const fvec3_t &pnt2) const
Compute the cross prodcut.
seg_isect_t
Segment intersection types.
@ CI_VERTEX0
Cardinality=infinite. Intersection is a segment – no vertexes included.
@ BAD_SEGMENT
At least one of the segments was degenerate.
@ C1_INTERIOR
Cardinality=1. Intersection is a single point in interior of at least one segment.
@ C0_EMPTY
Cardinality=0. Intersection is the empty set.
@ CI_VERTEX1
Cardinality=infinite. Intersection is a segment – exactially one vertex in the intersection.
@ CI_VERTEX2
Cardinality=infinite. Intersection is a segment – equal to input segments.
@ C1_VERTEX1
Cardinality=1. Intersection is a single, shared vertex.
bool geomi_pts_colinear(node_idx_t pi1, node_idx_t pi2, node_idx_t pi3) const
Check if points are colinear.
bool geomi_pts_coplanar(const node_idx_list_t &pnt_list) const
Check if points are coplanar.
int named_vector_datasets_count() const
Return the number of named vector datasets.
int named_datasets_count() const
Return the number of named (both vector and scalar) datasets.
bool cell_stat_is_bad(cell_stat_t cell_stat) const
Convert cell_stat_t to a bool (true if BAD).
fvec3_t geomr_tri_normal(const fvec3_t &tripnt1, const fvec3_t &tripnt2, const fvec3_t &tripnt3, bool unit) const
Compute the normal of a triangle (or a plane defined by 3 points)
uft_t vec3_det3(const fvec3_t &pnt1, const fvec3_t &pnt2, const fvec3_t &pnt3) const
Determinant of 3x3 matrix with given vectors as columns/rows.
uft_t geomr_pnt_pnt_distance(const fvec3_t &pnt1, const fvec3_t &pnt2) const
Compute the euculedian (2 norm) distance between two points.
seg_isect_t geomi_seg_isect_type(node_idx_t ilin1pnt1, node_idx_t ilin1pnt2, node_idx_t ilin2pnt1, node_idx_t ilin2pnt2) const
Determine the nature of the intersection between two line segments.
node_idx_t last_point_added_was_new() const
Retruns true if the last point given to the add_node() method was a new point.
void segment_folder(p2data_func_t data_func, p2real_func_t sdf_func, uft_t solve_epsilon=epsilon/10)
Fold segments that cross over an SDF function.
cell_kind_t req_pt_cnt_to_cell_kind(std::vector< int >::size_type node_count) const
Convert number of points in a cell to cell_kind_t.
bool geomi_seg_isect1(node_idx_t ilin1pnt1, node_idx_t ilin1pnt2, node_idx_t ilin2pnt1, node_idx_t ilin2pnt2) const
Check if two line segments intersect in a single point.
node_idx_t last_point_idx
The index of the last point added via the add_node() method.
std::vector< named_data_name_t > named_data_name_list_t
Type to hold a list of dataset names.
std::vector< node_data_t > node_idx_to_node_data_t
Type to hold a all node data.
cell_stat_t check_cell_faces_plainer(cell_kind_t cell_kind, cell_verts_t cell_verts) const
Check if the vertexes of a cell are coplainer.
flt_type uft_t
Universal floating point type – used for point components, scalar data values, vector components,...
uft_t vec3_self_dot_product(const fvec3_t &pnt) const
Compute the self dot product – i.e.
cell_lst_t cell_structure_t
Cell segment/face/etc structure.
void create_dataset_to_point_mapping(node_data_idx_lst_t point_data_index)
Create mapping beteen node data and geometric pionts.
uft_t vec3_two_norm(const fvec3_t &pnt) const
Compute the magnitude.
node_idx_t node_count() const
Return the number of points in the central node data list.
fvec3_t get_pnt(node_idx_t pnt_idx) const
Return point given a node index.
bool add_cell(cell_kind_t new_cell_kind, cell_verts_t new_cell_verts)
Add a cell.
static constexpr uft_t epsilon
epsilon
bool geomi_pts_coplanar(node_idx_t pi1, node_idx_t pi2, node_idx_t pi3, node_idx_t pi4) const
Check if points are coplanar.
node_idx_t add_node(node_data_t node_data)
Add a point to the central node data store.
data_name_to_node_data_idx_lst_t data_name_to_data_idx_lst
Hold named descriptions of data (scalars & vectors)
io_result write_xml_vtk(std::string file_name, std::string description)
Dump to an XML VTK unstructured grid file.
void clear_cache_edge_solver_sdf()
Clear the solution cache stored in edge_solver_sdf().
std::string cell_kind_to_string(cell_kind_t cell_kind) const
Convert cell_kind_t value to the VTK cell type integer.
bool last_cell_new
True if the last cell given to the add_cell() method was new – i.e.
void create_named_datasets(named_data_name_list_t scalar_name_strings)
Create named data sets.
int node_idx_t
Integer type used to indentify/index nodes.
std::map< fvec3_t, node_idx_t, pnt_less > pnt_to_node_idx_map_t
Used to uniquify points and assign point index values.
bool geomr_seg_isect1(const fvec3_t &lin1pnt1, const fvec3_t &lin1pnt2, const fvec3_t &lin2pnt1, const fvec3_t &lin2pnt2) const
Check if two line segments intersect in a single point.
bool geomr_seg_tri_intersection(fvec3_t tp1, fvec3_t tp2, fvec3_t tp3, fvec3_t sp1, fvec3_t sp2) const
Compute intersection of a segment and a triangle.
uft_t geomr_pnt_line_distance(const fvec3_t &linpnt1, const fvec3_t &linpnt2, const fvec3_t &pnt, bool seg_distance) const
Distance between a point and a line.
@ TOO_FEW_PNT
List of points was empty check_cell_vertexes.
@ GOOD
Looks like a good cell N/A.
@ DUP_PNT
At least two points have the same index check_cell_vertexes.
@ BAD_FACEI
Bad face-edge intersection check_cell_face_intersections.
@ NEG_PNT_IDX
Negative point index (i.e. not on the central node data) check_cell_vertexes.
@ TOO_MANY_PNT
List of points was too long (>5) check_cell_vertexes.
@ BIG_PNT_IDX
Point index was too big (i.e. not on the central node data) check_cell_vertexes.
@ FACE_BENT
A face (QUAD, HEXAHEDRON, or PYRAMID) was not plainer check_cell_faces_plainer.
@ BAD_EDGEI
Bad edge-edge intersection check_cell_edge_intersections.
@ DIM_LOW
Dimension low (degenerate) check_cell_dimension.
@ CONCAVE
(QUAD, HEXAHEDRON, or PYRAMID) was concave TBD
bool last_point_new
True if the last point given to the add_node() method was new – i.e.
int cull_cells(c2bool_func_t func)
Delete cells matching a predicate function.
std::string named_data_name_t
Type to hold a dataset name.
int cell_kind_to_dimension(cell_kind_t cell_kind) const
Convert cell_kind_t value to the logical dimension of the cell.
bool vec3_unitize(fvec3_t &pnt) const
Unitize the given point in place.
void mirror(std::vector< int > flip_list, uft_t zero_epsilon=epsilon *1000, bool reverse_vertex_order=true)
Add new cells with points from existing cells with the given coordinates negated.
int add_cell(cell_kind_t new_cell_kind, cell_verts_t new_cell_verts, int dimension)
Add parts of a cell of the specified dimension.
node_idx_t edge_solver_sdf(p2data_func_t dat_func, node_idx_t pnt_idx1, node_idx_t pnt_idx2, p2real_func_t sdf_func, uft_t solve_epsilon=epsilon/10)
Solve an SDF function for zero on a line between two node data sets, and add the solution to the cent...
io_result write_ply(std::string file_name, std::string description)
Dump to a PLY file.
bool pnt_has_nan(const fvec3_t &test_pnt)
Return true if any component of the point has a NaN.
uniq_cell_lst_t uniq_cell_lst
Unique cell list.
std::map< named_data_name_t, node_data_idx_lst_t > data_name_to_node_data_idx_lst_t
Type to map names to named data sets (index lists).
int cell_kind_to_vtk_type(cell_kind_t cell_kind) const
Convert cell_kind_t value to the VTK cell type integer.
static constexpr uft_t uft_epsilon
cell_stat_t check_cell_face_intersections(cell_kind_t cell_kind, cell_verts_t cell_verts) const
Checks that cell faces have expected intersections.
std::variant< int, uft_t > node_data_idx_t
Type used to hold an index into a node_data_t or a constant MR_cell_cplx::uft_t.
uft_t geomi_pnt_line_distance(node_idx_t ilinpnt1, node_idx_t ilinpnt2, node_idx_t ipnt, bool seg_distance) const
Distance between a point and a line.
int pnt_vs_level(const fvec3_t &test_pnt, int axis_index, uft_t level, uft_t close_epsilon=epsilon)
Return 0 if point is close to the level, -1 if it is below the level, and 1 if it is above the level.
int named_scalar_datasets_count() const
Return the number of named scalar datasets.
cell_lst_t cell_lst
House all poly cells.
cell_stat_t check_cell_edge_intersections(cell_kind_t cell_kind, cell_verts_t cell_verts) const
Checks that cell edges have expected intersections.
uft_t geomr_pnt_tri_distance(const fvec3_t &tripnt1, const fvec3_t &tripnt2, const fvec3_t &tripnt3, const fvec3_t &pnt) const
Compute the distance between a point and a triangle.
vdat_t vector_from_node_data(node_data_idx_lst_t data_idx_lst, node_data_t node_data) const
Construct a vdat_t from a node_data_t and a node_data_idx_lst_t.
std::function< bool(const node_data_t &)> p2bool_func_t
Function that takes node data and returns a bool (Node Data Predicate)
node_idx_to_node_data_t node_idx_to_node_data
Hold all node data sets.
bool cell_above_level(const cell_verts_t cell_verts, int level_index, uft_t level, uft_t level_epsilon=epsilon)
Return true if ALL vertexes are above the level by more than epsilon.
void triangle_folder(p2data_func_t data_func, p2real_func_t sdf_func, uft_t solve_epsilon=epsilon/10)
Fold triangles that cross over an SDF function.
bool geomr_pnt_zero(const fvec3_t &p1) const
Check if points (just one point for this function) are zero.
int cell_kind_to_req_pt_cnt(cell_kind_t cell_kind) const
Convert cell_kind_t value to the number of points required for cell type.
std::vector< node_data_idx_t > node_data_idx_lst_t
Type to hold a list of data indexes – one element for scalars, 3 for vectors, etc....
std::function< uft_t(const node_data_t &)> p2real_func_t
Function that takes node data and returns a float (Node Data SDF)
io_result write_legacy_vtk(std::string file_name, std::string description)
Dump to a legacy VTK UNSTRUCTUREDGRID file.
pnt_to_node_idx_map_t pnt_to_node_idx_map
Maps points to point index – used to detect points with nearly identical geometric points in R^3.
fvec3_t fvec3_from_node_data(node_data_idx_lst_t data_idx_lst, node_data_t node_data) const
Construct a fvec3_t from a node_data_t and a node_data_idx_lst_t.
fvec3_t vec3_diff(const fvec3_t &pnt1, const fvec3_t &pnt2) const
Compute the vector diffrence.
MR_cell_cplx< false, false, false, false, false, double, 1.0e-9 > MRccF9
MR_cell_cplx< false, false, false, false, false, double, 1.0e-5 > MRccF5
MR_cell_cplx< true, true, true, true, true, double, 1.0e-3 > MRccT3
MR_cell_cplx< true, true, true, true, true, double, 1.0e-5 > MRccT5
MR_cell_cplx< true, true, true, true, true, double, 1.0e-9 > MRccT9
MR_cell_cplx< false, false, false, false, false, double, 1.0e-3 > MRccF3