printrun-src/printrun/gl/libtatlin/actors.py

changeset 46
cce0af6351f0
parent 15
0bbb006204fc
--- a/printrun-src/printrun/gl/libtatlin/actors.py	Tue Jan 19 20:45:09 2021 +0100
+++ b/printrun-src/printrun/gl/libtatlin/actors.py	Wed Jan 20 10:15:13 2021 +0100
@@ -65,7 +65,7 @@
     return [i1, i2, j2, j2, j1, i1, i2, i3, j3, j3, j2, i2,
             i3, i4, j4, j4, j3, i3, i4, i1, j1, j1, j4, i4]
 
-class BoundingBox(object):
+class BoundingBox:
     """
     A rectangular box (cuboid) enclosing a 3D model, defined by lower and upper corners.
     """
@@ -89,13 +89,12 @@
         return round(height, 2)
 
 
-class Platform(object):
+class Platform:
     """
     Platform on which models are placed.
     """
-    graduations_major = 10
 
-    def __init__(self, build_dimensions, light = False, circular = False):
+    def __init__(self, build_dimensions, light = False, circular = False, grid = (1, 10)):
         self.light = light
         self.circular = circular
         self.width = build_dimensions[0]
@@ -104,6 +103,7 @@
         self.xoffset = build_dimensions[3]
         self.yoffset = build_dimensions[4]
         self.zoffset = build_dimensions[5]
+        self.grid = grid
 
         self.color_grads_minor = (0xaf / 255, 0xdf / 255, 0x5f / 255, 0.1)
         self.color_grads_interm = (0xaf / 255, 0xdf / 255, 0x5f / 255, 0.2)
@@ -122,9 +122,9 @@
         glTranslatef(self.xoffset, self.yoffset, self.zoffset)
 
         def color(i):
-            if i % self.graduations_major == 0:
+            if i % self.grid[1] == 0:
                 glColor4f(*self.color_grads_major)
-            elif i % (self.graduations_major / 2) == 0:
+            elif i % (self.grid[1] // 2) == 0:
                 glColor4f(*self.color_grads_interm)
             else:
                 if self.light: return False
@@ -134,26 +134,26 @@
         # draw the grid
         glBegin(GL_LINES)
         if self.circular:  # Draw a circular grid
-            for i in range(0, int(math.ceil(self.width + 1))):
+            for i in numpy.arange(0, int(math.ceil(self.width + 1)), self.grid[0]):
                 angle = math.asin(2 * float(i) / self.width - 1)
                 x = (math.cos(angle) + 1) * self.depth / 2
                 if color(i):
                     glVertex3f(float(i), self.depth - x, 0.0)
                     glVertex3f(float(i), x, 0.0)
 
-            for i in range(0, int(math.ceil(self.depth + 1))):
+            for i in numpy.arange(0, int(math.ceil(self.depth + 1)), self.grid[0]):
                 angle = math.acos(2 * float(i) / self.depth - 1)
                 x = (math.sin(angle) + 1) * self.width / 2
                 if color(i):
                     glVertex3f(self.width - x, float(i), 0.0)
                     glVertex3f(x, float(i), 0.0)
         else:  # Draw a rectangular grid
-            for i in range(0, int(math.ceil(self.width + 1))):
+            for i in numpy.arange(0, int(math.ceil(self.width + 1)), self.grid[0]):
                 if color(i):
                     glVertex3f(float(i), 0.0, 0.0)
                     glVertex3f(float(i), self.depth, 0.0)
 
-            for i in range(0, int(math.ceil(self.depth + 1))):
+            for i in numpy.arange(0, int(math.ceil(self.depth + 1)), self.grid[0]):
                 if color(i):
                     glVertex3f(0, float(i), 0.0)
                     glVertex3f(self.width, float(i), 0.0)
@@ -174,7 +174,7 @@
         # glCallList(self.display_list)
         self.draw()
 
-class PrintHead(object):
+class PrintHead:
     def __init__(self):
         self.color = (43. / 255, 0., 175. / 255, 1.0)
         self.scale = 5
@@ -209,7 +209,7 @@
         glLineWidth(orig_linewidth)
         glDisable(GL_LINE_SMOOTH)
 
-class Model(object):
+class Model:
     """
     Parent class for models that provides common functionality.
     """
@@ -315,6 +315,47 @@
         gline_idx = 0
     return None
 
+def interpolate_arcs(gline, prev_gline):
+    if gline.command == "G2" or gline.command == "G3":
+        rx = gline.i if gline.i is not None else 0
+        ry = gline.j if gline.j is not None else 0
+        r = math.sqrt(rx*rx + ry*ry)
+
+        cx = prev_gline.current_x + rx
+        cy = prev_gline.current_y + ry
+
+        a_start = math.atan2(-ry, -rx)
+        dx = gline.current_x - cx
+        dy = gline.current_y - cy
+        a_end = math.atan2(dy, dx)
+        a_delta = a_end - a_start
+
+        if gline.command == "G3" and a_delta <= 0:
+            a_delta += math.pi * 2
+        elif gline.command == "G2" and a_delta >= 0:
+            a_delta -= math.pi * 2
+
+        z0 = prev_gline.current_z
+        dz = gline.current_z - z0
+
+        # max segment size: 0.5mm, max num of segments: 100
+        segments = math.ceil(abs(a_delta) * r * 2 / 0.5)
+        if segments > 100:
+            segments = 100
+
+        for t in range(segments):
+            a = t / segments * a_delta + a_start
+
+            mid = (
+                cx + math.cos(a) * r,
+                cy + math.sin(a) * r,
+                z0 + t / segments * dz
+            )
+            yield mid
+
+    yield (gline.current_x, gline.current_y, gline.current_z)
+
+
 class GcodeModel(Model):
     """
     Model for displaying Gcode data.
@@ -363,6 +404,7 @@
         # to store coordinates/colors/normals.
         # Nicely enough we have 3 per kind of thing for all kinds.
         coordspervertex = 3
+        buffered_color_len = 3  # 4th color component (alpha) is ignored
         verticesperline = 8
         coordsperline = coordspervertex * verticesperline
         coords_count = lambda nlines: nlines * coordsperline
@@ -389,20 +431,19 @@
         vertices = self.vertices = numpy.zeros(ncoords, dtype = GLfloat)
         vertex_k = 0
         colors = self.colors = numpy.zeros(ncoords, dtype = GLfloat)
+
         color_k = 0
         normals = self.normals = numpy.zeros(ncoords, dtype = GLfloat)
-        normal_k = 0
         indices = self.indices = numpy.zeros(nindices, dtype = GLuint)
         index_k = 0
         self.layer_idxs_map = {}
         self.layer_stops = [0]
 
-        prev_is_extruding = False
         prev_move_normal_x = None
         prev_move_normal_y = None
         prev_move_angle = None
-
         prev_pos = (0, 0, 0)
+        prev_gline = None
         layer_idx = 0
 
         self.printed_until = 0
@@ -435,83 +476,122 @@
                     if gline.x is None and gline.y is None and gline.z is None:
                         continue
                     has_movement = True
-                    current_pos = (gline.current_x, gline.current_y, gline.current_z)
-                    if not gline.extruding:
-                        travel_vertices[travel_vertex_k] = prev_pos[0]
-                        travel_vertices[travel_vertex_k + 1] = prev_pos[1]
-                        travel_vertices[travel_vertex_k + 2] = prev_pos[2]
-                        travel_vertices[travel_vertex_k + 3] = current_pos[0]
-                        travel_vertices[travel_vertex_k + 4] = current_pos[1]
-                        travel_vertices[travel_vertex_k + 5] = current_pos[2]
-                        travel_vertex_k += 6
-                        prev_is_extruding = False
-                    else:
-                        gline_color = self.movement_color(gline)
+                    for current_pos in interpolate_arcs(gline, prev_gline):
+                        if not gline.extruding:
+                            if self.travels.size < (travel_vertex_k + 100 * 6):
+                                # arc interpolation extra points allocation
+                                # if not enough room for another 100 points now,
+                                # allocate enough and 50% extra to minimize separate allocations
+                                ratio = (travel_vertex_k + 100 * 6) / self.travels.size * 1.5
+                                # print(f"gl realloc travel {self.travels.size} -> {int(self.travels.size * ratio)}")
+                                self.travels.resize(int(self.travels.size * ratio), refcheck = False)
 
-                        next_move = get_next_move(model_data, layer_idx, gline_idx)
-                        next_is_extruding = (next_move.extruding
-                                             if next_move is not None else False)
+                            travel_vertices[travel_vertex_k:travel_vertex_k+3] = prev_pos
+                            travel_vertices[travel_vertex_k + 3:travel_vertex_k + 6] = current_pos
+                            travel_vertex_k += 6
+                        else:
+                            delta_x = current_pos[0] - prev_pos[0]
+                            delta_y = current_pos[1] - prev_pos[1]
+                            norm = delta_x * delta_x + delta_y * delta_y
+                            if norm == 0:  # Don't draw anything if this move is Z+E only
+                                continue
+                            norm = math.sqrt(norm)
+                            move_normal_x = - delta_y / norm
+                            move_normal_y = delta_x / norm
+                            move_angle = math.atan2(delta_y, delta_x)
 
-                        delta_x = current_pos[0] - prev_pos[0]
-                        delta_y = current_pos[1] - prev_pos[1]
-                        norm = delta_x * delta_x + delta_y * delta_y
-                        if norm == 0:  # Don't draw anything if this move is Z+E only
-                            continue
-                        norm = math.sqrt(norm)
-                        move_normal_x = - delta_y / norm
-                        move_normal_y = delta_x / norm
-                        move_angle = math.atan2(delta_y, delta_x)
-
-                        # FIXME: compute these dynamically
-                        path_halfwidth = self.path_halfwidth * 1.2
-                        path_halfheight = self.path_halfheight * 1.2
+                            # FIXME: compute these dynamically
+                            path_halfwidth = self.path_halfwidth * 1.2
+                            path_halfheight = self.path_halfheight * 1.2
 
-                        new_indices = []
-                        new_vertices = []
-                        new_normals = []
-                        if prev_is_extruding:
-                            # Store previous vertices indices
-                            prev_id = vertex_k / 3 - 4
-                            avg_move_normal_x = (prev_move_normal_x + move_normal_x) / 2
-                            avg_move_normal_y = (prev_move_normal_y + move_normal_y) / 2
-                            norm = avg_move_normal_x * avg_move_normal_x + avg_move_normal_y * avg_move_normal_y
-                            if norm == 0:
-                                avg_move_normal_x = move_normal_x
-                                avg_move_normal_y = move_normal_y
+                            new_indices = []
+                            new_vertices = []
+                            new_normals = []
+                            if prev_gline and prev_gline.extruding:
+                                # Store previous vertices indices
+                                prev_id = vertex_k // 3 - 4
+                                avg_move_normal_x = (prev_move_normal_x + move_normal_x) / 2
+                                avg_move_normal_y = (prev_move_normal_y + move_normal_y) / 2
+                                norm = avg_move_normal_x * avg_move_normal_x + avg_move_normal_y * avg_move_normal_y
+                                if norm == 0:
+                                    avg_move_normal_x = move_normal_x
+                                    avg_move_normal_y = move_normal_y
+                                else:
+                                    norm = math.sqrt(norm)
+                                    avg_move_normal_x /= norm
+                                    avg_move_normal_y /= norm
+                                delta_angle = move_angle - prev_move_angle
+                                delta_angle = (delta_angle + twopi) % twopi
+                                fact = abs(math.cos(delta_angle / 2))
+                                # If move is turning too much, avoid creating a big peak
+                                # by adding an intermediate box
+                                if fact < 0.5:
+                                    # FIXME: It looks like there's some heavy code duplication here...
+                                    hw = path_halfwidth
+                                    p1x = prev_pos[0] - hw * prev_move_normal_x
+                                    p2x = prev_pos[0] + hw * prev_move_normal_x
+                                    p1y = prev_pos[1] - hw * prev_move_normal_y
+                                    p2y = prev_pos[1] + hw * prev_move_normal_y
+                                    new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] + path_halfheight))
+                                    new_vertices.extend((p1x, p1y, prev_pos[2]))
+                                    new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] - path_halfheight))
+                                    new_vertices.extend((p2x, p2y, prev_pos[2]))
+                                    new_normals.extend((0, 0, 1))
+                                    new_normals.extend((-prev_move_normal_x, -prev_move_normal_y, 0))
+                                    new_normals.extend((0, 0, -1))
+                                    new_normals.extend((prev_move_normal_x, prev_move_normal_y, 0))
+                                    first = vertex_k // 3
+                                    # Link to previous
+                                    new_indices += triangulate_box(prev_id, prev_id + 1,
+                                                                prev_id + 2, prev_id + 3,
+                                                                first, first + 1,
+                                                                first + 2, first + 3)
+                                    p1x = prev_pos[0] - hw * move_normal_x
+                                    p2x = prev_pos[0] + hw * move_normal_x
+                                    p1y = prev_pos[1] - hw * move_normal_y
+                                    p2y = prev_pos[1] + hw * move_normal_y
+                                    new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] + path_halfheight))
+                                    new_vertices.extend((p1x, p1y, prev_pos[2]))
+                                    new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] - path_halfheight))
+                                    new_vertices.extend((p2x, p2y, prev_pos[2]))
+                                    new_normals.extend((0, 0, 1))
+                                    new_normals.extend((-move_normal_x, -move_normal_y, 0))
+                                    new_normals.extend((0, 0, -1))
+                                    new_normals.extend((move_normal_x, move_normal_y, 0))
+                                    prev_id += 4
+                                    first += 4
+                                    # Link to previous
+                                    new_indices += triangulate_box(prev_id, prev_id + 1,
+                                                                prev_id + 2, prev_id + 3,
+                                                                first, first + 1,
+                                                                first + 2, first + 3)
+                                else:
+                                    hw = path_halfwidth / fact
+                                    # Compute vertices
+                                    p1x = prev_pos[0] - hw * avg_move_normal_x
+                                    p2x = prev_pos[0] + hw * avg_move_normal_x
+                                    p1y = prev_pos[1] - hw * avg_move_normal_y
+                                    p2y = prev_pos[1] + hw * avg_move_normal_y
+                                    new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] + path_halfheight))
+                                    new_vertices.extend((p1x, p1y, prev_pos[2]))
+                                    new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] - path_halfheight))
+                                    new_vertices.extend((p2x, p2y, prev_pos[2]))
+                                    new_normals.extend((0, 0, 1))
+                                    new_normals.extend((-avg_move_normal_x, -avg_move_normal_y, 0))
+                                    new_normals.extend((0, 0, -1))
+                                    new_normals.extend((avg_move_normal_x, avg_move_normal_y, 0))
+                                    first = vertex_k // 3
+                                    # Link to previous
+                                    new_indices += triangulate_box(prev_id, prev_id + 1,
+                                                                prev_id + 2, prev_id + 3,
+                                                                first, first + 1,
+                                                                first + 2, first + 3)
                             else:
-                                norm = math.sqrt(norm)
-                                avg_move_normal_x /= norm
-                                avg_move_normal_y /= norm
-                            delta_angle = move_angle - prev_move_angle
-                            delta_angle = (delta_angle + twopi) % twopi
-                            fact = abs(math.cos(delta_angle / 2))
-                            # If move is turning too much, avoid creating a big peak
-                            # by adding an intermediate box
-                            if fact < 0.5:
-                                # FIXME: It looks like there's some heavy code duplication here...
-                                hw = path_halfwidth
-                                p1x = prev_pos[0] - hw * prev_move_normal_x
-                                p2x = prev_pos[0] + hw * prev_move_normal_x
-                                p1y = prev_pos[1] - hw * prev_move_normal_y
-                                p2y = prev_pos[1] + hw * prev_move_normal_y
-                                new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] + path_halfheight))
-                                new_vertices.extend((p1x, p1y, prev_pos[2]))
-                                new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] - path_halfheight))
-                                new_vertices.extend((p2x, p2y, prev_pos[2]))
-                                new_normals.extend((0, 0, 1))
-                                new_normals.extend((-prev_move_normal_x, -prev_move_normal_y, 0))
-                                new_normals.extend((0, 0, -1))
-                                new_normals.extend((prev_move_normal_x, prev_move_normal_y, 0))
-                                first = vertex_k / 3
-                                # Link to previous
-                                new_indices += triangulate_box(prev_id, prev_id + 1,
-                                                               prev_id + 2, prev_id + 3,
-                                                               first, first + 1,
-                                                               first + 2, first + 3)
-                                p1x = prev_pos[0] - hw * move_normal_x
-                                p2x = prev_pos[0] + hw * move_normal_x
-                                p1y = prev_pos[1] - hw * move_normal_y
-                                p2y = prev_pos[1] + hw * move_normal_y
+                                # Compute vertices normal to the current move and cap it
+                                p1x = prev_pos[0] - path_halfwidth * move_normal_x
+                                p2x = prev_pos[0] + path_halfwidth * move_normal_x
+                                p1y = prev_pos[1] - path_halfwidth * move_normal_y
+                                p2y = prev_pos[1] + path_halfwidth * move_normal_y
                                 new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] + path_halfheight))
                                 new_vertices.extend((p1x, p1y, prev_pos[2]))
                                 new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] - path_halfheight))
@@ -520,97 +600,68 @@
                                 new_normals.extend((-move_normal_x, -move_normal_y, 0))
                                 new_normals.extend((0, 0, -1))
                                 new_normals.extend((move_normal_x, move_normal_y, 0))
-                                prev_id += 4
-                                first += 4
-                                # Link to previous
-                                new_indices += triangulate_box(prev_id, prev_id + 1,
-                                                               prev_id + 2, prev_id + 3,
-                                                               first, first + 1,
-                                                               first + 2, first + 3)
-                            else:
-                                hw = path_halfwidth / fact
-                                # Compute vertices
-                                p1x = prev_pos[0] - hw * avg_move_normal_x
-                                p2x = prev_pos[0] + hw * avg_move_normal_x
-                                p1y = prev_pos[1] - hw * avg_move_normal_y
-                                p2y = prev_pos[1] + hw * avg_move_normal_y
-                                new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] + path_halfheight))
-                                new_vertices.extend((p1x, p1y, prev_pos[2]))
-                                new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] - path_halfheight))
-                                new_vertices.extend((p2x, p2y, prev_pos[2]))
+                                first = vertex_k // 3
+                                new_indices = triangulate_rectangle(first, first + 1,
+                                                                    first + 2, first + 3)
+
+                            next_move = get_next_move(model_data, layer_idx, gline_idx)
+                            next_is_extruding = next_move and next_move.extruding
+                            if not next_is_extruding:
+                                # Compute caps and link everything
+                                p1x = current_pos[0] - path_halfwidth * move_normal_x
+                                p2x = current_pos[0] + path_halfwidth * move_normal_x
+                                p1y = current_pos[1] - path_halfwidth * move_normal_y
+                                p2y = current_pos[1] + path_halfwidth * move_normal_y
+                                new_vertices.extend((current_pos[0], current_pos[1], current_pos[2] + path_halfheight))
+                                new_vertices.extend((p1x, p1y, current_pos[2]))
+                                new_vertices.extend((current_pos[0], current_pos[1], current_pos[2] - path_halfheight))
+                                new_vertices.extend((p2x, p2y, current_pos[2]))
                                 new_normals.extend((0, 0, 1))
-                                new_normals.extend((-avg_move_normal_x, -avg_move_normal_y, 0))
+                                new_normals.extend((-move_normal_x, -move_normal_y, 0))
                                 new_normals.extend((0, 0, -1))
-                                new_normals.extend((avg_move_normal_x, avg_move_normal_y, 0))
-                                first = vertex_k / 3
-                                # Link to previous
-                                new_indices += triangulate_box(prev_id, prev_id + 1,
-                                                               prev_id + 2, prev_id + 3,
-                                                               first, first + 1,
-                                                               first + 2, first + 3)
-                        else:
-                            # Compute vertices normal to the current move and cap it
-                            p1x = prev_pos[0] - path_halfwidth * move_normal_x
-                            p2x = prev_pos[0] + path_halfwidth * move_normal_x
-                            p1y = prev_pos[1] - path_halfwidth * move_normal_y
-                            p2y = prev_pos[1] + path_halfwidth * move_normal_y
-                            new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] + path_halfheight))
-                            new_vertices.extend((p1x, p1y, prev_pos[2]))
-                            new_vertices.extend((prev_pos[0], prev_pos[1], prev_pos[2] - path_halfheight))
-                            new_vertices.extend((p2x, p2y, prev_pos[2]))
-                            new_normals.extend((0, 0, 1))
-                            new_normals.extend((-move_normal_x, -move_normal_y, 0))
-                            new_normals.extend((0, 0, -1))
-                            new_normals.extend((move_normal_x, move_normal_y, 0))
-                            first = vertex_k / 3
-                            new_indices = triangulate_rectangle(first, first + 1,
-                                                                first + 2, first + 3)
+                                new_normals.extend((move_normal_x, move_normal_y, 0))
+                                end_first = vertex_k // 3 + len(new_vertices) // 3 - 4
+                                new_indices += triangulate_rectangle(end_first + 3, end_first + 2,
+                                                                    end_first + 1, end_first)
+                                new_indices += triangulate_box(first, first + 1,
+                                                            first + 2, first + 3,
+                                                            end_first, end_first + 1,
+                                                            end_first + 2, end_first + 3)
 
-                        if not next_is_extruding:
-                            # Compute caps and link everything
-                            p1x = current_pos[0] - path_halfwidth * move_normal_x
-                            p2x = current_pos[0] + path_halfwidth * move_normal_x
-                            p1y = current_pos[1] - path_halfwidth * move_normal_y
-                            p2y = current_pos[1] + path_halfwidth * move_normal_y
-                            new_vertices.extend((current_pos[0], current_pos[1], current_pos[2] + path_halfheight))
-                            new_vertices.extend((p1x, p1y, current_pos[2]))
-                            new_vertices.extend((current_pos[0], current_pos[1], current_pos[2] - path_halfheight))
-                            new_vertices.extend((p2x, p2y, current_pos[2]))
-                            new_normals.extend((0, 0, 1))
-                            new_normals.extend((-move_normal_x, -move_normal_y, 0))
-                            new_normals.extend((0, 0, -1))
-                            new_normals.extend((move_normal_x, move_normal_y, 0))
-                            end_first = vertex_k / 3 + len(new_vertices) / 3 - 4
-                            new_indices += triangulate_rectangle(end_first + 3, end_first + 2,
-                                                                 end_first + 1, end_first)
-                            new_indices += triangulate_box(first, first + 1,
-                                                           first + 2, first + 3,
-                                                           end_first, end_first + 1,
-                                                           end_first + 2, end_first + 3)
+                            if self.indices.size < (index_k + len(new_indices) + 100 * indicesperline):
+                                # arc interpolation extra points allocation
+                                ratio = (index_k + len(new_indices) + 100 * indicesperline) / self.indices.size * 1.5
+                                # print(f"gl realloc print {self.vertices.size} -> {int(self.vertices.size * ratio)}")
+                                self.vertices.resize(int(self.vertices.size * ratio), refcheck = False)
+                                self.colors.resize(int(self.colors.size * ratio), refcheck = False)
+                                self.normals.resize(int(self.normals.size * ratio), refcheck = False)
+                                self.indices.resize(int(self.indices.size * ratio), refcheck = False)
+
+                            for new_i, item in enumerate(new_indices):
+                                indices[index_k + new_i] = item
+                            index_k += len(new_indices)
 
-                        for new_i, item in enumerate(new_indices):
-                            indices[index_k + new_i] = item
-                        index_k += len(new_indices)
-                        for new_i, item in enumerate(new_vertices):
-                            vertices[vertex_k + new_i] = item
-                        vertex_k += len(new_vertices)
-                        for new_i, item in enumerate(new_normals):
-                            normals[normal_k + new_i] = item
-                        normal_k += len(new_normals)
-                        new_colors = list(gline_color)[:-1] * (len(new_vertices) / 3)
-                        for new_i, item in enumerate(new_colors):
-                            colors[color_k + new_i] = item
-                        color_k += len(new_colors)
+                            new_vertices_len = len(new_vertices)
+                            vertices[vertex_k:vertex_k+new_vertices_len] = new_vertices
+                            normals[vertex_k:vertex_k+new_vertices_len] = new_normals
+                            vertex_k += new_vertices_len
 
-                        prev_is_extruding = True
-                        prev_move_normal_x = move_normal_x
-                        prev_move_normal_y = move_normal_y
-                        prev_move_angle = move_angle
+                            new_vertices_count = new_vertices_len//coordspervertex
+                            # settings support alpha (transperancy), but it is ignored here
+                            gline_color = self.movement_color(gline)[:buffered_color_len]
+                            for vi in range(new_vertices_count):
+                                colors[color_k:color_k+buffered_color_len] = gline_color
+                                color_k += buffered_color_len
 
-                    prev_pos = current_pos
-                    count_travel_indices.append(travel_vertex_k / 3)
+                            prev_move_normal_x = move_normal_x
+                            prev_move_normal_y = move_normal_y
+                            prev_move_angle = move_angle
+
+                        prev_pos = current_pos
+                    prev_gline = gline
+                    count_travel_indices.append(travel_vertex_k // 3)
                     count_print_indices.append(index_k)
-                    count_print_vertices.append(vertex_k / 3)
+                    count_print_vertices.append(vertex_k // 3)
                     gline.gcview_end_vertex = len(count_print_indices) - 1
 
                 if has_movement:
@@ -637,7 +688,7 @@
             self.travels.resize(travel_vertex_k, refcheck = False)
             self.vertices.resize(vertex_k, refcheck = False)
             self.colors.resize(color_k, refcheck = False)
-            self.normals.resize(normal_k, refcheck = False)
+            self.normals.resize(vertex_k, refcheck = False)
             self.indices.resize(index_k, refcheck = False)
 
             self.layer_stops = array.array('L', self.layer_stops)
@@ -655,7 +706,7 @@
         t_end = time.time()
 
         logging.debug(_('Initialized 3D visualization in %.2f seconds') % (t_end - t_start))
-        logging.debug(_('Vertex count: %d') % ((len(self.vertices) + len(self.travels)) / 3))
+        logging.debug(_('Vertex count: %d') % ((len(self.vertices) + len(self.travels)) // 3))
         yield None
 
     def copy(self):
@@ -673,6 +724,24 @@
         copy.initialized = False
         return copy
 
+    def update_colors(self):
+        """Rebuild gl color buffer without loading. Used after color settings edit"""
+        ncoords = self.count_print_vertices[-1]
+        colors = numpy.empty(ncoords*3, dtype = GLfloat)
+        cur_vertex = 0
+        gline_i = 1
+        for gline in self.gcode.lines:
+            if gline.gcview_end_vertex:
+                gline_color = self.movement_color(gline)[:3]
+                last_vertex = self.count_print_vertices[gline_i]
+                gline_i += 1
+                while cur_vertex < last_vertex:
+                    colors[cur_vertex*3:cur_vertex*3+3] = gline_color
+                    cur_vertex += 1
+        if self.vertex_color_buffer:
+            self.vertex_color_buffer.delete()
+        self.vertex_color_buffer = numpy2vbo(colors, use_vbos = self.use_vbos)
+
     # ------------------------------------------------------------------------
     # DRAWING
     # ------------------------------------------------------------------------
@@ -869,10 +938,11 @@
         color_k = 0
         self.printed_until = -1
         self.only_current = False
+        prev_gline = None
         while layer_idx < len(model_data.all_layers):
             with self.lock:
                 nlines = len(model_data)
-                if nlines * 6 != vertices.size:
+                if nlines * 6 > vertices.size:
                     self.vertices.resize(nlines * 6, refcheck = False)
                     self.colors.resize(nlines * 8, refcheck = False)
                 layer = model_data.all_layers[layer_idx]
@@ -882,32 +952,43 @@
                         continue
                     if gline.x is None and gline.y is None and gline.z is None:
                         continue
+
                     has_movement = True
-                    vertices[vertex_k] = prev_pos[0]
-                    vertices[vertex_k + 1] = prev_pos[1]
-                    vertices[vertex_k + 2] = prev_pos[2]
-                    current_pos = (gline.current_x, gline.current_y, gline.current_z)
-                    vertices[vertex_k + 3] = current_pos[0]
-                    vertices[vertex_k + 4] = current_pos[1]
-                    vertices[vertex_k + 5] = current_pos[2]
-                    vertex_k += 6
+                    for current_pos in interpolate_arcs(gline, prev_gline):
+
+                        if self.vertices.size < (vertex_k + 100 * 6):
+                            # arc interpolation extra points allocation
+                            ratio = (vertex_k + 100 * 6) / self.vertices.size * 1.5
+                            # print(f"gl realloc lite {self.vertices.size} -> {int(self.vertices.size * ratio)}")
+                            self.vertices.resize(int(self.vertices.size * ratio), refcheck = False)
+                            self.colors.resize(int(self.colors.size * ratio), refcheck = False)
+
 
-                    vertex_color = self.movement_color(gline)
-                    colors[color_k] = vertex_color[0]
-                    colors[color_k + 1] = vertex_color[1]
-                    colors[color_k + 2] = vertex_color[2]
-                    colors[color_k + 3] = vertex_color[3]
-                    colors[color_k + 4] = vertex_color[0]
-                    colors[color_k + 5] = vertex_color[1]
-                    colors[color_k + 6] = vertex_color[2]
-                    colors[color_k + 7] = vertex_color[3]
-                    color_k += 8
+                        vertices[vertex_k] = prev_pos[0]
+                        vertices[vertex_k + 1] = prev_pos[1]
+                        vertices[vertex_k + 2] = prev_pos[2]
+                        vertices[vertex_k + 3] = current_pos[0]
+                        vertices[vertex_k + 4] = current_pos[1]
+                        vertices[vertex_k + 5] = current_pos[2]
+                        vertex_k += 6
 
-                    prev_pos = current_pos
-                    gline.gcview_end_vertex = vertex_k / 3
+                        vertex_color = self.movement_color(gline)
+                        colors[color_k] = vertex_color[0]
+                        colors[color_k + 1] = vertex_color[1]
+                        colors[color_k + 2] = vertex_color[2]
+                        colors[color_k + 3] = vertex_color[3]
+                        colors[color_k + 4] = vertex_color[0]
+                        colors[color_k + 5] = vertex_color[1]
+                        colors[color_k + 6] = vertex_color[2]
+                        colors[color_k + 7] = vertex_color[3]
+                        color_k += 8
+
+                        prev_pos = current_pos
+                        prev_gline = gline
+                        gline.gcview_end_vertex = vertex_k // 3
 
                 if has_movement:
-                    self.layer_stops.append(vertex_k / 3)
+                    self.layer_stops.append(vertex_k // 3)
                     self.layer_idxs_map[layer_idx] = len(self.layer_stops) - 1
                     self.max_layers = len(self.layer_stops) - 1
                     self.num_layers_to_draw = self.max_layers + 1
@@ -936,7 +1017,7 @@
         t_end = time.time()
 
         logging.debug(_('Initialized 3D visualization in %.2f seconds') % (t_end - t_start))
-        logging.debug(_('Vertex count: %d') % (len(self.vertices) / 3))
+        logging.debug(_('Vertex count: %d') % (len(self.vertices) // 3))
         yield None
 
     def copy(self):

mercurial