Changeset View
Changeset View
Standalone View
Standalone View
source/blender/bmesh/tools/bmesh_bevel.c
| Show All 14 Lines | |||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup bmesh | * \ingroup bmesh | ||||
| * | * | ||||
| * Main functions for beveling a BMesh (used by the tool and modifier) | * Main functions for beveling a BMesh (used by the tool and modifier) | ||||
| */ | */ | ||||
| #include "CLG_log.h" | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "DNA_curveprofile_types.h" | #include "DNA_curveprofile_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_modifier_types.h" | #include "DNA_modifier_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "BLI_alloca.h" | #include "BLI_alloca.h" | ||||
| Show All 27 Lines | |||||
| #define BEVEL_EPSILON_ANG DEG2RADF(2.0f) | #define BEVEL_EPSILON_ANG DEG2RADF(2.0f) | ||||
| #define BEVEL_SMALL_ANG DEG2RADF(10.0f) | #define BEVEL_SMALL_ANG DEG2RADF(10.0f) | ||||
| /** Difference in dot products that corresponds to 10 degree difference between vectors. */ | /** Difference in dot products that corresponds to 10 degree difference between vectors. */ | ||||
| #define BEVEL_SMALL_ANG_DOT 1 - cosf(BEVEL_SMALL_ANG) | #define BEVEL_SMALL_ANG_DOT 1 - cosf(BEVEL_SMALL_ANG) | ||||
| #define BEVEL_MAX_ADJUST_PCT 10.0f | #define BEVEL_MAX_ADJUST_PCT 10.0f | ||||
| #define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f | #define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f | ||||
| #define BEVEL_MATCH_SPEC_WEIGHT 0.2 | #define BEVEL_MATCH_SPEC_WEIGHT 0.2 | ||||
| //#define DEBUG_CUSTOM_PROFILE_CUTOFF | |||||
| /* Happens far too often, uncomment for development. */ | /* Happens far too often, uncomment for development. */ | ||||
| // #define BEVEL_ASSERT_PROJECT | // #define BEVEL_ASSERT_PROJECT | ||||
| /* for testing */ | /* for testing */ | ||||
| // #pragma GCC diagnostic error "-Wpadded" | // #pragma GCC diagnostic error "-Wpadded" | ||||
| static CLG_LogRef LOG = {"bmesh.bmesh_bevel"}; | |||||
| //#define DEBUG_ADJUST | |||||
| #ifdef DEBUG_ADJUST | |||||
| static CLG_LogRef _LOG_ADJUST = {"bmesh.bmesh_bevel.debug_adjust"}; | |||||
| # define CLOG_ADJUST(log_level, ...) CLOG_VERBOSE(&_LOG_ADJUST, log_level, __VA_ARGS__) | |||||
| #else | |||||
| # define CLOG_ADJUST(log_level, ...) {}(void)0 | |||||
| #endif // DEBUG_ADJUST | |||||
| //#define DEBUG_CUSTOM_PROFILE_CUTOFF | |||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | |||||
| static CLG_LogRef _LOG_CUSTOM_PROFILE_CUTOFF = {"bmesh.bmesh_bevel.debug_custom_profile_cutoff"}; | |||||
| # define CLOG_CUSTOM_PROFILE(log_level, ...) \ | |||||
| CLOG_VERBOSE(&_LOG_CUSTOM_PROFILE_CUTOFF, log_level, __VA_ARGS__) | |||||
| # define CLOG_CUSTOM_PROFILE_V3(log_level, ...) \ | |||||
| CLOG_V3(&_LOG_CUSTOM_PROFILE_CUTOFF, log_level, __VA_ARGS__) | |||||
| #else | |||||
| # define CLOG_CUSTOM_PROFILE(log_level, ...) {}(void)0 | |||||
| # define CLOG_CUSTOM_PROFILE_V3(log_level, ...) {}(void)0 | |||||
| #endif // DEBUG_CUSTOM_PROFILE_CUTOFF | |||||
| /* Constructed vertex, sometimes later instantiated as BMVert. */ | /* Constructed vertex, sometimes later instantiated as BMVert. */ | ||||
| typedef struct NewVert { | typedef struct NewVert { | ||||
| BMVert *v; | BMVert *v; | ||||
| float co[3]; | float co[3]; | ||||
| char _pad[4]; | char _pad[4]; | ||||
| } NewVert; | } NewVert; | ||||
| struct BoundVert; | struct BoundVert; | ||||
| ▲ Show 20 Lines • Show All 2,233 Lines • ▼ Show 20 Lines | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| } | } | ||||
| else if (fprevkind == F_RECON && BM_elem_flag_test(l, BM_ELEM_LONG_TAG)) { | else if (fprevkind == F_RECON && BM_elem_flag_test(l, BM_ELEM_LONG_TAG)) { | ||||
| pnorm = lprev->f->no; | pnorm = lprev->f->no; | ||||
| } | } | ||||
| else if (fnextkind == F_RECON && BM_elem_flag_test(l->prev, BM_ELEM_LONG_TAG)) { | else if (fnextkind == F_RECON && BM_elem_flag_test(l->prev, BM_ELEM_LONG_TAG)) { | ||||
| pnorm = lnext->f->no; | pnorm = lnext->f->no; | ||||
| } | } | ||||
| else { | else { | ||||
| /* printf("unexpected harden case (edge)\n"); */ | CLOG_ERROR(&LOG, "unexpected harden case (edge)"); | ||||
| } | } | ||||
| } | } | ||||
| else if (fkind == F_VERT) { | else if (fkind == F_VERT) { | ||||
| if (fprevkind == F_VERT && fnextkind == F_VERT) { | if (fprevkind == F_VERT && fnextkind == F_VERT) { | ||||
| pnorm = l->v->no; | pnorm = l->v->no; | ||||
| } | } | ||||
| else if (fprevkind == F_RECON) { | else if (fprevkind == F_RECON) { | ||||
| pnorm = lprev->f->no; | pnorm = lprev->f->no; | ||||
| Show All 26 Lines | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| add_v3_v3v3(norm, lprev->f->no, lprevprev->f->no); | add_v3_v3v3(norm, lprev->f->no, lprevprev->f->no); | ||||
| pnorm = norm; | pnorm = norm; | ||||
| } | } | ||||
| else if (fnextkind == F_EDGE && fprevkind == F_VERT && fnextnextkind == F_EDGE) { | else if (fnextkind == F_EDGE && fprevkind == F_VERT && fnextnextkind == F_EDGE) { | ||||
| add_v3_v3v3(norm, lnext->f->no, lnextnext->f->no); | add_v3_v3v3(norm, lnext->f->no, lnextnext->f->no); | ||||
| pnorm = norm; | pnorm = norm; | ||||
| } | } | ||||
| else { | else { | ||||
| /* printf("unexpected harden case (vert)\n"); */ | CLOG_ERROR(&LOG, "unexpected harden case (vert)"); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (pnorm) { | if (pnorm) { | ||||
| if (pnorm == norm) { | if (pnorm == norm) { | ||||
| normalize_v3(norm); | normalize_v3(norm); | ||||
| } | } | ||||
| int l_index = BM_elem_index_get(l); | int l_index = BM_elem_index_get(l); | ||||
| ▲ Show 20 Lines • Show All 622 Lines • ▼ Show 20 Lines | else { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #ifdef DEBUG_ADJUST | #ifdef DEBUG_ADJUST | ||||
| static void print_adjust_stats(BoundVert *vstart) | static void print_adjust_stats(BoundVert *vstart) | ||||
| { | { | ||||
| printf("\nSolution analysis\n"); | CLOG_ADJUST(1, "Solution analysis"); | ||||
| double even_residual2 = 0.0; | double even_residual2 = 0.0; | ||||
| double spec_residual2 = 0.0; | double spec_residual2 = 0.0; | ||||
| double max_even_r = 0.0; | double max_even_r = 0.0; | ||||
| double max_even_r_pct = 0.0; | double max_even_r_pct = 0.0; | ||||
| double max_spec_r = 0.0; | double max_spec_r = 0.0; | ||||
| double max_spec_r_pct = 0.0; | double max_spec_r_pct = 0.0; | ||||
| printf("width matching\n"); | CLOG_ADJUST(1, "width matching"); | ||||
| BoundVert *v = vstart; | BoundVert *v = vstart; | ||||
| do { | do { | ||||
| if (v->adjchain != NULL) { | if (v->adjchain != NULL) { | ||||
| EdgeHalf *eright = v->efirst; | EdgeHalf *eright = v->efirst; | ||||
| EdgeHalf *eleft = v->adjchain->elast; | EdgeHalf *eleft = v->adjchain->elast; | ||||
| double delta = fabs(eright->offset_r - eleft->offset_l); | double delta = fabs(eright->offset_r - eleft->offset_l); | ||||
| double delta_pct = 100.0 * delta / eright->offset_r_spec; | double delta_pct = 100.0 * delta / eright->offset_r_spec; | ||||
| printf("e%d r(%f) vs l(%f): abs(delta)=%f, delta_pct=%f\n", | CLOG_ADJUST(1, | ||||
| "e%d r(%f) vs l(%f): abs(delta)=%f, delta_pct=%f\n", | |||||
| BM_elem_index_get(eright->e), | BM_elem_index_get(eright->e), | ||||
| eright->offset_r, | eright->offset_r, | ||||
| eleft->offset_l, | eleft->offset_l, | ||||
| delta, | delta, | ||||
| delta_pct); | delta_pct); | ||||
| even_residual2 += delta * delta; | even_residual2 += delta * delta; | ||||
| if (delta > max_even_r) { | if (delta > max_even_r) { | ||||
| max_even_r = delta; | max_even_r = delta; | ||||
| } | } | ||||
| if (delta_pct > max_even_r_pct) { | if (delta_pct > max_even_r_pct) { | ||||
| max_even_r_pct = delta_pct; | max_even_r_pct = delta_pct; | ||||
| } | } | ||||
| } | } | ||||
| v = v->adjchain; | v = v->adjchain; | ||||
| } while (v && v != vstart); | } while (v && v != vstart); | ||||
| printf("spec matching\n"); | CLOG_ADJUST(2, "spec matching"); | ||||
| v = vstart; | v = vstart; | ||||
| do { | do { | ||||
| if (v->adjchain != NULL) { | if (v->adjchain != NULL) { | ||||
| EdgeHalf *eright = v->efirst; | EdgeHalf *eright = v->efirst; | ||||
| EdgeHalf *eleft = v->adjchain->elast; | EdgeHalf *eleft = v->adjchain->elast; | ||||
| double delta = eright->offset_r - eright->offset_r_spec; | double delta = eright->offset_r - eright->offset_r_spec; | ||||
| double delta_pct = 100.0 * delta / eright->offset_r_spec; | double delta_pct = 100.0 * delta / eright->offset_r_spec; | ||||
| printf("e%d r(%f) vs r spec(%f): delta=%f, delta_pct=%f\n", | CLOG_ADJUST(2, | ||||
| "e%d r(%f) vs r spec(%f): delta=%f, delta_pct=%f", | |||||
| BM_elem_index_get(eright->e), | BM_elem_index_get(eright->e), | ||||
| eright->offset_r, | eright->offset_r, | ||||
| eright->offset_r_spec, | eright->offset_r_spec, | ||||
| delta, | delta, | ||||
| delta_pct); | delta_pct); | ||||
| spec_residual2 += delta * delta; | spec_residual2 += delta * delta; | ||||
| delta = fabs(delta); | delta = fabs(delta); | ||||
| delta_pct = fabs(delta_pct); | delta_pct = fabs(delta_pct); | ||||
| if (delta > max_spec_r) { | if (delta > max_spec_r) { | ||||
| max_spec_r = delta; | max_spec_r = delta; | ||||
| } | } | ||||
| if (delta_pct > max_spec_r_pct) { | if (delta_pct > max_spec_r_pct) { | ||||
| max_spec_r_pct = delta_pct; | max_spec_r_pct = delta_pct; | ||||
| } | } | ||||
| delta = eleft->offset_l - eleft->offset_l_spec; | delta = eleft->offset_l - eleft->offset_l_spec; | ||||
| delta_pct = 100.0 * delta / eright->offset_l_spec; | delta_pct = 100.0 * delta / eright->offset_l_spec; | ||||
| printf("e%d l(%f) vs l spec(%f): delta=%f, delta_pct=%f\n", | CLOG_ADJUST(2, | ||||
| "e%d l(%f) vs l spec(%f): delta=%f, delta_pct=%f", | |||||
| BM_elem_index_get(eright->e), | BM_elem_index_get(eright->e), | ||||
| eleft->offset_l, | eleft->offset_l, | ||||
| eleft->offset_l_spec, | eleft->offset_l_spec, | ||||
| delta, | delta, | ||||
| delta_pct); | delta_pct); | ||||
| spec_residual2 += delta * delta; | spec_residual2 += delta * delta; | ||||
| delta = fabs(delta); | delta = fabs(delta); | ||||
| delta_pct = fabs(delta_pct); | delta_pct = fabs(delta_pct); | ||||
| if (delta > max_spec_r) { | if (delta > max_spec_r) { | ||||
| max_spec_r = delta; | max_spec_r = delta; | ||||
| } | } | ||||
| if (delta_pct > max_spec_r_pct) { | if (delta_pct > max_spec_r_pct) { | ||||
| max_spec_r_pct = delta_pct; | max_spec_r_pct = delta_pct; | ||||
| } | } | ||||
| } | } | ||||
| v = v->adjchain; | v = v->adjchain; | ||||
| } while (v && v != vstart); | } while (v && v != vstart); | ||||
| printf("Analysis Result:\n"); | CLOG_ADJUST(1, | ||||
| printf("even residual2 = %f, spec residual2 = %f\n", even_residual2, spec_residual2); | "Analysis Result:\n" | ||||
| printf("max even delta = %f, max as percent of spec = %f\n", max_even_r, max_even_r_pct); | "even residual2 = %f, spec residual2 = %f\n" | ||||
| printf("max spec delta = %f, max as percent of spec = %f\n", max_spec_r, max_spec_r_pct); | "max even delta = %f, max as percent of spec = %f\n" | ||||
| "max spec delta = %f, max as percent of spec = %f", | |||||
| even_residual2, | |||||
| spec_residual2, | |||||
| max_even_r, | |||||
| max_even_r_pct, | |||||
| max_spec_r, | |||||
| max_spec_r_pct); | |||||
| } | } | ||||
| #endif | #endif | ||||
| #ifdef FAST_ADJUST_CODE | #ifdef FAST_ADJUST_CODE | ||||
| /* This code uses a direct solution to the adjustment problem for chains and certain cycles. | /* This code uses a direct solution to the adjustment problem for chains and certain cycles. | ||||
| * It is a two-step approach: first solve for the exact solution of the 'match widths' constraints | * It is a two-step approach: first solve for the exact solution of the 'match widths' constraints | ||||
| * using the one degree of freedom that allows for expressing all other widths in terms of that. | * using the one degree of freedom that allows for expressing all other widths in terms of that. | ||||
| * And then minimize the spec-matching constraints using the derivative of the least squares | * And then minimize the spec-matching constraints using the derivative of the least squares | ||||
| ▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | |||||
| * Otherwise, we set up and solve a linear least squares problem | * Otherwise, we set up and solve a linear least squares problem | ||||
| * that tries to minimize the squared differences of lengths | * that tries to minimize the squared differences of lengths | ||||
| * at each end of an edge, and (with smaller weight) the | * at each end of an edge, and (with smaller weight) the | ||||
| * squared differences of the offsets from their specs. | * squared differences of the offsets from their specs. | ||||
| */ | */ | ||||
| static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) | static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) | ||||
| { | { | ||||
| int np = 0; | int np = 0; | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, "adjust the %s (with eigen)", iscycle ? "cycle" : "chain"); | ||||
| printf("\nadjust the %s (with eigen)\n", iscycle ? "cycle" : "chain"); | |||||
| #endif | |||||
| BoundVert *v = vstart; | BoundVert *v = vstart; | ||||
| do { | do { | ||||
| #ifdef DEBUG_ADJUST | #ifdef DEBUG_ADJUST | ||||
| eleft = v->elast; | eleft = v->elast; | ||||
| eright = v->efirst; | eright = v->efirst; | ||||
| printf(" (left=e%d, right=e%d)", BM_elem_index_get(eleft->e), BM_elem_index_get(eright->e)); | CLOG_ADJUST( | ||||
| 1, " (left=e%d, right=e%d)", BM_elem_index_get(eleft->e), BM_elem_index_get(eright->e)); | |||||
| #endif | #endif | ||||
| np++; | np++; | ||||
| v = v->adjchain; | v = v->adjchain; | ||||
| } while (v && v != vstart); | } while (v && v != vstart); | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, " -> %d parms", np); | ||||
| printf(" -> %d parms\n", np); | |||||
| #endif | |||||
| #ifdef FAST_ADJUST_CODE | #ifdef FAST_ADJUST_CODE | ||||
| if (adjust_the_cycle_or_chain_fast(vstart, np, iscycle)) { | if (adjust_the_cycle_or_chain_fast(vstart, np, iscycle)) { | ||||
| return; | return; | ||||
| } | } | ||||
| #endif | #endif | ||||
| int nrows = iscycle ? 3 * np : 3 * np - 3; | int nrows = iscycle ? 3 * np : 3 * np - 3; | ||||
| LinearSolver *solver = EIG_linear_least_squares_solver_new(nrows, np, 1); | LinearSolver *solver = EIG_linear_least_squares_solver_new(nrows, np, 1); | ||||
| v = vstart; | v = vstart; | ||||
| int i = 0; | int i = 0; | ||||
| /* Sqrt of factor to weight down importance of spec match. */ | /* Sqrt of factor to weight down importance of spec match. */ | ||||
| double weight = BEVEL_MATCH_SPEC_WEIGHT; | double weight = BEVEL_MATCH_SPEC_WEIGHT; | ||||
| EdgeHalf *eleft, *eright, *enextleft; | EdgeHalf *eleft, *eright, *enextleft; | ||||
| do { | do { | ||||
| /* Except at end of chain, v's indep variable is offset_r of v->efirst. */ | /* Except at end of chain, v's indep variable is offset_r of v->efirst. */ | ||||
| if (iscycle || i < np - 1) { | if (iscycle || i < np - 1) { | ||||
| eright = v->efirst; | eright = v->efirst; | ||||
| eleft = v->elast; | eleft = v->elast; | ||||
| enextleft = v->adjchain->elast; | enextleft = v->adjchain->elast; | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, "p%d: e%d->offset_r = %f", i, BM_elem_index_get(eright->e), eright->offset_r); | ||||
| printf("p%d: e%d->offset_r = %f\n", i, BM_elem_index_get(eright->e), eright->offset_r); | |||||
| if (iscycle || v != vstart) { | if (iscycle || v != vstart) { | ||||
| printf(" dependent: e%d->offset_l = %f * p%d\n", | CLOG_ADJUST(1, | ||||
| " dependent: e%d->offset_l = %f * p%d", | |||||
| BM_elem_index_get(eleft->e), | BM_elem_index_get(eleft->e), | ||||
| v->sinratio, | v->sinratio, | ||||
| i); | i); | ||||
| } | } | ||||
| #endif | |||||
| /* Residue i: width difference between eright and eleft of next. */ | /* Residue i: width difference between eright and eleft of next. */ | ||||
| EIG_linear_solver_matrix_add(solver, i, i, 1.0); | EIG_linear_solver_matrix_add(solver, i, i, 1.0); | ||||
| EIG_linear_solver_right_hand_side_add(solver, 0, i, 0.0); | EIG_linear_solver_right_hand_side_add(solver, 0, i, 0.0); | ||||
| if (iscycle) { | if (iscycle) { | ||||
| EIG_linear_solver_matrix_add(solver, i > 0 ? i - 1 : np - 1, i, -v->sinratio); | EIG_linear_solver_matrix_add(solver, i > 0 ? i - 1 : np - 1, i, -v->sinratio); | ||||
| } | } | ||||
| else { | else { | ||||
| if (i > 0) { | if (i > 0) { | ||||
| EIG_linear_solver_matrix_add(solver, i - 1, i, -v->sinratio); | EIG_linear_solver_matrix_add(solver, i - 1, i, -v->sinratio); | ||||
| } | } | ||||
| } | } | ||||
| /* Residue np + 2*i (if cycle) else np - 1 + 2*i: | /* Residue np + 2*i (if cycle) else np - 1 + 2*i: | ||||
| * right offset for parm i matches its spec; weighted. */ | * right offset for parm i matches its spec; weighted. */ | ||||
| int row = iscycle ? np + 2 * i : np - 1 + 2 * i; | int row = iscycle ? np + 2 * i : np - 1 + 2 * i; | ||||
| EIG_linear_solver_matrix_add(solver, row, i, weight); | EIG_linear_solver_matrix_add(solver, row, i, weight); | ||||
| EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eright->offset_r); | EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eright->offset_r); | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, | ||||
| printf("b[%d]=%f * %f, for e%d->offset_r\n", | "b[%d]=%f * %f, for e%d->offset_r", | ||||
| row, | row, | ||||
| weight, | weight, | ||||
| eright->offset_r, | eright->offset_r, | ||||
| BM_elem_index_get(eright->e)); | BM_elem_index_get(eright->e)); | ||||
| #endif | |||||
| /* Residue np + 2*i + 1 (if cycle) else np - 1 + 2*i + 1: | /* Residue np + 2*i + 1 (if cycle) else np - 1 + 2*i + 1: | ||||
| * left offset for parm i matches its spec; weighted. */ | * left offset for parm i matches its spec; weighted. */ | ||||
| row = row + 1; | row = row + 1; | ||||
| EIG_linear_solver_matrix_add( | EIG_linear_solver_matrix_add( | ||||
| solver, row, (i == np - 1) ? 0 : i + 1, weight * v->adjchain->sinratio); | solver, row, (i == np - 1) ? 0 : i + 1, weight * v->adjchain->sinratio); | ||||
| EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * enextleft->offset_l); | EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * enextleft->offset_l); | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, | ||||
| printf("b[%d]=%f * %f, for e%d->offset_l\n", | "b[%d]=%f * %f, for e%d->offset_l", | ||||
| row, | row, | ||||
| weight, | weight, | ||||
| enextleft->offset_l, | enextleft->offset_l, | ||||
| BM_elem_index_get(enextleft->e)); | BM_elem_index_get(enextleft->e)); | ||||
| #endif | |||||
| } | } | ||||
| else { | else { | ||||
| /* Not a cycle, and last of chain. */ | /* Not a cycle, and last of chain. */ | ||||
| eleft = v->elast; | eleft = v->elast; | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, "p%d: e%d->offset_l = %f", i, BM_elem_index_get(eleft->e), eleft->offset_l); | ||||
| printf("p%d: e%d->offset_l = %f\n", i, BM_elem_index_get(eleft->e), eleft->offset_l); | |||||
| #endif | |||||
| /* Second part of residue i for last i. */ | /* Second part of residue i for last i. */ | ||||
| EIG_linear_solver_matrix_add(solver, i - 1, i, -1.0); | EIG_linear_solver_matrix_add(solver, i - 1, i, -1.0); | ||||
| } | } | ||||
| i++; | i++; | ||||
| v = v->adjchain; | v = v->adjchain; | ||||
| } while (v && v != vstart); | } while (v && v != vstart); | ||||
| EIG_linear_solver_solve(solver); | EIG_linear_solver_solve(solver); | ||||
| #ifdef DEBUG_ADJUST | #ifdef DEBUG_ADJUST | ||||
| /* Note: this print only works after solve, but by that time b has been cleared. */ | /* Note: this print only works after solve, but by that time b has been cleared. */ | ||||
| EIG_linear_solver_print_matrix(solver); | EIG_linear_solver_print_matrix(solver); | ||||
| printf("\nSolution:\n"); | CLOG_ADJUST(1, "Solution:"); | ||||
| for (i = 0; i < np; i++) { | for (i = 0; i < np; i++) { | ||||
| printf("p%d = %f\n", i, EIG_linear_solver_variable_get(solver, 0, i)); | CLOG_ADJUST(1, "p%d = %f", i, EIG_linear_solver_variable_get(solver, 0, i)); | ||||
| } | } | ||||
| #endif | #endif | ||||
| /* Use the solution to set new widths. */ | /* Use the solution to set new widths. */ | ||||
| v = vstart; | v = vstart; | ||||
| i = 0; | i = 0; | ||||
| do { | do { | ||||
| double val = EIG_linear_solver_variable_get(solver, 0, i); | double val = EIG_linear_solver_variable_get(solver, 0, i); | ||||
| if (iscycle || i < np - 1) { | if (iscycle || i < np - 1) { | ||||
| eright = v->efirst; | eright = v->efirst; | ||||
| eleft = v->elast; | eleft = v->elast; | ||||
| eright->offset_r = (float)val; | eright->offset_r = (float)val; | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, "e%d->offset_r = %f", BM_elem_index_get(eright->e), eright->offset_r); | ||||
| printf("e%d->offset_r = %f\n", BM_elem_index_get(eright->e), eright->offset_r); | |||||
| #endif | |||||
| if (iscycle || v != vstart) { | if (iscycle || v != vstart) { | ||||
| eleft->offset_l = (float)(v->sinratio * val); | eleft->offset_l = (float)(v->sinratio * val); | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, "e%d->offset_l = %f", BM_elem_index_get(eleft->e), eleft->offset_l); | ||||
| printf("e%d->offset_l = %f\n", BM_elem_index_get(eleft->e), eleft->offset_l); | |||||
| #endif | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* Not a cycle, and last of chain. */ | /* Not a cycle, and last of chain. */ | ||||
| eleft = v->elast; | eleft = v->elast; | ||||
| eleft->offset_l = (float)val; | eleft->offset_l = (float)val; | ||||
| #ifdef DEBUG_ADJUST | CLOG_ADJUST(1, "e%d->offset_l = %f", BM_elem_index_get(eleft->e), eleft->offset_l); | ||||
| printf("e%d->offset_l = %f\n", BM_elem_index_get(eleft->e), eleft->offset_l); | |||||
| #endif | |||||
| } | } | ||||
| i++; | i++; | ||||
| v = v->adjchain; | v = v->adjchain; | ||||
| } while (v && v != vstart); | } while (v && v != vstart); | ||||
| #ifdef DEBUG_ADJUST | #ifdef DEBUG_ADJUST | ||||
| print_adjust_stats(vstart); | print_adjust_stats(vstart); | ||||
| EIG_linear_solver_print_matrix(solver); | EIG_linear_solver_print_matrix(solver); | ||||
| ▲ Show 20 Lines • Show All 1,690 Lines • ▼ Show 20 Lines | |||||
| * are two problems currently: | * are two problems currently: | ||||
| * - Miter profiles don't have plane_no filled, so down direction is incorrect. | * - Miter profiles don't have plane_no filled, so down direction is incorrect. | ||||
| * - Indexing profile points of miters with (i, 0, k) seems to return zero except for the first | * - Indexing profile points of miters with (i, 0, k) seems to return zero except for the first | ||||
| * and last profile point. | * and last profile point. | ||||
| * TODO(Hans): Use repface / edge arrays for UV interpolation properly. | * TODO(Hans): Use repface / edge arrays for UV interpolation properly. | ||||
| */ | */ | ||||
| static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) | static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) | ||||
| { | { | ||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | CLOG_CUSTOM_PROFILE(1, "BEVEL BUILD CUTOFF"); | ||||
| printf("BEVEL BUILD CUTOFF\n"); | |||||
| # define F3(v) (v)[0], (v)[1], (v)[2] | |||||
| #endif | |||||
| int n_bndv = bv->vmesh->count; | int n_bndv = bv->vmesh->count; | ||||
| /* Find the locations for the corner vertices at the bottom of the cutoff faces. */ | /* Find the locations for the corner vertices at the bottom of the cutoff faces. */ | ||||
| BoundVert *bndv = bv->vmesh->boundstart; | BoundVert *bndv = bv->vmesh->boundstart; | ||||
| do { | do { | ||||
| int i = bndv->index; | int i = bndv->index; | ||||
| /* Find the "down" direction for this side of the cutoff face. */ | /* Find the "down" direction for this side of the cutoff face. */ | ||||
| Show All 12 Lines | do { | ||||
| madd_v3_v3v3fl(new_vert, bndv->nv.co, down_direction, length); | madd_v3_v3v3fl(new_vert, bndv->nv.co, down_direction, length); | ||||
| /* Use this location for this profile's first corner vert and the last profile's second. */ | /* Use this location for this profile's first corner vert and the last profile's second. */ | ||||
| copy_v3_v3(mesh_vert(bv->vmesh, i, 1, 0)->co, new_vert); | copy_v3_v3(mesh_vert(bv->vmesh, i, 1, 0)->co, new_vert); | ||||
| copy_v3_v3(mesh_vert(bv->vmesh, bndv->prev->index, 1, 1)->co, new_vert); | copy_v3_v3(mesh_vert(bv->vmesh, bndv->prev->index, 1, 1)->co, new_vert); | ||||
| } while ((bndv = bndv->next) != bv->vmesh->boundstart); | } while ((bndv = bndv->next) != bv->vmesh->boundstart); | ||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | |||||
| printf("Corner vertices:\n"); | |||||
| for (int j = 0; j < n_bndv; j++) { | for (int j = 0; j < n_bndv; j++) { | ||||
| printf(" (%.3f, %.3f, %.3f)\n", F3(mesh_vert(bv->vmesh, j, 1, 0)->co)); | CLOG_CUSTOM_PROFILE_V3(1, "Corner vertices", mesh_vert(bv->vmesh, j, 1, 0)->co); | ||||
| } | } | ||||
| #endif | |||||
| /* Disable the center face if the corner vertices share the same location. */ | /* Disable the center face if the corner vertices share the same location. */ | ||||
| bool build_center_face = true; | bool build_center_face = true; | ||||
| if (n_bndv == 3) { /* Vertices only collapse with a 3-way VMesh. */ | if (n_bndv == 3) { /* Vertices only collapse with a 3-way VMesh. */ | ||||
| build_center_face &= len_squared_v3v3(mesh_vert(bv->vmesh, 0, 1, 0)->co, | build_center_face &= len_squared_v3v3(mesh_vert(bv->vmesh, 0, 1, 0)->co, | ||||
| mesh_vert(bv->vmesh, 1, 1, 0)->co) > BEVEL_EPSILON; | mesh_vert(bv->vmesh, 1, 1, 0)->co) > BEVEL_EPSILON; | ||||
| build_center_face &= len_squared_v3v3(mesh_vert(bv->vmesh, 0, 1, 0)->co, | build_center_face &= len_squared_v3v3(mesh_vert(bv->vmesh, 0, 1, 0)->co, | ||||
| mesh_vert(bv->vmesh, 2, 1, 0)->co) > BEVEL_EPSILON; | mesh_vert(bv->vmesh, 2, 1, 0)->co) > BEVEL_EPSILON; | ||||
| build_center_face &= len_squared_v3v3(mesh_vert(bv->vmesh, 1, 1, 0)->co, | build_center_face &= len_squared_v3v3(mesh_vert(bv->vmesh, 1, 1, 0)->co, | ||||
| mesh_vert(bv->vmesh, 2, 1, 0)->co) > BEVEL_EPSILON; | mesh_vert(bv->vmesh, 2, 1, 0)->co) > BEVEL_EPSILON; | ||||
| } | } | ||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | CLOG_CUSTOM_PROFILE(1, "build_center_face: %d", build_center_face); | ||||
| printf("build_center_face: %d\n", build_center_face); | |||||
| #endif | |||||
| /* Create the corner vertex BMVerts. */ | /* Create the corner vertex BMVerts. */ | ||||
| if (build_center_face) { | if (build_center_face) { | ||||
| do { | do { | ||||
| int i = bndv->index; | int i = bndv->index; | ||||
| create_mesh_bmvert(bm, bv->vmesh, i, 1, 0, bv->v); | create_mesh_bmvert(bm, bv->vmesh, i, 1, 0, bv->v); | ||||
| /* The second corner vertex for the previous profile shares this BMVert. */ | /* The second corner vertex for the previous profile shares this BMVert. */ | ||||
| mesh_vert(bv->vmesh, bndv->prev->index, 1, 1)->v = mesh_vert(bv->vmesh, i, 1, 0)->v; | mesh_vert(bv->vmesh, bndv->prev->index, 1, 1)->v = mesh_vert(bv->vmesh, i, 1, 0)->v; | ||||
| } while ((bndv = bndv->next) != bv->vmesh->boundstart); | } while ((bndv = bndv->next) != bv->vmesh->boundstart); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Use the same BMVert for all of the corner vertices. */ | /* Use the same BMVert for all of the corner vertices. */ | ||||
| create_mesh_bmvert(bm, bv->vmesh, 0, 1, 0, bv->v); | create_mesh_bmvert(bm, bv->vmesh, 0, 1, 0, bv->v); | ||||
| for (int i = 1; i < n_bndv; i++) { | for (int i = 1; i < n_bndv; i++) { | ||||
| mesh_vert(bv->vmesh, i, 1, 0)->v = mesh_vert(bv->vmesh, 0, 1, 0)->v; | mesh_vert(bv->vmesh, i, 1, 0)->v = mesh_vert(bv->vmesh, 0, 1, 0)->v; | ||||
| } | } | ||||
| } | } | ||||
| /* Build the profile cutoff faces. */ | /* Build the profile cutoff faces. */ | ||||
| /* Extra one or two for corner vertices and one for last point along profile, or the size of the | /* Extra one or two for corner vertices and one for last point along profile, or the size of the | ||||
| * center face array if it's bigger. */ | * center face array if it's bigger. */ | ||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | CLOG_CUSTOM_PROFILE(1, "Building profile cutoff faces."); | ||||
| printf("Building profile cutoff faces.\n"); | |||||
| #endif | |||||
| BMVert **face_bmverts = BLI_memarena_alloc( | BMVert **face_bmverts = BLI_memarena_alloc( | ||||
| bp->mem_arena, sizeof(BMVert *) * max_ii(bp->seg + 2 + build_center_face, n_bndv)); | bp->mem_arena, sizeof(BMVert *) * max_ii(bp->seg + 2 + build_center_face, n_bndv)); | ||||
| bndv = bv->vmesh->boundstart; | bndv = bv->vmesh->boundstart; | ||||
| do { | do { | ||||
| int i = bndv->index; | int i = bndv->index; | ||||
| BMEdge **bmedges = NULL; | BMEdge **bmedges = NULL; | ||||
| BMFace **bmfaces = NULL; | BMFace **bmfaces = NULL; | ||||
| BLI_array_staticdeclare(bmedges, BM_DEFAULT_NGON_STACK_SIZE); | BLI_array_staticdeclare(bmedges, BM_DEFAULT_NGON_STACK_SIZE); | ||||
| BLI_array_staticdeclare(bmfaces, BM_DEFAULT_NGON_STACK_SIZE); | BLI_array_staticdeclare(bmfaces, BM_DEFAULT_NGON_STACK_SIZE); | ||||
| /* Add the first corner vertex under this boundvert. */ | /* Add the first corner vertex under this boundvert. */ | ||||
| face_bmverts[0] = mesh_vert(bv->vmesh, i, 1, 0)->v; | face_bmverts[0] = mesh_vert(bv->vmesh, i, 1, 0)->v; | ||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | CLOG_CUSTOM_PROFILE(1, "Profile Number %d:", i); | ||||
| printf("Profile Number %d:\n", i); | |||||
| if (bndv->is_patch_start || bndv->is_arc_start) { | if (bndv->is_patch_start || bndv->is_arc_start) { | ||||
| printf(" Miter profile\n"); | CLOG_CUSTOM_PROFILE(1, " Miter profile"); | ||||
| } | } | ||||
| printf(" Corner 1: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 0)->co)); | CLOG_CUSTOM_PROFILE_V3(1, " Corner 1", mesh_vert(bv->vmesh, i, 1, 0)->co); | ||||
| #endif | |||||
| /* Add profile point vertices to the face, including the last one. */ | /* Add profile point vertices to the face, including the last one. */ | ||||
| for (int k = 0; k < bp->seg + 1; k++) { | for (int k = 0; k < bp->seg + 1; k++) { | ||||
| face_bmverts[k + 1] = mesh_vert(bv->vmesh, i, 0, k)->v; /* Leave room for first vert. */ | face_bmverts[k + 1] = mesh_vert(bv->vmesh, i, 0, k)->v; /* Leave room for first vert. */ | ||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | CLOG_CUSTOM_PROFILE(1, " Profile %d", k); | ||||
| printf(" Profile %d: (%0.3f, %0.3f, %0.3f)\n", k, F3(mesh_vert(bv->vmesh, i, 0, k)->co)); | CLOG_CUSTOM_PROFILE_V3(1, " Coordinates", mesh_vert(bv->vmesh, i, 0, k)->co); | ||||
| #endif | |||||
| } | } | ||||
| /* Add the second corner vert to complete the bottom of the face. */ | /* Add the second corner vert to complete the bottom of the face. */ | ||||
| if (build_center_face) { | if (build_center_face) { | ||||
| face_bmverts[bp->seg + 2] = mesh_vert(bv->vmesh, i, 1, 1)->v; | face_bmverts[bp->seg + 2] = mesh_vert(bv->vmesh, i, 1, 1)->v; | ||||
| #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF | CLOG_CUSTOM_PROFILE_V3(1, " Corner 2", mesh_vert(bv->vmesh, i, 1, 1)->co); | ||||
| printf(" Corner 2: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 1)->co)); | |||||
| #endif | |||||
| } | } | ||||
| /* Create the profile cutoff face for this boundvert. */ | /* Create the profile cutoff face for this boundvert. */ | ||||
| /* repface = boundvert_rep_face(bndv, NULL); */ | /* repface = boundvert_rep_face(bndv, NULL); */ | ||||
| bev_create_ngon(bm, | bev_create_ngon(bm, | ||||
| face_bmverts, | face_bmverts, | ||||
| bp->seg + 2 + build_center_face, | bp->seg + 2 + build_center_face, | ||||
| bmfaces, | bmfaces, | ||||
| ▲ Show 20 Lines • Show All 2,200 Lines • Show Last 20 Lines | |||||