Skip to content

Commit 6f711e0

Browse files
committed
bug fixes; identified the potential source of man problem causing floating polygon partitioning to create duplicate vertices
1 parent 29c766e commit 6f711e0

File tree

5 files changed

+138
-27
lines changed

5 files changed

+138
-27
lines changed

include/mcut/internal/frontend.h

+6
Original file line numberDiff line numberDiff line change
@@ -286,13 +286,19 @@ struct connected_component_t {
286286
// ]
287287
//
288288
std::vector<uint32_t> seam_vertex_sequence_array_cache;
289+
# if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
289290
//
290291
// The multiplier is a value that is used to convert between native user coordinates
291292
// and rational integer coordinates. Each connected component has such a value, which
292293
// we determine from the two respective input meshes from which the connected component
293294
// came from. Refer to the "preproc" function for more detail on how it is computed.
294295
//
295296
double multiplier;
297+
// the vertex centre of mass computed using the srcmesh and cutmesh (in user coordinates).
298+
vec3_<double> srcmesh_cutmesh_com;
299+
// translation vectors that shifts recentred coordinates to the positive quadrant.
300+
vec3_<double> pre_quantization_translation;
301+
#endif
296302
};
297303

298304
// struct representing a fragment

source/frontend.cpp

+13-2
Original file line numberDiff line numberDiff line change
@@ -2051,8 +2051,10 @@ void get_connected_component_data_impl_detail(
20512051
for (int i = 0; i < 3; ++i) {
20522052
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
20532053

2054-
const float val = static_cast<float>(
2055-
scalar_t::dequantize(coords[i], cc_uptr->multiplier));
2054+
const float val = static_cast<float>(scalar_t::dequantize(
2055+
coords[i], cc_uptr->multiplier)) +
2056+
cc_uptr->srcmesh_cutmesh_com[i] -
2057+
cc_uptr->pre_quantization_translation[i];
20562058
#else
20572059
const float val = static_cast<float>(coords[i]);
20582060
#endif
@@ -2133,7 +2135,16 @@ void get_connected_component_data_impl_detail(
21332135

21342136
// for each component of coordinate
21352137
for (int i = 0; i < 3; ++i) {
2138+
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
2139+
const double val =
2140+
scalar_t::dequantize(coords[i], cc_uptr->multiplier) +
2141+
cc_uptr->srcmesh_cutmesh_com[i] -
2142+
cc_uptr->pre_quantization_translation[i];
2143+
#else
2144+
21362145
const double val = static_cast<double>(coords[i]);
2146+
2147+
#endif
21372148
*(casted_ptr + elem_offset) = val;
21382149
elem_offset += 1;
21392150
}

source/math.cpp

+73-13
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,37 @@
131131
normal = vec3(0.0);
132132
//int crossprods = 0;
133133
for (int i = 1; i < polygon_vertex_count - 1; ++i) {
134-
auto cross = cross_product( polygon_vertices[i] - polygon_vertices[0],
135-
polygon_vertices[(i + 1) % polygon_vertex_count] - polygon_vertices[0]);
136-
if(squared_length(cross) > scalar_t::zero())
137-
{
134+
#if !defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS)
138135
normal = normal +
139136
normalize( cross_product(polygon_vertices[i] - polygon_vertices[0],
140137
polygon_vertices[(i + 1) % polygon_vertex_count] -
141138
polygon_vertices[0]) , multiplier);
142-
//crossprods++;
143-
}
139+
#else
140+
auto vec0 = polygon_vertices[i] - polygon_vertices[0];
144141

142+
auto vec1 = polygon_vertices[(i + 1) % polygon_vertex_count] - polygon_vertices[0];
145143

144+
if(squared_length(vec0) > scalar_t::zero() && squared_length(vec1) > scalar_t::zero())
145+
{
146+
vec3_<double> vec0_(scalar_t::dequantize(vec0[0], multiplier),
147+
scalar_t::dequantize(vec0[1], multiplier),
148+
scalar_t::dequantize(vec0[2], multiplier));
149+
vec3_<double> vec1_(scalar_t::dequantize(vec1[0], multiplier),
150+
scalar_t::dequantize(vec1[1], multiplier),
151+
scalar_t::dequantize(vec1[2], multiplier));
152+
153+
auto cross_ = cross_product(vec0_, vec1_);
154+
if(squared_length(cross_) > 0.)
155+
{
156+
auto cross_n = normalize(cross_);
157+
vec3 cross = vec3(scalar_t::quantize(cross_n[0], multiplier),
158+
scalar_t::quantize(cross_n[1], multiplier),
159+
scalar_t::quantize(cross_n[2], multiplier));
160+
normal = normal + cross;
161+
break;
162+
}
163+
}
164+
#endif
146165
}
147166

148167

@@ -227,10 +246,48 @@
227246
const int polygon_vertex_count = (int)polygon_vertices.size();
228247
MCUT_ASSERT(polygon_vertex_count >= 3);
229248

249+
/*{
250+
std::ofstream f("poly.obj");
251+
252+
for(int v = 0; v < polygon_vertices.size(); ++v)
253+
{
254+
f << "v " << scalar_t::dequantize(polygon_vertices[v][0], multiplier) << " "
255+
<< scalar_t::dequantize(polygon_vertices[v][1], multiplier) << " "
256+
<< scalar_t::dequantize(polygon_vertices[v][2], multiplier) << std::endl;
257+
}
258+
259+
f << "f ";
260+
for(int v = 0; v < polygon_vertices.size(); ++v)
261+
{
262+
f << v << " ";
263+
}
264+
f << std::endl;
265+
f.close();
266+
}*/
267+
230268
std::vector<vec2> x;
231269
project_to_2d(x, polygon_vertices, polygon_normal, polygon_normal_largest_component, multiplier);
232270
MCUT_ASSERT(x.size() == (size_t)polygon_vertex_count);
233271

272+
/*{
273+
std::ofstream f("poly2.obj");
274+
275+
for(int v = 0; v < x.size(); ++v)
276+
{
277+
f << "v " << scalar_t::dequantize(x[v][0], multiplier) << " "
278+
<< scalar_t::dequantize(x[v][1], multiplier) << " "
279+
<< 0 << std::endl;
280+
}
281+
282+
f << "f ";
283+
for(int v = 0; v < x.size(); ++v)
284+
{
285+
f << v << " ";
286+
}
287+
f << std::endl;
288+
f.close();
289+
}*/
290+
234291
/*
235292
NOTE: We cannot just use _any_/the first result of "colinear(x[i], x[j], x[k])" which returns true since
236293
any three points that are _nearly_ colinear (in the limit of floating point precision)
@@ -245,17 +302,20 @@
245302
*/
246303

247304
// get any three vertices that are not collinear
248-
i = 0;
305+
/*i = 0;
249306
j = i + 1;
250-
k = j + 1;
307+
k = j + 1;*/
251308
std::vector<std::tuple<int, int, int, scalar_t>> non_colinear_triplets;
252309

253-
for (; i < polygon_vertex_count; ++i) {
254-
for (; j < polygon_vertex_count; ++j) {
255-
for (; k < polygon_vertex_count; ++k) {
310+
for (int i_=0; i_ < polygon_vertex_count; ++i_)
311+
{
312+
for (int j_=i_+1; j_ < polygon_vertex_count; ++j_) {
313+
for(int k_ = j_ + 1; k_ < polygon_vertex_count; ++k_)
314+
{
256315
scalar_t predRes;
257-
if (!collinear(x[i], x[j], x[k], predRes)) {
258-
non_colinear_triplets.emplace_back(std::make_tuple(i, j, k, predRes));
316+
//std::cout << "i=" << i_ << " j=" << j_ << " k="<<k_ << std::endl;
317+
if (!collinear(x[i_], x[j_], x[k_], predRes)) {
318+
non_colinear_triplets.emplace_back(std::make_tuple(i_, j_, k_, predRes));
259319
}
260320
}
261321
}

source/preproc.cpp

+44-12
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ void resolve_floating_polygons(
10151015

10161016
// NOTE: using max (i.e. < operator) lead to floating point precision issues on
10171017
// test 40. The only solution to which is exact arithmetic. However, since we still
1018-
// want MCUT to work even if the user only has fixed precision numbers.
1018+
// want MCUT to work even if the user only has fixed precision numbers (outdated).
10191019
// We pick edges based on this which are closest. No worries about colinear edges
10201020
// because they will be detected later and skipped!
10211021
auto fp_max_dist_predicate = [&](std::pair<int, int> edgePairA,
@@ -1079,14 +1079,16 @@ void resolve_floating_polygons(
10791079
it != polyVerts.cend();
10801080
++it)
10811081
{
1082-
1082+
// TODO: call "collinear" with vec3_<double> not vec3. That is the only way to
1083+
// get a reliable measure because with double everything is in the same space/units
1084+
// (lengths areas etc).
10831085
bool are_collinear = collinear(segStart, segEnd, (*it), predResult);
10841086
// last ditch attempt to prevent the possibility of creating a partitioning
10851087
// edge that more-or-less passes through a vertex (of origin-face or the floatig poly itself)
10861088
// see: test41
1087-
const scalar_t epsilon = 1e-6;
1089+
const double epsilon = 1e-6;
10881090
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
1089-
if(are_collinear || (!are_collinear && epsilon > absolute_value(predResult)))
1091+
if(are_collinear || epsilon > scalar_t::dequantize(absolute_value(predResult),multiplier))
10901092
#else
10911093
if(are_collinear || (!are_collinear && epsilon > std::fabs(predResult)))
10921094
#endif
@@ -2213,6 +2215,20 @@ bool calculate_vertex_parameters(
22132215

22142216
pre_quantization_translation = to_positive_quadrant + offset_from_origin;
22152217

2218+
//
2219+
// update bboxes and coms
2220+
//
2221+
srcmesh_com = srcmesh_com + pre_quantization_translation;
2222+
cutmesh_com = cutmesh_com + pre_quantization_translation;
2223+
srcmesh_cutmesh_com = srcmesh_cutmesh_com + pre_quantization_translation;
2224+
srcmesh_bboxmin = srcmesh_bboxmin + pre_quantization_translation;
2225+
srcmesh_bboxmax = srcmesh_bboxmax + pre_quantization_translation;
2226+
cutmesh_bboxmin = cutmesh_bboxmin + pre_quantization_translation;
2227+
cutmesh_bboxmax = cutmesh_bboxmax + pre_quantization_translation;
2228+
srcmesh_cutmesh_bboxmin = srcmesh_cutmesh_bboxmin + pre_quantization_translation;
2229+
srcmesh_cutmesh_bboxmax = srcmesh_cutmesh_bboxmax + pre_quantization_translation;
2230+
2231+
22162232
double max_coord = std::numeric_limits<double>::lowest();
22172233
double min_coord = std::numeric_limits<double>::max();
22182234

@@ -2307,8 +2323,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
23072323
numSrcMeshVertices,
23082324
numSrcMeshFaces,
23092325
multiplier,
2310-
vec3_<double>(0.0) /*srcmesh_cutmesh_com*/,
2311-
vec3_<double>(0.0)/*pre_quantization_translation*/))
2326+
srcmesh_cutmesh_com,
2327+
pre_quantization_translation))
23122328
{
23132329
throw std::invalid_argument("invalid source-mesh arrays");
23142330
}
@@ -2331,12 +2347,12 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
23312347

23322348
kernel_input.src_mesh = source_hmesh;
23332349

2334-
kernel_input.verbose = false;
2350+
kernel_input.verbose = true;
23352351
kernel_input.require_looped_cutpaths = false;
23362352

2337-
kernel_input.verbose =
2338-
static_cast<bool>((context_ptr->get_flags() & MC_DEBUG) &&
2339-
(context_ptr->dbgCallbackBitfieldType & MC_DEBUG_SOURCE_KERNEL));
2353+
//kernel_input.verbose =
2354+
// static_cast<bool>((context_ptr->get_flags() & MC_DEBUG) &&
2355+
// (context_ptr->dbgCallbackBitfieldType & MC_DEBUG_SOURCE_KERNEL));
23402356
kernel_input.require_looped_cutpaths =
23412357
static_cast<bool>(dispatchFlags & MC_DISPATCH_REQUIRE_THROUGH_CUTS);
23422358
kernel_input.populate_vertex_maps =
@@ -2620,8 +2636,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
26202636
numCutMeshVertices,
26212637
numCutMeshFaces,
26222638
multiplier,
2623-
vec3_<double>(0.0) /*srcmesh_cutmesh_com*/,
2624-
vec3_<double>(0.0) /*pre_quantization_translation*/,
2639+
srcmesh_cutmesh_com,
2640+
pre_quantization_translation,
26252641
((cut_mesh_perturbation_count == 0) ? NULL : &perturbation)))
26262642
{
26272643
throw std::invalid_argument("invalid cut-mesh arrays");
@@ -3030,6 +3046,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
30303046

30313047
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
30323048
asFragPtr->multiplier = multiplier;
3049+
asFragPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3050+
asFragPtr->pre_quantization_translation = pre_quantization_translation;
30333051
#endif
30343052

30353053
context_ptr->connected_components.push_front(
@@ -3095,6 +3113,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
30953113

30963114
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
30973115
asFragPtr->multiplier = multiplier;
3116+
asFragPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3117+
asFragPtr->pre_quantization_translation = pre_quantization_translation;
30983118
#endif
30993119

31003120
context_ptr->connected_components.push_front(
@@ -3164,6 +3184,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
31643184

31653185
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
31663186
asPatchPtr->multiplier = multiplier;
3187+
asPatchPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3188+
asPatchPtr->pre_quantization_translation = pre_quantization_translation;
31673189
#endif
31683190
context_ptr->connected_components.push_front(
31693191
cc_ptr); // copy the connected component ptr into the context object
@@ -3229,6 +3251,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
32293251

32303252
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
32313253
asPatchPtr->multiplier = multiplier;
3254+
asPatchPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3255+
asPatchPtr->pre_quantization_translation = pre_quantization_translation;
32323256
#endif
32333257

32343258
context_ptr->connected_components.push_front(
@@ -3300,6 +3324,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
33003324

33013325
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
33023326
asSrcMeshSeamPtr->multiplier = multiplier;
3327+
asSrcMeshSeamPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3328+
asSrcMeshSeamPtr->pre_quantization_translation = pre_quantization_translation;
33033329
#endif
33043330

33053331
context_ptr->connected_components.push_front(
@@ -3365,6 +3391,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
33653391

33663392
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
33673393
asCutMeshSeamPtr->multiplier = multiplier;
3394+
asCutMeshSeamPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3395+
asCutMeshSeamPtr->pre_quantization_translation = pre_quantization_translation;
33683396
#endif
33693397

33703398
context_ptr->connected_components.push_front(
@@ -3498,6 +3526,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
34983526

34993527
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
35003528
asCutMeshInputPtr->multiplier = multiplier;
3529+
asCutMeshInputPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3530+
asCutMeshInputPtr->pre_quantization_translation = pre_quantization_translation;
35013531
#endif
35023532

35033533
context_ptr->connected_components.push_front(
@@ -3622,6 +3652,8 @@ extern "C" void preproc(std::shared_ptr<context_t> context_ptr,
36223652

36233653
#if MCUT_WITH_ARBITRARY_PRECISION_NUMBERS
36243654
asSrcMeshInputPtr->multiplier = multiplier;
3655+
asSrcMeshInputPtr->srcmesh_cutmesh_com = srcmesh_cutmesh_com;
3656+
asSrcMeshInputPtr->pre_quantization_translation = pre_quantization_translation;
36253657
#endif
36263658

36273659
context_ptr->connected_components.push_front(

tests/source/benchmark.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ UTEST_I_TEARDOWN(Benchmark)
103103

104104
UTEST_I(Benchmark, inputID, NUMBER_OF_BENCHMARKS)
105105
{
106+
106107
std::vector<std::pair<std::string, std::string>> benchmarkMeshPairs;
107108

108109
std::stringstream ss;
@@ -138,6 +139,7 @@ UTEST_I(Benchmark, inputID, NUMBER_OF_BENCHMARKS)
138139
&utest_fixture->cutMesh.numVertices,
139140
&utest_fixture->cutMesh.numFaces);
140141

142+
141143
//
142144
// do the cutting
143145
//

0 commit comments

Comments
 (0)