Merge branch 'layerview_dev' of https://github.com/Johan3DV/Cura into Johan3DV-layerview_dev

This commit is contained in:
Tim Kuipers 2016-07-25 16:41:13 +02:00
commit c6e9e62e73
7 changed files with 264 additions and 85 deletions

View file

@ -35,24 +35,31 @@ class Layer:
def setThickness(self, thickness): def setThickness(self, thickness):
self._thickness = thickness self._thickness = thickness
def vertexCount(self): def lineMeshVertexCount(self):
result = 0 result = 0
for polygon in self._polygons: for polygon in self._polygons:
result += polygon.vertexCount() result += polygon.lineMeshVertexCount()
return result return result
def build(self, offset, vertices, colors, indices): def lineMeshElementCount(self):
result = offset result = 0
for polygon in self._polygons: for polygon in self._polygons:
if polygon.type == LayerPolygon.InfillType or polygon.type == LayerPolygon.MoveCombingType or polygon.type == LayerPolygon.MoveRetractionType: result += polygon.lineMeshElementCount()
continue
polygon.build(result, vertices, colors, indices) return result
result += polygon.vertexCount()
def build(self, vertex_offset, index_offset, vertices, colors, indices):
result_vertex_offset = vertex_offset
result_index_offset = index_offset
self._element_count = 0
for polygon in self._polygons:
polygon.build(result_vertex_offset, result_index_offset, vertices, colors, indices)
result_vertex_offset += polygon.lineMeshVertexCount()
result_index_offset += polygon.lineMeshElementCount()
self._element_count += polygon.elementCount self._element_count += polygon.elementCount
return result return (result_vertex_offset, result_index_offset)
def createMesh(self): def createMesh(self):
return self.createMeshOrJumps(True) return self.createMeshOrJumps(True)
@ -60,40 +67,52 @@ class Layer:
def createJumps(self): def createJumps(self):
return self.createMeshOrJumps(False) return self.createMeshOrJumps(False)
# Defines the two triplets of local point indices to use to draw the two faces for each line segment in createMeshOrJump
__index_pattern = numpy.array([[0, 3, 2, 0, 1, 3]], dtype = numpy.int32 )
def createMeshOrJumps(self, make_mesh): def createMeshOrJumps(self, make_mesh):
builder = MeshBuilder() builder = MeshBuilder()
line_count = 0
if make_mesh:
for polygon in self._polygons:
line_count += polygon.meshLineCount
else:
for polygon in self._polygons:
line_count += polygon.jumpCount
# Reserve the neccesary space for the data upfront
builder.reserveFaceAndVertexCount(2 * line_count, 4 * line_count)
for polygon in self._polygons: for polygon in self._polygons:
if make_mesh and (polygon.type == LayerPolygon.MoveCombingType or polygon.type == LayerPolygon.MoveRetractionType): # Filter out the types of lines we are not interesed in depending on whether we are drawing the mesh or the jumps.
continue index_mask = numpy.logical_not(polygon.jumpMask) if make_mesh else polygon.jumpMask
if not make_mesh and not (polygon.type == LayerPolygon.MoveCombingType or polygon.type == LayerPolygon.MoveRetractionType):
continue
poly_color = polygon.getColor() # Create an array with rows [p p+1] and only keep those we whant to draw based on make_mesh
points = numpy.concatenate((polygon.data[:-1], polygon.data[1:]), 1)[index_mask.ravel()]
# Line types of the points we want to draw
line_types = polygon.types[index_mask]
# Shift the z-axis according to previous implementation.
if make_mesh:
points[polygon.isInfillOrSkinType(line_types), 1::3] -= 0.01
else:
points[:, 1::3] += 0.01
points = numpy.copy(polygon.data) # Create an array with normals and tile 2 copies to match size of points variable
if polygon.type == LayerPolygon.InfillType or polygon.type == LayerPolygon.SkinType or polygon.type == LayerPolygon.SupportInfillType: normals = numpy.tile( polygon.getNormals()[index_mask.ravel()], (1, 2))
points[:,1] -= 0.01
if polygon.type == LayerPolygon.MoveCombingType or polygon.type == LayerPolygon.MoveRetractionType:
points[:,1] += 0.01
normals = polygon.getNormals() # Scale all normals by the line width of the current line so we can easily offset.
normals *= (polygon.lineWidths[index_mask.ravel()] / 2)
# Scale all by the line width of the polygon so we can easily offset. # Create 4 points to draw each line segment, points +- normals results in 2 points each. Reshape to one point per line
normals *= (polygon.lineWidth / 2) f_points = numpy.concatenate((points-normals, points+normals), 1).reshape((-1, 3))
# __index_pattern defines which points to use to draw the two faces for each lines egment, the following linesegment is offset by 4
f_indices = ( self.__index_pattern + numpy.arange(0, 4 * len(normals), 4, dtype=numpy.int32).reshape((-1, 1)) ).reshape((-1, 3))
f_colors = numpy.repeat(polygon.mapLineTypeToColor(line_types), 4, 0)
#TODO: Use numpy magic to perform the vertex creation to speed up things. builder.addFacesWithColor(f_points, f_indices, f_colors)
for i in range(len(points)):
start = points[i - 1]
end = points[i]
normal = normals[i - 1]
return builder.build()
point1 = Vector(data = start - normal)
point2 = Vector(data = start + normal)
point3 = Vector(data = end + normal)
point4 = Vector(data = end - normal)
builder.addQuad(point1, point2, point3, point4, color = poly_color)
return builder.build()

View file

@ -50,16 +50,19 @@ class LayerDataBuilder(MeshBuilder):
def build(self): def build(self):
vertex_count = 0 vertex_count = 0
index_count = 0
for layer, data in self._layers.items(): for layer, data in self._layers.items():
vertex_count += data.vertexCount() vertex_count += data.lineMeshVertexCount()
index_count += data.lineMeshElementCount()
vertices = numpy.empty((vertex_count, 3), numpy.float32) vertices = numpy.empty((vertex_count, 3), numpy.float32)
colors = numpy.empty((vertex_count, 4), numpy.float32) colors = numpy.empty((vertex_count, 4), numpy.float32)
indices = numpy.empty((vertex_count, 2), numpy.int32) indices = numpy.empty((index_count, 2), numpy.int32)
offset = 0 vertex_offset = 0
index_offset = 0
for layer, data in self._layers.items(): for layer, data in self._layers.items():
offset = data.build(offset, vertices, colors, indices) ( vertex_offset, index_offset ) = data.build( vertex_offset, index_offset, vertices, colors, indices)
self._element_counts[layer] = data.elementCount self._element_counts[layer] = data.elementCount
self.addVertices(vertices) self.addVertices(vertices)

View file

@ -14,40 +14,113 @@ class LayerPolygon:
SupportInfillType = 7 SupportInfillType = 7
MoveCombingType = 8 MoveCombingType = 8
MoveRetractionType = 9 MoveRetractionType = 9
def __init__(self, mesh, polygon_type, data, line_width): __jump_map = numpy.logical_or( numpy.arange(10) == NoneType, numpy.arange(10) >= MoveCombingType )
def __init__(self, mesh, extruder, line_types, data, line_widths):
self._mesh = mesh self._mesh = mesh
self._type = polygon_type self._extruder = extruder
self._types = line_types
self._data = data self._data = data
self._line_width = line_width / 1000 self._line_widths = line_widths
self._begin = 0
self._end = 0 self._vertex_begin = 0
self._vertex_end = 0
self._index_begin = 0
self._index_end = 0
self._jump_mask = self.__jump_map[self._types]
self._jump_count = numpy.sum(self._jump_mask)
self._mesh_line_count = len(self._types)-self._jump_count
self._vertex_count = self._mesh_line_count + numpy.sum( self._types[1:] == self._types[:-1])
self._color = self.__color_map[polygon_type] # Buffering the colors shouldn't be necessary as it is not
# re-used and can save alot of memory usage.
self._colors = self.__color_map[self._types]
self._color_map = self.__color_map
# When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType
# Should be generated in better way, not hardcoded.
self._isInfillOrSkinTypeMap = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0], dtype=numpy.bool)
self._build_cache_line_mesh_mask = None
self._build_cache_needed_points = None
def buildCache(self):
# For the line mesh we do not draw Infill or Jumps. Therefore those lines are filtered out.
self._build_cache_line_mesh_mask = numpy.logical_not(numpy.logical_or(self._jump_mask, self._types == LayerPolygon.InfillType ))
mesh_line_count = numpy.sum(self._build_cache_line_mesh_mask)
self._index_begin = 0
self._index_end = mesh_line_count
self._build_cache_needed_points = numpy.ones((len(self._types), 2), dtype=numpy.bool)
# Only if the type of line segment changes do we need to add an extra vertex to change colors
self._build_cache_needed_points[1:, 0][:, numpy.newaxis] = self._types[1:] != self._types[:-1]
# Mark points as unneeded if they are of types we don't want in the line mesh according to the calculated mask
numpy.logical_and(self._build_cache_needed_points, self._build_cache_line_mesh_mask, self._build_cache_needed_points )
self._vertex_begin = 0
self._vertex_end = numpy.sum( self._build_cache_needed_points )
def build(self, offset, vertices, colors, indices): def build(self, vertex_offset, index_offset, vertices, colors, indices):
self._begin = offset if (self._build_cache_line_mesh_mask is None) or (self._build_cache_needed_points is None ):
self._end = self._begin + len(self._data) - 1 self.buildCache()
line_mesh_mask = self._build_cache_line_mesh_mask
needed_points_list = self._build_cache_needed_points
# Index to the points we need to represent the line mesh. This is constructed by generating simple
# start and end points for each line. For line segment n these are points n and n+1. Row n reads [n n+1]
# Then then the indices for the points we don't need are thrown away based on the pre-calculated list.
index_list = ( numpy.arange(len(self._types)).reshape((-1, 1)) + numpy.array([[0, 1]]) ).reshape((-1, 1))[needed_points_list.reshape((-1, 1))]
# The relative values of begin and end indices have already been set in buildCache, so we only need to offset them to the parents offset.
self._vertex_begin += vertex_offset
self._vertex_end += vertex_offset
# Points are picked based on the index list to get the vertices needed.
vertices[self._vertex_begin:self._vertex_end, :] = self._data[index_list, :]
# Create an array with colors for each vertex and remove the color data for the points that has been thrown away.
colors[self._vertex_begin:self._vertex_end, :] = numpy.tile(self._colors, (1, 2)).reshape((-1, 4))[needed_points_list.ravel()]
colors[self._vertex_begin:self._vertex_end, :] *= numpy.array([[0.5, 0.5, 0.5, 1.0]], numpy.float32)
vertices[self._begin:self._end + 1, :] = self._data[:, :] # The relative values of begin and end indices have already been set in buildCache, so we only need to offset them to the parents offset.
colors[self._begin:self._end + 1, :] = numpy.array([self._color.r * 0.5, self._color.g * 0.5, self._color.b * 0.5, self._color.a], numpy.float32) self._index_begin += index_offset
self._index_end += index_offset
indices[self._index_begin:self._index_end, :] = numpy.arange(self._index_end-self._index_begin, dtype=numpy.int32).reshape((-1, 1))
# When the line type changes the index needs to be increased by 2.
indices[self._index_begin:self._index_end, :] += numpy.cumsum(needed_points_list[line_mesh_mask.ravel(), 0], dtype=numpy.int32).reshape((-1, 1))
# Each line segment goes from it's starting point p to p+1, offset by the vertex index.
# The -1 is to compensate for the neccecarily True value of needed_points_list[0,0] which causes an unwanted +1 in cumsum above.
indices[self._index_begin:self._index_end, :] += numpy.array([self._vertex_begin - 1, self._vertex_begin])
self._build_cache_line_mesh_mask = None
self._build_cache_needed_points = None
for i in range(self._begin, self._end): def getColors(self):
indices[i, 0] = i return self._colors
indices[i, 1] = i + 1
indices[self._end, 0] = self._end def mapLineTypeToColor(self, line_types):
indices[self._end, 1] = self._begin return self._color_map[line_types]
def getColor(self): def isInfillOrSkinType(self, line_types):
return self._color return self._isInfillOrSkinTypeMap[line_types]
def vertexCount(self): def lineMeshVertexCount(self):
return len(self._data) return (self._vertex_end - self._vertex_begin)
def lineMeshElementCount(self):
return (self._index_end - self._index_begin)
@property @property
def type(self): def extruder(self):
return self._type return self._extruder
@property
def types(self):
return self._types
@property @property
def data(self): def data(self):
@ -55,11 +128,23 @@ class LayerPolygon:
@property @property
def elementCount(self): def elementCount(self):
return ((self._end - self._begin) + 1) * 2 # The range of vertices multiplied by 2 since each vertex is used twice return (self._index_end - self._index_begin) * 2 # The range of vertices multiplied by 2 since each vertex is used twice
@property @property
def lineWidth(self): def lineWidths(self):
return self._line_width return self._line_widths
@property
def jumpMask(self):
return self._jump_mask
@property
def meshLineCount(self):
return self._mesh_line_count
@property
def jumpCount(self):
return self._jump_count
# Calculate normals for the entire polygon using numpy. # Calculate normals for the entire polygon using numpy.
def getNormals(self): def getNormals(self):
@ -71,7 +156,8 @@ class LayerPolygon:
# we end up subtracting each next point from the current, wrapping # we end up subtracting each next point from the current, wrapping
# around. This gives us the edges from the next point to the current # around. This gives us the edges from the next point to the current
# point. # point.
normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0) normals = numpy.diff(normals, 1, 0)
# Calculate the length of each edge using standard Pythagoras # Calculate the length of each edge using standard Pythagoras
lengths = numpy.sqrt(normals[:, 0] ** 2 + normals[:, 2] ** 2) lengths = numpy.sqrt(normals[:, 0] ** 2 + normals[:, 2] ** 2)
# The normal of a 2D vector is equal to its x and y coordinates swapped # The normal of a 2D vector is equal to its x and y coordinates swapped
@ -85,7 +171,7 @@ class LayerPolygon:
return normals return normals
__color_map = { __color_mapping = {
NoneType: Color(1.0, 1.0, 1.0, 1.0), NoneType: Color(1.0, 1.0, 1.0, 1.0),
Inset0Type: Color(1.0, 0.0, 0.0, 1.0), Inset0Type: Color(1.0, 0.0, 0.0, 1.0),
InsetXType: Color(0.0, 1.0, 0.0, 1.0), InsetXType: Color(0.0, 1.0, 0.0, 1.0),
@ -97,3 +183,17 @@ class LayerPolygon:
MoveCombingType: Color(0.0, 0.0, 1.0, 1.0), MoveCombingType: Color(0.0, 0.0, 1.0, 1.0),
MoveRetractionType: Color(0.5, 0.5, 1.0, 1.0), MoveRetractionType: Color(0.5, 0.5, 1.0, 1.0),
} }
# Should be generated in better way, not hardcoded.
__color_map = numpy.array([
[1.0, 1.0, 1.0, 1.0],
[1.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 0.0, 1.0],
[1.0, 1.0, 0.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
[1.0, 0.74, 0.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0],
[0.5, 0.5, 1.0, 1.0]
])

View file

@ -61,6 +61,28 @@ message Polygon {
float line_width = 3; // The width of the line being laid down float line_width = 3; // The width of the line being laid down
} }
message LayerOptimized {
int32 id = 1;
float height = 2; // Z position
float thickness = 3; // height of a single layer
repeated PathSegment path_segment = 4; // layer data
}
message PathSegment {
int32 extruder = 1; // The extruder used for this path segment
enum PointType {
Point2D = 0;
Point3D = 1;
}
PointType point_type = 2;
bytes points = 3; // The points defining the line segments, bytes of float[2/3] array of length N+1
bytes line_type = 4; // Type of line segment as an unsigned char array of length 1 or N, where N is the number of line segments in this path
bytes line_width = 5; // The widths of the line segments as bytes of a float array of length 1 or N
}
message GCodeLayer { message GCodeLayer {
bytes data = 2; bytes data = 2;
} }

View file

@ -57,6 +57,7 @@ class CuraEngineBackend(Backend):
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
self._onActiveViewChanged() self._onActiveViewChanged()
self._stored_layer_data = [] self._stored_layer_data = []
self._stored_optimized_layer_data = []
#Triggers for when to (re)start slicing: #Triggers for when to (re)start slicing:
self._global_container_stack = None self._global_container_stack = None
@ -77,6 +78,7 @@ class CuraEngineBackend(Backend):
#Listeners for receiving messages from the back-end. #Listeners for receiving messages from the back-end.
self._message_handlers["cura.proto.Layer"] = self._onLayerMessage self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
self._message_handlers["cura.proto.LayerOptimized"] = self._onOptimizedLayerMessage
self._message_handlers["cura.proto.Progress"] = self._onProgressMessage self._message_handlers["cura.proto.Progress"] = self._onProgressMessage
self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage
self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage
@ -139,6 +141,7 @@ class CuraEngineBackend(Backend):
self.printDurationMessage.emit(0, [0]) self.printDurationMessage.emit(0, [0])
self._stored_layer_data = [] self._stored_layer_data = []
self._stored_optimized_layer_data = []
if self._slicing: #We were already slicing. Stop the old job. if self._slicing: #We were already slicing. Stop the old job.
self._terminate() self._terminate()
@ -167,6 +170,7 @@ class CuraEngineBackend(Backend):
self._slicing = False self._slicing = False
self._restart = True self._restart = True
self._stored_layer_data = [] self._stored_layer_data = []
self._stored_optimized_layer_data = []
if self._start_slice_job is not None: if self._start_slice_job is not None:
self._start_slice_job.cancel() self._start_slice_job.cancel()
@ -267,6 +271,12 @@ class CuraEngineBackend(Backend):
def _onLayerMessage(self, message): def _onLayerMessage(self, message):
self._stored_layer_data.append(message) self._stored_layer_data.append(message)
## Called when an optimized sliced layer data message is received from the engine.
#
# \param message The protobuf message containing sliced layer data.
def _onOptimizedLayerMessage(self, message):
self._stored_optimized_layer_data.append(message)
## Called when a progress message is received from the engine. ## Called when a progress message is received from the engine.
# #
# \param message The protobuf message containing the slicing progress. # \param message The protobuf message containing the slicing progress.
@ -284,9 +294,9 @@ class CuraEngineBackend(Backend):
self._slicing = False self._slicing = False
Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time ) Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time )
if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()): if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()):
self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_layer_data) self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_optimized_layer_data)
self._process_layers_job.start() self._process_layers_job.start()
self._stored_layer_data = [] self._stored_optimized_layer_data = []
## Called when a g-code message is received from the engine. ## Called when a g-code message is received from the engine.
# #
@ -357,10 +367,10 @@ class CuraEngineBackend(Backend):
self._layer_view_active = True self._layer_view_active = True
# There is data and we're not slicing at the moment # There is data and we're not slicing at the moment
# if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment. # if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment.
if self._stored_layer_data and not self._slicing: if self._stored_optimized_layer_data and not self._slicing:
self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_layer_data) self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_optimized_layer_data)
self._process_layers_job.start() self._process_layers_job.start()
self._stored_layer_data = [] self._stored_optimized_layer_data = []
else: else:
self._layer_view_active = False self._layer_view_active = False

View file

@ -15,6 +15,7 @@ from UM.Math.Vector import Vector
from cura import LayerDataBuilder from cura import LayerDataBuilder
from cura import LayerDataDecorator from cura import LayerDataDecorator
from cura import LayerPolygon
import numpy import numpy
from time import time from time import time
@ -82,26 +83,46 @@ class ProcessSlicedLayersJob(Job):
abs_layer_number = layer.id + abs(min_layer_number) abs_layer_number = layer.id + abs(min_layer_number)
layer_data.addLayer(abs_layer_number) layer_data.addLayer(abs_layer_number)
this_layer = layer_data.getLayer(abs_layer_number)
layer_data.setLayerHeight(abs_layer_number, layer.height) layer_data.setLayerHeight(abs_layer_number, layer.height)
layer_data.setLayerThickness(abs_layer_number, layer.thickness) layer_data.setLayerThickness(abs_layer_number, layer.thickness)
for p in range(layer.repeatedMessageCount("polygons")): for p in range(layer.repeatedMessageCount("path_segment")):
polygon = layer.getRepeatedMessage("polygons", p) polygon = layer.getRepeatedMessage("path_segment", p)
points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array extruder = polygon.extruder
points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
line_types = numpy.fromstring(polygon.line_type, dtype="u1") # Convert bytearray to numpy array
line_types = line_types.reshape((-1,1))
points = numpy.fromstring(polygon.points, dtype="f4") # Convert bytearray to numpy array
if polygon.point_type == 0: # Point2D
points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
else: # Point3D
points = points.reshape((-1,3))
line_widths = numpy.fromstring(polygon.line_width, dtype="f4") # Convert bytearray to numpy array
line_widths = line_widths.reshape((-1,1)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
# Create a new 3D-array, copy the 2D points over and insert the right height. # Create a new 3D-array, copy the 2D points over and insert the right height.
# This uses manual array creation + copy rather than numpy.insert since this is # This uses manual array creation + copy rather than numpy.insert since this is
# faster. # faster.
new_points = numpy.empty((len(points), 3), numpy.float32) new_points = numpy.empty((len(points), 3), numpy.float32)
new_points[:,0] = points[:,0] if polygon.point_type == 0: # Point2D
new_points[:,1] = layer.height new_points[:,0] = points[:,0]
new_points[:,2] = -points[:,1] new_points[:,1] = layer.height/1000 # layer height value is in backend representation
new_points[:,2] = -points[:,1]
else: # Point3D
new_points[:,0] = points[:,0]
new_points[:,1] = points[:,2]
new_points[:,2] = -points[:,1]
new_points /= 1000 this_poly = LayerPolygon.LayerPolygon(layer_data, extruder, line_types, new_points, line_widths)
this_poly.buildCache()
this_layer.polygons.append(this_poly)
layer_data.addPolygon(abs_layer_number, polygon.type, new_points, polygon.line_width)
Job.yieldThread() Job.yieldThread()
Job.yieldThread() Job.yieldThread()
current_layer += 1 current_layer += 1

View file

@ -25,6 +25,8 @@ from . import LayerViewProxy
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
import numpy
## View used to display g-code paths. ## View used to display g-code paths.
class LayerView(View): class LayerView(View):
def __init__(self): def __init__(self):
@ -42,7 +44,7 @@ class LayerView(View):
self._top_layers_job = None self._top_layers_job = None
self._activity = False self._activity = False
Preferences.getInstance().addPreference("view/top_layer_count", 1) Preferences.getInstance().addPreference("view/top_layer_count", 5)
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count")) self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))
@ -253,11 +255,13 @@ class _CreateTopLayersJob(Job):
if not layer or layer.getVertices() is None: if not layer or layer.getVertices() is None:
continue continue
layer_mesh.addIndices(layer_mesh._vertex_count+layer.getIndices())
layer_mesh.addVertices(layer.getVertices()) layer_mesh.addVertices(layer.getVertices())
# Scale layer color by a brightness factor based on the current layer number # Scale layer color by a brightness factor based on the current layer number
# This will result in a range of 0.5 - 1.0 to multiply colors by. # This will result in a range of 0.5 - 1.0 to multiply colors by.
brightness = (2.0 - (i / self._solid_layers)) / 2.0 brightness = numpy.ones((1,4), dtype=numpy.float32) * (2.0 - (i / self._solid_layers)) / 2.0
brightness[0, 3] = 1.0;
layer_mesh.addColors(layer.getColors() * brightness) layer_mesh.addColors(layer.getColors() * brightness)
if self._cancel: if self._cancel: