From 6f711e0ab2058ea41762894ea644799d8f4208c5 Mon Sep 17 00:00:00 2001 From: Floyd Chitalu Date: Mon, 13 Jan 2025 21:26:18 +0000 Subject: [PATCH] bug fixes; identified the potential source of man problem causing floating polygon partitioning to create duplicate vertices --- include/mcut/internal/frontend.h | 6 +++ source/frontend.cpp | 15 +++++- source/math.cpp | 86 +++++++++++++++++++++++++++----- source/preproc.cpp | 56 ++++++++++++++++----- tests/source/benchmark.cpp | 2 + 5 files changed, 138 insertions(+), 27 deletions(-) diff --git a/include/mcut/internal/frontend.h b/include/mcut/internal/frontend.h index ac90846..f25c663 100644 --- a/include/mcut/internal/frontend.h +++ b/include/mcut/internal/frontend.h @@ -286,6 +286,7 @@ struct connected_component_t { // ] // std::vector seam_vertex_sequence_array_cache; +# if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS // // The multiplier is a value that is used to convert between native user coordinates // and rational integer coordinates. Each connected component has such a value, which @@ -293,6 +294,11 @@ struct connected_component_t { // came from. Refer to the "preproc" function for more detail on how it is computed. // double multiplier; + // the vertex centre of mass computed using the srcmesh and cutmesh (in user coordinates). + vec3_ srcmesh_cutmesh_com; + // translation vectors that shifts recentred coordinates to the positive quadrant. + vec3_ pre_quantization_translation; + #endif }; // struct representing a fragment diff --git a/source/frontend.cpp b/source/frontend.cpp index f12f1e5..c79ea78 100644 --- a/source/frontend.cpp +++ b/source/frontend.cpp @@ -2051,8 +2051,10 @@ void get_connected_component_data_impl_detail( for (int i = 0; i < 3; ++i) { #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS - const float val = static_cast( - scalar_t::dequantize(coords[i], cc_uptr->multiplier)); + const float val = static_cast(scalar_t::dequantize( + coords[i], cc_uptr->multiplier)) + + cc_uptr->srcmesh_cutmesh_com[i] - + cc_uptr->pre_quantization_translation[i]; #else const float val = static_cast(coords[i]); #endif @@ -2133,7 +2135,16 @@ void get_connected_component_data_impl_detail( // for each component of coordinate for (int i = 0; i < 3; ++i) { +#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS + const double val = + scalar_t::dequantize(coords[i], cc_uptr->multiplier) + + cc_uptr->srcmesh_cutmesh_com[i] - + cc_uptr->pre_quantization_translation[i]; +#else + const double val = static_cast(coords[i]); + +#endif *(casted_ptr + elem_offset) = val; elem_offset += 1; } diff --git a/source/math.cpp b/source/math.cpp index 3138479..a9579c7 100644 --- a/source/math.cpp +++ b/source/math.cpp @@ -131,18 +131,37 @@ normal = vec3(0.0); //int crossprods = 0; for (int i = 1; i < polygon_vertex_count - 1; ++i) { - auto cross = cross_product( polygon_vertices[i] - polygon_vertices[0], - polygon_vertices[(i + 1) % polygon_vertex_count] - polygon_vertices[0]); - if(squared_length(cross) > scalar_t::zero()) - { +#if !defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS) normal = normal + normalize( cross_product(polygon_vertices[i] - polygon_vertices[0], polygon_vertices[(i + 1) % polygon_vertex_count] - polygon_vertices[0]) , multiplier); - //crossprods++; - } +#else + auto vec0 = polygon_vertices[i] - polygon_vertices[0]; + auto vec1 = polygon_vertices[(i + 1) % polygon_vertex_count] - polygon_vertices[0]; + if(squared_length(vec0) > scalar_t::zero() && squared_length(vec1) > scalar_t::zero()) + { + vec3_ vec0_(scalar_t::dequantize(vec0[0], multiplier), + scalar_t::dequantize(vec0[1], multiplier), + scalar_t::dequantize(vec0[2], multiplier)); + vec3_ vec1_(scalar_t::dequantize(vec1[0], multiplier), + scalar_t::dequantize(vec1[1], multiplier), + scalar_t::dequantize(vec1[2], multiplier)); + + auto cross_ = cross_product(vec0_, vec1_); + if(squared_length(cross_) > 0.) + { + auto cross_n = normalize(cross_); + vec3 cross = vec3(scalar_t::quantize(cross_n[0], multiplier), + scalar_t::quantize(cross_n[1], multiplier), + scalar_t::quantize(cross_n[2], multiplier)); + normal = normal + cross; + break; + } + } +#endif } @@ -227,10 +246,48 @@ const int polygon_vertex_count = (int)polygon_vertices.size(); MCUT_ASSERT(polygon_vertex_count >= 3); + /*{ + std::ofstream f("poly.obj"); + + for(int v = 0; v < polygon_vertices.size(); ++v) + { + f << "v " << scalar_t::dequantize(polygon_vertices[v][0], multiplier) << " " + << scalar_t::dequantize(polygon_vertices[v][1], multiplier) << " " + << scalar_t::dequantize(polygon_vertices[v][2], multiplier) << std::endl; + } + + f << "f "; + for(int v = 0; v < polygon_vertices.size(); ++v) + { + f << v << " "; + } + f << std::endl; + f.close(); + }*/ + std::vector x; project_to_2d(x, polygon_vertices, polygon_normal, polygon_normal_largest_component, multiplier); MCUT_ASSERT(x.size() == (size_t)polygon_vertex_count); + /*{ + std::ofstream f("poly2.obj"); + + for(int v = 0; v < x.size(); ++v) + { + f << "v " << scalar_t::dequantize(x[v][0], multiplier) << " " + << scalar_t::dequantize(x[v][1], multiplier) << " " + << 0 << std::endl; + } + + f << "f "; + for(int v = 0; v < x.size(); ++v) + { + f << v << " "; + } + f << std::endl; + f.close(); + }*/ + /* NOTE: We cannot just use _any_/the first result of "colinear(x[i], x[j], x[k])" which returns true since any three points that are _nearly_ colinear (in the limit of floating point precision) @@ -245,17 +302,20 @@ */ // get any three vertices that are not collinear - i = 0; + /*i = 0; j = i + 1; - k = j + 1; + k = j + 1;*/ std::vector> non_colinear_triplets; - for (; i < polygon_vertex_count; ++i) { - for (; j < polygon_vertex_count; ++j) { - for (; k < polygon_vertex_count; ++k) { + for (int i_=0; i_ < polygon_vertex_count; ++i_) + { + for (int j_=i_+1; j_ < polygon_vertex_count; ++j_) { + for(int k_ = j_ + 1; k_ < polygon_vertex_count; ++k_) + { scalar_t predRes; - if (!collinear(x[i], x[j], x[k], predRes)) { - non_colinear_triplets.emplace_back(std::make_tuple(i, j, k, predRes)); + //std::cout << "i=" << i_ << " j=" << j_ << " k="< edgePairA, @@ -1079,14 +1079,16 @@ void resolve_floating_polygons( it != polyVerts.cend(); ++it) { - + // TODO: call "collinear" with vec3_ not vec3. That is the only way to + // get a reliable measure because with double everything is in the same space/units + // (lengths areas etc). bool are_collinear = collinear(segStart, segEnd, (*it), predResult); // last ditch attempt to prevent the possibility of creating a partitioning // edge that more-or-less passes through a vertex (of origin-face or the floatig poly itself) // see: test41 - const scalar_t epsilon = 1e-6; + const double epsilon = 1e-6; #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS - if(are_collinear || (!are_collinear && epsilon > absolute_value(predResult))) + if(are_collinear || epsilon > scalar_t::dequantize(absolute_value(predResult),multiplier)) #else if(are_collinear || (!are_collinear && epsilon > std::fabs(predResult))) #endif @@ -2213,6 +2215,20 @@ bool calculate_vertex_parameters( pre_quantization_translation = to_positive_quadrant + offset_from_origin; + // + // update bboxes and coms + // + srcmesh_com = srcmesh_com + pre_quantization_translation; + cutmesh_com = cutmesh_com + pre_quantization_translation; + srcmesh_cutmesh_com = srcmesh_cutmesh_com + pre_quantization_translation; + srcmesh_bboxmin = srcmesh_bboxmin + pre_quantization_translation; + srcmesh_bboxmax = srcmesh_bboxmax + pre_quantization_translation; + cutmesh_bboxmin = cutmesh_bboxmin + pre_quantization_translation; + cutmesh_bboxmax = cutmesh_bboxmax + pre_quantization_translation; + srcmesh_cutmesh_bboxmin = srcmesh_cutmesh_bboxmin + pre_quantization_translation; + srcmesh_cutmesh_bboxmax = srcmesh_cutmesh_bboxmax + pre_quantization_translation; + + double max_coord = std::numeric_limits::lowest(); double min_coord = std::numeric_limits::max(); @@ -2307,8 +2323,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, numSrcMeshVertices, numSrcMeshFaces, multiplier, - vec3_(0.0) /*srcmesh_cutmesh_com*/, - vec3_(0.0)/*pre_quantization_translation*/)) + srcmesh_cutmesh_com, + pre_quantization_translation)) { throw std::invalid_argument("invalid source-mesh arrays"); } @@ -2331,12 +2347,12 @@ extern "C" void preproc(std::shared_ptr context_ptr, kernel_input.src_mesh = source_hmesh; - kernel_input.verbose = false; + kernel_input.verbose = true; kernel_input.require_looped_cutpaths = false; - kernel_input.verbose = - static_cast((context_ptr->get_flags() & MC_DEBUG) && - (context_ptr->dbgCallbackBitfieldType & MC_DEBUG_SOURCE_KERNEL)); + //kernel_input.verbose = + // static_cast((context_ptr->get_flags() & MC_DEBUG) && + // (context_ptr->dbgCallbackBitfieldType & MC_DEBUG_SOURCE_KERNEL)); kernel_input.require_looped_cutpaths = static_cast(dispatchFlags & MC_DISPATCH_REQUIRE_THROUGH_CUTS); kernel_input.populate_vertex_maps = @@ -2620,8 +2636,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, numCutMeshVertices, numCutMeshFaces, multiplier, - vec3_(0.0) /*srcmesh_cutmesh_com*/, - vec3_(0.0) /*pre_quantization_translation*/, + srcmesh_cutmesh_com, + pre_quantization_translation, ((cut_mesh_perturbation_count == 0) ? NULL : &perturbation))) { throw std::invalid_argument("invalid cut-mesh arrays"); @@ -3030,6 +3046,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asFragPtr->multiplier = multiplier; + asFragPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asFragPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( @@ -3095,6 +3113,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asFragPtr->multiplier = multiplier; + asFragPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asFragPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( @@ -3164,6 +3184,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asPatchPtr->multiplier = multiplier; + asPatchPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asPatchPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( cc_ptr); // copy the connected component ptr into the context object @@ -3229,6 +3251,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asPatchPtr->multiplier = multiplier; + asPatchPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asPatchPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( @@ -3300,6 +3324,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asSrcMeshSeamPtr->multiplier = multiplier; + asSrcMeshSeamPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asSrcMeshSeamPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( @@ -3365,6 +3391,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asCutMeshSeamPtr->multiplier = multiplier; + asCutMeshSeamPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asCutMeshSeamPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( @@ -3498,6 +3526,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asCutMeshInputPtr->multiplier = multiplier; + asCutMeshInputPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asCutMeshInputPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( @@ -3622,6 +3652,8 @@ extern "C" void preproc(std::shared_ptr context_ptr, #if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS asSrcMeshInputPtr->multiplier = multiplier; + asSrcMeshInputPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com; + asSrcMeshInputPtr->pre_quantization_translation = pre_quantization_translation; #endif context_ptr->connected_components.push_front( diff --git a/tests/source/benchmark.cpp b/tests/source/benchmark.cpp index e9a6720..327903b 100644 --- a/tests/source/benchmark.cpp +++ b/tests/source/benchmark.cpp @@ -103,6 +103,7 @@ UTEST_I_TEARDOWN(Benchmark) UTEST_I(Benchmark, inputID, NUMBER_OF_BENCHMARKS) { + std::vector> benchmarkMeshPairs; std::stringstream ss; @@ -138,6 +139,7 @@ UTEST_I(Benchmark, inputID, NUMBER_OF_BENCHMARKS) &utest_fixture->cutMesh.numVertices, &utest_fixture->cutMesh.numFaces); + // // do the cutting //