Tweaks in generation of rendering geometry for preview toolpaths. Fixes #240 and #348

This commit is contained in:
Enrico Turri 2018-04-17 15:04:14 +02:00
parent d7dc04eb57
commit 3bedcf4413

View File

@ -788,15 +788,14 @@ static void thick_lines_to_indexed_vertex_array(
#define TOP 2 #define TOP 2
#define BOTTOM 3 #define BOTTOM 3
Line prev_line;
// right, left, top, bottom // right, left, top, bottom
int idx_prev[4] = { -1, -1, -1, -1 }; int idx_prev[4] = { -1, -1, -1, -1 };
double bottom_z_prev = 0.; double bottom_z_prev = 0.;
Pointf b1_prev; Pointf b1_prev;
Pointf b2_prev;
Vectorf v_prev; Vectorf v_prev;
int idx_initial[4] = { -1, -1, -1, -1 }; int idx_initial[4] = { -1, -1, -1, -1 };
double width_initial = 0.; double width_initial = 0.;
double bottom_z_initial = 0.0;
// loop once more in case of closed loops // loop once more in case of closed loops
size_t lines_end = closed ? (lines.size() + 1) : lines.size(); size_t lines_end = closed ? (lines.size() + 1) : lines.size();
@ -804,12 +803,17 @@ static void thick_lines_to_indexed_vertex_array(
size_t i = (ii == lines.size()) ? 0 : ii; size_t i = (ii == lines.size()) ? 0 : ii;
const Line &line = lines[i]; const Line &line = lines[i];
double len = unscale(line.length()); double len = unscale(line.length());
double inv_len = 1.0 / len;
double bottom_z = top_z - heights[i]; double bottom_z = top_z - heights[i];
double middle_z = (top_z + bottom_z) / 2.; double middle_z = 0.5 * (top_z + bottom_z);
double width = widths[i]; double width = widths[i];
bool is_first = (ii == 0);
bool is_last = (ii == lines_end - 1);
bool is_closing = closed && is_last;
Vectorf v = Vectorf::new_unscale(line.vector()); Vectorf v = Vectorf::new_unscale(line.vector());
v.scale(1. / len); v.scale(inv_len);
Pointf a = Pointf::new_unscale(line.a); Pointf a = Pointf::new_unscale(line.a);
Pointf b = Pointf::new_unscale(line.b); Pointf b = Pointf::new_unscale(line.b);
@ -818,17 +822,19 @@ static void thick_lines_to_indexed_vertex_array(
Pointf b1 = b; Pointf b1 = b;
Pointf b2 = b; Pointf b2 = b;
{ {
double dist = width / 2.; // scaled double dist = 0.5 * width; // scaled
a1.translate(+dist*v.y, -dist*v.x); double dx = dist * v.x;
a2.translate(-dist*v.y, +dist*v.x); double dy = dist * v.y;
b1.translate(+dist*v.y, -dist*v.x); a1.translate(+dy, -dx);
b2.translate(-dist*v.y, +dist*v.x); a2.translate(-dy, +dx);
b1.translate(+dy, -dx);
b2.translate(-dy, +dx);
} }
// calculate new XY normals // calculate new XY normals
Vector n = line.normal(); Vector n = line.normal();
Vectorf3 xy_right_normal = Vectorf3::new_unscale(n.x, n.y, 0); Vectorf3 xy_right_normal = Vectorf3::new_unscale(n.x, n.y, 0);
xy_right_normal.scale(1.f / len); xy_right_normal.scale(inv_len);
int idx_a[4]; int idx_a[4];
int idx_b[4]; int idx_b[4];
@ -837,14 +843,21 @@ static void thick_lines_to_indexed_vertex_array(
bool bottom_z_different = bottom_z_prev != bottom_z; bool bottom_z_different = bottom_z_prev != bottom_z;
bottom_z_prev = bottom_z; bottom_z_prev = bottom_z;
if (!is_first && bottom_z_different)
{
// Found a change of the layer thickness -> Add a cap at the end of the previous segment.
volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]);
}
// Share top / bottom vertices if possible. // Share top / bottom vertices if possible.
if (ii == 0) { if (is_first) {
idx_a[TOP] = idx_last++; idx_a[TOP] = idx_last++;
volume.push_geometry(a.x, a.y, top_z , 0., 0., 1.); volume.push_geometry(a.x, a.y, top_z , 0., 0., 1.);
} else { } else {
idx_a[TOP] = idx_prev[TOP]; idx_a[TOP] = idx_prev[TOP];
} }
if (ii == 0 || bottom_z_different) {
if (is_first || bottom_z_different) {
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z. // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
idx_a[BOTTOM] = idx_last ++; idx_a[BOTTOM] = idx_last ++;
volume.push_geometry(a.x, a.y, bottom_z, 0., 0., -1.); volume.push_geometry(a.x, a.y, bottom_z, 0., 0., -1.);
@ -852,13 +865,15 @@ static void thick_lines_to_indexed_vertex_array(
volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z); volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
idx_a[RIGHT] = idx_last ++; idx_a[RIGHT] = idx_last ++;
volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z); volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
} else { }
else {
idx_a[BOTTOM] = idx_prev[BOTTOM]; idx_a[BOTTOM] = idx_prev[BOTTOM];
} }
if (ii == 0) { if (is_first) {
// Start of the 1st line segment. // Start of the 1st line segment.
width_initial = width; width_initial = width;
bottom_z_initial = bottom_z;
memcpy(idx_initial, idx_a, sizeof(int) * 4); memcpy(idx_initial, idx_a, sizeof(int) * 4);
} else { } else {
// Continuing a previous segment. // Continuing a previous segment.
@ -866,17 +881,26 @@ static void thick_lines_to_indexed_vertex_array(
double v_dot = dot(v_prev, v); double v_dot = dot(v_prev, v);
bool sharp = v_dot < 0.707; // sin(45 degrees) bool sharp = v_dot < 0.707; // sin(45 degrees)
if (sharp) { if (sharp) {
if (!bottom_z_different)
{
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
idx_a[RIGHT] = idx_last++; idx_a[RIGHT] = idx_last++;
volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z); volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
idx_a[LEFT] = idx_last++; idx_a[LEFT] = idx_last++;
volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z); volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
} }
}
if (v_dot > 0.9) { if (v_dot > 0.9) {
if (!bottom_z_different)
{
// The two successive segments are nearly collinear. // The two successive segments are nearly collinear.
idx_a[LEFT ] = idx_prev[LEFT]; idx_a[LEFT ] = idx_prev[LEFT];
idx_a[RIGHT] = idx_prev[RIGHT]; idx_a[RIGHT] = idx_prev[RIGHT];
} else if (! sharp) { }
}
else if (!sharp) {
if (!bottom_z_different)
{
// Create a sharp corner with an overshot and average the left / right normals. // Create a sharp corner with an overshot and average the left / right normals.
// At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc. // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
Pointf intersection; Pointf intersection;
@ -902,7 +926,9 @@ static void thick_lines_to_indexed_vertex_array(
n_right_prev[1] = float( xy_right_normal.y); n_right_prev[1] = float( xy_right_normal.y);
idx_a[LEFT ] = idx_prev[LEFT ]; idx_a[LEFT ] = idx_prev[LEFT ];
idx_a[RIGHT] = idx_prev[RIGHT]; idx_a[RIGHT] = idx_prev[RIGHT];
} else if (cross(v_prev, v) > 0.) { }
}
else if (cross(v_prev, v) > 0.) {
// Right turn. Fill in the right turn wedge. // Right turn. Fill in the right turn wedge.
volume.push_triangle(idx_prev[RIGHT], idx_a [RIGHT], idx_prev[TOP] ); volume.push_triangle(idx_prev[RIGHT], idx_a [RIGHT], idx_prev[TOP] );
volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a [RIGHT] ); volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a [RIGHT] );
@ -911,8 +937,10 @@ static void thick_lines_to_indexed_vertex_array(
volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a [LEFT] ); volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a [LEFT] );
volume.push_triangle(idx_prev[LEFT], idx_a [LEFT], idx_prev[BOTTOM]); volume.push_triangle(idx_prev[LEFT], idx_a [LEFT], idx_prev[BOTTOM]);
} }
if (ii == lines.size()) { if (is_closing) {
if (!sharp) { if (!sharp) {
if (!bottom_z_different)
{
// Closing a loop with smooth transition. Unify the closing left / right vertices. // Closing a loop with smooth transition. Unify the closing left / right vertices.
memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6); memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6);
memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6); memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6);
@ -925,19 +953,21 @@ static void thick_lines_to_indexed_vertex_array(
volume.quad_indices[u] = idx_initial[RIGHT]; volume.quad_indices[u] = idx_initial[RIGHT];
} }
} }
}
// This is the last iteration, only required to solve the transition. // This is the last iteration, only required to solve the transition.
break; break;
} }
} }
// Only new allocate top / bottom vertices, if not closing a loop. // Only new allocate top / bottom vertices, if not closing a loop.
if (closed && ii + 1 == lines.size()) { if (is_closing) {
idx_b[TOP] = idx_initial[TOP]; idx_b[TOP] = idx_initial[TOP];
} else { } else {
idx_b[TOP] = idx_last ++; idx_b[TOP] = idx_last ++;
volume.push_geometry(b.x, b.y, top_z , 0., 0., 1.); volume.push_geometry(b.x, b.y, top_z , 0., 0., 1.);
} }
if (closed && ii + 1 == lines.size() && width == width_initial) {
if (is_closing && (width == width_initial) && (bottom_z == bottom_z_initial)) {
idx_b[BOTTOM] = idx_initial[BOTTOM]; idx_b[BOTTOM] = idx_initial[BOTTOM];
} else { } else {
idx_b[BOTTOM] = idx_last ++; idx_b[BOTTOM] = idx_last ++;
@ -949,19 +979,23 @@ static void thick_lines_to_indexed_vertex_array(
idx_b[RIGHT ] = idx_last ++; idx_b[RIGHT ] = idx_last ++;
volume.push_geometry(b1.x, b1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z); volume.push_geometry(b1.x, b1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
prev_line = line;
memcpy(idx_prev, idx_b, 4 * sizeof(int)); memcpy(idx_prev, idx_b, 4 * sizeof(int));
bottom_z_prev = bottom_z; bottom_z_prev = bottom_z;
b1_prev = b1; b1_prev = b1;
b2_prev = b2;
v_prev = v; v_prev = v;
if (bottom_z_different)
{
// Found a change of the layer thickness -> Add a cap at the beginning of this segment.
volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]);
}
if (! closed) { if (! closed) {
// Terminate open paths with caps. // Terminate open paths with caps.
if (i == 0) if (is_first && !bottom_z_different)
volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]);
// We don't use 'else' because both cases are true if we have only one line. // We don't use 'else' because both cases are true if we have only one line.
if (i + 1 == lines.size()) if (is_last && !bottom_z_different)
volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]);
} }